Entradas en la categoría: Software Libre

PostgreSQL Day Perú 2007

Este sábado, se realizará un pequeño evento sobre PostgreSQL:

Pedimos disculpa si el presente mail le llega por diversas listas.

La comunidad PostgreSQL Peru (http://www.postgresql.org.pe) tiene el agrado de invitarte a participar de nuestro primer PostgreSQL Day a llevarse a cabo este sábado 8 de Septiembre de 3pm a 8pm en los locales de la Universidad Cayetano Heredia de Miraflores (Av. Armendariz 445 - Miraflores - Lima).

El programa del evento es:

  • 3:00 pm Inauguración
    • Palabras de bienvenida al evento (10″)
  • 3:10 pm Introducción a PostgreSQL
    1. Que es PostgreSQL (20″)
    2. Estandares SQL92 AnSI y SQL99 (20″)
    3. Comparativas contra otros dbms libres (20″)
  • 4:10 pm Instalación de PostgreSQL en diversas plataformas
    1. Debian (15″)
    2. CentOS (15″)
    3. Windows (15″)
    4. FreeBSD (15″)
    5. Preguntas (20″)
  • 5:30pm Break 15″
  • 5:45pm Entornos de Administración
    1. PgAdmin3 (20″)
    2. PhpPgAdmin (20″)
    3. Consola (20″)
    4. Preguntas (20″)
  • 7:05pm Mesa redonda de experiencias
    1. Experiencia Xendra (10″)
    2. Experiencia Cargo Master (10″)
    3. Experiencias EQSoft-Asoc. Empleados del BCP (10″)
    4. Rueda de preguntas (25″)

No es necesario inscribirse, se ingresará por orden de llegada, tenemos capacidad para recibir a 150 personas por lo cual te invitamos a llegar temprano, mas información sobre el evento será publicada en nuestra página web en los siguientes días, las diapositivas del evento serán publicadas en el mismo lugar.

Información sobre PostgreSQL:
PostgreSQL es un motor de base de datos totalmente libre, multiplataforma y de altas prestaciones, probado en varios proyectos a nivel nacional e internacional, es estable, rápido y fácil de utilizar, si quieres saber mas de PostgreSQL puedes visitar nuestra página web en http://www.postgresql.org.pe o la página principal del proyecto en http://www.postgresql.org

Si estás cerca y todavía sigues usando ciegamente MySQL te gustaría conocer algo más sobre PostgreSQL, ésta es tu oportunidad. ;)

Unir documentos PDF con .NET

Actualización (19/07/2007): Luis Ruiz Pavón comenta una forma más sencilla de unir documentos usando iTextDotNet.

Una pequeña clase que hace uso de iText# (Software Libre) para unir dos o más documentos PDF en uno solo.

using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

public class PdfMerge
{
    private BaseFont baseFont;
    private bool enablePagination = false;
    private readonly List<PdfReader> documents;
    private int totalPages;

    public BaseFont BaseFont
    {
        get { return baseFont; }
        set { baseFont = value; }
    }

    public bool EnablePagination
    {
        get { return enablePagination; }
        set
        {
            enablePagination = value;
            if (value && baseFont == null)
                baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
        }
    }

    public List<PdfReader> Documents
    {
        get { return documents; }
    }

    public void AddDocument(string filename)
    {
        documents.Add(new PdfReader(filename));
    }
    public void AddDocument(Stream pdfStream)
    {
        documents.Add(new PdfReader(pdfStream));
    }
    public void AddDocument(byte[] pdfContents)
    {
        documents.Add(new PdfReader(pdfContents));
    }
    public void AddDocument(PdfReader pdfDocument)
    {
        documents.Add(pdfDocument);
    }

    public void Merge(string outputFilename)
    {
        Merge(new FileStream(outputFilename, FileMode.Create));
    }
    public void Merge(Stream outputStream)
    {
        if (outputStream == null || !outputStream.CanWrite)
            throw new Exception("OutputStream es nulo o no se puede escribir en éste.");

        Document newDocument = null;
        try
        {
            newDocument = new Document();
            PdfWriter pdfWriter = PdfWriter.GetInstance(newDocument, outputStream);

            newDocument.Open();
            PdfContentByte pdfContentByte = pdfWriter.DirectContent;

            if (EnablePagination)
                documents.ForEach(delegate(PdfReader doc)
                                  {
                                      totalPages += doc.NumberOfPages;
                                  });

            int currentPage = 1;
            foreach (PdfReader pdfReader in documents)
            {
                for (int page = 1; page <= pdfReader.NumberOfPages; page++)
                {
                    newDocument.NewPage();
                    PdfImportedPage importedPage = pdfWriter.GetImportedPage(pdfReader, page);
                    pdfContentByte.AddTemplate(importedPage, 0, 0);

                    if (EnablePagination)
                    {
                        pdfContentByte.BeginText();
                        pdfContentByte.SetFontAndSize(baseFont, 9);
                        pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_CENTER,
                            string.Format("{0} de {1}", currentPage++, totalPages), 520, 5, 0);
                        pdfContentByte.EndText();
                    }
                }
            }
        }
        finally
        {
            outputStream.Flush();
            if (newDocument != null)
                newDocument.Close();
            outputStream.Close();
        }
    }

    public PdfMerge()
    {
        documents = new List<PdfReader>();
    }
}

Si bien es cierto que hay muchas cosas por mejorar, creo que para escenarios no muy complejos basta y sobra.

Pueden descargar la solución creada en Visual Studio 2005 que — incluye el ensamblado iText# y — como ejemplo une dos papers bastante interesantes (“Composable Memory Transactions” y “Static Typing Where Posible, Dynamic Typing When Needed: The End of The Cold War Between Programming Languages”).

Nota: La clase está basada en el artículo Merge PDF files with iText.

Cecil: Examina y modifica ensamblados .NET al vuelo

Cecil es una librería creada por Jean-Baptiste Evain que permite examinar y modificar los ensamblados .NET de manera sencilla, a su vez estos cambios pueden sobreescribir el original o ser almacenados en un ensamblado nuevo.

Veamos dos ejemplos sencillos que muestran como funciona Cecil:

  1. Convertir una aplicación de consola a una aplicación Windows.- Si compilamos el siguiente código como una aplicación de consola, al ejecutarse mostrará 2 ventanas (una para la consola y otra para el formulario creado):

     // console.cs
    using System;
    using System.Windows.Forms;
    
    class Program
    {
        static void Main(string[] args)
        {
            Form frm = new Form();
            frm.Height = 100;
            frm.Width = 100;
            frm.ShowDialog();
        }
    }

    Para hacer la conversión usando Cecil, lo único que se tiene que hacer es:

    using Mono.Cecil;
    using Mono.Cecil.Cil;
    
    class Program
    {
        static void Main(string[] args)
        {
            AssemblyDefinition assembly = AssemblyFactory.GetAssembly("consola.exe");
    	assembly.Kind = AssemblyKind.Windows;
    	AssemblyFactory.SaveAssembly(assembly, "windows.exe");
        }
    }

    Si ejecutamos windows.exe, esta vez sólo se mostrará el formulario creado.

  2. Cambiar el espacio de nombres y modificadores de acceso: En este ejemplo se va a cambiar el espacio de nombres de las clases y los modificadores de acceso de un ensamblado denominado ClassLibrary1.dll

    namespace ClassLibrary1.Utility
    {
        public enum HashMethod
        {
            MD5,
            SHA1
        }
    
        internal class Security
        {
            public static string MD5(string password)
            {
                throw new System.Exception("The method or operation is not implemented.");
            }
        }
        
        class Validation
        {
            public static bool IsEmail(string email)
            {
                throw new System.Exception("The method or operation is not implemented.");
            }
            private void IsUrl(string url)
            {
                throw new System.Exception("The method or operation is not implemented.");
            }
            private void IsIp(string ip)
            {
                throw new System.Exception("The method or operation is not implemented.");
            }
        } 
    }

    Para hacer realizar los cambios en el ensamblado de arriba:

    using Mono.Cecil;
    using Mono.Cecil.Cil;
    
    namespace CecilDemo
    {
        class Program
        {  
            static void Main(string[] args)
            {
                string assemblyName = "ClassLibrary1.dll";
    
                /* Cargar el ensamblado */
                AssemblyDefinition assembly = AssemblyFactory.GetAssembly(assemblyName);
    
                /* Iterar sobre los tipos del módulo principal */
                foreach (TypeDefinition type in assembly.MainModule.Types)
                {
                    /* Cambiar el espacio de nombres y el
                     * nivel de acceso a todas las clases 
                     */
                    if ("<Module>" != type.Name)
                    {
                        type.Namespace = type.Namespace.Replace("ClassLibrary1", "Buayacorp");
                        type.Attributes |= TypeAttributes.Public;                    
                    }
                    
                    /* Hacer que todos los métodos de la clase Validation 
                     * sean públicos y miembros de clase (static).
                     */
                    if ("Validation" == type.Name)
                    {
                        foreach (MethodDefinition method in type.Methods)
                        {
                            /* Eliminar el atributo 'private' de cada uno de los métodos */
                            if ((method.Attributes & MethodAttributes.Private) == MethodAttributes.Private)
                            {
                                method.Attributes ^= MethodAttributes.Private;
                            }
    
                            method.Attributes |= MethodAttributes.Public | MethodAttributes.Static;                        
                        }
                    }
                }
                /* Almacenar el nuevo ensamblado en CustomClassLibrary1.dll */
                AssemblyFactory.SaveAssembly(assembly, "Custom" + assemblyName);
            }
        }
    }

    Si observamos el ensamblado modificado con Reflector, veremos que se realizaron los cambios.

El uso de esta herramienta obviamente va a depender de las necesidades y posibles limitaciones de acceso al código fuente que tengamos, puesto que no sería nada productivo usar Cecil para hacer cosas parecidas a los ejemplos que muestro. :D

Free software only dies when the last copy of the source code is erased.
Henrik Nordstrom, desarrollador de Squid

Visto en logadmin.net

#Permalink Comentarios (0) Frases, Miniposts, Software Libre

Tipos personalizados de PostgreSQL y Npgsql

A raíz de una pregunta en la lista de discusión en español de PostgreSQL en el que hacían la siguiente pregunta:

Hola, tengo una función definida en mi BD postgresql que recive un array de un elementos de un tipo definido en la BD. (este tipo es un bigint y un character varying). Ahora mi duda es si el conector npgsql (Conector para .NET) soporta la posibilidad de llamar a una funcion con estas características.

Estos tipos compuestos en PostgreSQL se crean con la sentencia CREATE TYPE:

test=> CREATE TYPE complex AS (
test(>     r       double precision,
test(>     i       double precision
test(> );
CREATE TYPE
test=> create table foo (item complex);
CREATE TABLE
test=> insert into foo values(ROW(5.2,1.6));
INSERT 0 1
test=> insert into foo values(ROW(2,-1));
INSERT 0 1
test=> select * from foo;
   item
-----------
 (5.2,1.6)
 (2,-1)
(2 filas)

Npgsql trae soporte sólo para los tipos de datos nativos que ofrece PostgreSQL, y trata a estos tipos compuestos como una cadena de caracteres. Si bien es cierto que se podría trabajar solamente con cadenas tanto para insertar como para recuperar este tipo de datos, esto probablemente causaría algunos problemas en la etapa de desarrollo, porque estos valores no serían comprobados en tiempo de compilación (más detalles); puesto que disponemos del código de Npgsql, es posible extenderlo sin mayores problemas para que soporte los tipos de datos que usemos en una aplicación X.

Lo primero, es definir una clase que represente el tipo que hayamos definido en la base de datos:

public struct NpgsqlComplex
{
	private double _r;
	private double _i;

	public double I
	{
		get { return _i; }
		set { _i = value; }
	}

	public double R
	{
		get { return _r; }
		set { _r = value; }
	}

	public NpgsqlComplex(double r, double i)
	{
		_r = r;
		_i = i;
	}        
}

Luego se tiene que registrar esta clase en el método VerifyDefaultTypesMap de la clase NpgsqlTypesHelper:

NativeTypeMapping.AddType("complex", NpgsqlDbType.Complex, DbType.Object, true,
	new ConvertNativeToBackendHandler(ExtendedNativeToBackendTypeConverter.ToComplex));

NativeTypeMapping.AddTypeAlias("complex", typeof(NpgsqlComplex));

y agregar un nuevo elemento a la variable TypeInfoList ubicado en el método CreateAndLoadInitialTypesMapping de la misma clase:

new NpgsqlBackendTypeInfo(0, "complex", NpgsqlDbType.Complex, DbType.Object, typeof(NpgsqlComplex),
                        new ConvertBackendToNativeHandler(ExtendedBackendToNativeTypeConverter.ToComplex)),

Los métodos ExtendedNativeToBackendTypeConverter.ToComplex y ExtendedBackendToNativeTypeConverter.ToComplex se usan para convertir estos tipos compuestos desde .NET a PostgreSQL y desde PostgreSQL a .NET respectivamente

// clase ExtendedNativeToBackendTypeConverter
private static readonly Regex complexRegex = new Regex(@"\(([-+]?\b[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?\b),([-+]?\b[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\)", RegexOptions.Compiled);
internal static Object ToComplex(NpgsqlBackendTypeInfo TypeInfo, String BackendData, Int16 TypeSize, Int32 TypeModifier)
{
	Match m = complexRegex.Match(BackendData);

	return new NpgsqlComplex(
			Double.Parse(m.Groups[1].ToString(), NumberStyles.Any,
						 CultureInfo.InvariantCulture.NumberFormat),
			Double.Parse(m.Groups[2].ToString(), NumberStyles.Any,
						 CultureInfo.InvariantCulture.NumberFormat));
}


// clase ExtendedBackendToNativeTypeConverter
internal static String ToComplex(NpgsqlNativeTypeInfo TypeInfo, Object NativeData)
{
	if (NativeData is NpgsqlComplex)
	{
		NpgsqlComplex complex = (NpgsqlComplex)NativeData;
		return String.Format(CultureInfo.InvariantCulture, "({0},{1})", complex.R, complex.I);
	}
	else
	{
		throw new InvalidCastException("Unable to cast data to NpgsqlComplex type");
	}
}

Finalmente, la clase de prueba para ver si todo funciona como debería:

using System;
using System.Collections.Generic;
using System.Text;
using Npgsql;
using NpgsqlTypes;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (NpgsqlCommand command = new NpgsqlCommand("SELECT item FROM foo LIMIT 1", new NpgsqlConnection("server=192.168.1.20;uid=alex;database=test")))
            {
                command.Connection.Open();

                NpgsqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    NpgsqlComplex num = (NpgsqlComplex)reader["item"];
                    Console.WriteLine("{0} + {1}i", num.R, num.I);
                }
                reader.Close();

                command.CommandText = "INSERT INTO foo VALUES (@item)";
                command.Parameters.Add("@item", NpgsqlDbType.Complex);
                command.Parameters["@item"].Value = new NpgsqlComplex(15.5, -5);

                command.ExecuteNonQuery();
            }
        }
    }
}

Aunque el ejemplo es bastante trivial y tiene poco o nulo valor en aplicaciones reales, este ejemplo intenta mostrar uno de los beneficios del uso de Software Libre: el hecho de poder acomodar a nuestras necesidades las cosas que usemos.

Nota: Si alguien le interesa el ejemplo mostrado, puede descargar una versión modificada de Npgsql (para Visual Studio 2005) más el proyecto de prueba.