jump to navigation

Plantillas en JavaScript febrero 28, 2007

Posted by superpiwi in Javascript.
add a comment

Una funcionalidad muy buena de prototype es la de permitirnos usar plantillas en javascript.
Un ejemplo sencillo:

/**

* Devuelve el texto formateado del usuario (utiliza una plantilla de javascript)

* @param user objeto con los datos del usuario

* @return una cadena con los datos del usuario preparados para presentar en formato HTML

*/

function returnar(user)

{

//Ejemplo de plantilla en javascript

var syntax = /(^|.|r|n)(<%=s*(w+)s*%>)/; //matches symbols like '<%= field %>'

var t = new Template('<div>Nombre: <b><%= name %></b>, Email: <b><%=email%></b></div>', syntax);

//a = t.evaluate( {name: 'John Doe', email: 'john@doe.es'} );

return t.evaluate(user);

//alert(a);

}

//----// datos del usuario

usuario = {name: 'John Doe', email: 'john@doe.es'};

user_html = returnar(usuario);

// texto formateado

alert("recuperado:"+user_html);

Al evaluarlo nos devolvera lo siguiente:

Nombre: John Doe, Email: john@doe.es

StringTokenizer modificado para usar multiples caracteres febrero 28, 2007

Posted by superpiwi in Java.
3 comments

He tenido que hacer una clase muy rapida para tokenizar cadenas cuando el delimitador no es de un solo caracter sino que esta compuesto por multiples caracteres. El tema es que tenia que pasar una serie de parametros compuestos y una de dos, o modificaba el Stringtokenizer para poder parsearlos correctamente o cambiaba la forma de enviar los parametros (por ejemplo usando JSon).

Imaginate que tienes una cadena con estos valores:

valor1=1|2|3 ||| valor2=3|4|5 ||| valor3=0

Si utilizas el StringTokenizer normal :

StringTokenizer st=new StringTokenizer(cadena,"|||");

Realmente no es correcto, porque no le estas indicando que tokenize por la cadena “|||” sino que use 3 tokenizadores de 1 caracter que son el mismo “|”. Asi que al recuperar los tokens obtienes;


valor1=1
2
3
valor2=3
4
5
valor3=0

Con esta clase que he implementado y usando el delimitador “|||” ya se tokeniza de manera correcta.


valor1=1|2|3
valor2=3|4|5
valor3=0

Aqui el código (no esta optimizado porque he tenido poco tiempo era más una solución para salir del paso).


/**
* MiStringTokenizer
*
* Sencilla clase para poder tokenizar por mas de un caracter.
* Ejemplo:
*
* 1 | 2 ||| 3 ||| 4 | 5 | 6 con StringTokenizer normal devuelve 1,2,3,4,5,6
* con MiStringTokenizer devuelve 1|2|,3,4|5|6
*
* @author jdelgado
* @version 0.0.0.1 - Version inicial puede tener errores
* @since 27 Feb 2007 - Eclipse 3.2
*/
package comun.util;
import java.util.StringTokenizer;
public class MiStringTokenizer
{
private String cadena;
private String delimitador;
private String _procesa;
/**
* Constructor
* @param cadena cadena a procesar
* @param multipledelimitador tokenizador
*/
public MiStringTokenizer(String cadena,String multipledelimitador)
{
this.cadena = cadena;
this.delimitador=multipledelimitador;
this._procesa = cadena;
}
//----
/**
* Cuenta el numero de tokens
* @return el numero de tokens
*/
public int countTokens()
{
try
{
int len = cadena.length();
if (this.cadena==null) return 0;
if (len==0) return 0;
if (this.delimitador==null) return 0;
int del_len = this.delimitador.length();
if (del_len==0) return 0;
String trata=cadena;
int count=1;
int posic = trata.indexOf(this.delimitador);
while (posic!=-1)
{
trata = trata.substring(posic+del_len);
count++;
posic = trata.indexOf(this.delimitador);
}
return count;
}
catch(Exception e)
{
return 0;
}
}
//-----
/**
* Indica si quedan tokens por procesar
* @return variable booleanda indicando si quedan tokens para procesar
*/
public boolean hasMoreTokens()
{
if (this._procesa==null) return false;
if (this._procesa.length()==0) return false;
int posi = _procesa.indexOf(this.delimitador);
return (posi!=-1||_procesa.length()>0);
}
//----
/**
* Devuelve el proximo token
* @return un String con el proximo token
* @throws Exception Excepcion levantada en caso de error
*/
public String nextToken() throws Exception
{
if (_procesa==null) throw new Exception("no quedan tokens");
String token="";
int posi = _procesa.indexOf(this.delimitador);
if (posi!=-1)
{
int len = this.delimitador.length();
token = _procesa.substring(0,posi);
_procesa = _procesa.substring(posi+len);
}
else
{
token = _procesa;
_procesa = null;
}
return token;
}
//----
/**
* Para probar el correcto funcionamiento de la clase de ejemplo
*/
public static void main(String[] args)
{
try
{
String cadena="valores=1|2|3|||valores=4|5|6|||valores=7|8|9";
String delimitador="|||";
MiStringTokenizer st = new MiStringTokenizer(cadena,delimitador);
int numeroTokens = st.countTokens();
System.out.println("cadena:"+cadena);
System.out.println("numero de tokens:"+numeroTokens);
while (st.hasMoreTokens())
{
String token = st.nextToken();
System.out.println("token:"+token);
}
/*
StringTokenizer st2 = new StringTokenizer(cadena,delimitador);
numeroTokens = st2.countTokens();
System.out.println("cadena:"+cadena);
System.out.println("numero de tokens:"+numeroTokens);
while (st2.hasMoreTokens())
{
String token = st2.nextToken();
System.out.println("token:"+token);
}
*/
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
//end of clas MiStringTokenizer

** Actualizacion ** En http://snippets.dzone.com encuentro un metodo que es mas eficiente que el que he implementado:


private String[] splitString(String str, String delims)
{
if(str == null)
return null;
else if(str.equals("") || delims == null || delims.length() == 0)
return new String[]{ str };
String[] s;
Vector v = new Vector();
int pos = 0;
int newpos = str.indexOf(delims, pos);;
while(newpos != -1)
{
v.addElement(str.substring(pos, newpos));
pos = newpos + delims.length();
newpos = str.indexOf(delims, pos);
}
v.addElement(str.substring(pos));
s = new String[v.size()];
for(int i=0, cnt=s.length; i<cnt; i++)
s[i] = (String) v.elementAt(i);
return s;
}

Cuando disponga de tiempo, seguramente modificare la clase para usarlo.

Enviar un formulario mediante Ajax febrero 27, 2007

Posted by superpiwi in Uncategorized.
5 comments

Navegando me encuentro con AJForm , una libreria de javascript bastante interesante. Con esta libreria podemos mandar los datos de un formulario mediante Ajax y recibir el resultado en una funcion javascript que se encargara de procesar la respuesta. En caso de que ocurra un error en la transmision, pues el formulario se enviara de la manera habitual (ya sabeis, lo que implica, la recarga de la pagina). La documentacion de la pagina esta muy bien, pero adapto el ejemplo para usar un JSP:

Escribimos el codigo de la pagina que guarda el Formulario (Formulario.jsp):


<%
String contexto=request.getContextPath();
%>
<head>
<script type="text/javascript" src="<%=contexto%>/ajform.js"></script>
<script type="text/javascript">
function preProcess( thisFormElement ) {
if( thisForm.elements['myName'].value == "" ) {
alert( "El nombre esta vacio." );
return false;
}
else {
//alert( "You successfully completed the form. The data will now be sent to the server." );
return true;
}
}
function getReturnData( data , statusCode , statusMessage) {
//AJFORM failed. Submit form normally.
if( statusCode != AJForm.STATUS['SUCCESS'] ) {
alert( statusMessage );
return true;
}
//AJFORM succeeded.
else {
//alert( "Data:\n" + data );
document.getElementById("mensaje").innerHTML=data;
}
}
</script>
</head>
<body>
<form action="<%=contexto %>/ajform.jsp" onsubmit="javascript:preProcess(); ajform:getReturnData();">
DATOS:
<br/>
<div name="mensaje" id="mensaje">
</div>
<table>
<tr>
<td>Nombre:</td>
<td><input type="text" name="myName" /></td>
</tr>
<tr>
<td>
<select name="favoriteColor">
<option value="Negro">Negro</option>
<option value="Rojo">Rojo</option>
<option value="Verde">Verde</option>
</select>
</td>
</tr>
<tr>
<td><input type="submit" name="submit" value="Enviar" /></td>
</tr>
</table>
</form>
</body>

y el JSP que recoge los datos del formulario (ajform.jsp):


<%
String ajform = request.getParameter("ajform");
System.out.println("ajform"+ajform);
if (ajform.equalsIgnoreCase("1"))
{
//se retorna el valor a la funcion javascript
%>
<font color="blue">Hola <%=request.getParameter("myName") %>, tu color favorito es <%=request.getParameter("favoriteColor") %></font>
<%
}
else
{
//procesamiento del formulario en modo normal
%>
<a href="javascript:history.back(-1);">Volver al formulario </a>
<%
}
%>

Este ultimo se compone de un chequeo, si el envio mediante AJForm ha tenido exito se procesa la respuesta para enviarla a la funcion javascript, si no se devuelve el contenido normal y que se mostrara al recargar la pagina.

ajform01.jpg

Ajax simplificado al máximo y muy sencillo de usar!!!

Compilacion nativa de codigo Java febrero 23, 2007

Posted by superpiwi in Java.
2 comments

Hace unos cuantos meses que intente compilar nativamente una aplicacion que se conectaba a una base de datos Oracle mediante gcj

http://gcc.gnu.org/java/

Pero desisti, porque me daba problemas el driver de conexion de Oracle y la solucion era compilarlo nativamente (por entonces no tenia tiempo y lo cierto es que ahora tampoco, y lo deje aparcado). Pero el otro dia decidi echar otro vistazo y me alegro saber que ya estaba soportado.

Asi que corriendo me instale la nueva version de gcc (incluyendo gcj). Cuya instalacion comente en otro post.

instalacion de gcj

Vamos al tema. Como ejemplo voy a compilar nativamente una clase que implemente hace tiempo para copiar datos entre tablas. Esta formada por 2 clases “DatabaseUtil.java” y “Migracion.java”. mas detalles sobre estas clases en el siguiente post:

copiar tablas entre bases de datos

el comando para compilar a ejecutable nativamente es el siguiente:

gcj --main=Migracion -o migrar DatabaseUtil.java Migracion.java

(ojo son 2 guiones –main)

se nos genera un ejecutable con el nombre “migrar” (por la opcion -o de output)

si comprobamos el tipo de fichero:

/export>file migrar
migrar: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped

Si queremos ejecutarlo, nos aseguramos de tener en la variable de entorno LD_LIBRARY_PATH las librerias necesarias, para ello hacemos:

export LD_LIBRARY_PATH=/usr/local/lib

El comando “ldd” nos permite ver las librerias que necesitamos para que funcione:

/export/gcj > ldd migrar
/etc/libcwait.so => /etc/libcwait.so (0xb75e7000)
libgcc_s.so.1 => /usr/local/lib/libgcc_s.so.1 (0xb75dc000)
libgcj.so.7 => /usr/local/lib/libgcj.so.7 (0xb60eb000)
libm.so.6 => /lib/tls/libm.so.6 (0xb60bc000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0xb60ac000)
libdl.so.2 => /lib/libdl.so.2 (0xb60a9000)
libc.so.6 => /lib/tls/libc.so.6 (0xb5f71000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)

En otro caso a la hora de ejecutar nos saltaria un mensaje de error indicando que no encuentra tal o cual libreria.

Otra cosa, al ejecutar nos dara un error de ClassNotFoundException:

./migrar -file migrar.cnf -verbose
[Migracion] [main] : activado trazas del proceso (verbose)
[Migracion] [imprimirParametros] : SOURCE_DRIVER: oracle.jdbc.driver.OracleDriver
[Migracion] [imprimirParametros] : TARGET_DRIVER: oracle.jdbc.driver.OracleDriver
[Migracion] [migrar] : @obtener conexiones
java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver not found in gnu.gcj.runtime.SystemClassLoader{urls=[file:./], parent=gnu.gcj.runtime.ExtensionClassLoader{urls=[], parent=null}}

Para solucionarlo indicamos en el CLASSPATH la ruta al driver Jdbc utilizado:

export CLASSPATH=./ojdbc14_g.jar

Ahora ya funciona correctamente:

[Migracion] [migrar] : @obtener conexiones
[Migracion] [migrar] : conexion origen:oracle.jdbc.driver.OracleConnection@53ded8
[Migracion] [migrar] : conexion destino:oracle.jdbc.driver.OracleConnection@53de10
[Migracion] [migrar] : @Procesar tablas
[Migracion] [migrar] : Procesando tabla:SMT_APPLICATION...
[DatabaseUtil] [copyTable] : creando conexion con el origen...
[DatabaseUtil] [copyTable] : creando origen creada...
[DatabaseUtil] [copyTable] : creando conexion con el destino...

Genial!!!. ya podemos desarrollar aplicaciones java con acceso a base de datos y compilarlas de manera nativa en nuestra plataforma.

Herramientas UML febrero 23, 2007

Posted by superpiwi in Java, UML.
add a comment

Si necesitas generar algun diagrama, aqui tienes un listado muy completo de herramientas:

http://www.objectsbydesign.com/tools/umltools_byCompany.html

Yo durante muchos años utilice Rational Rose (si te acabas acostumbrando no está mal). Otras que recomiendo son Omondo, ArgoUml o Poseidon. Sin embargo si necesitas generar de manera rapida y urgente un diagrama de clases a partir del codigo mediante ingenieria inversa y no dispones de mucho tiempo puedes usar Ess-Model:

http://essmodel.sourceforge.net/

ess.gif

Ejemplos de codigo febrero 22, 2007

Posted by superpiwi in Uncategorized.
2 comments

Los Snippets son pequeños trozos de codigo que hacen algo generico de una forma comun y pueden ser reutilizados en diferentes proyectos. En la siguiente pagina te puedes encontrar cientos de ellos:

http://snippets.dzone.com/tag/java

Los 27 mejores Tutoriales de Eclipse febrero 22, 2007

Posted by superpiwi in Eclipse, Java.
2 comments

Los 27 mejores tutoriales de Eclipse desde el sitio de IBM.

Visto en:
http://www.intelligentedu.com/blogs/post/Best_New_Training_Sites/440/Best-27-Eclipse-Tutorials-by-IBM

Como ser un programador febrero 22, 2007

Posted by superpiwi in Uncategorized.
2 comments

serprogramador.jpg

visto en secretgeek

Graficas con Java febrero 22, 2007

Posted by superpiwi in Java.
115 comments

Hace tiempo escribi un post de como generar graficas de tarta con Javascript, ahora vamos a ver como crear rapidamente graficas con Java.

Necesitamos las siguiente librerias:

jcommon-1.0.8.jar
jfreechart-1.0.4.jar

Las podemos descargar de :

http://www.jfree.org/jfreechart/

y ahora unos ejemplillos:


import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import java.io.File;
import org.jfree.chart.plot.*;
import java.io.*;
import org.jfree.data.category.DefaultCategoryDataset;
public class BarChart {
public static void main(String[] args)
{
// Create a simple Bar chart
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.setValue(5, "Compras", "Enero");
dataset.setValue(7, "Compras", "Febrero");
dataset.setValue(9, "Compras", "Marzo");
dataset.setValue(5, "Compras", "Abril");
dataset.setValue(10, "Compras", "Mayo");
JFreeChart chart = ChartFactory.createBarChart("Compras realizadas",
"Compras realizadas, 2007", "Numero de Compras", dataset, PlotOrientation.VERTICAL, false,
true, false);
try {
ChartUtilities.saveChartAsJPEG(new File("/home/jose/Desktop/Barchart.jpg"), chart, 500,
300);
} catch (IOException e) {
System.err.println("Error creando grafico.");
}
}
}

barchart.jpg


import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.data.general.DefaultPieDataset;
import java.io.File;
public class PieChart {
public static void main(String[] args) {
// Create a simple pie chart
DefaultPieDataset pieDataset = new DefaultPieDataset();
pieDataset.setValue("Ubuntu", new Integer(75));
pieDataset.setValue("Xubuntu", new Integer(10));
pieDataset.setValue("Kubuntu", new Integer(10));
pieDataset.setValue("Otros", new Integer(5));
JFreeChart chart = ChartFactory.createPieChart(
"Sistemas Operativos",
pieDataset,
true,
true,
false);
try {
ChartUtilities.saveChartAsJPEG(new File("/home/jose/Desktop/PieChart.jpg"), chart, 500,
300);
} catch (Exception e) {
System.out.println("Error creando grafico.");
}
}
}

piechart.jpg


import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import java.io.File;
import java.io.*;
import org.jfree.data.time.Day;
import org.jfree.data.time.*;
public class TimeSeries {
public static void main(String[] args) {
// Create a time series chart
org.jfree.data.time.TimeSeries pop = new org.jfree.data.time.TimeSeries("Linea de Crecimiento", Day.class);
pop.add(new Day(2, 1, 2007), 100);
pop.add(new Day(2, 2, 2007), 150);
pop.add(new Day(2, 3, 2007), 200);
pop.add(new Day(2, 4, 2007), 250);
pop.add(new Day(2, 5, 2007), 300);
pop.add(new Day(2, 6, 2007), 1500);
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(pop);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Crecimiento Ubuntu",
"Fecha",
"Numero Usuarios",
dataset,
true,
true,
false);
try {
ChartUtilities.saveChartAsJPEG(new File("/home/jose/Desktop/TimeSeries.jpg"), chart, 500, 300);
} catch (IOException e) {
System.err.println("Error creando grafico.");
}
}}

timeseries.jpg


import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import java.io.File;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.data.xy.*;
import org.jfree.chart.plot.*;
import java.io.*;
public class XYChart {
public static void main(String[] args) {
//Create a simple XY chart
XYSeries series = new XYSeries("Crecimiento XYGrafico");
series.add(1, 10);
series.add(2, 20);
series.add(3, 10);
series.add(4, 30);
series.add(5, 40);
//Add the series to your data set
XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series);
//Generate the graph
//JFreeChart chart = ChartFactory.createXYLineChart("Crecimiento Ubuntu", // Title
JFreeChart chart = ChartFactory.createXYAreaChart("XY Chart", // Title
"Tiempo", // x-axis Label
"Usuarios", // y-axis Label
dataset, // Dataset
PlotOrientation.VERTICAL, // Plot Orientation
true, // Show Legend
true, // Use tooltips
false // Configure chart to generate URLs?
);
try {
ChartUtilities.saveChartAsJPEG(new File("/home/jose/Desktop/XYchart.jpg"), chart, 500,
300);
} catch (IOException e) {
System.err.println("Error creando grafico.");
}
}
}

xychart.jpg

Hay muchos mas y variantes de estos (prueba a jugar cambiando las propiedades). Tambien puedes examinar los ejemplos incluidos en la descarga o comprar la documentacion. JFreeChart es una libreria grafica muy sencilla de utilizar y flexible.

Copiar tablas entre bases de datos febrero 22, 2007

Posted by superpiwi in Java.
8 comments

Hoy dos pequeñas clases para realizar el volcado de datos de una serie de tablas entre dos bases de datos. Para que funcione en ambas bases de datos tenemos que tener ya creado el modelo y debe coincidir es decir, usar el mismo nombre de tablas y nombre de columnas.

Ya se que existen otras opciones como usar export/import de bases de datos, o generar scripts SQL, pero no siempre es posible usar estas opciones o simplemente necesitas algo rapido para copiar datos entre bases de datos que son distintas.

Aqui las clases Migracion.java y DatabaseUtil.java.


/**
* Clase de utilidad para copiar tablas de una base de datos origen a una destino
*
* @author jdelgado
* @version 0.0.0.1 - 21 Feb 2007 (a partir de codigo de 2004)
*
*/
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.StringTokenizer;
import java.util.Properties;
import java.io.File;
import java.io.FileInputStream;
//-- version sin log4J para poder compilarlo con gcj.
// si quieres usar log4j descomenta las lineas comentadas a continuacion y en los metodos debug y error.
//import org.apache.log4j.Logger;
public class Migracion
{
/**
* Activar / desactivar trazas
*/
static public boolean verbose=false;
/**
* Propiedades de conexion
*/
public String odriver,ouser,opass,ourl,oschema,otables,ddriver,duser,dpass,durl,dschema;
/**
* Trazas
*/
// descomenta esta linea si quieres usar log4j
//private static final Logger logger = Logger.getLogger(Migracion.class);
/**
* Constructror
* @param odriver nombre driver jdbc para origen
* @param ouser usuario de base de datos origen
* @param opass password de base de datos origen
* @param ourl url jdbc origen
* @param oschema schema origen (opcional)
* @param otables una lista separada por ',' de las tablas a migrar
* @param ddriver nombre driver jdbc para destino
* @param duser usuario de base de datos destino
* @param dpass password de base de datos destino
* @param durl url jdbc destino
* @param dschema schema destino (opcional)
*
* Nota: el modelo de datos debe existir en ambas bases de datos, el proceso de migracion no crea
* las tablas, y los nombres de tablas y columnas deben coincidir.
*/
public Migracion(String odriver,String ouser,String opass,String ourl,String oschema,String otables,String ddriver,String duser,String dpass,String durl,String dschema)
{
this.odriver = odriver;
this.ouser = ouser;
this.opass = opass;
this.ourl = ourl;
this.oschema = oschema;
this.otables = otables;
this.ddriver = ddriver;
this.duser = duser;
this.dpass = dpass;
this.durl = durl;
this.dschema = dschema;
}
//----
/**
* Constructor
* @param pathname ruta del fichero con las propiedades
* @throws Excepcion excepcion levantada en caso de error
*/
public Migracion(String pathname) throws Exception
{
this.leerProperties(pathname);
}
//----
public void imprimirParametros()
{
Migracion.debug(Migracion.class.getName(), "imprimirParametros", "SOURCE_DRIVER: "+this.odriver, 6, null, null);
Migracion.debug(Migracion.class.getName(), "imprimirParametros", "SOURCE_URL: "+this.ourl, 6, null, null);
Migracion.debug(Migracion.class.getName(), "imprimirParametros", "SOURCE_TABLES: "+this.otables, 6, null, null);
Migracion.debug(Migracion.class.getName(), "imprimirParametros", "TARGET_DRIVER: "+this.ddriver, 6, null, null);
Migracion.debug(Migracion.class.getName(), "imprimirParametros", "TARGET_URL: "+this.durl, 6, null, null);
}
/**
* Inicia el proceso de volcado de tablas.
* @return un pequeño informe con los tiempos de ejecucion.
* @throws Exception excepcion levantada en caso de error.
*/
public String migrar() throws Exception
{
Connection ORIGEN=null;
Connection DESTINO=null;
DatabaseUtil util = null;
try
{
imprimirParametros();
Migracion.debug(Migracion.class.getName(), "migrar", "@obtener conexiones", 6, null, null);
Class.forName(this.odriver);
ORIGEN=DriverManager.getConnection(this.ourl,this.ouser,this.opass);
Migracion.debug(Migracion.class.getName(), "migrar", "conexion origen:"+ORIGEN, 6, null, null);
Class.forName(this.ddriver);
DESTINO=DriverManager.getConnection(this.durl,this.duser,this.dpass);
Migracion.debug(Migracion.class.getName(), "migrar", "conexion destino:"+DESTINO, 6, null, null);
// Iniciar transaccion
Migracion.debug(Migracion.class.getName(), "migrar", "@Procesar tablas", 6, null, null);
util = new DatabaseUtil();
util.setVerbose(verbose);
// obtener tablas
StringTokenizer st = new StringTokenizer(this.otables,",");
while (st.hasMoreTokens())
{
String TABLENAME = st.nextToken();
Migracion.debug(Migracion.class.getName(), "migrar", "Procesando tabla:"+TABLENAME+"...", 6, null, null);
// Copiar el contenido de la tabla desde la base de datos origen a destino, borrando la tabla en el destino previamente
util.copyTable(TABLENAME, ORIGEN, DESTINO, true, null);
}
return util.getSb().toString();
}
catch(Exception e)
{
throw e;
}
finally
{
try
{
if (ORIGEN!=null) ORIGEN.close();
}
catch(Exception f)
{
;
}
try
{
if (DESTINO!=null) DESTINO.close();
}
catch(Exception f)
{
;
}
}
}
//----
/**
* Para mostrar un error si falta algun properties
* @param key valor de la clave
* @param name nombre de la clave
* @throws Exception excepcion levantada en caso de error
*/
public void existe(String key,String name) throws Exception
{
if (key==null) throw new Exception("clave ["+name+"] no encontrada en el fichero de propiedades");
}
//----
/**
* Leer las propiedades de conexion desde fichero
* @throws Excepcion excepcion levantada en caso de error
*/
public void leerProperties(String pathname) throws Exception
{
Properties p = null;
FileInputStream fin = null;
try
{
// leemos el contenido del fichero y lo cargamos en el properties
String FILENAME=pathname;
File f = new File(FILENAME);
if (!f.exists()) throw new Exception ("El fichero \'"+pathname+"\' no existe");
//InputStream is = getClass().getResourceAsStream(FILENAME);
fin = new FileInputStream(f);
p = new Properties();
p.load(fin);
// recuperamos las propiedades y las asignamos a la clase
String SOURCE_DRIVER = p.getProperty("SOURCE_DRIVER");
String SOURCE_URL = p.getProperty("SOURCE_URL");
String SOURCE_USER = p.getProperty("SOURCE_USER");
String SOURCE_PASSWORD = p.getProperty("SOURCE_PASSWORD");
String SOURCE_SCHEMA = p.getProperty("SOURCE_SCHEMA");
String SOURCE_TABLES = p.getProperty("SOURCE_TABLES");
String TARGET_DRIVER = p.getProperty("TARGET_DRIVER");
String TARGET_URL = p.getProperty("TARGET_URL");
String TARGET_USER = p.getProperty("TARGET_USER");
String TARGET_PASSWORD = p.getProperty("TARGET_PASSWORD");
String TARGET_SCHEMA = p.getProperty("TARGET_SCHEMA");
// chequeos de valores nulos
existe(SOURCE_DRIVER,"SOURCE_DRIVER");
existe(SOURCE_URL,"SOURCE_URL");
existe(SOURCE_USER,"SOURCE_USER");
existe(SOURCE_PASSWORD,"SOURCE_PASSWORD");
existe(SOURCE_TABLES,"SOURCE_TABLES");
existe(TARGET_DRIVER,"TARGET_DRIVER");
existe(TARGET_URL,"TARGET_URL");
existe(TARGET_USER,"TARGET_USER");
existe(TARGET_PASSWORD,"TARGET_PASSWORD");
// asignamos las propiedades leidas a los atributos de la clase
this.odriver = SOURCE_DRIVER;
this.ourl = SOURCE_URL;
this.ouser = SOURCE_USER;
this.opass = SOURCE_PASSWORD;
this.oschema = SOURCE_SCHEMA;
this.otables = SOURCE_TABLES;
this.ddriver = TARGET_DRIVER;
this.durl = TARGET_URL;
this.duser = TARGET_USER;
this.dpass = TARGET_PASSWORD;
}
catch(Exception e)
{
throw e;
}
finally
{
try
{
if (fin!=null) fin.close();
}
catch(Exception f)
{
;
}
}
}
//----
/**
* Para probar el correcto funcionamiento de la clase de ejemplo
* @param args argumentos de entrada
*/
public static void main(String[] args) {
try
{
String TABLAS="TABLA1,TABLA2,TABLA3";
/*
Migracion m = new Migracion(
"oracle.jdbc.driver.OracleDriver",
"tu_user",
"tu_password",
"jdbc:oracle:thin:@tu_hostname:1521:tu_basedatos",
null,
TABLAS,
"oracle.jdbc.driver.OracleDriver",
"tu_user",
"tu_password",
"jdbc:oracle:thin:@tu_hostname.hi.inet:1521:tu_basedatos",
null);
m.migrar();
*/
// comprobar parametros
int num_argumentos = args.length;
if (num_argumentos < 2)
{
System.out.println("migrar: copia las tablas especificadas desde una base de datos origen a una base de datos destino.");
System.out.println("sintaxis: migrar -file <fichero de configuracion> [-verbose]");
}
else
{
String argumento1 = args[0];
String argumento2 = args[1];
String argumento3 = "";
if (num_argumentos>2) argumento3 = args[2];
if (!argumento1.equalsIgnoreCase("-file"))
{
System.out.println("Parametro incorrecto");
System.out.println("sintaxis: migrar -file <fichero de configuracion> [-verbose]");
}
else
{
if (argumento3.equalsIgnoreCase("-verbose"))
{
//System.out.println("activado trazas del proceso (verbose)");
Migracion.verbose = true;
Migracion.debug(Migracion.class.getName(), "main", "activado trazas del proceso (verbose)", 6, null, null);
}
long time = System.currentTimeMillis();
Migracion m = new Migracion(argumento2);
String report = m.migrar();
long time_end = System.currentTimeMillis();
long total = time_end-time;
System.out.println("\r\nMigracion terminada\r\n-------------------\r\n");
System.out.println(report);
System.out.println("Process Total Time: "+total+" ms");
}
}
}
catch(Exception e)
{
//e.printStackTrace();
String ERROR = e.toString();
System.out.println(ERROR);
}
}
//----
/**
* Imprime un mensaje de traza.
* @param nombre de la clase clase donde se genera el mensaje.
* @param metodo nombre del metodo donde se genera el mensaje.
* @param mensaje texto del mensaje.
* @param prioridad prioridad del mensaje.
* @param user usuario del mensaje.
* @param parameters parametros del mensaje.
*/
static public void debug(String clase,String metodo,String mensaje,int prioridad,String user,Object parameters)
{
if (verbose)
{
//if (logger.isDebugEnabled())
//{
String MENSAJE = "["+clase+"] ["+metodo+"] : "+mensaje;
System.out.println(MENSAJE);
//logger.debug(MENSAJE);
//}
}
}
//--------------------------------------------
}
//end of class Migracion.java


/**
* DatabaseUtil.java
*
* Utileria para bases de datos
*
* @author jdelgado
* @version 1.0 - 31/05/2004
* @revision 1.1 - 21/02/2007
*
* @since JDK 1.4.1_02 - Eclipse 3 release M8
* @since revision JDK 1.5 - Eclipse 3.2
*
* TODO: sustituir metodo para recuperar nombres de columnas de las tablas no mediante SQL sino introspeccion
* en la base de datos
*
* */
import java.sql.*;
import java.util.Vector;
import java.io.*;
//-- version sin log4J para poder compilarlo con gcj.
// si quieres utilizar log4j descomenta las lineas
//import org.apache.log4j.Logger;
public class DatabaseUtil
{
/**
* Trazas
*/
//private static final Logger logger = Logger.getLogger(DatabaseUtil.class);
/**
* Activar / desactivar trazas
*/
static public boolean verbose=false;
/**
* report
*/
StringBuffer sb = new StringBuffer();
/**
* Copia el contenido de una tabla desde una base de datos origen a una base de datos destino.(NOTA: NO SE CIERRAN LAS CONEXIONES).
*
* @param tablename nombre de la tabla que se quiere copiar.
* @param source conexion origen conexion con la base de datos origen.
* @param target conexion conexion con la base de datos destino.
* @throws Exception excepcion levantada en caso de error.
*/
public void copyTable(String tablename, Connection source, Connection target, boolean deleteTarget,FileOutputStream out)
throws Exception
{
ResultSet rs = null;
Statement stmt = null;
ResultSetMetaData metadata = null;
String[] columnas = null;
Vector valores = null;
Vector SENTENCIAS_A_EJECUTAR = null;
Statement stmt2 = null;
String tablename2 = null;
int[] resultados=null;
try
{
tablename2 = tablename;
// crear conexion con el origen.
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando conexion con el origen...", 6, null, null);
try
{
stmt = source.createStatement();
}
catch(Exception e)
{
String error = e.getMessage();
DatabaseUtil.error(DatabaseUtil.class.getName(), "copyTable", "No se pudo establecer la conexion con el origen : "+error, 6, null, null);
throw new Exception("No se pudo establecer la conexion origen : "+error);
}
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando origen creada...", 6, null, null);
// crear conexion con el destino.
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando conexion con el destino...", 6, null, null);
try
{
stmt2 = target.createStatement();
}
catch(Exception e)
{
String error = e.getMessage();
DatabaseUtil.error(DatabaseUtil.class.getName(), "copyTable", "No se pudo establecer la conexion con el destino : "+error, 6, null, null);
throw new Exception("No se pudo establecer la conexion destino : "+e.getMessage());
}
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando destino creada...", 6, null, null);
// Contabilizar el numero de registros
String SENTENCIA_SQL = "SELECT COUNT(*) FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
rs.next();
String numero_registros = rs.getString(1);
if (rs!=null) rs.close();
// TODO: cambiar esta parte pq funciona pero no es adecuada, hay una clase que nos devuelve el metadato de columnas de una tabla
// sin necesidad de emplear el SELECT * sino directamente analizando el esquema de la base de datos
// ejecutar la consulta para recuperar los nombres de las columnas.
SENTENCIA_SQL = "SELECT * FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
// recuperamos los metadatos
metadata = rs.getMetaData();
int numero_columnas = metadata.getColumnCount();
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "La tabla tiene "+numero_columnas+" columnas", 6, null, null);
// las almacenamos en un Array de Strings.
columnas = new String[numero_columnas];
for (int i=1; i SQL anterior: ["+sentencia_anterior+"]", 6, null, null);
DatabaseUtil.debug(DatabaseUtil.class.getName(), "imprimeSQL", "==> SQL: ["+sentencia+"]", 6, null, null);
}
catch(Exception e)
{
DatabaseUtil.error(DatabaseUtil.class.getName(), "imprimeSQL", "No se ha podido recuperar la informacion de las sentencias SQL", 6, null, null);
}
}
//----
/**
* Imprime un mensaje de traza.
* @param nombre de la clase clase donde se genera el mensaje.
* @param metodo nombre del metodo donde se genera el mensaje.
* @param mensaje texto del mensaje.
* @param prioridad prioridad del mensaje.
* @param user usuario del mensaje.
* @param parameters parametros del mensaje.
*/
static public void debug(String clase,String metodo,String mensaje,int prioridad,String user,Object parameters)
{
if (verbose)
{
//if (logger.isDebugEnabled())
//{
String MENSAJE = "["+clase+"] ["+metodo+"] : "+mensaje;
//logger.debug(MENSAJE);
System.out.println(MENSAJE);
//}
}
}
//--------------------------------------------
/**
* Imprime un mensaje de error.
* @param nombre de la clase clase donde se genera el mensaje.
* @param metodo nombre del metodo donde se genera el mensaje.
* @param mensaje texto del mensaje.
* @param prioridad prioridad del mensaje.
* @param user usuario del mensaje.
* @param parameters parametros del mensaje.
*/
static public void error(String clase,String metodo,String mensaje,int prioridad,String user,Object parameters)
{
if (verbose)
{
//if (logger.isDebugEnabled())
//{
String MENSAJE = "["+clase+"] ["+metodo+"] : "+mensaje;
//logger.error(MENSAJE);
System.out.println(MENSAJE);
//}
}
}
//--------------------------------------------
public static boolean isVerbose() {
return verbose;
}
public static void setVerbose(boolean verbose) {
DatabaseUtil.verbose = verbose;
}
public StringBuffer getSb() {
return sb;
}
}
//end of DatabaseUtil.java

Puedes pasar los parametros de conexion directamente a la clase, pero la forma general de utilizarlo es especificar un fichero de properties con el parametro -file

La sintaxis es:


Migracion -file <fichero de propiedades> [-verbose]

si indicas el flag -verbose se activa la traza y te muestra por consola el resultado de la ejecucion.

La salida es similar a lo siguiente:

copiatablas01.jpg

En el fichero de propiedades tienes que indicar los siguientes valores:


# Fichero de propiedades para la migracion de tablas
#Base de datos origen
SOURCE_DRIVER=oracle.jdbc.driver.OracleDriver
SOURCE_URL=jdbc:oracle:thin:@<hostname>:1521:<database>
SOURCE_USER=<user>
SOURCE_PASSWORD=<password>
#Tablas a copiar
SOURCE_TABLES=TABLA1,TABLA2,...,TABLAN (lista de tablas separadas por ,)
#Base de datos destino
TARGET_DRIVER=oracle.jdbc.driver.OracleDriver
TARGET_URL=jdbc:oracle:thin:@<hotname>:1521:<database>
TARGET_USER=<user>
TARGET_PASSWORD=<password>
(Sustituyelos por tus valores)

Otra opcion si utilizas el IDE Eclipse es instalar el plugin DbCopy

http://dbcopy.sourceforge.net/en/dbcopy/index.html

example2dbcopy.jpg

Si usas Log4J te dejo un ejemplo de properties para el proceso de migracion:


# initialise root logger with level DEBUG and call it BLAH
log4j.rootLogger=DEBUG, BLAH, DebugAppender
# add a ConsoleAppender to the logger BLAH
log4j.appender.BLAH=org.apache.log4j.ConsoleAppender
# set set that layout to be SimpleLayout
#log4j.appender.BLAH.layout=org.apache.log4j.SimpleLayout
log4j.appender.BLAH.layout=org.apache.log4j.PatternLayout
log4j.appender.BLAH.layout.ConversionPattern=%d %m %n
#log4j.appender.DebugAppender=org.apache.log4j.RollingFileAppender
#log4j.appender.DebugAppender.File=/tmp/migracion.log
#log4j.appender.DebugAppender.MaxFileSize=500KB
#log4j.appender.DebugAppender.MaxBackupIndex=10
#log4j.appender.DebugAppender.layout=org.apache.log4j.PatternLayout
#log4j.appender.DebugAppender.layout.ConversionPattern=%c %d{ISO8601} -- %p -- %m%n
#log4j.appender.DebugAppender.Threshold=DEBUG

ACTUALIZACION:

En los comentarios, me comenta que el codigo esta mal, es un problema al copiar y pegar. Aqui pego una version nueva, aunque no definitiva pues posteare de nuevo esta clase cuando la examine mejor:
He abandonado temporalmente este proyecto porque el objetivo que tenia era migrar de Oracle a MySQL y eso ya lo he realizado con el MySQL Oracle Migration, asi que si algun dia completo este codigo solo sera como Ejemplo.


/**
* DatabaseUtil.java
*
* Utileria para bases de datos
*
* @author jdelgado
* @version 1.0 - 31/05/2004
* @revision 1.1 - 21/02/2007
*
* @since JDK 1.4.1_02 - Eclipse 3 release M8
* @since revision JDK 1.5 - Eclipse 3.2
*
* TODO: sustituir metodo para recuperar nombres de columnas de las tablas no mediante SQL sino introspeccion
* en la base de datos
*
* */
import java.sql.*;
import java.util.Vector;
import java.io.*;
//– version sin log4J para poder compilarlo con gcj.
// si quieres utilizar log4j descomenta las lineas
//import org.apache.log4j.Logger;
public class DatabaseUtil
{
/**
* Trazas
*/
//private static final Logger logger = Logger.getLogger(DatabaseUtil.class);
/**
* Activar / desactivar trazas
*/
static public boolean verbose=false;
/**
* report
*/
StringBuffer sb = new StringBuffer();
/**
* Copia el contenido de una tabla desde una base de datos origen a una base de datos destino.(NOTA: NO SE CIERRAN LAS CONEXIONES).
*
* @param tablename nombre de la tabla que se quiere copiar.
* @param source conexion origen conexion con la base de datos origen.
* @param target conexion conexion con la base de datos destino.
* @throws Exception excepcion levantada en caso de error.
*/
public void copyTable(String tablename, Connection source, Connection target, boolean deleteTarget,FileOutputStream out)
throws Exception
{
ResultSet rs = null;
Statement stmt = null;
ResultSetMetaData metadata = null;
String[] columnas = null;
Vector valores = null;
Vector SENTENCIAS_A_EJECUTAR = null;
Statement stmt2 = null;
String tablename2 = null;
int[] resultados=null;
try
{
tablename2 = tablename;
// crear conexion con el origen.
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando conexion con el origen…", 6, null, null);
try
{
stmt = source.createStatement();
}
catch(Exception e)
{
String error = e.getMessage();
DatabaseUtil.error(DatabaseUtil.class.getName(), "copyTable", "No se pudo establecer la conexion con el origen : "+error, 6, null, null);
throw new Exception("No se pudo establecer la conexion origen : "+error);
}
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando origen creada…", 6, null, null);
// crear conexion con el destino.
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando conexion con el destino…", 6, null, null);
try
{
stmt2 = target.createStatement();
}
catch(Exception e)
{
String error = e.getMessage();
DatabaseUtil.error(DatabaseUtil.class.getName(), "copyTable", "No se pudo establecer la conexion con el destino : "+error, 6, null, null);
throw new Exception("No se pudo establecer la conexion destino : "+e.getMessage());
}
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "creando destino creada…", 6, null, null);
// Contabilizar el numero de registros
String SENTENCIA_SQL = "SELECT COUNT(*) FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
rs.next();
String numero_registros = rs.getString(1);
if (rs!=null) rs.close();
// TODO: cambiar esta parte pq funciona pero no es adecuada, hay una clase que nos devuelve el metadato de columnas de una tabla
// sin necesidad de emplear el SELECT * sino directamente analizando el esquema de la base de datos
// ejecutar la consulta para recuperar los nombres de las columnas.
SENTENCIA_SQL = "SELECT * FROM "+tablename;
rs = stmt.executeQuery(SENTENCIA_SQL);
// recuperamos los metadatos
metadata = rs.getMetaData();
int numero_columnas = metadata.getColumnCount();
DatabaseUtil.debug(DatabaseUtil.class.getName(), "copyTable", "La tabla tiene "+numero_columnas+" columnas", 6, null, null);
// las almacenamos en un Array de Strings.
columnas = new String[numero_columnas];
// las añadimos a un Array de Strings.
columnas = new String[numero_columnas];
for (int i=1; i<=numero_columnas;i++)
{
String columna = metadata.getColumnName(i);
columnas[i-1] = columna;
}
// Construimos los INSERTs...
SENTENCIAS_A_EJECUTAR = new Vector();
while (rs.next())
{String INSERT = "INSERT INTO "+tablename2+"(";
// recuperamos el valor de todos los registros...
valores = new Vector();
for (int j=1;j<=numero_columnas;j++)
{
INSERT=INSERT+""+columnas[j-1]+",";
String dato = rs.getString(columnas[j-1]);
if (dato==null) dato="";
if (dato!=null)
{
// esto se hace para evitar errores a la hora de insertar campos numericos.
if (dato.equals("null")) dato="";
}
valores.add(dato);
}
//end for
if (INSERT.endsWith(",")) INSERT=INSERT.substring(0,INSERT.length()-1);
INSERT=INSERT+") VALUES (";
// Insertamos los valores...
for (int k=0;k<valores.size();k++)
{
String valor = (String) valores.elementAt(k);
//
// BUG: se evita la insercion de valores que contengan "'" para ello se escapa el campo "''".
//
//valor = Replacement.escape(valor);
INSERT = INSERT+"'"+valor+"',";
}
if (INSERT.endsWith(",")) INSERT=INSERT.substring(0,INSERT.length()-1);
INSERT=INSERT+")";
// String tenemos la sentencia INSERT que añadimos a un vector de sentencias...
SENTENCIAS_A_EJECUTAR.addElement(INSERT);
}
// Ejecutamos los insert como un lote.
int num_sentencias = SENTENCIAS_A_EJECUTAR.size();
if (deleteTarget)
{
String DELETE = "DELETE FROM "+tablename2;
stmt2.addBatch(DELETE);
}
for (int i=0;i<num_sentencias;i++)
{
String SENTENCIA = (String) SENTENCIAS_A_EJECUTAR.elementAt(i);
stmt2.addBatch(SENTENCIA);
}
resultados = stmt2.executeBatch();
/*
String RESULTADOS = "";
for (int i=0; i<resultados.length; i++)
{
String resultado = (String) String.valueOf( resultados[i] );
RESULTADOS = RESULTADOS+","+resultado;
}
if (RESULTADOS.startsWith(",")) {RESULTADOS = RESULTADOS.substring(1,RESULTADOS.length());}
*/
}
catch(Exception e)
{
DatabaseUtil.error(DatabaseUtil.class.getName(), "imprimeSQL", "No se ha podido recuperar la informacion de las sentencias SQL", 6, null, null);
}
}
//—-
/**
* Imprime un mensaje de traza.
* @param nombre de la clase clase donde se genera el mensaje.
* @param metodo nombre del metodo donde se genera el mensaje.
* @param mensaje texto del mensaje.
* @param prioridad prioridad del mensaje.
* @param user usuario del mensaje.
* @param parameters parametros del mensaje.
*/
static public void debug(String clase,String metodo,String mensaje,int prioridad,String user,Object parameters)
{
if (verbose)
{
//if (logger.isDebugEnabled())
//{
String MENSAJE = "["+clase+"] ["+metodo+"] : "+mensaje;
//logger.debug(MENSAJE);
System.out.println(MENSAJE);
//}
}
}
//——————————————–
/**
* Imprime un mensaje de error.
* @param nombre de la clase clase donde se genera el mensaje.
* @param metodo nombre del metodo donde se genera el mensaje.
* @param mensaje texto del mensaje.
* @param prioridad prioridad del mensaje.
* @param user usuario del mensaje.
* @param parameters parametros del mensaje.
*/
static public void error(String clase,String metodo,String mensaje,int prioridad,String user,Object parameters)
{
if (verbose)
{
//if (logger.isDebugEnabled())
//{
String MENSAJE = "["+clase+"] ["+metodo+"] : "+mensaje;
//logger.error(MENSAJE);
System.out.println(MENSAJE);
//}
}
}
//——————————————–
public static boolean isVerbose() {
return verbose;
}
public static void setVerbose(boolean verbose) {
DatabaseUtil.verbose = verbose;
}
public StringBuffer getSb() {
return sb;
}
}
//end of DatabaseUtil.java