0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019:
0020: package org.apache.axis2.jaxws.description.impl;
0021:
0022: import org.apache.axis2.AxisFault;
0023: import org.apache.axis2.description.AxisOperation;
0024: import org.apache.axis2.description.AxisOperationFactory;
0025: import org.apache.axis2.description.AxisService;
0026: import org.apache.axis2.jaxws.ExceptionFactory;
0027: import org.apache.axis2.jaxws.description.EndpointDescription;
0028: import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
0029: import org.apache.axis2.jaxws.description.EndpointInterfaceDescriptionJava;
0030: import org.apache.axis2.jaxws.description.EndpointInterfaceDescriptionWSDL;
0031: import org.apache.axis2.jaxws.description.OperationDescription;
0032: import org.apache.axis2.jaxws.description.ServiceDescriptionWSDL;
0033: import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
0034: import org.apache.axis2.jaxws.description.builder.MDQConstants;
0035: import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
0036: import org.apache.axis2.wsdl.WSDLConstants;
0037: import org.apache.commons.logging.Log;
0038: import org.apache.commons.logging.LogFactory;
0039:
0040: import javax.jws.WebService;
0041: import javax.jws.soap.SOAPBinding;
0042: import javax.wsdl.Definition;
0043: import javax.wsdl.PortType;
0044: import javax.xml.namespace.QName;
0045: import java.lang.reflect.Method;
0046: import java.lang.reflect.Modifier;
0047: import java.util.ArrayList;
0048: import java.util.HashMap;
0049: import java.util.Iterator;
0050: import java.util.List;
0051:
0052: //import org.apache.log4j.BasicConfigurator;
0053:
0054: /** @see ../EndpointInterfaceDescription */
0055: class EndpointInterfaceDescriptionImpl implements
0056: EndpointInterfaceDescription, EndpointInterfaceDescriptionJava,
0057: EndpointInterfaceDescriptionWSDL {
0058: private EndpointDescriptionImpl parentEndpointDescription;
0059: private ArrayList<OperationDescription> operationDescriptions = new ArrayList<OperationDescription>();
0060: // This may be an actual Service Endpoint Interface -OR- it may be a service implementation class that did not
0061: // specify an @WebService.endpointInterface.
0062: private Class seiClass;
0063: private DescriptionBuilderComposite dbc;
0064:
0065: //Logging setup
0066: private static final Log log = LogFactory
0067: .getLog(EndpointInterfaceDescriptionImpl.class);
0068:
0069: // ===========================================
0070: // ANNOTATION related information
0071: // ===========================================
0072:
0073: // ANNOTATION: @WebService
0074: private WebService webServiceAnnotation;
0075: private String webServiceTargetNamespace;
0076: private String webService_Name;
0077:
0078: // ANNOTATION: @SOAPBinding
0079: // Note this is the Type-level annotation. See OperationDescription for the Method-level annotation
0080: private SOAPBinding soapBindingAnnotation;
0081: // TODO: Should this be using the jaxws annotation values or should that be wrappered?
0082: private javax.jws.soap.SOAPBinding.Style soapBindingStyle;
0083: // Default value per JSR-181 MR Sec 4.7 "Annotation: javax.jws.soap.SOAPBinding" pg 28
0084: public static final javax.jws.soap.SOAPBinding.Style SOAPBinding_Style_DEFAULT = javax.jws.soap.SOAPBinding.Style.DOCUMENT;
0085: private javax.jws.soap.SOAPBinding.Use soapBindingUse;
0086: // Default value per JSR-181 MR Sec 4.7 "Annotation: javax.jws.soap.SOAPBinding" pg 28
0087: public static final javax.jws.soap.SOAPBinding.Use SOAPBinding_Use_DEFAULT = javax.jws.soap.SOAPBinding.Use.LITERAL;
0088: private javax.jws.soap.SOAPBinding.ParameterStyle soapParameterStyle;
0089: // Default value per JSR-181 MR Sec 4.7 "Annotation: javax.jws.soap.SOAPBinding" pg 28
0090: public static final javax.jws.soap.SOAPBinding.ParameterStyle SOAPBinding_ParameterStyle_DEFAULT = javax.jws.soap.SOAPBinding.ParameterStyle.WRAPPED;
0091:
0092: void addOperation(OperationDescription operation) {
0093: operationDescriptions.add(operation);
0094: }
0095:
0096: EndpointInterfaceDescriptionImpl(Class sei,
0097: EndpointDescriptionImpl parent) {
0098: seiClass = sei;
0099: parentEndpointDescription = parent;
0100:
0101: // Per JSR-181 all methods on the SEI are mapped to operations regardless
0102: // of whether they include an @WebMethod annotation. That annotation may
0103: // be present to customize the mapping, but is not required (p14)
0104: // TODO: Testcases that do and do not include @WebMethod anno
0105: for (Method method : getSEIMethods(seiClass)) {
0106: OperationDescription operation = new OperationDescriptionImpl(
0107: method, this );
0108: addOperation(operation);
0109: }
0110: }
0111:
0112: /**
0113: * Build from AxisService
0114: *
0115: * @param parent
0116: */
0117: EndpointInterfaceDescriptionImpl(EndpointDescriptionImpl parent) {
0118: parentEndpointDescription = parent;
0119: AxisService axisService = parentEndpointDescription
0120: .getAxisService();
0121: if (axisService != null) {
0122: ArrayList publishedOperations = axisService
0123: .getPublishedOperations();
0124: Iterator operationsIterator = publishedOperations
0125: .iterator();
0126: while (operationsIterator.hasNext()) {
0127: AxisOperation axisOperation = (AxisOperation) operationsIterator
0128: .next();
0129: addOperation(new OperationDescriptionImpl(
0130: axisOperation, this ));
0131: }
0132: }
0133: }
0134:
0135: /**
0136: * Construct as Provider-based endpoint which does not have specific WSDL operations. Since there
0137: * are no specific WSDL operations in this case, there will be a single generic operation that
0138: * will accept any incoming operation.
0139: *
0140: * @param dbc
0141: * @param parent
0142: */
0143: EndpointInterfaceDescriptionImpl(DescriptionBuilderComposite dbc,
0144: EndpointDescriptionImpl parent) {
0145: if (log.isDebugEnabled()) {
0146: log
0147: .debug("Creating a EndpointInterfaceDescription for a generic WSDL-less provider");
0148: }
0149: parentEndpointDescription = parent;
0150: this .dbc = dbc;
0151:
0152: // Construct the generic provider AxisOperation to use then construct
0153: // an OperactionDescription for it.
0154: AxisOperation genericProviderAxisOp = null;
0155: try {
0156: genericProviderAxisOp = AxisOperationFactory
0157: .getOperationDescription(WSDLConstants.WSDL20_2006Constants.MEP_URI_IN_OUT);
0158: } catch (AxisFault e) {
0159: if (log.isDebugEnabled()) {
0160: log
0161: .debug(
0162: "Unable to build AxisOperation for generic Provider; caught exception.",
0163: e);
0164: }
0165: // TODO: NLS & RAS
0166: throw ExceptionFactory.makeWebServiceException(
0167: "Caught exception trying to create AxisOperation",
0168: e);
0169: }
0170:
0171: genericProviderAxisOp.setName(new QName(
0172: JAXWS_NOWSDL_PROVIDER_OPERATION_NAME));
0173: OperationDescription opDesc = new OperationDescriptionImpl(
0174: genericProviderAxisOp, this );
0175:
0176: addOperation(opDesc);
0177: AxisService axisService = getEndpointDescription()
0178: .getAxisService();
0179: axisService.addOperation(genericProviderAxisOp);
0180: }
0181:
0182: /**
0183: * Build an EndpointInterfaceDescription from a DescriptionBuilderComposite. This EID has
0184: * WSDL operations associated with it. It could represent an SEI-based endpoint built from
0185: * WSDL or annotations, OR it could represent a Provider-based enpoint built from WSDL. It will
0186: * not represent a Provider-based endpoint built without WSDL (which does not know about
0187: * specific WSDL operations). For that type of EID, see:
0188: * @see #EndpointInterfaceDescriptionImpl(DescriptionBuilderComposite dbc, EndpointDescriptionImpl parent)
0189: * @param dbc
0190: * @param isClass
0191: * @param parent
0192: */
0193: EndpointInterfaceDescriptionImpl(DescriptionBuilderComposite dbc,
0194: boolean isClass, EndpointDescriptionImpl parent) {
0195:
0196: parentEndpointDescription = parent;
0197: this .dbc = dbc;
0198:
0199: //TODO: yikes! ...too much redirection, consider setting this in higher level
0200: getEndpointDescription().getAxisService().setTargetNamespace(
0201: getEndpointDescriptionImpl().getTargetNamespace());
0202:
0203: //TODO: Determine if the isClass parameter is really necessary
0204:
0205: // Per JSR-181 all methods on the SEI are mapped to operations regardless
0206: // of whether they include an @WebMethod annotation. That annotation may
0207: // be present to customize the mapping, but is not required (p14)
0208:
0209: // TODO: Testcases that do and do not include @WebMethod anno
0210:
0211: //We are processing the SEI composite
0212: //For every MethodDescriptionComposite in this list, call OperationDescription
0213: //constructor for it, then add this operation
0214:
0215: //Retrieve the relevent method composites for this dbc (and those in the superclass chain)
0216: Iterator<MethodDescriptionComposite> iter = retrieveReleventMethods(dbc);
0217:
0218: if (log.isDebugEnabled())
0219: log
0220: .debug("EndpointInterfaceDescriptionImpl: Finished retrieving methods");
0221: MethodDescriptionComposite mdc = null;
0222:
0223: while (iter.hasNext()) {
0224: mdc = iter.next();
0225:
0226: //TODO: Verify that this classname is truly always the wrapper class
0227: mdc.setDeclaringClass(dbc.getClassName());
0228:
0229: // Only add if it is a method that would be or is in the WSDL i.e.
0230: // don't create an OperationDescriptor for the MDC representing the
0231: // constructor
0232: if (DescriptionUtils.createOperationDescription(mdc
0233: .getMethodName())) {
0234: //First check if this operation already exists on the AxisService, if so
0235: //then use that in the description hierarchy
0236:
0237: AxisService axisService = getEndpointDescription()
0238: .getAxisService();
0239: AxisOperation axisOperation = axisService
0240: .getOperation(OperationDescriptionImpl
0241: .determineOperationQName(mdc));
0242:
0243: OperationDescription operation = new OperationDescriptionImpl(
0244: mdc, this , axisOperation);
0245:
0246: if (axisOperation == null) {
0247: // This axisOperation did not already exist on the AxisService, and so was created
0248: // with the OperationDescription, so we need to add the operation to the service
0249: ((OperationDescriptionImpl) operation)
0250: .addToAxisService(axisService);
0251: }
0252:
0253: if (log.isDebugEnabled())
0254: log.debug("EID: Just added operation= "
0255: + operation.getOperationName());
0256: addOperation(operation);
0257: }
0258:
0259: }
0260:
0261: if (log.isDebugEnabled())
0262: log
0263: .debug("EndpointInterfaceDescriptionImpl: Finished Adding operations");
0264:
0265: //TODO: Need to process the other annotations that can exist, on the server side
0266: // and at the class level.
0267: // They are, as follows:
0268: // HandlerChain (181)
0269: // SoapBinding (181)
0270: // WebServiceRefAnnot (List) (JAXWS)
0271: // BindingTypeAnnot (JAXWS Sec. 7.8 -- Used to set either the AS.endpoint, or AS.SoapNSUri)
0272: // WebServiceContextAnnot (JAXWS via injection)
0273: }
0274:
0275: private static Method[] getSEIMethods(Class sei) {
0276: // Per JSR-181 all methods on the SEI are mapped to operations regardless
0277: // of whether they include an @WebMethod annotation. That annotation may
0278: // be present to customize the mapping, but is not required (p14)
0279: Method[] seiMethods = sei.getMethods();
0280: ArrayList methodList = new ArrayList();
0281: if (sei != null) {
0282: for (Method method : seiMethods) {
0283:
0284: if (method.getDeclaringClass().getName().equals(
0285: "java.lang.Object")) {
0286: continue;
0287: }
0288: methodList.add(method);
0289: if (!Modifier.isPublic(method.getModifiers())) {
0290: // JSR-181 says methods must be public (p14)
0291: // TODO NLS
0292: ExceptionFactory
0293: .makeWebServiceException("SEI methods must be public");
0294: }
0295: // TODO: other validation per JSR-181
0296: }
0297:
0298: }
0299: return (Method[]) methodList.toArray(new Method[methodList
0300: .size()]);
0301: // return seiMethods;
0302: }
0303:
0304: /**
0305: * Update a previously created EndpointInterfaceDescription with information from an annotated
0306: * SEI. This should only be necessary when the this was created with WSDL. In this case, the
0307: * information from the WSDL is augmented based on the annotated SEI.
0308: *
0309: * @param sei
0310: */
0311: void updateWithSEI(Class sei) {
0312: if (seiClass != null && seiClass != sei)
0313: // TODO: It probably is invalid to try reset the SEI; but this isn't the right error processing
0314: throw new UnsupportedOperationException(
0315: "The seiClass is already set; reseting it is not supported");
0316: else if (seiClass != null && seiClass == sei)
0317: // We've already done the necessary updates for this SEI
0318: return;
0319: else if (sei != null) {
0320: seiClass = sei;
0321: // Update (or possibly add) the OperationDescription for each of the methods on the SEI.
0322: for (Method seiMethod : getSEIMethods(seiClass)) {
0323:
0324: if (getOperation(seiMethod) != null) {
0325: // If an OpDesc already exists with this java method set on it, then the OpDesc has already
0326: // been updated for this method, so skip it.
0327: continue;
0328: }
0329: // At this point (for now at least) the operations were created with WSDL previously.
0330: // If they had been created from an annotated class and no WSDL, then the seiClass would have
0331: // already been set so we would have taken other branches in this if test. (Note this could
0332: // change once AxisServices can be built from annotations by the ServiceDescription class).
0333: // Since the operations were created from WSDL, they will not have a java method, which
0334: // comes from the SEI, set on them yet.
0335: //
0336: // Another consideration is that currently Axis2 does not support overloaded WSDL operations.
0337: // That means there will only be one OperationDesc build from WSDL. Still another consideration is
0338: // that the JAXWS async methods which may exist on the SEI will NOT exist in the WSDL. An example
0339: // of these methods for the WSDL operation:
0340: // String echo(String)
0341: // optionally generated JAX-WS SEI methods from the tooling; take note of the annotation specifying the
0342: // operation name
0343: // @WebMethod(operationName="echo" ...)
0344: // Response<String> echoStringAsync(String)
0345: // @WebMethod(operationName="echo" ...)
0346: // Future<?> echoStringAsync(String, AsyncHandler)
0347: //
0348: // So given all the above, the code does the following based on the operation QName
0349: // (which might also be the java method name; see determineOperationQName for details)
0350: // (1) If an operationDesc does not exist, add it.
0351: // (2) If an operationDesc does exist but does not have a java method set on it, set it
0352: // (3) If an operationDesc does exist and has a java method set on it already, add a new one.
0353: //
0354: // TODO: May need to change when Axis2 supports overloaded WSDL operations
0355: // TODO: May need to change when ServiceDescription can build an AxisService from annotations
0356:
0357: // Get the QName for this java method and then update (or add) the appropriate OperationDescription
0358: // See comments below for imporant notes about the current implementation.
0359: // NOTE ON OVERLOADED OPERATIONS
0360: // Axis2 does NOT currently support overloading WSDL operations.
0361: QName seiOperationQName = OperationDescriptionImpl
0362: .determineOperationQName(seiMethod);
0363: OperationDescription[] updateOpDesc = getOperation(seiOperationQName);
0364: if (updateOpDesc == null || updateOpDesc.length == 0) {
0365: // This operation wasn't defined in the WSDL. Note that the JAX-WS async methods
0366: // which are defined on the SEI are not defined as operations in the WSDL.
0367: // Although they usually specific the same OperationName as the WSDL operation,
0368: // there may be cases where they do not.
0369: // TODO: Is this path an error path, or can the async methods specify different operation names than the
0370: // WSDL operation?
0371: OperationDescription operation = new OperationDescriptionImpl(
0372: seiMethod, this );
0373: addOperation(operation);
0374: } else {
0375: // Currently Axis2 does not support overloaded operations. That means that even if the WSDL
0376: // defined overloaded operations, there would still only be a single AxisOperation, and it
0377: // would be the last operation encounterd.
0378: // HOWEVER the generated JAX-WS async methods (see above) may (will always?) have the same
0379: // operation name and so will come down this path; they need to be added.
0380: // TODO: When Axis2 starts supporting overloaded operations, then this logic will need to be changed
0381: // TODO: Should we verify that these are the async methods before adding them, and treat it as an error otherwise?
0382:
0383: // Loop through all the opdescs; if one doesn't currently have a java method set, set it
0384: // If all have java methods set, then add a new one. Assume we'll need to add a new one.
0385: boolean addOpDesc = true;
0386: for (OperationDescription checkOpDesc : updateOpDesc) {
0387: if (checkOpDesc.getSEIMethod() == null) {
0388: // TODO: Should this be checking (somehow) that the signature matches? Probably not an issue until overloaded WSDL ops are supported.
0389:
0390: //Make sure that this is not one of the 'async' methods associated with
0391: //this operation. If it is, let it be created as its own opDesc.
0392: if (!DescriptionUtils.isAsync(seiMethod)) {
0393: ((OperationDescriptionImpl) checkOpDesc)
0394: .setSEIMethod(seiMethod);
0395: addOpDesc = false;
0396: break;
0397: }
0398: }
0399: }
0400: if (addOpDesc) {
0401: OperationDescription operation = new OperationDescriptionImpl(
0402: seiMethod, this );
0403: addOperation(operation);
0404: }
0405: }
0406: }
0407: }
0408: }
0409:
0410: /**
0411: * Return the OperationDescriptions corresponding to a particular Java method name. Note that an
0412: * array is returned because a method could be overloaded.
0413: *
0414: * @param javaMethodName String representing a Java Method Name
0415: * @return
0416: */
0417: // FIXME: This is confusing; some getOperations use the QName from the WSDL or annotation; this one uses the java method name; rename this signature I think; add on that takes a String but does a QName lookup against the WSDL/Annotation
0418: public OperationDescription[] getOperationForJavaMethod(
0419: String javaMethodName) {
0420: if (DescriptionUtils.isEmpty(javaMethodName)) {
0421: return null;
0422: }
0423:
0424: ArrayList<OperationDescription> matchingOperations = new ArrayList<OperationDescription>();
0425: for (OperationDescription operation : getOperations()) {
0426: if (javaMethodName.equals(operation.getJavaMethodName())) {
0427: matchingOperations.add(operation);
0428: }
0429: }
0430:
0431: if (matchingOperations.size() == 0)
0432: return null;
0433: else
0434: return matchingOperations
0435: .toArray(new OperationDescription[0]);
0436: }
0437:
0438: /**
0439: * Return the OperationDesription (only one) corresponding to the OperationName passed in.
0440: *
0441: * @param operationName
0442: * @return
0443: */
0444: public OperationDescription getOperation(String operationName) {
0445: if (DescriptionUtils.isEmpty(operationName)) {
0446: return null;
0447: }
0448:
0449: OperationDescription matchingOperation = null;
0450: for (OperationDescription operation : getOperations()) {
0451: if (operationName.equals(operation.getOperationName())) {
0452: matchingOperation = operation;
0453: break;
0454: }
0455: }
0456: return matchingOperation;
0457: }
0458:
0459: public OperationDescription[] getOperations() {
0460: return operationDescriptions
0461: .toArray(new OperationDescription[0]);
0462: }
0463:
0464: EndpointDescriptionImpl getEndpointDescriptionImpl() {
0465: return (EndpointDescriptionImpl) parentEndpointDescription;
0466: }
0467:
0468: public EndpointDescription getEndpointDescription() {
0469: return parentEndpointDescription;
0470: }
0471:
0472: /**
0473: * Return an array of Operations given an operation QName. Note that an array is returned since
0474: * a WSDL operation may be overloaded per JAX-WS.
0475: *
0476: * @param operationQName
0477: * @return
0478: */
0479: public OperationDescription[] getOperation(QName operationQName) {
0480: OperationDescription[] returnOperations = null;
0481: if (!DescriptionUtils.isEmpty(operationQName)) {
0482: ArrayList<OperationDescription> matchingOperations = new ArrayList<OperationDescription>();
0483: OperationDescription[] allOperations = getOperations();
0484: for (OperationDescription operation : allOperations) {
0485: if (operation.getName().getLocalPart().equals(
0486: operationQName.getLocalPart())) {
0487: matchingOperations.add(operation);
0488: }
0489: }
0490: // Only return an array if there's anything in it
0491: if (matchingOperations.size() > 0) {
0492: returnOperations = matchingOperations
0493: .toArray(new OperationDescription[0]);
0494: }
0495: }
0496: return returnOperations;
0497: }
0498:
0499: /* (non-Javadoc)
0500: * @see org.apache.axis2.jaxws.description.EndpointInterfaceDescription#getDispatchableOperation(QName operationQName)
0501: */
0502: public OperationDescription[] getDispatchableOperation(
0503: QName operationQName) {
0504: OperationDescription[] returnOperations = null;
0505: OperationDescription[] allMatchingOperations = getOperation(operationQName);
0506: if (allMatchingOperations != null
0507: && allMatchingOperations.length > 0) {
0508: ArrayList<OperationDescription> dispatchableOperations = new ArrayList<OperationDescription>();
0509: for (OperationDescription operation : allMatchingOperations) {
0510: if (!operation.isJAXWSAsyncClientMethod()) {
0511: dispatchableOperations.add(operation);
0512: }
0513: }
0514:
0515: if (dispatchableOperations.size() > 0) {
0516: returnOperations = dispatchableOperations
0517: .toArray(new OperationDescription[0]);
0518: }
0519: }
0520: return returnOperations;
0521: }
0522:
0523: /* (non-Javadoc)
0524: * @see org.apache.axis2.jaxws.description.EndpointInterfaceDescription#getDispatchableOperations()
0525: */
0526: public OperationDescription[] getDispatchableOperations() {
0527: OperationDescription[] returnOperations = null;
0528: OperationDescription[] allMatchingOperations = getOperations();
0529: if (allMatchingOperations != null
0530: && allMatchingOperations.length > 0) {
0531: ArrayList<OperationDescription> dispatchableOperations = new ArrayList<OperationDescription>();
0532: for (OperationDescription operation : allMatchingOperations) {
0533: if (!operation.isJAXWSAsyncClientMethod()) {
0534: dispatchableOperations.add(operation);
0535: }
0536: }
0537:
0538: if (dispatchableOperations.size() > 0) {
0539: returnOperations = dispatchableOperations
0540: .toArray(new OperationDescription[0]);
0541: }
0542: }
0543: return returnOperations;
0544: }
0545:
0546: /**
0547: * Return an OperationDescription for the corresponding SEI method. Note that this ONLY works
0548: * if the OperationDescriptions were created from introspecting an SEI. If the were created
0549: * with a WSDL then use the getOperation(QName) method, which can return > 1 operation.
0550: *
0551: * @param seiMethod The java.lang.Method from the SEI for which an OperationDescription is
0552: * wanted
0553: * @return
0554: */
0555: public OperationDescription getOperation(Method seiMethod) {
0556: OperationDescription returnOperation = null;
0557: if (seiMethod != null) {
0558: OperationDescription[] allOperations = getOperations();
0559: for (OperationDescription operation : allOperations) {
0560: if (operation.getSEIMethod() != null
0561: && operation.getSEIMethod().equals(seiMethod)) {
0562: returnOperation = operation;
0563: }
0564: }
0565: }
0566: return returnOperation;
0567: }
0568:
0569: public Class getSEIClass() {
0570: return seiClass;
0571: }
0572:
0573: // Annotation-realted getters
0574:
0575: // ========================================
0576: // SOAP Binding annotation realted methods
0577: // ========================================
0578: public SOAPBinding getAnnoSoapBinding() {
0579: // TODO: Test with sei Null, not null, SOAP Binding annotated, not annotated
0580:
0581: if (soapBindingAnnotation == null) {
0582: if (dbc != null) {
0583: soapBindingAnnotation = dbc.getSoapBindingAnnot();
0584: } else {
0585: if (seiClass != null) {
0586: soapBindingAnnotation = (SOAPBinding) seiClass
0587: .getAnnotation(SOAPBinding.class);
0588: }
0589: }
0590: }
0591: return soapBindingAnnotation;
0592: }
0593:
0594: public javax.jws.soap.SOAPBinding.Style getSoapBindingStyle() {
0595: // REVIEW: Implement WSDL/Anno merge
0596: return getAnnoSoapBindingStyle();
0597: }
0598:
0599: public javax.jws.soap.SOAPBinding.Style getAnnoSoapBindingStyle() {
0600: if (soapBindingStyle == null) {
0601: if (getAnnoSoapBinding() != null
0602: && getAnnoSoapBinding().style() != null) {
0603: soapBindingStyle = getAnnoSoapBinding().style();
0604: } else {
0605: soapBindingStyle = SOAPBinding_Style_DEFAULT;
0606: }
0607: }
0608: return soapBindingStyle;
0609: }
0610:
0611: public javax.jws.soap.SOAPBinding.Use getSoapBindingUse() {
0612: // REVIEW: Implement WSDL/Anno merge
0613: return getAnnoSoapBindingUse();
0614: }
0615:
0616: public javax.jws.soap.SOAPBinding.Use getAnnoSoapBindingUse() {
0617: if (soapBindingUse == null) {
0618: if (getAnnoSoapBinding() != null
0619: && getAnnoSoapBinding().use() != null) {
0620: soapBindingUse = getAnnoSoapBinding().use();
0621: } else {
0622: soapBindingUse = SOAPBinding_Use_DEFAULT;
0623: }
0624: }
0625: return soapBindingUse;
0626: }
0627:
0628: public javax.jws.soap.SOAPBinding.ParameterStyle getSoapBindingParameterStyle() {
0629: // REVIEW: Implement WSDL/Anno merge
0630: return getAnnoSoapBindingParameterStyle();
0631: }
0632:
0633: public javax.jws.soap.SOAPBinding.ParameterStyle getAnnoSoapBindingParameterStyle() {
0634: if (soapParameterStyle == null) {
0635: if (getAnnoSoapBinding() != null
0636: && getAnnoSoapBinding().parameterStyle() != null) {
0637: soapParameterStyle = getAnnoSoapBinding()
0638: .parameterStyle();
0639: } else {
0640: soapParameterStyle = SOAPBinding_ParameterStyle_DEFAULT;
0641: }
0642: }
0643: return soapParameterStyle;
0644: }
0645:
0646: /*
0647: * Returns a non-null (possibly empty) list of MethodDescriptionComposites
0648: */
0649: Iterator<MethodDescriptionComposite> retrieveReleventMethods(
0650: DescriptionBuilderComposite dbc) {
0651:
0652: /*
0653: * Depending on whether this is an implicit SEI or an actual SEI, Gather up and build a
0654: * list of MDC's. If this is an actual SEI, then starting with this DBC, build a list of all
0655: * MDC's that are public methods in the chain of extended classes.
0656: * If this is an implicit SEI, then starting with this DBC,
0657: * 1. If a false exclude is found, then take only those that have false excludes
0658: * 2. Assuming no false excludes, take all public methods that don't have exclude == true
0659: * 3. For each super class, if 'WebService' present, take all MDC's according to rules 1&2
0660: * But, if WebService not present, grab only MDC's that are annotated.
0661: */
0662: if (log.isTraceEnabled()) {
0663: log.trace("retrieveReleventMethods: Enter");
0664: }
0665:
0666: ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>();
0667:
0668: if (dbc.isInterface()) {
0669:
0670: retrieveList.addAll(retrieveSEIMethodsChain(dbc));
0671:
0672: } else {
0673: //this is an implied SEI...rules are more complicated
0674:
0675: retrieveList = retrieveImplicitSEIMethods(dbc);
0676:
0677: //Now, continue to build this list with relevent methods in the chain of
0678: //superclasses. If the logic for processing superclasses is the same as for
0679: //the original SEI, then we can combine this code with above code. But, its possible
0680: //the logic is different for superclasses...keeping separate for now.
0681: DescriptionBuilderComposite tempDBC = dbc;
0682:
0683: while (!DescriptionUtils.isEmpty(tempDBC
0684: .getSuperClassName())) {
0685:
0686: //verify that this superclass name is not
0687: // java.lang.object, if so, then we're done processing
0688: if (DescriptionUtils.javifyClassName(
0689: tempDBC.getSuperClassName()).equals(
0690: MDQConstants.OBJECT_CLASS_NAME))
0691: break;
0692:
0693: DescriptionBuilderComposite super DBC = getEndpointDescriptionImpl()
0694: .getServiceDescriptionImpl().getDBCMap().get(
0695: tempDBC.getSuperClassName());
0696:
0697: if (log.isTraceEnabled())
0698: log.trace("superclass name for this DBC is:"
0699: + tempDBC.getSuperClassName());
0700:
0701: //Verify that we can find the SEI in the composite list
0702: if (super DBC == null) {
0703: throw ExceptionFactory
0704: .makeWebServiceException("EndpointInterfaceDescriptionImpl: cannot find super class that was specified for this class");
0705: }
0706:
0707: if (super DBC.getWebServiceAnnot() != null) {
0708: //Now, gather the list of Methods just like we do for the lowest subclass
0709: retrieveList
0710: .addAll(retrieveImplicitSEIMethods(super DBC));
0711: } else {
0712: //This superclass does not contain a WebService annotation, add only the
0713: //methods that are annotated with WebMethod
0714:
0715: Iterator<MethodDescriptionComposite> iterMethod = dbc
0716: .getMethodDescriptionsList().iterator();
0717:
0718: while (iterMethod.hasNext()) {
0719: MethodDescriptionComposite mdc = iterMethod
0720: .next();
0721:
0722: if (!DescriptionUtils.isExcludeTrue(mdc)) {
0723: mdc.setDeclaringClass(super DBC
0724: .getClassName());
0725: retrieveList.add(mdc);
0726: }
0727: }
0728: }
0729: tempDBC = super DBC;
0730: } //Done with implied SEI's superclasses
0731: retrieveList = removeOverriddenMethods(retrieveList, dbc);
0732: }//Done with implied SEI's
0733:
0734: return retrieveList.iterator();
0735: }
0736:
0737: /**
0738: * This method will establish a <code>HashMap</code> that represents a class name of a composite
0739: * and an integer value for the entry. The integer represents the classes level in the Java
0740: * hierarchy. 0 represents the most basic class with n representing the highest level class.
0741: *
0742: * @param dbc - <code>DescriptionBuilderComposite</code>
0743: * @return - <code>HashMap</code>
0744: */
0745: private HashMap<String, Integer> getClassHierarchy(
0746: DescriptionBuilderComposite dbc) {
0747: HashMap<String, DescriptionBuilderComposite> dbcMap = getEndpointDescriptionImpl()
0748: .getServiceDescriptionImpl().getDBCMap();
0749: HashMap<String, Integer> hierarchyMap = new HashMap<String, Integer>();
0750: if (log.isDebugEnabled()) {
0751: log.debug("Putting class at base level: "
0752: + dbc.getClassName());
0753: }
0754: hierarchyMap.put(dbc.getClassName(), Integer.valueOf(0));
0755: DescriptionBuilderComposite super DBC = dbcMap.get((dbc
0756: .getSuperClassName()));
0757: int i = 1;
0758: while (super DBC != null
0759: && !super DBC.getClassName().equals("java.lang.Object")) {
0760: hierarchyMap.put(super DBC.getClassName(), Integer
0761: .valueOf(i));
0762: if (log.isDebugEnabled()) {
0763: log.debug("Putting class: " + super DBC.getClassName()
0764: + " at hierarchy rank: " + i);
0765: }
0766: i++;
0767: super DBC = dbcMap.get(super DBC.getSuperClassName());
0768: }
0769: return hierarchyMap;
0770: }
0771:
0772: /**
0773: * This method will loop through each method that was previously determined as being relevant to
0774: * the current composite. It will then drive the call to determine if this represents a method
0775: * that has been overridden. If it represents an overriding method declaration it will remove
0776: * the inherited methods from the list leaving only the most basic method declaration.
0777: *
0778: * @param methodList - <code>ArrayList</code> list of relevant methods
0779: * @param dbc - <code>DescriptionBuilderComposite</code> current composite
0780: * @return - <code>ArrayList</code>
0781: */
0782: private ArrayList<MethodDescriptionComposite> removeOverriddenMethods(
0783: ArrayList<MethodDescriptionComposite> methodList,
0784: DescriptionBuilderComposite dbc) {
0785: HashMap<String, Integer> hierarchyMap = getClassHierarchy(dbc);
0786: ArrayList<MethodDescriptionComposite> returnMethods = new ArrayList<MethodDescriptionComposite>();
0787: for (int i = 0; i < methodList.size(); i++) {
0788: if (notFound(returnMethods, methodList.get(i))) {
0789: returnMethods.add(getBaseMethod(methodList.get(i), i,
0790: methodList, hierarchyMap));
0791: }
0792:
0793: }
0794: return returnMethods;
0795: }
0796:
0797: /**
0798: * This method will loop through each method we have already identified as a base method and
0799: * compare the current method.
0800: *
0801: * @param mdcList - <code>ArrayList</code> identified base methods
0802: * @param mdc - <code>MethodDescriptionComposite</code> current method
0803: * @return - boolean
0804: */
0805: private boolean notFound(
0806: ArrayList<MethodDescriptionComposite> mdcList,
0807: MethodDescriptionComposite mdc) {
0808: for (MethodDescriptionComposite method : mdcList) {
0809: if (mdc.compare(method)) {
0810: return false;
0811: }
0812: }
0813: return true;
0814: }
0815:
0816: /**
0817: * This method is responsible for determining the most basic level of a method declaration in
0818: * the <code>DescriptionBuilderComposite</code> hierarchy.
0819: *
0820: * @param mdc - <code>MethodDescriptionComposite</code> current method
0821: * @param index - <code>int</code> current location in method list
0822: * @param methodList - <code>List</code> list of methods available on this composite
0823: * @param hierarchyMap - <code>HashMap</code> map that represents the hierarchy of the current
0824: * <code>DescriptionBuilderComposite</code>
0825: * @return - <code>MethodDescriptionComposite</code> most basic method declaration
0826: */
0827: private static MethodDescriptionComposite getBaseMethod(
0828: MethodDescriptionComposite mdc, int index,
0829: ArrayList<MethodDescriptionComposite> methodList,
0830: HashMap<String, Integer> hierarchyMap) {
0831: int baseLevel = hierarchyMap.get(mdc.getDeclaringClass());
0832: if (log.isDebugEnabled()) {
0833: log.debug("Base method: " + mdc.getMethodName()
0834: + " initial level: " + baseLevel);
0835: }
0836: for (; index < methodList.size(); index++) {
0837: MethodDescriptionComposite compareMDC = methodList
0838: .get(index);
0839: // If the two methods are the same method that means we have found an inherited
0840: // overridden case
0841: if (mdc.equals(compareMDC)) {
0842: if (log.isDebugEnabled()) {
0843: log.debug("Found equivalent methods: "
0844: + mdc.getMethodName());
0845: }
0846: // get the declaration level of the method we are comparing to
0847: int compareLevel = hierarchyMap.get(compareMDC
0848: .getDeclaringClass());
0849: // if the method was declared by a class in a lower level of the hierarchy it
0850: // becomes the method that we will compare other methods to
0851: if (compareLevel < baseLevel) {
0852: if (log.isDebugEnabled()) {
0853: log
0854: .debug("Found method lower in hierarchy chain: "
0855: + compareMDC.getMethodName()
0856: + " of class: "
0857: + compareMDC.getMethodName());
0858: }
0859: mdc = compareMDC;
0860: baseLevel = compareLevel;
0861: }
0862: }
0863: }
0864: return mdc;
0865: }
0866:
0867: /*
0868: * This is called when we know that this DBC is an implicit SEI
0869: */
0870: private ArrayList<MethodDescriptionComposite> retrieveImplicitSEIMethods(
0871: DescriptionBuilderComposite dbc) {
0872:
0873: ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>();
0874:
0875: retrieveList = DescriptionUtils
0876: .getMethodsWithFalseExclusions(dbc);
0877:
0878: //If this list is empty, then there are no false exclusions, so gather
0879: //all composites that don't have exclude == true
0880: //If the list is not empty, then it means we found at least one method with 'exclude==false'
0881: //so the list should contain only those methods
0882: if (retrieveList == null || retrieveList.size() == 0) {
0883: Iterator<MethodDescriptionComposite> iter = null;
0884: List<MethodDescriptionComposite> mdcList = dbc
0885: .getMethodDescriptionsList();
0886:
0887: if (mdcList != null) {
0888: iter = dbc.getMethodDescriptionsList().iterator();
0889: while (iter.hasNext()) {
0890: MethodDescriptionComposite mdc = iter.next();
0891:
0892: if (!DescriptionUtils.isExcludeTrue(mdc)) {
0893: mdc.setDeclaringClass(dbc.getClassName());
0894: retrieveList.add(mdc);
0895: }
0896: }
0897: }
0898: }
0899:
0900: return retrieveList;
0901: }
0902:
0903: private ArrayList<MethodDescriptionComposite> retrieveSEIMethods(
0904: DescriptionBuilderComposite dbc) {
0905:
0906: //Rules for retrieving Methods on an SEI (or a superclass of an SEI) are simple
0907: //Just retrieve all methods regardless of WebMethod annotations
0908: ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>();
0909:
0910: Iterator<MethodDescriptionComposite> iter = null;
0911: List<MethodDescriptionComposite> mdcList = dbc
0912: .getMethodDescriptionsList();
0913:
0914: if (mdcList != null) {
0915: iter = dbc.getMethodDescriptionsList().iterator();
0916: while (iter.hasNext()) {
0917: MethodDescriptionComposite mdc = iter.next();
0918: mdc.setDeclaringClass(dbc.getClassName());
0919: retrieveList.add(mdc);
0920: }
0921: }
0922:
0923: return retrieveList;
0924: }
0925:
0926: private ArrayList<MethodDescriptionComposite> retrieveSEIMethodsChain(
0927: DescriptionBuilderComposite tmpDBC) {
0928:
0929: DescriptionBuilderComposite dbc = tmpDBC;
0930: ArrayList<MethodDescriptionComposite> retrieveList = new ArrayList<MethodDescriptionComposite>();
0931:
0932: retrieveList = retrieveSEIMethods(dbc);
0933:
0934: //Since this is an interface, anything that is in the extends clause will actually appear
0935: // in the interfaces list instead.
0936: Iterator<String> iter = null;
0937: List<String> interfacesList = dbc.getInterfacesList();
0938: if (interfacesList != null) {
0939: iter = dbc.getInterfacesList().iterator();
0940:
0941: while (iter.hasNext()) {
0942:
0943: String interfaceName = iter.next();
0944: DescriptionBuilderComposite super Interface = getEndpointDescriptionImpl()
0945: .getServiceDescriptionImpl().getDBCMap().get(
0946: interfaceName);
0947:
0948: retrieveList
0949: .addAll(retrieveSEIMethodsChain(super Interface));
0950: }
0951: }
0952:
0953: return retrieveList;
0954: }
0955:
0956: private Definition getWSDLDefinition() {
0957: return ((ServiceDescriptionWSDL) getEndpointDescription()
0958: .getServiceDescription()).getWSDLDefinition();
0959: }
0960:
0961: public PortType getWSDLPortType() {
0962: PortType portType = null;
0963: // EndpointDescriptionWSDL endpointDescWSDL = (EndpointDescriptionWSDL) getEndpointDescription();
0964: // Binding wsdlBinding = endpointDescWSDL.getWSDLBinding();
0965: // if (wsdlBinding != null) {
0966: // portType = wsdlBinding.getPortType();
0967: // }
0968: Definition wsdlDefn = getWSDLDefinition();
0969: if (wsdlDefn != null) {
0970: String tns = getEndpointDescription().getTargetNamespace();
0971: String localPart = getEndpointDescription().getName();
0972: if (localPart != null) {
0973: portType = wsdlDefn.getPortType(new QName(tns,
0974: localPart));
0975: }
0976: }
0977: return portType;
0978: }
0979:
0980: public String getTargetNamespace() {
0981: // REVIEW: WSDL/Anno mertge
0982: return getAnnoWebServiceTargetNamespace();
0983: }
0984:
0985: public WebService getAnnoWebService() {
0986: // TODO Auto-generated method stub
0987: if (webServiceAnnotation == null) {
0988: if (dbc != null) {
0989: webServiceAnnotation = dbc.getWebServiceAnnot();
0990: } else {
0991: if (seiClass != null) {
0992: webServiceAnnotation = (WebService) seiClass
0993: .getAnnotation(WebService.class);
0994: }
0995: }
0996: }
0997: return webServiceAnnotation;
0998: }
0999:
1000: public String getAnnoWebServiceTargetNamespace() {
1001: if (webServiceTargetNamespace == null) {
1002: if (getAnnoWebService() != null
1003: && !DescriptionUtils.isEmpty(getAnnoWebService()
1004: .targetNamespace())) {
1005: webServiceTargetNamespace = getAnnoWebService()
1006: .targetNamespace();
1007: } else {
1008: // Default value per JSR-181 MR Sec 4.1 pg 15 defers to "Implementation defined,
1009: // as described in JAX-WS 2.0, section 3.2" which is JAX-WS 2.0 Sec 3.2, pg 29.
1010: // FIXME: Hardcoded protocol for namespace
1011: if (dbc != null)
1012: webServiceTargetNamespace = DescriptionUtils
1013: .makeNamespaceFromPackageName(
1014: DescriptionUtils
1015: .getJavaPackageName(dbc
1016: .getClassName()),
1017: "http");
1018: else
1019: webServiceTargetNamespace = DescriptionUtils
1020: .makeNamespaceFromPackageName(
1021: DescriptionUtils
1022: .getJavaPackageName(seiClass),
1023: "http");
1024:
1025: }
1026: }
1027: return webServiceTargetNamespace;
1028: }
1029:
1030: public String getAnnoWebServiceName() {
1031: //REVIEW the following, used to get Port
1032: if (webService_Name == null) {
1033:
1034: if (getAnnoWebService() != null
1035: && !DescriptionUtils.isEmpty(getAnnoWebService()
1036: .name())) {
1037: webService_Name = getAnnoWebService().name();
1038: } else {
1039: webService_Name = "";
1040: }
1041: }
1042: return webService_Name;
1043: }
1044:
1045: public String getName() {
1046: return getAnnoWebServiceName();
1047: }
1048:
1049: public QName getPortType() {
1050: String name = getName();
1051: String tns = getTargetNamespace();
1052: return new QName(tns, name);
1053: }
1054:
1055: public String toString() {
1056: final String newline = "\n";
1057: final String sameline = "; ";
1058: StringBuffer string = new StringBuffer();
1059: try {
1060: string.append(super .toString());
1061: string.append(newline);
1062: string.append("Name: " + getName());
1063: string.append(sameline);
1064: string.append("PortType: " + getPortType());
1065: //
1066: string.append(newline);
1067: string.append("SOAP Style: " + getSoapBindingStyle());
1068: string.append(sameline);
1069: string.append("SOAP Use: " + getSoapBindingUse());
1070: string.append(sameline);
1071: string.append("SOAP Paramater Style: "
1072: + getSoapBindingParameterStyle());
1073: //
1074: string.append(newline);
1075: OperationDescription[] operations = getOperations();
1076: if (operations != null && operations.length > 0) {
1077: string.append("Number of operations: "
1078: + operations.length);
1079: for (OperationDescription operation : operations) {
1080: string.append(newline);
1081: string.append("Operation: " + operation.toString());
1082: }
1083: } else {
1084: string.append("OperationDescription array is null");
1085: }
1086: } catch (Throwable t) {
1087: string.append(newline);
1088: string
1089: .append("Complete debug information not currently available for "
1090: + "EndpointInterfaceDescription");
1091: return string.toString();
1092: }
1093: return string.toString();
1094: }
1095:
1096: }
|