001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.management.wsdm.capabilities;
022
023 import java.net.InetAddress;
024 import java.util.HashMap;
025 import java.util.Map;
026
027 import javax.management.MBeanAttributeInfo;
028 import javax.management.MBeanOperationInfo;
029 import javax.management.MBeanParameterInfo;
030 import javax.management.ObjectName;
031 import javax.xml.XMLConstants;
032 import javax.xml.namespace.QName;
033
034 import org.apache.muse.core.Environment;
035 import org.apache.muse.util.ReflectUtils;
036 import org.apache.muse.util.xml.XmlUtils;
037 import org.apache.muse.ws.wsdl.WsdlUtils;
038 import org.apache.qpid.management.Messages;
039 import org.apache.qpid.management.Names;
040 import org.apache.qpid.management.wsdm.muse.serializer.ObjectSerializer;
041 import org.apache.qpid.qman.debug.WsdlDebugger;
042 import org.apache.qpid.transport.util.Logger;
043 import org.apache.xpath.XPathAPI;
044 import org.w3c.dom.Attr;
045 import org.w3c.dom.Document;
046 import org.w3c.dom.Element;
047 /**
048 * TO BE IMPROVED USING JAXB!!
049 *
050 * @author Andrea Gazzarini
051 */
052 class WsdlBuilder implements IArtifactBuilder {
053
054 private final static Logger LOGGER = Logger.get(WsdlBuilder.class);
055
056 private Environment _environment;
057 private Document _document;
058 private Element schema;
059
060 private ObjectSerializer serializer = new ObjectSerializer();
061
062 private ObjectName _objectName;
063
064 private boolean mapTypeHasBeenDeclared;
065 private boolean uuidTypeHasBeenDeclared;
066 private Map<String, String> arrayTypesAlreadyDeclared = new HashMap<String, String>();
067
068 public void onAttribute(MBeanAttributeInfo attributeMetadata) throws BuilderException
069 {
070 try
071 {
072 /*
073 <xs:element name='accountAttributes'>
074 <xs:complexType>
075 <xs:sequence>
076 <xs:element maxOccurs='unbounded' minOccurs='0' name='entry'>
077 <xs:complexType>
078 <xs:sequence>
079 <xs:element minOccurs='0' name='key' type='xs:string'/>
080 <xs:element minOccurs='0' name='value' type='xs:anyType'/>
081 </xs:sequence>
082 </xs:complexType>
083 </xs:element>
084 </xs:sequence>
085 </xs:complexType>
086 </xs:element>
087 */
088 schema.appendChild(defineSchemaFor(attributeMetadata.getType(), attributeMetadata.getName()));
089 Element wsrpProperties = (Element) XPathAPI.selectSingleNode(
090 _document,
091 "/wsdl:definitions/wsdl:types/xsd:schema[" +
092 "@targetNamespace='http://amqp.apache.org/qpid/management/qman']" +
093 "/xsd:element[@name='QManWsResourceProperties']/xsd:complexType/xsd:sequence");
094
095 Element propertyRef= XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
096 propertyRef.setAttribute(
097 "ref",
098 Names.PREFIX+":"+attributeMetadata.getName());
099 propertyRef.setAttribute("minOccurs", "0");
100 wsrpProperties.appendChild(propertyRef);
101
102 } catch(Exception exception)
103 {
104 throw new BuilderException(exception);
105 }
106 }
107
108 private final static QName XSD_ELEMENT_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"element","xsd");
109 private final static QName XSD_COMPLEX_TYPE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"complexType","xsd");
110 private final static QName XSD_SEQUENCE_QNAME = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI,"sequence","xsd");
111
112 @SuppressWarnings("unchecked")
113 private Element defineSchemaFor(String type, String attributeName) throws Exception
114 {
115 if (type.equals("java.util.Map"))
116 {
117 if (!mapTypeHasBeenDeclared)
118 {
119 Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME);
120 complexType.setAttribute("name","map");
121 Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME);
122
123 Element entry = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
124 entry.setAttribute("name", "entry");
125 entry.setAttribute("minOccurs", "0");
126 entry.setAttribute("maxOccurs", "unbounded");
127
128 Element complexType2 = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME);
129 Element sequence2 = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME);
130
131 Element key = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
132 key.setAttribute("name", "key");
133 key.setAttribute("type", "xsd:string");
134
135 Element value = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
136 value.setAttribute("name", "value");
137 value.setAttribute("type", "xsd:anyType");
138
139 sequence2.appendChild(key);
140 sequence2.appendChild(value);
141 complexType2.appendChild(sequence2);
142 entry.appendChild(complexType2);
143 sequence.appendChild(entry);
144 complexType.appendChild(sequence);
145 schema.appendChild(complexType);
146 mapTypeHasBeenDeclared = true;
147 }
148 Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
149 propertyDeclaration.setAttribute("name",attributeName);
150 propertyDeclaration.setAttribute("type", "qman:map");
151 return propertyDeclaration;
152
153 } else if ("java.util.UUID".equals(type))
154 {
155 if (!uuidTypeHasBeenDeclared)
156 {
157 Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME);
158 complexType.setAttribute("name", "uuid");
159 Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME);
160 Element uuid = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
161 uuid.setAttribute("name", "uuid");
162 uuid.setAttribute("type", "xsd:string");
163 sequence.appendChild(uuid);
164 complexType.appendChild(sequence);
165 schema.appendChild(complexType);
166 uuidTypeHasBeenDeclared = true;
167 }
168 Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
169 propertyDeclaration.setAttribute("name",attributeName);
170 propertyDeclaration.setAttribute("type", "qman:uuid");
171 return propertyDeclaration;
172 } else if (type.startsWith("["))
173 {
174 Class arrayClass = Class.forName(type);
175 Class clazz = ReflectUtils.getClassFromArrayClass(arrayClass);
176 String arrayType = arrayClass.getSimpleName().replace("[]", "").trim();
177 arrayType = Character.toUpperCase(arrayType.charAt(0))+arrayType.substring(1);
178 if (!arrayTypesAlreadyDeclared.containsKey(type))
179 {
180 Element complexType = XmlUtils.createElement(_document, XSD_COMPLEX_TYPE_QNAME);
181 complexType.setAttribute("name", "arrayOf"+arrayType);
182 Element sequence = XmlUtils.createElement(_document, XSD_SEQUENCE_QNAME);
183 Element entry = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
184 entry.setAttribute("name", "entry");
185 entry.setAttribute("type", serializer.getXmlType(clazz));
186 sequence.appendChild(entry);
187 complexType.appendChild(sequence);
188 schema.appendChild(complexType);
189 arrayTypesAlreadyDeclared.put(type, arrayType);
190 }
191 Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
192 propertyDeclaration.setAttribute("name",attributeName);
193 propertyDeclaration.setAttribute("type", "qman:arrayOf"+arrayTypesAlreadyDeclared.get(type));
194 return propertyDeclaration;
195 }
196 else {
197 Element propertyDeclaration = XmlUtils.createElement(_document, XSD_ELEMENT_QNAME);
198 propertyDeclaration.setAttribute("name",attributeName);
199 propertyDeclaration.setAttribute("type", serializer.getXmlType(Class.forName(type)));
200
201 return propertyDeclaration;
202 }
203 }
204
205 public void begin(ObjectName objectName) throws BuilderException
206 {
207 this._objectName = objectName;
208 try
209 {
210 Attr location = (Attr) XPathAPI.selectSingleNode(
211 _document,
212 "/wsdl:definitions/wsdl:service/wsdl:port/wsdl-soap:address/@location");
213
214 StringBuilder builder = new StringBuilder("http://")
215 .append(InetAddress.getLocalHost().getHostName())
216 .append(':')
217 .append(System.getProperty(Names.ADAPTER_PORT_PROPERTY_NAME,"8080"))
218 .append('/')
219 .append("qman")
220 .append('/')
221 .append("services/QManWsResource");
222 location.setValue(builder.toString());
223 } catch(Exception exception)
224 {
225 LOGGER.error(
226 exception,
227 Messages.QMAN_100026_SOAP_ADDRESS_REPLACEMENT_FAILURE);
228 throw new BuilderException(exception);
229 }
230
231 try
232 {
233 schema = (Element) XPathAPI.selectSingleNode(
234 _document.getDocumentElement(),
235 "/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace='http://amqp.apache.org/qpid/management/qman']");
236 } catch(Exception exception)
237 {
238 LOGGER.error(
239 exception,
240 Messages.QMAN_100034_WSDL_SCHEMA_SECTION_NOT_FOUND);
241 throw new BuilderException(exception);
242 }
243 /*
244 <xs:complexType name='InvocationResult'>
245 <xs:sequence>
246 <xs:element name='statusCode' type="xsd:long" />
247 <xs:element name='statusText' type="xsd:string" />
248 <xs:element name='outputParameters'>
249 <xs:complexType>
250 <xs:sequence>
251
252 <xs:element maxOccurs='unbounded' minOccurs='0' name='entry'>
253
254 <xs:complexType>
255 <xs:sequence>
256 <xs:element minOccurs='0' name="name' type='xs:string'/>
257 <xs:element minOccurs='0' name="value" type='xs:anyType'/>
258 </xs:sequence>
259 </xs:complexType>
260 </xs:element>
261 </xs:sequence>
262 </xs:complexType>
263 </xs:element>
264 </xs:sequence>
265 </xs:complexType>
266 */
267 Element complexTypeResult = _document.createElement("xsd:complexType");
268 complexTypeResult.setAttribute("name", "result");
269 Element sequence = _document.createElement("xsd:sequence");
270 complexTypeResult.appendChild(sequence);
271
272 Element statusCode = _document.createElement("xsd:element");
273 statusCode.setAttribute("name", "statusCode");
274 statusCode.setAttribute("type", "xsd:long");
275
276 Element statusText = _document.createElement("xsd:element");
277 statusText.setAttribute("name", "statusText");
278 statusText.setAttribute("type", "xsd:string");
279
280 sequence.appendChild(statusCode);
281 sequence.appendChild(statusText);
282
283 Element outputParams = _document.createElement("xsd:complexType");
284 outputParams.setAttribute("name", "outputParameters");
285 sequence.appendChild(outputParams);
286
287 Element complexTypeOutput = _document.createElement("xsd:complexType");
288 Element outputSequence = _document.createElement("xsd:sequence");
289
290 outputParams.appendChild(complexTypeOutput);
291 complexTypeOutput.appendChild(outputSequence);
292
293 Element entry = _document.createElement("xsd:element");
294 entry.setAttribute("maxOccurs", "unbounded");
295 entry.setAttribute("minOccurs", "0");
296 entry.setAttribute("name", "entry");
297
298 outputSequence.appendChild(entry);
299
300 Element entryComplexType = _document.createElement("xsd:complexType");
301 Element entrySequence = _document.createElement("xsd:sequence");
302 entryComplexType.appendChild(entrySequence);
303 entry.appendChild(entryComplexType);
304
305 Element name = _document.createElement("xsd:name");
306 name.setAttribute("name", "key");
307 name.setAttribute("type", "xsd:string");
308
309 Element value = _document.createElement("xsd:element");
310 value.setAttribute("name", "value");
311 value.setAttribute("type", "xsd:anyType");
312
313 entrySequence.appendChild(name);
314 entrySequence.appendChild(value);
315
316 schema.appendChild(complexTypeResult);
317 }
318
319 public void onOperation(MBeanOperationInfo operationMetadata) throws BuilderException
320 {
321 // SCHEMA SECTION
322 /*
323 <xs:element name='purgeRequest' type='qman:purgeRequest' />
324
325 <xs:element name='purgeResponse' type='qman:purgeResponse' />
326
327 <xs:complexType name='purgeRequest'>
328 <xs:sequence>
329 <xs:element name='arg0' type='xs:int' />
330 <xs:element minOccurs='0' name='arg1' type='qman:hashMap' />
331 </xs:sequence>
332 </xs:complexType>
333
334 <xs:element name='hashMap'>
335 <xs:complexType>
336 <xs:sequence>
337 <xs:element maxOccurs='unbounded' minOccurs='0' name='entry'>
338 <xs:complexType>
339 <xs:sequence>
340 <xs:element minOccurs='0' name='key' type='xs:string'/>
341 <xs:element minOccurs='0' name='value' type='xs:anyType'/>
342 </xs:sequence>
343 </xs:complexType>
344 </xs:element>
345 </xs:sequence>
346 </xs:complexType>
347 </xs:element>
348
349 <xs:complexType name='purgeResponse'>
350 <xs:sequence />
351 </xs:complexType>
352 */
353 try
354 {
355 // <xs:element name='purgeRequest' type='qman:purgeRequest' />
356 // <xsd:element xmlns="" name="purgeRequest" type="qman:purgeRequest"/>
357
358 Element methodRequestElement= _document.createElement("xsd:element");
359 String methodNameRequest = operationMetadata.getName()+"Request";
360 methodRequestElement.setAttribute("name", methodNameRequest);
361 methodRequestElement.setAttribute("type", "qman:"+methodNameRequest);
362
363 // <xs:element name='purgeResponse' type='qman:purgeResponse' />
364 Element methodResponseElement= _document.createElement("xsd:element");
365 String methodNameResponse= operationMetadata.getName()+"Response";
366 methodResponseElement.setAttribute("name", methodNameResponse);
367 methodResponseElement.setAttribute("type", "qman:"+methodNameResponse);
368
369 schema.appendChild(methodRequestElement);
370 schema.appendChild(methodResponseElement);
371
372 /*
373 <xs:complexType name='purgeRequest'>
374 <xs:sequence>
375 <xs:element name='arg0' type='xs:int' />
376 <xs:element minOccurs='0' name='arg1' type='qman:hashMap' />
377 </xs:sequence>
378 </xs:complexType>
379
380 */
381
382 Element methodNameRequestComplexType = _document.createElement("xsd:complexType");
383 methodNameRequestComplexType.setAttribute("name", methodNameRequest);
384 Element methodNameRequestComplexTypeSequence = _document.createElement("xsd:sequence");
385
386 for(MBeanParameterInfo parameter : operationMetadata.getSignature())
387 {
388 methodNameRequestComplexTypeSequence.appendChild(defineSchemaFor(parameter.getType(), parameter.getName()));
389 }
390
391 methodNameRequestComplexType.appendChild(methodNameRequestComplexTypeSequence);
392 schema.appendChild(methodNameRequestComplexType);
393
394 Element methodNameResponseComplexType = _document.createElement("xsd:complexType");
395 methodNameResponseComplexType.setAttribute("name", methodNameResponse);
396
397 Element methodNameResponseSequence = _document.createElement("xsd:sequence");
398 methodNameResponseComplexType.appendChild(methodNameResponseSequence);
399
400 Element result = _document.createElement("xsd:element");
401 result.setAttribute("name", "result");
402 result.setAttribute("type", "qman:result");
403 methodNameResponseSequence.appendChild(result);
404
405 schema.appendChild(methodNameResponseComplexType);
406
407 /*
408 <message name="purgeResponseMessage">
409 <part element='qman:purgeResponse' name='purgeResponse'></part>
410 </message>
411
412 <message name='purgeRequestMessage'>
413 <part element="qman:purgeRequest" name='purgeRequest'></part>
414 </message>
415 */
416 Element definitions = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions");
417
418 String requestMessageName = methodNameRequest+"Message";
419 String responseMessageName = methodNameResponse+"Message";
420
421 Element requestMessage = _document.createElement("message");
422 requestMessage.setAttribute("name", requestMessageName);
423 Element requestPart = _document.createElement("wsdl:part");
424 requestPart.setAttribute("element", "qman:"+methodNameRequest);
425 requestPart.setAttribute("name", methodNameRequest);
426 requestMessage.appendChild(requestPart);
427
428 Element responseMessage = _document.createElement("wsdl:message");
429 responseMessage.setAttribute("name", responseMessageName);
430 Element responsePart = _document.createElement("wsdl:part");
431 responsePart.setAttribute("element", "qman:"+methodNameResponse);
432 responsePart.setAttribute("name", methodNameResponse);
433 responseMessage.appendChild(responsePart);
434
435 definitions.appendChild(requestMessage);
436 definitions.appendChild(responseMessage);
437
438
439 /*
440 <operation name='purge'>
441 <input message="qman:purgeRequestMessage">
442 </input>
443 <output message='qman:purgeResponseMessage'>
444 </output>
445 </operation>
446 */
447 Element portType = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions/wsdl:portType");
448 Element operation = _document.createElement("wsdl:operation");
449 operation.setAttribute("name", operationMetadata.getName());
450
451 Element input = _document.createElement("wsdl:input");
452 input.setAttribute("message", "qman:"+requestMessageName);
453 input.setAttribute("name", methodNameRequest);
454 input.setAttribute("wsa:action", Names.NAMESPACE_URI+"/"+operationMetadata.getName());
455
456 //name="SetResourcePropertiesRequest" wsa:Action="http://docs.oasis-open.org/wsrf/rpw-2/SetResourceProperties/SetResourcePropertiesRequest"/>
457
458 operation.appendChild(input);
459
460 Element output = _document.createElement("wsdl:output");
461 output.setAttribute("message", "qman:"+responseMessageName);
462 output.setAttribute("name", methodNameResponse);
463 output.setAttribute("wsa:action", Names.NAMESPACE_URI+"/"+methodNameResponse);
464
465 operation.appendChild(output);
466
467 portType.appendChild(operation);
468
469 /*
470 <operation name='purge'>
471 <soap:operation soapAction='purge' />
472 <input>
473 <soap:body use='literal' />
474 </input>
475 <output>
476 <soap:body use='literal' />
477 </output>
478 </operation>
479 */
480 Element binding = (Element) XPathAPI.selectSingleNode(_document, "/wsdl:definitions/wsdl:binding");
481 Element bindingOperation = _document.createElement("wsdl:operation");
482 bindingOperation.setAttribute("name", operationMetadata.getName());
483
484 Element soapOperation = _document.createElement("wsdl-soap:operation");
485 soapOperation.setAttribute("soapAction", Names.NAMESPACE_URI+"/"+operationMetadata.getName());
486
487 Element bindingInput = _document.createElement("wsdl:input");
488 Element bodyIn = _document.createElement("wsdl-soap:body");
489 bodyIn.setAttribute("use", "literal");
490
491 Element bindingOutput = _document.createElement("wsdl:output");
492 Element bodyOut = _document.createElement("wsdl-soap:body");
493 bodyOut.setAttribute("use", "literal");
494
495 bindingOutput.appendChild(bodyOut);
496 bindingInput.appendChild(bodyIn);
497
498 bindingOperation.appendChild(soapOperation);
499 bindingOperation.appendChild(bindingInput);
500 bindingOperation.appendChild(bindingOutput);
501
502 binding.appendChild(bindingOperation);
503 } catch(Exception exception)
504 {
505 throw new BuilderException(exception);
506 }
507 }
508
509 public void endAttributes()
510 {
511 // N.A.
512 }
513
514 public void endOperations()
515 {
516
517 }
518
519 public Document getWsdl()
520 {
521 WsdlDebugger.debug(_objectName,_document);
522 return _document;
523 }
524
525 public void setEnvironment(Environment environment)
526 {
527 this._environment = environment;
528 }
529
530 public void setWsdlPath(String wsdlPath)
531 {
532 _document = WsdlUtils.createWSDL(_environment, wsdlPath, true);
533 }
534 }
|