martes, 11 de octubre de 2011

Tomcat: Problemas con UTF-8, (RequestDumperValve)

En el trabajo hemos tenido un gran dolor de cabeza con la codificación de caracteres, nuestro middleware estaba teniendo problemas con acentos, diéresis y "eñes", y por este motivo las respuestas a las peticiones de los web services se tornaron un desastre.

Todo inicio cuando tratamos de mudarnos a un ambiente de desarrollo con alta disponibilidad, ya que en el ambiente anterior funcionaba correctamente, tratamos por todos los medios posibles para corregir el problema, intentamos con:
  • Agregar URIEncoding="UTF-8" y useBodyEncodingForURI="true" a la configuración del server.xml
  • Agregar el encoding a las opciones de catalina: export CATALINA_OPTS= Dfile.encoding="UTF-8"
  • Agregar también el encoding en las opciones de java: export JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding="UTF-8"
  • Agregar las locale al usuario que ejecuta el proceso tomcat
Y nada parecía funcionar, hasta que por fin @NataS encontró algo que finalmente nos ayudo a resolver nuestro problemita que nos había consumido muchas horas.

Pues resulta que en las configuraciones nuevas de nuestros servidores estaba habilitada la opción RequestDumperValve en el server.xml, y que hace ese tal RequestDumperValve?, desde la documentación de tomcat:

"The Request Dumper Valve is a useful tool in debugging interactions with a client application (or browser) that is sending HTTP requests to your Tomcat-based server. When configured, it causes details about each request processed by its associated Engine, Host, or Context to be logged according to the logging configuration for that container.

WARNING: Using this valve has side-effects. The output from this valve includes any parameters included with the request. The parameters will be decoded using the default platform encoding. Any subsequent calls to request.setCharacterEncoding() within the web application will have no effect. NOTE: Since all parameters are included in the output, the InputStream is consumed for requests made with the method POST and content-type application/x-www-form-urlencoded."

Fuente.

En palabras de Endre Stølsvik:

“Enabling the RequestDumperValve in both 5.5.12 and 5.0.16 (!) messes up the parsing of other-than-ISO-8859-1 incoming parameters.
After using a rather huge bunch of hours, this came down as the result: when this “debug valve” is turned on, it seems to default to ISO-8859-1 when it parses and log-outputs the incoming parameters, thus also implicitly setting the entire Request-object to this enc, so any subsequnt setting to UTF-8 doesn’t matter at all. At least this is true for POST parameters.
For GET parameters, the situation is a little different. Here an explicit setting of URIEncoding to UTF-8 seems to work as it should, while useBodyEncodingForURI doesn’t – it picks up the wrong already implicitly set encoding. (For 5.0.16 I can’t seem to get the latter version to work, and have to use the explicit setting.)
Sorry if my analysis doesn’t hold water, but at least the bug seems to be very consistent.”



Y al parecer nos es especifico de estas versiones, también sucede en la versión 6.  Para la versión 7 esta válvula se llama RequestDumperFilter

Entonces tal como se expresa en estas citas, tener activado RequestDumperValve puede tener efectos colaterales, ya que se puede parsear a otra codificación todos los parámetros, y además que, posterior a esto no importa cualquier otra configuración que sea agregada, ya que no será respetada, al menos para las peticiones POST (cuyo método usamos para todas nuestras peticiones).

Tal como dijó rolfje:

Si tienes problemas raros con UTF-8 y Tomcat, busca en tu archivo server.xml una linea parecida a:

<Valve className="org.apache.catalina.valves.RequestDumperValve">

comentala, reinicia tu servidor de aplicaciones y vuelve a intentarlo. Puede que con eso, tus problemas también sean resueltos.

martes, 4 de enero de 2011

PostgreSql: Interfaces de conexión y lenguajes de programación

Con esta publicación se intenta proveer una guía inicial en cuanto a la conectividad de PostgreSql y algunos lenguajes de programación. Los ejemplos han sido probados en linux Debian (a menos que se indique lo contrario), pero debe de funcionar normalmente en cualquier otra distribución, solo instalando los paquetes equivalentes.

¿Cómo conectarse desde JAVA via JDBC?

Requisitos:


jurasec@dev:~/test$ CLASSPATH=.:postgresql-8.4-702.jdbc3.jar 

Ejemplo
import java.sql.*;
public class Conexion {
 public static void main(String args[]) {
  Connection conn;
  Statement stat;
  ResultSet rset;

  try{
   Class.forName("org.postgresql.Driver");
   conn=DriverManager.getConnection("jdbc:postgresql:test","postgres","postgres");
   stat=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);

    rset = stat.executeQuery("SELECT id,descripcion FROM articulos");
   while (rset.next()) {
    System.out.println(rset.getString(1)+" - "+rset.getString(2));
   }
   rset.close();
   stat.close();      

  }catch(Exception e){
   System.out.println("Error: "+e.getMessage());
  }
 }
}

¿Cómo conectarse a C# con (Npgsql)?

Este ejemplo ha sido probado sobre Windows con .NET y en Linux con Mono
Requisitos:


Ejemplo
using System;
using System.Data;
using Npgsql;
 
public class Conexion{
 public static void Main(string[] args){
  string connectionString =
   "Server=localhost;" +
   "Database=test;" +
   "User ID=postgres;" +
   "Password=postgres;";
  IDbConnection dbcon;
  dbcon = new NpgsqlConnection(connectionString);
  dbcon.Open();
  IDbCommand dbcmd = dbcon.CreateCommand();

  string sql = "SELECT id,descripcion FROM articulos";
  dbcmd.CommandText = sql;
  IDataReader reader = dbcmd.ExecuteReader();
  while(reader.Read()) {
   int id = reader.GetInt32(reader.GetOrdinal("id"));
   string descripcion = reader.GetString(reader.GetOrdinal("descripcion"));
   Console.WriteLine(id + " - " + descripcion);
  }

  reader.Close();
  reader = null;
  dbcmd.Dispose();
  dbcmd = null;
  dbcon.Close();
  dbcon = null;
 }
}

Compilando el ejemplo:
gmcs Conexion.cs -r:System.Data.dll -r:Npgsql.dll
 

Para ejecutarlo:
mono Conexion.exe
 

¿Cómo conectarse desde PHP?

Requisitos:

  • Instalar php5-pgsql

Ejemplo
$dbconn = pg_connect("host=localhost dbname=test user=postgres password=postgres")
    or die('No se pudo conectar: ' . pg_last_error());

$query = 'SELECT id,descripcion FROM articulos';
$result = pg_Exec($query) or die('Error: ' . pg_last_error());

echo "\n";
while ($line = pg_fetch_object($result)) {
    echo "\t\n";
    foreach ($line as $col_value) {
        echo "\t\t\n";
    }
    echo "\t\n";
}
echo "
$col_value
\n"; pg_free_result($result); pg_close($dbconn);

¿Cómo conectarse desde Python 2.x  (psycopg2)?


Requisitos:

  • Instalar python-psycopg2

Ejemplo
import psycopg2
try:
 con = psycopg2.connect("host=localhost dbname=test user=postgres password=postgres")
 cursor = con.cursor()
 cursor.execute("select id,descripcion from articulos")
 for row in cursor:
  id,descripcion=row
  print id,descripcion

 cursor.close()
 con.close()
except:
 print "Error"

¿Cómo conectarse desde Python 3 (psycopg2)?


Requisitos:


python3 setup.py install

Ejemplo
import postgresql
try:
 db = postgresql.open("pq://postgres:postgres@localhost/test")
 ps = db.prepare("SELECT id,descripcion from articulos")
 for row in ps:
  id,descripcion=row
  print (id,descripcion)
except:
 print ("Error")

¿Cómo conectarse desde C?


Requisitos:

  • Instalar postgresql-server-dev-8.4

Ejemplo
#include <stdio.h>
#include <libpq-fe.h>

int main(){
 PGconn *conn;
 PGresult *res;
 int i,j;

 conn = PQsetdbLogin("localhost","5432",NULL,NULL,"test","postgres","postgres");
 
 if (PQstatus(conn) != CONNECTION_BAD){
  res = PQexec(conn, "select id,descripcion from articulos");
  if (res != NULL && PGRES_TUPLES_OK == PQresultStatus(res)){
   for (i = 0; i < PQntuples(res); i++){
    for (j = 0; j < PQnfields(res); j++)
     printf("%s\t",PQgetvalue(res,i,j));
    printf("\n");
   }
   PQclear(res);
  }
 }
 else
  printf("Error");
 
 PQfinish(conn);
 return 0;
}

Compilando el ejemplo:
gcc db.c -o db -lpq -I/usr/include/postgresql/

¿Cómo conectarse desde Perl?

Requisitos:

  • Instalar libdbi-perl

Ejemplo
#!/usr/bin/perl
use DBI;
#use strict;
my $dbh = DBI->connect("DBI:Pg:dbname=test;host=localhost", "postgres", "postgres");
$dbh->{RaiseError} => 1; #ref

my $sth = $dbh->prepare("SELECT id,descripcion FROM articulos");
$sth->execute();
 
while(my $ref = $sth->fetchrow_hashref()) {
   print "$ref->{'id'} - $ref->{'descripcion'}\n";
}
$sth->finish;
$dbh->disconnect;
exit;

¿Cómo conectarse desde Ruby on Rails? 

Requisitos:

  • Instalar libdbd-pg-ruby1.8 
Creamos nuestra aplicación de prueba
rails -d postgresql test_app
Editamos el archivo config/database.yml con los parámetros necesarios para la conexión con Pgsql
development:
  adapter: postgresql
  database: test
  username: postgres
  password: postgres
  host: localhost
Generamos el controlador y el modelo necesario:
ruby1.8 script/generate controller Articulo
ruby1.8 script/generate model Articulo
Creamos la base necesario para poder ver, crear, actualizar y eliminar los datos de la tabla Articulos
class ArticuloController < ApplicationController
 scaffold :articulo
end
Veamos el resultado en http://0.0.0.0:3000/articulo

 Los siguientes ejemplos estan probados en Windows Xp, Vista, 7

 ¿Cómo conectarse desde Visual Basic 6 (ADO)? 

 Requisitos:


Ejemplo
Set cn = CreateObject("ADODB.Connection")
cn.Open "Driver={PostgreSQL ANSI};SERVER=localhost;DATABASE=test;PORT=5432;UID=postgres;PWD=postgres;"

Set rs = CreateObject("ADODB.Recordset")
rs.Open "SELECT id,descripcion FROM articulos", cn

Do Until rs.EOF
   Debug.Print rs!id, rs!descripcion
   rs.MoveNext
Loop
¿Cómo conectarse desde Visual FoxPro?

Requisitos:


Ejemplo
strConnection = 'DRIVER={PostgreSQL Ansi};SERVER=localhost;'+;
        'PORT=5432;DATABASE=test;'+;
        'UID=postgres;' +;
        'PWD=postgres;'

SQLSETPROP(0,'DispLogin',3) && evita que aparezca el login del DSN ODBC
conn  = SQLSTRINGCONNECT(strConnection,.F.) 

IF conn = -1
 AERROR(arrayerror)
 IF arrayerror(4)='28000' THEN 
  MESSAGEBOX('Usuario y/o contraseña incorrectos',16,'Error')
 ENDIF 
ELSE
 MESSAGEBOX('Conectado')
 ssql="select id,descripcion from articulos"
 status = SQLEXEC(conn,ssql,'cCursor')
 IF status=-1
  MESSAGEBOX('Error en la consulta')  
  RETURN 
 ELSE
  select cCursor
  browse
 ENDIF 
ENDIF

¿Cómo conectarse desde Access?


Requisitos:

Creamos una base de datos vacía.

Elegimos importar base de datos ODBC.


Elegimos la vinculación de datos.

Creamos un nuevo origen de datos, seleccionando PostgreSql.

Configuramos origen de datos.

 Guardamos el origen configurado y luego se selecciona de la lista.

Se seleccionan las tablas que se desean vincular.

Resultado.



lunes, 13 de diciembre de 2010

SchemaSpy: Documentando tu base de datos

Sabemos lo importante que es generar y mantener una buena documentación de nuestro código fuente, al igual que de la estructura de nuestras bases de datos. 

Cuando iniciamos un proyecto nuevo se supone que antes de hacer algún cambio a la base de datos directamente, ya paso por un proceso de análisis y se plasmo en algún modelo, llámese Modelo Relacional, Entidad-Relación, UML, etc.

Pero aveces sucede que los cambios se hacen de manera directa, y con el tiempo se van olvidando detalles ó partes importantes de la estructura, en otros casos la base de datos ya fue generada por alguien más y te ha sido heredada sin documentación, aquí es donde entra la utilidad de ésta herramienta SchemaSpy (LGPL), la cual genera un diagrama Entidad-Relación de tu base de datos en formato HTML, permitiendo poder navegar entre las relaciones de las tablas mediante links. Aparte de representar las relaciones de una manera muy clara, también genera otros datos, como el número de tablas que dependen de cada relación, el número de filas, el número de columnas por tabla, una lista de todos los constraints, una lista de todas las columnas con su nombre, tipo de datos, tamaño, si es NULL o no, si es serial, su valor que tiene por default, y por si fuera poco un lista donde muestra posibles anomalías dentro de la base de datos.

Requerimientos:
SchemaSpy puede generar el diagrama de la mayoria de los gestores de bases de datos, solo se necesita su driver de conexión.



Es una herramienta para la linea de ordenes y su sintaxis básica es:
java -jar schemaSpy_5.0.0.jar -dp rutaDriver -t tipoGestor -db nombreBase -s esquema -host host -p contraseña -port puerto -u usuario -o directorioSalida

El resultado se vería algo como esto:


Para ver la documentación completa favor de ir a http://schemaspy.sourceforge.net/
Si deseas ver un ejemplo de como queda, puedes acceder a http://schemaspy.sourceforge.net/sample/

También existe la posibilidad de utilizar esta herramienta de manera gráfica mediante SchemaSpyGUI (LGPL) ésta tiene control completo de schemaSpy.  Para iniciar el programa solamente hay que escribir:
java -jar schemaSpyGUI.jar