View Javadoc

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             /* Note: we are not registering the type here, because it is an anonymous
170              * type. Potentially there could be many schema types with this name. For example,
171              * there could be many ns:in0 paramters.
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             /* Note: we are not registering the type here, because it is an anonymous
201              * type. Potentially there could be many schema types with this name. For example,
202              * there could be many ns:in0 paramters.
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 }