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 26package com.sun.xml.internal.ws.model; 27 28import com.sun.xml.internal.bind.api.TypeReference; 29import com.sun.xml.internal.ws.api.databinding.MetadataReader; 30import com.sun.xml.internal.ws.api.model.JavaMethod; 31import com.sun.xml.internal.ws.api.model.MEP; 32import com.sun.xml.internal.ws.api.model.SEIModel; 33import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; 34import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; 35import com.sun.xml.internal.ws.api.model.wsdl.WSDLFault; 36import com.sun.xml.internal.ws.api.model.soap.SOAPBinding; 37import com.sun.xml.internal.ws.model.soap.SOAPBindingImpl; 38import com.sun.xml.internal.ws.spi.db.TypeInfo; 39import com.sun.xml.internal.ws.wsdl.ActionBasedOperationSignature; 40import com.sun.istack.internal.Nullable; 41 42import javax.xml.namespace.QName; 43import javax.xml.ws.Action; 44import javax.xml.ws.WebServiceException; 45import javax.jws.WebMethod; 46import java.lang.reflect.Method; 47import java.util.ArrayList; 48import java.util.Collections; 49import java.util.List; 50import java.util.logging.Logger; 51 52/** 53 * Build this runtime model using java SEI and annotations 54 * 55 * @author Vivek Pandey 56 */ 57public 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} 417