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