<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1507867380128235429</id><updated>2011-11-28T02:17:01.769+01:00</updated><category term='Programación'/><category term='bases de datos'/><category term='Informática'/><category term='isolation levels'/><category term='modelo relacional'/><category term='mysql'/><category term='Java'/><category term='niveles de aislamiento'/><category term='PDF'/><category term='Impresión'/><title type='text'>Recetas Informáticas</title><subtitle type='html'>Teoría y, sobre todo, práctica sobre temas concernientes al desarrollo de aplicaciones: Lenguajes de programación, compiladores, Gestores de bases de datos, aspectos de ingeniería del software, ect.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://recetasinformaticas.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://recetasinformaticas.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Juan Ángel Gascón Moya</name><uri>http://www.blogger.com/profile/03601148345319659146</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>3</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1507867380128235429.post-5282401973008129082</id><published>2007-09-25T16:46:00.000+02:00</published><updated>2007-09-25T23:00:56.951+02:00</updated><title type='text'>Ingenieria del Software: Ingenieria Inversa</title><content type='html'>Introducción sobre la utilización de la &lt;span style="font-style: italic;"&gt;Ingeniería Inversa  o Reverse Engineering&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En este caso y razón del motivo por el que fue creado este blog, trataré el tema de la &lt;span style="font-weight: bold;"&gt;Ingeniería Inversa sobre aplicaciones en Java.&lt;/span&gt; Es decir, veremos como a través de un proyecto Java obtendremos su UML.&lt;br /&gt;&lt;br /&gt;Utilizaremos la nueva versión de NetBeans IDE 6.0, este entorno de desarrollo ha introducido una serie de herramientas que se utilizan para la creación de proyectos de software como son las siguientes:&lt;br /&gt;&lt;br /&gt;- Diagrama de Paquetes&lt;br /&gt;- Diagrama de Secuencia&lt;br /&gt;- Modelo del Dominio&lt;br /&gt;- Diagrama de Casos de Uso&lt;br /&gt;- Diagrama de Clases&lt;br /&gt;- Diagrama de Comunicación&lt;br /&gt;- Diagrama de Clases de Diseño&lt;br /&gt;&lt;br /&gt;A parte de estas versátiles herramientas de desarrollo de software, a través de la herramienta de ingeniería inversa obtendremos los diagramas creados a partir de un proyecto de una aplicación de Java existente.&lt;br /&gt;&lt;br /&gt;En este caso la aplicación existente será una aplicación bancaria, crearemos un nuevo proyecto de UML escogiendo la opción de Reverse Engeened Java-Model Platform&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Después de crear nuestro proyecto de UML mediante la Ingeniería Inversa tendremos la opción de generar los diferentes diagramas,  en projects nos encontraremos con Model, aquí encontraremos las clases obtenidas en bankpack &lt;span style="font-style: italic;"&gt;(en mi caso)&lt;/span&gt; y generaremos un diagrama en cualquiera &lt;span style="font-style: italic;"&gt;(click derecho de ratón sobre la clase, new y elegir diagrama)&lt;/span&gt;  en nuestro caso escogeremos un diagrama de clases de diseño de bankaccount:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_sBvXgyN7FuU/RvkuTwZw5uI/AAAAAAAAAAc/KW5lMST06Q4/s1600-h/Opcion2.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_sBvXgyN7FuU/RvkuTwZw5uI/AAAAAAAAAAc/KW5lMST06Q4/s400/Opcion2.JPG" alt="" id="BLOGGER_PHOTO_ID_5114169768801265378" border="0" /&gt;&lt;/a&gt;Y una serie de diagramas de la aplicación en conjunto, simplemente seleccionando las clases que queremos representar en nuestro proyecto de UML y voilá&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_sBvXgyN7FuU/RvkvaAZw5vI/AAAAAAAAAAk/sZ3W3sX3NkA/s1600-h/Opcion3.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_sBvXgyN7FuU/RvkvaAZw5vI/AAAAAAAAAAk/sZ3W3sX3NkA/s400/Opcion3.JPG" alt="" id="BLOGGER_PHOTO_ID_5114170975687075570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Al mismo tiempo y una gran ventaja, podemos generar también código fuente para un proyecto de Java que hayamos creado previamente, simplemente escogiendo la opción generate code y creará un archivo o archivos con código fuente en nuestro nuevo proyecto.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(102, 51, 0);"&gt;ej:   BankAccount.java&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;package bankpack;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;font-size:&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;/**&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt; *  @author Administrator&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt; */&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;abstract class BankAccount implements Account {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private double balance;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private String accountNumber;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private double interestRate;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private History mHistory = new History();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    /**&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;     *  Creates a new instance of BankAccount&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;     */&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;   &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public BankAccount () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public BankAccount (String accNumber, double initialAmount) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public BankAccount (String accNumber, double initialAmount, double rate) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public double getBalance () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return 0.0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public String getAccountNumber () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return null;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public void withdraw (double val) throws bankpack.NoAvailableFundsException {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public void deposit (double val) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public void setAccountNumber (String val) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public boolean equals (Object o) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return true;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public int hashCode () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public String toString () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return null;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public History getHistory () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return null;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public void setHistory (History val) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public String getMessage () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return null;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public double getInterestRate () {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;        return 0.0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    public void setInterestRate (double val) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private void setBalance (double val) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    private void noAvailableFunds () throws bankpack.NoAvailableFundsException {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/font-size:&gt;&lt;br /&gt;&lt;br /&gt;Un saludo a todos y espero que aprovechéis esta &lt;span style="font-weight: bold;"&gt;herramienta de Netbeans&lt;/span&gt; para crear proyectos &lt;span style="font-weight: bold;"&gt;UML&lt;/span&gt; de vuestras aplicaciones o otras como &lt;span style="font-weight: bold;"&gt;JEnigma&lt;/span&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;One sign of a good programmer is their absolute need to understand&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1507867380128235429-5282401973008129082?l=recetasinformaticas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recetasinformaticas.blogspot.com/feeds/5282401973008129082/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1507867380128235429&amp;postID=5282401973008129082' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/5282401973008129082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/5282401973008129082'/><link rel='alternate' type='text/html' href='http://recetasinformaticas.blogspot.com/2007/09/ingenieria-del-software-ingenieria.html' title='Ingenieria del Software: Ingenieria Inversa'/><author><name>Rafa Passas</name><uri>http://www.blogger.com/profile/10697298837893506852</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_sBvXgyN7FuU/RvkuTwZw5uI/AAAAAAAAAAc/KW5lMST06Q4/s72-c/Opcion2.JPG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1507867380128235429.post-195374923564246542</id><published>2007-09-01T12:19:00.000+02:00</published><updated>2007-09-03T08:52:42.883+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='modelo relacional'/><category scheme='http://www.blogger.com/atom/ns#' term='niveles de aislamiento'/><category scheme='http://www.blogger.com/atom/ns#' term='isolation levels'/><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL: Niveles de aislamiento (Isolations levels)</title><content type='html'>En esta ocasión voy a abordar la temática de las bases de datos. Para ello me voy a referir a un DBMS tan extendido en uso como criticado por sus carencias con respecto a servidores de bases de datos comerciales: &lt;span style="font-weight: bold;"&gt;MySQL&lt;/span&gt;. Concretamente me voy a referir a una característica que a mí me ha encantado y es que MySQL nos permite especificar el &lt;span style="font-style: italic;"&gt;nivel de aislamiento&lt;/span&gt; que deseamos para las transacciones.&lt;br /&gt;Doy por hecho que la persona que está leyendo este artículo conoce, cuanto menos, lo que son las transacciones dentro de los SGBDR. Las especificaciones ANSI establecen que una transacción debe de cumplir con la norma &lt;span style="font-weight: bold;"&gt;ACID&lt;/span&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Atomic&lt;/b&gt; (Atomicidad): Establece que las operaciones que se realizan dentro de una transacción son efectuadas de manera atómica. Esto significa que la transacción bien se cometa o bien se anule siempre debe de ser al completo.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Consistent&lt;/b&gt; (Consistencia): Esta es una característica que más bien depende del programador del DBMS. Define que la base de datos debe de quedar de manera consistente tras la finalización (con éxito o no) de la transacción.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Isolation&lt;/b&gt; (Aislamiento): Determina que las distintas transacciones que se estén ejecutando lo hagan de forma aislada. Esto es, que los resultados de una transacción no son visibles por el resto de transacciones en curso hasta que dicha transacción finalize.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Durable&lt;/b&gt; (Durable): Esta regla impone que los cambios realizados por una transacción cometida deben de ser durables en el tiempo, deben de permanecer.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Pues bien, repasado este concepto ya podemos mostrar los problemas asociados a los distintos tipos de transacciones:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Dirty reads&lt;/b&gt; (Lecturas sucias): Es el problema más importante de todos. Supone que las transacciones en curso puedan leer el resultado de otras transacciones aún no confirmadas. Por ejemplo, vamos a suponer que tenemos dos transacciones activas (A y B). Inicialmente la transacción A lee un valor X de una tabla que, por ejemplo, es 0. Durante dicha transacción el valor de X se cambia a 10, pero aún la transacción no se ha cometido, por lo que en la tabla X = 0. Ahora la transacción B accede al valor X y obtiene ¡¡X = 10!! un valor que está usando A y que aún no se ha cometido. Supongamos que ahora se anula la transacción A. El resultado sería X = 0 en la tabla y X = 10 en la transacción B por lo que hemos llegado a un estado muy grave de inconsistencia.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Non-Repeatable reads&lt;/b&gt; (Lecturas no repetibles): Ocurre cuando una transacción activa vuelve a leer un dato cuyo valor difiere con respecto al de la anterior lectura. Lo vemos más claro con un ejemplo. Supongamos que una transacción activa, A, lee un valor X = 0. En este momento otra transacción B modifica el valor de X, por ejemplo X = 10, y se comete dicha transacción. Si ahora duracte la transacción A se vuelve a leer el valor X obtendríamos 10 en lugar del 0 que se esperaba. Aunque a primera vista este problema no parezca muy importante en realidad sí que lo es, sobre todo cuando X es una clave primaria o ajena. En este caso se puede originar una gran pérdida de consistencia en nuestra base de datos.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Phantom reads&lt;/b&gt; (Lecturas fantasma): Este supone el menor problema que se nos puede plantear con respecto a las transacciones. Sucede cuando una transacción en un momento lanza una consulta de selección con una condición y recibe en ese momento N filas y posteriormente vuelve a lanzar la misma consulta junto con la misma condición y recibe M filas con M &gt; N. Esto es debido a que durante el intervalo que va de la primera a la segunda lectura se insertaron nuevas filas que cumplen la condición impuesta en la consulta.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Debido a estos problemas el ANSI establece diferentes niveles de aislamiento (isolations levels) para solventarlos. Hay que tener en cuenta que a mayor nivel de aislamiento mayores son los sacrificios que se hacen con respecto a la concurrencia y al rendimiento. Vamos a enumerar los niveles de aislamiento desde el menor hasta el mayor:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Read uncommitted&lt;/b&gt; (Lectura sin confirmación): En la práctica casi no se suele utilizar este nivel de aislamiento ya que es propenso a sufrir todos los problemas anteriormente descritos. En este nivel una transacción puede ver los resultados de transacciones aún no cometidas. Podemos apreciar que en este nivel no existe aislamiento alguno entre transacciones.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Read committed&lt;/b&gt; (Lectura confirmada): Es el predeterminado para la mayoría de gestores de bases de datos relacionales. Supone que dentro de una transacción únicamente se pueden ver los cambios de las transacciones ya cometidas. Soluciona el problema de las lecturas sucias, pero no el de las lecturas no repetibles ni tampoco el de las lecturas fantasmas.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Repeatable read&lt;/b&gt; (Lectura repetible): Define que cualquier tupla leída durante el transcurso de una transacción es bloqueada. De esta forma se soluciona, además de las lecturas sucias, el problema de las lecturas no repetibles. Aunque en dicho nivel se siguen dando las lecturas fantasmas.&lt;/li&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Serializable&lt;/b&gt; (Lecturas en serie): Soluciona todos los problemas descritos. Para ello ordena las transacciones con el objetivo de que no entren en conflicto. Este nivel de aislamiento es bastante problemático ya que es, con diferencia, el que más sacrifica en rendimiento y concurrencia.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;Hasta aquí hemos llegado con la teoría, ahora vamos a ver como MySQL nos permite trabajar con cualquiera de estos niveles de aislamiento (eso sí, siempre que utilicemos el motor de tabla InnoDB). Si deseamos conocer el nivel de aislamiento con el que actualmente está trabajando nuestro servidor no tenemos más que lanzar la sentencia: &lt;span style="font-style: italic;"&gt;SHOW VARIABLES LIKE 'tx_isolation'&lt;/span&gt;. De esta manera la salida que obtendremos será similar a la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_P7rsN_IgHak/RtlQp8q2cXI/AAAAAAAAABE/tvgYZFM2Bng/s1600-h/mysql1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_P7rsN_IgHak/RtlQp8q2cXI/AAAAAAAAABE/tvgYZFM2Bng/s320/mysql1.png" alt="" id="BLOGGER_PHOTO_ID_5105200334191882610" border="0" /&gt;&lt;/a&gt;En mi caso con MySQL 5 aparece que el nivel de aislamiento es el de&lt;span style="font-weight: bold;"&gt; REPEATABLE-READ&lt;/span&gt;. Para cambiarlo directamente desde la línea de comando de MySQL lo podemos hacer con la sentencia:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-style: italic;"&gt;SET&lt;/span&gt; {&lt;span style="font-style: italic;"&gt;GLOBAL&lt;/span&gt; | &lt;span style="font-style: italic;"&gt;SESSION&lt;/span&gt;} &lt;span style="font-style: italic;"&gt;TRANSACTION ISOLATION LEVEL&lt;/span&gt; {&lt;span style="font-style: italic;"&gt;READ&lt;/span&gt; &lt;span style="font-style: italic;"&gt;UNCOMMITTED&lt;/span&gt; | &lt;span style="font-style: italic;"&gt;READ&lt;/span&gt; &lt;span style="font-style: italic;"&gt;COMMITED&lt;/span&gt; | &lt;span style="font-style: italic;"&gt;REPEATABLE&lt;/span&gt; &lt;span style="font-style: italic;"&gt;READ&lt;/span&gt;  | &lt;span style="font-style: italic;"&gt;SERIALIZABLE}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;A través de ella podemos especificar el nivel de aislamiento tanto para la sesión actual (SESSION) como para el servidor (GLOBAL). También es posible establecer el nivel de aislamiento al arranzar el servidor con el argumento&lt;span style="font-style: italic;"&gt; --transation-isolation&lt;/span&gt; o modificando el fichero de configuración del servidor &lt;span style="font-style: italic;"&gt;my.cfg&lt;/span&gt;.&lt;br /&gt;Para terminar sólo quiero especificar que esta cualidad de mysql es válida a partir de la versión &lt;span style="font-weight: bold;"&gt;4.0.5&lt;/span&gt; y al igual que en el artículo anterior estoy totalmente abierto a sugerencias, críticas y demás. Un saludo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1507867380128235429-195374923564246542?l=recetasinformaticas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recetasinformaticas.blogspot.com/feeds/195374923564246542/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1507867380128235429&amp;postID=195374923564246542' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/195374923564246542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/195374923564246542'/><link rel='alternate' type='text/html' href='http://recetasinformaticas.blogspot.com/2007/09/mysql-niveles-de-aislamiento-isolations.html' title='MySQL: Niveles de aislamiento (Isolations levels)'/><author><name>Juan Ángel Gascón Moya</name><uri>http://www.blogger.com/profile/03601148345319659146</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_P7rsN_IgHak/RtlQp8q2cXI/AAAAAAAAABE/tvgYZFM2Bng/s72-c/mysql1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1507867380128235429.post-2908195450656319147</id><published>2007-08-09T15:51:00.000+02:00</published><updated>2007-08-12T21:24:05.505+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PDF'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Informática'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Impresión'/><title type='text'>Generación e impresión de informes en formato PDF desde Java con software libre</title><content type='html'>Hola Mundo!&lt;br /&gt;Bueno, como se puede apreciar, quiero comenzar con este blog con buen humor y con un tema que, a mi parecer, resulta muy interesante. Hace unos días me topé con la tediosa labor de abordar el desarrollo de una aplicación java que fuera capaz de generar informes en formato PDF, y lo más difícil, imprimirlos. Tras muchos calentamientos de cabeza (sobre todo con el asunto de la impresión bajo Java) y muchísimas horas &lt;span style="font-style: italic;"&gt;googleando&lt;/span&gt; llegué a encontrar la solución a este problema, y lo que es mejor aún, a través del uso de &lt;span style="font-weight: bold;"&gt;software libre&lt;/span&gt; ;-) . Seguidamente detallo el proceso.&lt;br /&gt;Lo primero que necesitamos es descargar la herramienta de generación de informes &lt;span style="font-weight: bold;"&gt;DataVision &lt;/span&gt;(&lt;a href="http://datavision.sourceforge.net/"&gt;http://datavision.sourceforge.net&lt;/a&gt;). Esta herramienta, aunque sencilla, es de gran flexibilidad y se integra a la perfección con Java. Una vez descargada la descomprimimos y accedemos al directorio que se ha generado. Llegados aquí vemos varios archivos, los más importantes &lt;span style="font-style: italic;"&gt;datavision.bat&lt;/span&gt; y &lt;span style="font-style: italic;"&gt;datavision.sh&lt;/span&gt;. Ejecutaremos el que corresponda en función a nuestro sistema operativo y nos aparecerá un cuadro de diálogo inicial en el que se nos muestran las opciones iniciales:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_P7rsN_IgHak/Rrsg6X0Vx7I/AAAAAAAAAAM/pxR2dCbrA_E/s1600-h/dv_1.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_P7rsN_IgHak/Rrsg6X0Vx7I/AAAAAAAAAAM/pxR2dCbrA_E/s320/dv_1.PNG" alt="" id="BLOGGER_PHOTO_ID_5096703590497896370" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Aquí le diremos a DataVision que deseamos crear un nuevo informe, por lo que pinchamos sobre el botón &lt;span style="font-style: italic;"&gt;Start a New Report&lt;/span&gt;. Con ello este cuadro de diálogo se cerrará para dejar paso a una ventana que, a priori, nos puede intimidar ya que parece que nos pide gran cantidad de información. No hemos de asustarnos ya que ese no es el objetivo de esta última ventana, sino que lo que nos requiere es información acerca de la conexión con el DBMS (Servidor de Bases de Datos Relacionales). Habremos de cumplimentar dicha información:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr7dnX0Vx-I/AAAAAAAAAAk/CGP0qrlF1Jc/s1600-h/dv2.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr7dnX0Vx-I/AAAAAAAAAAk/CGP0qrlF1Jc/s320/dv2.PNG" alt="" id="BLOGGER_PHOTO_ID_5097755496708163554" border="0" /&gt;&lt;/a&gt;Para el que ande un poco perdido:&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Nombre de Clase del Controlador&lt;/span&gt;: Nombre de la clase que sirve como driver para JDBC. En mi caso, como estoy utilizando el SGBDR MySQL, utilizo la clase com.mysql.jdbc.Driver que previamente descargué de &lt;a href="http://www.mysql.org/"&gt;http://www.mysql.org&lt;/a&gt;. Por cierto, nunca hay que olvidar añadir el paquete jar que contiene dicha clase a la variable de entorno CLASSPATH. &lt;span style="font-weight: bold;"&gt;Información de la Conexión&lt;/span&gt;: Es la cadena de conexión JDBC. La que he usado yo es &lt;span style="font-style: italic;"&gt;jdbc:mysql://localhost&lt;/span&gt;&lt;span style="font-style: italic;"&gt;/blog&lt;/span&gt;. Ya que estoy accediendo, a través de JDBC, a la base de datos &lt;span style="font-style: italic;"&gt;blog &lt;/span&gt;de un servidor MySQL que tengo instalado en mi máquina local.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Nombre de la Base de Datos, Nombre de Usuario y Contraseña&lt;/span&gt;: Bueno, con respecto a esto creo que hay poco que decir.&lt;br /&gt;Proporcionados los datos correctos pulsamos sobre el botón &lt;span style="font-style: italic;"&gt;Aceptar&lt;/span&gt; y, si todo ha ido bien, nos aparecerá la siguiente ventana:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_P7rsN_IgHak/Rr7bVH0Vx9I/AAAAAAAAAAc/wUaYg_kv0gw/s1600-h/dv3.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_P7rsN_IgHak/Rr7bVH0Vx9I/AAAAAAAAAAc/wUaYg_kv0gw/s320/dv3.PNG" alt="" id="BLOGGER_PHOTO_ID_5097752984152295378" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;En ella nos aparecen las secciones del informe y una barra de menú, a través de la cual se puede acceder a las distintas opciones. Si no estamos familiarizados con las secciones de un informe podemos consultar la documentación de  DataVision (en formato HTML). En mi caso voy a realizar el informe para una tabla de alumnos, de los que almaceno su DNI, nombre, sexo y fecha de nacimiento.&lt;br /&gt;Podemos comenzar añadiendo al encabezado del informe un título, como por ejemplo: &lt;span style="font-style: italic;"&gt;Informe sobre los alumno&lt;/span&gt;s. Para ello seleccionamos Insertar-&gt;Texto. Pinchamos la sección &lt;span style="font-style: italic;"&gt;Encabezado del reporte&lt;/span&gt; y escribimos el texto. Si deseamos modificar el formato del texto no tenemos más que acceder a Formato-&gt;Formato de campo. Ahora vamos a insertar lo que verdaderamente nos importa: los datos de nuestra tabla. Para hacer esto pulsamos en Insertar-&gt;Campo de Base de datos. Nos parece una nueva ventana en la cual accedemos a la tabla que deseemos y arrastramos los campos necesarios sobre la sección &lt;span style="font-style: italic;"&gt;Detalle &lt;/span&gt;del informe. Una vez situados, si es necesario, podemos acceder al menú &lt;span style="font-style: italic;"&gt;Formato&lt;/span&gt; el cual nos posibilita poner a punto ciertos aspectos tales como la alineación y el tamaño. Finalmente, en el pie de pagina vamos a insertar dos campos especiales: numero de página y nombre del autor. Para ello procedemos de forma similar a la que hemos hecho para insertar los campos de la tabla. Si hemos seguido estas indicaciones el aspecto final del informe es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr7vNX0Vx_I/AAAAAAAAAAs/RSXnqT1nhdw/s1600-h/dv4.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr7vNX0Vx_I/AAAAAAAAAAs/RSXnqT1nhdw/s320/dv4.PNG" alt="" id="BLOGGER_PHOTO_ID_5097774841240864754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Para guardar este informe y que pueda ser accedido a través de Java vamos a pulsar sobre Archivo-&gt;Guardar. Elegimos la ruta donde queremos almacenarlo y le nombraremos, por ejemplo, alumnos.xml. Antes de guardar el fichero también es interesante acceder al menú Archivo-&gt;Tamaño de papel y modificar el valor dado, ya que lo más normal es generar el informe para tamaño A4.&lt;br /&gt;Llegados hasta aquí ya estamos listos para generar nuestro informe en formato PDF desde Java. A continuación se muestra un sencillo programa que genera el informe anterior en PDF y establece el nombre del autor del informe en tiempo de ejecución:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import jimm.datavision.*;&lt;br /&gt;import jimm.datavision.layout.pdf.PDFLE;&lt;br /&gt;import java.sql.Connection;&lt;br /&gt;import java.sql.DriverManager;&lt;br /&gt;import java.io.FileOutputStream;&lt;br /&gt;import java.io.File;&lt;br /&gt;&lt;br /&gt;public class Ejemplo{&lt;br /&gt;public static void main(String[] args){&lt;br /&gt; Report r = new Report();&lt;br /&gt; Connection con = null;&lt;br /&gt;&lt;br /&gt; try{&lt;br /&gt;     Class.forName("com.mysql.jdbc.Driver");&lt;br /&gt;     con = DriverManager.getConnection("jdbc:mysql://localhost/blog",&lt;br /&gt;                         "root", "passwd");&lt;br /&gt;&lt;br /&gt;     r.setDatabaseConnection(con);&lt;br /&gt; }&lt;br /&gt; catch(Exception e){&lt;br /&gt;     System.err.println(e.getMessage());&lt;br /&gt;     System.exit(-1);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; FileOutputStream pdf = null;&lt;br /&gt; File xml = null;&lt;br /&gt;&lt;br /&gt; try{&lt;br /&gt;     pdf = new FileOutputStream("C:\\alumnos.pdf");&lt;br /&gt;     xml = new File("C:\\alumnos.xml");&lt;br /&gt; }&lt;br /&gt; catch(Exception e){&lt;br /&gt;     System.err.println(e.getMessage());&lt;br /&gt;     System.exit(-2);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; try{ r.read(xml); }&lt;br /&gt; catch(Exception e){ System.exit(-3); }&lt;br /&gt;&lt;br /&gt; r.setAuthor("Juan Ángel Gascón Moya");&lt;br /&gt; r.setLayoutEngine(new PDFLE(pdf));&lt;br /&gt; r.runReport();&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Para poder compilar este programa es necesario tener en el CLASSPATH los ficheros jar que contiene el directorio bin de DataVision y el driver del DBMS. Como se aprecia en el fuente DataVision nos proporciona una clase, &lt;span style="font-style: italic;"&gt;Report&lt;/span&gt;, que es la que vamos a utilizar para generar nuestros informes. Una vez creado un objeto de dicha clase debemos de proporcionarle la información necesaria para que sea capaz de acceder a la base de datos. Existen varias maneras, pero en este ejemplo se ha optado por llamar al método &lt;span style="font-style: italic;"&gt;setDatabaseConnection&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;java.sql.Connection&lt;/span&gt;) el cual recibe como parámetro un objeto Connection que esté inicializado. Lo siguiente que hay que hacer es indicarle al objeto Report cuál es el fichero XML que generamos anteriormente con DataVision. Para hacer esto utilizamos el método &lt;span style="font-style: italic;"&gt;read&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;java.io.File&lt;/span&gt;). Dicha operación recibe un objeto de tipo File que ya esté inicializado con el fichero XML al que se va a acceder. Ahora hemos de establecer el formato con el que deseamos que se genere el informe, por eso hacemos uso del método &lt;span style="font-style: italic;"&gt;setLayoutEngine&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;jimm.datavision.layout.LayoutEngine&lt;/span&gt;). DataVision nos permite generar informes en múltiples formatos como HTML, texto separado por comas, XML, LaTeX... En nuestro caso como vamos a crear un informe en formato PDF utilizamos la clase &lt;span style="font-style: italic;"&gt;jimm.datavision.layout.pdf.PDFLE&lt;/span&gt;. El único constructor de esta clase recibe como argumento un objeto de la clase abstracta &lt;span style="font-style: italic;"&gt;java.io.OutputStream&lt;/span&gt;. En este caso concreto se ha utilizado un objeto FileOutputStream que indica el fichero PDF que se va a generar. También se puede apreciar que se ha establecido en tiempo de ejecución el nombre del autor del informe. Es importante que los métodos como este, que establecen ciertas propiedades del informe, sean llamados tras la ejecución del método &lt;span style="font-style: italic;"&gt;read&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;java.io.File&lt;/span&gt;) ya que en otro caso no surtirán ningún efecto. En la última línea se hace una llamada al método &lt;span style="font-style: italic;"&gt;runReport&lt;/span&gt;() el cual es el encargado de realizar la generación del informe a partir de los datos que previamente le hemos proporcionado. Además de este método existe el método &lt;span style="font-style: italic;"&gt;run&lt;/span&gt;() que realiza exactamente la misma función, pero en un hilo (&lt;span style="font-style: italic;"&gt;thread&lt;/span&gt;) a parte.&lt;br /&gt;Pues bien lo único que nos queda es compilar y luego ejecutar este programa para obtener nuestro informe en formato PDF. Como ya se ha dicho antes, es muy importante que todos los ficheros jar utilizados estén en el CLASSPATH. Si hacemos uso de un buen entorno de desarrollo nuestra labor se verá bastante simplificada. Como opinión personal recomiendo el IDE netbeans (&lt;a href="http://www.netbeans.org/"&gt;http://www.netbeans.org&lt;/a&gt;) el cual considero como un excelente entorno de desarrollo para java, y además es software libre.&lt;br /&gt;&lt;br /&gt;Bueno, hasta aquí hemos llegado para realizar la generación de informes en formato PDF, pero ahora viene la parte más complicada: imprimir un archivo PDF desde java. Digo que esta parte es complicada y el que halla tenido que abordar el tema de impresión desde java, y en especial, la impresión de ficheros en formato PDF sabe porque lo digo. Para realizar esta labor vamos a hacer uso de, como no, software libre: &lt;span style="font-weight: bold;"&gt;PDFBox&lt;/span&gt; (&lt;a href="http://www.pdfbox.org/"&gt;http://www.pdfbox.org/&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Los propios autores de PDFBox lo definen como &lt;span style="font-style: italic;"&gt;una librería open source para java trabajar con documentos PDF&lt;/span&gt;. Además incluye un conjunto de programas (hechos en java, por supuesto) para trabajar con ficheros PDF desde la línea de comando. Estos programas van desde encriptadores y extractores de texto hasta conversores de PDF a imagen y, el más importante en el tema que abordamos, impresores de PDF. Concretamente el programa que nos permite imprimir un fichero PDF desde el prompt de nuestra línea de comando es el &lt;span style="font-weight: bold;"&gt;PrintPDF&lt;/span&gt;. Este comando, además de las opciones que se desee incluir, recibe un único argumento: el documento PDF a imprimir. Si deseamos imprimir el informe PDF generado anteriormente operaremos de la siguiente forma:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Una vez descargado PDFBox lo descomprimimos.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Accedemos a través de una terminal al directorio lib.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Lanzamos el comando para imprimir. En mi caso, que me he descargado la versión 0.7.3 y estoy utilizando windows, lo hago de la siguiente manera:&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt; prompt&gt; java -cp ..\external\FontBox-0.1.0-dev.jar;&lt;br /&gt;.\PDFBox-0.7.3.jar; org.pdfbox.PrintPDF&lt;br /&gt;c:\alumnos.pdf&lt;br /&gt;&lt;/pre&gt;Nótese que además de incluir el fichero jar de PDFBox en el CLASSPATH también he añadido el paquete FontBox ya que es requerido por el anterior. También hay que tener cuidado si estamos en Linux ya que el separador que debemos de usar para la variable de entorno es : en lugar del ; que se utiliza en Windows. Al lanzar el comando nos aparecerá una ventana similar a esta:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr9YVH0VyAI/AAAAAAAAAA0/2-7rWOotPzU/s1600-h/dv7.PNG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_P7rsN_IgHak/Rr9YVH0VyAI/AAAAAAAAAA0/2-7rWOotPzU/s320/dv7.PNG" alt="" id="BLOGGER_PHOTO_ID_5097890423105767426" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;A partir de aquí podremos imprimir el documento. Las formas de integrar esta funcionalidad en nuestra aplicación java son varias. Podemos usar directamente el comando mediante &lt;span style="font-style: italic;"&gt;Runtime&lt;/span&gt;.&lt;span style="font-style: italic;"&gt;getRuntime&lt;/span&gt;().&lt;span style="font-style: italic;"&gt;exec&lt;/span&gt;(&lt;span style="font-style: italic;"&gt;java.lang.String&lt;/span&gt;), o, como al ser open source el código fuente, está incluido, podemos adaptar el programa PrintPDF a nuestra aplicación codificándolo como una clase. Esto es una decisión personal del programador por lo que no indagaré más en este asunto.&lt;br /&gt;&lt;br /&gt;Y ya poco más que decir. Tanto DataVision como PDFBox son compatibles con apache ant (&lt;a href="http://ant.apache.org/"&gt;http://ant.apache.org&lt;/a&gt;). Esto hace mucho más fácil la modificación y recompilación del fuente. También, quiero decir que en este artículo he expuesto una mínima parte, tanto de DataVision como de PDFBox. Ambas aplicaciones constan de multitud de clases y librerías, además son muchas sus funcionalidades. Por ello animo a cualquiera que tenga interés en este software que pase por las webs de estas respectivas aplicaciones y consulte su documentación.&lt;br /&gt;&lt;br /&gt;Espero que este artículo halla sido de utilidad y estoy abierto a cualquier comentario. Un saludo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1507867380128235429-2908195450656319147?l=recetasinformaticas.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://recetasinformaticas.blogspot.com/feeds/2908195450656319147/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1507867380128235429&amp;postID=2908195450656319147' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/2908195450656319147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1507867380128235429/posts/default/2908195450656319147'/><link rel='alternate' type='text/html' href='http://recetasinformaticas.blogspot.com/2007/08/generacin-e-impresin-de-informes-en.html' title='Generación e impresión de informes en formato PDF desde Java con software libre'/><author><name>Juan Ángel Gascón Moya</name><uri>http://www.blogger.com/profile/03601148345319659146</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_P7rsN_IgHak/Rrsg6X0Vx7I/AAAAAAAAAAM/pxR2dCbrA_E/s72-c/dv_1.PNG' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
