Retired Document
Important: This document may not represent best practices for current development. Links to downloads and other resources may no longer be valid.
Code Listings
This appendix contains the listings of the example serialization utility classes used in Serializing Objects and Data and Transforming XML Documents and the example transformation script, which is also used in the transformation of XML documents.
BinarySerialization.java
Listing B-1 shows the implementation of the BinarySerialization example class.
Listing B-1 BinarySerializer.java
class
import com.webobjects.appserver.*; |
import com.webobjects.foundation.*; |
import com.webobjects.eocontrol.*; |
import java.io.BufferedInputStream; |
import java.io.BufferedOutputStream; |
import java.io.FileInputStream; |
import java.io.FileOutputStream; |
import java.io.IOException; |
import java.io.ObjectInputStream; |
import java.io.ObjectOutputStream; |
import java.lang.ClassNotFoundException; |
/** |
* Manages serialization and deserialization of objects |
* to and from binary files. |
*/ |
public class BinarySerializer { |
/** |
* Encapsulates a file stream and an object stream (a channel). |
*/ |
private static class Channel { |
protected Object file_stream; |
protected Object object_stream; |
protected boolean input_stream; |
Channel(Object file_stream, Object object_stream, boolean input_stream) { |
this.file_stream = file_stream; |
this.object_stream = object_stream; |
this.input_stream = input_stream; |
} |
} |
/** |
* Stores open channels. |
*/ |
private static NSMutableDictionary channels = new NSMutableDictionary(); |
/** |
* Directory in which serialized data intended for |
* deserialization is stored. |
*/ |
private static final String FILE_PREFIX = "/tmp/"; |
/** |
* Suffix (including extension) of files used to store serialized data. |
*/ |
private static final String FILE_SUFFIX = "_data.binary"; |
/** |
* Serializes data to a file. |
* |
* @param source object to serialize |
* @param identifier file identifier for deserialization |
* (name of the file without the extension) |
* |
* @return <code>true</code> when the process succeeds. |
*/ |
public static boolean serializeObject(Object source, String identifier) { |
ObjectOutputStream binary_stream; |
String filename = FILE_PREFIX + identifier + FILE_SUFFIX; |
boolean success = false; |
try { |
// Create a stream to the output file. |
binary_stream = (ObjectOutputStream)BinarySerializer.openStream(filename, false); |
// Serialize data to output stream. |
binary_stream.writeObject(source); |
// Close the stream. |
binary_stream.flush(); |
closeStream(filename); |
success = true; |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
return success; |
} |
/** |
* Deserializes data from a file. |
* |
* @param identifier file identifier (name of the file |
* without the extension) |
* |
* @return deserialized object. |
*/ |
public static Object deserializeObject(String identifier) { |
ObjectInputStream binary_stream; |
String filename = FILE_PREFIX + identifier + FILE_SUFFIX; |
Object object = null; |
try { |
// Create a stream to the input file. |
binary_stream = (ObjectInputStream)openStream(filename, true); |
// Deserialize data from input stream. |
object = (Object)binary_stream.readObject(); |
// Close the stream. |
closeStream(filename); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
catch (ClassNotFoundException e) { |
e.printStackTrace(); |
} |
return object; |
} |
/** |
* Opens an output stream. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to open. |
*/ |
public static ObjectOutputStream openOutputStream(String filename) throws IOException { |
return (ObjectOutputStream)openStream(filename, false); |
} |
/** |
* Opens an input stream. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to open. |
*/ |
public static ObjectInputStream openInputStream(String filename) throws IOException { |
return (ObjectInputStream)openStream(filename, true); |
} |
/** |
* Opens a file stream to or from a file and a corresponding |
* output or input object stream. |
* The method adds the pair of streams to an internal dictionary |
* for use by the <code>closeStream</code> method. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to open. |
* @param input_stream indicates whether the stream returned |
* is an input stream or an output stream: |
* <code>true</code> for an input stream and |
* <code>false</code> for an output stream. |
* |
* @return object stream, <code>null</code> when the stream could not |
* be created. |
*/ |
private static Object openStream(String filename, boolean input_stream) throws IOException { |
BufferedOutputStream file_output_stream = null; |
BufferedInputStream file_input_stream = null; |
Channel channel; |
Object binary_stream = null; |
if (input_stream) { |
// Create an input stream from the file. |
file_input_stream = new BufferedInputStream(new FileInputStream(filename)); |
// Create object-input stream. |
binary_stream = new ObjectInputStream(file_input_stream); |
channel = new Channel(file_input_stream, binary_stream, input_stream); |
} else { |
// Create an output stream to the file. |
file_output_stream = new BufferedOutputStream(new FileOutputStream(filename)); |
// Create object-output stream. |
binary_stream = new ObjectOutputStream(file_output_stream); |
channel = new Channel(file_output_stream, binary_stream, input_stream); |
} |
channels.setObjectForKey(channel, filename); |
return binary_stream; |
} |
/** |
* Closes an object stream and its corresponding file stream. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the streams to close. |
*/ |
public static void closeStream(String filename) throws IOException { |
Channel channel = (Channel)channels.objectForKey(filename); |
if (channel.input_stream) { |
((ObjectInputStream)channel.object_stream).close(); |
((BufferedInputStream)channel.file_stream).close(); |
} else { |
((ObjectOutputStream)channel.object_stream).close(); |
((BufferedOutputStream)channel.file_stream).close(); |
} |
channels.removeObjectForKey(filename); |
} |
} |
XMLSerializer.java
Listing B-2 shows the implementation of the XMLSerializer example class.
Listing B-2 XMLSerializer.java
class
import com.webobjects.appserver.WOApplication; |
import com.webobjects.appserver.WOResourceManager; |
import com.webobjects.eocontrol.*; |
import com.webobjects.foundation.*; |
import com.webobjects.foundation.xml.*; |
import java.io.BufferedInputStream; |
import java.io.BufferedOutputStream; |
import java.io.File; |
import java.io.FileInputStream; |
import java.io.FileNotFoundException; |
import java.io.FileOutputStream; |
import java.io.InputStream; |
import java.io.IOException; |
import java.io.ObjectOutputStream; |
import java.io.OutputStream; |
import javax.xml.transform.Transformer; |
/** |
* Manages serialization and deserialization of objects |
* to and from XML files. |
*/ |
public class XMLSerializer extends Object { |
/** |
* Encapsulates a file stream and an object stream (a channel). |
*/ |
private static class Channel { |
protected Object file_stream; |
protected Object object_stream; |
protected boolean input_stream; |
Channel(Object file_stream, Object object_stream, boolean input_stream) { |
this.file_stream = file_stream; |
this.object_stream = object_stream; |
this.input_stream = input_stream; |
} |
} |
/** |
* Identifier for a simple transformation. |
*/ |
public static final String TRANSFORM_SIMPLE = "SimpleTransformation"; |
/** |
* Directory where serialized data is stored. |
*/ |
private static final String FILE_PREFIX = "/tmp/"; |
/** |
* Suffix (including extension) of files used to store serialized data. |
*/ |
private static final String FILE_SUFFIX = "_data.xml"; |
/** |
* Stores open channels. |
*/ |
private static NSMutableDictionary channels = new NSMutableDictionary(); |
/** |
* Serializes data to a file. |
* |
* @param source object to serialize |
* @param identifier file identifier for deserialization |
* (name of the file without its path or extension) |
* |
* @return <code>true</code> when the process succeeds. |
*/ |
public static boolean serializeObject(Object source, String identifier) { |
String filename = FILE_PREFIX + identifier + FILE_SUFFIX; |
boolean success = transformObject(source, filename, null); |
return success; |
} |
/** |
* Deserializes data from a file. |
* |
* @param identifier file identifier |
* (name of the file without the extension) |
* |
* @return deserialized object. |
*/ |
public static Object deserializeObject(String identifier) { |
String filename = FILE_PREFIX + identifier + FILE_SUFFIX; |
Object object = null; |
try { |
// Create a stream from the input file. |
NSXMLInputStream stream = (NSXMLInputStream)openStream(filename, true, null); |
// Deserialize data from input stream. |
object = stream.readObject(); |
// Close stream |
closeStream(filename); |
} |
catch (FileNotFoundException e) { |
e.printStackTrace(); |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
catch (ClassNotFoundException e) { |
e.printStackTrace(); |
} |
return object; |
} |
/** |
* Serializes objects and data to a stream, which can also be |
* transformed. The product of the process is written to a file. |
* |
* @param source object to serialize or transform |
* @param filename filename of the target document, |
* including path and extension |
* @param transformation type of transformation to perform; |
* indicates which transformation script to use. |
* When <code>null</code>, no transformation |
* is to be performed, only serialization. |
* |
* @return <code>true</code> when the process succeeds. |
*/ |
public static boolean transformObject(Object source, String filename, String transformation) { |
boolean success = false; |
try { |
// Create a stream to the output file. |
NSXMLOutputStream stream = (NSXMLOutputStream)openStream(filename, false, transformation); |
// Serialize data to object output stream. |
stream.writeObject(source); |
stream.flush(); |
closeStream(filename); |
success = true; |
} |
catch (IOException e) { |
e.printStackTrace(); |
} |
return success; |
} |
/** |
* Opens an output stream. |
* |
* @param filename fully qualified filename of the target |
* or source file; identifies the channel to open. |
* @param transformation type of transformation to perform |
* (indicates which transformation file to use) |
*/ |
public static NSXMLOutputStream openOutputStream(String filename, String transformation) throws IOException { |
return (NSXMLOutputStream)openStream(filename, false, transformation); |
} |
/** |
* Opens an input stream. |
* |
* @param filename fully qualified filename of the target |
* or source file; identifies the channel to open. |
*/ |
public static NSXMLInputStream openInputStream(String filename) throws IOException { |
return (NSXMLInputStream)openStream(filename, true, null); |
} |
/** |
* Opens a file stream to or from a file and a corresponding |
* output or input object stream. |
* Adds the pair of streams to an internal dictionary for use by |
* the <code>closeStream</code> method. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to open |
* @param input_stream indicates whether the stream returned |
* is an input stream or an output stream: |
* <code>true</code> for an input stream and |
* <code>false</code> for an output stream. |
* @param transformation type of transformation to perform; |
* indicates which transformation script to use. |
* When <code>null</code> no transformation |
* is performed, only serialization. |
* |
* @return object stream, <code>null</code> when the stream |
* could not be created. |
*/ |
private static Object openStream(String filename, boolean input_stream, String transformation) throws IOException { |
BufferedOutputStream file_output_stream = null; |
BufferedInputStream file_input_stream = null; |
Channel channel; |
Object xml_stream = null; |
if (input_stream) { |
// Create an input stream from the file. |
file_input_stream = new BufferedInputStream(new FileInputStream(filename)); |
// Create object-input stream. |
xml_stream = new NSXMLInputStream(file_input_stream); |
channel = new Channel(file_input_stream, xml_stream, input_stream); |
} else { |
// Create an output stream to the file. |
file_output_stream = new BufferedOutputStream(new FileOutputStream(filename)); |
// Create object-output stream. |
if (transformation != null) { |
xml_stream = initializeTransformer(file_output_stream, transformation); |
} else { |
xml_stream = new NSXMLOutputStream(file_output_stream); |
} |
// Set the format of the output document (XML). |
NSXMLOutputFormat format = new NSXMLOutputFormat(true); |
((NSXMLOutputStream)xml_stream).setOutputFormat(format); |
channel = new Channel(file_output_stream, xml_stream, input_stream); |
} |
channels.setObjectForKey(channel, filename); |
return xml_stream; |
} |
/** |
* Closes an object stream and its corresponding file stream. |
* |
* @param filename fully qualified filename of the |
* target or source file; identifies |
* the channel to close |
*/ |
public static void closeStream(String filename) throws IOException { |
Channel channel = (Channel)channels.objectForKey(filename); |
if (channel.input_stream) { |
((NSXMLInputStream)channel.object_stream).close(); |
((BufferedInputStream)channel.file_stream).close(); |
} else { |
((NSXMLOutputStream)channel.object_stream).close(); |
((BufferedOutputStream)channel.file_stream).close(); |
} |
channels.removeObjectForKey(filename); |
} |
/** |
* Computes the URI of a transformation file. |
* |
* @param transformation type of transformation (does not |
* include the .xsl extension); |
* for example, "SimpleTransformation" |
* |
* @return relative path to the transformation file. |
*/ |
private static String transformationURI(String transformation) { |
WOApplication application = WOApplication.application(); |
WOResourceManager resource_manager = application.resourceManager(); |
String transformationURI = resource_manager.pathForResourceNamed("SimpleTransformation" + ".xsl", null, null); |
return transformationURI; |
} |
/** |
* Initializes the transformer. |
* |
* @param file_stream target file stream |
* @param transformationtype of transformation to perform; |
* indicates which transformation script to use |
* |
* @throws IOException when there's a problem initializing |
* the transformer. |
*/ |
private static NSXMLOutputStream initializeTransformer(BufferedOutputStream file_stream, String transformation) throws IOException { |
NSXMLOutputStream xml_stream = new NSXMLOutputStream(file_stream, new File(transformationURI(transformation))); |
Transformer transformer = ((NSXMLOutputStream)xml_stream).transformer(); |
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); |
return xml_stream; |
} |
} |
SimpleTransformation.xsl
Listing B-3 shows an example of an XSLT file that is used by an XML transformer or XSLT processor to transform an XML document generated by NSXMLOutputStream into another XML document.
Listing B-3 SimpleTransformation.
xsl file
<?xml version="1.0" encoding="UTF-8"?> |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
xmlns:woxml="http://www.apple.com/webobjects/XMLSerialization" |
exclude-result-prefixes="woxml" |
version="1.0"> |
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="no" indent = "yes"/> |
<!-- ** Constants ** --> |
<!-- Indicates how dictionaries are encoded: key-value or two-array. --> |
<xsl:variable name="dictionary_encoding"> |
<xsl:value-of select="'key-value'" /> |
</xsl:variable> |
<!-- ** Utilities ** --> |
<!-- Gets the base class name from a fully-qualified class name. --> |
<xsl:template name="basename"> |
<xsl:param name="path"/> |
<xsl:choose> |
<xsl:when test="contains($path, '.')"> |
<xsl:call-template name="basename"> |
<xsl:with-param name="path" select="substring-after($path, '.')"/> |
</xsl:call-template> |
</xsl:when> |
<xsl:otherwise> |
<xsl:value-of select="$path"/> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:template> |
<!-- ** Element Processing ** --> |
<!-- Processes the tree root. --> |
<xsl:template match="/"> |
<xsl:element name="content"> |
<xsl:apply-templates select="woxml:content" /> |
</xsl:element> |
</xsl:template> |
<!-- Processes the root element (woxml:content). --> |
<xsl:template match="woxml:content"> |
<xsl:apply-templates select="*"/> |
</xsl:template> |
<!-- Processes woxml:object elements. --> |
<xsl:template name="process_object" match="woxml:object"> |
<!-- extract class name --> |
<xsl:variable name="className"> |
<xsl:value-of select="woxml:class/@name" /> |
</xsl:variable> |
<!-- get base class name --> |
<xsl:variable name="class"> |
<xsl:call-template name="basename"> |
<xsl:with-param name="path" select="$className"/> |
</xsl:call-template> |
</xsl:variable> |
<!-- determine the element name --> |
<xsl:variable name="tag"> |
<xsl:choose> |
<xsl:when test="$class='NSDictionary' or $class='NSMutableDictionary'"> |
<xsl:value-of select="'dictionary'" /> |
</xsl:when> |
<xsl:when test="$class='NSArray' or $class='NSMutableArray'"> |
<xsl:value-of select="'array'" /> |
</xsl:when> |
<xsl:otherwise> |
<xsl:value-of select="$class" /> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:variable> |
<!-- create the element --> |
<xsl:element name="{$tag}"> |
<xsl:choose> |
<xsl:when test="$class='NSDictionary' or $class='NSMutableDictionary'"> |
<xsl:call-template name="process_dictionary" /> |
</xsl:when> |
<xsl:otherwise> |
<xsl:call-template name="process_object_content" /> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:element> |
</xsl:template> |
<!-- Processes the content of a woxml:object element. --> |
<xsl:template name="process_object_content"> |
<xsl:apply-templates select="*" /> |
</xsl:template> |
<!-- Processes woxml:class elements. --> |
<xsl:template match="woxml:class" /> |
<!-- Processes woxml:array elements. --> |
<xsl:template match="woxml:array"> |
<xsl:for-each select="woxml:object"> |
<xsl:call-template name="process_object" /> |
</xsl:for-each> |
</xsl:template> |
<!-- Processes primitive-type and woxml:string elements. --> |
<xsl:template match="woxml:boolean|woxml:byte|woxml:ch|woxml:short|woxml:int| |
woxml:long|woxml:float|woxml:double|woxml:string"> |
<!-- determine the element name --> |
<xsl:variable name="element_name"> |
<xsl:choose> |
<xsl:when test="@key"> |
<xsl:value-of select="@key" /> |
</xsl:when> |
<xsl:when test="@field"> |
<xsl:value-of select="@field" /> |
</xsl:when> |
<xsl:otherwise> |
<xsl:value-of select="name()" /> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:variable> |
<!-- store possible reference to another element --> |
<xsl:variable name="ref"> |
<xsl:value-of select="@idRef" /> |
</xsl:variable> |
<!-- create the element --> |
<xsl:element name="{$element_name}"> |
<xsl:choose> |
<xsl:when test="string(number($ref))='NaN'"> |
<!-- $ref is not a number, therefore there's no reference --> |
<xsl:value-of select="." /> |
</xsl:when> |
<xsl:otherwise> |
<!-- $ref is a number and, by extension, a reference --> |
<xsl:value-of select="//*[@id=$ref]" /> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:element> |
</xsl:template> |
<!-- Processes woxml:object elements that contain a NSDictionary or NSMutableDictionary. --> |
<xsl:template name="process_dictionary"> |
<xsl:choose> |
<xsl:when test="$dictionary_encoding='key-value'"> |
<!-- output the two arrays as key-value pairs within item elements --> |
<xsl:for-each select="woxml:array[1]"> |
<xsl:for-each select="*"> |
<xsl:variable name="current_position"> |
<xsl:value-of select="position()" /> |
</xsl:variable> |
<xsl:element name="item"> |
<xsl:element name="key"> |
<xsl:apply-templates select="." /> |
</xsl:element> |
<xsl:element name="value"> |
<xsl:apply-templates select="ancestor::*[position()=2]/child::woxml:array[2]/child::*[position()=$current_position]" /> |
</xsl:element> |
</xsl:element> |
</xsl:for-each> |
</xsl:for-each> |
</xsl:when> |
<xsl:otherwise> |
<!-- output the two arrays on separate nodes --> |
<xsl:for-each select="woxml:array"> |
<xsl:element name="array"> |
<xsl:apply-templates select="*"/> |
</xsl:element> |
</xsl:for-each> |
</xsl:otherwise> |
</xsl:choose> |
</xsl:template> |
</xsl:stylesheet> |
Copyright © 2002, 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-08-11