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      /***
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         //concreteEl.addAttribute("type", arrayNs.getPrefix() + ":" + getSchemaType().getName());
180         
181         org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
182 
183 		Element complex = concreteEl.addElement(complexQ);
184         //complex.addAttribute("name", getName());
185         
186 		org.dom4j.QName seqQ = new org.dom4j.QName("sequence", xsdNs);
187 		Element seq = complex.addElement(seqQ);
188 
189         // Write out the array type.
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 		// TODO: Add config support for nillable
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 }