1 package org.codehaus.xfire.aegis.type;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashSet;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 import ognl.Ognl;
12 import ognl.OgnlException;
13
14 import org.codehaus.xfire.SOAPConstants;
15 import org.codehaus.xfire.XFireRuntimeException;
16 import org.codehaus.xfire.aegis.AegisService;
17 import org.codehaus.xfire.aegis.mapping.TypeRegistry;
18 import org.codehaus.xfire.fault.XFireFault;
19 import org.codehaus.xfire.util.NamespaceHelper;
20 import org.dom4j.Attribute;
21 import org.dom4j.Element;
22 import org.dom4j.Namespace;
23 import org.dom4j.QName;
24
25 /***
26 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse </a>
27 */
28 public class ArrayType
29 extends Type
30 {
31 private String key;
32
33 private String arrayClass;
34
35 private Type childType;
36
37 /***
38 * Uses an OGNL expression to find an array. It then puts each
39 * array object in as the key (see <code>getKey()</code> for retrieval
40 * when write()'ing in the child type.
41 *
42 * @see org.codehaus.xfire.aegis.type.Type#write(org.dom4j.Element, java.util.Map)
43 */
44 public void write(Element element, Map context) throws XFireFault
45 {
46 Element typeEl = element.addElement(getQName());
47
48 try
49 {
50 Object value = Ognl.getValue(getOgnl(), context, (Object) null);
51
52 if ( value == null )
53 {
54 return;
55 }
56
57 if ( value instanceof Object[] )
58 {
59 Object[] children = (Object[]) value;
60
61 for (int i = 0; i < children.length; i++)
62 {
63 context.put( getKey(), children[i] );
64
65 Type type = getChildType();
66 type.write(typeEl, context);
67 }
68 }
69 else if ( value instanceof Collection )
70 {
71 Collection children = (Collection) value;
72 for ( Iterator itr = children.iterator(); itr.hasNext(); )
73 {
74 context.put( getKey(), itr.next());
75
76 Type type = getChildType();
77 type.write(typeEl, context);
78 }
79 }
80
81 context.put( getKey(), null );
82 }
83 catch (OgnlException e)
84 {
85 throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
86 }
87 }
88
89 /***
90 * Semantics are still under development, but here is how it works
91 * currently:
92 * <p>
93 * An ArrayList is built for the elements of the array.
94 * The number of elements in the array are put in as "key.length". The current
95 * index of the array is put in as "key.index". Each child is put in the
96 * array via the OGNL expression (<code>getOgnl()</code>). Finally,
97 * the array is put in the context as "key". (Where key in all of this
98 * refers to the key you specify.)
99 *
100 * @see org.codehaus.xfire.aegis.type.Type#read(org.dom4j.Element, java.util.Map)
101 */
102 public void read(Element element, Map context) throws XFireFault
103 {
104 List array = new ArrayList();
105 List elements = element.elements();
106
107 context.put( getKey() + ".length", new Integer(elements.size()) );
108
109 int i = 0;
110 for (Iterator itr = elements.iterator(); itr.hasNext();)
111 {
112 context.put( getKey() + ".index", new Integer(i) );
113 Element arrayEl = (Element) itr.next();
114
115 getChildType().read(arrayEl, context);
116
117 try
118 {
119 Object value = Ognl.getValue(getOgnl(), context, (Object) null);
120
121 array.add(value);
122 }
123 catch (OgnlException e)
124 {
125 throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
126 }
127
128 i++;
129 }
130
131 context.put( getKey(), array );
132 }
133
134 public boolean isComplex()
135 {
136 return true;
137 }
138
139 public Set getDependencies()
140 {
141 Set deps = new HashSet();
142
143 deps.add( getChildType() );
144
145 return deps;
146 }
147
148 public Type getChildType()
149 {
150 return childType;
151 }
152
153 public void setChildType(Type childType)
154 {
155 this.childType = childType;
156 }
157
158 public String getKey()
159 {
160 return key;
161 }
162
163 public void setKey(String key)
164 {
165 this.key = key;
166 }
167
168 /***
169 * @see org.codehaus.xfire.aegis.type.Type#writeSchema(org.dom4j.Element)
170 */
171 public void writeSchema(Element root)
172 {
173 Namespace xsdNs = root.getNamespaceForURI(SOAPConstants.XSD);
174 Namespace arrayNs = root.getNamespaceForURI( getSchemaType().getNamespaceURI() );
175
176 org.dom4j.QName elementQ = new org.dom4j.QName( "element", xsdNs );
177 Element concreteEl = root.addElement( elementQ );
178 concreteEl.addAttribute("name", getName());
179
180
181 org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
182
183 Element complex = concreteEl.addElement(complexQ);
184
185
186 org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs);
187 Element seq = complex.addElement(seqQ);
188
189
190 Type type = getChildType();
191
192 Element element = seq.addElement(elementQ);
193 Namespace typeNS = root.getNamespaceForURI( type.getSchemaType().getNamespaceURI() );
194
195 if ( type.isComplex() )
196 {
197 element.addAttribute("ref", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
198 }
199 else
200 {
201 element.addAttribute("name", type.getName());
202 element.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
203 element.addAttribute("nillable", "true");
204 }
205
206
207 element.addAttribute("minOccurs", "0");
208 element.addAttribute("maxOccurs", "unbounded");
209 }
210
211 /***
212 * @see org.codehaus.xfire.aegis.type.Type#configure(org.dom4j.Element)
213 */
214 public void configure(Element configuration,
215 AegisService service,
216 TypeRegistry reg)
217 {
218 setName(configuration.attributeValue("name"));
219 setOgnl(configuration.attributeValue("ognl"));
220 setKey(configuration.attributeValue("key"));
221 setDocumentation( configuration.getTextTrim() );
222
223 setQName(QName.get(getName(), service.getDefaultNamespace()));
224
225 Attribute xsdAt = configuration.attribute("schemaType");
226 if (xsdAt != null)
227 {
228 setSchemaType(null);
229 }
230 else
231 {
232 Namespace ns = NamespaceHelper.getNamespace(configuration, service
233 .getDefaultNamespace());
234 setSchemaType(new QName(getName(), ns));
235 }
236
237 if ( configuration.elements().size() > 1 )
238 {
239 throw new XFireRuntimeException("Only one array child type allowed.");
240 }
241
242 Element childTypeEl = (Element) configuration.elements().get(0);
243 QName typeQ = QName.get(childTypeEl.getName(), service.getSoapVersion());
244
245 Type type = reg.createType(typeQ);
246 type.configure(childTypeEl, service, reg);
247
248 setChildType(type);
249 }
250
251 }