001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.bind.v2.runtime.output;
038:
039: import java.io.IOException;
040: import java.lang.reflect.Constructor;
041:
042: import javax.xml.stream.XMLStreamException;
043: import javax.xml.stream.XMLStreamWriter;
044:
045: import com.sun.xml.bind.v2.runtime.JAXBContextImpl;
046: import com.sun.xml.bind.v2.runtime.MarshallerImpl;
047: import com.sun.xml.bind.v2.runtime.XMLSerializer;
048: import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
049:
050: import org.xml.sax.SAXException;
051:
052: /**
053: * {@link XmlOutput} that writes to StAX {@link XMLStreamWriter}.
054: * <p>
055: * TODO:
056: * Finding the optimized FI implementations is a bit hacky and not very
057: * extensible. Can we use the service provider mechnism in general for
058: * concrete implementations of XmlOutputAbstractImpl.
059: *
060: * @author Kohsuke Kawaguchi
061: */
062: public class XMLStreamWriterOutput extends XmlOutputAbstractImpl {
063:
064: /**
065: * Creates a new {@link XmlOutput} from a {@link XMLStreamWriter}.
066: * This method recognizes an FI StAX writer.
067: */
068: public static XmlOutput create(XMLStreamWriter out,
069: JAXBContextImpl context) {
070: // try optimized path
071: final Class writerClass = out.getClass();
072: if (writerClass == FI_STAX_WRITER_CLASS) {
073: try {
074: return FI_OUTPUT_CTOR.newInstance(out, context);
075: } catch (Exception e) {
076: }
077: }
078: if (STAXEX_WRITER_CLASS != null
079: && STAXEX_WRITER_CLASS.isAssignableFrom(writerClass)) {
080: try {
081: return STAXEX_OUTPUT_CTOR.newInstance(out);
082: } catch (Exception e) {
083: }
084: }
085:
086: // otherwise the normal writer.
087: return new XMLStreamWriterOutput(out);
088: }
089:
090: private final XMLStreamWriter out;
091:
092: protected final char[] buf = new char[256];
093:
094: protected XMLStreamWriterOutput(XMLStreamWriter out) {
095: this .out = out;
096: }
097:
098: // not called if we are generating fragments
099: public void startDocument(XMLSerializer serializer,
100: boolean fragment, int[] nsUriIndex2prefixIndex,
101: NamespaceContextImpl nsContext) throws IOException,
102: SAXException, XMLStreamException {
103: super .startDocument(serializer, fragment,
104: nsUriIndex2prefixIndex, nsContext);
105: if (!fragment)
106: out.writeStartDocument();
107: }
108:
109: public void endDocument(boolean fragment) throws IOException,
110: SAXException, XMLStreamException {
111: if (!fragment) {
112: out.writeEndDocument();
113: out.flush();
114: }
115: super .endDocument(fragment);
116: }
117:
118: public void beginStartTag(int prefix, String localName)
119: throws IOException, XMLStreamException {
120: out.writeStartElement(nsContext.getPrefix(prefix), localName,
121: nsContext.getNamespaceURI(prefix));
122:
123: NamespaceContextImpl.Element nse = nsContext.getCurrent();
124: if (nse.count() > 0) {
125: for (int i = nse.count() - 1; i >= 0; i--) {
126: String uri = nse.getNsUri(i);
127: if (uri.length() == 0 && nse.getBase() == 1)
128: continue; // no point in definint xmlns='' on the root
129: out.writeNamespace(nse.getPrefix(i), uri);
130: }
131: }
132: }
133:
134: public void attribute(int prefix, String localName, String value)
135: throws IOException, XMLStreamException {
136: if (prefix == -1)
137: out.writeAttribute(localName, value);
138: else
139: out.writeAttribute(nsContext.getPrefix(prefix), nsContext
140: .getNamespaceURI(prefix), localName, value);
141: }
142:
143: public void endStartTag() throws IOException, SAXException {
144: // noop
145: }
146:
147: public void endTag(int prefix, String localName)
148: throws IOException, SAXException, XMLStreamException {
149: out.writeEndElement();
150: }
151:
152: public void text(String value, boolean needsSeparatingWhitespace)
153: throws IOException, SAXException, XMLStreamException {
154: if (needsSeparatingWhitespace)
155: out.writeCharacters(" ");
156: out.writeCharacters(value);
157: }
158:
159: public void text(Pcdata value, boolean needsSeparatingWhitespace)
160: throws IOException, SAXException, XMLStreamException {
161: if (needsSeparatingWhitespace)
162: out.writeCharacters(" ");
163:
164: int len = value.length();
165: if (len < buf.length) {
166: value.writeTo(buf, 0);
167: out.writeCharacters(buf, 0, len);
168: } else {
169: out.writeCharacters(value.toString());
170: }
171: }
172:
173: /**
174: * Reference to FI's XMLStreamWriter class, if FI can be loaded.
175: */
176: private static final Class FI_STAX_WRITER_CLASS = initFIStAXWriterClass();
177: private static final Constructor<? extends XmlOutput> FI_OUTPUT_CTOR = initFastInfosetOutputClass();
178:
179: private static Class initFIStAXWriterClass() {
180: try {
181: Class llfisw = MarshallerImpl.class
182: .getClassLoader()
183: .loadClass(
184: "org.jvnet.fastinfoset.stax.LowLevelFastInfosetStreamWriter");
185: Class sds = MarshallerImpl.class
186: .getClassLoader()
187: .loadClass(
188: "com.sun.xml.fastinfoset.stax.StAXDocumentSerializer");
189: // Check if StAXDocumentSerializer implements LowLevelFastInfosetStreamWriter
190: if (llfisw.isAssignableFrom(sds))
191: return sds;
192: else
193: return null;
194: } catch (Throwable e) {
195: return null;
196: }
197: }
198:
199: private static Constructor<? extends XmlOutput> initFastInfosetOutputClass() {
200: try {
201: if (FI_STAX_WRITER_CLASS == null)
202: return null;
203:
204: Class c = UnmarshallerImpl.class
205: .getClassLoader()
206: .loadClass(
207: "com.sun.xml.bind.v2.runtime.output.FastInfosetStreamWriterOutput");
208: return c.getConstructor(FI_STAX_WRITER_CLASS,
209: JAXBContextImpl.class);
210: } catch (Throwable e) {
211: return null;
212: }
213: }
214:
215: //
216: // StAX-ex
217: //
218: private static final Class STAXEX_WRITER_CLASS = initStAXExWriterClass();
219: private static final Constructor<? extends XmlOutput> STAXEX_OUTPUT_CTOR = initStAXExOutputClass();
220:
221: private static Class initStAXExWriterClass() {
222: try {
223: return MarshallerImpl.class.getClassLoader().loadClass(
224: "org.jvnet.staxex.XMLStreamWriterEx");
225: } catch (Throwable e) {
226: return null;
227: }
228: }
229:
230: private static Constructor<? extends XmlOutput> initStAXExOutputClass() {
231: try {
232: Class c = UnmarshallerImpl.class
233: .getClassLoader()
234: .loadClass(
235: "com.sun.xml.bind.v2.runtime.output.StAXExStreamWriterOutput");
236: return c.getConstructor(STAXEX_WRITER_CLASS);
237: } catch (Throwable e) {
238: return null;
239: }
240: }
241: }
|