001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.wsdl.codegen.extension;
020:
021: import org.apache.axis2.AxisFault;
022: import org.apache.axis2.description.AxisMessage;
023: import org.apache.axis2.description.AxisOperation;
024: import org.apache.axis2.description.AxisService;
025: import org.apache.axis2.description.Parameter;
026: import org.apache.axis2.wsdl.WSDLConstants;
027: import org.apache.axis2.wsdl.WSDLUtil;
028: import org.apache.axis2.wsdl.codegen.CodeGenConfiguration;
029: import org.apache.axis2.wsdl.codegen.CodeGenerationException;
030: import org.apache.axis2.wsdl.i18n.CodegenMessages;
031: import org.apache.axis2.wsdl.util.ConfigPropertyFileLoader;
032: import org.apache.axis2.wsdl.util.Constants;
033: import org.apache.axis2.wsdl.util.MessagePartInformationHolder;
034: import org.apache.ws.commons.schema.*;
035:
036: import javax.xml.namespace.QName;
037: import java.util.ArrayList;
038: import java.util.Iterator;
039: import java.util.LinkedList;
040: import java.util.List;
041:
042: /**
043: * This extension invokes the schema unwrapper depending on the users setting. it is desirable to
044: * put this extension before other extensions since extnsions such as the databinding extension may
045: * well depend on the schema being unwrapped previously. For a complete unwrap the following format
046: * of the schema is expected < element > < complexType > < sequence > < element
047: * /> < /sequence > < /complexType > < /element >
048: * <p/>
049: * When an unwrapped WSDL is encountered Axis2 generates a wrapper schema and that wrapper schema
050: * has the above mentioned format. This unwrapping algorithm will work on a pure doc/lit WSDL if it
051: * has the above mentioned format only
052: */
053: public class SchemaUnwrapperExtension extends
054: AbstractCodeGenerationExtension {
055:
056: private CodeGenConfiguration codeGenConfiguration;
057:
058: /**
059: * @param configuration
060: * @throws CodeGenerationException
061: */
062: public void engage(CodeGenConfiguration configuration)
063: throws CodeGenerationException {
064: this .codeGenConfiguration = configuration;
065:
066: if (!configuration.isParametersWrapped()) {
067:
068: // A check to avoid nasty surprises - Since unwrapping is not
069: // supported by all frameworks, we check the framework name to be
070: // compatible
071: if (!ConfigPropertyFileLoader
072: .getUnwrapSupportedFrameworkNames().contains(
073: configuration.getDatabindingType())) {
074: throw new CodeGenerationException(
075: CodegenMessages
076: .getMessage("extension.unsupportedforunwrapping"));
077: } else if (!ConfigPropertyFileLoader
078: .getUnwrapDirectFrameworkNames().contains(
079: configuration.getDatabindingType())) {
080:
081: //walk the schema and find the top level elements
082: List services = configuration.getAxisServices();
083: AxisService axisService;
084:
085: for (Iterator servicesIter = services.iterator(); servicesIter
086: .hasNext();) {
087: axisService = (AxisService) servicesIter.next();
088: for (Iterator operations = axisService
089: .getOperations(); operations.hasNext();) {
090: AxisOperation op = (AxisOperation) operations
091: .next();
092:
093: if (WSDLUtil.isInputPresentForMEP(op
094: .getMessageExchangePattern())) {
095: walkSchema(
096: op
097: .getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE),
098: WSDLConstants.INPUT_PART_QNAME_SUFFIX);
099: }
100: // get the out put parameter details as well to unwrap the responses
101: //TODO: support xmlbeans
102: if (configuration.getDatabindingType().equals(
103: "adb")) {
104: if (WSDLUtil.isOutputPresentForMEP(op
105: .getMessageExchangePattern())) {
106: walkSchema(
107: op
108: .getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE),
109: WSDLConstants.OUTPUT_PART_QNAME_SUFFIX);
110: }
111: }
112: }
113: }
114: }
115: }
116: }
117:
118: /**
119: * walk the given schema element For a successful unwrapping the element should have the
120: * following structure < element > < complexType > < sequence > < element
121: * /> < /sequence > < /complexType > < /element >
122: */
123:
124: public void walkSchema(AxisMessage message, String qnameSuffix)
125: throws CodeGenerationException {
126: //nothing to unwrap
127: if (message.getSchemaElement() == null) {
128: return;
129: }
130:
131: List partNameList = new LinkedList();
132:
133: XmlSchemaElement schemaElement = message.getSchemaElement();
134: XmlSchemaType schemaType = schemaElement.getSchemaType();
135: QName schemaTypeQname = schemaElement.getSchemaTypeName();
136: if (schemaType == null) {
137: if (schemaTypeQname != null) {
138: // find the schema type from all the schemas
139: // now we need to get the schema of the extension type from the parent schema. For that let's first retrieve
140: // the parent schema
141: AxisService axisService = message.getAxisOperation()
142: .getAxisService();
143: ArrayList schemasList = axisService.getSchema();
144:
145: XmlSchema schema = null;
146: for (Iterator iter = schemasList.iterator(); iter
147: .hasNext();) {
148: schema = (XmlSchema) iter.next();
149: schemaType = getSchemaType(schema, schemaTypeQname);
150: if (schemaType != null) {
151: break;
152: }
153: }
154: }
155: }
156:
157: if (schemaType instanceof XmlSchemaComplexType) {
158: handleAllCasesOfComplexTypes(schemaType, message,
159: partNameList, qnameSuffix);
160: } else if ((schemaType instanceof XmlSchemaSimpleType)
161: || ((schemaTypeQname != null) && (schemaTypeQname
162: .equals(new QName(
163: "http://www.w3.org/2001/XMLSchema",
164: "anyType"))))) {
165: QName opName = message.getAxisOperation().getName();
166: partNameList.add(WSDLUtil.getPartQName(opName
167: .getLocalPart(), qnameSuffix, schemaElement
168: .getQName().getLocalPart()));
169: } else if (schemaType == null) {
170: throw new CodeGenerationException(
171: "Can not determine the schema type for the "
172: + schemaElement.getName());
173: } else {
174: //we've no idea how to unwrap a non complexType!!!!!!
175: throw new CodeGenerationException(CodegenMessages
176: .getMessage("extension.unsupportedSchemaFormat",
177: schemaType.getName(), "complexType"));
178: }
179:
180: try {
181: //set in the axis message that the unwrapping was success
182: message.addParameter(getParameter(Constants.UNWRAPPED_KEY,
183: Boolean.TRUE));
184:
185: // attach the opName and the parts name list into the
186: // axis message by using the holder
187: MessagePartInformationHolder infoHolder = new MessagePartInformationHolder();
188: infoHolder.setOperationName(message.getAxisOperation()
189: .getName());
190: infoHolder.setPartsList(partNameList);
191:
192: //attach it to the parameters
193: message.addParameter(getParameter(
194: Constants.UNWRAPPED_DETAILS, infoHolder));
195:
196: } catch (AxisFault axisFault) {
197: throw new CodeGenerationException(axisFault);
198: }
199:
200: }
201:
202: private void handleAllCasesOfComplexTypes(XmlSchemaType schemaType,
203: AxisMessage message, List partNameList, String qnameSuffix)
204: throws CodeGenerationException {
205:
206: // if a complex type name exits for a element then
207: // we keep that complex type to support unwrapping
208: if (schemaType instanceof XmlSchemaComplexType) {
209: XmlSchemaComplexType cmplxType = (XmlSchemaComplexType) schemaType;
210: if (cmplxType.getContentModel() == null) {
211: if (cmplxType.getParticle() != null) {
212: processXMLSchemaSequence(cmplxType.getParticle(),
213: message, partNameList, qnameSuffix);
214: }
215: } else {
216: // now lets handle case with extensions
217: processComplexContentModel(cmplxType, message,
218: partNameList, qnameSuffix);
219: }
220: // handle attributes here
221: processAttributes(cmplxType, message, partNameList,
222: qnameSuffix);
223:
224: }
225: }
226:
227: private void processAttributes(XmlSchemaComplexType complexType,
228: AxisMessage message, List partNameList, String qnameSuffix) {
229: QName opName = message.getAxisOperation().getName();
230: XmlSchemaObjectCollection xmlObjectCollection = complexType
231: .getAttributes();
232: XmlSchemaObject item;
233: XmlSchemaAttribute xmlSchemaAttribute;
234: for (Iterator iter = xmlObjectCollection.getIterator(); iter
235: .hasNext();) {
236: item = (XmlSchemaObject) iter.next();
237: if (item instanceof XmlSchemaAttribute) {
238: xmlSchemaAttribute = (XmlSchemaAttribute) item;
239: String partName = xmlSchemaAttribute.getName();
240: partNameList.add(WSDLUtil.getPartQName(opName
241: .getLocalPart(), qnameSuffix, partName));
242: }
243: }
244:
245: }
246:
247: private void processComplexContentModel(
248: XmlSchemaComplexType cmplxType, AxisMessage message,
249: List partNameList, String qnameSuffix)
250: throws CodeGenerationException {
251: XmlSchemaContentModel contentModel = cmplxType
252: .getContentModel();
253: if (contentModel instanceof XmlSchemaComplexContent) {
254: XmlSchemaComplexContent xmlSchemaComplexContent = (XmlSchemaComplexContent) contentModel;
255: XmlSchemaContent content = xmlSchemaComplexContent
256: .getContent();
257: if (content instanceof XmlSchemaComplexContentExtension) {
258: XmlSchemaComplexContentExtension schemaExtension = (XmlSchemaComplexContentExtension) content;
259:
260: // process particles inside this extension, if any
261: if (schemaExtension.getParticle() != null) {
262: processXMLSchemaSequence(schemaExtension
263: .getParticle(), message, partNameList,
264: qnameSuffix);
265: }
266:
267: // now we need to get the schema of the extension type from the parent schema. For that let's first retrieve
268: // the parent schema
269: AxisService axisService = message.getAxisOperation()
270: .getAxisService();
271: ArrayList schemasList = axisService.getSchema();
272:
273: XmlSchema parentSchema = null;
274:
275: XmlSchema schema = null;
276: XmlSchemaType extensionSchemaType = null;
277: for (Iterator iter = schemasList.iterator(); iter
278: .hasNext();) {
279: schema = (XmlSchema) iter.next();
280: extensionSchemaType = getSchemaType(schema,
281: schemaExtension.getBaseTypeName());
282: if (extensionSchemaType != null) {
283: break;
284: }
285: }
286:
287: // ok now we got the parent schema. Now let's get the extension's schema type
288:
289: handleAllCasesOfComplexTypes(extensionSchemaType,
290: message, partNameList, qnameSuffix);
291: }
292: }
293: }
294:
295: private XmlSchemaType getSchemaType(XmlSchema schema, QName typeName) {
296: XmlSchemaType xmlSchemaType = null;
297: if (schema != null) {
298: xmlSchemaType = schema.getTypeByName(typeName);
299: if (xmlSchemaType == null) {
300: // try to find in an import or an include
301: XmlSchemaObjectCollection includes = schema
302: .getIncludes();
303: if (includes != null) {
304: Iterator includesIter = includes.getIterator();
305: Object object = null;
306: while (includesIter.hasNext()) {
307: object = includesIter.next();
308: if (object instanceof XmlSchemaImport) {
309: XmlSchema schema1 = ((XmlSchemaImport) object)
310: .getSchema();
311: xmlSchemaType = getSchemaType(schema1,
312: typeName);
313: }
314: if (object instanceof XmlSchemaInclude) {
315: XmlSchema schema1 = ((XmlSchemaInclude) object)
316: .getSchema();
317: xmlSchemaType = getSchemaType(schema1,
318: typeName);
319: }
320: if (xmlSchemaType != null) {
321: break;
322: }
323: }
324: }
325: }
326: }
327: return xmlSchemaType;
328: }
329:
330: private void processXMLSchemaSequence(
331: XmlSchemaParticle schemaParticle, AxisMessage message,
332: List partNameList, String qnameSuffix)
333: throws CodeGenerationException {
334: if (schemaParticle instanceof XmlSchemaSequence) {
335: // get the name of the operation name and namespace,
336: // part name and hang them somewhere ? The ideal place
337: // would be the property bag in the codegen config!
338: QName opName = message.getAxisOperation().getName();
339:
340: XmlSchemaSequence sequence = (XmlSchemaSequence) schemaParticle;
341: XmlSchemaObjectCollection items = sequence.getItems();
342:
343: // if this is an empty sequence, return
344: if (items.getCount() == 0) {
345: return;
346: }
347: for (Iterator i = items.getIterator(); i.hasNext();) {
348: Object item = i.next();
349: // get each and every element in the sequence and
350: // traverse through them
351: if (item instanceof XmlSchemaElement) {
352: //add the element name to the part name list
353: XmlSchemaElement xmlSchemaElement = (XmlSchemaElement) item;
354: XmlSchemaType schemaType = xmlSchemaElement
355: .getSchemaType();
356: String partName = null;
357: if (xmlSchemaElement.getRefName() != null) {
358: partName = xmlSchemaElement.getRefName()
359: .getLocalPart();
360: } else {
361: partName = xmlSchemaElement.getName();
362: }
363:
364: // part names are not unique across messages. Hence
365: // we need some way of making the part name a unique
366: // one (due to the fact that the type mapper
367: // is a global list of types).
368: // The seemingly best way to do that is to
369: // specify a namespace for the part QName reference which
370: // is stored in the list. This part qname is
371: // temporary and should not be used with it's
372: // namespace URI (which happened to be the operation name)
373: // with _input attached to it
374:
375: partNameList.add(WSDLUtil.getPartQName(opName
376: .getLocalPart(), qnameSuffix, partName));
377:
378: // if the particle contains anything other than
379: // a XMLSchemaElement then we are not in a position
380: // to unwrap it
381: } else if (item instanceof XmlSchemaAny) {
382:
383: // if this is an instance of xs:any, then there is no part name for it. Using ANY_ELEMENT_FIELD_NAME
384: // for it for now
385:
386: //we have to handle both maxoccurs 1 and maxoccurs > 1 situation
387: XmlSchemaAny xmlSchemaAny = (XmlSchemaAny) item;
388:
389: partNameList.add(WSDLUtil.getPartQName(opName
390: .getLocalPart(), qnameSuffix,
391: Constants.ANY_ELEMENT_FIELD_NAME));
392: } else {
393: throw new CodeGenerationException(
394: CodegenMessages
395: .getMessage(
396: "extension.unsupportedSchemaFormat",
397: "unknown type", "Element"));
398: }
399: }
400:
401: //we do not know how to deal with other particles
402: //such as xs:all or xs:choice. Usually occurs when
403: //passed with the user built WSDL where the style
404: //is document.
405: } else if (schemaParticle instanceof XmlSchemaChoice) {
406: throw new CodeGenerationException(CodegenMessages
407: .getMessage("extension.unsupportedSchemaFormat",
408: "choice", "sequence"));
409:
410: } else if (schemaParticle instanceof XmlSchemaAll) {
411: throw new CodeGenerationException(CodegenMessages
412: .getMessage("extension.unsupportedSchemaFormat",
413: "all", "sequence"));
414: } else {
415: throw new CodeGenerationException(CodegenMessages
416: .getMessage("extension.unsupportedSchemaFormat",
417: "unknown", "sequence"));
418: }
419: }
420:
421: /**
422: * Generate a parametes object
423: *
424: * @param key
425: * @param value
426: */
427: private Parameter getParameter(String key, Object value) {
428: Parameter myParameter = new Parameter();
429: myParameter.setName(key);
430: myParameter.setValue(value);
431: return myParameter;
432: }
433:
434: }
|