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: */package org.apache.cxf.tools.wsdlto.frontend.jaxws.processor.internal;
019:
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.logging.Level;
025:
026: import javax.wsdl.OperationType;
027: import javax.xml.namespace.QName;
028:
029: import org.apache.cxf.common.i18n.Message;
030: import org.apache.cxf.common.util.StringUtils;
031: import org.apache.cxf.jaxb.JAXBUtils;
032: import org.apache.cxf.service.model.MessageInfo;
033: import org.apache.cxf.service.model.MessagePartInfo;
034: import org.apache.cxf.tools.common.ToolConstants;
035: import org.apache.cxf.tools.common.ToolContext;
036: import org.apache.cxf.tools.common.ToolException;
037: import org.apache.cxf.tools.common.model.JavaMethod;
038: import org.apache.cxf.tools.common.model.JavaParameter;
039: import org.apache.cxf.tools.common.model.JavaReturn;
040: import org.apache.cxf.tools.common.model.JavaType;
041: import org.apache.cxf.tools.wsdlto.core.DataBindingProfile;
042: import org.apache.cxf.tools.wsdlto.frontend.jaxws.processor.internal.annotator.WebParamAnnotator;
043: import org.apache.cxf.tools.wsdlto.frontend.jaxws.processor.internal.mapper.ParameterMapper;
044:
045: public class ParameterProcessor extends AbstractProcessor {
046: public static final String HEADER = "messagepart.isheader";
047: public static final String OUT_OF_BAND_HEADER = "messagepart.is_out_of_band_header";
048:
049: private DataBindingProfile dataBinding;
050:
051: @SuppressWarnings("unchecked")
052: public ParameterProcessor(ToolContext penv) {
053: super (penv);
054: dataBinding = context.get(DataBindingProfile.class);
055: }
056:
057: private boolean isRequestResponse(JavaMethod method) {
058: return method.getStyle() == OperationType.REQUEST_RESPONSE;
059: }
060:
061: public void process(JavaMethod method, MessageInfo inputMessage,
062: MessageInfo outputMessage, List<String> parameterOrder)
063: throws ToolException {
064:
065: if (!StringUtils.isEmpty(parameterOrder)
066: && isValidOrdering(parameterOrder, inputMessage,
067: outputMessage) && !method.isWrapperStyle()) {
068:
069: buildParamModelsWithOrdering(method, inputMessage,
070: outputMessage, parameterOrder);
071: } else {
072: buildParamModelsWithoutOrdering(method, inputMessage,
073: outputMessage);
074: }
075: }
076:
077: /**
078: * This method will be used by binding processor to change existing
079: * generated java method of porttype
080: *
081: * @param method
082: * @param part
083: * @param style
084: * @throws ToolException
085: */
086: public JavaParameter addParameterFromBinding(JavaMethod method,
087: MessagePartInfo part, JavaType.Style style)
088: throws ToolException {
089: return addParameter(method, getParameterFromPart(part, style));
090: }
091:
092: private JavaParameter getParameterFromPart(MessagePartInfo part,
093: JavaType.Style style) {
094: return ParameterMapper.map(part, style, context);
095: }
096:
097: protected JavaParameter addParameter(JavaMethod method,
098: JavaParameter parameter) throws ToolException {
099: if (parameter == null) {
100: return null;
101: }
102: parameter.setMethod(method);
103: parameter.annotate(new WebParamAnnotator());
104: method.addParameter(parameter);
105: return parameter;
106: }
107:
108: private void processReturn(JavaMethod method, MessagePartInfo part) {
109: String name = part == null ? "return" : part.getName()
110: .getLocalPart();
111: String type = part == null ? "void" : ProcessorUtil
112: .resolvePartType(part, context);
113:
114: String namespace = part == null ? null : ProcessorUtil
115: .resolvePartNamespace(part);
116:
117: JavaReturn returnType = new JavaReturn(name, type, namespace);
118: if (part != null) {
119: returnType.setDefaultValueWriter(ProcessorUtil
120: .getDefaultValueWriter(part, context));
121: }
122:
123: returnType.setQName(ProcessorUtil.getElementName(part));
124: returnType.setStyle(JavaType.Style.OUT);
125: if (namespace != null && type != null && !"void".equals(type)) {
126: returnType.setClassName(ProcessorUtil.getFullClzName(part,
127: context, false));
128: }
129: method.setReturn(returnType);
130: }
131:
132: private boolean isOutOfBandHeader(final MessagePartInfo part) {
133: return Boolean.TRUE
134: .equals(part.getProperty(OUT_OF_BAND_HEADER));
135: }
136:
137: private boolean requireOutOfBandHeader() {
138: String value = (String) context
139: .get(ToolConstants.CFG_EXTRA_SOAPHEADER);
140: if (StringUtils.isEmpty(value)) {
141: return false;
142: }
143: return Boolean.valueOf(value).booleanValue();
144: }
145:
146: private int countOutOfBandHeader(MessageInfo message) {
147: int count = 0;
148: for (MessagePartInfo part : message.getMessageParts()) {
149: if (isOutOfBandHeader(part)) {
150: count++;
151: }
152: }
153: return count;
154: }
155:
156: private boolean messagePartsNotUnique(final MessageInfo message) {
157: int count = countOutOfBandHeader(message);
158: return message.getMessageParts().size() - count > 1;
159: }
160:
161: @SuppressWarnings("unchecked")
162: private void processInput(JavaMethod method,
163: MessageInfo inputMessage) throws ToolException {
164: if (requireOutOfBandHeader()) {
165: try {
166: Class
167: .forName("org.apache.cxf.binding.soap.SoapBindingFactory");
168: } catch (Exception e) {
169: LOG.log(Level.WARNING, new Message("SOAP_MISSING", LOG)
170: .toString());
171: }
172: }
173:
174: for (MessagePartInfo part : inputMessage.getMessageParts()) {
175: if (isOutOfBandHeader(part) && !requireOutOfBandHeader()) {
176: continue;
177: }
178: addParameter(method, getParameterFromPart(part,
179: JavaType.Style.IN));
180: }
181: }
182:
183: @SuppressWarnings("unchecked")
184: private void processWrappedInput(JavaMethod method,
185: MessageInfo inputMessage) throws ToolException {
186: List<MessagePartInfo> inputParts = inputMessage
187: .getMessageParts();
188:
189: if (messagePartsNotUnique(inputMessage)) {
190: processInput(method, inputMessage);
191: return;
192: } else if (inputParts.isEmpty()) {
193: return;
194: }
195: MessagePartInfo part = inputParts.iterator().next();
196:
197: List<QName> wrappedElements = ProcessorUtil.getWrappedElement(
198: context, part.getElementQName());
199: if (wrappedElements == null || wrappedElements.size() == 0) {
200: return;
201: }
202: boolean isSchemaQualified = ProcessorUtil
203: .isSchemaFormQualified(context, part.getElementQName());
204: for (QName item : wrappedElements) {
205: JavaParameter jp = getParameterFromQName(part
206: .getElementQName(), item, JavaType.Style.IN, part);
207: if (!isSchemaQualified) {
208: jp.setTargetNamespace("");
209: }
210:
211: addParameter(method, jp);
212: }
213:
214: // Adding out of band headers
215: if (countOutOfBandHeader(inputMessage) > 0) {
216: for (MessagePartInfo hpart : inputMessage.getMessageParts()) {
217: if (!isOutOfBandHeader(hpart)
218: || !requireOutOfBandHeader()) {
219: continue;
220: }
221: addParameter(method, getParameterFromPart(hpart,
222: JavaType.Style.IN));
223: }
224: }
225: }
226:
227: @SuppressWarnings("unchecked")
228: private void processOutput(JavaMethod method,
229: MessageInfo inputMessage, MessageInfo outputMessage)
230: throws ToolException {
231: Map<QName, MessagePartInfo> inputPartsMap = inputMessage
232: .getMessagePartsMap();
233: List<MessagePartInfo> outputParts = outputMessage == null ? new ArrayList<MessagePartInfo>()
234: : outputMessage.getMessageParts();
235: // figure out output parts that are not present in input parts
236: List<MessagePartInfo> outParts = new ArrayList<MessagePartInfo>();
237: if (isRequestResponse(method)) {
238:
239: for (MessagePartInfo outpart : outputParts) {
240: MessagePartInfo inpart = inputPartsMap.get(outpart
241: .getName());
242: if (inpart == null) {
243: outParts.add(outpart);
244: continue;
245: } else if (isSamePart(inpart, outpart)) {
246: addParameter(method, getParameterFromPart(outpart,
247: JavaType.Style.INOUT));
248: continue;
249: } else if (!isSamePart(inpart, outpart)) {
250: outParts.add(outpart);
251: continue;
252: }
253: }
254: }
255:
256: if (isRequestResponse(method) && outParts.size() == 1) {
257: processReturn(method, outParts.get(0));
258: return;
259: } else {
260: processReturn(method, null);
261: }
262: if (isRequestResponse(method)) {
263: for (MessagePartInfo part : outParts) {
264: addParameter(method, getParameterFromPart(part,
265: JavaType.Style.OUT));
266: }
267: }
268: }
269:
270: private void processWrappedOutput(JavaMethod method,
271: MessageInfo inputMessage, MessageInfo outputMessage)
272: throws ToolException {
273:
274: processWrappedAbstractOutput(method, inputMessage,
275: outputMessage);
276:
277: // process out of band headers
278: if (countOutOfBandHeader(outputMessage) > 0) {
279: for (MessagePartInfo hpart : outputMessage
280: .getMessageParts()) {
281: if (!isOutOfBandHeader(hpart)
282: || !requireOutOfBandHeader()) {
283: continue;
284: }
285: addParameter(method, getParameterFromPart(hpart,
286: JavaType.Style.OUT));
287: }
288: }
289: }
290:
291: @SuppressWarnings("unchecked")
292: private void processWrappedAbstractOutput(JavaMethod method,
293: MessageInfo inputMessage, MessageInfo outputMessage)
294: throws ToolException {
295:
296: List<MessagePartInfo> outputParts = outputMessage
297: .getMessageParts();
298: List<MessagePartInfo> inputParts = inputMessage
299: .getMessageParts();
300:
301: if (messagePartsNotUnique(inputMessage)
302: || messagePartsNotUnique(outputMessage)) {
303: processOutput(method, inputMessage, outputMessage);
304: return;
305: }
306: if (outputParts.size() == 0) {
307: addVoidReturn(method);
308: return;
309: }
310:
311: MessagePartInfo inputPart = inputParts.size() > 0 ? inputParts
312: .iterator().next() : null;
313: MessagePartInfo outputPart = outputParts.size() > 0 ? outputParts
314: .iterator().next()
315: : null;
316:
317: List<QName> inputWrapElement = null;
318: List<QName> outputWrapElement = null;
319:
320: if (inputPart != null) {
321: inputWrapElement = ProcessorUtil.getWrappedElement(context,
322: inputPart.getElementQName());
323: }
324:
325: if (outputPart != null) {
326: outputWrapElement = ProcessorUtil.getWrappedElement(
327: context, outputPart.getElementQName());
328: }
329:
330: if (inputWrapElement == null || outputWrapElement.size() == 0) {
331: addVoidReturn(method);
332: return;
333: }
334: method.setReturn(null);
335: boolean qualified = ProcessorUtil.isSchemaFormQualified(
336: context, outputPart.getElementQName());
337:
338: if (outputWrapElement.size() == 1 && inputWrapElement != null) {
339: QName outElement = outputWrapElement.iterator().next();
340: boolean sameWrapperChild = false;
341: for (QName inElement : inputWrapElement) {
342: if (isSameWrapperChild(inElement, outElement)) {
343: JavaParameter jp = getParameterFromQName(outputPart
344: .getElementQName(), outElement,
345: JavaType.Style.INOUT, outputPart);
346: if (!qualified) {
347: jp.setTargetNamespace("");
348: }
349: addParameter(method, jp);
350: sameWrapperChild = true;
351: if (method.getReturn() == null) {
352: addVoidReturn(method);
353: }
354: break;
355: }
356: }
357: if (!sameWrapperChild) {
358: JavaReturn jreturn = getReturnFromQName(outElement,
359: outputPart);
360: if (!qualified) {
361: jreturn.setTargetNamespace("");
362: }
363: method.setReturn(jreturn);
364: return;
365: }
366:
367: }
368:
369: for (QName outElement : outputWrapElement) {
370: if ("return".equals(outElement.getLocalPart())) {
371: if (method.getReturn() != null) {
372: org.apache.cxf.common.i18n.Message msg = new org.apache.cxf.common.i18n.Message(
373: "WRAPPER_STYLE_TWO_RETURN_TYPES", LOG);
374: throw new ToolException(msg);
375: }
376: JavaReturn jreturn = getReturnFromQName(outElement,
377: outputPart);
378: if (!qualified) {
379: jreturn.setTargetNamespace("");
380: }
381: method.setReturn(jreturn);
382: continue;
383: }
384: boolean sameWrapperChild = false;
385: if (inputWrapElement != null) {
386: for (QName inElement : inputWrapElement) {
387: if (isSameWrapperChild(inElement, outElement)) {
388: JavaParameter jp = getParameterFromQName(
389: outputPart.getElementQName(),
390: outElement, JavaType.Style.INOUT,
391: outputPart);
392: if (!qualified) {
393: jp.setTargetNamespace("");
394: }
395: addParameter(method, jp);
396: sameWrapperChild = true;
397: break;
398: }
399: }
400: }
401: if (!sameWrapperChild) {
402: JavaParameter jp = getParameterFromQName(outputPart
403: .getElementQName(), outElement,
404: JavaType.Style.OUT, outputPart);
405: if (!qualified) {
406: jp.setTargetNamespace("");
407: }
408: addParameter(method, jp);
409: }
410: }
411: if (method.getReturn() == null) {
412: addVoidReturn(method);
413: }
414: }
415:
416: private void addVoidReturn(JavaMethod method) {
417: JavaReturn returnType = new JavaReturn("return", "void", null);
418: method.setReturn(returnType);
419: }
420:
421: private boolean isSameWrapperChild(QName in, QName out) {
422: if (!in.getLocalPart().equals(out.getLocalPart())) {
423: return false;
424: }
425:
426: if (!in.getNamespaceURI().equals(out.getNamespaceURI())) {
427: return false;
428: }
429: return true;
430: }
431:
432: private JavaParameter getParameterFromQName(QName wrapperElement,
433: QName item, JavaType.Style style, MessagePartInfo part) {
434:
435: String fullJavaName = "";
436:
437: fullJavaName = this .dataBinding.getWrappedElementType(
438: wrapperElement, item);
439:
440: String targetNamespace = item.getNamespaceURI();
441:
442: String jpname = ProcessorUtil.mangleNameToVariableName(item
443: .getLocalPart());
444: JavaParameter parameter = new JavaParameter(jpname,
445: fullJavaName, targetNamespace);
446: parameter.setStyle(style);
447: parameter.setQName(item);
448:
449: parameter.setDefaultValueWriter(ProcessorUtil
450: .getDefaultValueWriterForWrappedElement(part, context,
451: item));
452:
453: if (style == JavaType.Style.OUT
454: || style == JavaType.Style.INOUT) {
455: parameter.setHolder(true);
456: parameter
457: .setHolderName(javax.xml.ws.Holder.class.getName());
458: String holderClass = fullJavaName;
459: if (JAXBUtils.holderClass(fullJavaName) != null) {
460: holderClass = JAXBUtils.holderClass(fullJavaName)
461: .getName();
462: }
463: parameter.setClassName(holderClass);
464: }
465: return parameter;
466:
467: }
468:
469: private JavaReturn getReturnFromQName(QName element,
470: MessagePartInfo part) {
471:
472: String fullJavaName = "";
473: String simpleJavaName = "";
474: fullJavaName = this .dataBinding.getWrappedElementType(part
475: .getElementQName(), element);
476: simpleJavaName = fullJavaName;
477:
478: int index = fullJavaName.lastIndexOf(".");
479:
480: if (index > -1) {
481: simpleJavaName = fullJavaName.substring(index);
482: }
483:
484: String targetNamespace = "";
485: if (isHeader(part)) {
486: targetNamespace = part.getMessageInfo().getOperation()
487: .getInterface().getService().getTargetNamespace();
488: } else {
489: targetNamespace = element.getNamespaceURI();
490: }
491:
492: String jpname = ProcessorUtil
493: .mangleNameToVariableName(simpleJavaName);
494: JavaReturn returnType = new JavaReturn(jpname, fullJavaName,
495: targetNamespace);
496:
497: returnType.setDefaultValueWriter(ProcessorUtil
498: .getDefaultValueWriterForWrappedElement(part, context,
499: element));
500:
501: returnType.setQName(element);
502: returnType.setStyle(JavaType.Style.OUT);
503: return returnType;
504: }
505:
506: private boolean isHeader(final MessagePartInfo part) {
507: return Boolean.TRUE.equals(part.getProperty(HEADER));
508: }
509:
510: private void buildParamModelsWithoutOrdering(JavaMethod method,
511: MessageInfo inputMessage, MessageInfo outputMessage)
512: throws ToolException {
513: if (inputMessage != null) {
514: if (method.isWrapperStyle()) {
515: processWrappedInput(method, inputMessage);
516: } else {
517: processInput(method, inputMessage);
518: }
519: }
520: if (outputMessage == null) {
521: processReturn(method, null);
522: } else {
523: if (method.isWrapperStyle()) {
524: processWrappedOutput(method, inputMessage,
525: outputMessage);
526: } else {
527: processOutput(method, inputMessage, outputMessage);
528: }
529: }
530: }
531:
532: @SuppressWarnings("unchecked")
533: private void buildParamModelsWithOrdering(JavaMethod method,
534: MessageInfo inputMessage, MessageInfo outputMessage,
535: List<String> parameterList) throws ToolException {
536:
537: Map<QName, MessagePartInfo> inputPartsMap = inputMessage
538: .getMessagePartsMap();
539:
540: Map<QName, MessagePartInfo> outputPartsMap = outputMessage
541: .getMessagePartsMap();
542:
543: List<MessagePartInfo> inputParts = inputMessage
544: .getMessageParts();
545: List<MessagePartInfo> outputParts = outputMessage
546: .getMessageParts();
547:
548: List<MessagePartInfo> inputUnlistedParts = new ArrayList<MessagePartInfo>();
549: List<MessagePartInfo> outputUnlistedParts = new ArrayList<MessagePartInfo>();
550:
551: for (MessagePartInfo part : inputParts) {
552: if (!parameterList.contains(part.getName().getLocalPart())) {
553: inputUnlistedParts.add(part);
554: }
555: }
556:
557: if (isRequestResponse(method)) {
558: for (MessagePartInfo part : outputParts) {
559: if (!parameterList.contains(part.getName()
560: .getLocalPart())) {
561: MessagePartInfo inpart = inputMessage
562: .getMessagePart(part.getName());
563: if (inpart == null
564: || (inpart != null && !isSamePart(inpart,
565: part))) {
566: outputUnlistedParts.add(part);
567: }
568: }
569: }
570:
571: if (outputUnlistedParts.size() == 1) {
572: processReturn(method, outputUnlistedParts.get(0));
573: outputPartsMap.remove(outputUnlistedParts.get(0));
574: outputUnlistedParts.clear();
575: } else {
576: processReturn(method, null);
577: }
578: }
579:
580: // now create list of paramModel with parts
581: // first for the ordered list
582: int index = 0;
583: int size = parameterList.size();
584: while (index < size) {
585: String partName = parameterList.get(index);
586: MessagePartInfo part = inputPartsMap.get(inputMessage
587: .getMessagePartQName(partName));
588: JavaType.Style style = JavaType.Style.IN;
589: if (part == null) {
590: part = outputPartsMap.get(inputMessage
591: .getMessagePartQName(partName));
592: style = JavaType.Style.OUT;
593: } else if (outputPartsMap.get(inputMessage
594: .getMessagePartQName(partName)) != null
595: && isSamePart(part, outputPartsMap.get(inputMessage
596: .getMessagePartQName(partName)))) {
597: style = JavaType.Style.INOUT;
598: }
599: if (part != null) {
600: addParameter(method, getParameterFromPart(part, style));
601: }
602: index++;
603: }
604: // now from unlisted input parts
605: for (MessagePartInfo part : inputUnlistedParts) {
606: addParameter(method, getParameterFromPart(part,
607: JavaType.Style.IN));
608: }
609: // now from unlisted output parts
610: for (MessagePartInfo part : outputUnlistedParts) {
611: addParameter(method, getParameterFromPart(part,
612: JavaType.Style.INOUT));
613: }
614: }
615:
616: private boolean isSamePart(MessagePartInfo part1,
617: MessagePartInfo part2) {
618: QName qname1 = part1.getElementQName();
619: QName qname2 = part2.getElementQName();
620: if (qname1 != null && qname2 != null) {
621: return qname1.equals(qname2);
622: }
623: qname1 = part1.getTypeQName();
624: qname2 = part2.getTypeQName();
625: if (qname1 != null && qname2 != null) {
626: return qname1.equals(qname2);
627: }
628: return false;
629: }
630:
631: @SuppressWarnings("unchecked")
632: private boolean isValidOrdering(List<String> parameterOrder,
633: MessageInfo inputMessage, MessageInfo outputMessage) {
634: Iterator<String> params = parameterOrder.iterator();
635:
636: List<MessagePartInfo> inputParts = inputMessage
637: .getMessageParts();
638: List<MessagePartInfo> outputParts = outputMessage
639: .getMessageParts();
640:
641: boolean partFound = false;
642:
643: while (params.hasNext()) {
644: String param = params.next();
645: partFound = false;
646: for (MessagePartInfo part : inputParts) {
647: if (param.equals(part.getName().getLocalPart())) {
648: partFound = true;
649: break;
650: }
651: }
652: // if not found, check output parts
653: if (!partFound) {
654: for (MessagePartInfo part : outputParts) {
655: if (param.equals(part.getName().getLocalPart())) {
656: partFound = true;
657: break;
658: }
659: }
660: }
661: if (!partFound) {
662: break;
663: }
664: }
665: return partFound;
666: }
667: }
|