/* * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.xml.internal.ws.model; import com.sun.xml.internal.bind.api.TypeReference; import com.sun.xml.internal.ws.api.databinding.MetadataReader; import com.sun.xml.internal.ws.api.model.JavaMethod; import com.sun.xml.internal.ws.api.model.MEP; import com.sun.xml.internal.ws.api.model.SEIModel; import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; import com.sun.xml.internal.ws.api.model.wsdl.WSDLFault; import com.sun.xml.internal.ws.api.model.soap.SOAPBinding; import com.sun.xml.internal.ws.model.soap.SOAPBindingImpl; import com.sun.xml.internal.ws.spi.db.TypeInfo; import com.sun.xml.internal.ws.wsdl.ActionBasedOperationSignature; import com.sun.istack.internal.Nullable; import javax.xml.namespace.QName; import javax.xml.ws.Action; import javax.xml.ws.WebServiceException; import javax.jws.WebMethod; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Logger; /** * Build this runtime model using java SEI and annotations * * @author Vivek Pandey */ public final class JavaMethodImpl implements JavaMethod { private String inputAction = ""; private String outputAction = ""; private final List<CheckedExceptionImpl> exceptions = new ArrayList<CheckedExceptionImpl>(); private final Method method; /*package*/ final List<ParameterImpl> requestParams = new ArrayList<ParameterImpl>(); /*package*/ final List<ParameterImpl> responseParams = new ArrayList<ParameterImpl>(); private final List<ParameterImpl> unmReqParams = Collections.unmodifiableList(requestParams); private final List<ParameterImpl> unmResParams = Collections.unmodifiableList(responseParams); private SOAPBinding binding; private MEP mep; private QName operationName; private WSDLBoundOperation wsdlOperation; /*package*/ final AbstractSEIModelImpl owner; private final Method seiMethod; private QName requestPayloadName; private String soapAction; /** * @param owner * @param method : Implementation class method * @param seiMethod : corresponding SEI Method. * Is there is no SEI, it should be Implementation class method */ public JavaMethodImpl(AbstractSEIModelImpl owner, Method method, Method seiMethod, MetadataReader metadataReader) { this.owner = owner; this.method = method; this.seiMethod = seiMethod; setWsaActions(metadataReader); } private void setWsaActions(MetadataReader metadataReader) { Action action = (metadataReader != null)? metadataReader.getAnnotation(Action.class, seiMethod):seiMethod.getAnnotation(Action.class); if(action != null) { inputAction = action.input(); outputAction = action.output(); } //@Action(input) =="", get it from @WebMethod(action) WebMethod webMethod = (metadataReader != null)? metadataReader.getAnnotation(WebMethod.class, seiMethod):seiMethod.getAnnotation(WebMethod.class); soapAction = ""; if (webMethod != null ) soapAction = webMethod.action(); if(!soapAction.equals("")) { //non-empty soapAction if(inputAction.equals("")) // set input action to non-empty soapAction inputAction = soapAction; else if(!inputAction.equals(soapAction)){ //both are explicitly set via annotations, make sure @Action == @WebMethod.action //http://java.net/jira/browse/JAX_WS-1108 //throw new WebServiceException("@Action and @WebMethod(action=\"\" does not match on operation "+ method.getName()); } } } public ActionBasedOperationSignature getOperationSignature() { QName qname = getRequestPayloadName(); if (qname == null) qname = new QName("", ""); return new ActionBasedOperationSignature(getInputAction(), qname); } public SEIModel getOwner() { return owner; } /** * @see JavaMethod * * @return Returns the method. */ public Method getMethod() { return method; } /** * @see JavaMethod * * @return Returns the SEI method where annotations are present */ public Method getSEIMethod() { return seiMethod; } /** * @return Returns the mep. */ public MEP getMEP() { return mep; } /** * @param mep * The mep to set. */ void setMEP(MEP mep) { this.mep = mep; } /** * @return the Binding object */ public SOAPBinding getBinding() { if (binding == null) return new SOAPBindingImpl(); return binding; } /** * @param binding */ void setBinding(SOAPBinding binding) { this.binding = binding; } /** * Returns the {@link WSDLBoundOperation} Operation associated with {@link JavaMethodImpl} * operation. * @deprecated * @return the WSDLBoundOperation for this JavaMethod */ public WSDLBoundOperation getOperation() { // assert wsdlOperation != null; return wsdlOperation; } public void setOperationQName(QName name) { this.operationName = name; } public QName getOperationQName() { return (wsdlOperation != null)? wsdlOperation.getName(): operationName; } public String getSOAPAction() { return (wsdlOperation != null)? wsdlOperation.getSOAPAction(): soapAction; } public String getOperationName() { return operationName.getLocalPart(); } public String getRequestMessageName() { return getOperationName(); } public String getResponseMessageName() { if(mep.isOneWay()) return null; return getOperationName()+"Response"; } public void setRequestPayloadName(QName n) { requestPayloadName = n; } /** * @return soap:Body's first child name for request message. */ public @Nullable QName getRequestPayloadName() { return (wsdlOperation != null)? wsdlOperation.getRequestPayloadName(): requestPayloadName; } /** * @return soap:Body's first child name for response message. */ public @Nullable QName getResponsePayloadName() { return (mep == MEP.ONE_WAY) ? null : wsdlOperation.getResponsePayloadName(); } /** * @return returns unmodifiable list of request parameters */ public List<ParameterImpl> getRequestParameters() { return unmReqParams; } /** * @return returns unmodifiable list of response parameters */ public List<ParameterImpl> getResponseParameters() { return unmResParams; } void addParameter(ParameterImpl p) { if (p.isIN() || p.isINOUT()) { assert !requestParams.contains(p); requestParams.add(p); } if (p.isOUT() || p.isINOUT()) { // this check is only for out parameters assert !responseParams.contains(p); responseParams.add(p); } } void addRequestParameter(ParameterImpl p){ if (p.isIN() || p.isINOUT()) { requestParams.add(p); } } void addResponseParameter(ParameterImpl p){ if (p.isOUT() || p.isINOUT()) { responseParams.add(p); } } /** * @return Returns number of java method parameters - that will be all the * IN, INOUT and OUT holders * * @deprecated no longer use in the new architecture */ public int getInputParametersCount() { int count = 0; for (ParameterImpl param : requestParams) { if (param.isWrapperStyle()) { count += ((WrapperParameter) param).getWrapperChildren().size(); } else { count++; } } for (ParameterImpl param : responseParams) { if (param.isWrapperStyle()) { for (ParameterImpl wc : ((WrapperParameter) param).getWrapperChildren()) { if (!wc.isResponse() && wc.isOUT()) { count++; } } } else if (!param.isResponse() && param.isOUT()) { count++; } } return count; } /** * @param ce */ void addException(CheckedExceptionImpl ce) { if (!exceptions.contains(ce)) exceptions.add(ce); } /** * @param exceptionClass * @return CheckedException corresponding to the exceptionClass. Returns * null if not found. */ public CheckedExceptionImpl getCheckedException(Class exceptionClass) { for (CheckedExceptionImpl ce : exceptions) { if (ce.getExceptionClass()==exceptionClass) return ce; } return null; } /** * @return a list of checked Exceptions thrown by this method */ public List<CheckedExceptionImpl> getCheckedExceptions(){ return Collections.unmodifiableList(exceptions); } public String getInputAction() { // return (wsdlOperation != null)? wsdlOperation.getOperation().getInput().getAction(): inputAction; return inputAction; } public String getOutputAction() { // return (wsdlOperation != null)? wsdlOperation.getOperation().getOutput().getAction(): outputAction; return outputAction; } /** * @deprecated * @param detailType * @return Gets the CheckedException corresponding to detailType. Returns * null if no CheckedExcpetion with the detailType found. */ public CheckedExceptionImpl getCheckedException(TypeReference detailType) { for (CheckedExceptionImpl ce : exceptions) { TypeInfo actual = ce.getDetailType(); if (actual.tagName.equals(detailType.tagName) && actual.type==detailType.type) { return ce; } } return null; } /** * Returns if the java method is async * @return if this is an Asynch */ public boolean isAsync(){ return mep.isAsync; } /*package*/ void freeze(WSDLPort portType) { this.wsdlOperation = portType.getBinding().get(new QName(portType.getBinding().getPortType().getName().getNamespaceURI(),getOperationName())); // TODO: replace this with proper error handling if(wsdlOperation ==null) throw new WebServiceException("Method "+seiMethod.getName()+" is exposed as WebMethod, but there is no corresponding wsdl operation with name "+operationName+" in the wsdl:portType" + portType.getBinding().getPortType().getName()); //so far, the inputAction, outputAction and fault actions are set from the @Action and @FaultAction //set the values from WSDLModel, if such annotations are not present or defaulted if(inputAction.equals("")) { inputAction = wsdlOperation.getOperation().getInput().getAction(); } else if(!inputAction.equals(wsdlOperation.getOperation().getInput().getAction())) //TODO input action might be from @Action or WebMethod(action) LOGGER.warning("Input Action on WSDL operation "+wsdlOperation.getName().getLocalPart() + " and @Action on its associated Web Method " + seiMethod.getName() +" did not match and will cause problems in dispatching the requests"); if (!mep.isOneWay()) { if (outputAction.equals("")) outputAction = wsdlOperation.getOperation().getOutput().getAction(); for (CheckedExceptionImpl ce : exceptions) { if (ce.getFaultAction().equals("")) { QName detailQName = ce.getDetailType().tagName; WSDLFault wsdlfault = wsdlOperation.getOperation().getFault(detailQName); if(wsdlfault == null) { // mismatch between wsdl model and SEI model, log a warning and use SEI model for Action determination LOGGER.warning("Mismatch between Java model and WSDL model found, For wsdl operation " + wsdlOperation.getName() + ",There is no matching wsdl fault with detail QName " + ce.getDetailType().tagName); ce.setFaultAction(ce.getDefaultFaultAction()); } else { ce.setFaultAction(wsdlfault.getAction()); } } } } } final void fillTypes(List<TypeInfo> types) { fillTypes(requestParams, types); fillTypes(responseParams, types); for (CheckedExceptionImpl ce : exceptions) { types.add(ce.getDetailType()); } } private void fillTypes(List<ParameterImpl> params, List<TypeInfo> types) { for (ParameterImpl p : params) { p.fillTypes(types); } } private static final Logger LOGGER = Logger.getLogger(com.sun.xml.internal.ws.model.JavaMethodImpl.class.getName()); }