001: /*
002: Copyright (c) 2003-2004, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.extras;
030:
031: import java.io.OutputStream;
032: import java.io.Writer;
033:
034: import org.jibx.runtime.BindingDirectory;
035: import org.jibx.runtime.IBindingFactory;
036: import org.jibx.runtime.IMarshallable;
037: import org.jibx.runtime.IUnmarshallingContext;
038: import org.jibx.runtime.JiBXException;
039: import org.jibx.runtime.impl.MarshallingContext;
040: import org.jibx.runtime.impl.UnmarshallingContext;
041:
042: /**
043: * Binding selector that supports versioned XML documents. This looks for a
044: * <i>version</i> attribute on the root element of the document, and selects the
045: * mapping to be used for unmarshalling based on the value. It also supports
046: * selecting the version for marshalling based on a supplied version argument
047: * value.
048: *
049: * @author Dennis M. Sosnoski
050: * @version 1.0
051: */
052:
053: public class BindingSelector {
054: /** URI of version selection attribute. */
055: private final String m_attributeUri;
056:
057: /** Name of version selection attribute. */
058: private final String m_attributeName;
059:
060: /** Array of version names. */
061: private final String[] m_versionTexts;
062:
063: /** Array of bindings corresponding to versions. */
064: private final String[] m_versionBindings;
065:
066: /** Basic unmarshalling context used to determine document version. */
067: private final UnmarshallingContext m_context;
068:
069: /** Stream for marshalling output. */
070: private OutputStream m_outputStream;
071:
072: /** Encoding for output stream. */
073: private String m_outputEncoding;
074:
075: /** Output writer for marshalling. */
076: private Writer m_outputWriter;
077:
078: /** Indentation for marshalling. */
079: private int m_outputIndent;
080:
081: /**
082: * Constructor.
083: *
084: * @param uri version selection attribute URI (<code>null</code> if none)
085: * @param name version selection attribute name
086: * @param versions array of version texts (first is default)
087: * @param bindings array of binding names corresponding to versions
088: */
089:
090: public BindingSelector(String uri, String name, String[] versions,
091: String[] bindings) {
092: m_attributeUri = uri;
093: m_attributeName = name;
094: m_versionTexts = versions;
095: m_versionBindings = bindings;
096: m_context = new UnmarshallingContext();
097: m_outputIndent = -1;
098: }
099:
100: /**
101: * Get initial unmarshalling context. This gives access to the unmarshalling
102: * context used before the specific version is determined. The document
103: * information must be set for this context before calling {@link
104: * #unmarshalVersioned}.
105: *
106: * @return initial unmarshalling context
107: */
108:
109: public IUnmarshallingContext getContext() {
110: return m_context;
111: }
112:
113: /**
114: * Set output stream and encoding.
115: *
116: * @param outs stream for document data output
117: * @param enc document output encoding, or <code>null</code> for default
118: */
119:
120: public void setOutput(OutputStream outs, String enc) {
121: m_outputStream = outs;
122: m_outputEncoding = enc;
123: }
124:
125: /**
126: * Set output writer.
127: *
128: * @param outw writer for document data output
129: */
130:
131: public void setOutput(Writer outw) {
132: m_outputWriter = outw;
133: }
134:
135: /**
136: * Set nesting indent spaces.
137: *
138: * @param indent number of spaces to indent per level, or disable
139: * indentation if negative
140: */
141:
142: public void setIndent(int indent) {
143: m_outputIndent = indent;
144: }
145:
146: /**
147: * Marshal according to supplied version.
148: *
149: * @param obj root object to be marshalled
150: * @param version identifier for version to be used in marshalling
151: * @throws JiBXException if error in marshalling
152: */
153:
154: public void marshalVersioned(Object obj, String version)
155: throws JiBXException {
156:
157: // look up version in defined list
158: String match = (version == null) ? m_versionTexts[0] : version;
159: for (int i = 0; i < m_versionTexts.length; i++) {
160: if (match.equals(m_versionTexts[i])) {
161:
162: // version found, create marshaller for the associated binding
163: IBindingFactory fact = BindingDirectory.getFactory(
164: m_versionBindings[i], obj.getClass());
165: MarshallingContext context = (MarshallingContext) fact
166: .createMarshallingContext();
167:
168: // configure marshaller for writing document
169: context.setIndent(m_outputIndent);
170: if (m_outputWriter == null) {
171: if (m_outputStream == null) {
172: throw new JiBXException("Output not configured");
173: } else {
174: context.setOutput(m_outputStream,
175: m_outputEncoding);
176: }
177: } else {
178: context.setOutput(m_outputWriter);
179: }
180:
181: // output object as document
182: context.startDocument(m_outputEncoding, null);
183: ((IMarshallable) obj).marshal(context);
184: context.endDocument();
185: return;
186:
187: }
188: }
189:
190: // error if unknown version in document
191: throw new JiBXException("Unrecognized document version "
192: + version);
193: }
194:
195: /**
196: * Unmarshal according to document version.
197: *
198: * @param clas expected class mapped to root element of document (used only
199: * to look up the binding)
200: * @return root object unmarshalled from document
201: * @throws JiBXException if error in unmarshalling
202: */
203:
204: public Object unmarshalVersioned(Class clas) throws JiBXException {
205:
206: // get the version attribute value (using first value as default)
207: m_context.toStart();
208: String version = m_context.attributeText(m_attributeUri,
209: m_attributeName, m_versionTexts[0]);
210:
211: // look up version in defined list
212: for (int i = 0; i < m_versionTexts.length; i++) {
213: if (version.equals(m_versionTexts[i])) {
214:
215: // version found, create unmarshaller for the associated binding
216: IBindingFactory fact = BindingDirectory.getFactory(
217: m_versionBindings[i], clas);
218: UnmarshallingContext context = (UnmarshallingContext) fact
219: .createUnmarshallingContext();
220:
221: // return object unmarshalled using binding for document version
222: context.setFromContext(m_context);
223: return context.unmarshalElement();
224:
225: }
226: }
227:
228: // error if unknown version in document
229: throw new JiBXException("Unrecognized document version "
230: + version);
231: }
232: }
|