aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.model; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.xml.internal.bind.api.Bridge; aoqi@0: import com.sun.xml.internal.bind.api.JAXBRIContext; aoqi@0: import com.sun.xml.internal.bind.api.TypeReference; aoqi@0: import com.sun.xml.internal.ws.api.BindingID; aoqi@0: import com.sun.xml.internal.ws.api.WSBinding; aoqi@0: import com.sun.xml.internal.ws.api.databinding.Databinding; aoqi@0: import com.sun.xml.internal.ws.api.model.JavaMethod; aoqi@0: import com.sun.xml.internal.ws.api.model.ParameterBinding; aoqi@0: import com.sun.xml.internal.ws.api.model.SEIModel; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLModel; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLPart; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundPortType; aoqi@0: import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; aoqi@0: import com.sun.xml.internal.ws.encoding.soap.streaming.SOAPNamespaceConstants; aoqi@0: import com.sun.xml.internal.ws.resources.ModelerMessages; aoqi@0: import com.sun.xml.internal.ws.spi.db.BindingContext; aoqi@0: import com.sun.xml.internal.ws.spi.db.BindingContextFactory; aoqi@0: import com.sun.xml.internal.ws.spi.db.BindingInfo; aoqi@0: import com.sun.xml.internal.ws.spi.db.XMLBridge; aoqi@0: import com.sun.xml.internal.ws.spi.db.TypeInfo; aoqi@0: import com.sun.xml.internal.ws.util.Pool; aoqi@0: import com.sun.xml.internal.ws.developer.UsesJAXBContextFeature; aoqi@0: import com.sun.xml.internal.ws.developer.JAXBContextFactory; aoqi@0: import com.sun.xml.internal.ws.binding.WebServiceFeatureList; aoqi@0: aoqi@0: import javax.jws.WebParam.Mode; aoqi@0: import javax.xml.bind.JAXBContext; aoqi@0: import javax.xml.bind.annotation.XmlSeeAlso; aoqi@0: import javax.xml.namespace.QName; aoqi@0: import javax.xml.ws.WebServiceException; aoqi@0: aoqi@0: aoqi@0: import java.lang.reflect.Method; aoqi@0: import java.security.AccessController; aoqi@0: import java.security.PrivilegedActionException; aoqi@0: import java.security.PrivilegedExceptionAction; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.Collection; aoqi@0: import java.util.Collections; aoqi@0: import java.util.HashMap; aoqi@0: import java.util.List; aoqi@0: import java.util.Map; aoqi@0: import java.util.logging.Level; aoqi@0: import java.util.logging.Logger; aoqi@0: aoqi@0: /** aoqi@0: * model of the web service. Used by the runtime marshall/unmarshall aoqi@0: * web service invocations aoqi@0: * aoqi@0: * @author JAXWS Development Team aoqi@0: */ aoqi@0: public abstract class AbstractSEIModelImpl implements SEIModel { aoqi@0: aoqi@0: protected AbstractSEIModelImpl(WebServiceFeatureList features) { aoqi@0: this.features = features; aoqi@0: databindingInfo = new BindingInfo(); aoqi@0: databindingInfo.setSEIModel(this); aoqi@0: } aoqi@0: aoqi@0: void postProcess() { aoqi@0: // should be called only once. aoqi@0: if (jaxbContext != null) { aoqi@0: return; aoqi@0: } aoqi@0: populateMaps(); aoqi@0: createJAXBContext(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Link {@link SEIModel} to {@link WSDLModel}. aoqi@0: * Merge it with {@link #postProcess()}. aoqi@0: */ aoqi@0: public void freeze(WSDLPort port) { aoqi@0: this.port = port; aoqi@0: for (JavaMethodImpl m : javaMethods) { aoqi@0: m.freeze(port); aoqi@0: putOp(m.getOperationQName(),m); aoqi@0: aoqi@0: } aoqi@0: if (databinding != null) { aoqi@0: ((com.sun.xml.internal.ws.db.DatabindingImpl)databinding).freeze(port); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Populate methodToJM and nameToJM maps. aoqi@0: */ aoqi@0: abstract protected void populateMaps(); aoqi@0: aoqi@0: @Override aoqi@0: public Pool.Marshaller getMarshallerPool() { aoqi@0: return marshallers; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return the JAXBRIContext aoqi@0: * @deprecated aoqi@0: */ aoqi@0: @Override aoqi@0: public JAXBContext getJAXBContext() { aoqi@0: JAXBContext jc = bindingContext.getJAXBContext(); aoqi@0: if (jc != null) { aoqi@0: return jc; aoqi@0: } aoqi@0: return jaxbContext; aoqi@0: } aoqi@0: aoqi@0: public BindingContext getBindingContext() { aoqi@0: return bindingContext; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return the known namespaces from JAXBRIContext aoqi@0: */ aoqi@0: public List getKnownNamespaceURIs() { aoqi@0: return knownNamespaceURIs; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return the Bridge for the type aoqi@0: * @deprecated use getBond aoqi@0: */ aoqi@0: public final Bridge getBridge(TypeReference type) { aoqi@0: Bridge b = bridgeMap.get(type); aoqi@0: assert b!=null; // we should have created Bridge for all TypeReferences known to this model aoqi@0: return b; aoqi@0: } aoqi@0: aoqi@0: public final XMLBridge getXMLBridge(TypeInfo type) { aoqi@0: XMLBridge b = xmlBridgeMap.get(type); aoqi@0: assert b!=null; // we should have created Bridge for all TypeReferences known to this model aoqi@0: return b; aoqi@0: } aoqi@0: aoqi@0: private void /*JAXBRIContext*/ createJAXBContext() { aoqi@0: final List types = getAllTypeInfos(); aoqi@0: final List cls = new ArrayList(types.size() + additionalClasses.size()); aoqi@0: aoqi@0: cls.addAll(additionalClasses); aoqi@0: for (TypeInfo type : types) { aoqi@0: cls.add((Class) type.type); aoqi@0: } aoqi@0: aoqi@0: try { aoqi@0: //jaxbContext = JAXBRIContext.newInstance(cls, types, targetNamespace, false); aoqi@0: // Need to avoid doPriv block once JAXB is fixed. Afterwards, use the above aoqi@0: bindingContext = AccessController.doPrivileged(new PrivilegedExceptionAction() { aoqi@0: public BindingContext run() throws Exception { aoqi@0: if(LOGGER.isLoggable(Level.FINEST)) { aoqi@0: LOGGER.log(Level.FINEST, "Creating JAXBContext with classes={0} and types={1}", new Object[]{cls, types}); aoqi@0: } aoqi@0: UsesJAXBContextFeature f = features.get(UsesJAXBContextFeature.class); aoqi@0: com.oracle.webservices.internal.api.databinding.DatabindingModeFeature dmf = aoqi@0: features.get(com.oracle.webservices.internal.api.databinding.DatabindingModeFeature.class); aoqi@0: JAXBContextFactory factory = f!=null ? f.getFactory() : null; aoqi@0: if(factory==null) factory=JAXBContextFactory.DEFAULT; aoqi@0: aoqi@0: // return factory.createJAXBContext(AbstractSEIModelImpl.this,cls,types); aoqi@0: aoqi@0: databindingInfo.properties().put(JAXBContextFactory.class.getName(), factory); aoqi@0: if (dmf != null) { aoqi@0: if (LOGGER.isLoggable(Level.FINE)) aoqi@0: LOGGER.log(Level.FINE, "DatabindingModeFeature in SEI specifies mode: {0}", dmf.getMode()); aoqi@0: databindingInfo.setDatabindingMode(dmf aoqi@0: .getMode()); aoqi@0: } aoqi@0: aoqi@0: if (f!=null) databindingInfo.setDatabindingMode(BindingContextFactory.DefaultDatabindingMode); aoqi@0: databindingInfo.setClassLoader(classLoader); aoqi@0: databindingInfo.contentClasses().addAll(cls); aoqi@0: databindingInfo.typeInfos().addAll(types); aoqi@0: databindingInfo.properties().put("c14nSupport", Boolean.FALSE); aoqi@0: databindingInfo.setDefaultNamespace(AbstractSEIModelImpl.this.getDefaultSchemaNamespace()); aoqi@0: BindingContext bc = BindingContextFactory.create(databindingInfo); aoqi@0: if (LOGGER.isLoggable(Level.FINE)) aoqi@0: LOGGER.log(Level.FINE, aoqi@0: "Created binding context: " aoqi@0: + bc.getClass().getName()); aoqi@0: // System.out.println("---------------------- databinding " + bc); aoqi@0: return bc; aoqi@0: } aoqi@0: }); aoqi@0: // createBridgeMap(types); aoqi@0: createBondMap(types); aoqi@0: } catch (PrivilegedActionException e) { aoqi@0: throw new WebServiceException(ModelerMessages.UNABLE_TO_CREATE_JAXB_CONTEXT(), e); aoqi@0: } aoqi@0: knownNamespaceURIs = new ArrayList(); aoqi@0: for (String namespace : bindingContext.getKnownNamespaceURIs()) { aoqi@0: if (namespace.length() > 0) { aoqi@0: if (!namespace.equals(SOAPNamespaceConstants.XSD) && !namespace.equals(SOAPNamespaceConstants.XMLNS)) aoqi@0: knownNamespaceURIs.add(namespace); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: marshallers = new Pool.Marshaller(jaxbContext); aoqi@0: aoqi@0: //return getJAXBContext(); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return returns non-null list of TypeReference aoqi@0: */ aoqi@0: private List getAllTypeInfos() { aoqi@0: List types = new ArrayList(); aoqi@0: Collection methods = methodToJM.values(); aoqi@0: for (JavaMethodImpl m : methods) { aoqi@0: m.fillTypes(types); aoqi@0: } aoqi@0: return types; aoqi@0: } aoqi@0: aoqi@0: private void createBridgeMap(List types) { aoqi@0: for (TypeReference type : types) { aoqi@0: Bridge bridge = jaxbContext.createBridge(type); aoqi@0: bridgeMap.put(type, bridge); aoqi@0: } aoqi@0: } aoqi@0: private void createBondMap(List types) { aoqi@0: for (TypeInfo type : types) { aoqi@0: XMLBridge binding = bindingContext.createBridge(type); aoqi@0: xmlBridgeMap.put(type, binding); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * @return true if name is the name aoqi@0: * of a known fault name for the Method method aoqi@0: */ aoqi@0: public boolean isKnownFault(QName name, Method method) { aoqi@0: JavaMethodImpl m = getJavaMethod(method); aoqi@0: for (CheckedExceptionImpl ce : m.getCheckedExceptions()) { aoqi@0: if (ce.getDetailType().tagName.equals(name)) aoqi@0: return true; aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return true if ex is a Checked Exception aoqi@0: * for Method m aoqi@0: */ aoqi@0: public boolean isCheckedException(Method m, Class ex) { aoqi@0: JavaMethodImpl jm = getJavaMethod(m); aoqi@0: for (CheckedExceptionImpl ce : jm.getCheckedExceptions()) { aoqi@0: if (ce.getExceptionClass().equals(ex)) aoqi@0: return true; aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return the JavaMethod representing the method aoqi@0: */ aoqi@0: public JavaMethodImpl getJavaMethod(Method method) { aoqi@0: return methodToJM.get(method); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return the JavaMethod associated with the aoqi@0: * operation named name aoqi@0: */ aoqi@0: public JavaMethodImpl getJavaMethod(QName name) { aoqi@0: return nameToJM.get(name); aoqi@0: } aoqi@0: aoqi@0: public JavaMethod getJavaMethodForWsdlOperation(QName operationName) { aoqi@0: return wsdlOpToJM.get(operationName); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /** aoqi@0: * @return the QName associated with the aoqi@0: * JavaMethod jm. aoqi@0: * aoqi@0: * @deprecated aoqi@0: * Use {@link JavaMethod#getOperationName()}. aoqi@0: */ aoqi@0: public QName getQNameForJM(JavaMethodImpl jm) { aoqi@0: for (QName key : nameToJM.keySet()) { aoqi@0: JavaMethodImpl jmethod = nameToJM.get(key); aoqi@0: if (jmethod.getOperationName().equals(jm.getOperationName())){ aoqi@0: return key; aoqi@0: } aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * @return a Collection of JavaMethods aoqi@0: * associated with this RuntimeModel aoqi@0: */ aoqi@0: public final Collection getJavaMethods() { aoqi@0: return Collections.unmodifiableList(javaMethods); aoqi@0: } aoqi@0: aoqi@0: void addJavaMethod(JavaMethodImpl jm) { aoqi@0: if (jm != null) aoqi@0: javaMethods.add(jm); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Applies binding related information to the RpcLitPayload. The payload map is populated correctly aoqi@0: * @return aoqi@0: * Returns attachment parameters if/any. aoqi@0: */ aoqi@0: private List applyRpcLitParamBinding(JavaMethodImpl method, WrapperParameter wrapperParameter, WSDLBoundPortType boundPortType, Mode mode) { aoqi@0: QName opName = new QName(boundPortType.getPortTypeName().getNamespaceURI(), method.getOperationName()); aoqi@0: WSDLBoundOperation bo = boundPortType.get(opName); aoqi@0: Map bodyParams = new HashMap(); aoqi@0: List unboundParams = new ArrayList(); aoqi@0: List attachParams = new ArrayList(); aoqi@0: for(ParameterImpl param : wrapperParameter.wrapperChildren){ aoqi@0: String partName = param.getPartName(); aoqi@0: if(partName == null) aoqi@0: continue; aoqi@0: aoqi@0: ParameterBinding paramBinding = boundPortType.getBinding(opName, aoqi@0: partName, mode); aoqi@0: if(paramBinding != null){ aoqi@0: if(mode == Mode.IN) aoqi@0: param.setInBinding(paramBinding); aoqi@0: else if(mode == Mode.OUT || mode == Mode.INOUT) aoqi@0: param.setOutBinding(paramBinding); aoqi@0: aoqi@0: if(paramBinding.isUnbound()){ aoqi@0: unboundParams.add(param); aoqi@0: } else if(paramBinding.isAttachment()){ aoqi@0: attachParams.add(param); aoqi@0: }else if(paramBinding.isBody()){ aoqi@0: if(bo != null){ aoqi@0: WSDLPart p = bo.getPart(param.getPartName(), mode); aoqi@0: if(p != null) aoqi@0: bodyParams.put(p.getIndex(), param); aoqi@0: else aoqi@0: bodyParams.put(bodyParams.size(), param); aoqi@0: }else{ aoqi@0: bodyParams.put(bodyParams.size(), param); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: } aoqi@0: wrapperParameter.clear(); aoqi@0: for(int i = 0; i < bodyParams.size();i++){ aoqi@0: ParameterImpl p = bodyParams.get(i); aoqi@0: wrapperParameter.addWrapperChild(p); aoqi@0: } aoqi@0: aoqi@0: //add unbounded parts aoqi@0: for(ParameterImpl p:unboundParams){ aoqi@0: wrapperParameter.addWrapperChild(p); aoqi@0: } aoqi@0: return attachParams; aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void put(QName name, JavaMethodImpl jm) { aoqi@0: nameToJM.put(name, jm); aoqi@0: } aoqi@0: aoqi@0: void put(Method method, JavaMethodImpl jm) { aoqi@0: methodToJM.put(method, jm); aoqi@0: } aoqi@0: aoqi@0: void putOp(QName opName, JavaMethodImpl jm) { aoqi@0: wsdlOpToJM.put(opName, jm); aoqi@0: } aoqi@0: public String getWSDLLocation() { aoqi@0: return wsdlLocation; aoqi@0: } aoqi@0: aoqi@0: void setWSDLLocation(String location) { aoqi@0: wsdlLocation = location; aoqi@0: } aoqi@0: aoqi@0: public QName getServiceQName() { aoqi@0: return serviceName; aoqi@0: } aoqi@0: aoqi@0: public WSDLPort getPort() { aoqi@0: return port; aoqi@0: } aoqi@0: aoqi@0: public QName getPortName() { aoqi@0: return portName; aoqi@0: } aoqi@0: aoqi@0: public QName getPortTypeName() { aoqi@0: return portTypeName; aoqi@0: } aoqi@0: aoqi@0: void setServiceQName(QName name) { aoqi@0: serviceName = name; aoqi@0: } aoqi@0: aoqi@0: void setPortName(QName name) { aoqi@0: portName = name; aoqi@0: } aoqi@0: aoqi@0: void setPortTypeName(QName name) { aoqi@0: portTypeName = name; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This is the targetNamespace for the WSDL containing the PortType aoqi@0: * definition aoqi@0: */ aoqi@0: void setTargetNamespace(String namespace) { aoqi@0: targetNamespace = namespace; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * This is the targetNamespace for the WSDL containing the PortType aoqi@0: * definition aoqi@0: */ aoqi@0: public String getTargetNamespace() { aoqi@0: return targetNamespace; aoqi@0: } aoqi@0: aoqi@0: String getDefaultSchemaNamespace() { aoqi@0: String defaultNamespace = getTargetNamespace(); aoqi@0: if (defaultSchemaNamespaceSuffix == null) return defaultNamespace; aoqi@0: if (!defaultNamespace.endsWith("/")) { aoqi@0: defaultNamespace += "/"; aoqi@0: } aoqi@0: return (defaultNamespace + defaultSchemaNamespaceSuffix); aoqi@0: } aoqi@0: aoqi@0: @NotNull aoqi@0: public QName getBoundPortTypeName() { aoqi@0: assert portName != null; aoqi@0: return new QName(portName.getNamespaceURI(), portName.getLocalPart()+"Binding"); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Adds additional classes obtained from {@link XmlSeeAlso} annotation. In starting aoqi@0: * from wsdl case these classes would most likely be JAXB ObjectFactory that references other classes. aoqi@0: */ aoqi@0: public void addAdditionalClasses(Class... additionalClasses) { aoqi@0: for(Class cls : additionalClasses) aoqi@0: this.additionalClasses.add(cls); aoqi@0: } aoqi@0: aoqi@0: public Databinding getDatabinding() { aoqi@0: return databinding; aoqi@0: } aoqi@0: aoqi@0: public void setDatabinding(Databinding wsRuntime) { aoqi@0: this.databinding = wsRuntime; aoqi@0: } aoqi@0: aoqi@0: public WSBinding getWSBinding() { aoqi@0: return wsBinding; aoqi@0: } aoqi@0: aoqi@0: public Class getContractClass() { aoqi@0: return contractClass; aoqi@0: } aoqi@0: aoqi@0: public Class getEndpointClass() { aoqi@0: return endpointClass; aoqi@0: } aoqi@0: aoqi@0: private List additionalClasses = new ArrayList(); aoqi@0: aoqi@0: private Pool.Marshaller marshallers; aoqi@0: /** aoqi@0: * @deprecated aoqi@0: */ aoqi@0: protected JAXBRIContext jaxbContext; aoqi@0: protected BindingContext bindingContext; aoqi@0: private String wsdlLocation; aoqi@0: private QName serviceName; aoqi@0: private QName portName; aoqi@0: private QName portTypeName; aoqi@0: private Map methodToJM = new HashMap(); aoqi@0: /** aoqi@0: * Payload QName to the method that handles it. aoqi@0: */ aoqi@0: private Map nameToJM = new HashMap(); aoqi@0: /** aoqi@0: * Wsdl Operation QName to the method that handles it. aoqi@0: */ aoqi@0: private Map wsdlOpToJM = new HashMap(); aoqi@0: aoqi@0: private List javaMethods = new ArrayList(); aoqi@0: private final Map bridgeMap = new HashMap(); aoqi@0: private final Map xmlBridgeMap = new HashMap(); aoqi@0: protected final QName emptyBodyName = new QName(""); aoqi@0: private String targetNamespace = ""; aoqi@0: private List knownNamespaceURIs = null; aoqi@0: private WSDLPort port; aoqi@0: private final WebServiceFeatureList features; aoqi@0: private Databinding databinding; aoqi@0: BindingID bindingId; aoqi@0: protected Class contractClass; aoqi@0: protected Class endpointClass; aoqi@0: protected ClassLoader classLoader = null; aoqi@0: protected WSBinding wsBinding; aoqi@0: protected BindingInfo databindingInfo; aoqi@0: protected String defaultSchemaNamespaceSuffix; aoqi@0: private static final Logger LOGGER = Logger.getLogger(AbstractSEIModelImpl.class.getName()); aoqi@0: }