1 package org.codehaus.xfire.aegis;
2
3 import java.util.HashMap;
4 import java.util.Iterator;
5 import java.util.Map;
6
7 import javax.xml.namespace.QName;
8 import javax.xml.stream.XMLStreamReader;
9 import javax.xml.stream.XMLStreamWriter;
10
11 import org.codehaus.xfire.MessageContext;
12 import org.codehaus.xfire.XFireRuntimeException;
13 import org.codehaus.xfire.aegis.stax.ElementReader;
14 import org.codehaus.xfire.aegis.stax.ElementWriter;
15 import org.codehaus.xfire.aegis.type.DefaultTypeMappingRegistry;
16 import org.codehaus.xfire.aegis.type.Type;
17 import org.codehaus.xfire.aegis.type.TypeMapping;
18 import org.codehaus.xfire.aegis.type.TypeMappingRegistry;
19 import org.codehaus.xfire.aegis.yom.YOMReader;
20 import org.codehaus.xfire.aegis.yom.YOMWriter;
21 import org.codehaus.xfire.fault.XFireFault;
22 import org.codehaus.xfire.service.MessageHeaderInfo;
23 import org.codehaus.xfire.service.MessagePartContainer;
24 import org.codehaus.xfire.service.MessagePartInfo;
25 import org.codehaus.xfire.service.OperationInfo;
26 import org.codehaus.xfire.service.Service;
27 import org.codehaus.xfire.service.binding.AbstractBinding;
28 import org.codehaus.xfire.service.binding.BindingProvider;
29 import org.codehaus.xfire.soap.SoapConstants;
30 import org.codehaus.yom.Element;
31
32 /***
33 * A BindingProvider for the Aegis type system.
34 *
35 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
36 */
37 public class AegisBindingProvider
38 implements BindingProvider
39 {
40 public static final String TYPE_MAPPING_KEY = "type.mapping";
41 public static final String ENCODING_URI_KEY = "type.encodingUri";
42
43 private TypeMappingRegistry registry;
44
45 private Map part2type = new HashMap();
46
47 public AegisBindingProvider()
48 {
49 this(new DefaultTypeMappingRegistry(true));
50 }
51
52 public AegisBindingProvider(TypeMappingRegistry registry)
53 {
54 this.registry = registry;
55 }
56
57 /***
58 * Creates a type mapping for this class and registers it with the TypeMappingRegistry. This needs to be called
59 * before initializeOperations().
60 */
61 public void initialize(Service endpoint)
62 {
63 for (Iterator itr = endpoint.getServiceInfo().getOperations().iterator(); itr.hasNext();)
64 {
65 OperationInfo opInfo = (OperationInfo) itr.next();
66 try
67 {
68 initializeMessage(endpoint, opInfo.getInputMessage());
69 }
70 catch(XFireRuntimeException e)
71 {
72 e.prepend("Error initializing parameters for method " + opInfo.getMethod());
73 throw e;
74 }
75 try
76 {
77 initializeMessage(endpoint, opInfo.getOutputMessage());
78 }
79 catch(XFireRuntimeException e)
80 {
81 e.prepend("Error initializing return value for method " + opInfo.getMethod());
82 throw e;
83 }
84 }
85 }
86
87 protected void initializeMessage(Service service, MessagePartContainer container)
88 {
89 for (Iterator itr = container.getMessageHeaders().iterator(); itr.hasNext();)
90 {
91 MessageHeaderInfo header = (MessageHeaderInfo) itr.next();
92
93 header.setSchemaType(getParameterType(getTypeMapping(service), header));
94 }
95
96 for (Iterator itr = container.getMessageParts().iterator(); itr.hasNext();)
97 {
98 MessagePartInfo part = (MessagePartInfo) itr.next();
99
100 part.setSchemaType(getParameterType(getTypeMapping(service), part));
101 }
102 }
103
104 public Object readParameter(MessagePartInfo p, XMLStreamReader xsr, MessageContext context)
105 throws XFireFault
106 {
107 Type type = (Type) p.getSchemaType();
108
109 MessageReader reader = new ElementReader(xsr);
110
111 return type.readObject(reader, context);
112 }
113
114 public void writeParameter(MessagePartInfo p,
115 XMLStreamWriter writer,
116 MessageContext context,
117 Object value)
118 throws XFireFault
119 {
120 Type type = (Type) p.getSchemaType();
121
122 MessageWriter mw;
123 boolean writeOuter = type.isWriteOuter();
124 if (writeOuter)
125 mw = new ElementWriter(writer, p.getName());
126 else
127 mw = new ElementWriter(writer);
128
129 type.writeObject(value, mw, context);
130
131 if (writeOuter)
132 mw.close();
133 }
134
135 public QName getSuggestedName(Service service, OperationInfo op, int param)
136 {
137 TypeMapping tm = getTypeMapping(service);
138 Type type = tm.getTypeCreator().createType(op.getMethod(), param);
139
140 if (type.isComplex() && !type.isAbstract())
141 return type.getSchemaType();
142
143 return null;
144 }
145
146 private Type getParameterType(TypeMapping tm, MessagePartInfo param)
147 {
148 Type type = tm.getType(param.getName());
149
150 if (type == null && tm.isRegistered(param.getTypeClass()))
151 {
152 type = tm.getType(param.getTypeClass());
153 }
154
155 if (type == null)
156 {
157 type = (Type) part2type.get(param);
158 }
159
160 if (type == null)
161 {
162 OperationInfo op = param.getContainer().getOperation();
163
164 int index = -1;
165
166 if (op.getInputMessage().getMessageParts().contains(param))
167 index = param.getIndex();
168
169
170
171
172
173 type = tm.getTypeCreator().createType(op.getMethod(), index);
174 type.setTypeMapping(tm);
175
176 part2type.put(param, type);
177 }
178
179 return type;
180 }
181
182 private Type getParameterType(TypeMapping tm, MessageHeaderInfo param)
183 {
184 Type type = tm.getType(param.getName());
185
186 if (type == null && tm.isRegistered(param.getTypeClass()))
187 {
188 type = tm.getType(param.getTypeClass());
189 }
190
191 if (type == null)
192 {
193 OperationInfo op = param.getContainer().getOperation();
194
195 int index = -1;
196
197 if (op.getInputMessage().getMessageHeaders().contains(param))
198 index = param.getIndex();
199
200
201
202
203
204 type = tm.getTypeCreator().createType(op.getMethod(), index);
205 type.setTypeMapping(tm);
206 }
207
208 return type;
209 }
210
211 public TypeMapping getTypeMapping(Service service)
212 {
213 TypeMapping tm = (TypeMapping) service.getProperty(TYPE_MAPPING_KEY);
214
215 if (tm == null) tm = createTypeMapping(service);
216
217 return tm;
218 }
219
220 protected TypeMapping createTypeMapping(Service endpoint)
221 {
222 String encodingStyle = (String) endpoint.getProperty(ENCODING_URI_KEY);
223
224 if (encodingStyle == null)
225 {
226 AbstractBinding binding = (AbstractBinding) endpoint.getBinding();
227 if (binding.getUse().equals(SoapConstants.USE_ENCODED))
228 {
229 encodingStyle = endpoint.getSoapVersion().getSoapEncodingStyle();
230 }
231 else
232 {
233 encodingStyle = SoapConstants.XSD;
234 }
235 }
236
237 endpoint.setProperty(ENCODING_URI_KEY, encodingStyle);
238 final TypeMapping tm = registry.createTypeMapping(encodingStyle, true);
239
240 endpoint.setProperty(TYPE_MAPPING_KEY, tm);
241 registry.register(endpoint.getServiceInfo().getName().getNamespaceURI(), tm);
242
243 return tm;
244 }
245
246 public Object readHeader(MessageHeaderInfo p, MessageContext context)
247 throws XFireFault
248 {
249 Type type = (Type) p.getSchemaType();
250
251 QName name = p.getName();
252 Element headers = context.getExchange().getInMessage().getHeader();
253 Element header = headers.getFirstChildElement(name.getLocalPart(), name.getNamespaceURI());
254
255 if (header == null) return null;
256
257 return type.readObject(new YOMReader(header), context);
258 }
259
260 public void writeHeader(MessagePartInfo p, MessageContext context, Object value)
261 throws XFireFault
262 {
263 Type type = (Type) p.getSchemaType();
264
265 MessageWriter mw = new YOMWriter(context.getOutMessage().getHeader());
266
267 type.writeObject(value, mw, context);
268
269 mw.close();
270 }
271
272 }