View Javadoc

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      private String postOgnl;
38      
39      /***
40       * Uses an OGNL expression to find an array.  It then puts each
41       * array object in as the key (see <code>getKey()</code> for retrieval
42       * when write()'ing in the child type.
43       * 
44       * @see org.codehaus.xfire.aegis.type.Type#write(org.dom4j.Element, java.util.Map)
45       */
46  	public void write(Element element, Map context) throws XFireFault
47  	{
48  		try
49          {   
50              Object value = null;
51              try
52              {
53                  value =  Ognl.getValue(getOgnl(), context, (Object) null);
54              }
55              catch ( NullPointerException e )
56              {
57                  return;
58              }
59              
60              if ( value == null )
61              {
62              	return;
63              }
64              
65              Element typeEl = element.addElement(getQName());
66  
67              if ( value instanceof Object[] )
68              {
69                  Object[] children = (Object[]) value;
70                  
71                  for (int i = 0; i < children.length; i++)
72                  {
73                      context.put( getKey(), children[i] );
74                      
75                      Type type = getChildType();
76                      type.write(typeEl, context);
77                  }
78              }
79              else if ( value instanceof Collection )
80              {
81                  Collection children = (Collection) value;
82                  for ( Iterator itr = children.iterator(); itr.hasNext(); )
83                  {
84                      context.put( getKey(), itr.next());
85                      
86                      Type type = getChildType();
87                      type.write(typeEl, context);
88                  }
89              }
90              
91              context.put( getKey(), null );
92          }
93          catch (OgnlException e)
94          {
95              throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
96          }
97  	}
98  
99      /***
100      * Semantics are still under development, but here is how it works
101      * currently:
102      * <p>
103      * An ArrayList is built for the elements of the array.
104      * The number of elements in the array are put in as "key.length". The current
105      * index of the array is put in as "key.index". Each child is put in the 
106      * array via the OGNL expression (<code>getOgnl()</code>).  Finally,
107      * the array is put in the context as "key".  (Where key in all of this
108      * refers to the key you specify.)
109      * 
110      * @see org.codehaus.xfire.aegis.type.Type#read(org.dom4j.Element, java.util.Map)
111      */
112     public void read( Element element, Map context )
113         throws XFireFault 
114     {
115         read( element, 0, context );
116     }
117     
118     /***
119      * @see org.codehaus.xfire.aegis.type.Type#read(org.dom4j.Element, int, java.util.Map)
120      */
121     public void read(Element root, int occurrence, Map context) throws XFireFault
122     {
123         List elements = root.elements( getQName() );
124         if ( elements.size() <= occurrence )
125             return;
126         
127         Element element = (Element) elements.get(occurrence);
128 
129         int size = element.elements().size();
130         
131         List array = new ArrayList(size);
132         context.put( getKey() + ".length", new Integer(size) );
133 
134         for ( int i = 0; i < size; i++ )
135         {
136             context.put( getKey() + ".index", new Integer(i) );
137 
138             getChildType().read(element, i, context);
139             
140             try
141             {
142                 Object value = Ognl.getValue(getOgnl(), context, (Object) null);
143                 array.add(value);
144             }
145             catch (OgnlException e)
146             {
147                 throw new XFireFault("Couldn't process message.", e, XFireFault.SENDER);
148             }
149             
150             i++;
151         }
152         
153         if ( array.size() > 0 )
154         {
155             context.put( getKey(), array );
156             
157             if ( getPostOgnl() != null )
158             {
159                 try
160                 {
161                     Ognl.getValue( getPostOgnl(), context, array );
162                 }
163                 catch (OgnlException e)
164                 {
165                     throw new XFireFault( "Couldn't process message.", e, XFireFault.SENDER );
166                 }
167             }
168         }
169 	}
170 
171     public boolean isComplex()
172     {
173         return true;
174     }
175     
176     public Set getDependencies()
177     {
178         Set deps = new HashSet();
179         
180         deps.add( getChildType() );
181         
182         return deps;
183     }
184     
185     public Type getChildType()
186     {
187         return childType;
188     }
189     
190     public void setChildType(Type childType)
191     {
192         this.childType = childType;
193     }
194     
195 	public String getKey()
196 	{
197 		return key;
198 	}
199 
200 	public void setKey(String key)
201 	{
202 		this.key = key;
203     }
204 
205     public String getPostOgnl()
206     {
207         return postOgnl;
208     }
209     
210     public void setPostOgnl(String postOgnl)
211     {
212         this.postOgnl = postOgnl;
213     }
214     
215 	/***
216 	 * @see org.codehaus.xfire.aegis.type.Type#writeSchema(org.dom4j.Element)
217 	 */
218 	public void writeSchema(Element root)
219 	{
220         Namespace xsdNs = root.getNamespaceForURI(SOAPConstants.XSD);
221         Namespace arrayNs = root.getNamespaceForURI( getSchemaType().getNamespaceURI() );
222         
223         org.dom4j.QName elementQ = new org.dom4j.QName( "element", xsdNs );
224         Element concreteEl = root.addElement( elementQ );
225         concreteEl.addAttribute("name", getName());
226         //concreteEl.addAttribute("type", arrayNs.getPrefix() + ":" + getSchemaType().getName());
227         
228         org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
229 
230 		Element complex = concreteEl.addElement(complexQ);
231         //complex.addAttribute("name", getName());
232         
233 		org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs);
234 		Element seq = complex.addElement(seqQ);
235 
236         // Write out the array type.
237 		Type type = getChildType();
238         
239         Element element = seq.addElement(elementQ);
240         Namespace typeNS = root.getNamespaceForURI( type.getSchemaType().getNamespaceURI() );
241         
242         if ( type.isComplex() )
243         {
244             element.addAttribute("ref", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
245         }
246         else
247         {
248             element.addAttribute("name", type.getName());
249             element.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName());
250             element.addAttribute("nillable", "true");
251         }
252 		
253 		// TODO: Add config support for nillable
254 		element.addAttribute("minOccurs", "0");
255         element.addAttribute("maxOccurs", "unbounded");
256 	}
257 
258 	/***
259 	 * @see org.codehaus.xfire.aegis.type.Type#configure(org.dom4j.Element)
260 	 */
261 	public void configure(Element configuration,
262                           AegisService service,
263                           TypeRegistry reg)
264 	{
265 		setName(configuration.attributeValue("name"));
266         setOgnl(configuration.attributeValue("ognl"));
267         setPostOgnl(configuration.attributeValue("postOgnl"));
268         setKey(configuration.attributeValue("key"));
269         setDocumentation(configuration.getTextTrim());
270         
271         setQName(QName.get(getName(), service.getDefaultNamespace()));
272 
273 		Attribute xsdAt = configuration.attribute("schemaType");
274 		if (xsdAt != null)
275 		{
276 			setSchemaType(null);
277 		}
278 		else
279 		{
280 			Namespace ns = NamespaceHelper.getNamespace(configuration, service
281 					.getDefaultNamespace());
282 			setSchemaType(new QName(getName(), ns));
283 		}
284 
285 		if ( configuration.elements().size() > 1 )
286         {
287             throw new XFireRuntimeException("Only one array child type allowed.");
288         }
289         
290 		Element childTypeEl = (Element) configuration.elements().get(0);
291 		QName typeQ = QName.get(childTypeEl.getName(), service.getSoapVersion());
292 
293 		Type type = reg.createType(typeQ);
294 		type.configure(childTypeEl, service, reg);
295 
296 		setChildType(type);
297 	}
298 
299 }