jkesselm 00/10/23 12:23:24
Added: java/src/org/apache/xalan/processor
CompiledStylesheetBundle.java
Log:
Generate and reload .zip file containing serialized compiled stylesheet (and
generated .classes to support it)
Revision Changes Path
1.1
xml-xalan/java/src/org/apache/xalan/processor/CompiledStylesheetBundle.java
Index: CompiledStylesheetBundle.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xalan.processor;
import java.net.URL;
import java.util.Stack;
import java.util.Vector;
import java.io.File;
import java.util.StringTokenizer;
import org.apache.xalan.templates.Constants;
import org.apache.xalan.templates.ElemTemplateElement;
import org.apache.xalan.templates.ElemTemplate;
import org.apache.xalan.templates.ElemLiteralResult;
import org.apache.xalan.templates.ElemAttributeSet;
import org.apache.xalan.templates.ElemAttribute;
import org.apache.xalan.templates.StylesheetRoot;
import org.apache.xalan.templates.Stylesheet;
import org.apache.xalan.templates.XMLNSDecl;
import org.apache.trax.ProcessorException;
import org.apache.trax.TemplatesBuilder;
import org.apache.trax.Templates;
import org.apache.trax.TransformException;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathFactory;
import org.apache.xpath.compiler.XPathParser;
import org.apache.xpath.compiler.FunctionTable;
import org.apache.xpath.functions.Function;
import org.apache.xalan.res.XSLMessages;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.utils.PrefixResolver;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.helpers.NamespaceSupport;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
// Java Compiler support. *****
// TODO: Merge the Microsoft VJ++ workarounds in this file into that one.
import org.apache.xalan.utils.synthetic.JavaUtils;
/**
* <meta name="usage" content="advanced"/>
* File save and reload for Compiled Stylesheets.
* @see CompilingStylesheetHandler
*/
public class CompiledStylesheetBundle
{
public CompiledStylesheetBundle()
{
}
// Create an executable bundle -- a zipfile
// containing the serialized root, the synthesized classes needed
// to support it, and a main entry point which retrieves these.
//
// ***** ISSUE: Need to make sure we're looking in the same directory
// that the classes were generated into. Currently that's ".". Should
// be parameterized both during compilation and here.
// ***** ISSUE: What filename to write to? Hardcoded for initial test,
// should be taken from stylesheet's Public/System IDs. Stand-alone
// loader entry point ditto?
// ***** ISSUE: ZIP or JAR? Zipfile support is in Java 1.1.x, direct
// jarfile doesn't appear until 1.2. Main difference is that latter
// automatically produces manefest, but a manefest is optional anyway.
static void createBundle(Stylesheet root,Vector compiledTemplates)
{
String outdir="."+File.separator;
java.util.Hashtable dirs=new java.util.Hashtable();
try {
java.io.FileOutputStream f=
new
java.io.FileOutputStream(outdir+"CompiledStylesheet.zip");
java.util.zip.ZipOutputStream zf=new
java.util.zip.ZipOutputStream(f);
zf.setMethod(zf.DEFLATED);
// Copy in the classfiles
byte buffer[]=new byte[4096];
java.util.zip.ZipEntry ze;
for(int i=compiledTemplates.size()-1;i>=0;--i)
{
// WARNING: I'm assuming that a package name has been
specified,
// which should be safe in this case. If that changes,
this
// lazy parse needs to be improved.
Class c=compiledTemplates.elementAt(i).getClass();
String fullname=c.getName();
int start=fullname.lastIndexOf(".");
String packagename=fullname.substring(0,start);
String shortname=fullname.substring(start+1);
// Need to convert as a relative path for the jarfile;
// it's "anchored" later when we open for read.
String
source=packageNameToDirectory(packagename,outdir,File.separator)
+shortname+".class";
String sink=packageNameToDirectory(packagename,"","/")
+shortname+".class";
// I'm not sure whether this is needed or not. The JDK I'm using seems to say
// it isn't, but I want to keep it around for now in case another JDK
// disagrees.
if(false)
{
for(int slash=sink.indexOf('/');
slash>=0;
slash=sink.indexOf('/',slash+1))
{
String dirname=sink.substring(0,slash+1);
if(dirs.get(dirname) == null)
{
ze=new java.util.zip.ZipEntry(dirname);
zf.putNextEntry(ze);
zf.closeEntry();
dirs.put(dirname,dirname);
}
}
}
ze=new java.util.zip.ZipEntry(sink);
zf.putNextEntry(ze);
java.io.FileInputStream fis=new
java.io.FileInputStream(source);
int count=0;
for(int got=1;got>=0;)
{
got=fis.read(buffer);
if(got>0)
{
zf.write(buffer,0,got);
count+=got;
}
}
fis.close();
ze.setSize(count); // Ought to get set automagically,
BUT....
zf.closeEntry();
}
// Write out the serialized stylesheet
ze=new java.util.zip.ZipEntry("Stylesheet.ser");
zf.putNextEntry(ze);
java.io.ObjectOutputStream of=new
java.io.ObjectOutputStream(zf);
of.writeObject(root);
of.flush(); // ***** Should this be close?
zf.closeEntry();
// TODO: *****MAKE SELF-LOADABLE!*****
// Set up a Classloader pointed at the zipfile and deserialize
from?
// This may be overkill, but I'm getting complaints about
// "not a ZIP file (END header not found"...
zf.finish();
zf.flush();
zf.close();
f.flush();
f.close();
}
catch(java.io.IOException e)
{
System.err.println("Exception while packaging compiled
stylesheet");
e.printStackTrace(System.err);
}
}
// Reload an executable bundle -- a zipfile or jarfile
// containing the serialized root, the synthesized classes needed
// to support it, and a main entry point which retrieves these.
//
// Note use of a custom classloader in order to pick these up
interactively.
public Stylesheet loadBundle(String filename)
throws java.io.IOException,java.lang.ClassNotFoundException
{
Stylesheet ss=null;
java.io.InputStream is;
java.io.ObjectInputStream os;
if(true)
{
java.lang.ClassLoader cl=new
ZipfileClassLoader(filename);
is=cl.getResourceAsStream("Stylesheet.ser");
os=new ClassLoaderObjectInputStream(cl,is);
}
else
{
is=this.getClass().getResourceAsStream("/Stylesheet.ser");
os=new java.io.ObjectInputStream(is);
}
ss=(Stylesheet)os.readObject();
os.close();
is.close();
return ss;
}
static String packageNameToDirectory(String packagename,String baseLocation,
String separator)
{
int fnstart=baseLocation.lastIndexOf(separator);
StringBuffer subdir=new StringBuffer(
(fnstart>=0)
? baseLocation.substring(0,fnstart+1)
: "");
StringTokenizer parts=
new StringTokenizer(packagename,".");
while(parts.hasMoreTokens())
subdir.append(parts.nextToken()).append(separator);
return subdir.toString();
}
// Custom classloader is needed if we want to load from a
// zipfile which wasn't on the classpath at startup time.
class ZipfileClassLoader extends ClassLoader
{
String filename;
java.util.zip.ZipFile zip=null;
ZipfileClassLoader(String filename) throws java.io.IOException
{
this.filename=filename;
zip=new java.util.zip.ZipFile(filename);
}
// TODO: ***** RECONSIDER EFFECTIVE CLASSPATH
// What I really want is to try system classes, than zipfile, then
// user classpath. JDK 1.2 seems to have hooks that will support that,
// but I'm not sure about JDK 1.1.
public Class findClass(String name)
{
Class c=null;
try
{
c=this.getClass().forName(name);
}
catch (ClassNotFoundException e)
{
byte[] b = loadClassData(name);
if(b!=null)
c=defineClass(name,b,0,b.length);
}
return c;
}
private byte[] loadClassData(String name)
{
int start=name.lastIndexOf(".");
String packagename=name.substring(0,start);
String shortname=name.substring(start+1);
// Need to convert as a relative path for the jarfile;
// it's "anchored" later when we open for read.
String fn=packageNameToDirectory(packagename,"","/")
+shortname+".class";
byte[] data=null;
try
{
java.util.zip.ZipEntry entry=zip.getEntry(fn);
// If it isn't in the zipfile, we can't retrieve any
data
if(entry!=null)
{
// This assumes entry length fits in an int.
Should be safe.
int bufsize = (int)entry.getSize();
data=new byte[bufsize];
java.io.InputStream
is=zip.getInputStream(entry);
int len=0, off=0;
while (off<bufsize){
len = is.read(data,off,bufsize-off);
off += len;
}
is.close();
}
}
catch(java.io.IOException e)
{
System.err.println("Exception while reloading compiled
stylesheet");
e.printStackTrace(System.err);
}
return data;
}
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c=findClass(name);
if(c!=null && resolve==true)
resolveClass(c);
return c;
}
public java.io.InputStream getResourceAsStream(String name)
{
java.io.InputStream is=null;
try
{
java.util.zip.ZipEntry entry=zip.getEntry(name);
is=zip.getInputStream(entry);
}
catch(java.io.IOException e)
{
System.err.println("Problem loading compiled stylesheet");
e.printStackTrace();
// TODO: ***** Should this fall back to default classloader?
// is=this.getClass().getResourceAsStream(name);
}
return is;
}
}
// Kluge: Check a specific classloader when deserializing. Alternative
// is to dump a stub object into the zipfile and have it do the deserialize
// ... which doesn't strike me as being any prettier.
class ClassLoaderObjectInputStream extends java.io.ObjectInputStream
{
java.lang.ClassLoader cl;
public ClassLoaderObjectInputStream(java.lang.ClassLoader
cl,java.io.InputStream is)
throws java.io.IOException
{
super(is);
this.cl=cl;
}
// Note that this assumes cl knows how to cascade to other classloaders
// as appropriate, since it has to resolve _all_ classes that may be
// referenced in the object stream -- including system classes.
protected Class resolveClass(java.io.ObjectStreamClass v)
throws java.io.IOException, ClassNotFoundException
{
return cl.loadClass(v.getName());
}
}
}