001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.event.Stripper;
005: import net.sf.saxon.functions.FunctionLibrary;
006: import net.sf.saxon.om.NamespaceConstant;
007: import net.sf.saxon.query.StaticQueryContext;
008: import net.sf.saxon.sort.CodepointCollator;
009: import net.sf.saxon.sort.IntHashMap;
010: import net.sf.saxon.sort.IntHashSet;
011: import net.sf.saxon.sort.IntIterator;
012: import net.sf.saxon.trans.*;
013:
014: import java.io.Serializable;
015: import java.util.*;
016:
017: /**
018: * A compiled stylesheet or a query in executable form.
019: * Note that the original stylesheet tree is not retained.
020: */
021:
022: public class Executable implements Serializable {
023:
024: // the Configuration options
025: private transient Configuration config;
026:
027: // definitions of strip/preserve space action
028: private Mode stripperRules;
029:
030: // boolean indicating whether any whitespace is stripped
031: private boolean stripsWhitespace;
032:
033: // definitions of template rules
034: private RuleManager ruleManager;
035:
036: // definitions of keys
037: private KeyManager keyManager;
038:
039: // definitions of decimal formats
040: private DecimalFormatManager decimalFormatManager;
041:
042: // the map of slots used for global variables and params
043: private SlotManager globalVariableMap;
044:
045: // Index of global variables and parameters, by fingerprint
046: // The key is the variable name fingerprint
047: // The value is the compiled GlobalVariable object.
048: private IntHashMap compiledGlobalVariables = new IntHashMap(32);
049:
050: // default collating sequence
051: private String defaultCollationName;
052:
053: // default output properties (for the unnamed output format)
054: private Properties defaultOutputProperties;
055:
056: // index of named templates.
057: private IntHashMap namedTemplateTable = new IntHashMap(32);
058:
059: // count of the maximum number of local variables in the match pattern of any template rule
060: private int largestPatternStackFrame = 0;
061:
062: // table of named collations defined in the stylesheet/query
063: private HashMap collationTable = new HashMap(10);
064:
065: // table of character maps
066: private IntHashMap characterMapIndex;
067:
068: // location map for expressions in this executable
069: private LocationMap locationMap;
070:
071: // hash table of query library modules
072: private HashMap queryLibraryModules;
073:
074: // flag to indicate that source documents are to have their type annotations stripped
075: private boolean stripsInputTypeAnnotations;
076:
077: // list of functions available in the static context
078: private FunctionLibrary functionLibrary;
079:
080: // flag to indicate whether the principal language is for example XSLT or XQuery
081: private int hostLanguage = Configuration.XSLT;
082:
083: // a list of required parameters, identified by the fingerprint of their names
084: private IntHashSet requiredParams = null;
085:
086: // hash table of named (and unnamed) output declarations. This is assembled only
087: // if there is a need for it: that is, if there is a call on xsl:result-document
088: // with a format attribute computed at run-time
089: private IntHashMap outputDeclarations = null;
090:
091: // a string explaining why this Executable can't be compiled, or null if it can
092: private String reasonUnableToCompile = null;
093:
094: public Executable() {
095:
096: }
097:
098: /**
099: * Set the configuration
100: */
101:
102: public void setConfiguration(Configuration config) {
103: this .config = config;
104: }
105:
106: /**
107: * Get the configuration
108: */
109:
110: public Configuration getConfiguration() {
111: return config;
112: }
113:
114: /**
115: * Set the host language
116: */
117:
118: public void setHostLanguage(int language) {
119: hostLanguage = language;
120: }
121:
122: /**
123: * Get the host language
124: *
125: * @return a value identifying the host language: {@link Configuration#XQUERY} or {@link Configuration#XSLT}
126: * or {@link Configuration#JAVA_APPLICATION}
127: */
128:
129: public int getHostLanguage() {
130: return hostLanguage;
131: }
132:
133: /**
134: * Set the RuleManager that handles template rules
135: *
136: * @param rm the RuleManager containing details of all the template rules
137: */
138:
139: public void setRuleManager(RuleManager rm) {
140: ruleManager = rm;
141: }
142:
143: /**
144: * Get the RuleManager which handles template rules
145: *
146: * @return the RuleManager registered with setRuleManager
147: */
148:
149: public RuleManager getRuleManager() {
150: return ruleManager;
151: }
152:
153: /**
154: * Get the named template table. Provided for use by tools allowing selection
155: * of a transformation entry point from a supplied list.
156: *
157: * @return a hash table containing entries that map the names of named
158: * templates (in the form of namePool fingerprints) to the Template objects representing
159: * the compiled xsl:template element in the stylesheet.
160: */
161:
162: public IntHashMap getNamedTemplateTable() {
163: if (namedTemplateTable == null) {
164: namedTemplateTable = new IntHashMap(32);
165: }
166: return namedTemplateTable;
167: }
168:
169: /**
170: * Get the named template with a given name.
171: *
172: * @param fingerprint The namepool fingerprint of the template name
173: * @return The template (of highest import precedence) with this name if there is one;
174: * null if none is found.
175: */
176:
177: public Template getNamedTemplate(int fingerprint) {
178: return (Template) namedTemplateTable.get(fingerprint);
179: }
180:
181: /**
182: * Register the named template with a given name
183: */
184:
185: public void putNamedTemplate(int fingerprint, Template template) {
186: namedTemplateTable.put(fingerprint, template);
187: }
188:
189: /**
190: * Get the library containing all the in-scope functions in the static context
191: *
192: * @return the function libary
193: */
194:
195: public FunctionLibrary getFunctionLibrary() {
196: return functionLibrary;
197: }
198:
199: /**
200: * Set the library containing all the in-scope functions in the static context
201: *
202: * @param functionLibrary the function libary
203: */
204:
205: public void setFunctionLibrary(FunctionLibrary functionLibrary) {
206: //System.err.println("***" + this + " setFunctionLib to " + functionLibrary);
207: this .functionLibrary = functionLibrary;
208: }
209:
210: /**
211: * Set the index of named character maps
212: *
213: * @param cmi a hash table that maps the names of character maps
214: * to the HashMap objects representing the character maps
215: */
216:
217: public void setCharacterMapIndex(IntHashMap cmi) {
218: characterMapIndex = cmi;
219: }
220:
221: /**
222: * Get the index of named character maps
223: *
224: * @return the hash table that maps the names of character maps
225: * to the HashMap objects representing the character maps
226: */
227:
228: public IntHashMap getCharacterMapIndex() {
229: if (characterMapIndex == null) {
230: characterMapIndex = new IntHashMap(10);
231: }
232: return characterMapIndex;
233: }
234:
235: /**
236: * Set the rules determining which nodes are to be stripped from the tree
237: *
238: * @param rules a Mode object containing the whitespace stripping rules. A Mode
239: * is generally a collection of template rules, but it is reused here to represent
240: * a collection of stripping rules.
241: */
242:
243: public void setStripperRules(Mode rules) {
244: stripperRules = rules;
245: }
246:
247: /**
248: * Get the rules determining which nodes are to be stripped from the tree
249: *
250: * @return a Mode object containing the whitespace stripping rules. A Mode
251: * is generally a collection of template rules, but it is reused here to represent
252: * a collection of stripping rules.
253: */
254:
255: public Mode getStripperRules() {
256: return stripperRules;
257: }
258:
259: /**
260: * Indicate that the stylesheet does some whitespace stripping
261: *
262: * @param strips true if the stylesheet performs whitespace stripping
263: * of one or more elements.
264: */
265:
266: public void setStripsWhitespace(boolean strips) {
267: stripsWhitespace = strips;
268: }
269:
270: /**
271: * Create a Stripper which handles whitespace stripping definitions
272: *
273: * @return the constructed Stripper object
274: */
275:
276: public Stripper newStripper() {
277: return new Stripper(stripperRules);
278: }
279:
280: /**
281: * Determine whether this stylesheet does any whitespace stripping
282: *
283: * @return true if the stylesheet performs whitespace stripping
284: * of one or more elements.
285: */
286:
287: public boolean stripsWhitespace() {
288: return stripsWhitespace;
289: }
290:
291: /**
292: * Set whether source documents are to have their type annotations stripped
293: */
294:
295: public void setStripsInputTypeAnnotations(boolean strips) {
296: stripsInputTypeAnnotations = strips;
297: }
298:
299: /**
300: * Determine whether source documents are to have their type annotations stripped
301: */
302:
303: public boolean stripsInputTypeAnnotations() {
304: return stripsInputTypeAnnotations;
305: }
306:
307: /**
308: * Set the KeyManager which handles key definitions
309: *
310: * @param km the KeyManager containing the xsl:key definitions
311: */
312:
313: public void setKeyManager(KeyManager km) {
314: keyManager = km;
315: }
316:
317: /**
318: * Get the KeyManager which handles key definitions
319: *
320: * @return the KeyManager containing the xsl:key definitions
321: */
322:
323: public KeyManager getKeyManager() {
324: if (keyManager == null) {
325: keyManager = new KeyManager(getConfiguration());
326: }
327: return keyManager;
328: }
329:
330: /**
331: * Set the default output properties (the properties for the unnamed output format)
332: *
333: * @param properties the output properties to be used when the unnamed output format
334: * is selected
335: */
336:
337: public void setDefaultOutputProperties(Properties properties) {
338: defaultOutputProperties = properties;
339: }
340:
341: /**
342: * Get the default output properties
343: *
344: * @return the properties for the unnamed output format
345: */
346:
347: public Properties getDefaultOutputProperties() {
348: if (defaultOutputProperties == null) {
349: defaultOutputProperties = new Properties();
350: }
351: return defaultOutputProperties;
352: }
353:
354: /**
355: * An a named output format
356: *
357: * @param fingerprint the name of the output format
358: * @param properties the properties of the output format
359: */
360:
361: public void setOutputProperties(int fingerprint,
362: Properties properties) {
363: if (outputDeclarations == null) {
364: outputDeclarations = new IntHashMap(5);
365: }
366: outputDeclarations.put(fingerprint, properties);
367: }
368:
369: /**
370: * Get a named output format
371: *
372: * @param fingerprint the name of the output format
373: * @return properties the properties of the output format. Return null if there are
374: * no output properties with the given name
375: */
376:
377: public Properties getOutputProperties(int fingerprint) {
378: if (outputDeclarations == null) {
379: return null;
380: } else {
381: Properties props = (Properties) outputDeclarations
382: .get(fingerprint);
383: if (props == null && fingerprint == -1) {
384: props = new Properties();
385: }
386: return props;
387: }
388: }
389:
390: /**
391: * Set the DecimalFormatManager which handles decimal-format definitions
392: *
393: * @param dfm the DecimalFormatManager containing the named xsl:decimal-format definitions
394: */
395:
396: public void setDecimalFormatManager(DecimalFormatManager dfm) {
397: decimalFormatManager = dfm;
398: }
399:
400: /**
401: * Get the DecimalFormatManager which handles decimal-format definitions
402: *
403: * @return the DecimalFormatManager containing the named xsl:decimal-format definitions
404: */
405:
406: public DecimalFormatManager getDecimalFormatManager() {
407: if (decimalFormatManager == null) {
408: decimalFormatManager = new DecimalFormatManager();
409: }
410: return decimalFormatManager;
411: }
412:
413: /**
414: * Set the default collation
415: *
416: * @param name the name of the default collation
417: */
418:
419: public void setDefaultCollationName(String name) {
420: defaultCollationName = name;
421: }
422:
423: /**
424: * Get the name of the default collation
425: *
426: * @return the name of the default collation; this is the code point collation URI if no other default
427: * has been set up.
428: */
429:
430: public String getDefaultCollationName() {
431: if (defaultCollationName == null) {
432: return NamespaceConstant.CODEPOINT_COLLATION_URI;
433: } else {
434: return defaultCollationName;
435: }
436: }
437:
438: /**
439: * Get the default collation
440: *
441: * @return a Comparator that implements the default collation
442: */
443:
444: public Comparator getDefaultCollation() {
445: if (defaultCollationName == null) {
446: return CodepointCollator.getInstance();
447: } else {
448: return getNamedCollation(defaultCollationName);
449: }
450: }
451:
452: /**
453: * Set the table of collations
454: *
455: * @param table a hash table that maps collation names (URIs) to objects representing the
456: * collation information
457: */
458:
459: public void setCollationTable(HashMap table) {
460: collationTable = table;
461: }
462:
463: /**
464: * Get the table of collations
465: *
466: * @return a hash table that maps collation names (URIs) to objects representing the
467: * collation information
468: */
469:
470: public HashMap getCollationTable() {
471: return collationTable;
472: }
473:
474: /**
475: * Find a named collation.
476: *
477: * @param name identifies the name of the collation required; null indicates that the default
478: * collation is required
479: * @return the requested collation, or null if the collation is not found
480: */
481:
482: public Comparator getNamedCollation(String name) {
483: if (collationTable == null) {
484: collationTable = new HashMap(10);
485: }
486: return (Comparator) collationTable.get(name);
487: }
488:
489: /**
490: * Add an XQuery library module to the configuration. The Executable maintains a table indicating
491: * for each module namespace, the set of modules that have been loaded from that namespace. If a
492: * module import is encountered that specifies no location hint, all the known modules for that
493: * namespace are imported.
494: */
495:
496: public void addQueryLibraryModule(StaticQueryContext module) {
497: if (queryLibraryModules == null) {
498: queryLibraryModules = new HashMap(5);
499: }
500: String uri = module.getModuleNamespace();
501: List existing = (List) queryLibraryModules.get(uri);
502: if (existing == null) {
503: existing = new ArrayList(5);
504: existing.add(module);
505: queryLibraryModules.put(uri, existing);
506: } else {
507: existing.add(module);
508: }
509: }
510:
511: /**
512: * Locate the known XQuery library modules for a given module namespace.
513: *
514: * @param namespace the module namespace URI
515: * @return a list of items each of which is the StaticQueryContext representing a module, or
516: * null if the module namespace is unknown
517: */
518:
519: public List getQueryLibraryModules(String namespace) {
520: if (queryLibraryModules == null) {
521: return null;
522: }
523: return (List) queryLibraryModules.get(namespace);
524: }
525:
526: /**
527: * Fix up global variables and functions in all query modules. This is done right at the end, because
528: * recursive imports are permitted
529: */
530:
531: public void fixupQueryModules(StaticQueryContext main)
532: throws XPathException {
533:
534: main.bindUnboundVariables();
535: if (queryLibraryModules != null) {
536: Iterator iter = queryLibraryModules.values().iterator();
537: while (iter.hasNext()) {
538: List modules = (List) iter.next();
539: Iterator iter2 = modules.iterator();
540: while (iter2.hasNext()) {
541: StaticQueryContext env = (StaticQueryContext) iter2
542: .next();
543: env.bindUnboundVariables();
544: }
545: }
546: }
547: List compiledVars = main.fixupGlobalVariables(main
548: .getGlobalStackFrameMap());
549:
550: main.bindUnboundFunctionCalls();
551: if (queryLibraryModules != null) {
552: Iterator iter = queryLibraryModules.values().iterator();
553: while (iter.hasNext()) {
554: List modules = (List) iter.next();
555: Iterator iter2 = modules.iterator();
556: while (iter2.hasNext()) {
557: StaticQueryContext env = (StaticQueryContext) iter2
558: .next();
559: env.bindUnboundFunctionCalls();
560: }
561: }
562: }
563: main.fixupGlobalFunctions();
564:
565: main.typeCheckGlobalVariables(compiledVars);
566: }
567:
568: /**
569: * Set the space requirements for variables used in template match patterns
570: *
571: * @param patternLocals The largest number of local variables used in the match pattern of any template rule
572: */
573:
574: public void setPatternSlotSpace(int patternLocals) {
575: largestPatternStackFrame = patternLocals;
576: }
577:
578: /**
579: * Get the global variable map
580: *
581: * @return the SlotManager defining the allocation of slots to global variables
582: */
583:
584: public SlotManager getGlobalVariableMap() {
585: if (globalVariableMap == null) {
586: globalVariableMap = config.makeSlotManager();
587: }
588: return globalVariableMap;
589: }
590:
591: /**
592: * Get the index of global variables
593: *
594: * @return the index of global variables. This is a HashMap in which the key is the integer fingerprint
595: * of the variable name, and the value is the GlobalVariable object representing the compiled global variable
596: */
597:
598: public IntHashMap getCompiledGlobalVariables() {
599: return compiledGlobalVariables;
600: }
601:
602: /**
603: * Register a global variable
604: */
605:
606: public void registerGlobalVariable(GlobalVariable variable) {
607: compiledGlobalVariables.put(variable.getVariableFingerprint(),
608: variable);
609: }
610:
611: /**
612: * Allocate space in bindery for all the variables needed
613: *
614: * @param bindery The bindery to be initialized
615: */
616:
617: public void initialiseBindery(Bindery bindery) {
618: bindery.allocateGlobals(getGlobalVariableMap());
619: }
620:
621: /**
622: * Determine the size of the stack frame needed for evaluating match patterns
623: */
624:
625: public int getLargestPatternStackFrame() {
626: return largestPatternStackFrame;
627: }
628:
629: /**
630: * Set the location map
631: */
632:
633: public void setLocationMap(LocationMap map) {
634: locationMap = map;
635: }
636:
637: /**
638: * Get the location map
639: */
640:
641: public LocationMap getLocationMap() {
642: return locationMap;
643: }
644:
645: /**
646: * Add a required parameter
647: */
648:
649: public void addRequiredParam(int fingerprint) {
650: if (requiredParams == null) {
651: requiredParams = new IntHashSet(5);
652: }
653: requiredParams.add(fingerprint);
654: }
655:
656: /**
657: * Check that all required parameters have been supplied
658: */
659:
660: public void checkAllRequiredParamsArePresent(
661: GlobalParameterSet params) throws XPathException {
662: if (requiredParams == null) {
663: return;
664: }
665: IntIterator iter = requiredParams.iterator();
666: while (iter.hasNext()) {
667: int req = iter.next();
668: if (params == null || params.get(req) == null) {
669: DynamicError err = new DynamicError(
670: "No value supplied for required parameter "
671: + config.getNamePool().getDisplayName(
672: req));
673: err.setErrorCode("XTDE0050");
674: throw err;
675: }
676: }
677: }
678:
679: /**
680: * If this Executable can't be compiled, set a message explaining why
681: */
682:
683: public void setReasonUnableToCompile(String reason) {
684: reasonUnableToCompile = reason;
685: }
686:
687: /**
688: * Determine whether this executable can be compiled; and if it can't, return the reason why
689: *
690: * @return null if the executable can be compiled, or a message otherwise
691: */
692:
693: public String getReasonUnableToCompile() {
694: return reasonUnableToCompile;
695: }
696:
697: }
698:
699: //
700: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
701: // you may not use this file except in compliance with the License. You may obtain a copy of the
702: // License at http://www.mozilla.org/MPL/
703: //
704: // Software distributed under the License is distributed on an "AS IS" basis,
705: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
706: // See the License for the specific language governing rights and limitations under the License.
707: //
708: // The Original Code is: all this file.
709: //
710: // The Initial Developer of the Original Code is Michael H. Kay.
711: //
712: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
713: //
714: // Contributor(s):
715: // Portions marked "e.g." are from Edwin Glaser (edwin@pannenleiter.de)
716: //
|