001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.runtime;
027:
028: import javax.xml.bind.Binder;
029: import javax.xml.bind.JAXBElement;
030: import javax.xml.bind.JAXBException;
031: import javax.xml.bind.PropertyException;
032: import javax.xml.bind.ValidationEventHandler;
033: import javax.xml.validation.Schema;
034: import javax.xml.namespace.QName;
035:
036: import com.sun.xml.internal.bind.unmarshaller.InfosetScanner;
037: import com.sun.xml.internal.bind.v2.runtime.output.DOMOutput;
038: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor;
039: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector;
040: import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl;
041:
042: import org.w3c.dom.Element;
043: import org.w3c.dom.Node;
044: import org.xml.sax.SAXException;
045:
046: /**
047: * Implementation of {@link Binder}.
048: *
049: * TODO: investigate how much in-place unmarshalling is implemented
050: * - some preliminary work is there. Probably buggy.
051: * TODO: work on the marshaller side.
052: *
053: * @author
054: * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
055: */
056: public class BinderImpl<XmlNode> extends Binder<XmlNode> {
057:
058: /**
059: * The parent context object.
060: */
061: private final JAXBContextImpl context;
062:
063: /**
064: * Lazily created unmarshaller to do XML->Java binding.
065: * @see #getUnmarshaller()
066: */
067: private UnmarshallerImpl unmarshaller;
068:
069: /**
070: * Lazily create marshaller to do Java->XML binding.
071: * @see #getMarshaller()
072: */
073: private MarshallerImpl marshaller;
074:
075: private final InfosetScanner<XmlNode> scanner;
076:
077: /**
078: * A {@link Binder} always works with the same
079: * association map.
080: */
081: private final AssociationMap<XmlNode> assoc = new AssociationMap<XmlNode>();
082:
083: BinderImpl(JAXBContextImpl _context, InfosetScanner<XmlNode> scanner) {
084: this .context = _context;
085: this .scanner = scanner;
086: }
087:
088: private UnmarshallerImpl getUnmarshaller() {
089: if (unmarshaller == null)
090: unmarshaller = new UnmarshallerImpl(context, assoc);
091: return unmarshaller;
092: }
093:
094: private MarshallerImpl getMarshaller() {
095: if (marshaller == null)
096: marshaller = new MarshallerImpl(context, assoc);
097: return marshaller;
098: }
099:
100: public void marshal(Object jaxbObject, XmlNode xmlNode)
101: throws JAXBException {
102: if ((xmlNode == null) || (jaxbObject == null))
103: throw new IllegalArgumentException();
104: getMarshaller().marshal(jaxbObject, createOutput(xmlNode));
105: }
106:
107: // TODO move this to a sub class once we support something other than W3C DOM
108: private DOMOutput createOutput(XmlNode xmlNode) {
109: return new DOMOutput((Node) xmlNode, assoc);
110: }
111:
112: public Object updateJAXB(XmlNode xmlNode) throws JAXBException {
113: return associativeUnmarshal(xmlNode, true, null);
114: }
115:
116: public Object unmarshal(XmlNode xmlNode) throws JAXBException {
117: return associativeUnmarshal(xmlNode, false, null);
118: }
119:
120: public <T> JAXBElement<T> unmarshal(XmlNode xmlNode,
121: Class<T> expectedType) throws JAXBException {
122: if (expectedType == null)
123: throw new IllegalArgumentException();
124: return (JAXBElement) associativeUnmarshal(xmlNode, true,
125: expectedType);
126: }
127:
128: public void setSchema(Schema schema) {
129: getUnmarshaller().setSchema(schema);
130: }
131:
132: public Schema getSchema() {
133: return getUnmarshaller().getSchema();
134: }
135:
136: private Object associativeUnmarshal(XmlNode xmlNode,
137: boolean inplace, Class expectedType) throws JAXBException {
138: if (xmlNode == null)
139: throw new IllegalArgumentException();
140:
141: JaxBeanInfo bi = null;
142: if (expectedType != null)
143: bi = context.getBeanInfo(expectedType, true);
144:
145: InterningXmlVisitor handler = new InterningXmlVisitor(
146: getUnmarshaller().createUnmarshallerHandler(scanner,
147: inplace, bi));
148: scanner.setContentHandler(new SAXConnector(handler, scanner
149: .getLocator()));
150: try {
151: scanner.scan(xmlNode);
152: } catch (SAXException e) {
153: throw unmarshaller.createUnmarshalException(e);
154: }
155:
156: return handler.getContext().getResult();
157: }
158:
159: public XmlNode getXMLNode(Object jaxbObject) {
160: AssociationMap.Entry<XmlNode> e = assoc.byPeer(jaxbObject);
161: if (e == null)
162: return null;
163: return e.element();
164: }
165:
166: public Object getJAXBNode(XmlNode xmlNode) {
167: AssociationMap.Entry e = assoc.byElement(xmlNode);
168: if (e == null)
169: return null;
170: if (e.outer() != null)
171: return e.outer();
172: return e.inner();
173: }
174:
175: public XmlNode updateXML(Object jaxbObject) throws JAXBException {
176: return updateXML(jaxbObject, getXMLNode(jaxbObject));
177: }
178:
179: public XmlNode updateXML(Object jaxbObject, XmlNode xmlNode)
180: throws JAXBException {
181: if (jaxbObject == null || xmlNode == null)
182: throw new IllegalArgumentException();
183:
184: // TODO
185: // for now just marshal
186: // TODO: object model independenc
187: Element e = (Element) xmlNode;
188: Node ns = e.getNextSibling();
189: Node p = e.getParentNode();
190: p.removeChild(e);
191:
192: // if the type object is passed, the following step is necessary to make
193: // the marshalling successful.
194: JaxBeanInfo bi = context.getBeanInfo(jaxbObject, true);
195: if (!bi.isElement())
196: jaxbObject = new JAXBElement(new QName(e.getNamespaceURI(),
197: e.getLocalName()), bi.jaxbType, jaxbObject);
198:
199: getMarshaller().marshal(jaxbObject, p);
200: Node newNode = p.getLastChild();
201: p.removeChild(newNode);
202: p.insertBefore(newNode, ns);
203:
204: return (XmlNode) newNode;
205: }
206:
207: public void setEventHandler(ValidationEventHandler handler)
208: throws JAXBException {
209: getUnmarshaller().setEventHandler(handler);
210: getMarshaller().setEventHandler(handler);
211: }
212:
213: public ValidationEventHandler getEventHandler() {
214: return getUnmarshaller().getEventHandler();
215: }
216:
217: public Object getProperty(String name) throws PropertyException {
218: if (name == null)
219: throw new IllegalArgumentException(
220: Messages.NULL_PROPERTY_NAME.format());
221:
222: // exclude RI properties that don't make sense for Binder
223: if (excludeProperty(name)) {
224: throw new PropertyException(name);
225: }
226:
227: Object prop = null;
228: PropertyException pe = null;
229:
230: try {
231: prop = getMarshaller().getProperty(name);
232: return prop;
233: } catch (PropertyException p) {
234: pe = p;
235: }
236:
237: try {
238: prop = getUnmarshaller().getProperty(name);
239: return prop;
240: } catch (PropertyException p) {
241: pe = p;
242: }
243:
244: pe.setStackTrace(Thread.currentThread().getStackTrace());
245: throw pe;
246: }
247:
248: public void setProperty(String name, Object value)
249: throws PropertyException {
250: if (name == null)
251: throw new IllegalArgumentException(
252: Messages.NULL_PROPERTY_NAME.format());
253:
254: // exclude RI properties that don't make sense for Binder
255: if (excludeProperty(name)) {
256: throw new PropertyException(name, value);
257: }
258:
259: PropertyException pe = null;
260:
261: try {
262: getMarshaller().setProperty(name, value);
263: return;
264: } catch (PropertyException p) {
265: pe = p;
266: }
267:
268: try {
269: getUnmarshaller().setProperty(name, value);
270: return;
271: } catch (PropertyException p) {
272: pe = p;
273: }
274:
275: // replace the stacktrace - we don't want to see a trace
276: // originating from Un|Marshaller.setProperty
277: pe.setStackTrace(Thread.currentThread().getStackTrace());
278: throw pe;
279: }
280:
281: private boolean excludeProperty(String name) {
282: return name.equals(MarshallerImpl.ENCODING_HANDLER)
283: || name.equals(MarshallerImpl.XMLDECLARATION)
284: || name.equals(MarshallerImpl.XML_HEADERS);
285: }
286: }
|