001: /*
002: * Portions Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package com.sun.xml.internal.ws.model;
026:
027: import com.sun.xml.internal.ws.pept.ept.MessageInfo;
028: import com.sun.xml.internal.bind.api.Bridge;
029: import com.sun.xml.internal.bind.api.BridgeContext;
030: import com.sun.xml.internal.bind.api.JAXBRIContext;
031: import com.sun.xml.internal.bind.api.TypeReference;
032: import com.sun.xml.internal.bind.api.RawAccessor;
033: import com.sun.xml.internal.ws.encoding.JAXWSAttachmentMarshaller;
034: import com.sun.xml.internal.ws.encoding.JAXWSAttachmentUnmarshaller;
035: import com.sun.xml.internal.ws.encoding.jaxb.JAXBBridgeInfo;
036: import com.sun.xml.internal.ws.encoding.jaxb.RpcLitPayload;
037: import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants;
038: import com.sun.xml.internal.ws.wsdl.parser.Binding;
039: import com.sun.xml.internal.ws.wsdl.parser.Part;
040: import com.sun.xml.internal.ws.wsdl.parser.BindingOperation;
041: import com.sun.xml.internal.ws.wsdl.writer.WSDLGenerator;
042: import com.sun.xml.internal.ws.model.soap.SOAPBinding;
043:
044: import javax.xml.namespace.QName;
045: import javax.xml.ws.WebServiceException;
046:
047: import java.lang.reflect.Method;
048: import java.security.AccessController;
049: import java.security.PrivilegedActionException;
050: import java.security.PrivilegedExceptionAction;
051: import java.util.ArrayList;
052: import java.util.Collection;
053: import java.util.Collections;
054: import java.util.HashMap;
055: import java.util.Iterator;
056: import java.util.List;
057: import java.util.Map;
058: import java.util.Set;
059:
060: /**
061: * model of the web service. Used by the runtime marshall/unmarshall
062: * web service invocations
063: *
064: * $author: JAXWS Development Team
065: */
066: public abstract class RuntimeModel {
067:
068: /**
069: *
070: */
071: public RuntimeModel() {
072: super ();
073: // TODO Auto-generated constructor stub
074: }
075:
076: public void postProcess() {
077: // should be called only once.
078: if (jaxbContext != null)
079: return;
080: populateMaps();
081: populateAsyncExceptions();
082: createJAXBContext();
083: createDecoderInfo();
084: }
085:
086: /**
087: * Populate methodToJM and nameToJM maps.
088: */
089: protected void populateMaps() {
090: for (JavaMethod jm : getJavaMethods()) {
091: put(jm.getMethod(), jm);
092: for (Parameter p : jm.getRequestParameters()) {
093: put(p.getName(), jm);
094: }
095: }
096: }
097:
098: protected void populateAsyncExceptions() {
099: for (JavaMethod jm : getJavaMethods()) {
100: int mep = jm.getMEP();
101: if (mep == MessageInfo.ASYNC_CALLBACK_MEP
102: || mep == MessageInfo.ASYNC_POLL_MEP) {
103: String opName = jm.getOperationName();
104: Method m = jm.getMethod();
105: Class[] params = m.getParameterTypes();
106: if (mep == MessageInfo.ASYNC_CALLBACK_MEP) {
107: params = new Class[params.length - 1];
108: System.arraycopy(m.getParameterTypes(), 0, params,
109: 0, m.getParameterTypes().length - 1);
110: }
111: try {
112: Method om = m.getDeclaringClass().getMethod(opName,
113: params);
114: JavaMethod jm2 = getJavaMethod(om);
115: for (CheckedException ce : jm2
116: .getCheckedExceptions()) {
117: jm.addException(ce);
118: }
119: } catch (NoSuchMethodException ex) {
120: }
121: }
122: }
123: }
124:
125: /**
126: * @return the <code>BridgeContext</code> for this <code>RuntimeModel</code>
127: */
128: public BridgeContext getBridgeContext() {
129: if (jaxbContext == null)
130: return null;
131: BridgeContext bc = bridgeContext.get();
132: if (bc == null) {
133: bc = jaxbContext.createBridgeContext();
134: bc.setAttachmentMarshaller(new JAXWSAttachmentMarshaller(
135: enableMtom));
136: bc
137: .setAttachmentUnmarshaller(new JAXWSAttachmentUnmarshaller());
138: bridgeContext.set(bc);
139: }
140: return bc;
141: }
142:
143: /**
144: * @return the <code>JAXBRIContext</code>
145: */
146: public JAXBRIContext getJAXBContext() {
147: return jaxbContext;
148: }
149:
150: /**
151: * @return the known namespaces from JAXBRIContext
152: */
153: public List<String> getKnownNamespaceURIs() {
154: return knownNamespaceURIs;
155: }
156:
157: /**
158: * @param type
159: * @return the <code>Bridge</code> for the <code>type</code>
160: */
161: public Bridge getBridge(TypeReference type) {
162: return bridgeMap.get(type);
163: }
164:
165: /**
166: * @param name
167: * @return either a <code>RpcLitpayload</code> or a <code>JAXBBridgeInfo</code> for
168: * an operation named <code>name</code>
169: */
170: public Object getDecoderInfo(QName name) {
171: Object obj = payloadMap.get(name);
172: if (obj instanceof RpcLitPayload) {
173: return RpcLitPayload.copy((RpcLitPayload) obj);
174: } else if (obj instanceof JAXBBridgeInfo) {
175: return JAXBBridgeInfo.copy((JAXBBridgeInfo) obj);
176: }
177: return null;
178: }
179:
180: /**
181: * @param name
182: * @param payload
183: */
184: public void addDecoderInfo(QName name, Object payload) {
185: payloadMap.put(name, payload);
186: }
187:
188: /**
189: * @return
190: */
191: private JAXBRIContext createJAXBContext() {
192: final List<TypeReference> types = getAllTypeReferences();
193: final Class[] cls = new Class[types.size()];
194: final String ns = targetNamespace;
195: int i = 0;
196: for (TypeReference type : types) {
197: cls[i++] = (Class) type.type;
198: }
199: try {
200: //jaxbContext = JAXBRIContext.newInstance(cls, types, targetNamespace, false);
201: // Need to avoid doPriv block once JAXB is fixed. Afterwards, use the above
202: jaxbContext = (JAXBRIContext) AccessController
203: .doPrivileged(new PrivilegedExceptionAction() {
204: public java.lang.Object run() throws Exception {
205: return JAXBRIContext.newInstance(cls,
206: types, ns, false);
207: }
208: });
209: createBridgeMap(types);
210: } catch (PrivilegedActionException e) {
211: throw new WebServiceException(e.getMessage(), e
212: .getException());
213: }
214: knownNamespaceURIs = new ArrayList<String>();
215: for (String namespace : jaxbContext.getKnownNamespaceURIs()) {
216: if (namespace.length() > 0) {
217: if (!namespace.equals(SOAPNamespaceConstants.XSD)
218: && !namespace
219: .equals(SOAPNamespaceConstants.XMLNS))
220: knownNamespaceURIs.add(namespace);
221: }
222: }
223:
224: return jaxbContext;
225: }
226:
227: /**
228: * @return returns non-null list of TypeReference
229: */
230: public List<TypeReference> getAllTypeReferences() {
231: List<TypeReference> types = new ArrayList<TypeReference>();
232: Collection<JavaMethod> methods = methodToJM.values();
233: for (JavaMethod m : methods) {
234: fillTypes(m, types);
235: fillFaultDetailTypes(m, types);
236: }
237: return types;
238: }
239:
240: private void fillFaultDetailTypes(JavaMethod m,
241: List<TypeReference> types) {
242: for (CheckedException ce : m.getCheckedExceptions()) {
243: types.add(ce.getDetailType());
244: // addGlobalType(ce.getDetailType());
245: }
246: }
247:
248: protected void fillTypes(JavaMethod m, List<TypeReference> types) {
249: addTypes(m.getRequestParameters(), types);
250: addTypes(m.getResponseParameters(), types);
251: }
252:
253: private void addTypes(List<Parameter> params,
254: List<TypeReference> types) {
255: for (Parameter p : params) {
256: types.add(p.getTypeReference());
257: }
258: }
259:
260: private void createBridgeMap(List<TypeReference> types) {
261: for (TypeReference type : types) {
262: Bridge bridge = jaxbContext.createBridge(type);
263: bridgeMap.put(type, bridge);
264: }
265: }
266:
267: /**
268: * @param qname
269: * @return the <code>Method</code> for a given Operation <code>qname</code>
270: */
271: public Method getDispatchMethod(QName qname) {
272: //handle the empty body
273: if (qname == null)
274: qname = emptyBodyName;
275: JavaMethod jm = getJavaMethod(qname);
276: if (jm != null) {
277: return jm.getMethod();
278: }
279: return null;
280: }
281:
282: /**
283: * @param name
284: * @param method
285: * @return true if <code>name</code> is the name
286: * of a known fault name for the <code>Method method</code>
287: */
288: public boolean isKnownFault(QName name, Method method) {
289: JavaMethod m = getJavaMethod(method);
290: for (CheckedException ce : m.getCheckedExceptions()) {
291: if (ce.getDetailType().tagName.equals(name))
292: return true;
293: }
294: return false;
295: }
296:
297: /**
298: * @param m
299: * @param ex
300: * @return true if <code>ex</code> is a Checked Exception
301: * for <code>Method m</code>
302: */
303: public boolean isCheckedException(Method m, Class ex) {
304: JavaMethod jm = getJavaMethod(m);
305: for (CheckedException ce : jm.getCheckedExceptions()) {
306: if (ce.getExcpetionClass().equals(ex))
307: return true;
308: }
309: return false;
310: }
311:
312: /**
313: * @param method
314: * @return the <code>JavaMethod</code> representing the <code>method</code>
315: */
316: public JavaMethod getJavaMethod(Method method) {
317: return methodToJM.get(method);
318: }
319:
320: /**
321: * @param name
322: * @return the <code>JavaMethod</code> associated with the
323: * operation named name
324: */
325: public JavaMethod getJavaMethod(QName name) {
326: return nameToJM.get(name);
327: }
328:
329: /**
330: * @param jm
331: * @return the <code>QName</code> associated with the
332: * JavaMethod jm
333: */
334: public QName getQNameForJM(JavaMethod jm) {
335: Set<QName> set = nameToJM.keySet();
336: Iterator iter = set.iterator();
337: while (iter.hasNext()) {
338: QName key = (QName) iter.next();
339: JavaMethod jmethod = (JavaMethod) nameToJM.get(key);
340: if (jmethod.getOperationName()
341: .equals(jm.getOperationName())) {
342: return key;
343: }
344: }
345: return null;
346: }
347:
348: /**
349: * @return a <code>Collection</code> of <code>JavaMethods</code>
350: * associated with this <code>RuntimeModel</code>
351: */
352: public Collection<JavaMethod> getJavaMethods() {
353: return Collections.unmodifiableList(javaMethods);
354: }
355:
356: public void addJavaMethod(JavaMethod jm) {
357: if (jm != null)
358: javaMethods.add(jm);
359: }
360:
361: public void applyParameterBinding(Binding wsdlBinding) {
362: if (wsdlBinding == null)
363: return;
364: wsdlBinding.finalizeBinding();
365: for (JavaMethod method : javaMethods) {
366: if (method.isAsync())
367: continue;
368: boolean isRpclit = ((SOAPBinding) method.getBinding())
369: .isRpcLit();
370: List<Parameter> reqParams = method.getRequestParameters();
371: List<Parameter> reqAttachParams = null;
372: for (Parameter param : reqParams) {
373: if (param.isWrapperStyle()) {
374: if (isRpclit) {
375: WrapperParameter reqParam = (WrapperParameter) param;
376: BindingOperation bo = wsdlBinding.get(method
377: .getOperationName());
378: if (bo != null
379: && bo.getRequestNamespace() != null) {
380: patchRpclitNamespace(bo
381: .getRequestNamespace(), reqParam);
382: }
383: reqAttachParams = applyRpcLitParamBinding(
384: method, reqParam, wsdlBinding, Mode.IN);
385: }
386: continue;
387: }
388: String partName = param.getPartName();
389: if (partName == null)
390: continue;
391: ParameterBinding paramBinding = wsdlBinding.getBinding(
392: method.getOperationName(), partName, Mode.IN);
393: if (paramBinding != null)
394: param.setInBinding(paramBinding);
395: }
396:
397: List<Parameter> resAttachParams = null;
398: List<Parameter> resParams = method.getResponseParameters();
399: for (Parameter param : resParams) {
400: if (param.isWrapperStyle()) {
401: if (isRpclit) {
402: WrapperParameter respParam = (WrapperParameter) param;
403: BindingOperation bo = wsdlBinding.get(method
404: .getOperationName());
405: if (bo != null
406: && bo.getResponseNamespace() != null) {
407: patchRpclitNamespace(bo
408: .getResponseNamespace(), respParam);
409: }
410: resAttachParams = applyRpcLitParamBinding(
411: method, respParam, wsdlBinding,
412: Mode.OUT);
413: }
414: continue;
415: }
416: //if the parameter is not inout and its header=true then dont get binding from WSDL
417: // if(!param.isINOUT() && param.getBinding().isHeader())
418: // continue;
419: String partName = param.getPartName();
420: if (partName == null)
421: continue;
422: ParameterBinding paramBinding = wsdlBinding.getBinding(
423: method.getOperationName(), partName, Mode.OUT);
424: if (paramBinding != null)
425: param.setOutBinding(paramBinding);
426: }
427: if (reqAttachParams != null) {
428: for (Parameter p : reqAttachParams) {
429: method.addRequestParameter(p);
430: }
431: }
432: if (resAttachParams != null) {
433: for (Parameter p : resAttachParams) {
434: method.addResponseParameter(p);
435: }
436: }
437:
438: }
439: }
440:
441: /**
442: * For rpclit wrapper element inside <soapenv:Body>, the targetNamespace should be taked from
443: * the soapbind:body@namespace value. Since no annotations on SEI/impl class captures it so we
444: * need to get it from WSDL and patch it. *
445: */
446: private void patchRpclitNamespace(String namespace,
447: WrapperParameter param) {
448: TypeReference type = param.getTypeReference();
449: TypeReference newType = new TypeReference(new QName(namespace,
450: type.tagName.getLocalPart()), type.type,
451: type.annotations);
452:
453: param.setTypeReference(newType);
454: }
455:
456: /**
457: * Applies binding related information to the RpcLitPayload. The payload map is populated correctly.
458: * @param method
459: * @param wrapperParameter
460: * @param wsdlBinding
461: * @param mode
462: * @return
463: *
464: * Returns attachment parameters if/any.
465: */
466: private List<Parameter> applyRpcLitParamBinding(JavaMethod method,
467: WrapperParameter wrapperParameter, Binding wsdlBinding,
468: Mode mode) {
469: String opName = method.getOperationName();
470: RpcLitPayload payload = new RpcLitPayload(wrapperParameter
471: .getName());
472: BindingOperation bo = wsdlBinding.get(opName);
473:
474: Map<Integer, Parameter> bodyParams = new HashMap<Integer, Parameter>();
475: List<Parameter> unboundParams = new ArrayList<Parameter>();
476: List<Parameter> attachParams = new ArrayList<Parameter>();
477: for (Parameter param : wrapperParameter.getWrapperChildren()) {
478: String partName = param.getPartName();
479: if (partName == null)
480: continue;
481:
482: ParameterBinding paramBinding = wsdlBinding.getBinding(
483: opName, partName, mode);
484: if (paramBinding != null) {
485: if (mode == Mode.IN)
486: param.setInBinding(paramBinding);
487: else if (mode == Mode.OUT)
488: param.setOutBinding(paramBinding);
489:
490: if (paramBinding.isUnbound()) {
491: unboundParams.add(param);
492: } else if (paramBinding.isAttachment()) {
493: attachParams.add(param);
494: } else if (paramBinding.isBody()) {
495: if (bo != null) {
496: Part p = bo.getPart(param.getPartName(), mode);
497: if (p != null)
498: bodyParams.put(p.getIndex(), param);
499: else
500: bodyParams.put(bodyParams.size(), param);
501: } else {
502: bodyParams.put(bodyParams.size(), param);
503: }
504: }
505: }
506:
507: }
508: wrapperParameter.clear();
509: for (int i = 0; i < bodyParams.size(); i++) {
510: Parameter p = bodyParams.get(i);
511: wrapperParameter.addWrapperChild(p);
512: if (((mode == Mode.IN) && p.getInBinding().isBody())
513: || ((mode == Mode.OUT) && p.getOutBinding()
514: .isBody())) {
515: JAXBBridgeInfo bi = new JAXBBridgeInfo(getBridge(p
516: .getTypeReference()), null);
517: payload.addParameter(bi);
518: }
519: }
520:
521: for (Parameter p : attachParams) {
522: JAXBBridgeInfo bi = new JAXBBridgeInfo(getBridge(p
523: .getTypeReference()), null);
524: payloadMap.put(p.getName(), bi);
525: }
526:
527: //add unbounded parts
528: for (Parameter p : unboundParams) {
529: wrapperParameter.addWrapperChild(p);
530: }
531: payloadMap.put(wrapperParameter.getName(), payload);
532: return attachParams;
533: }
534:
535: /**
536: * @param name
537: * @param jm
538: */
539: protected void put(QName name, JavaMethod jm) {
540: nameToJM.put(name, jm);
541: }
542:
543: /**
544: * @param method
545: * @param jm
546: */
547: protected void put(Method method, JavaMethod jm) {
548: methodToJM.put(method, jm);
549: }
550:
551: public String getWSDLLocation() {
552: return wsdlLocation;
553: }
554:
555: public void setWSDLLocation(String location) {
556: wsdlLocation = location;
557: }
558:
559: public QName getServiceQName() {
560: return serviceName;
561: }
562:
563: public QName getPortName() {
564: return portName;
565: }
566:
567: public QName getPortTypeName() {
568: return portTypeName;
569: }
570:
571: public void setServiceQName(QName name) {
572: serviceName = name;
573: }
574:
575: public void setPortName(QName name) {
576: portName = name;
577: }
578:
579: public void setPortTypeName(QName name) {
580: portTypeName = name;
581: }
582:
583: /**
584: * This is the targetNamespace for the WSDL containing the PortType
585: * definition
586: */
587: public void setTargetNamespace(String namespace) {
588: targetNamespace = namespace;
589: }
590:
591: /**
592: * This is the targetNamespace for the WSDL containing the PortType
593: * definition
594: */
595: public String getTargetNamespace() {
596: return targetNamespace;
597: }
598:
599: /**
600: * Add a global type. Global types will be used to generate global
601: * elements in the generated schema's
602: * @param typeReference
603: */
604: /* public void addGlobalType(TypeReference typeReference) {
605:
606: }*/
607:
608: /**
609: * Add a global type. Global types will be used to generate global
610: * elements in the generated schema's
611: * @return
612: */
613: /* public Collection<TypeReference> getGlobalTypes() {
614: return globalTypes;
615: }*/
616:
617: /**
618: * Mtom processing is disabled by default. To enable it the RuntimeModel creator must call it to enable it.
619: * @param enableMtom
620: */
621: public void enableMtom(boolean enableMtom) {
622: this .enableMtom = enableMtom;
623: }
624:
625: public Map<Integer, RawAccessor> getRawAccessorMap() {
626: return rawAccessorMap;
627: }
628:
629: protected abstract void createDecoderInfo();
630:
631: private boolean enableMtom = false;
632: private ThreadLocal<BridgeContext> bridgeContext = new ThreadLocal<BridgeContext>();
633: protected JAXBRIContext jaxbContext;
634: private String wsdlLocation;
635: private QName serviceName;
636: private QName portName;
637: private QName portTypeName;
638: private Map<Method, JavaMethod> methodToJM = new HashMap<Method, JavaMethod>();
639: private Map<QName, JavaMethod> nameToJM = new HashMap<QName, JavaMethod>();
640: private List<JavaMethod> javaMethods = new ArrayList<JavaMethod>();
641: private final Map<TypeReference, Bridge> bridgeMap = new HashMap<TypeReference, Bridge>();
642: private final Map<QName, Object> payloadMap = new HashMap<QName, Object>();
643: protected final QName emptyBodyName = new QName("");
644: private String targetNamespace = "";
645: private final Map<Integer, RawAccessor> rawAccessorMap = new HashMap<Integer, RawAccessor>();
646: private List<String> knownNamespaceURIs = null;
647: // protected Collection<TypeReference> globalTypes = new ArrayList<TypeReference>();
648: }
|