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: package com.sun.xml.bind.v2.runtime;
037:
038: import javax.xml.bind.Binder;
039: import javax.xml.bind.JAXBElement;
040: import javax.xml.bind.JAXBException;
041: import javax.xml.bind.PropertyException;
042: import javax.xml.bind.ValidationEventHandler;
043: import javax.xml.validation.Schema;
044: import javax.xml.namespace.QName;
045:
046: import com.sun.xml.bind.unmarshaller.InfosetScanner;
047: import com.sun.xml.bind.v2.runtime.output.DOMOutput;
048: import com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor;
049: import com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector;
050: import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
051:
052: import org.w3c.dom.Element;
053: import org.w3c.dom.Node;
054: import org.xml.sax.SAXException;
055:
056: /**
057: * Implementation of {@link Binder}.
058: *
059: * TODO: investigate how much in-place unmarshalling is implemented
060: * - some preliminary work is there. Probably buggy.
061: * TODO: work on the marshaller side.
062: *
063: * @author
064: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
065: */
066: public class BinderImpl<XmlNode> extends Binder<XmlNode> {
067:
068: /**
069: * The parent context object.
070: */
071: private final JAXBContextImpl context;
072:
073: /**
074: * Lazily created unmarshaller to do XML->Java binding.
075: * @see #getUnmarshaller()
076: */
077: private UnmarshallerImpl unmarshaller;
078:
079: /**
080: * Lazily create marshaller to do Java->XML binding.
081: * @see #getMarshaller()
082: */
083: private MarshallerImpl marshaller;
084:
085: private final InfosetScanner<XmlNode> scanner;
086:
087: /**
088: * A {@link Binder} always works with the same
089: * association map.
090: */
091: private final AssociationMap<XmlNode> assoc = new AssociationMap<XmlNode>();
092:
093: BinderImpl(JAXBContextImpl _context, InfosetScanner<XmlNode> scanner) {
094: this .context = _context;
095: this .scanner = scanner;
096: }
097:
098: private UnmarshallerImpl getUnmarshaller() {
099: if (unmarshaller == null)
100: unmarshaller = new UnmarshallerImpl(context, assoc);
101: return unmarshaller;
102: }
103:
104: private MarshallerImpl getMarshaller() {
105: if (marshaller == null)
106: marshaller = new MarshallerImpl(context, assoc);
107: return marshaller;
108: }
109:
110: public void marshal(Object jaxbObject, XmlNode xmlNode)
111: throws JAXBException {
112: if ((xmlNode == null) || (jaxbObject == null))
113: throw new IllegalArgumentException();
114: getMarshaller().marshal(jaxbObject, createOutput(xmlNode));
115: }
116:
117: // TODO move this to a sub class once we support something other than W3C DOM
118: private DOMOutput createOutput(XmlNode xmlNode) {
119: return new DOMOutput((Node) xmlNode, assoc);
120: }
121:
122: public Object updateJAXB(XmlNode xmlNode) throws JAXBException {
123: return associativeUnmarshal(xmlNode, true, null);
124: }
125:
126: public Object unmarshal(XmlNode xmlNode) throws JAXBException {
127: return associativeUnmarshal(xmlNode, false, null);
128: }
129:
130: public <T> JAXBElement<T> unmarshal(XmlNode xmlNode,
131: Class<T> expectedType) throws JAXBException {
132: if (expectedType == null)
133: throw new IllegalArgumentException();
134: return (JAXBElement) associativeUnmarshal(xmlNode, true,
135: expectedType);
136: }
137:
138: public void setSchema(Schema schema) {
139: getMarshaller().setSchema(schema);
140: getUnmarshaller().setSchema(schema);
141: }
142:
143: public Schema getSchema() {
144: return getUnmarshaller().getSchema();
145: }
146:
147: private Object associativeUnmarshal(XmlNode xmlNode,
148: boolean inplace, Class expectedType) throws JAXBException {
149: if (xmlNode == null)
150: throw new IllegalArgumentException();
151:
152: JaxBeanInfo bi = null;
153: if (expectedType != null)
154: bi = context.getBeanInfo(expectedType, true);
155:
156: InterningXmlVisitor handler = new InterningXmlVisitor(
157: getUnmarshaller().createUnmarshallerHandler(scanner,
158: inplace, bi));
159: scanner.setContentHandler(new SAXConnector(handler, scanner
160: .getLocator()));
161: try {
162: scanner.scan(xmlNode);
163: } catch (SAXException e) {
164: throw unmarshaller.createUnmarshalException(e);
165: }
166:
167: return handler.getContext().getResult();
168: }
169:
170: public XmlNode getXMLNode(Object jaxbObject) {
171: if (jaxbObject == null)
172: throw new IllegalArgumentException();
173: AssociationMap.Entry<XmlNode> e = assoc.byPeer(jaxbObject);
174: if (e == null)
175: return null;
176: return e.element();
177: }
178:
179: public Object getJAXBNode(XmlNode xmlNode) {
180: if (xmlNode == null)
181: throw new IllegalArgumentException();
182: AssociationMap.Entry e = assoc.byElement(xmlNode);
183: if (e == null)
184: return null;
185: if (e.outer() != null)
186: return e.outer();
187: return e.inner();
188: }
189:
190: public XmlNode updateXML(Object jaxbObject) throws JAXBException {
191: return updateXML(jaxbObject, getXMLNode(jaxbObject));
192: }
193:
194: public XmlNode updateXML(Object jaxbObject, XmlNode xmlNode)
195: throws JAXBException {
196: if (jaxbObject == null || xmlNode == null)
197: throw new IllegalArgumentException();
198:
199: // TODO
200: // for now just marshal
201: // TODO: object model independenc
202: Element e = (Element) xmlNode;
203: Node ns = e.getNextSibling();
204: Node p = e.getParentNode();
205: p.removeChild(e);
206:
207: // if the type object is passed, the following step is necessary to make
208: // the marshalling successful.
209: JaxBeanInfo bi = context.getBeanInfo(jaxbObject, true);
210: if (!bi.isElement())
211: jaxbObject = new JAXBElement(new QName(e.getNamespaceURI(),
212: e.getLocalName()), bi.jaxbType, jaxbObject);
213:
214: getMarshaller().marshal(jaxbObject, p);
215: Node newNode = p.getLastChild();
216: p.removeChild(newNode);
217: p.insertBefore(newNode, ns);
218:
219: return (XmlNode) newNode;
220: }
221:
222: public void setEventHandler(ValidationEventHandler handler)
223: throws JAXBException {
224: getUnmarshaller().setEventHandler(handler);
225: getMarshaller().setEventHandler(handler);
226: }
227:
228: public ValidationEventHandler getEventHandler() {
229: return getUnmarshaller().getEventHandler();
230: }
231:
232: public Object getProperty(String name) throws PropertyException {
233: if (name == null)
234: throw new IllegalArgumentException(
235: Messages.NULL_PROPERTY_NAME.format());
236:
237: // exclude RI properties that don't make sense for Binder
238: if (excludeProperty(name)) {
239: throw new PropertyException(name);
240: }
241:
242: Object prop = null;
243: PropertyException pe = null;
244:
245: try {
246: prop = getMarshaller().getProperty(name);
247: return prop;
248: } catch (PropertyException p) {
249: pe = p;
250: }
251:
252: try {
253: prop = getUnmarshaller().getProperty(name);
254: return prop;
255: } catch (PropertyException p) {
256: pe = p;
257: }
258:
259: pe.setStackTrace(Thread.currentThread().getStackTrace());
260: throw pe;
261: }
262:
263: public void setProperty(String name, Object value)
264: throws PropertyException {
265: if (name == null)
266: throw new IllegalArgumentException(
267: Messages.NULL_PROPERTY_NAME.format());
268:
269: // exclude RI properties that don't make sense for Binder
270: if (excludeProperty(name)) {
271: throw new PropertyException(name, value);
272: }
273:
274: PropertyException pe = null;
275:
276: try {
277: getMarshaller().setProperty(name, value);
278: return;
279: } catch (PropertyException p) {
280: pe = p;
281: }
282:
283: try {
284: getUnmarshaller().setProperty(name, value);
285: return;
286: } catch (PropertyException p) {
287: pe = p;
288: }
289:
290: // replace the stacktrace - we don't want to see a trace
291: // originating from Un|Marshaller.setProperty
292: pe.setStackTrace(Thread.currentThread().getStackTrace());
293: throw pe;
294: }
295:
296: private boolean excludeProperty(String name) {
297: return name.equals(MarshallerImpl.ENCODING_HANDLER)
298: || name.equals(MarshallerImpl.XMLDECLARATION)
299: || name.equals(MarshallerImpl.XML_HEADERS);
300: }
301: }
|