Select recursivo en Oracle

En el trabajo hoy hemos tenido que hacer una pequeña consulta recursiva sobre una tabla y como, aunque me acordaba que se podía hacer, no me acordaba de como, me ha todaco buscarlo. Así que para futuras ocasiones, y por si a alguien le es útil ahí va.

En primer lugar, que es, o a que llamo yo un select recursivo. Pues es una consulta en una tabla en la que uno o varios registos están vinculados entre sí por una relación generalemente jerárquica. Por poner un ejemplo imaginaros una tabla con empleados, donde cada empleado depende de otro. Dicha tabla sería algo así (resumida):

empleado_id | Nombre | jefe_id
---------------------------
        100 | Pepe   | 101
        101 | Juan   | 103
        102 | Jose   | 106
        103 | María  | 0 (0 -> No tiene jefe)
        106 | Ramón  | 0 (0 -> No tiene jefe)

La idea es recuperar en una sola consulta, todos los empleados asociados a Pepe, quizás respondiendo algo como “¿Quien es el jefe principal de Pepe?” Con una consulta normal, tendríamos que ejecutar tres sentencias, una para recuperar el jefe_id de Pepe, otra para recuperar a Juan y una última para recuperar a María. Extrapolad esto a una relación donde hayan cientos de elementos y tendréis un montón de conexiones a la BBDD innecesarias o algo peor. Con una consulta recursiva (Oracle la llama jerárquica) podríamos hacerlo todo de una vez.

select empleado_id, nombre, jefe_id, level
  from empleados
 start with empleado_id = 100
 connected by empleado_id = prior jefe_id
 order by level;

Como se puede ver la consulta es bastante intuitiva, empezando en nuestro empleado Pepe (empleado_id = 100) obtendrá todos los registros conectados con él a través del campo jafe_id, y para estos, hará lo mismo hasta no encontrar más resultado (llegará a María que no está relacionada con nadie jefe_id = 0). Tener cuidado con relaciones cíclicas.

Lo único importante digno de mención en la consulta es la palabrá PRIOR, depende de donde la pongamos, recorrerá la relación en un sentido u otro. Es decir, tal como está ahora busca la clave jefe_id en la columna empleado_id. Si cambiamos de posición la palabra reservada PRIOR (connected by prior empleado_id = jefe_id) buscará la clave empleado_id en la columna jefe_id. de está forma recorrerá las relaciones de hijos a padres o al revés.

La otra palabra reservada a la que merece la pena hacer mención es LEVEL, la cual nos muestra la posición de la relación en la que ha sido encontrado el registro. Es decir, para Pepe el nivel será igual a uno, para Juan será igual a dos y para María será igual a tres. En caso de haber registros en el mismo nivel, podrán aparecer varios niveles iguales.

Bueno, espero que os sirve a alguno, y desde luego a mi, espero que no se me vuelva a olvidar. Nos vemos.

Documentación de Oracle

Select recursivo en Oracle

PHP + WS + Autenticación + SSL

Estos días por unos u otros motivos me ha tocado desarrollar un par de clientes para conectar a servicios web en diferentes tecnologías. Los servicios web están hechos en Java, pero van a ser consumidos desde diferentes plataformas y lenguajes, y me ha tocado a mí escribir el código de estos primeros clientes. Uno de ellos lo he desarrollado sobre PHP, y aunque he de decir que al principio ha sido muy fácil, la parte de SSL se me ha atragantado un poco ya que, pese a conseguir que la negociación entre cliente y servidor, y la obtención del WSDL se hiciera sobre “https”, la petición al servicio web y su respuesta se hacían sobre “http”. Así que con motivo de los quebraderos de cabeza que me ha dado esto, lo voy a dejar por escrito por tres razones: la primera es que no se me vuelva a olvidar, la segunda es que tanto yo como cualquiera de vosotros lo tenga a mano (creedme he llegado a la página 20 de la búsqueda de Google, jamás digáis que no hay nada interesante más haya de la página 4), y la tercera es que, algún día con más tiempo, me gustaría investigar que hace exactamente cada una de las propiedades que estoy utilizando y si se puede prescindir de alguna.

Antes de empezar, decir que estoy escribiendo todo esto partiendo de que tengo instalada una versión 5.3.18 de PHP, sobre todo lo digo porque, según entre que versiones, hay diferencias muy grandes. En principio, entre la 5.3 y la 5.4 no debería haber grandes diferencias. (la 5.5 está en alfa así que no se nada)

PHP + WS
Para empezar vamos a consumir un servicio web básico, sin autenticación ni SSL.

$wsdl = “http://server/webservice?wsdl”;
$client = new SoapClient($wsdl);
$result = $client->webservice($parameters);
print_r($result);

En la primera línea tenemos la dirección del fichero WSDL correspondiente al servicio web que queremos consumir.

En la segunda línea tenemos la creación del cliente a partir del WSDL que nos va a permitir utilizar los métodos ofertados por el servicio web.

En la tercera llamamos al método del servicio web que queremos utilizar pasándole un “array” con los parámetros que necesitemos.

En la cuarta simplemente escribimos el resultado.

PHP + WS + Autenticación
En el siguiente paso vamos añadir la parte de autenticación, es decir, pasar un usuario y contraseña al servidor para poder identificarnos en un sistema de control de acceso básico. El código será muy parecido, solo que ha la hora de crear el cliente con el método “SoapClient” le pasaremos estos credenciales.

$wsdl = “http://server/webservice?wsdl”;
$clientOptions = array(‘login’ => ’nuestroUser’, ‘password‘ => ‘nuestraContr’);
$client = new SoapClient($wsdl, $clientOptions);
$result = $client->webservice($parameters);
print_r($result);

Con esto conseguiremos identificarnos de forma exitosa en el servidor para poder utilizar los métodos ofertados por el servicio web.

PHP + WS + Autenticación + SSL
El tercer paso es añadir el soporte SSL. Aquí es donde yo me atasqué hasta que conseguí encontrar la combinación de parámetros adecuada. No se es la forma correcta o la más eficiente, pero si que por lo menos funciona. De hecho, podemos capturar el tráfico con una herramienta como WireShark o Network Monitor para comprobar que nuestras peticiones van cifradas. Para añadir la capacidad de realizar consultas sobre SSL bastará con añadir las siguientes propiedades al array de opciones que se le pasa al método SoapClient junto con el nombre de usuario y la contraseña.

$wsdl = “https://server/webservice?wsdl”;
$localCert = “certificado.pem”;
$clientOptions = array(‘login’ => ’nuestroUser’, ‘password‘ => ‘nuestraContr’,
                       ‘local_cert’ => $localCert, ‘passphrase’ => ‘contrCertificado’,
                       ‘soap_version’ => SOAP_1_1, ‘encoding’ => ‘UTF-8’,
                       ‘compression’ => (SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP),
                       ‘location’ => ‘urlWS’);
$client = new SoapClient($wsdl, $clientOptions);
$result = $client->webservice($parameters);
print_r($result);

login y password, son los credenciales para la autenticación.

local_cert, es el certificado que tendremos en nuestro sistema local para acceder al servidor a través de SSL.

passphrase, es la contraseña de dicho certificado.

soap_version, es la versión de soap que está usando el servidor (Es una constante PHP).

encoding, es la codificación que vamos a utilizar para la comunicación.

compression, es si aceptamos compresión o no y en que formatos.

location, es la url del servicio web, generalmente es como la del WSDL pero sin el “?wsdl”.

Con esto tendremos nuestro tráfico cifrado y podremos consultar sin problemas los métodos del servicio web sobre SSL.

Quede dicho que es post está hecho únicamente desde el punto de vista del programador, ni hemos explicado como habilitar SOAP o SSL en PHP ni como configurar nada, esto es lo primero que tendríais que revisar si tenéis algún problema.

Y para terminar, sé que el post no va muy el la línea de la serie de artículos que estábamos haciendo últimamente, pero lo que hace bonito el trabajo en parte es que nunca sabes a que problema te vas a enfrentar mañana. Nos vemos.

PHP + WS + Autenticación + SSL

JDBCAppender – Log4j

Como ya sabéis, además de poner artículos y demás, este blog lo utilizo como extensión de mi memoria, así que hoy, sin que venga mucho a cuento con la última serie de artículos publicados, voy a escribir como configurar un JDBCAppender para Log4j, ya que es algo que sabía existía pero no recordaba como se configuraba hasta que estos días he tenido que investigarlo.

Para el que no caiga ahora mismo, los Appenders en Log4j son la definición de propiedades que se hace de como mostrar, almacenar o informar de las actividades de log en un aplicación Java. Imagino que todo el que desarrolle en Java o J2EE los habrá utilizado. En nuestro caso, el Appender que nos ocupa, JDBCAppender se encarga de guardar los errores en base de datos.

Para ello lo primero que tendremos que hacer es crear una tabla en BBDD para guardar nuestros logs, algo como la siguiente (los tamaños son totalmente arbitrarios, están sin ajustar y elejidos al alza):

create table logs
(
  user varchar2(10),
  event_date date,
  logger varchar2(50),
  event_level varchar2(4),
  event varchar2(4000),
  details varchar2(100)
)

Evidentemente, esta tabla podrá tener tantos campos como deseemos y en cada uno de ellos podremos guardar aquellos datos que nos permite Log4j, teniendo siempre en cuenta la concordancia de tipos de datos y formatos. Para aquel que tenga un poco olvidado Log4j, aquí tenéis una pequeña chuleta sobre ello.

A continuación nos definiremos en nuestro fichero de configuración de log4j el JDBCAppender. Existen dos posibilidades, en un fichero properties y en un xml, yo como la aplicación que estaba utilizando ya tenía un xml voy a hacerlo en xml. La convenversión de un formato a otro es trivial.

<appender name="NOMBREAPPENDER">
    <param name="URL" value="jdbc:oracle:thin:@SERVER:PORT/SERVICENAME" />
    <param name="Driver" value="oracle.jdbc.driver.OracleDriver" /> 
    <param name="User" value="USER" /> 
    <param name="Password" value="PASSWORD" /> 
    <param name="Threshold" value="ERROR"/>
    <layout> 
        <param name="ConversionPattern" value="INSERT INTO LOGS ('%x',SYSDATE,'%C','%p','%m','%l')"/>
    </layout> 
</appender>

Existen más propiedades que se pueden añadir, pero estás son las básicas:

  • URL: Dirección de nuestra BBDD, en mi caso ORACLE. Si en vez de utilizar el SERVICENAME utilizamos el SID, sería algo así: “jdbc:oracle:thin:@SERVER:PORT:SID” Nótese los dos puntos en lugar de la barra detrás del puerto.
  • Driver: El driver para la conexión a BBDD.
  • User: Usuario de conexión a la BBDD.
  • Password: Password de conexión a la BBDD.
  • ConversionPattern: Realiza la inserción de los datos que deseamos. Para entender los patrones, mirad la chuleta que os he puesto antes.

Después de esto, ya solo nos quedará añadir este appender a nuestra sección “root” para que se ejecute.

<root>
    ...
    <appender-ref ref="NOMBREAPPENDER"/>
</root>

Y con esto ya funcionará.

También simplemente a modo de comentario dejar escrito que hay otro appender muy interesante que es el de SMTPAppender, que se encarga de mandarnos por email directamente el error que se ha producido.
Bueno, espero que os sea de utilidad. Nos vemos.

JDBCAppender – Log4j

Conservando nuestro código: Dropbox

Supongo que ha estas alturas, casi todos sino todos, conoceréis Dropbox. Para el que no lo conozca, Dropbox es un servicio de alojamiento de archivos en la nube. Podéis leer algo más sobre él en la propia página de Dropbox o en Wikipedia:Dropbox.

Para los desarrolladores puede ser interesante por varios motivos, cada uno tendrá los suyos, tener nuestro código en la nube. Ya sea, por ejemplo, por disponibilidad de poder trabajar desde cualquier lado, o simplemente por seguridad a modo de backup por si pasa algún accidente. Obviamente, este post no aplica para grandes proyecto corporativos ya que estos deberían tener su propio servidores de subversión y servidores de backup, aunque lamentablemente, esto no siempre es así. Luego, todo son pánico, carreras, explicaciones al cliente y presión a los desarrolladores, pero bueno, esto es otra historia.

El post está enfocado más bien a nuestros pequeños proyecto caseros, esos que aunque no son relevantes, son muy importantes para nosotros. Esos en los que trabajas en cualquier sitio en cuanto tienes 5 minutos libres.

Yo voy a proponer dos pequeñas ideas apoyándome en Dropbox. La primera de ellas, está mas relacionada con el backup de nuestros proyectos, y la segunda, con la disponibilidad de estos.

En mi casa, aunque hay varios ordenadores, yo solo utilizo el mío y algún disco duro externo para backups, almacenamiento de datos y demás. Como el disco duro no lo tengo constantemente enchufado, cuando monto un servidor subversión lo hago sobre mi misma máquina, más pensado para controlar las versiones del código que voy escribiendo que pensando en que sea un backup en caso de desastre. Pero claro, un día se produjo este desastre y perdí bastante código, no todo, porque cada semana hago un backup de la máquina, pero si lo suficiente como para que decidiera buscar una solución. Y esta fue Dropbox. Decidí meter mis repositorios dentro de la carpeta de sincronización de Dropbox, y así de forma automática, cada vez que hago un “commit”, toda la información se sube a la nube. Esta fue la primera idea.

Pero, llegó el día en que no llevaba mi ordenador encima, tenía unas horas muertas para malgastar en algo y estaba rodeado de ordenadores, el único problema era que no tenía mi código a mano para trabajar un ratito sobre él. El código estaba en la nube, yo me podía bajar un eclipse en uno de los ordenadores que tenía a mano, pero por razones de capado de puertos, no podía montar un servidor subversión para  bajar el código en él y abrirlo en el eclipse. Y a partir de aquí, fue donde se me ocurrió la idea de meter directamente el workspace de trabajo en la carpeta de Dropbox. De esta forma, fuera donde fuera, con descargar un eclipse (o llevarlo en un USB) podía trabajar sobre mi código en cualquier parte.

Por supuesto, se pueden poner en práctica las dos ideas a la vez sin ningún problema obteniendo así los beneficios de ambas:

a) Tener a buen recaudo nuestro código y el versionado de este.

b) Tenerlos a nuestro alcance para trabajar en todo momento.

Espero que a alguno os sirva. Si alguien tiene algún método más sobre como ha resuelto el problema, que se anime a comentarlo. Nos vemos.

Conservando nuestro código: Dropbox

Kiai – Katas

No, no me vuelto loco ni nada parecido. Hoy vamos a hablar de Katas, pero no las que estáis pensando pertenecientes a algún arte marcial, sino de unas que os van a ayudar a fortalecer vuestro cerebro y vuestras habilidades como desarrollador.

Como muchos sabréis, aunque en el blog suelo escribir sobre temas enfocados a seguridad, realmente yo soy desarrollador. Estos últimos años principalmente de Java EE, aunque he pasado por unos cuantos lenguajes, pero esto, es una historia para otro día.

Pues bien, una de las cosas que obviamente hago en casa en mis ratos libres es desarrollar, ya sea algún proyecto propio, o simplemente, algún código pequeñito para solventar un problema puntual. A raíz de esto, descubrí las Katas de programación. Pero, vamos a empezar por el principio. ¿Qué es una kata? Según la Wikipedia, y estoy seguro que todo el que haya hecho artes marciales estará de acuerdo, una kata describe una serie de secuencias o movimientos preestablecidos que persiguen un fin. ¿Quién piensa que no se parece a una de las definiciones de algoritmo?

Una vez dicho todo esto, una kata de programación, no es más que un pequeño problema de programación que persigue resolver un problema en un tiempo finito de unos 30 o 40 minutos. El objetivo de estas katas es, por un lado, desarrollar nuestros propios algoritmos para resolver la kata en ese corto espacio de tiempos, y por otro lado, ver la solución que le da otra gente a ese mismo problema. Además, estas katas son independientes del lenguaje, con lo cual, cada uno puede solucionarlas en el lenguaje que mejor le parezca. Y para añadirle un poco más de emoción, se pueden implementer utilizando “Extreme Programming” por parejas.

A raíz de descubrir estas katas, he encontrado un página en Internet llamada “12 meses 12 katas”. El objetivo, como ellos dicen es:

Un mes una kata, ¡mejora tu arte y compártelo con los demás! Ese es el objetivo principal de esta iniciativa que nace de una comunidad preocupada por mejorar sus habilidades y así crear software de más calidad.

Yo he empezado recientemente con la implementación de estas, y por un lado me estoy divirtiendo mucho picando el código, y por otro, estoy aprendiendo cosillas viendo el código de los demás.

Os recomiendo que le echéis una ojeadilla si os gusta programar y tenéis poco tiempo para hacerlo.

Bueno, como siempre, si tenéis dudas, sugerencias y/o conocéis alguna otra página de katas, estaría bien debatirlo. Nos vemos.

Kiai – Katas

Bromas con PHP – Clonar Web

Si, lo se, este post no es nada serio, pero hay veces que estás conversando con alguien y no puedes evitar dejar correr la mente y hacer alguna tontería. Pues bien, hoy es uno de esos días. De un modo u otro, hoy ha salido el tema de como clonar una página web en nuestro propio servidor, no descargarla y tenerla offline, sino tener una página (una fuente) en php que sea capaz de hacerse pasar por la web clonada. Como la idea es solo hacer un pequeño experimente, pues hemos ido a lo básico, una página de un blog. Para el caso se ha elegido la de SecuritybyDefault (esperemos no se cabreen). Y la verdad es que los resultados han sido bastante mejores de lo esperado. Con solo un par de líneas hemos conseguido hacer un clon de ella. Solo de la página principal, pero si tuviéramos un formulario de registro, la petición se realizaría desde nuestro servidor (da que pensar). El código inicial ha sido algo así:

<? 
$html = file_get_contents('http://www.securitybydefault.com');
echo $html;
?>

Sorprendentemente, teníamos que nuestra página era capaz de reproducir la de securitybydefault a la perfección. Aquí, se ha comentado, que lo que primero suele hacer un usuario cuando accede a una página es navegar por sus links, con lo cual mediante el sistema creado hasta ahora, en cuento el usuario haga click en un enlace, volverá al dominio correcto.

Aquí, como primer experimento, hemos decidido coger una página html con varios enlaces. Por ejemplo, una así:

<html>
<head>
<title>pruebas</title>
</head>
<body>
<a href="www.google.com">Google(EN)</a><br />
<a href="www.google.es">Google(ES)</a><br />
<a href="www.yahoo.es">Yahoo</a><br />
<a href="www.microsoft.es">Microsoft</a><br />
</body>
</html>

Obviamente, si esta página la clonamos con nuestro sistema, en cuanto el usuario haga click en alguno de los enlaces, abandonará nuestro servidor para irse a uno de los correctos  ¿Cual es el problema? Los enlaces, deberíamos cambiar estos para hacer llamadas a nuestro clonador con las nuevas direcciones, así clonar la nueva página solicitada, pero permanecer en nuestro servidor.

Pues dicho, y sorprendentemente hecho.

<?
$url = $_POST['url'];
if(!empty($url)) {
$patternHref = "/href=\"(.*?)\"/is";
$html = file_get_contents($url);
$insertCode = "<script language=\"javascript\" type=\"text/javascript\">
function redirectUrl(destination) {
window.localtion.href = 'cloner.php?url=' + destination; }
</script></head>";
$htmlConstruida = str_replace("</head>", $insertCode, $html);
$matches = array();
preg_match_all($patternHref, $htmlConstruida, $matches);
for($i = 0; $i < count($matches[0]); $i++) {
$htmlConstruida = str_replace($matches[0][$i],
          "href=\"javascript:redirectUrl(" . $matches[1][$i] .");\"",
          $htmlConstruida);
}
echo $htmlConstruida;
}
else
{
?>      
<html><head><title>Cloner v0.1</title></head><body>
<form name="urlCloner" method="POST" action="cloner.php">
Url: <input type="text" name="url" size="60"/>
<input type="submit" value="Submit" />
</form></body></html>
<? } ?>

Como podéis ver lo único que se hace, es a través de expresiones regulares, hacer un par de inserciones y modificaciones en el código de la página que vamos a clonar, algo que no las afecte visualmente, pero si afecte su funcionamiento.

Una de las cosas que se hace es insertar una función javascript (redirectUrl) que llamará a nuestro clonador con una url que reciba. La otra modificación que se hace es la de remplazar los enlaces por llamadas a nuestra función manteniendo las url’s de estos.

De esta forma el ejemplo de página html que hemos visto antes, quedaría de está forma al clonarlo:

<html>
<head>
<title>pruebas</title>
<script language="javascript" type="text/javascript">
function redirectUrl(destination) {
window.localtion.href = 'cloner.php?url=' + destination; }
</script>
</head>
<body>
<a href="javascript:redirectUrl(www.google.com);">Google(EN)</a><br />
<a href="javascript:redirectUrl(www.google.es);">Google(ES)</a><br />
<a href="javascript:redirectUrl(www.yahoo.es);">Yahoo</a><br />
<a href="javascript:redirectUrl(www.microsoft.es);">Microsoft</a><br />
</body>
</html>

Ahora, aunque el usuario navegue por la página, seguirá estando en nuestro servidor sin tener que tener un montón de páginas almacenadas en él.

Como todo esto era un experimento para pasar el rato, y el rato ha pasado, pues aquí nos hemos quedado. Obviamente no creo que funcione en todas las páginas, ni que reconozca todos los enlaces, por ejemplo, aquellos que en vez de comillas dobles sean con comillas simples, solo sirve para navegar por partes públicas de la aplicación, ya que no clona sesiones ni ningún tipo de seguridad, los enlaces al pasar el ratón sobre ellos se ven modificados, etc… pero bueno, aquí lo dejo. Como se suele decir, es un experimento de laboratorio, donde todo esta controlado, no pasa de ser una curiosidad. Cualquiera es libre de coger el código y seguir jugando con él, y por supuesto de comentarlo aquí. Ya sabéis GPL y esas cosas. Nos vemos.

Bromas con PHP – Clonar Web

TryParse

Acabo de descubrir paseando por ahí y leyendo cosillas, una nueva incorporación a C# de .NET a partir de la aparición de “.NET Framework 2.0“.
Seguro que a más de uno se sonará haber escrito más de una vez algo así para convertir un string en algún tipo de valor:

string numero = "1";
int resultado = 0;

try {
    resultado = int.Parse(numero);
} catch (Exception e) {
    //Aquí el error
}

Bien pues esto se va a terminar con la llegada del “TryParse“. Este método devuelve true sí se ha podido realizar la conversión y false en caso contrario. además de conseguir en valor de la conversión realizada.

string numero = "1";
int resultado = 0;
if(!int.TryParse(numero, out resultado) //Aquí el error

Como se puede ver se recorta considerablemente el número de lineas necesarias además de clarificar, en mi opinión el código. Por supuesto, aunque el ejemplo esta hecho sobre un dato de tipo entero, se puede relalizar con todos o casi todos los tipos de datos; Boolean, Byte, DateTime, Char, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64.

Para mas información os recomiendo pasar por las páginas de MSDN Library.

Bueno, hoy espero haber contribuido a que el dicho ese de “nunca te acostarás sin aprender nada nuevo” se haya hecho realidad.

TryParse