|
Buscador
Secciones
Otras zonas
Registro
Foros
Recomendamos
|
Omitiendo el impacto del consumo de memoria en el rendimiento general del sistema, el procesamiento usando el API DOM normalmente es más lento que usando el API SAX, principalmente porque el API DOM podría tener primero que cargar todo el documento en memoria para permitir que sea editado o que los datos sean recuperados facilmente, mientras que el API SAX permite un procesamiento inmediato mientras el documento es analizado. Por lo tanto, DOM debería utilizarse cuando el documento fuente va a ser editado o procesado varias veces. SAX es muy conveniente cuando queremos extraer información de un documento XML (el contenido de un elemento o el valor de un atributo) sin importar el contexto general -- su posición en el árbol del documento XML, o si la estructura del documento se mapea exactamente con la extructura de objetos de lógica de negocio. De otra forma, seguir la pista de los elmentos anidados podría ser muy tedioso y podría hacerse mejor usando DOM. A pesar de todo, cuando un documento fuente va a ser mapeado a objetos de negocio que no son representados principalmene como un árbol DOM, se recomienda usar SAX para mapear directamente a los objetos de negocio, evitando una representación intermedia consumidora de recursos. Por supuesto, si los objetos de negocio tienen una representación directa en Java, se pueden usar las tecnologías como XML Data Binding (JAXB). Como las tecnologías de alto nivel como XSLT tratan con tecnologías de nivel más bajo como SAX y DOM, el rendimiento cuando usamos estas tecnologías podría verse impactado por el uso de SAX o DOM. JAXP proporciona soporte para implementaciones de XSLT que aceptan una fuente de entrada y un resultado de salida en la forma de eventos SAX. Cuando construyamos complejas tuberías de procesamiento XML, podemos usar SAXTransformerFactory de JAXP para procesar el resultado de otra hoja de estilo de transformación con otra hoja de estilo. Trabajar con eventos SAX hasta el último estadio de una tubería optimizará el rendimiento evitando la creacción de estructuras de datos en memoria como árboles DOM.
|
|
Nota:
Para las especificaciones XML, un analizador sin validación no es necesario que lea las entidades externas (inlcuyendo el DTD externo); por lo tanto, las entidades externas referenciadas en el documento podrían no ser expandidas y los atributos podrían no ser sustituidos por sus valores por defecto. En dicho caso, la información pasada a la aplicación llamante podría no ser la misma cuando se usa un analizador con o sin validación. En el contexto de este tutorial, sólo estamos considerando analizadores que, incluso aunque son sin validación, hacen -- por defecto, o a través de la configuración apropiada -- la carga y análisis del DTD y las entidades referenciadas en el documento. Esto permite, por ejemplo, que las entidades sean sustituidas, los valores de atributos normalizados, y sus valores por defecto apropiadamente sustituidos, para que la aplicación se pueda ejecutar sin modificar cuando cambia de validación a no validación del documento de entrada. |
Código de ejemplo 5: Un dócumento XML inválido. XML válido, pero el dominio de la aplicación inválido: dos peones están en la misma posición; la validación XML no descarga en la aplicación el esfuerzo de algunas restricciones específicas del dominio:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE CHESSBOARDS SYSTEM "dtd/Chessboards.dtd"> <CHESSBOARDS> <CHESSBOARD> <WHITEPIECES> <KING><POSITION COLUMN="G" ROW="1" /></KING> <BISHOP><POSITION COLUMN="D" ROW="6" /></BISHOP> <ROOK><POSITION COLUMN="E" ROW="1" /></ROOK> <PAWN><POSITION COLUMN="A" ROW="4" /></PAWN> <PAWN><POSITION COLUMN="A" ROW="4" /></PAWN> <PAWN><POSITION COLUMN="B" ROW="3" /></PAWN> <PAWN><POSITION COLUMN="C" ROW="2" /></PAWN> <PAWN><POSITION COLUMN="F" ROW="2" /></PAWN> <PAWN><POSITION COLUMN="G" ROW="2" /></PAWN> <PAWN><POSITION COLUMN="H" ROW="5" /></PAWN> </WHITEPIECES> <BLACKPIECES> <KING><POSITION COLUMN="B" ROW="6" /></KING> <QUEEN><POSITION COLUMN="A" ROW="7" /></QUEEN> <PAWN><POSITION COLUMN="A" ROW="5" /></PAWN> <PAWN><POSITION COLUMN="D" ROW="4" /></PAWN> </BLACKPIECES> </CHESSBOARD> <CHESSBOARD> ... </CHESSBOARD> </CHESSBOARDS>
En un sistema con componentes que intercambian documentos, el coste de la validación puede reducirse eficientemente teniendo en cuenta las siguientes observaciones (ver la Ilustración 1):
Por ejemplo, una aplicación de negocios multi-capa que intercambia documentos con partners a través de la red forzará la validación en la capa web (capa inicial) de cualquier documento entrante. No sólo chequea la validación del documento contra un esquema, también se asegurará de que el tipo del documento es uno (o el único) que puede aceptarse. Entonces los documentos podrían ser enrutados a otros servidores para ser manejados por los servicios apropiados. Como los documentos ya se han validado no requieren posteriores validaciones.
En otras palabras, cuando nosotros somos el productor y el consumidor de documentos XML podríamos usar la validación sólo para depurar y desactivarla durante la producción.

Aún, incluso sin validación, las DTDs y las entidades referenciadas en los documentos necesitan ser cargadas y analizadas permitiendo a las entidades ser sustituidas, a los valores de atributos ser normalizados o sus valores por defecto apropiadamente sustituidos.
En este extremo, los documento sin DTDs no requieren validación. Como no se refieren a ninguna DTD o entidad externa, no se carga o analiza nada y no se puede hacer la validación. El rendimiento es por lo tanto mejor. Esta solución extrema, como no es viable para intercambiar documentos XML entre aplicaciones, puede usarse entre los componentes de una aplicación XML. En este caso particular, la declaración de tipo de documento podria insertarse durante la depuración para activar la validación, y ser omitida en un entorno de producción.
Aún un documento conforme a una DTD, puede, después de una validación opcional, ser convertido en un documento equivalente que no requerirá validación o sustitución de entidades externas usando el proceso de canonizalización XML. Este proceso, que se describe más abajo, no fue pensado originalmene para mejorar el rendimiento, pero podríamos beneficiarnos de él bajo ciertas situaciones y con ciertas limitaciones.
Cualquier documento puede ser convertido en un equivalente (con algunas limitaciones) a un documento sin DTD a través de un proceso XML llamado Canonizalización. El documento generado se llama un documento XML Canónico.
| "Cualquier documento XML es parte de un conjunto de documentos XML que son equivalentes lógicos dentro de un contexto de aplicación, pero que podrían variar en la representación física basada en los cambios de sintaxis permitidos por XML 1.0 y Namespaces en XML. Esta especificación describe un método para generar una representación física, la forma canónica, de un documento XML que cuenta con los cambios permisibles. Excepto para las limitaciones de unos pocos casos inusuales, si dos documentos tienen la misma forma canónica, los dos documentos son lógicamente equivalentes dentro de un contexto de aplicación dado. Observa que los dos documentos podrían tener formas canónicas diferentes y todavía ser equivalentes en un contexto dado basado en las reglas de equivalencia específicas de la aplicación para las que la especificación XML generalizada podría no tenerse en cuenta" -- Extraído de Canonical XML Version 1.0 - W3C Recommendation 15 March 200. |
El proceso de canonizalización resulta en algunos cambios en el documento original, entre otros:
Aunque la canonizalización no se ha pensado para este propósito, podemos usarlo para mejorar el rendimiento. El frontal de una aplicación de negocios electrónico desde nuestros ejemplos anteriores podría verse mejorado para validar el documento entrante y generar una forma canónica de los documentos que son enrutados a los servicios apropiados. Los servicios finales están disponibles para analizar el documento mucho más rápidametne ya que no se requiere validación y el documento no se refiere a ninguna entidad externa. Los documentos canónicos generados, aunque tienen la misma estructura lógica, no comparten la misma estructura física que los documentos originales. La aplicación por lo tanto, podría requerir que la versión original sea archivada al principio del proceso de tubería.
Desafortunadamente, hasta ahora, no hay un método de salida XSL estándard que pudiera ser utilizado con el identity transformer (presentado arriba) para generar una forma canónica de un documento fuente. Para generar esta forma canónica podríamos tener que escribir un ContentHandler de SAX2 personalizado. La distribución Xerces incluye programas de ejemplo (sax.SAX2Writer o sax.Writer por ejemplo) que generan XML canónico.
El código de ejemplo de abajo muestra la forma canónica de un documento XML. Observa la ausencia de las declaraciones XML y DTD y el reemplazo de cada ruptura de línea por un #xA. Aunque siendo equivalente en la estrructura lógica, no comparte la misma estructura física y es bastante menos leíble. Por lo tanto, si se tuviera que hacer algún archivado debería hacerse con el documento original.
Código de ejemplo 6: La forma canónica de uno de los documentos Chessboards-[10-5000].xml (se han reintroducido rupturas de líneas después de alguno de los caracteres 
 para propósitos de lectura):
<CHESSBOARDS>
 <CHESSBOARD>
 <WHITEPIECES>
 <KING><POSITION COLUMN="G" ROW="1"></POSITION></KING>
 <BISHOP><POSITION COLUMN="D" ROW="6"></POSITION></BISHOP>
 <ROOK><POSITION COLUMN="E" ROW="1"></POSITION></ROOK>
 <PAWN><POSITION COLUMN="A" ROW="4"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="B" ROW="3"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="C" ROW="2"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="F" ROW="2"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="G" ROW="2"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="H" ROW="5"></POSITION></PAWN>
 </WHITEPIECES>
 <BLACKPIECES>
 <KING><POSITION COLUMN="B" ROW="6"></POSITION></KING>
 <QUEEN><POSITION COLUMN="A" ROW="7"></POSITION></QUEEN>
 <PAWN><POSITION COLUMN="A" ROW="5"></POSITION></PAWN>
 <PAWN><POSITION COLUMN="D" ROW="4"></POSITION></PAWN>
 </BLACKPIECES>
</CHESSBOARD>
 ... </CHESSBOARDS>
El gráfico de abajo meustra el tiempo relativo para procesar un documento XML en su forma original y en su forma canónica. Dependiendo de la complejidad del esquema y del número de entidades externas referidas, la diferencia de rendimienro podría ser incluso mayor:

AL igual que la validación, la canonizalización podría ser activada sólo en un entorno de producción, cuando buscamos el mejor rendimiento. La canonizalización sólo puede usarse si los documentos XML canónicos y los documentos originales son equivalentes. Si la aplicación trata, por ejemplo, sobre comentarios u otros eventos léxicos generados por el anlizador, la canonizalización no puede ser utilizada. Cualquier variante de este proceso se puede aplicar siempre que ámbas formas del documento XML - el original y el refinado - sean equivalentes para la aplicación.

Reducir el Coste de Referenciar Entidades ExternasLas entidades externas incluyendo subconjuntos de DTD externos, requieren que sean cargadas y analizadas, incluso cuando son sin validación, para poder ofrecer la misma información a la aplicación sin importar la validación. Los documentos independientes no referencian ninguna entidad externa pero todavía podrían usar subconjuntos DTD internos. Por lo tanto, evitando la carga de entidades externas, se podría mejorar el rendimiento, especialmente comparado con los casos donde el DTD u otras entidades externas residen en un repositorio no local.
De cualquier forma, los documentos independientes podrían no ser la solución especialmente en el caso de los documentos de negocios intercambiables que tratan con esquemas XML públicos que están publicados en algúnr registro común o repositorio.
Código de ejemplo 7: Un documento XML independiente, el DTD ha sido embebido como un subconjunto DTD interno. El rendimiento se podría mejorar especialmetne comparandolo con una situación donde el DTD es un subconjunto DTD externo localizado en un repositorio remoto.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE CHESSBOARD [ <!ELEMENT CHESSBOARD (WHITEPIECES, BLACKPIECES)> <!ENTITY % pieces "KING, QUEEN?, BISHOP?, BISHOP?, ROOK?, ROOK?, KNIGHT?, KNIGHT?, PAWN?, PAWN?, PAWN?, PAWN?, PAWN?, PAWN?, PAWN?, PAWN?" > <!ELEMENT WHITEPIECES (%pieces;)> <!ELEMENT BLACKPIECES (%pieces;)> <!ELEMENT POSITION EMPTY> <!ATTLIST POSITION COLUMN (A|B|C|D|E|F|G|H) #REQUIRED ROW (1|2|3|4|5|6|7|8) #REQUIRED > <!ELEMENT KING (POSITION)> <!ELEMENT QUEEN (POSITION)> <!ELEMENT BISHOP (POSITION)> <!ELEMENT ROOK (POSITION)> <!ELEMENT KNIGHT (POSITION)> <!ELEMENT PAWN (POSITION)> ]> <CHESSBOARD> <WHITEPIECES> <KING><POSITION COLUMN="G" ROW="1"/></KING> <BISHOP><POSITION COLUMN="D" ROW="6"/></BISHOP> <ROOK><POSITION COLUMN="E" ROW="1"/></ROOK> <PAWN><POSITION COLUMN="A" ROW="4"/></PAWN> <PAWN><POSITION COLUMN="B" ROW="3"/></PAWN> <PAWN><POSITION COLUMN="C" ROW="2"/></PAWN> <PAWN><POSITION COLUMN="F" ROW="2"/></PAWN> <PAWN><POSITION COLUMN="G" ROW="2"/></PAWN> <PAWN><POSITION COLUMN="H" ROW="5"/></PAWN> </WHITEPIECES> <BLACKPIECES> <KING><POSITION COLUMN="B" ROW="6"/></KING> <QUEEN><POSITION COLUMN="A" ROW="7"/></QUEEN> <PAWN><POSITION COLUMN="A" ROW="5"/></PAWN> <PAWN><POSITION COLUMN="D" ROW="4"/></PAWN> </BLACKPIECES> </CHESSBOARD>
Cachear Entidades ExternasCachear usando un Proxy Cache
Las referencias a entidades externas localizadas en un repositorio remoto podrían ser mejoradas seleccionando un proxy que almacene cualquier documento recuperado y especialmente las entidades externas -- proporcionando las referencias a las entidades externas en URLs cuyos protocolos son manejados por el proxy.

Cachear con un EntityResolver Personalizado
Los analizadores SAX permiten a las aplicaciones XML manejar entidades externas de una forma personalizada. Dichas aplicaciones tienen que registrar su propia implementación del interface org.xml.sax.EntityResolver con el analizador usando el método setEntityResolver. Entonces las aplicaciones pueden interceptar cualquier entidad externa (incluyendo subconjuntos de DTD externos) antes de que sean analizadas.
Esta característica puede utilizarse para implementar:
Ambos mecanismos pueden usarse conjuntametne para asegurarnos incluso un mejor rendimiento. El primero podría usarse para entidades estáticas que tienen un tiempo de vida mayor que el de la aplicación. Este es especialmente el caso de los DTDs públicos que normalmente evolucionan a través de sucesivas versiones, y que incluyen la versión en su identificador público o de sistema. El segundo mecanismo podría primero mapear los identificadores públicos a identificadores del sistema y luego aplicar el mismo mecanismo que un caché por proxy normal cuando se trata con identificadores de sistema en la forma de URL, especialmente chequeando las actualizaciones y evitando el cambio del contenido dinámico.
Código de ejemplo 8: Una simple implementación de Caché para entiades externas (esta implementación esta incompleta: no libera las entradas no usadas en el mapeo de entidades).
import java.lang.ref.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
...
public class EntityCache {
public static final int MAXCHUNCK = 5 * 1024 * 1024;
private Map entities = new HashMap();
private byte[] buf = new byte[MAXCHUNCK];
public InputStream getEntity(String systemId) {
byte[] entity = null;
SoftReference reference
= (SoftReference) entities.get(systemId);
if (reference != null) {
// Got a soft reference to the entity,
// let's get the actual entity.
entity = (byte[]) reference.get();
}
if (entity == null) {
// The entity has been reclaimed by the GC or was
// never created, let's download it again!
return cacheEntity(systemId);
}
return new ByteArrayInputStream(entity);
}
// Attempt to cache an entity - if it's too big
// just return an input stream to it
private InputStream cacheEntity(String systemId) {
try {
BufferedInputStream stream
= new BufferedInputStream(new
URL(systemId).openStream());
int count = 0;
for (int i = 0; count < buf.length; count += i) {
if ((i = stream.read(buf, count, buf.length -
count)) < 0) {
break;
}
}
byte[] entity = new byte[count];
System.arraycopy(buf, 0, entity, 0, count);
if (count != buf.length) { // Not a too big entity
// Cache the entity for future use, using a soft
// reference so that the GC may reclaim it
// if the memory is running low.
entities.put(systemId, new SoftReference(entity));
return new ByteArrayInputStream(entity);
}
// Entity too big to be cached
return new SequenceInputStream(
new ByteArrayInputStream(entity), stream);
} catch (Exception exception) {
// The default EntityResolver will try to get it...
return null;
}
}
}
Código de ejemplo 9: Un simple programa que usa el API SAX e implementa el entity resolver para buscar entiades en un caché de memoria:
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import javax.xml.parsers.*;
...
public class ChessboardSAXPrinter {
private SAXParser parser;
private EntityCache entityCache;
public class ChessboardHandler extends HandlerBase {
public void startElement(String name,
AttributeList attrs) {
// XML processing
...
}
public InputSource resolveEntity(String publicId,
String systemId) {
if (entityCache != null) {
if (systemId != null) {
InputStream stream =
entityCache.getEntity(systemId);
if (stream != null) {
InputSource source = new InputSource(stream);
source.setPublicId(publicId);
source.setSystemId(systemId);
return source;
}
}
}
// Let the default entity resolver resolve this one...
return null;
}
}
public ChessboardSAXPrinter(boolean validating,
boolean caching) throws Exception {
this.entityCache = caching ? new EntityCache() : null;
SAXParserFactory parserFactory
= SAXParserFactory.newInstance();
parserFactory.setValidating(validating);
parser = parserFactory.newSAXParser();
return;
}
}
La mejora de rendimiento es bastante significante, especialmente cuando las entidades externas están localizadas a través de la red:

Cuando se combinan las dos arquitecturas sugeridas para reducir el coste de la validación y el coste de las referencias a entidades externas, la arquitectura resultante se podría parece a esta:

Cachear el Contenido Generado y las Hojas de EstiloEl ejemplo eMobile de aplicación presentado en la Conferencia JavaOne 2000 proporcionana un ejemplo de cómo los servlets pueden generar contenido dirigido a diferentes dispositivos desde valores de objetos devueltos por una aplicación EJB. Las hojas de estilo se aplicación a los árboles DOM construidos desde los valores de los objetos para poder transformarlos en el tipo de contenido objetivo.
Hay dos sitios donde se mejoró el rendimiento de la capa web de la aplicación de ejemplo eMobile:

Cuando todo el contenido generado no podía entrar en el dispositivo (la pantalla WML o la página HTML), el resultado fue dividio entre varias pantallas o páginas para permitir que el usuario nevegara por todo el resultado. Las pantallas o páginas fueron generadas una cada vez sobre la solicitud del usuario desde el árbol DOM. Para evitar llamar de nuevo a la aplicación EJB, el árbol DOM fue almacenado en la sesión del usuario. Cuando se cargó, las hojas de estilo también fueron almacenadas (cacheadas) para evitar tener que recargarlas para cada generación de contenido.
Cachear los resultados de un solicitud de usuario para servir más rápidamente las siguientes peticiones relacionadas consume memoria. No debe hacerse en detremiento de otros usuarios: la aplicación no debe fallar porque se acabe la memoria debidó al caché de resultados. Las referencias blandas introducidas con Java 2 permiten interactúar con el recolector de basura para implementar cachés.
En el contexto de un contenedor web distribuido, la referencia al árbol DOM almacenado en la sesión podría tener que ser declarada como transient, primero porque no todas las implementaciones de DOM son serializables (lo que es un requerimiento para cualquier objeto almacenado en una HttpSession) y segundo porque como veremos luego, la serialización de un árbol DOM podría ser muy costosa y por lo tanto podría afectar a los beneficios del caché.
El siguiente ejemplo de código muestra cómo una consulta y su resultado son cacheados en la sesión asociada del cliente, y cómo el resultado de una consulta realizada anteriormente podría ser recuperado de la sesión. Ese código de ejemplo de la aplicación eMobile ha sido actualizado para tener en cuenta los contenedores web distribuidos.
Código de ejemplo 10: Cachear una consulta y su resultado en la sesión asociada al cliente:
import java.ref.*;
private class CacheEntry implements Serializable
{
Object query;
// If the entry is replicated through serialization
// result will be reset to null
transient SoftReference result = null;
CacheEntry(Object query, Object result) {
this.query = query;
this.result = new SoftReference(result);
Object getResult() {
if (result != null) {
return result.get();
}
return null;
}
}
/**
* Stores the query and its result in the client's
* associated session so that the response to the
* same query will be immediate.
* A soft reference is used so that if the memory is
* running low the GC may reclaim the result objects.
*
* @param query the query, may be the HTTP request
* query string itself...
* @param result the result to the query
* @param session the HTTP session
*/
protected void cacheQueryResult(Object query, Object
result, HttpSession session)
{
session.setAttribute(QUERY_ATTRIBUTE,
new CacheEntry(query, result));
return;
}
/**
* Gets the result of a previously executed query
* that has been cached in the session.
* The previously cached result may be returned only
* if the cached query and the requested query match.
* Since soft references are used a matching result
* may not be returned if the result has already been
* reclaimed by the GC due to a shortage of memory.
*
* @param query the query, may be the HTTP request query
* string itself...
* @param session the HTTP session
* @return the associated matching result if it could be
* retrieved or null
*/
protected Object getCachedQueryResult(Object query,
HttpSession session)
{
CacheEntry entry = (CacheEntry)
session.getAttribute(QUERY_ATTRIBUTE);
if (entry != null) {
// A cached entry was retrieved
Object cachedResult = entry.getResult();
if (cachedResult != null) {
// The referred cached result was not reclaimed by the GC
Object cachedQuery = entry.query;
if (cachedQuery.equals(query)){
// The cached query and the requested query match
if (TRACE) {
System.err.println("Query cache hit.");
}
return cachedResult;
} else if (TRACE) {
System.err.println("Query cache miss (mismatch).");
}
} else if (TRACE) {
System.err.println("Query cache miss (GC).");
}
} else if (TRACE) {
System.err.println("Query cache miss (session).");
}
// The queries didn't match or the cached result could not
// be retrieved, let's just clean
session.removeAttribute(QUERY_ATTRIBUTE);
return null;
}
Cachear las hojas de estilo trata con el mismo principio que cachear los árboles DOM resultantes. Cuando fueron cargadas, las hojas de estilo fueron almacenadas en un hashtable usando referencias blandas donde pueden ser compartidas por todos los servlets.
Junto con esta línea, JAXP 1.1 define el inteface javax.xml.transform.URIResolver que podría implementarse para recuperar recursos referenciados en la hoja de estilo con sentencias xsl:import o xsl:include. En el contexto de una aplicacion que usa un gran conjunto de hojas de estilo, esto podría usarse para implementar el caché de la misma forma que EntityResolver arriba.
Usar Java 2 SE v 1.3 (y superiores)El procesamiento XML consume mucha CPU y mucha memoria. Para una aplicación del laldo del servidor, se obtiene mejor rendimiento usando el servidor de sistema HotSpot que puede ser activado pasando la opción -server cuando se lanza la máquina virtual Java. También hay disponibles algunas otras opciones para configurar el tamaño de la pila y el recolector de basura. La información importante se puede encontrar en Frequently Asked Questions - HotSpot.
Usar XML con ParsimoniaLos documentos XML son documentos de texto. Por lo tanto pueden intercambiarse fácilmente entre sistemas heterogéneos. Pero requieren una fase de análisis que, como se menciono anteriormente, es muy costosa. Es el precio a pagar para permitir que los sistemas debilmente emparejados funcionen -- debilmente emparejados no sólo técnicamente, sino también en el entorno empresarial. Cuando los componentes del sistema están fuertemente acoplados, técnicas no orientadas a documentos "normales" (usando RMI por ejemplo) hasta ahora son más eficientes no sólo en términos de rendimiento sino también en términos de complejidad de código. Con tecnologías como JAXB los dos mundos se pueden combinar eficientemente para desarrollar sistemas que sean internamente fuertemente acoplados, orientados a objetos y que interactúan junto de una forma orientada a documento debilmente acoplada.

Para ilustrar esta sentencia, comparemos el coste de serializar/deserilizar desde/hacia:
Cuando diseñamos las clases Java que implementan todas las piezas (clases (King, Queen, Bishop, Rook, Knight y Pawn) así como las clases que implementan un tablero de ajedrez y un conjunto de tableros (clases Chessboard y Chessboards). Todas estas clases implementan métodos para crear una representación DOM equivalente. También podrían implementar el interface Serializable para que sus ejemplares puedan ser serializados o deserializados desde una forma Java serializada. La clase Chessboards implementa adicionalmente método para serializar a XML y deserializar desde XML.
El fragmento de código de abajo muestra los métodos de la clase Chessboards para serializar a XML y deserializar desde XML, crear un ejemplar desde una representación DOM, y crear una representación DOM desde un ejemplar. Las otras clases (Chessboard, King, Queen...) implementan métodos DOM equivalentes.
Código de ejemplo 11: Implementación de los métodos de Chessboards para serializar/deserializar desde/hacia XML y DOM: la serialización/deserialización desde/hacia un objeto Java serializado simplemente se activa implementando el interface Serializable:
public void toXML(OutputStream out, DocumentBuilder builder,
Transformer transformer) throws Exception {
transformer.transform(new DOMSource(toDOM(builder)),
new StreamResult(out));
return;
}
public Document toDOM(DocumentBuilder builder)
throws Exception {
Document document = builder.newDocument();
Element root
= (Element) document.createElement("CHESSBOARDS");
for (Iterator j = chessboards.iterator(); j.hasNext();) {
Chessboard chessboard = (Chessboard) j.next();
root.appendChild(chessboard.toDOM(document));
}
document.appendChild(root);
return document;
}
public static Chessboards fromXML(String sourceURI,
DocumentBuilder builder)
throws Exception {
Document document = builder.parse(sourceURI);
return fromDOM(document);
}
public static Chessboards fromDOM(Document document)
throws Exception {
Element root = document.getDocumentElement();
if (root.getTagName().equals("CHESSBOARDS")) {
Node child = root.getFirstChild();
Chessboards chessboards = new Chessboards();
do {
if (child.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) child;
if (element.getTagName().equals("CHESSBOARD")) {
chessboards.chessboards.add(Chessboard.fromDOM(element));
}
}
} while ((child = child.getNextSibling()) != null);
return chessboards;
}
throw new IllegalArgumentException(root.getTagName());
}
Para medir los rendimientos hemos implementado tres programas de prueba estructuralmente equivalentes. El primero cargaba el documento original XML describiendo un conjunto de configuraciones de tableros de ajedrez y, en un bucle, lo escribía en un fichero y lo leía de nuevo como un documento XML o como objetos Java serializados. Ejecutamos estos programas de pruebas sobre un conjunto de 1000 configuraciones de tableros de ajedrez, cada uno procesado 10 veces durante 10 ejecuciones. El tiempo medido fue la suma de los tiempos de usuario y de sistema devueltos por el comando ptime, dividido por el número total de serializaciones/deserializaciones.
Código de ejemplo 12: El prorama de ejemplo para serializar/deserializar hacia/desde XML a través de un árbol DOM intemedio.
DocumentBuilderFactory builderFactory
= DocumentBuilderFactory.newInstance();
DocumentBuilder builder
= builderFactory.newDocumentBuilder();
TransformerFactory transformerFactory
= TransformerFactory.newInstance();
Transformer transformer;
transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
"file:dtd/Chessboards.dtd");
transformer.setOutputProperty(OutputKeys.METHOD,
"xml");
// Reading the original XML document
Chessboards chessboards
= Chessboards.fromXML(args[1], builder);
for (int k = 0; k < r; k++) {
for (int i = 0; i < n; i++) {
PrintStream out = new PrintStream(
new BufferedOutputStream(new
FileOutputStream(args[2])));
// Serializing
chessboards.toXML(out, builder, transformer);
out.close();
// Deserializing
chessboards = Chessboards.fromXML(args[2], builder);
}
}
Código de ejemplo 13: El programa de prueba para serializar/deserializar desde/hacia un objeto Java serializado:
// Reading the original XML document
Chessboards chessboards = Chessboards.fromXML(args[1]);
for (int k = 0; k < r; k++) {
for (int i = 0; i < n; i++) {
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(new
FileOutputStream(args[2])));
// Serializing
out.writeObject(chessboards);
out.close();
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(new
FileInputStream(args[2])));
// Deserializing
chessboards = (Chessboards) in.readObject();
in.close();
}
}
Código de ejemplo 14: El programa de prueba para serializar/deserializar desde/hacia un árgol DOM Java serializado:
DocumentBuilderFactory builderFactory
= DocumentBuilderFactory.newInstance();
DocumentBuilder builder
= builderFactory.newDocumentBuilder();
// Reading the original XML document
Chessboards chessboards
= Chessboards.fromXML(args[1], builder);
for (int k = 0; k < r; k++) {
for (int i = 0; i < n; i++) {
ObjectOutputStream out = new ObjectOutputStream(
new BufferedOutputStream(new
FileOutputStream(args[2])));
// Serializing
out.writeObject(chessboards.toDOM(builder));
out.close();
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(new
FileInputStream(args[2])));
// Deserializing
chessboards
= Chessboards.fromDOM((Document) in.readObject());
in.close();
}
}
Los resultados de esto muestran que la serialización directa de objetos de negocio Java no es sólo más rápida que la serialización XML o la serialización de árboles DOM Java, sino que también el objeto serializado resultante es más pequeño que el documento XML serializado o el árbol DOM serializado. La serialización Java del árbol DOM es la más costosa en tiempo de proceso así como en consumo de memoria, por lo tanto debería usarse en casos extremos, especialmente en el contexto de Enterprise JavaBeans (EJB) donde la serialización ocurre cuando se accede a EJBs remotos. Cuando se accede a EJBs locales, árboles DOM o fragmentos de árboles DOM se pueden pasar sin incurrir en el mismo problema.


Las aplicaciones que están internamente orientadas a documento podría estar diseñadas para que sólo la información más relevante y la más accedida sea extraída desde el documento para ser procesada y mapeada en objetos de negocio. Estos objetos de negocio podrían mantener una referencia al documento original (en su forma de texto origianl o en una representación DOM cacheada) para que más información se pueda consultar cuando se necesite desde el documento original usando expresiones XPath o XQuery, por ejemplo.
ConclusiónEn esta página hemos presentado diferentes trucos para mejorar el rendimiento. La primera cuestión a realizarnos cuando desarrollamos aplicaciones basadas en XML es "¿Debería estar basada en XML?" Si la respuesta es si, tenemos que diseñar una arquitectura balanceada, una arquitectura que sólo trate con XML para lo que sea bueno: comunicaciones abiertas entre aplicaciiones, descripciones de configuraciones, compartición de información, o cualquier dominio para que el que pueda existir un esquema XML. Podría no ser la elección para interfaces no expuesto o para intercambio de componentes que de otra forma deberían acoplarse fuertemente. Debería ser el procesamiento XML sólo un estado de pre o post-procesamiento de la lógica de negocio o debería tener sentido para la aplicación tener su estructura de datos principal representada como documentos, el desarrollador tendrá que elegir entre los diferetes APIs e implementaciones considerando no sólo sus funcionalidades y su facilidad de uso, sino también su rendimiento. Por último, las aplicaciones Java basadas en XAML se desarrollan en Java y por lo tanto también se les puede aplicar cualquier regla de mejora de rendimiento Java, especialmente, aquellas que tratan con el procesamiento de strings y la creación de objetos.
| Leer comentarios (8) | |
| Escribir comentario | |
| Puntuación: |
|
| Votar | |
| Recomendar este tutorial | |
| Estadísticas |
Copyright © 1999-2007
Programación en castellano.
Todos los derechos reservados.
Formulario de Contacto -
Datos legales -
Publicidad
Hospedaje web y servidores dedicados linux por Ferca Network
red internet: musica mp3 | logos y melodias | hospedaje web linux | registro de dominios | servidores dedicados
más internet: comprar | recursos gratis | posicionamiento en buscadores | tienda virtual | gifs animados