001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.aegis.type.collection;
019:
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Hashtable;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import javax.xml.namespace.QName;
028:
029: import org.apache.cxf.aegis.Context;
030: import org.apache.cxf.aegis.DatabindingException;
031: import org.apache.cxf.aegis.type.Type;
032: import org.apache.cxf.aegis.type.TypeUtil;
033: import org.apache.cxf.aegis.util.NamespaceHelper;
034: import org.apache.cxf.aegis.util.XmlConstants;
035: import org.apache.cxf.aegis.xml.MessageReader;
036: import org.apache.cxf.aegis.xml.MessageWriter;
037: import org.jdom.Attribute;
038: import org.jdom.Element;
039:
040: public class MapType extends Type {
041: private Type keyType;
042: private Type valueType;
043: private QName keyName;
044: private QName valueName;
045: private QName entryName;
046:
047: public MapType(QName schemaType, Type keyType, Type valueType) {
048: super ();
049:
050: this .keyType = keyType;
051: this .valueType = valueType;
052:
053: setSchemaType(schemaType);
054: keyName = new QName(schemaType.getNamespaceURI(), "key");
055: valueName = new QName(schemaType.getNamespaceURI(), "value");
056: entryName = new QName(schemaType.getNamespaceURI(), "entry");
057: }
058:
059: @Override
060: public Object readObject(MessageReader reader, Context context)
061: throws DatabindingException {
062: Map<Object, Object> map = instantiateMap();
063: try {
064: Type kType = getKeyType();
065: Type vType = getValueType();
066:
067: Object key = null;
068: Object value = null;
069:
070: while (reader.hasMoreElementReaders()) {
071: MessageReader entryReader = reader
072: .getNextElementReader();
073:
074: if (entryReader.getName().equals(getEntryName())) {
075: while (entryReader.hasMoreElementReaders()) {
076: MessageReader evReader = entryReader
077: .getNextElementReader();
078:
079: if (evReader.getName().equals(getKeyName())) {
080: key = kType.readObject(evReader, context);
081: } else if (evReader.getName().equals(
082: getValueName())) {
083: value = vType.readObject(evReader, context);
084: } else {
085: readToEnd(evReader);
086: }
087: }
088:
089: map.put(key, value);
090: } else {
091: readToEnd(entryReader);
092: }
093: }
094:
095: return map;
096: } catch (IllegalArgumentException e) {
097: throw new DatabindingException("Illegal argument.", e);
098: }
099: }
100:
101: private void readToEnd(MessageReader childReader) {
102: while (childReader.hasMoreElementReaders()) {
103: readToEnd(childReader.getNextElementReader());
104: }
105: }
106:
107: /**
108: * Creates a map instance. If the type class is a <code>Map</code> or
109: * extends the <code>Map</code> interface a <code>HashMap</code> is
110: * created. Otherwise the map classs (i.e. LinkedHashMap) is instantiated
111: * using the default constructor.
112: *
113: * @return
114: */
115: @SuppressWarnings("unchecked")
116: protected Map<Object, Object> instantiateMap() {
117: Map<Object, Object> map = null;
118:
119: if (getTypeClass().equals(Map.class)) {
120: map = new HashMap<Object, Object>();
121: } else if (getTypeClass().equals(Hashtable.class)) {
122: map = new Hashtable<Object, Object>();
123: } else if (getTypeClass().isInterface()) {
124: map = new HashMap<Object, Object>();
125: } else {
126: try {
127: map = (Map<Object, Object>) getTypeClass()
128: .newInstance();
129: } catch (Exception e) {
130: throw new DatabindingException(
131: "Could not create map implementation: "
132: + getTypeClass().getName(), e);
133: }
134: }
135:
136: return map;
137: }
138:
139: @Override
140: public void writeObject(Object object, MessageWriter writer,
141: Context context) throws DatabindingException {
142: if (object == null) {
143: return;
144: }
145:
146: try {
147: Map map = (Map) object;
148:
149: Type kType = getKeyType();
150: Type vType = getValueType();
151:
152: for (Iterator itr = map.entrySet().iterator(); itr
153: .hasNext();) {
154: Map.Entry entry = (Map.Entry) itr.next();
155:
156: writeEntry(writer, context, kType, vType, entry);
157: }
158: } catch (IllegalArgumentException e) {
159: throw new DatabindingException("Illegal argument.", e);
160: }
161: }
162:
163: private void writeEntry(MessageWriter writer, Context context,
164: Type kType, Type vType, Map.Entry entry)
165: throws DatabindingException {
166: kType = TypeUtil.getWriteType(context, entry.getKey(), kType);
167: vType = TypeUtil.getWriteType(context, entry.getValue(), vType);
168:
169: MessageWriter entryWriter = writer
170: .getElementWriter(getEntryName());
171:
172: MessageWriter keyWriter = entryWriter
173: .getElementWriter(getKeyName());
174: kType.writeObject(entry.getKey(), keyWriter, context);
175: keyWriter.close();
176:
177: MessageWriter valueWriter = entryWriter
178: .getElementWriter(getValueName());
179: vType.writeObject(entry.getValue(), valueWriter, context);
180: valueWriter.close();
181:
182: entryWriter.close();
183: }
184:
185: @Override
186: public void writeSchema(Element root) {
187: Element complex = new Element("complexType",
188: XmlConstants.XSD_PREFIX, XmlConstants.XSD);
189: complex.setAttribute(new Attribute("name", getSchemaType()
190: .getLocalPart()));
191: root.addContent(complex);
192:
193: Element seq = new Element("sequence", XmlConstants.XSD_PREFIX,
194: XmlConstants.XSD);
195: complex.addContent(seq);
196:
197: Type kType = getKeyType();
198: Type vType = getValueType();
199:
200: Element element = new Element("element",
201: XmlConstants.XSD_PREFIX, XmlConstants.XSD);
202: seq.addContent(element);
203:
204: element.setAttribute(new Attribute("name", getEntryName()
205: .getLocalPart()));
206: element.setAttribute(new Attribute("minOccurs", "0"));
207: element.setAttribute(new Attribute("maxOccurs", "unbounded"));
208:
209: Element evComplex = new Element("complexType",
210: XmlConstants.XSD_PREFIX, XmlConstants.XSD);
211: element.addContent(evComplex);
212:
213: Element evseq = new Element("sequence",
214: XmlConstants.XSD_PREFIX, XmlConstants.XSD);
215: evComplex.addContent(evseq);
216:
217: createElement(root, evseq, getKeyName(), kType);
218: createElement(root, evseq, getValueName(), vType);
219: }
220:
221: /**
222: * Creates a element in a sequence for the key type and the value type.
223: */
224: private void createElement(Element root, Element seq, QName name,
225: Type type) {
226: Element element = new Element("element",
227: XmlConstants.XSD_PREFIX, XmlConstants.XSD);
228: seq.addContent(element);
229:
230: String prefix = NamespaceHelper.getUniquePrefix((Element) root,
231: type.getSchemaType().getNamespaceURI());
232: String typeName = prefix + ":"
233: + type.getSchemaType().getLocalPart();
234:
235: element
236: .setAttribute(new Attribute("name", name.getLocalPart()));
237: element.setAttribute(new Attribute("type", typeName));
238:
239: element.setAttribute(new Attribute("minOccurs", "0"));
240: element.setAttribute(new Attribute("maxOccurs", "1"));
241: }
242:
243: @Override
244: public Set<Type> getDependencies() {
245: Set<Type> deps = new HashSet<Type>();
246: deps.add(getKeyType());
247: deps.add(getValueType());
248: return deps;
249: }
250:
251: public Type getKeyType() {
252: return keyType;
253: }
254:
255: public Type getValueType() {
256: return valueType;
257: }
258:
259: @Override
260: public boolean isComplex() {
261: return true;
262: }
263:
264: public QName getKeyName() {
265: return keyName;
266: }
267:
268: public void setKeyName(QName keyName) {
269: this .keyName = keyName;
270: }
271:
272: public QName getValueName() {
273: return valueName;
274: }
275:
276: public void setValueName(QName valueName) {
277: this .valueName = valueName;
278: }
279:
280: public QName getEntryName() {
281: return entryName;
282: }
283:
284: public void setEntryName(QName entryName) {
285: this.entryName = entryName;
286: }
287: }
|