001: /*
002: Copyright (c) 2005, 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.runtime;
030:
031: import java.util.ArrayList;
032:
033: import org.jibx.runtime.impl.MarshallingContext;
034: import org.jibx.runtime.impl.UnmarshallingContext;
035:
036: /**
037: * <p>Representation of a qualified name. This includes the JiBX
038: * serializer/deserializer methods for the representation. It assumes that the
039: * actual namespace declarations are being handled separately for
040: * marshalling</p>
041: *
042: * <p>Note that this implementation treats only the namespace and local name as
043: * significant for purposes of comparing values. The prefix is held only as a
044: * convenience, and the actual prefix used when writing a value may differ from
045: * the prefix defined by the instance.</p>
046: *
047: * @author Dennis M. Sosnoski
048: */
049: public class QName {
050: /** Namespace URI. */
051: private String m_uri;
052:
053: /** Namespace prefix. */
054: private String m_prefix;
055:
056: /** Local name. */
057: private String m_name;
058:
059: /**
060: * Constructor from full set of components.
061: *
062: * @param uri namespace uri, <code>null</code> if no-namespace namespace
063: * @param prefix namespace prefix, <code>null</code> if unspecified, empty
064: * string if default namespace
065: * @param name local name
066: */
067: public QName(String uri, String prefix, String name) {
068: m_uri = uri;
069: m_prefix = prefix;
070: m_name = name;
071: }
072:
073: /**
074: * Constructor from namespace and local name. This constructor is provided
075: * as a convenience for when the actual prefix used for a namespace is
076: * irrelevant.
077: *
078: * @param uri namespace uri, <code>null</code> if no-namespace namespace
079: * @param name
080: */
081: public QName(String uri, String name) {
082: this (uri, null, name);
083: }
084:
085: /**
086: * Constructor from local name only. This constructor is provided as a
087: * convenience for names in the no-namespace namespace.
088: *
089: * @param name
090: */
091: public QName(String name) {
092: this (null, null, name);
093: }
094:
095: //
096: // Overrides of base class methods
097:
098: /* (non-Javadoc)
099: * @see java.lang.Object#equals(java.lang.Object)
100: */
101: public boolean equals(Object obj) {
102: if (obj instanceof QName) {
103: QName qname = (QName) obj;
104: if (m_name.equals(qname.getName())) {
105: if (m_uri == null) {
106: return qname.getUri() == null;
107: } else {
108: return m_uri.equals(qname.getUri());
109: }
110: }
111: }
112: return false;
113: }
114:
115: /* (non-Javadoc)
116: * @see java.lang.Object#hashCode()
117: */
118: public int hashCode() {
119: return (m_uri == null ? 0 : m_uri.hashCode())
120: + m_name.hashCode();
121: }
122:
123: /* (non-Javadoc)
124: * @see java.lang.Object#toString()
125: */
126: public String toString() {
127: if (m_uri == null) {
128: return m_name;
129: } else {
130: return "{" + m_uri + "}:" + m_name;
131: }
132: }
133:
134: //
135: // Access methods
136:
137: /**
138: * Get local name.
139: *
140: * @return name
141: */
142: public String getName() {
143: return m_name;
144: }
145:
146: /**
147: * Set local name.
148: *
149: * @param name name
150: */
151: public void setName(String name) {
152: m_name = name;
153: }
154:
155: /**
156: * Get namespace prefix.
157: *
158: * @return prefix, <code>null</code> if unspecified, empty string if default
159: * namespace
160: */
161: public String getPrefix() {
162: return m_prefix;
163: }
164:
165: /**
166: * Set namespace prefix.
167: *
168: * @param prefix prefix, <code>null</code> if unspecified, empty string if
169: * default namespace
170: */
171: public void setPrefix(String prefix) {
172: m_prefix = prefix;
173: }
174:
175: /**
176: * Get namespace URI.
177: *
178: * @return uri namespace uri, <code>null</code> if no-namespace namespace
179: */
180: public String getUri() {
181: return m_uri;
182: }
183:
184: /**
185: * Set namespace URI.
186: *
187: * @param uri namespace uri, <code>null</code> if no-namespace namespace
188: */
189: public void setUri(String uri) {
190: m_uri = uri;
191: }
192:
193: //
194: // JiBX conversion methods
195:
196: /**
197: * JiBX deserializer method. This is intended for use as a deserializer for
198: * instances of the class.
199: *
200: * @param text value text
201: * @param ictx unmarshalling context
202: * @return created class instance
203: * @throws JiBXException on error in unmarshalling
204: */
205: public static QName deserialize(String text,
206: IUnmarshallingContext ictx) throws JiBXException {
207: if (text == null) {
208: return null;
209: } else {
210:
211: // check for prefix used in text representation
212: int split = text.indexOf(':');
213: if (split > 0) {
214:
215: // strip off prefix
216: String prefix = text.substring(0, split);
217: text = text.substring(split + 1);
218:
219: // look up the namespace URI associated with the prefix
220: String uri = ((UnmarshallingContext) ictx)
221: .getNamespaceUri(prefix);
222: if (uri == null) {
223: throw new JiBXException("Undefined prefix "
224: + prefix);
225: } else {
226:
227: // create an instance of class to hold all components
228: return new QName(uri, prefix, text);
229:
230: }
231:
232: } else {
233:
234: // create it using the default namespace URI
235: String uri = ((UnmarshallingContext) ictx)
236: .getNamespaceUri(null);
237: if (uri != null && uri.length() == 0) {
238: uri = null;
239: }
240: return new QName(uri, "", text);
241: }
242: }
243: }
244:
245: /**
246: * JiBX serializer method. This is intended for use as a serializer for
247: * instances of the class. The namespace must be active in the output
248: * document at the point where this is called.
249: *
250: * @param qname value to be serialized
251: * @param ictx unmarshalling context
252: * @return created class instance
253: * @throws JiBXException on error in marshalling
254: */
255: public static String serialize(QName qname, IMarshallingContext ictx)
256: throws JiBXException {
257: if (qname == null) {
258: return null;
259: } else {
260:
261: // check for specified prefix
262: IXMLWriter ixw = ((MarshallingContext) ictx).getXmlWriter();
263: int index = -1;
264: String uri = qname.getUri();
265: if (qname.getPrefix() != null) {
266:
267: // see if prefix already defined in document with correct URI
268: int tryidx = ixw.getPrefixIndex(qname.getPrefix());
269: if (tryidx >= 0
270: && uri.equals(ixw.getNamespaceUri(tryidx))) {
271: index = tryidx;
272: }
273: }
274:
275: // check if need to lookup prefix for namespace
276: if (index < 0) {
277:
278: // prefix not defined, find the namespace index in binding
279: if (uri == null) {
280: uri = "";
281: }
282: String[] nss = ixw.getNamespaces();
283: for (int i = 0; i < nss.length; i++) {
284: if (nss[i].equals(uri)) {
285: index = i;
286: break;
287: }
288: }
289: if (index < 0) {
290:
291: // namespace not in binding, check extensions
292: String[][] nsss = ixw.getExtensionNamespaces();
293: if (nsss != null) {
294: int base = nss.length;
295: outer: for (int i = 0; i < nsss.length; i++) {
296: nss = nsss[i];
297: for (int j = 0; j < nss.length; j++) {
298: if (nss[j].equals(uri)) {
299: index = base + j;
300: break outer;
301: }
302: }
303: base += nss.length;
304: }
305: }
306: }
307: }
308:
309: // check if prefix is alread defined in document with correct URI
310: if (index >= 0) {
311:
312: // get prefix defined for namespace
313: String prefix = ixw.getNamespacePrefix(index);
314: if (prefix == null) {
315: throw new JiBXException("Namespace URI "
316: + qname.getUri()
317: + " cannot be used since it is not active");
318: } else if (prefix.length() > 0) {
319: return prefix + ':' + qname.getName();
320: } else {
321: return qname.getName();
322: }
323:
324: } else {
325: throw new JiBXException("Unknown namespace URI "
326: + qname.m_uri);
327: }
328: }
329: }
330:
331: /**
332: * JiBX deserializer method. This is intended for use as a deserializer for
333: * a list made up of instances of the class.
334: *
335: * @param text value text
336: * @param ictx unmarshalling context
337: * @return array of instances
338: * @throws JiBXException on error in marshalling
339: */
340: public static QName[] deserializeList(String text,
341: final IUnmarshallingContext ictx) throws JiBXException {
342:
343: // use basic qualified name deserializer to handle items
344: IListItemDeserializer ldser = new IListItemDeserializer() {
345: public Object deserialize(String text) throws JiBXException {
346: return QName.deserialize(text, ictx);
347: }
348: };
349: ArrayList list = Utility.deserializeList(text, ldser);
350: if (list == null) {
351: return null;
352: } else {
353: return (QName[]) list.toArray(new QName[list.size()]);
354: }
355: }
356:
357: /**
358: * JiBX serializer method. This is intended for use as a serializer for a
359: * list made up of instances of the class. The namespace must be active in
360: * the output document at the point where this is called.
361: *
362: * @param qnames array of names to be serialized
363: * @param ictx unmarshalling context
364: * @return generated text
365: * @throws JiBXException on error in marshalling
366: */
367: public static String serializeList(QName[] qnames,
368: IMarshallingContext ictx) throws JiBXException {
369: StringBuffer buff = new StringBuffer();
370: for (int i = 0; i < qnames.length; i++) {
371: QName qname = qnames[i];
372: if (qname != null) {
373: if (buff.length() > 0) {
374: buff.append(' ');
375: }
376: buff.append(serialize(qname, ictx));
377: }
378: }
379: return buff.toString();
380: }
381: }
|