jump to navigation

JSQL2iBatis: Generador de codigo de Acceso a Bases de Datos agosto 19, 2007

Posted by superpiwi in Eclipse, Java, Oracle, Programacion.
10 comments

jsql2ibatis.gif

Este es un post tecnico (para desarrolladores de Java). Si no eres desarrollador o simplemente no te interesa, no lo leas, en esta web tambien encontraras muchas mas cosas.

Hace unas 2 o 3 semanas que termine JSQL2iBatis, pero hasta ahora no he tenido tiempo para contar de que iba esto.

JSQ2iBatis es un generador de codigo para hacer mas facil el acceso a cualquier tipo de base de datos a la que puedas conectar mediante JDBC. Esta inspirado en SQL2iBatis, y es similar a Abator, pero quitando la complejidad de este ultimo pues es mas simple. No es perfecto, tiene “algunos” fallos pero a mi me viene bien, me esta ahorrando mucho “tiempo” de codificacion. Imaginate que tienes que mapear 28 tablas, antes tardaba 1 semana, ahora tengo el codigo en 1 dia.

Yo empece escribiendo JSQL2iBatis como una “tool” que me ayudara para otro proyecto mayor: Alexandria. Es un proyecto que empezare en breve y toda la capa de acceso a base de datos la codificara ayudandome de esta tool.

He liberado el codigo como licencia GNU, podeis usarla libremente, y mejorarlo (esto ultimo es lo que espero mas, pues he escrito el codigo en poco tiempo y se que tiene muchas chapuzas, pero al menos funciona que es lo que me interesaba).

Pero bueno, vayamos “a lo que interesa”, veamos como se usa.

La idea es simple, es tomar un fichero con las sentencias CREATE TABLE de la base de datos y a partir de ese fichero generar las clases JAVA y ficheros XML de SQL Mappings para mapear esas tablas. Veamoslo mejor con un ejemplo.

Primeramente vamos a crear una tabla USUARIOS en MYSQL.

root@soledad:/opt/lampp/bin# ./mysql -u root mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.0.37 Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> show tables
-> ;
+---------------------------+
| Tables_in_mysql |
+---------------------------+
| columns_priv |
| db |
| func |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| proc |
| procs_priv |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| user |
+---------------------------+
17 rows in set (0,00 sec)

Creamos una base de datos:

mysql> CREATE DATABASE TEST;
Query OK, 1 row affected (0,12 sec)
mysql> exit
Bye

Nos conectamos a la base de datos recien creada y creamos una tabla usuarios:

root@soledad:/opt/lampp/bin# ./mysql -u root TEST;
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.0.37 Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> show tables;
Empty set (0,00 sec)
mysql> CREATE TABLE USUARIOS (LOGIN VARCHAR(50),PASS VARCHAR(50),IMAGEN BLOB,PERFIL VARCHAR(1),PRIMARY KEY(LOGIN));
Query OK, 0 rows affected (0,01 sec)
mysql> SELECT * FROM USUARIOS;
Empty set (0,00 sec)

gedit01.jpg

Bien, tenemos la tabla creada en MySQL, y un fichero llamado “TABLE.sql” con las sentencias CREATE TABLE de esta tabla. He de advertir que no soporto tipos compuestos, del estilo NUMBER(10), cuando definas el fichero de DDL con las sentencias CREATE TABLE, unicamente has de indicar el tipo de la columna (VARCHAR,BLOB,NUMBER,etc..) pero no la precision.

Vamos a generar el codigo JAVA y los XML correspondientes. Para ello en el directorio raiz de JSQL2iBatis existe un script “execute.sh” que hemos de ejecutar con la siguiente sintaxis:

./execute.sh <nombre_package> <directorio_destino> <fichero_sql>

donde:

nombre_package: es el package de las clases Java que se generaran. (nota: he detectado un pequeño fallo que hace que no se generen 2 clases java auxiliares, para evitarlo debes emplear como nombre del package “com.sqlmap”, de esa manera esas clases se generaran, despues ya puedes cambiar el nombre del package al que quieras).

directorio_destino: es el directorio donde se genera el codigo de las clases java y el xml.

fichero_sql: es el fichero de DDL con las sentencias CREATE TABLE que queremos mapear.

Por ejemplo ejecutamos:

./execute.sh com.sqlmap /home/jose/Desktop/source TABLE.sql

generacodigo.jpg

Se generaran en la carpeta /home/jose/Desktop/source las clases correspondientes.

Que son: Usuarios.java, Usuarios.xml, SQLMapping.xml, MyProperties.properties,y 2 clases de apoyo para iBatis llamadas SQLMap y SQLMapPool.

Ya solo nos queda añadir el driver de Acceso a MySQL. Y cambiar el properties para que apunte a nuestra base de datos de MySQL:

# Propiedades para MySQL (Descomenta si usas esta bdatos en lugar de ORACLE)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/TEST
username=root
password=
activeConnections=010
idleConnections=5
maxWait=120000

properties.jpg

Tal vez tengas que editar el XML Usuarios.xml para ajustar el nombre de la tabla. MySQL es sensible a mayusculas y minusculas, no es lo mismo la tabla USUARIOS que la tabla Usuarios. En Oracle no es necesario hacer nada mas.

Pues bien, si has llegado a este punto. Se han generado de manera automatica todo lo necesario para acceder a la tabla Usuarios mediante iBatis. Veamos un ejemplo de codigo:
Podriamos acceder a la tabla de la siguiente manera:

//Para probar el funcionamiento de la clase
public static void main(String args[])
{
try
{
System.out.println("[iniciado]");
Usuarios test = new Usuarios();
test.setLogin("jose");
test.setPass("jose");
test.setImagen("OK".getBytes());
test.setPerfil("user");
test.insert();
System.out.println("[Finalizado]");
}
catch(Exception e)
{
e.printStackTrace();}
}
//----

ejemplo-de-uso-de-jsql2ibatis.png

Y el resultado:

root@soledad:/opt/lampp/bin# ./mysql -u root TEST
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.0.37 Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> select * from USUARIOS;
+-------+------+--------+--------+
| LOGIN | PASS | IMAGEN | PERFIL |
+-------+------+--------+--------+
| jose | jose | OK | u |
+-------+------+--------+--------+
1 row in set (0,00 sec)

consulta1.jpg

YATA!!! que sencillo no?, no has tenido que escribir la clase Java de acceso a la tabla Usuarios y ya tienes una clase que te permite hacer INSERT, UPDATE, DELETES y mas operaciones. Incluso soporta insercion y recuperacion de BLOBS y todo…

Que guay!!!, y si no te gusta o quieres cambiar la SQL, solo tienes que editar el fichero Usuarios.xml.

Simple y Sencillo.

Pues ahora en vez de una tabla, escribe un fichero TABLE.sql con 28 tablas. A que mola!!! se acabo el escribir una por una el codigo de acceso Java a cada una de esas tablas.

Se que no es perfecto, pero esta basado en plantillas VELOCITY asi que facilmente cambiando las plantillas puedes generar tu propio codigo.

Espero que sea de utilidad. Puedes encontrar mas detalles en el fichero README que incluyo con la distribucion.

Referencias: iBatis Framework

Ejecutar multiples sentencias SQL con iBatis May 14, 2007

Posted by superpiwi in Eclipse, Java, Oracle, Programacion.
add a comment

Proximamente (todo depende del tiempo que me quede disponible) escribire una serie de tutoriales introductorios de iBatis. De todas formas aqui os comento algo que no esta del todo muy documentado y que puede servir a aquellas personas que ya emplean este framework.

El caso es para Oracle 10. Si necesitas ejecutar varias sentencias SQL debes escribir en el XML algo parecido a lo siguiente (es solo un ejemplo, adaptalo a tu caso particular):

<statement id="borrarDatos" parameterClass="comun.beans.Project" >
<![CDATA[
BEGIN
DELETE FROM TABLA1 WHERE PROJECT=#id#;
DELETE FROM TABLA2 WHERE PROJECT=#id#;
DELETE FROM TABLA3 WHERE PROJECT=#id#;
DELETE FROM TABLA4 PROJECT=#id# AND SID<>'0';
END;
]]>
</statement>

Despues lo ejecutariamos mediante un «update» por ejemplo:


Project p = new Project();
p.setId("666");
SQLMap.update("borrarDatos",p);

En resumen, empleamos el tagname <statement></statement> y encerramos las sentencias SQL separadas por ; y entre los elementos BEGIN y END;

Mas informacion | OpenSource

Shell Script – Consulta de Oracle almacenando el resultado en un Array abril 25, 2007

Posted by superpiwi in Java, Oracle, Programacion, Unix.
7 comments

Aqui un pequeño script que uso cuando realizo una consulta a Oracle y quiero guardar los resultados de la consulta en un Array de variables de un Shell Script para su posterior tratamiento.

consulta.sh


#!/bin/bash
#------------------------------------------------------------------------------
# EJEMPLO EN SHELL SCRIPT DE CONSULTA A ORACLE DEVOLVIENDO RESULTADO EN UN
# ARRAY DE VARIABLES
#
# @author
# @revision 10 Ago 2006
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# read_sql_stmt
#
# la funcion empleada para conectar a oracle y ejecutar la consulta
# @param stmt la sentencia SQL a ejecutar
# @param login la cadena de conexion a la base de datos en formato usuario/password@SID
#------------------------------------------------------------------------------
read_sql_stmt() {
typeset stmt=$1
typeset login=$2
echo "
set feedback off verify off heading off pagesize 0
$stmt;
exit
" | sqlplus -s $login
}
#------------------------------------------------------------------------------
echo "[ ->COMIENZO<- ]"
ORACLE_HOME=/usr/lib/oracle/10.2.0.3/client
PATH=$ORACLE_HOME/bin:$PATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
#No es necesario especificar TNS_ADMIN ya apunta por defecto
#TNS_ADMIN=$ORACLE_HOME/network/admin
export ORACLE_HOME
export PATH
export LD_LIBRARY_PATH
#
# En este ejemplo hacemos un select recorremos los resultados y los devolvemos
# en un array de variables compuesta por cadenas separadas por el token ","
# La consulta es sobre una tabla de ORACLE de mi modelo datos, cambia la sentencia
# SQL por la que utilices
#
CADENA_CONEXION="desa/desa@DESARROLLO"
export CADENA_CONEXION
echo "CADENA CONEXION $CADENA_CONEXION"
# Ejecutamos la consulta y devolvemos la fila de resultados en un ARRAY
# NOTA: aqui hay 2 columnas y hacemos un read $var1 $var2, si hubiera mas columnas deberias añadir mas variables de control $varN
ARRAY_1=(`read_sql_stmt "select login,password from STCORE_USER" $CADENA_CONEXION | while read var1 var2
do
#echo "$i||$n"
#exho "$i:$n"
#echo "$i\"$n"
#para el ejemplo tokenizamos las columnas separandolas con | y repitiendo la primera en la tercera
#echo "$i|$n|$i"
echo "login:{$var1},password:{$var2},$var1"
done`)
# Recorrer Todos, Recorremos el Array y generamos una traza de ejemplo que nos interese
echo "[ Procesar todos ]:"
for i in ${ARRAY_1[@]}; do
echo "__RESPUESTA__|Query1_Login|$i" >> consulta.log
done
cat ./consulta.log
rm ./consulta.log
# Otra forma de recorrer todos
# puede emplearse * en lugar de @
echo ""
echo "[ Otra forma de Todos ]:"
echo ${ARRAY_1[*]}
# Contar el numero de elementos
# (Loop until we find an empty string.)
count=0
while [ "x${ARRAY_1[count]}" != "x" ]
do
count=$(( $count + 1 ))
done
echo ""
echo "[ Numero de elementos del Array ]:"
echo "Hay $count Elementos en el array"
echo ""
echo "[ Consulta de elementos del array por el indice ]:"
echo "El Primero es: ${ARRAY_1[0]}"
echo "0 OK"
echo "[ FIN ]"

El shell script esta comentado con lo que facilmente puedes adaptarlo a tus propias consultas.

Realmente estoy realizando una consulta por los campos «login» y «password» de una tabla denominada «STCORE_USER» y al final genero un fichero con este formato:

__RESPUESTA__|Query1.login|login:{aqui la primera columna},password:{aqui la segunda},primera_columna

Al ejecutarlo en mi caso tengo un output como este:

jose@soledad:~/Desktop$ ./consulta.sh
[ ->COMIENZO<- ]
CADENA CONEXION desa/desa@DESARROLLO
[ Procesar todos ]:
__RESPUESTA__|Query1_Login|login:{admin},password:{admin},admin
__RESPUESTA__|Query1_Login|login:{test},password:{test},test
[ Otra forma de Todos ]:
login:{admin},password:{admin},admin login:{test},password:{test},test
[ Numero de elementos del Array ]:
Hay 2 Elementos en el array
[ Consulta de elementos del array por el indice ]:
El Primero es: login:{admin},password:{admin},admin
0 OK
[ FIN ]
jose@soledad:~/Desktop$

Generar la documentacion del Modelo de Datos abril 24, 2007

Posted by superpiwi in Eclipse, Java, Oracle, Programacion, UML.
add a comment

Generar la documentacion del Modelo de Datos

Migrar de Oracle a MySQL empleando MySQL Migration Toolkit abril 20, 2007

Posted by superpiwi in Eclipse, Java, Oracle, Programacion.
add a comment

Estaba desarrollando unas clases para migrar desde Oracle a MySQL a partir de un proyecto que me encontre, pero he encontrado otra solucion y dejare aparcado de momento este tema.La otra forma en la que lo he conseguido la comento aqui:

Migrar de Oracle a MySQL

Output HTML desde SQL*Plus abril 18, 2007

Posted by superpiwi in Oracle, Programacion.
1 comment so far

En decipherinfosys me encuentro un truco para Oracle muy interesante.

Generalmente cuando lanzamos una consulta con SQL*plus y capturamos la salida, el resultado es un fichero de texto. Pero si nos interesa podemos convertirlo a HTML.

Aqui un ejemplo:


SET PAGESIZE 50 LINESIZE 120 VERIFY OFF ECHO OFF TRIMSPOOL ON TRIMOUT ON FEEDBACK OFF
SET MARKUP HTML ON
SPOOL table_list.html
PROMPT
PROMPT
PROMPT Table List Report
PROMPT =================
COLUMN table_name HEADING ‘Table|Name’ FORMAT a30
COLUMN tablespace_name HEADING ‘Tablespace|Name’ FORMAT a30
COLUMN row_count HEADING ‘Total|Rows’ FORMAT 99G999G999
COLUMN avg_row_len HEADING ‘Average|Row Length’ FORMAT 9999999999
COLUMN last_analyzed HEADING ‘Analyze|Date’ FORMAT a20
COLUMN monitoring HEADING ‘Table|Monitored’ FORMAT a9
SELECT table_name, tablespace_name,num_rows,avg_row_len,last_analyzed,
monitoring
FROM user_tables
ORDER BY TABLE_NAME ASC
/
CLEAR COLUMNS
SPOOL OFF
SET MARKUP HTML OFF

Guarda este script a un fichero por ejemplo llamado table_list.sql, Ahora te conectas a tu base de datos y lo ejecutas.

$ sqlplus user/password@SID
$ @./ruta_al_fichero/table_list.sql

Automaticamente se crea un fichero table_list.html con el resultado de la consulta ejecutada.

Modelado de bases de datos con Linux abril 12, 2007

Posted by superpiwi in Eclipse, Java, Oracle, Programacion.
1 comment so far

Modelado de bases de datos con Linux

oerr – Obtener la descripcion de un mensaje de error de Oracle marzo 22, 2007

Posted by superpiwi in Java, Oracle, Programacion, Unix.
2 comments

oerr (Oracle error utility) es un shell script que se instala en las bases de datos de Oracle y unicamente en las plataformas UNIX. Nos sirve para obtener rapidamente la descripcion de un error a partir de su codigo.


$(manager): /manager > oerr
Usage: oerr facility error
Facility is identified by the prefix string in the error message.
For example, if you get ORA-7300, "ora" is the facility and "7300"
is the error. So you should type "oerr ora 7300".
If you get LCD-111, type "oerr lcd 111", and so on.
$(manager): /manager > oerr ora 1000
01000, 00000, "maximum open cursors exceeded"
// *Cause:
// *Action:

Para windows existen alternativas.

http://www.oracleutilities.com/OSUtil/oerr.html

http://www.jlcomp.demon.co.uk/faq/windowsoerr.htm

Tambien para encontrar la descripcion del error puedes utilizar un buscador como Google, pero lo anterior te sirve cuando no siempre tienes acceso a Internet.

Ejecutar Shell Scripts desde Java marzo 14, 2007

Posted by superpiwi in Java, Oracle, Programacion, Unix.
13 comments

Y ya que hemos hablado en el Post anterior de Shell Scripts, porque no ejecutarlos directamente desde codigo fuente con Java. Antes de nada recomiendo una lectura:

When Runtime.exec() won’t

En este caso he creado una clase propia «Script.java» y he adaptado la del ejemplo que aparece en el articulo anterior.

Esta clase Script nos permite ejecutar comandos y shell scripts empleando el interprete de comandos.

Por ejemplo el siguiente codigo:


Script sc = new Script();
sc.setVerbose(true);
String CONTENT = "sqlplus2\nls -l\nps\necho \"End\\nFin\"";
String OUTPUT = sc.executeScript(CONTENT,
"/home/jose/Desktop/MiScript.sh", true);
System.out.println(OUTPUT);
String ERROR = sc.getError();
System.out.println("**ERROR**" + ERROR);

Como observais estoy lanzando la ejecucion de estos tres comandos:


sqlplus2 (que no existe y dara error)
ls -l
ps
y un echo End salto de linea Fin

Al ejecutar este codigo desde java nos devolveria lo siguiente:


ERROR> /home/jose/Desktop/MiScript.sh: 1: sqlplus2: not found
OUTPUT> total 44
OUTPUT> drwxr-xr-x 3 jose jose 4096 2007-01-11 09:18 ant
OUTPUT> drwxr-xr-x 6 jose jose 4096 2007-02-01 17:34 build
OUTPUT> -rw-r--r-- 1 jose jose 12953 2007-02-01 17:34 build.xml
OUTPUT> drwxr-xr-x 2 jose jose 4096 2007-01-11 09:17 CVS
OUTPUT> drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 Documentacion
OUTPUT> drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 JavaSource
OUTPUT> -rwxr-xr-x 1 jose jose 111 2007-03-14 17:13 pepe.sh
OUTPUT> drwxr-xr-x 11 jose jose 4096 2007-02-20 15:52 WebContent
OUTPUT> PID TTY TIME CMD
OUTPUT> 4887 ? 00:00:00 gconfd-2
OUTPUT> 11652 ? 00:00:00 x-session-manag
OUTPUT> 11665 ? 00:00:02 Scribe.exe <defunct>
OUTPUT> 11693 ? 00:00:00 ssh-agent
OUTPUT> 11696 ? 00:00:00 dbus-daemon
OUTPUT> 11697 ? 00:00:00 dbus-launch
OUTPUT> 11700 ? 00:00:00 gnome-keyring-d
OUTPUT> 11703 ? 00:00:03 gnome-settings-
OUTPUT> 11727 ? 00:00:27 metacity
OUTPUT> 11732 ? 00:00:23 gnome-panel
OUTPUT> 11734 ? 00:00:15 nautilus
OUTPUT> 11738 ? 00:00:00 bonobo-activati
OUTPUT> 11741 ? 00:00:00 gnome-vfs-daemo
OUTPUT> 11747 ? 00:00:00 update-notifier
OUTPUT> 11749 ? 00:00:00 gnome-volume-ma
OUTPUT> 11751 ? 00:00:00 evolution-alarm
OUTPUT> 11759 ? 00:00:10 trackerd
OUTPUT> 11762 ? 00:00:15 gnome-cups-icon
OUTPUT> 11774 ? 00:00:02 python
OUTPUT> 11776 ? 00:00:00 trashapplet
OUTPUT> 11779 ? 00:00:00 evolution-data-
OUTPUT> 11803 ? 00:00:00 evolution-excha
OUTPUT> 11833 ? 00:00:00 mapping-daemon
OUTPUT> 11834 ? 00:00:00 gnome-power-man
OUTPUT> 11843 ? 00:00:00 mixer_applet2
OUTPUT> 11885 ? 00:00:02 notification-da
OUTPUT> 11912 ? 00:00:05 gnome-screensav
OUTPUT> 12025 ? 00:01:49 skype
OUTPUT> 12094 ? 00:04:30 firefox-bin
OUTPUT> 12270 ? 00:00:00 eclipse
OUTPUT> 12276 ? 00:03:44 java
OUTPUT> 14360 ? 00:00:03 gnome-terminal
OUTPUT> 14369 ? 00:00:00 gnome-pty-helpe
OUTPUT> 14597 ? 00:01:59 wineserver
OUTPUT> 14599 ? 00:00:00 explorer.exe
OUTPUT> 17598 ? 00:00:00 java
OUTPUT> 17617 ? 00:00:00 sh
OUTPUT> 17618 ? 00:00:00 sh
OUTPUT> 17622 ? 00:00:00 ps
OUTPUT> End
OUTPUT> Fin
total 44
drwxr-xr-x 3 jose jose 4096 2007-01-11 09:18 ant
drwxr-xr-x 6 jose jose 4096 2007-02-01 17:34 build
-rw-r--r-- 1 jose jose 12953 2007-02-01 17:34 build.xml
drwxr-xr-x 2 jose jose 4096 2007-01-11 09:17 CVS
drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 Documentacion
drwxr-xr-x 7 jose jose 4096 2007-01-11 09:17 JavaSource
-rwxr-xr-x 1 jose jose 111 2007-03-14 17:13 pepe.sh
drwxr-xr-x 11 jose jose 4096 2007-02-20 15:52 WebContent
PID TTY TIME CMD
4887 ? 00:00:00 gconfd-2
11652 ? 00:00:00 x-session-manag
11665 ? 00:00:02 Scribe.exe <defunct>
11693 ? 00:00:00 ssh-agent
11696 ? 00:00:00 dbus-daemon
11697 ? 00:00:00 dbus-launch
11700 ? 00:00:00 gnome-keyring-d
11703 ? 00:00:03 gnome-settings-
11727 ? 00:00:27 metacity
11732 ? 00:00:23 gnome-panel
11734 ? 00:00:15 nautilus
11738 ? 00:00:00 bonobo-activati
11741 ? 00:00:00 gnome-vfs-daemo
11747 ? 00:00:00 update-notifier
11749 ? 00:00:00 gnome-volume-ma
11751 ? 00:00:00 evolution-alarm
11759 ? 00:00:10 trackerd
11762 ? 00:00:15 gnome-cups-icon
11774 ? 00:00:02 python
11776 ? 00:00:00 trashapplet
11779 ? 00:00:00 evolution-data-
11803 ? 00:00:00 evolution-excha
11833 ? 00:00:00 mapping-daemon
11834 ? 00:00:00 gnome-power-man
11843 ? 00:00:00 mixer_applet2
11885 ? 00:00:02 notification-da
11912 ? 00:00:05 gnome-screensav
12025 ? 00:01:49 skype
12094 ? 00:04:30 firefox-bin
12270 ? 00:00:00 eclipse
12276 ? 00:03:44 java
14360 ? 00:00:03 gnome-terminal
14369 ? 00:00:00 gnome-pty-helpe
14597 ? 00:01:59 wineserver
14599 ? 00:00:00 explorer.exe
17598 ? 00:00:00 java
17617 ? 00:00:00 sh
17618 ? 00:00:00 sh
17622 ? 00:00:00 ps
End
**ERROR**/home/jose/Desktop/MiScript.sh: 1: sqlplus2: not found

Sencillo y potente!!!

Tambien permite ejecutar shell scripts creandolos dinamicamente. esto por ejemplo nos sirve para lanzar scripts que solo contienen sentencias SQL. Por ejemplo el siguiente caso:


Script sql = new Script();
sql.setVerbose(false);
sql.setAddSHELLHEADER(true);
sql.setSHELLHEADER("#!/bin/sh");
//sql.setRUTA("/home/jose/Desktop");
CONTENT = "SELECT sysdate FROM DUAL;\nSELECT sysdate FECHA_HOY FROM DUAL;";
OUTPUT = sql.executeSQLScript(CONTENT, "EVO", "EVO", "EVODES",
null, "/home/jose/Desktop/MiSQL.sh", false);
System.out.println(OUTPUT);
ERROR = sql.getError();
System.out.println("**ERROR**" + ERROR);

Que nos devolveria:


SQL*Plus: Release 10.2.0.3.0 - Production on Wed Mar 14 17:38:06 2007
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
SQL>
SYSDATE
---------
14-MAR-07
SQL>
FECHA_HOY
---------
14-MAR-07
SQL> Disconnected from Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
**ERROR**

Aqui el truco es generar dinamicamente un fichero .sh con el contenido que se quiere ejecutar y luego lanzar el interprete de comandos para ejecutar ese fichero creado dinamicamente.

Pero mejor veis las clases y ya trasteais con ellas. Aqui las dejo.

StreamGlobber.java


/**
* StramGobbler.java
*
* Para capturar la salida de la ejecucion del comando.
*
* @modified clase original de javaworld modificada por jdelgado
* @version 0.0.0.2 - 13 Marzo 2007
* @sinde JDK 1.5 - Eclipse 3.2
*/
package comun.util.unix;
import java.io.*;
class StreamGobbler extends Thread {
// Flujo de entrada
InputStream is;
// Tipo de Flujo: generalmente output o error
String type;
// Flujo de salida
OutputStream os;
// Variable para mostrar por la salida estandard
boolean debug = false;
// para guardar la salida generada
String output = "";
// ----
/**
* Constructor
*
* @param is
* InputStream
* @param type
* tipo de flujo (OUTPUT o ERROR)
* @param debug
* indica si se debe mostrar o no la salida por la salida
* estandard
*/
StreamGobbler(InputStream is, String type, boolean debug) {
this(is, type, null, debug);
}
// ----
/**
* Constructor
*
* @param is
* InputStram
* @param type
* tipo de flujo (OUTPUT o ERROR)
* @param redirect
* OutputStream donde redireccionar la salida
* @param debug
* indica si se debe mostrar o no la salida por la salida
* estandard
*/
StreamGobbler(InputStream is, String type, OutputStream redirect,
boolean debug) {
this.is = is;
this.type = type;
this.os = redirect;
this.debug = debug;
}
// ----
/**
* Ejecutar el hilo
*/
public void run() {
try {
PrintWriter pw = null;
if (os != null)
pw = new PrintWriter(os);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
// si hay fichero lo imprime a fichero
if (pw != null)
pw.println(line);
if (debug)
System.out.println(type + "> " + line);
output = output + line + "\r\n";
}
if (pw != null)
pw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// ------
/**
* Recuperar el flujo de datos generado
*
* @return un String con el output
*/
public String getOutput() {
return output;
}
// ------
}
// end of class StreamGobbler.java

y la clase Script.java:


/**
* Script.java
*
* Clase para ejecutar scripts unix o SQL localmente
*
* @author jdelgado
* @version 0.0.0.1 - 13 Marzo 2007
* @since JDK 1.5 - Eclipse 3.2
*
*/
package comun.util.unix;
import java.io.File;
import java.io.FileOutputStream;
public class Script {
// contenido a ejecutar
private String content = null;
// interprete de comandos: Si usas Windows adaptalo para usar CMD
private String SHELL = "/bin/sh";
// resultado de la ejecucion
private String output = null;
// posibles errores en la ejecucion
private String error = null;
// imprimir o no traza en los threads
private Boolean verbose = false;
// path por defecto para ficheros temporales
private String RUTA = "/tmp";
// cabecera para shell scripts
private String SHELLHEADER = "#!/bin/sh";
// indica si hay que añadir el interprete a los shell scripts que se generen
private boolean addSHELLHEADER = false;
// caracter de retorno
private String RETORNO = "\n";
// ----
/**
* Constructor. crea una nueva instancia de la clase
*/
public Script() {
}
// ----
/**
* Constructor. crea una nueva instancia de la clase
*
* @param content
* contenido del script a ejecutar
*/
public Script(String content) {
this.content = content;
}
// ----
/**
* Ejecuta el script
*
* @throws Exception
* excepcion levantada en caso de error
*/
public String executeCommand() throws Exception {
output = null;
error = null;
StreamGobbler errorGobbler = null;
StreamGobbler outputGobbler = null;
try {
if (content == null)
throw new Exception("command is null");
// String ruta="/home/jose/Desktop/temporal.txt";
// FileOutputStream fos = new FileOutputStream(ruta);
Runtime rt = Runtime.getRuntime();
// Process proc = rt.exec(new String[]{"/bin/sh", "-c", "cd
// /home/jose/Desktop\n./SQLPLUS.sh\ncal\\nps -ef"});
String[] data = new String[3];
data[0] = this.SHELL;
data[1] = "-c";
data[2] = this.content;
Process proc = rt.exec(data);
// any error message?
errorGobbler = new StreamGobbler(proc.getErrorStream(), "ERROR",
this.verbose);
// any output?
outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT",
null, this.verbose);
// StreamGobbler(proc.getInputStream(), "OUTPUT", fos);
// kick them off
errorGobbler.start();
outputGobbler.start();
// any error???
int exitVal = proc.waitFor();
} catch (Throwable t) {
t.printStackTrace();
} finally {
String out = outputGobbler.getOutput();
this.output = out;
output = out;
out = errorGobbler.getOutput();
this.error = out;
error = out;
}
return output;
}
// ----
/**
* Recupera la salida de la ejecucion del comando
* @return un string con el resultado de la ejecucion
*/
public String getOutput() {
return output;
}
// ----
/**
* Recupera el error de la ejecucion del comando
* @return un string con el error de la ejecucion
*/
public String getError() {
return error;
}
// ----
/**
* Ejecuta un Script creando un fichero .sh con el contenido y ejecutandolo
*
* @param content
* contenido del script
* @param pathname
* el nombre del fichero que se crea si es null lo crea en /tmp y
* de la forma /tmp/timestamp.sh
* @param delete
* indica si se debe borrar o no el fichero temporal tras su
* ejecucion
* @result el resultado de la ejecucion del Script
* @throws Exception
* Excepcion levantada en caso de error
*/
public String executeScript(String content, String pathname, boolean delete)
throws Exception {
File f = null;
FileOutputStream fout = null;
try {
// crear fichero .sh
if (pathname == null) {
long timestamp = System.currentTimeMillis();
pathname = RUTA + File.separator + timestamp + ".sh";
}
if (this.addSHELLHEADER)
{
content = this.SHELLHEADER+this.RETORNO+content;
}
traza("executeScript","Generando fichero [" + pathname + "]...");
f = new File(pathname);
fout = new FileOutputStream(f);
fout.write(content.getBytes());
if (fout != null)
fout.close();
traza("executeScript","Fichero generado");
// darle permisos de ejecucion
traza("executeScript","Asignando permisos...");
Script permisos = new Script("chmod +x " + pathname);
permisos.setVerbose(this.verbose);
permisos.executeCommand();
String error = permisos.getError();
if (error != null) {
if (error.length() > 0)
throw new Exception("Permission denied : " + error);
}
traza("executeScript","Permisos asignados");
// ejecutar fichero .sh
traza("executeScript","Ejecutando script...");
Script ejecucion = new Script(pathname);
ejecucion.setVerbose(this.verbose);
String result = ejecucion.executeCommand();
error = ejecucion.getError();
this.error = error;
this.output = result;
traza("executeScript","Script ejecutado");
// eliminar fichero .sh
if (delete) {
if (f != null) {
if (f.exists())
f.delete();
}
traza("executeScript","fichero eliminado");
}
return result;
} catch (Exception e) {
throw e;
}
}
// ----
/**
* Para probar el correcto funcionamiento de la clase
* @param args argumentos de entrada
*/
public static void main(String[] args) {
try {
// sqlplus directamente no mejor ejecutar sh shellscript.sh que tenga el
// contenido
// Script sc = new Script("ls -l\ncal2\nps -ef | grep
// java\nsqlplus");
// sc.setDebug(false);
// String output = sc.executeCommand();
// System.out.println("OUT:-------------------\r\n"+output);
// String error = sc.getError();
// System.out.println("ERROR:-----------------\r\n"+error);
// output = sc.getOutput();
// System.out.println("output:\r\n"+output);
// System.out.println("***ERROR***");
// String err = sc.getError();
// System.out.println("error:"+err);
Script sc = new Script();
sc.setVerbose(true);
String CONTENT = "sqlplus2\nls -l\nps\necho \"End\\nFin\"";
String OUTPUT = sc.executeScript(CONTENT,
"/home/jose/Desktop/MiScript.sh", true);
System.out.println(OUTPUT);
String ERROR = sc.getError();
System.out.println("**ERROR**" + ERROR);
Script sql = new Script();
sql.setVerbose(false);
sql.setAddSHELLHEADER(true);
sql.setSHELLHEADER("#!/bin/sh");
//sql.setRUTA("/home/jose/Desktop");
CONTENT = "SELECT sysdate FROM DUAL;\nSELECT sysdate FECHA_HOY FROM DUAL;";
OUTPUT = sql.executeSQLScript(CONTENT, "EVO", "EVO", "EVODES",
null, "/home/jose/Desktop/MiSQL.sh", false);
System.out.println(OUTPUT);
ERROR = sql.getError();
System.out.println("**ERROR**" + ERROR);
} catch (Exception e) {
e.printStackTrace();
}
}
// ----
/**
* Completa un script de SQL para poder ejecutarlo con sqlplus desde un
* shell script
*
* @param sqlcontent
* sentencias SQL
* @param user
* usuario de base de datos
* @param password
* password de la base de datos (TODO: guardar encriptada)
* @param sid
* sid de la base de datos
* @param redirect
* si se indica es el fichero donde se redirecciona la salida del
* sqlplus
* @return un string con el sqlplus
*/
public String prepareSQLScript(String sqlcontent, String user,
String password, String sid, String redirect) {
if (redirect == null)
redirect = "";
else
redirect = "> " + redirect;
String INICIO_SQL = "sqlplus " + user + "/" + password + "@" + sid
+ " << EOF" + " " + redirect;
String FIN_SQL = "EOF";
String sql = sqlcontent;
sql = INICIO_SQL + RETORNO + sql + RETORNO + "exit" + RETORNO + FIN_SQL;
return sql;
}
// ----
/**
* Ejecuta un Script SQL mediante sqlplus
*
* @param sqlcontent
* las sentencias SQL
* @param user
* usuario de la base de datos
* @param password
* la password de la base de datos
* @param redirect
* si se indica es el fichero donde se redirecciona la salida del
* sqlplus
* @param pathname
* nombre del shell script que se crea
* @param delete
* indica si se debe borrar o no el shell script tras la
* ejecucion
* @return el resultado de la ejecucion del script
*/
public String executeSQLScript(String sqlcontent, String user,
String password, String sid, String redirect, String pathname,
boolean delete) throws Exception {
String SQL_CONTENT = prepareSQLScript(sqlcontent, user, password, sid,
redirect);
return executeScript(SQL_CONTENT, pathname, delete);
}
// ----
/**
* Recupera el valor del flag
* @return el valor del flag
*/
public Boolean getVerbose() {
return verbose;
}
// ----
/**
* Fija el valor del flag para mostrar por la consola estandard la ejecucion
* @param debug el valor del flag
*/
public void setVerbose(Boolean debug) {
this.verbose = debug;
}
// ----
/**
* Para imprimir un mensaje de traza
*
* @param metodo
* nombre del metodo
* @param mensaje
* nombre de la clase
*/
public void traza(String metodo, String mensaje) {
// TODO: reemplazar aqui para emplear LOG4J
// System.out.println(mensaje);
}
// ----
public boolean isAddSHELLHEADER() {
return addSHELLHEADER;
}
public void setAddSHELLHEADER(boolean addSHELLHEADER) {
this.addSHELLHEADER = addSHELLHEADER;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getRETORNO() {
return RETORNO;
}
public void setRETORNO(String retorno) {
RETORNO = retorno;
}
public String getRUTA() {
return RUTA;
}
public void setRUTA(String ruta) {
RUTA = ruta;
}
public String getSHELL() {
return SHELL;
}
public void setSHELL(String shell) {
SHELL = shell;
}
public String getSHELLHEADER() {
return SHELLHEADER;
}
public void setSHELLHEADER(String shellheader) {
SHELLHEADER = shellheader;
}
public void setError(String error) {
this.error = error;
}
public void setOutput(String output) {
this.output = output;
}
}
// end Script.java

Pueden ser de utilidad cuando queremos automatizar tareas (ejecucion automatica de shell scripts) y no queremos meternos en mucha faena escribiendolos en ANT. Pero bueno, de esto ya hablaremos otro dia…

shell.jpg

Algunas formas de ejecutar sqlplus desde un Shell Script marzo 14, 2007

Posted by superpiwi in Java, Oracle, Programacion, Unix.
32 comments

Aqui un pequeño Tip. Imaginate que tienes una base de datos llamada DESA en tu tnsnames.ora y es de la forma:


DESA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = DESA)
)
)

Para un usuario de base de datos DESA con password DESA.

Desde linea de comandos una forma de ejecutar sentencias sql es mediante SQLPLUS. Tu abririas la session con:

sqlplus desa/desa@DESA (es de la forma user/password@SID)

y ya podrias empezar a escribir las sentencias SQL, cuando quisieras terminar teclearias el comando «exit» y terminarias la sesion con sqlplus. Si quisieramos hacer lo mismo pero desde un shell script podriamos hacer lo siguiente (presentare varias formas, no se si habra mas pero estas pueden serte de utilidad).

La primera es mediante el comando echo:


echo "lista de sentencias SQL....separadas con \n" | sqlplus desa/desa@DESA

Por ejemplo:


#!/bin/sh
echo "SELECT sysdate FROM DUAL;\nSELECT sysdate FECHA FROM DUAL" | sqlplus desa/desa@DESA


(\n es el retorno de carro, es como si pulsaramos la tecla Intro, para ir separando las diferentes sentencias SQL)

Otra opcion es la misma pero en vez de pasarle un listado con las sentencias le indicamos con el operador @ la ruta de un fichero sql con las sentencias (no te olvides de acabar con un commit; y/o exit; si fuera necesario).

echo "@/ruta fichero sql" | sqlplus user/password@bd

Ejemplo:


#!/bin/sh
echo "@/home/jose/sqls/insertar.sql" | sqlplus desa/desa@DESA

Arrancaria una sesion de sqlplus y ejecutaria el contenido del fichero «/home/jose/sqls/insertar.sql»

y la ultima y generalmente mas usada es la siguiente:


sqlplus user/pass@BD << ETIQUETA > redireccion
sentencias SQL...
ETIQUETA

Por ejemplo:


#!/bin/sh
sqlplus desa/desa@DESA << EOF > ./output.log
SELECT sysdate FROM DUAL;
SELECT sysdate FECHA FROM DUAL;
EOF

Ejecutaria todas las sentencias SQL entre ETIQUETA y fin de ETIQUETA. En este ultimo caso, Al ejecutar el script, desde la consola, obtenemos lo siguiente:


SQL*Plus: Release 10.2.0.3.0 - Production on Wed Mar 14 14:05:08 2007
Copyright (c) 1982, 2006, Oracle. All Rights Reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
SQL>
SYSDATE
---------
14-MAR-07
SQL>
FECHA
---------
14-MAR-07
SQL> Disconnected from Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production
With the Partitioning option
JServer Release 9.2.0.8.0 - Production
jose@soledad:~/Desktop$

Es util para construirnos nuestros shell script y poder modificar el modelo de datos de la base de datos ejecutandolos desde un terminal.