001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.webadapter;
039:
040: import java.io.IOException;
041: import java.io.InputStream;
042: import java.util.Collection;
043: import java.util.Iterator;
044:
045: import org.xml.sax.Attributes;
046: import org.xml.sax.ContentHandler;
047: import org.xml.sax.DTDHandler;
048: import org.xml.sax.EntityResolver;
049: import org.xml.sax.ErrorHandler;
050: import org.xml.sax.InputSource;
051: import org.xml.sax.Locator;
052: import org.xml.sax.SAXException;
053: import org.xml.sax.SAXNotRecognizedException;
054: import org.xml.sax.SAXNotSupportedException;
055: import org.xml.sax.SAXParseException;
056: import org.xml.sax.XMLReader;
057:
058: /** Class implementing XMLReader for the MillStone WebAdapter UIDLTransformer.
059: *
060: * @author IT Mill Ltd.
061: * @version 3.1.1
062: * @since 3.0
063: */
064:
065: public class XSLReader implements XMLReader, ContentHandler {
066:
067: static protected final int XSLT_UNKNOWN = 0;
068: static protected final int XSLT_XALAN = 1;
069: static protected final int XSLT_SAXON6 = 2;
070: static protected final int XSLT_SAXON7 = 3;
071: static protected final int XSLT_RESIN = 4;
072: static protected final int XSLT_WEBLOGIC = 5;
073: static protected int xsltProcessor = XSLT_UNKNOWN;
074: static {
075: String transformerName = UIDLTransformer.xsltFactory.getClass()
076: .getName();
077:
078: // Saxon 7.x
079: if ("net.sf.saxon.TransformerFactoryImpl"
080: .equals(transformerName))
081: xsltProcessor = XSLT_SAXON7;
082:
083: // Saxon 6.x
084: else if ("com.icl.saxon.TransformerFactoryImpl"
085: .equals(transformerName))
086: xsltProcessor = XSLT_SAXON6;
087:
088: // Xalan
089: else if ("org.apache.xalan.processor.TransformerFactoryImpl"
090: .equals(transformerName)
091: || "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"
092: .equals(transformerName))
093: xsltProcessor = XSLT_XALAN;
094: // Resin
095: else if ("com.caucho.xsl.Xsl".equals(transformerName))
096: xsltProcessor = XSLT_RESIN;
097:
098: else if ("weblogic.xml.jaxp.RegistrySAXTransformerFactory"
099: .equals(transformerName))
100: xsltProcessor = XSLT_WEBLOGIC;
101: else {
102: throw new RuntimeException(
103: "\nThis version of Millstone Web Adapter "
104: + " does not support the selected XSLT-processer:\n "
105: + transformerName
106: + "\n"
107: + "You can specify the used XSLT processor with JVM "
108: + "parameter like: \n"
109: + " -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl\n"
110: + " -Dorg.xml.sax.driver=org.apache.crimson.parser.XMLReaderImpl\n");
111: }
112: }
113:
114: private static final String MILLSTONE_PREFIX = "millstone://";
115: private Collection streams;
116: private boolean startTagHandled = false;
117: private String xslNamespace = "";
118: private ContentHandler handler;
119: private XMLReader reader;
120:
121: private XSLStreamLocator locator = null;
122: private Locator streamLocator = null;
123: private int streamStartLineNumber = 0;
124:
125: public XSLReader(XMLReader reader, Collection streams) {
126: this .reader = reader;
127: reader.setContentHandler(this );
128: this .streams = streams;
129: }
130:
131: /** Parse all streams given for constructor parameter.
132: * The input parameter is ignored.
133: * @see org.xml.sax.XMLReader#parse(InputSource)
134: */
135: public synchronized void parse(InputSource input)
136: throws IOException, SAXException {
137:
138: startTagHandled = false;
139: handler.startDocument();
140: // Parse all files
141: for (Iterator i = streams.iterator(); i.hasNext();) {
142: ThemeSource.XSLStream xslStream = (ThemeSource.XSLStream) i
143: .next();
144: this .locator = new XSLStreamLocator(xslStream.getId());
145: InputStream in = (xslStream).getStream();
146:
147: // Parse the stream
148: reader.parse(new InputSource(in));
149:
150: }
151: handler
152: .endElement(xslNamespace, "stylesheet",
153: "xsl:stylesheet");
154: handler.endDocument();
155: }
156:
157: /**
158: * @see org.xml.sax.ContentHandler#endElement(String, String, String)
159: */
160: public void endElement(String namespaceURI, String localName,
161: String qName) throws SAXException {
162: if (localName.equals("stylesheet")) {
163: return; //Skip
164: }
165: handler.endElement(namespaceURI, localName, qName);
166: }
167:
168: /**
169: * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
170: */
171: public void processingInstruction(String target, String data)
172: throws SAXException {
173: handler.processingInstruction(target, data);
174: }
175:
176: /**
177: * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
178: */
179: public void startElement(String namespaceURI, String localName,
180: String qName, Attributes atts) throws SAXException {
181:
182: // Only the first stylesheet is used
183: if (startTagHandled && localName.equals("stylesheet"))
184: return; //skip
185:
186: // Get the namespace that will be used for closing the theme
187: if (localName.equals("stylesheet")) {
188: startTagHandled = true;
189: this .xslNamespace = namespaceURI;
190:
191: // Manage calls to external functions in XSLT-processor independent
192: // way, but still using XSLT 1.0
193: handler.startElement(namespaceURI, localName, qName,
194: new AttributeMapper(atts));
195: } else
196:
197: // Handle the element in superclass directly
198: handler.startElement(namespaceURI, localName, qName, atts);
199: }
200:
201: /**
202: * @see org.xml.sax.ContentHandler#characters(char[], int, int)
203: */
204: public void characters(char[] ch, int start, int length)
205: throws SAXException {
206: handler.characters(ch, start, length);
207: }
208:
209: /**
210: * @see org.xml.sax.ContentHandler#startDocument()
211: */
212: public void startDocument() throws SAXException {
213: // Ignore document starts
214: }
215:
216: /**
217: * @see org.xml.sax.ContentHandler#endDocument()
218: */
219: public void endDocument() throws SAXException {
220: //Ignore document ends, but add previous line numbers
221: if (this .streamLocator != null) {
222: this .streamStartLineNumber += this .streamLocator
223: .getLineNumber();
224: }
225: }
226:
227: /**
228: * @see org.xml.sax.ContentHandler#endPrefixMapping(String)
229: */
230: public void endPrefixMapping(String prefix) throws SAXException {
231: handler.endPrefixMapping(prefix);
232: }
233:
234: /**
235: * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
236: */
237: public void ignorableWhitespace(char[] ch, int start, int length)
238: throws SAXException {
239: handler.ignorableWhitespace(ch, start, length);
240: }
241:
242: /**
243: * @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
244: */
245: public void setDocumentLocator(Locator locator) {
246: this .streamLocator = locator;
247: // create new locator combined streams/files
248: if (!startTagHandled) {
249: handler.setDocumentLocator(this .locator);
250: }
251: }
252:
253: /**
254: * @see org.xml.sax.ContentHandler#skippedEntity(String)
255: */
256: public void skippedEntity(String name) throws SAXException {
257: handler.skippedEntity(name);
258: }
259:
260: /**
261: * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
262: */
263: public void startPrefixMapping(String prefix, String uri)
264: throws SAXException {
265: handler.startPrefixMapping(prefix, uri);
266: }
267:
268: /** Override the default content handler.
269: * @see org.xml.sax.XMLReader#getContentHandler()
270: */
271: public ContentHandler getContentHandler() {
272: return this .handler;
273: }
274:
275: /** Override the default content handler.
276: * @see org.xml.sax.XMLReader#setContentHandler(ContentHandler)
277: */
278: public void setContentHandler(ContentHandler handler) {
279: this .handler = handler;
280: }
281:
282: /**
283: * @see org.xml.sax.XMLReader#getDTDHandler()
284: */
285: public DTDHandler getDTDHandler() {
286: return reader.getDTDHandler();
287: }
288:
289: /**
290: * @see org.xml.sax.XMLReader#getEntityResolver()
291: */
292: public EntityResolver getEntityResolver() {
293: return reader.getEntityResolver();
294: }
295:
296: /**
297: * @see org.xml.sax.XMLReader#getErrorHandler()
298: */
299: public ErrorHandler getErrorHandler() {
300: return reader.getErrorHandler();
301: }
302:
303: /**
304: * @see org.xml.sax.XMLReader#getFeature(String)
305: */
306: public boolean getFeature(String name)
307: throws SAXNotRecognizedException, SAXNotSupportedException {
308: return reader.getFeature(name);
309: }
310:
311: /**
312: * @see org.xml.sax.XMLReader#getProperty(String)
313: */
314: public Object getProperty(String name)
315: throws SAXNotRecognizedException, SAXNotSupportedException {
316: return reader.getProperty(name);
317: }
318:
319: /** Override the parse.
320: * @see org.xml.sax.XMLReader#parse(String)
321: */
322: public void parse(String systemId) throws IOException, SAXException {
323: this .parse((InputSource) null);
324: }
325:
326: /**
327: * @see org.xml.sax.XMLReader#setDTDHandler(DTDHandler)
328: */
329: public void setDTDHandler(DTDHandler handler) {
330: reader.setDTDHandler(handler);
331: }
332:
333: /**
334: * @see org.xml.sax.XMLReader#setEntityResolver(EntityResolver)
335: */
336: public void setEntityResolver(EntityResolver resolver) {
337: reader.setEntityResolver(resolver);
338: }
339:
340: /**
341: * @see org.xml.sax.XMLReader#setErrorHandler(ErrorHandler)
342: */
343: public void setErrorHandler(ErrorHandler handler) {
344: reader.setErrorHandler(new SAXStreamErrorHandler(handler));
345: }
346:
347: /**
348: * @see org.xml.sax.XMLReader#setFeature(String, boolean)
349: */
350: public void setFeature(String name, boolean value)
351: throws SAXNotRecognizedException, SAXNotSupportedException {
352: reader.setFeature(name, value);
353: }
354:
355: /**
356: * @see org.xml.sax.XMLReader#setProperty(String, Object)
357: */
358: public void setProperty(String name, Object value)
359: throws SAXNotRecognizedException, SAXNotSupportedException {
360: reader.setProperty(name, value);
361: }
362:
363: public class AttributeMapper implements Attributes {
364:
365: private Attributes original;
366:
367: public AttributeMapper(Attributes originalAttributes) {
368: original = originalAttributes;
369: }
370:
371: /**
372: * @see org.xml.sax.Attributes#getIndex(String, String)
373: */
374: public int getIndex(String uri, String localName) {
375: return original.getIndex(uri, localName);
376: }
377:
378: /**
379: * @see org.xml.sax.Attributes#getIndex(String)
380: */
381: public int getIndex(String qName) {
382: return original.getIndex(qName);
383: }
384:
385: /**
386: * @see org.xml.sax.Attributes#getLength()
387: */
388: public int getLength() {
389: return original.getLength();
390: }
391:
392: /**
393: * @see org.xml.sax.Attributes#getLocalName(int)
394: */
395: public String getLocalName(int index) {
396: return original.getLocalName(index);
397: }
398:
399: /**
400: * @see org.xml.sax.Attributes#getQName(int)
401: */
402: public String getQName(int index) {
403: return original.getQName(index);
404: }
405:
406: /**
407: * @see org.xml.sax.Attributes#getType(int)
408: */
409: public String getType(int index) {
410: return original.getType(index);
411: }
412:
413: /**
414: * @see org.xml.sax.Attributes#getType(String, String)
415: */
416: public String getType(String uri, String localName) {
417: return original.getType(uri, localName);
418: }
419:
420: /**
421: * @see org.xml.sax.Attributes#getType(String)
422: */
423: public String getType(String qName) {
424: return original.getType(qName);
425: }
426:
427: /**
428: * @see org.xml.sax.Attributes#getURI(int)
429: */
430: public String getURI(int index) {
431: String uri = original.getURI(index);
432:
433: // Map millstone:// namespaces to transformer specific namespaces
434: if (uri != null && uri.startsWith(MILLSTONE_PREFIX)) {
435:
436: System.out.print("DEBUG " + uri + " --> ");
437: switch (xsltProcessor) {
438: case XSLT_SAXON6:
439: uri = "saxon://"
440: + uri.substring(MILLSTONE_PREFIX.length());
441: break;
442: case XSLT_SAXON7:
443: uri = "saxon://"
444: + uri.substring(MILLSTONE_PREFIX.length());
445: break;
446: case XSLT_XALAN:
447: uri = "xalan://"
448: + uri.substring(MILLSTONE_PREFIX.length());
449: break;
450: default:
451: uri = "xalan://"
452: + uri.substring(MILLSTONE_PREFIX.length());
453: break;
454: }
455: System.out.println(uri);
456: }
457:
458: return uri;
459: }
460:
461: /**
462: * @see org.xml.sax.Attributes#getValue(int)
463: */
464: public String getValue(int index) {
465: return original.getValue(index);
466: }
467:
468: /**
469: * @see org.xml.sax.Attributes#getValue(String, String)
470: */
471: public String getValue(String uri, String localName) {
472: return original.getValue(uri, localName);
473: }
474:
475: /**
476: * @see org.xml.sax.Attributes#getValue(String)
477: */
478: public String getValue(String qName) {
479: return original.getValue(qName);
480: }
481: }
482:
483: public class XSLStreamLocator implements Locator {
484:
485: private String id;
486:
487: public XSLStreamLocator(String id) {
488: this .id = id;
489: }
490:
491: public String getPublicId() {
492: return streamLocator.getPublicId();
493: }
494:
495: public String getSystemId() {
496: return streamLocator.getSystemId() + "" + id;
497: }
498:
499: public int getLineNumber() {
500: return streamLocator.getLineNumber();
501: }
502:
503: public int getCombinedLineNumber() {
504: return streamLocator.getLineNumber()
505: + streamStartLineNumber;
506: }
507:
508: public int getColumnNumber() {
509: return streamLocator.getColumnNumber();
510: }
511:
512: public String getId() {
513: return id;
514: }
515: }
516:
517: public class SAXStreamErrorHandler implements ErrorHandler {
518:
519: private ErrorHandler handler;
520:
521: SAXStreamErrorHandler(ErrorHandler origHandler) {
522: this .handler = origHandler;
523: }
524:
525: public void warning(SAXParseException exception)
526: throws SAXException {
527: handler.warning(new SAXParseException(
528: "" + exception.getMessage() + " in "
529: + locator.getId(), locator, exception));
530: }
531:
532: public void error(SAXParseException exception)
533: throws SAXException {
534: handler.error(new SAXParseException(
535: "" + exception.getMessage() + " in "
536: + locator.getId(), locator, exception));
537: }
538:
539: public void fatalError(SAXParseException exception)
540: throws SAXException {
541: handler.fatalError(new SAXParseException(
542: "" + exception.getMessage() + " in "
543: + locator.getId(), locator, exception));
544: }
545: }
546: }
|