KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > runtime > AbstractTranslet


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: AbstractTranslet.java,v 1.52 2004/02/16 22:55:55 minchau Exp $
18  */

19
20 package org.apache.xalan.xsltc.runtime;
21
22 import java.io.FileWriter JavaDoc;
23 import java.text.DecimalFormat JavaDoc;
24 import java.text.DecimalFormatSymbols JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.Vector JavaDoc;
28 import javax.xml.transform.Templates JavaDoc;
29
30 import org.apache.xml.dtm.DTM;
31
32 import org.apache.xalan.xsltc.DOM;
33 import org.apache.xalan.xsltc.DOMCache;
34 import org.apache.xalan.xsltc.DOMEnhancedForDTM;
35 import org.apache.xalan.xsltc.Translet;
36 import org.apache.xalan.xsltc.TransletException;
37 import org.apache.xalan.xsltc.dom.DOMAdapter;
38 import org.apache.xalan.xsltc.dom.KeyIndex;
39 import org.apache.xalan.xsltc.runtime.output.TransletOutputHandlerFactory;
40 import org.apache.xml.dtm.DTMAxisIterator;
41 import org.apache.xml.serializer.SerializationHandler;
42
43 /**
44  * @author Jacek Ambroziak
45  * @author Santiago Pericas-Geertsen
46  * @author Morten Jorgensen
47  * @author G. Todd Miller
48  * @author John Howard, JohnH@schemasoft.com
49  */

50 public abstract class AbstractTranslet implements Translet {
51
52     // These attributes are extracted from the xsl:output element. They also
53
// appear as fields (with the same type, only public) in Output.java
54
public String JavaDoc _version = "1.0";
55     public String JavaDoc _method = null;
56     public String JavaDoc _encoding = "UTF-8";
57     public boolean _omitHeader = false;
58     public String JavaDoc _standalone = null;
59     public String JavaDoc _doctypePublic = null;
60     public String JavaDoc _doctypeSystem = null;
61     public boolean _indent = false;
62     public String JavaDoc _mediaType = null;
63     public Vector JavaDoc _cdata = null;
64
65     public static final int FIRST_TRANSLET_VERSION = 100;
66     public static final int VER_SPLIT_NAMES_ARRAY = 101;
67     public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;
68
69     // Initialize Translet version field to base value. A class that extends
70
// AbstractTranslet may override this value to a more recent translet
71
// version; if it doesn't override the value (because it was compiled
72
// before the notion of a translet version was introduced, it will get
73
// this default value).
74
protected int transletVersion = FIRST_TRANSLET_VERSION;
75
76     // DOM/translet handshaking - the arrays are set by the compiled translet
77
protected String JavaDoc[] namesArray;
78     protected String JavaDoc[] urisArray;
79     protected int[] typesArray;
80     protected String JavaDoc[] namespaceArray;
81     
82     // The Templates object that is used to create this Translet instance
83
protected Templates JavaDoc _templates = null;
84     
85     // Boolean flag to indicate whether this translet has id functions.
86
protected boolean _hasIdCall = false;
87
88     // TODO - these should only be instanciated when needed
89
protected StringValueHandler stringValueHandler = new StringValueHandler();
90
91     // Use one empty string instead of constantly instanciating String("");
92
private final static String JavaDoc EMPTYSTRING = "";
93
94     // This is the name of the index used for ID attributes
95
private final static String JavaDoc ID_INDEX_NAME = "##id";
96
97     
98     /************************************************************************
99      * Debugging
100      ************************************************************************/

101     public void printInternalState() {
102     System.out.println("-------------------------------------");
103     System.out.println("AbstractTranslet this = " + this);
104     System.out.println("pbase = " + pbase);
105     System.out.println("vframe = " + pframe);
106     System.out.println("paramsStack.size() = " + paramsStack.size());
107     System.out.println("namesArray.size = " + namesArray.length);
108     System.out.println("namespaceArray.size = " + namespaceArray.length);
109     System.out.println("");
110     System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
111     }
112
113     /**
114      * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
115      * a DOM multiplexer if the document() function is used (handled by compiled
116      * code in the translet - see compiler/Stylesheet.compileTransform()).
117      */

118     public final DOMAdapter makeDOMAdapter(DOM dom)
119     throws TransletException {
120     return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray);
121     }
122
123     /************************************************************************
124      * Parameter handling
125      ************************************************************************/

126
127     // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
128
// to denote the current parameter frame.
129
protected int pbase = 0, pframe = 0;
130     protected ArrayList JavaDoc paramsStack = new ArrayList JavaDoc();
131
132     /**
133      * Push a new parameter frame.
134      */

135     public final void pushParamFrame() {
136     paramsStack.add(pframe, new Integer JavaDoc(pbase));
137     pbase = ++pframe;
138     }
139
140     /**
141      * Pop the topmost parameter frame.
142      */

143     public final void popParamFrame() {
144     if (pbase > 0) {
145         final int oldpbase = ((Integer JavaDoc)paramsStack.get(--pbase)).intValue();
146         for (int i = pframe - 1; i >= pbase; i--) {
147         paramsStack.remove(i);
148         }
149         pframe = pbase; pbase = oldpbase;
150     }
151     }
152
153     /**
154      * Add a new global parameter if not already in the current frame.
155      * To setParameters of the form {http://foo.bar}xyz
156      * This needs to get mapped to an instance variable in the class
157      * The mapping created so that
158      * the global variables in the generated class become
159      * http$colon$$flash$$flash$foo$dot$bar$colon$xyz
160      */

161     public final Object JavaDoc addParameter(String JavaDoc name, Object JavaDoc value) {
162         name = BasisLibrary.mapQNameToJavaName (name);
163     return addParameter(name, value, false);
164     }
165
166     /**
167      * Add a new global or local parameter if not already in the current frame.
168      * The 'isDefault' parameter is set to true if the value passed is the
169      * default value from the <xsl:parameter> element's select attribute or
170      * element body.
171      */

172     public final Object JavaDoc addParameter(String JavaDoc name, Object JavaDoc value,
173     boolean isDefault)
174     {
175     // Local parameters need to be re-evaluated for each iteration
176
for (int i = pframe - 1; i >= pbase; i--) {
177         final Parameter param = (Parameter) paramsStack.get(i);
178
179         if (param._name.equals(name)) {
180         // Only overwrite if current value is the default value and
181
// the new value is _NOT_ the default value.
182
if (param._isDefault || !isDefault) {
183             param._value = value;
184             param._isDefault = isDefault;
185             return value;
186         }
187         return param._value;
188         }
189     }
190
191     // Add new parameter to parameter stack
192
paramsStack.add(pframe++, new Parameter(name, value, isDefault));
193     return value;
194     }
195
196     /**
197      * Clears the parameter stack.
198      */

199     public void clearParameters() {
200     pbase = pframe = 0;
201     paramsStack.clear();
202     }
203
204     /**
205      * Get the value of a parameter from the current frame or
206      * <tt>null</tt> if undefined.
207      */

208     public final Object JavaDoc getParameter(String JavaDoc name) {
209
210         name = BasisLibrary.mapQNameToJavaName (name);
211
212     for (int i = pframe - 1; i >= pbase; i--) {
213         final Parameter param = (Parameter)paramsStack.get(i);
214         if (param._name.equals(name)) return param._value;
215     }
216     return null;
217     }
218
219     /************************************************************************
220      * Message handling - implementation of <xsl:message>
221      ************************************************************************/

222
223     // Holds the translet's message handler - used for <xsl:message>.
224
// The deault message handler dumps a string stdout, but anything can be
225
// used, such as a dialog box for applets, etc.
226
private MessageHandler _msgHandler = null;
227
228     /**
229      * Set the translet's message handler - must implement MessageHandler
230      */

231     public final void setMessageHandler(MessageHandler handler) {
232     _msgHandler = handler;
233     }
234
235     /**
236      * Pass a message to the message handler - used by Message class.
237      */

238     public final void displayMessage(String JavaDoc msg) {
239     if (_msgHandler == null) {
240             System.err.println(msg);
241     }
242     else {
243         _msgHandler.displayMessage(msg);
244     }
245     }
246
247     /************************************************************************
248      * Decimal number format symbol handling
249      ************************************************************************/

250
251     // Contains decimal number formatting symbols used by FormatNumberCall
252
public Hashtable _formatSymbols = null;
253
254     /**
255      * Adds a DecimalFormat object to the _formatSymbols hashtable.
256      * The entry is created with the input DecimalFormatSymbols.
257      */

258     public void addDecimalFormat(String JavaDoc name, DecimalFormatSymbols JavaDoc symbols) {
259     // Instanciate hashtable for formatting symbols if needed
260
if (_formatSymbols == null) _formatSymbols = new Hashtable();
261
262     // The name cannot be null - use empty string instead
263
if (name == null) name = EMPTYSTRING;
264
265     // Construct a DecimalFormat object containing the symbols we got
266
final DecimalFormat JavaDoc df = new DecimalFormat JavaDoc();
267     if (symbols != null) {
268         df.setDecimalFormatSymbols(symbols);
269     }
270     _formatSymbols.put(name, df);
271     }
272
273     /**
274      * Retrieves a named DecimalFormat object from _formatSymbols hashtable.
275      */

276     public final DecimalFormat JavaDoc getDecimalFormat(String JavaDoc name) {
277
278     if (_formatSymbols != null) {
279         // The name cannot be null - use empty string instead
280
if (name == null) name = EMPTYSTRING;
281
282         DecimalFormat JavaDoc df = (DecimalFormat JavaDoc)_formatSymbols.get(name);
283         if (df == null) df = (DecimalFormat JavaDoc)_formatSymbols.get(EMPTYSTRING);
284         return df;
285     }
286     return(null);
287     }
288
289     /**
290      * Give the translet an opportunity to perform a prepass on the document
291      * to extract any information that it can store in an optimized form.
292      *
293      * Currently, it only extracts information about attributes of type ID.
294      */

295     public final void prepassDocument(DOM document) {
296         setIndexSize(document.getSize());
297         buildIDIndex(document);
298     }
299
300     /**
301      * Leverages the Key Class to implement the XSLT id() function.
302      * buildIdIndex creates the index (##id) that Key Class uses.
303      * The index contains the element node index (int) and Id value (String).
304      */

305     private final void buildIDIndex(DOM document) {
306         
307         if (document instanceof DOMEnhancedForDTM) {
308             DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document;
309             
310             // If the input source is DOMSource, the KeyIndex table is not
311
// built at this time. It will be built later by the lookupId()
312
// and containsId() methods of the KeyIndex class.
313
if (enhancedDOM.hasDOMSource()) {
314                 buildKeyIndex(ID_INDEX_NAME, document);
315                 return;
316             }
317             else {
318                 final Hashtable elementsByID = enhancedDOM.getElementsWithIDs();
319
320                 if (elementsByID == null) {
321                     return;
322                 }
323
324                 // Given a Hashtable of DTM nodes indexed by ID attribute values,
325
// loop through the table copying information to a KeyIndex
326
// for the mapping from ID attribute value to DTM node
327
final Enumeration JavaDoc idValues = elementsByID.keys();
328                 boolean hasIDValues = false;
329
330                 while (idValues.hasMoreElements()) {
331                     final Object JavaDoc idValue = idValues.nextElement();
332                     final int element = ((Integer JavaDoc)elementsByID.get(idValue)).intValue();
333
334                     buildKeyIndex(ID_INDEX_NAME, element, idValue);
335                     hasIDValues = true;
336                 }
337
338                 if (hasIDValues) {
339                     setKeyIndexDom(ID_INDEX_NAME, document);
340                 }
341             }
342         }
343     }
344
345     /**
346      * After constructing the translet object, this method must be called to
347      * perform any version-specific post-initialization that's required.
348      */

349     public final void postInitialization() {
350         // If the version of the translet had just one namesArray, split
351
// it into multiple fields.
352
if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
353             int arraySize = namesArray.length;
354             String JavaDoc[] newURIsArray = new String JavaDoc[arraySize];
355             String JavaDoc[] newNamesArray = new String JavaDoc[arraySize];
356             int[] newTypesArray = new int[arraySize];
357
358             for (int i = 0; i < arraySize; i++) {
359                 String JavaDoc name = namesArray[i];
360                 int colonIndex = name.lastIndexOf(':');
361                 int lNameStartIdx = colonIndex+1;
362
363                 if (colonIndex > -1) {
364                     newURIsArray[i] = name.substring(0, colonIndex);
365                 }
366
367                // Distinguish attribute and element names. Attribute has
368
// @ before local part of name.
369
if (name.charAt(lNameStartIdx) == '@') {
370                    lNameStartIdx++;
371                    newTypesArray[i] = DTM.ATTRIBUTE_NODE;
372                } else if (name.charAt(lNameStartIdx) == '?') {
373                    lNameStartIdx++;
374                    newTypesArray[i] = DTM.NAMESPACE_NODE;
375                } else {
376                    newTypesArray[i] = DTM.ELEMENT_NODE;
377                }
378                newNamesArray[i] =
379                           (lNameStartIdx == 0) ? name
380                                                : name.substring(lNameStartIdx);
381             }
382
383             namesArray = newNamesArray;
384             urisArray = newURIsArray;
385             typesArray = newTypesArray;
386         }
387
388         // Was translet compiled using a more recent version of the XSLTC
389
// compiler than is known by the AbstractTranslet class? If, so
390
// and we've made it this far (which is doubtful), we should give up.
391
if (transletVersion > CURRENT_TRANSLET_VERSION) {
392             BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
393                                       this.getClass().getName());
394         }
395     }
396
397     /************************************************************************
398      * Index(es) for <xsl:key> / key() / id()
399      ************************************************************************/

400
401     // Container for all indexes for xsl:key elements
402
private Hashtable _keyIndexes = null;
403     private KeyIndex _emptyKeyIndex = null;
404     private int _indexSize = 0;
405
406     /**
407      * This method is used to pass the largest DOM size to the translet.
408      * Needed to make sure that the translet can index the whole DOM.
409      */

410     public void setIndexSize(int size) {
411     if (size > _indexSize) _indexSize = size;
412     }
413
414     /**
415      * Creates a KeyIndex object of the desired size - don't want to resize!!!
416      */

417     public KeyIndex createKeyIndex() {
418     return(new KeyIndex(_indexSize));
419     }
420
421     /**
422      * Adds a value to a key/id index
423      * @name is the name of the index (the key or ##id)
424      * @node is the node id of the node to insert
425      * @value is the value that will look up the node in the given index
426      */

427     public void buildKeyIndex(String JavaDoc name, int node, Object JavaDoc value) {
428     if (_keyIndexes == null) _keyIndexes = new Hashtable();
429     
430     KeyIndex index = (KeyIndex)_keyIndexes.get(name);
431     if (index == null) {
432         _keyIndexes.put(name, index = new KeyIndex(_indexSize));
433     }
434     index.add(value, node);
435     }
436
437     /**
438      * Create an empty KeyIndex in the DOM case
439      * @name is the name of the index (the key or ##id)
440      * @node is the DOM
441      */

442     public void buildKeyIndex(String JavaDoc name, DOM dom) {
443     if (_keyIndexes == null) _keyIndexes = new Hashtable();
444     
445     KeyIndex index = (KeyIndex)_keyIndexes.get(name);
446     if (index == null) {
447         _keyIndexes.put(name, index = new KeyIndex(_indexSize));
448     }
449     index.setDom(dom);
450     }
451
452     /**
453      * Returns the index for a given key (or id).
454      * The index implements our internal iterator interface
455      */

456     public KeyIndex getKeyIndex(String JavaDoc name) {
457     // Return an empty key index iterator if none are defined
458
if (_keyIndexes == null) {
459         return (_emptyKeyIndex != null)
460             ? _emptyKeyIndex
461             : (_emptyKeyIndex = new KeyIndex(1));
462     }
463
464     // Look up the requested key index
465
final KeyIndex index = (KeyIndex)_keyIndexes.get(name);
466
467     // Return an empty key index iterator if the requested index not found
468
if (index == null) {
469         return (_emptyKeyIndex != null)
470             ? _emptyKeyIndex
471             : (_emptyKeyIndex = new KeyIndex(1));
472     }
473
474     return(index);
475     }
476
477     /**
478      * This method builds key indexes - it is overridden in the compiled
479      * translet in cases where the <xsl:key> element is used
480      */

481     public void buildKeys(DOM document, DTMAxisIterator iterator,
482               SerializationHandler handler,
483               int root) throws TransletException {
484                 
485     }
486     
487     /**
488      * This method builds key indexes - it is overridden in the compiled
489      * translet in cases where the <xsl:key> element is used
490      */

491     public void setKeyIndexDom(String JavaDoc name, DOM document) {
492         getKeyIndex(name).setDom(document);
493                 
494     }
495
496     /************************************************************************
497      * DOM cache handling
498      ************************************************************************/

499
500     // Hold the DOM cache (if any) used with this translet
501
private DOMCache _domCache = null;
502
503     /**
504      * Sets the DOM cache used for additional documents loaded using the
505      * document() function.
506      */

507     public void setDOMCache(DOMCache cache) {
508     _domCache = cache;
509     }
510
511     /**
512      * Returns the DOM cache used for this translet. Used by the LoadDocument
513      * class (if present) when the document() function is used.
514      */

515     public DOMCache getDOMCache() {
516     return(_domCache);
517     }
518
519     /************************************************************************
520      * Multiple output document extension.
521      * See compiler/TransletOutput for actual implementation.
522      ************************************************************************/

523
524     public SerializationHandler openOutputHandler(String JavaDoc filename, boolean append)
525     throws TransletException
526     {
527     try {
528         final TransletOutputHandlerFactory factory
529         = TransletOutputHandlerFactory.newInstance();
530
531         factory.setEncoding(_encoding);
532         factory.setOutputMethod(_method);
533         factory.setWriter(new FileWriter JavaDoc(filename, append));
534         factory.setOutputType(TransletOutputHandlerFactory.STREAM);
535
536         final SerializationHandler handler
537         = factory.getSerializationHandler();
538
539         transferOutputSettings(handler);
540         handler.startDocument();
541         return handler;
542     }
543     catch (Exception JavaDoc e) {
544         throw new TransletException(e);
545     }
546     }
547
548     public SerializationHandler openOutputHandler(String JavaDoc filename)
549        throws TransletException
550     {
551        return openOutputHandler(filename, false);
552     }
553
554     public void closeOutputHandler(SerializationHandler handler) {
555     try {
556         handler.endDocument();
557         handler.close();
558     }
559     catch (Exception JavaDoc e) {
560         // what can you do?
561
}
562     }
563
564     /************************************************************************
565      * Native API transformation methods - _NOT_ JAXP/TrAX
566      ************************************************************************/

567
568     /**
569      * Main transform() method - this is overridden by the compiled translet
570      */

571     public abstract void transform(DOM document, DTMAxisIterator iterator,
572                    SerializationHandler handler)
573     throws TransletException;
574
575     /**
576      * Calls transform() with a given output handler
577      */

578     public final void transform(DOM document, SerializationHandler handler)
579     throws TransletException {
580     transform(document, document.getIterator(), handler);
581     }
582     
583     /**
584      * Used by some compiled code as a shortcut for passing strings to the
585      * output handler
586      */

587     public final void characters(final String JavaDoc string,
588                  SerializationHandler handler)
589     throws TransletException {
590         if (string != null) {
591            //final int length = string.length();
592
try {
593                handler.characters(string);
594            } catch (Exception JavaDoc e) {
595                throw new TransletException(e);
596            }
597         }
598     }
599
600     /**
601      * Add's a name of an element whose text contents should be output as CDATA
602      */

603     public void addCdataElement(String JavaDoc name) {
604     if (_cdata == null) {
605             _cdata = new Vector JavaDoc();
606         }
607
608         int lastColon = name.lastIndexOf(':');
609
610         if (lastColon > 0) {
611             String JavaDoc uri = name.substring(0, lastColon);
612             String JavaDoc localName = name.substring(lastColon+1);
613         _cdata.addElement(uri);
614         _cdata.addElement(localName);
615         } else {
616         _cdata.addElement(null);
617         _cdata.addElement(name);
618         }
619     }
620
621     /**
622      * Transfer the output settings to the output post-processor
623      */

624     protected void transferOutputSettings(SerializationHandler handler) {
625     if (_method != null) {
626         if (_method.equals("xml")) {
627             if (_standalone != null) {
628             handler.setStandalone(_standalone);
629         }
630         if (_omitHeader) {
631             handler.setOmitXMLDeclaration(true);
632         }
633         handler.setCdataSectionElements(_cdata);
634         if (_version != null) {
635             handler.setVersion(_version);
636         }
637         handler.setIndent(_indent);
638         if (_doctypeSystem != null) {
639             handler.setDoctype(_doctypeSystem, _doctypePublic);
640         }
641         }
642         else if (_method.equals("html")) {
643         handler.setIndent(_indent);
644         handler.setDoctype(_doctypeSystem, _doctypePublic);
645         if (_mediaType != null) {
646             handler.setMediaType(_mediaType);
647         }
648         }
649     }
650     else {
651         handler.setCdataSectionElements(_cdata);
652         if (_version != null) {
653         handler.setVersion(_version);
654         }
655         if (_standalone != null) {
656         handler.setStandalone(_standalone);
657         }
658         if (_omitHeader) {
659         handler.setOmitXMLDeclaration(true);
660         }
661         handler.setIndent(_indent);
662         handler.setDoctype(_doctypeSystem, _doctypePublic);
663     }
664     }
665
666     private Hashtable _auxClasses = null;
667
668     public void addAuxiliaryClass(Class JavaDoc auxClass) {
669     if (_auxClasses == null) _auxClasses = new Hashtable();
670     _auxClasses.put(auxClass.getName(), auxClass);
671     }
672
673     public void setAuxiliaryClasses(Hashtable auxClasses) {
674         _auxClasses = auxClasses;
675     }
676     
677     public Class JavaDoc getAuxiliaryClass(String JavaDoc className) {
678     if (_auxClasses == null) return null;
679     return((Class JavaDoc)_auxClasses.get(className));
680     }
681
682     // GTM added (see pg 110)
683
public String JavaDoc[] getNamesArray() {
684     return namesArray;
685     }
686     
687     public String JavaDoc[] getUrisArray() {
688         return urisArray;
689     }
690     
691     public int[] getTypesArray() {
692         return typesArray;
693     }
694     
695     public String JavaDoc[] getNamespaceArray() {
696     return namespaceArray;
697     }
698     
699     public boolean hasIdCall() {
700         return _hasIdCall;
701     }
702     
703     public Templates JavaDoc getTemplates() {
704         return _templates;
705     }
706     
707     public void setTemplates(Templates JavaDoc templates) {
708         _templates = templates;
709     }
710 }
711
Popular Tags