001: /*
002: * Copyright (c) 1998-2007 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.jaxb;
031:
032: import com.caucho.jaxb.skeleton.ClassSkeleton;
033:
034: import com.caucho.util.L10N;
035:
036: import org.w3c.dom.Document;
037: import org.w3c.dom.Element;
038: import org.w3c.dom.Node;
039:
040: import javax.xml.bind.Binder;
041: import javax.xml.bind.JAXBElement;
042: import javax.xml.bind.JAXBException;
043: import javax.xml.bind.Marshaller;
044: import javax.xml.bind.MarshalException;
045: import javax.xml.bind.PropertyException;
046: import javax.xml.bind.Unmarshaller;
047: import javax.xml.bind.UnmarshalException;
048: import javax.xml.bind.ValidationEventHandler;
049: import javax.xml.bind.annotation.XmlRootElement;
050: import javax.xml.bind.annotation.XmlType;
051: import javax.xml.bind.annotation.adapters.XmlAdapter;
052: import javax.xml.bind.helpers.AbstractMarshallerImpl;
053: import javax.xml.namespace.QName;
054: import javax.xml.stream.XMLEventWriter;
055: import javax.xml.stream.XMLOutputFactory;
056: import javax.xml.stream.XMLStreamException;
057: import javax.xml.stream.XMLStreamWriter;
058: import javax.xml.transform.Result;
059: import javax.xml.validation.Schema;
060:
061: import java.io.IOException;
062:
063: import java.util.HashMap;
064:
065: /**
066: * A very basic implementation of Binder.
067: **/
068: public class BinderImpl extends Binder<Node> {
069: private static final L10N L = new L10N(BinderImpl.class);
070:
071: private final JAXBContextImpl _context;
072: /*
073: private Marshaller _marshaller;
074: private Unmarshaller _unmarshaller;*/
075: private Schema _schema;
076: private ValidationEventHandler _validationEventHandler;
077:
078: private final HashMap<Object, Node> _jaxbToXmlMap = new HashMap<Object, Node>();
079: private final HashMap<Node, Object> _xmlToJaxbMap = new HashMap<Node, Object>();
080:
081: BinderImpl(JAXBContextImpl context) {
082: _context = context;
083: _validationEventHandler = _context.DEFAULT_VALIDATION_EVENT_HANDLER;
084: }
085:
086: /*
087: public Marshaller getMarshaller()
088: throws JAXBException
089: {
090: if (_marshaller == null)
091: _marshaller = _context.createMarshaller();
092:
093: return _marshaller;
094: }
095:
096: public Unmarshaller getUnmarshaller()
097: throws JAXBException
098: {
099: if (_unmarshaller == null)
100: _unmarshaller = _context.createUnmarshaller();
101:
102: return _unmarshaller;
103: }*/
104:
105: public ValidationEventHandler getEventHandler()
106: throws JAXBException {
107: return _validationEventHandler;
108: }
109:
110: public void setEventHandler(ValidationEventHandler handler)
111: throws JAXBException {
112: if (handler == null)
113: _validationEventHandler = _context.DEFAULT_VALIDATION_EVENT_HANDLER;
114: else
115: _validationEventHandler = handler;
116: }
117:
118: public Object getProperty(String name) throws PropertyException {
119: if (name == null)
120: throw new IllegalArgumentException(name);
121:
122: if ("jaxb.encoding".equals(name)) {
123: // XXX
124: return null;
125: } else if ("jaxb.formatted.output".equals(name)) {
126: // XXX
127: return null;
128: } else if ("jaxb.schemaLocation".equals(name)) {
129: // XXX
130: return null;
131: } else if ("jaxb.noNamespaceSchemaLocation".equals(name)) {
132: // XXX
133: return null;
134: } else if ("jaxb.fragment".equals(name)) {
135: // XXX
136: return null;
137: } else
138: throw new PropertyException(name);
139: }
140:
141: public void setProperty(String name, Object value)
142: throws PropertyException {
143: if (name == null)
144: throw new IllegalArgumentException(name);
145:
146: if ("jaxb.encoding".equals(name)) { /* XXX */
147: } else if ("jaxb.formatted.output".equals(name)) { /* XXX */
148: } else if ("jaxb.schemaLocation".equals(name)) { /* XXX */
149: } else if ("jaxb.noNamespaceSchemaLocation".equals(name)) { /* XXX */
150: } else if ("jaxb.fragment".equals(name)) { /* XXX */
151: } else
152: throw new PropertyException(name);
153: }
154:
155: public Schema getSchema() {
156: return _schema;
157: }
158:
159: public void setSchema(Schema schema) {
160: _schema = schema;
161: }
162:
163: public Object getJAXBNode(Node node) {
164: if (node == null)
165: throw new IllegalArgumentException(L
166: .l("Node may not be null"));
167:
168: return _xmlToJaxbMap.get(node);
169: }
170:
171: public Node getXMLNode(Object jaxbObject) {
172: if (jaxbObject == null)
173: throw new IllegalArgumentException(L
174: .l("JAXB object may not be null"));
175:
176: if (jaxbObject instanceof JAXBElement)
177: return _jaxbToXmlMap.get(((JAXBElement) jaxbObject)
178: .getValue());
179: else
180: return _jaxbToXmlMap.get(jaxbObject);
181: }
182:
183: public void marshal(Object jaxbObject, Node xmlNode)
184: throws JAXBException {
185: // XXX Schema
186:
187: if (jaxbObject == null)
188: throw new IllegalArgumentException(L
189: .l("JAXB object may not be null"));
190:
191: if (xmlNode == null)
192: throw new IllegalArgumentException(L
193: .l("Node may not be null"));
194:
195: ClassSkeleton skeleton = _context
196: .findSkeletonForObject(jaxbObject);
197:
198: if (skeleton == null)
199: throw new MarshalException(
200: L
201: .l(
202: "Unable to marshal {0}: its type unknown to this JAXBContext",
203: jaxbObject));
204:
205: Document doc = xmlNode.getOwnerDocument();
206:
207: if (xmlNode.getNodeType() == Node.DOCUMENT_NODE)
208: doc = (Document) xmlNode;
209:
210: Node child = doc.createElement("root");
211:
212: try {
213: xmlNode.appendChild(skeleton.bindTo(this , child,
214: jaxbObject, null, null));
215: } catch (IOException e) {
216: throw new JAXBException(e);
217: }
218: }
219:
220: public Object unmarshal(Node xmlNode) throws JAXBException {
221: // XXX Schema
222:
223: if (xmlNode == null)
224: throw new IllegalArgumentException(L
225: .l("Node may not be null"));
226:
227: Node root = xmlNode;
228:
229: if (xmlNode.getNodeType() == Node.DOCUMENT_NODE) {
230: Document doc = (Document) xmlNode;
231: root = doc.getDocumentElement();
232: }
233:
234: QName name = JAXBUtil.qnameFromNode(root);
235:
236: ClassSkeleton skeleton = _context.getRootElement(name);
237:
238: if (skeleton == null)
239: throw new UnmarshalException(L
240: .l("Root element {0} is unknown to this context",
241: name));
242:
243: try {
244: return skeleton
245: .bindFrom(this , null, new NodeIterator(root));
246: } catch (IOException e) {
247: throw new JAXBException(e);
248: }
249: }
250:
251: public <T> JAXBElement<T> unmarshal(Node xmlNode,
252: Class<T> declaredType) throws JAXBException {
253: if (xmlNode == null)
254: throw new IllegalArgumentException(L
255: .l("Node may not be null"));
256:
257: Node root = xmlNode;
258:
259: if (xmlNode.getNodeType() == Node.DOCUMENT_NODE) {
260: Document doc = (Document) xmlNode;
261: root = doc.getDocumentElement();
262: }
263:
264: ClassSkeleton skeleton = _context
265: .findSkeletonForClass(declaredType);
266:
267: if (skeleton == null)
268: throw new UnmarshalException(L
269: .l("Type {0} is unknown to this context",
270: declaredType));
271:
272: try {
273: T value = (T) skeleton.bindFrom(this , null,
274: new NodeIterator(root));
275:
276: QName qname = JAXBUtil.qnameFromNode(root);
277:
278: return new JAXBElement<T>(qname, declaredType, value);
279: } catch (IOException e) {
280: throw new JAXBException(e);
281: }
282: }
283:
284: public Object updateJAXB(Node xmlNode) throws JAXBException {
285: Node root = xmlNode;
286:
287: if (xmlNode.getNodeType() == Node.DOCUMENT_NODE) {
288: Document doc = (Document) xmlNode;
289: root = doc.getDocumentElement();
290: }
291:
292: Object jaxbObject = getJAXBNode(root);
293:
294: if (jaxbObject == null)
295: throw new JAXBException(L.l("Unknown xmlNode"));
296:
297: ClassSkeleton skeleton = _context
298: .findSkeletonForObject(jaxbObject);
299:
300: if (skeleton == null) {
301: // we strip the JAXBElement when we bind objects, so rewrap
302: // the object and try again
303: QName qname = JAXBUtil.qnameFromNode(root);
304:
305: jaxbObject = new JAXBElement(qname, jaxbObject.getClass(),
306: jaxbObject);
307:
308: skeleton = _context.findSkeletonForObject(jaxbObject);
309:
310: if (skeleton == null)
311: throw new UnmarshalException(L.l(
312: "Type {0} is unknown to this context",
313: jaxbObject.getClass()));
314: }
315:
316: try {
317: return skeleton.bindFrom(this , jaxbObject,
318: new NodeIterator(root));
319: } catch (IOException e) {
320: throw new JAXBException(e);
321: }
322: }
323:
324: public Node updateXML(Object jaxbObject) throws JAXBException {
325: return updateXML(jaxbObject, getXMLNode(jaxbObject));
326: }
327:
328: public Node updateXML(Object jaxbObject, Node xmlNode)
329: throws JAXBException {
330: ClassSkeleton skeleton = _context
331: .findSkeletonForObject(jaxbObject);
332:
333: if (skeleton == null)
334: throw new MarshalException(
335: L
336: .l(
337: "Unable to update {0}: its type unknown to this JAXBContext",
338: jaxbObject));
339:
340: try {
341: return skeleton.bindTo(this , xmlNode, jaxbObject, null,
342: null);
343: } catch (IOException e) {
344: throw new JAXBException(e);
345: }
346: }
347:
348: public void bind(Object jaxbObject, Node xmlNode) {
349: if (jaxbObject instanceof JAXBElement)
350: jaxbObject = ((JAXBElement) jaxbObject).getValue();
351:
352: // ensure that old bindings one way or the other are cleaned up
353: Node oldNode = _jaxbToXmlMap.get(jaxbObject);
354:
355: if (xmlNode != oldNode)
356: _xmlToJaxbMap.remove(oldNode);
357: else {
358: Object oldObject = _xmlToJaxbMap.get(xmlNode);
359:
360: if (oldObject != jaxbObject)
361: _jaxbToXmlMap.remove(oldObject);
362: }
363:
364: // insert the new binding
365: _jaxbToXmlMap.put(jaxbObject, xmlNode);
366: _xmlToJaxbMap.put(xmlNode, jaxbObject);
367: }
368:
369: public void invalidate(Node root) {
370: if (root == null)
371: return;
372:
373: remove(root);
374:
375: for (Node node = root.getFirstChild(); node != null; node = node
376: .getNextSibling())
377: invalidate(root);
378: }
379:
380: private void remove(Node root) {
381: if (_xmlToJaxbMap.containsKey(root)) {
382: Object obj = _xmlToJaxbMap.remove(root);
383:
384: if (_jaxbToXmlMap.containsKey(obj))
385: _jaxbToXmlMap.remove(obj);
386: }
387: }
388: }
|