001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036: package com.sun.xml.ws.model;
037:
038: import com.sun.istack.NotNull;
039: import com.sun.xml.bind.api.Bridge;
040: import com.sun.xml.bind.api.JAXBRIContext;
041: import com.sun.xml.bind.api.TypeReference;
042: import com.sun.xml.ws.api.model.JavaMethod;
043: import com.sun.xml.ws.api.model.ParameterBinding;
044: import com.sun.xml.ws.api.model.SEIModel;
045: import com.sun.xml.ws.api.model.wsdl.WSDLModel;
046: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
047: import com.sun.xml.ws.client.WSServiceDelegate;
048: import com.sun.xml.ws.encoding.soap.streaming.SOAPNamespaceConstants;
049: import com.sun.xml.ws.model.wsdl.WSDLBoundOperationImpl;
050: import com.sun.xml.ws.model.wsdl.WSDLBoundPortTypeImpl;
051: import com.sun.xml.ws.model.wsdl.WSDLPartImpl;
052: import com.sun.xml.ws.model.wsdl.WSDLPortImpl;
053: import com.sun.xml.ws.resources.ModelerMessages;
054: import com.sun.xml.ws.util.Pool;
055:
056: import javax.jws.WebParam.Mode;
057: import javax.xml.bind.annotation.XmlSeeAlso;
058: import javax.xml.namespace.QName;
059: import javax.xml.ws.WebServiceException;
060: import java.lang.reflect.Method;
061: import java.security.AccessController;
062: import java.security.PrivilegedActionException;
063: import java.security.PrivilegedExceptionAction;
064: import java.util.ArrayList;
065: import java.util.Collection;
066: import java.util.Collections;
067: import java.util.HashMap;
068: import java.util.List;
069: import java.util.Map;
070:
071: /**
072: * model of the web service. Used by the runtime marshall/unmarshall
073: * web service invocations
074: *
075: * $author: JAXWS Development Team
076: */
077: public abstract class AbstractSEIModelImpl implements SEIModel {
078:
079: void postProcess() {
080: // should be called only once.
081: if (jaxbContext != null)
082: return;
083: populateMaps();
084: createJAXBContext();
085: }
086:
087: /**
088: * Link {@link SEIModel} to {@link WSDLModel}.
089: * Merge it with {@link #postProcess()}.
090: */
091: public void freeze(WSDLPortImpl port) {
092: this .port = port;
093: for (JavaMethodImpl m : javaMethods) {
094: m.freeze(port);
095: }
096: }
097:
098: /**
099: * Populate methodToJM and nameToJM maps.
100: */
101: abstract protected void populateMaps();
102:
103: public Pool.Marshaller getMarshallerPool() {
104: return marshallers;
105: }
106:
107: /**
108: * @return the <code>JAXBRIContext</code>
109: */
110: public JAXBRIContext getJAXBContext() {
111: return jaxbContext;
112: }
113:
114: /**
115: * @return the known namespaces from JAXBRIContext
116: */
117: public List<String> getKnownNamespaceURIs() {
118: return knownNamespaceURIs;
119: }
120:
121: /**
122: * @return the <code>Bridge</code> for the <code>type</code>
123: */
124: public final Bridge getBridge(TypeReference type) {
125: Bridge b = bridgeMap.get(type);
126: assert b != null; // we should have created Bridge for all TypeReferences known to this model
127: return b;
128: }
129:
130: private JAXBRIContext createJAXBContext() {
131: final List<TypeReference> types = getAllTypeReferences();
132: final Class[] cls = new Class[types.size()
133: + additionalClasses.size()];
134: int i = 0;
135: for (Class additionalClass : additionalClasses) {
136: cls[i++] = additionalClass;
137: }
138:
139: for (TypeReference type : types) {
140: cls[i++] = (Class) type.type;
141: }
142:
143: try {
144: //jaxbContext = JAXBRIContext.newInstance(cls, types, targetNamespace, false);
145: // Need to avoid doPriv block once JAXB is fixed. Afterwards, use the above
146: jaxbContext = AccessController
147: .doPrivileged(new PrivilegedExceptionAction<JAXBRIContext>() {
148: public JAXBRIContext run() throws Exception {
149: return JAXBRIContext.newInstance(cls,
150: types, null, targetNamespace,
151: false, null);
152: }
153: });
154: createBridgeMap(types);
155: } catch (PrivilegedActionException e) {
156: throw new WebServiceException(ModelerMessages
157: .UNABLE_TO_CREATE_JAXB_CONTEXT(), e);
158: }
159: knownNamespaceURIs = new ArrayList<String>();
160: for (String namespace : jaxbContext.getKnownNamespaceURIs()) {
161: if (namespace.length() > 0) {
162: if (!namespace.equals(SOAPNamespaceConstants.XSD)
163: && !namespace
164: .equals(SOAPNamespaceConstants.XMLNS))
165: knownNamespaceURIs.add(namespace);
166: }
167: }
168:
169: marshallers = new Pool.Marshaller(jaxbContext);
170:
171: return jaxbContext;
172: }
173:
174: /**
175: * @return returns non-null list of TypeReference
176: */
177: private List<TypeReference> getAllTypeReferences() {
178: List<TypeReference> types = new ArrayList<TypeReference>();
179: Collection<JavaMethodImpl> methods = methodToJM.values();
180: for (JavaMethodImpl m : methods) {
181: m.fillTypes(types);
182: }
183: return types;
184: }
185:
186: private void createBridgeMap(List<TypeReference> types) {
187: for (TypeReference type : types) {
188: Bridge bridge = jaxbContext.createBridge(type);
189: bridgeMap.put(type, bridge);
190: }
191: }
192:
193: /**
194: * @return the <code>Method</code> for a given WSDLOperation <code>qname</code>
195: */
196: public Method getDispatchMethod(QName qname) {
197: //handle the empty body
198: if (qname == null)
199: qname = emptyBodyName;
200: JavaMethodImpl jm = getJavaMethod(qname);
201: if (jm != null) {
202: return jm.getMethod();
203: }
204: return null;
205: }
206:
207: /**
208: * @return true if <code>name</code> is the name
209: * of a known fault name for the <code>Method method</code>
210: */
211: public boolean isKnownFault(QName name, Method method) {
212: JavaMethodImpl m = getJavaMethod(method);
213: for (CheckedExceptionImpl ce : m.getCheckedExceptions()) {
214: if (ce.getDetailType().tagName.equals(name))
215: return true;
216: }
217: return false;
218: }
219:
220: /**
221: * @return true if <code>ex</code> is a Checked Exception
222: * for <code>Method m</code>
223: */
224: public boolean isCheckedException(Method m, Class ex) {
225: JavaMethodImpl jm = getJavaMethod(m);
226: for (CheckedExceptionImpl ce : jm.getCheckedExceptions()) {
227: if (ce.getExceptionClass().equals(ex))
228: return true;
229: }
230: return false;
231: }
232:
233: /**
234: * @return the <code>JavaMethod</code> representing the <code>method</code>
235: */
236: public JavaMethodImpl getJavaMethod(Method method) {
237: return methodToJM.get(method);
238: }
239:
240: /**
241: * @return the <code>JavaMethod</code> associated with the
242: * operation named name
243: */
244: public JavaMethodImpl getJavaMethod(QName name) {
245: return nameToJM.get(name);
246: }
247:
248: /**
249: * @return the <code>QName</code> associated with the
250: * JavaMethod jm.
251: *
252: * @deprecated
253: * Use {@link JavaMethod#getPayloadName()}.
254: */
255: public QName getQNameForJM(JavaMethodImpl jm) {
256: for (QName key : nameToJM.keySet()) {
257: JavaMethodImpl jmethod = nameToJM.get(key);
258: if (jmethod.getOperationName()
259: .equals(jm.getOperationName())) {
260: return key;
261: }
262: }
263: return null;
264: }
265:
266: /**
267: * @return a <code>Collection</code> of <code>JavaMethods</code>
268: * associated with this <code>RuntimeModel</code>
269: */
270: public final Collection<JavaMethodImpl> getJavaMethods() {
271: return Collections.unmodifiableList(javaMethods);
272: }
273:
274: void addJavaMethod(JavaMethodImpl jm) {
275: if (jm != null)
276: javaMethods.add(jm);
277: }
278:
279: /**
280: * Used from {@link WSServiceDelegate}
281: * to apply the binding information from WSDL after the model is created frm SEI class on the client side. On the server
282: * side all the binding information is available before modeling and this method is not used.
283: *
284: * @deprecated To be removed once client side new architecture is implemented
285: */
286: public void applyParameterBinding(WSDLBoundPortTypeImpl wsdlBinding) {
287: if (wsdlBinding == null)
288: return;
289:
290: for (JavaMethodImpl method : javaMethods) {
291: if (method.isAsync())
292: continue;
293: QName opName = new QName(wsdlBinding.getPortTypeName()
294: .getNamespaceURI(), method.getOperationName());
295:
296: //patch the soapaction correctly from the WSDL
297: WSDLBoundOperationImpl bo = wsdlBinding.get(opName);
298: String action = bo.getSOAPAction();
299: method.getBinding().setSOAPAction(action);
300:
301: boolean isRpclit = method.getBinding().isRpcLit();
302: List<ParameterImpl> reqParams = method.requestParams;
303: List<ParameterImpl> reqAttachParams = null;
304: for (ParameterImpl param : reqParams) {
305: if (param.isWrapperStyle()) {
306: if (isRpclit) {
307: WrapperParameter reqParam = (WrapperParameter) param;
308: if (bo.getRequestNamespace() != null) {
309: patchRpclitNamespace(bo
310: .getRequestNamespace(), reqParam);
311: }
312: reqAttachParams = applyRpcLitParamBinding(
313: method, (WrapperParameter) param,
314: wsdlBinding, Mode.IN);
315: }
316: continue;
317: }
318: String partName = param.getPartName();
319: if (partName == null)
320: continue;
321: ParameterBinding paramBinding = wsdlBinding.getBinding(
322: opName, partName, Mode.IN);
323: if (paramBinding != null)
324: param.setInBinding(paramBinding);
325: }
326:
327: List<ParameterImpl> resAttachParams = null;
328: List<ParameterImpl> resParams = method.responseParams;
329: for (ParameterImpl param : resParams) {
330: if (param.isWrapperStyle()) {
331: if (isRpclit) {
332: WrapperParameter respParam = (WrapperParameter) param;
333: if (bo.getResponseNamespace() != null) {
334: patchRpclitNamespace(bo
335: .getResponseNamespace(), respParam);
336: }
337: resAttachParams = applyRpcLitParamBinding(
338: method, (WrapperParameter) param,
339: wsdlBinding, Mode.OUT);
340: }
341: continue;
342: }
343: //if the parameter is not inout and its header=true then dont get binding from WSDL
344: // if(!param.isINOUT() && param.getBinding().isHeader())
345: // continue;
346: String partName = param.getPartName();
347: if (partName == null)
348: continue;
349: ParameterBinding paramBinding = wsdlBinding.getBinding(
350: opName, partName, Mode.OUT);
351: if (paramBinding != null)
352: param.setOutBinding(paramBinding);
353: }
354: if (reqAttachParams != null) {
355: for (ParameterImpl p : reqAttachParams) {
356: method.addRequestParameter(p);
357: }
358: }
359: if (resAttachParams != null) {
360: for (ParameterImpl p : resAttachParams) {
361: method.addResponseParameter(p);
362: }
363: }
364:
365: }
366: }
367:
368: /**
369: * For rpclit wrapper element inside <soapenv:Body>, the targetNamespace should be taked from
370: * the soapbind:body@namespace value. Since no annotations on SEI/impl class captures it so we
371: * need to get it from WSDL and patch it. *
372: */
373: private void patchRpclitNamespace(String namespace,
374: WrapperParameter param) {
375: TypeReference type = param.getTypeReference();
376: TypeReference newType = new TypeReference(new QName(namespace,
377: type.tagName.getLocalPart()), type.type,
378: type.annotations);
379: param.setTypeReference(newType);
380: }
381:
382: /**
383: * Applies binding related information to the RpcLitPayload. The payload map is populated correctl
384: * @return
385: * Returns attachment parameters if/any.
386: */
387: private List<ParameterImpl> applyRpcLitParamBinding(
388: JavaMethodImpl method, WrapperParameter wrapperParameter,
389: WSDLBoundPortTypeImpl boundPortType, Mode mode) {
390: QName opName = new QName(boundPortType.getPortTypeName()
391: .getNamespaceURI(), method.getOperationName());
392: WSDLBoundOperationImpl bo = boundPortType.get(opName);
393: Map<Integer, ParameterImpl> bodyParams = new HashMap<Integer, ParameterImpl>();
394: List<ParameterImpl> unboundParams = new ArrayList<ParameterImpl>();
395: List<ParameterImpl> attachParams = new ArrayList<ParameterImpl>();
396: for (ParameterImpl param : wrapperParameter.wrapperChildren) {
397: String partName = param.getPartName();
398: if (partName == null)
399: continue;
400:
401: ParameterBinding paramBinding = boundPortType.getBinding(
402: opName, partName, mode);
403: if (paramBinding != null) {
404: if (mode == Mode.IN)
405: param.setInBinding(paramBinding);
406: else if (mode == Mode.OUT || mode == Mode.INOUT)
407: param.setOutBinding(paramBinding);
408:
409: if (paramBinding.isUnbound()) {
410: unboundParams.add(param);
411: } else if (paramBinding.isAttachment()) {
412: attachParams.add(param);
413: } else if (paramBinding.isBody()) {
414: if (bo != null) {
415: WSDLPartImpl p = bo.getPart(
416: param.getPartName(), mode);
417: if (p != null)
418: bodyParams.put(p.getIndex(), param);
419: else
420: bodyParams.put(bodyParams.size(), param);
421: } else {
422: bodyParams.put(bodyParams.size(), param);
423: }
424: }
425: }
426:
427: }
428: wrapperParameter.clear();
429: for (int i = 0; i < bodyParams.size(); i++) {
430: ParameterImpl p = bodyParams.get(i);
431: wrapperParameter.addWrapperChild(p);
432: }
433:
434: //add unbounded parts
435: for (ParameterImpl p : unboundParams) {
436: wrapperParameter.addWrapperChild(p);
437: }
438: return attachParams;
439: }
440:
441: void put(QName name, JavaMethodImpl jm) {
442: nameToJM.put(name, jm);
443: }
444:
445: void put(Method method, JavaMethodImpl jm) {
446: methodToJM.put(method, jm);
447: }
448:
449: public String getWSDLLocation() {
450: return wsdlLocation;
451: }
452:
453: void setWSDLLocation(String location) {
454: wsdlLocation = location;
455: }
456:
457: public QName getServiceQName() {
458: return serviceName;
459: }
460:
461: public WSDLPort getPort() {
462: return port;
463: }
464:
465: public QName getPortName() {
466: return portName;
467: }
468:
469: public QName getPortTypeName() {
470: return portTypeName;
471: }
472:
473: void setServiceQName(QName name) {
474: serviceName = name;
475: }
476:
477: void setPortName(QName name) {
478: portName = name;
479: }
480:
481: void setPortTypeName(QName name) {
482: portTypeName = name;
483: }
484:
485: /**
486: * This is the targetNamespace for the WSDL containing the PortType
487: * definition
488: */
489: void setTargetNamespace(String namespace) {
490: targetNamespace = namespace;
491: }
492:
493: /**
494: * This is the targetNamespace for the WSDL containing the PortType
495: * definition
496: */
497: public String getTargetNamespace() {
498: return targetNamespace;
499: }
500:
501: @NotNull
502: public QName getBoundPortTypeName() {
503: assert portName != null;
504: return new QName(portName.getNamespaceURI(), portName
505: .getLocalPart()
506: + "Binding");
507: }
508:
509: /**
510: * Adds additional classes obtained from {@link XmlSeeAlso} annotation. In starting
511: * from wsdl case these classes would most likely be JAXB ObjectFactory that references other classes.
512: */
513: public void addAdditionalClasses(Class... additionalClasses) {
514: for (Class cls : additionalClasses)
515: this .additionalClasses.add(cls);
516: }
517:
518: private List<Class> additionalClasses = new ArrayList<Class>();
519:
520: private Pool.Marshaller marshallers;
521: protected JAXBRIContext jaxbContext;
522: private String wsdlLocation;
523: private QName serviceName;
524: private QName portName;
525: private QName portTypeName;
526: private Map<Method, JavaMethodImpl> methodToJM = new HashMap<Method, JavaMethodImpl>();
527: /**
528: * Payload QName to the method that handles it.
529: */
530: private Map<QName, JavaMethodImpl> nameToJM = new HashMap<QName, JavaMethodImpl>();
531: private List<JavaMethodImpl> javaMethods = new ArrayList<JavaMethodImpl>();
532: private final Map<TypeReference, Bridge> bridgeMap = new HashMap<TypeReference, Bridge>();
533: protected final QName emptyBodyName = new QName("");
534: private String targetNamespace = "";
535: private List<String> knownNamespaceURIs = null;
536: private WSDLPortImpl port;
537: }
|