View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.model;
27  
28  import com.sun.xml.internal.bind.api.TypeReference;
29  import com.sun.xml.internal.ws.api.databinding.MetadataReader;
30  import com.sun.xml.internal.ws.api.model.JavaMethod;
31  import com.sun.xml.internal.ws.api.model.MEP;
32  import com.sun.xml.internal.ws.api.model.SEIModel;
33  import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
34  import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
35  import com.sun.xml.internal.ws.api.model.wsdl.WSDLFault;
36  import com.sun.xml.internal.ws.api.model.soap.SOAPBinding;
37  import com.sun.xml.internal.ws.model.soap.SOAPBindingImpl;
38  import com.sun.xml.internal.ws.spi.db.TypeInfo;
39  import com.sun.xml.internal.ws.wsdl.ActionBasedOperationSignature;
40  import com.sun.istack.internal.Nullable;
41  
42  import javax.xml.namespace.QName;
43  import javax.xml.ws.Action;
44  import javax.xml.ws.WebServiceException;
45  import javax.jws.WebMethod;
46  import java.lang.reflect.Method;
47  import java.util.ArrayList;
48  import java.util.Collections;
49  import java.util.List;
50  import java.util.logging.Logger;
51  
52  /**
53   * Build this runtime model using java SEI and annotations
54   *
55   * @author Vivek Pandey
56   */
57  public final class JavaMethodImpl implements JavaMethod {
58  
59      private String inputAction = "";
60      private String outputAction = "";
61      private final List<CheckedExceptionImpl> exceptions = new ArrayList<CheckedExceptionImpl>();
62      private final Method method;
63      /*package*/ final List<ParameterImpl> requestParams = new ArrayList<ParameterImpl>();
64      /*package*/ final List<ParameterImpl> responseParams = new ArrayList<ParameterImpl>();
65      private final List<ParameterImpl> unmReqParams = Collections.unmodifiableList(requestParams);
66      private final List<ParameterImpl> unmResParams = Collections.unmodifiableList(responseParams);
67      private SOAPBinding binding;
68      private MEP mep;
69      private QName operationName;
70      private WSDLBoundOperation wsdlOperation;
71      /*package*/ final AbstractSEIModelImpl owner;
72      private final Method seiMethod;
73      private QName requestPayloadName;
74      private String soapAction;
75  
76      /**
77       * @param owner
78       * @param method : Implementation class method
79       * @param seiMethod : corresponding SEI Method.
80       *                  Is there is no SEI, it should be Implementation class method
81       */
82      public JavaMethodImpl(AbstractSEIModelImpl owner, Method method, Method seiMethod, MetadataReader metadataReader) {
83          this.owner = owner;
84          this.method = method;
85          this.seiMethod = seiMethod;
86          setWsaActions(metadataReader);
87      }
88  
89      private void setWsaActions(MetadataReader metadataReader) {
90          Action action = (metadataReader != null)? metadataReader.getAnnotation(Action.class, seiMethod):seiMethod.getAnnotation(Action.class);
91          if(action != null) {
92              inputAction = action.input();
93              outputAction = action.output();
94          }
95  
96          //@Action(input) =="", get it from @WebMethod(action)
97          WebMethod webMethod = (metadataReader != null)? metadataReader.getAnnotation(WebMethod.class, seiMethod):seiMethod.getAnnotation(WebMethod.class);
98          soapAction = "";
99          if (webMethod != null )
100             soapAction = webMethod.action();
101         if(!soapAction.equals("")) {
102             //non-empty soapAction
103             if(inputAction.equals(""))
104                 // set input action to non-empty soapAction
105                 inputAction = soapAction;
106             else if(!inputAction.equals(soapAction)){
107                 //both are explicitly set via annotations, make sure @Action == @WebMethod.action
108                 //http://java.net/jira/browse/JAX_WS-1108
109               //throw new WebServiceException("@Action and @WebMethod(action=\"\" does not match on operation "+ method.getName());
110             }
111         }
112     }
113 
114     public ActionBasedOperationSignature getOperationSignature() {
115         QName qname = getRequestPayloadName();
116         if (qname == null) qname = new QName("", "");
117         return new ActionBasedOperationSignature(getInputAction(), qname);
118     }
119 
120     public SEIModel getOwner() {
121         return owner;
122     }
123 
124     /**
125      * @see JavaMethod
126      *
127      * @return Returns the method.
128      */
129     public Method getMethod() {
130         return method;
131     }
132 
133     /**
134      * @see JavaMethod
135      *
136      * @return Returns the SEI method where annotations are present
137      */
138     public Method getSEIMethod() {
139         return seiMethod;
140     }
141 
142     /**
143      * @return Returns the mep.
144      */
145     public MEP getMEP() {
146         return mep;
147     }
148 
149     /**
150      * @param mep
151      *            The mep to set.
152      */
153     void setMEP(MEP mep) {
154         this.mep = mep;
155     }
156 
157     /**
158      * @return the Binding object
159      */
160     public SOAPBinding getBinding() {
161         if (binding == null)
162             return new SOAPBindingImpl();
163         return binding;
164     }
165 
166     /**
167      * @param binding
168      */
169     void setBinding(SOAPBinding binding) {
170         this.binding = binding;
171     }
172 
173     /**
174      * Returns the {@link WSDLBoundOperation} Operation associated with {@link JavaMethodImpl}
175      * operation.
176      * @deprecated
177      * @return the WSDLBoundOperation for this JavaMethod
178      */
179     public WSDLBoundOperation getOperation() {
180 //        assert wsdlOperation != null;
181         return wsdlOperation;
182     }
183 
184     public void setOperationQName(QName name) {
185         this.operationName = name;
186     }
187 
188     public QName getOperationQName() {
189         return (wsdlOperation != null)? wsdlOperation.getName(): operationName;
190     }
191 
192     public String getSOAPAction() {
193         return (wsdlOperation != null)? wsdlOperation.getSOAPAction(): soapAction;
194     }
195 
196     public String getOperationName() {
197         return operationName.getLocalPart();
198     }
199 
200     public String getRequestMessageName() {
201         return getOperationName();
202     }
203 
204     public String getResponseMessageName() {
205         if(mep.isOneWay())
206             return null;
207         return getOperationName()+"Response";
208     }
209 
210     public void setRequestPayloadName(QName n)  {
211         requestPayloadName = n;
212     }
213 
214     /**
215      * @return soap:Body's first child name for request message.
216      */
217     public @Nullable QName getRequestPayloadName() {
218         return (wsdlOperation != null)? wsdlOperation.getRequestPayloadName(): requestPayloadName;
219     }
220 
221     /**
222      * @return soap:Body's first child name for response message.
223      */
224     public @Nullable QName getResponsePayloadName() {
225         return (mep == MEP.ONE_WAY) ? null : wsdlOperation.getResponsePayloadName();
226     }
227 
228     /**
229      * @return returns unmodifiable list of request parameters
230      */
231     public List<ParameterImpl> getRequestParameters() {
232         return unmReqParams;
233     }
234 
235     /**
236      * @return returns unmodifiable list of response parameters
237      */
238     public List<ParameterImpl> getResponseParameters() {
239         return unmResParams;
240     }
241 
242     void addParameter(ParameterImpl p) {
243         if (p.isIN() || p.isINOUT()) {
244             assert !requestParams.contains(p);
245             requestParams.add(p);
246         }
247 
248         if (p.isOUT() || p.isINOUT()) {
249             // this check is only for out parameters
250             assert !responseParams.contains(p);
251             responseParams.add(p);
252         }
253     }
254 
255     void addRequestParameter(ParameterImpl p){
256         if (p.isIN() || p.isINOUT()) {
257             requestParams.add(p);
258         }
259     }
260 
261     void addResponseParameter(ParameterImpl p){
262         if (p.isOUT() || p.isINOUT()) {
263             responseParams.add(p);
264         }
265     }
266 
267     /**
268      * @return Returns number of java method parameters - that will be all the
269      *         IN, INOUT and OUT holders
270      *
271      * @deprecated no longer use in the new architecture
272      */
273     public int getInputParametersCount() {
274         int count = 0;
275         for (ParameterImpl param : requestParams) {
276             if (param.isWrapperStyle()) {
277                 count += ((WrapperParameter) param).getWrapperChildren().size();
278             } else {
279                 count++;
280             }
281         }
282 
283         for (ParameterImpl param : responseParams) {
284             if (param.isWrapperStyle()) {
285                 for (ParameterImpl wc : ((WrapperParameter) param).getWrapperChildren()) {
286                     if (!wc.isResponse() && wc.isOUT()) {
287                         count++;
288                     }
289                 }
290             } else if (!param.isResponse() && param.isOUT()) {
291                 count++;
292             }
293         }
294 
295         return count;
296     }
297 
298     /**
299      * @param ce
300      */
301     void addException(CheckedExceptionImpl ce) {
302         if (!exceptions.contains(ce))
303             exceptions.add(ce);
304     }
305 
306     /**
307      * @param exceptionClass
308      * @return CheckedException corresponding to the exceptionClass. Returns
309      *         null if not found.
310      */
311     public CheckedExceptionImpl getCheckedException(Class exceptionClass) {
312         for (CheckedExceptionImpl ce : exceptions) {
313             if (ce.getExceptionClass()==exceptionClass)
314                 return ce;
315         }
316         return null;
317     }
318 
319 
320     /**
321      * @return a list of checked Exceptions thrown by this method
322      */
323     public List<CheckedExceptionImpl> getCheckedExceptions(){
324         return Collections.unmodifiableList(exceptions);
325     }
326 
327     public String getInputAction() {
328 //        return (wsdlOperation != null)? wsdlOperation.getOperation().getInput().getAction(): inputAction;
329         return inputAction;
330     }
331 
332     public String getOutputAction() {
333 //        return (wsdlOperation != null)? wsdlOperation.getOperation().getOutput().getAction(): outputAction;
334         return outputAction;
335     }
336 
337     /**
338      * @deprecated
339      * @param detailType
340      * @return Gets the CheckedException corresponding to detailType. Returns
341      *         null if no CheckedExcpetion with the detailType found.
342      */
343     public CheckedExceptionImpl getCheckedException(TypeReference detailType) {
344         for (CheckedExceptionImpl ce : exceptions) {
345             TypeInfo actual = ce.getDetailType();
346             if (actual.tagName.equals(detailType.tagName) && actual.type==detailType.type) {
347                 return ce;
348             }
349         }
350         return null;
351     }
352 
353 
354 
355     /**
356      * Returns if the java method  is async
357      * @return if this is an Asynch
358      */
359     public boolean isAsync(){
360         return mep.isAsync;
361     }
362 
363     /*package*/ void freeze(WSDLPort portType) {
364         this.wsdlOperation = portType.getBinding().get(new QName(portType.getBinding().getPortType().getName().getNamespaceURI(),getOperationName()));
365         // TODO: replace this with proper error handling
366         if(wsdlOperation ==null)
367             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());
368 
369         //so far, the inputAction, outputAction and fault actions are set from the @Action and @FaultAction
370         //set the values from WSDLModel, if such annotations are not present or defaulted
371         if(inputAction.equals("")) {
372                 inputAction = wsdlOperation.getOperation().getInput().getAction();
373         } else if(!inputAction.equals(wsdlOperation.getOperation().getInput().getAction()))
374                 //TODO input action might be from @Action or WebMethod(action)
375                 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");
376 
377         if (!mep.isOneWay()) {
378             if (outputAction.equals(""))
379                 outputAction = wsdlOperation.getOperation().getOutput().getAction();
380 
381             for (CheckedExceptionImpl ce : exceptions) {
382                 if (ce.getFaultAction().equals("")) {
383                     QName detailQName = ce.getDetailType().tagName;
384                     WSDLFault wsdlfault = wsdlOperation.getOperation().getFault(detailQName);
385                     if(wsdlfault == null) {
386                         // mismatch between wsdl model and SEI model, log a warning and use  SEI model for Action determination
387                         LOGGER.warning("Mismatch between Java model and WSDL model found, For wsdl operation " +
388                                 wsdlOperation.getName() + ",There is no matching wsdl fault with detail QName " +
389                                 ce.getDetailType().tagName);
390                         ce.setFaultAction(ce.getDefaultFaultAction());
391                     } else {
392                         ce.setFaultAction(wsdlfault.getAction());
393                     }
394                 }
395             }
396         }
397     }
398 
399     final void fillTypes(List<TypeInfo> types) {
400         fillTypes(requestParams, types);
401         fillTypes(responseParams, types);
402 
403         for (CheckedExceptionImpl ce : exceptions) {
404             types.add(ce.getDetailType());
405         }
406     }
407 
408     private void fillTypes(List<ParameterImpl> params, List<TypeInfo> types) {
409         for (ParameterImpl p : params) {
410             p.fillTypes(types);
411         }
412     }
413 
414     private static final Logger LOGGER = Logger.getLogger(com.sun.xml.internal.ws.model.JavaMethodImpl.class.getName());
415 
416 }