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.db;
  27 
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.io.OutputStream;
  31 import java.lang.reflect.Method;
  32 import java.util.HashMap;
  33 import java.util.Map;
  34 
  35 import javax.xml.ws.WebServiceFeature;
  36 
  37 import com.oracle.webservices.internal.api.databinding.JavaCallInfo;
  38 import com.oracle.webservices.internal.api.message.MessageContext;
  39 import com.sun.xml.internal.ws.api.databinding.EndpointCallBridge;
  40 import com.sun.xml.internal.ws.api.databinding.WSDLGenInfo;
  41 import com.sun.xml.internal.ws.api.databinding.Databinding;
  42 import com.sun.xml.internal.ws.api.databinding.DatabindingConfig;
  43 import com.sun.xml.internal.ws.api.databinding.ClientCallBridge;
  44 import com.sun.xml.internal.ws.api.message.Message;
  45 import com.sun.xml.internal.ws.api.message.MessageContextFactory;
  46 import com.sun.xml.internal.ws.api.message.Packet;
  47 import com.sun.xml.internal.ws.api.model.MEP;
  48 import com.sun.xml.internal.ws.api.model.SEIModel;
  49 import com.sun.xml.internal.ws.api.model.WSDLOperationMapping;
  50 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
  51 import com.sun.xml.internal.ws.api.pipe.Codec;
  52 import com.sun.xml.internal.ws.api.pipe.ContentType;
  53 import com.sun.xml.internal.ws.binding.BindingImpl;
  54 import com.sun.xml.internal.ws.client.sei.StubAsyncHandler;
  55 import com.sun.xml.internal.ws.client.sei.StubHandler;
  56 import com.sun.xml.internal.ws.model.AbstractSEIModelImpl;
  57 import com.sun.xml.internal.ws.model.JavaMethodImpl;
  58 import com.sun.xml.internal.ws.model.RuntimeModeler;
  59 import com.sun.xml.internal.ws.server.sei.TieHandler;
  60 import com.sun.xml.internal.ws.wsdl.ActionBasedOperationSignature;
  61 import com.sun.xml.internal.ws.wsdl.DispatchException;
  62 import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
  63 
  64 /**
  65  * WsRuntimeImpl is the databinding processor built on SEIModel
  66  *
  67  * @author shih-chang.chen@oracle.com
  68  */
  69 public final class DatabindingImpl implements Databinding {
  70 
  71     AbstractSEIModelImpl seiModel;
  72     Map<Method, StubHandler> stubHandlers;
  73 //    QNameMap<TieHandler> wsdlOpMap = new QNameMap<TieHandler>();
  74     Map<JavaMethodImpl, TieHandler> wsdlOpMap = new HashMap<JavaMethodImpl, TieHandler>();
  75     Map<Method, TieHandler> tieHandlers = new HashMap<Method, TieHandler>();
  76     OperationDispatcher operationDispatcher;
  77     OperationDispatcher operationDispatcherNoWsdl;
  78     boolean clientConfig = false;
  79     Codec codec;
  80     MessageContextFactory packetFactory = null;
  81 
  82     public DatabindingImpl(DatabindingProviderImpl p, DatabindingConfig config) {
  83         RuntimeModeler modeler = new RuntimeModeler(config);
  84         modeler.setClassLoader(config.getClassLoader());
  85         seiModel = modeler.buildRuntimeModel();
  86         WSDLPort wsdlport = config.getWsdlPort();
  87         Object facProp = config.properties().get("com.sun.xml.internal.ws.api.message.MessageContextFactory");
  88         packetFactory = (facProp != null && facProp instanceof MessageContextFactory)? (MessageContextFactory)facProp :
  89                         new MessageContextFactory(seiModel.getWSBinding().getFeatures());
  90         clientConfig = isClientConfig(config);
  91         if (clientConfig) {
  92             initStubHandlers();
  93         }
  94         seiModel.setDatabinding(this);
  95         if (wsdlport != null) {
  96             freeze(wsdlport);
  97         }
  98         if (operationDispatcher == null) {
  99             operationDispatcherNoWsdl = new OperationDispatcher(null, seiModel.getWSBinding(), seiModel);
 100         }
 101 //    if(!clientConfig) {
 102         for (JavaMethodImpl jm : seiModel.getJavaMethods()) {
 103             if (!jm.isAsync()) {
 104                 TieHandler th = new TieHandler(jm, seiModel.getWSBinding(), packetFactory);
 105                 wsdlOpMap.put(jm, th);
 106                 tieHandlers.put(th.getMethod(), th);
 107             }
 108         }
 109 //    }
 110     }
 111 
 112     //TODO isClientConfig
 113     private boolean isClientConfig(DatabindingConfig config) {
 114         if (config.getContractClass() == null) {
 115             return false;
 116         }
 117         if (!config.getContractClass().isInterface()) {
 118             return false;
 119         }
 120         return (config.getEndpointClass() == null || config.getEndpointClass().isInterface());
 121     }
 122     //TODO fix freeze
 123 
 124     public void freeze(WSDLPort port) {
 125         if (clientConfig) {
 126             return;
 127         }
 128         synchronized(this) {
 129             if (operationDispatcher == null) {
 130                 operationDispatcher = (port == null) ? null : new OperationDispatcher(port, seiModel.getWSBinding(), seiModel);
 131             }
 132         }
 133     }
 134 
 135     public SEIModel getModel() {
 136         return seiModel;
 137     }
 138 //Refactored from SEIStub
 139 
 140     private void initStubHandlers() {
 141         stubHandlers = new HashMap<Method, StubHandler>();
 142         Map<ActionBasedOperationSignature, JavaMethodImpl> syncs = new HashMap<ActionBasedOperationSignature, JavaMethodImpl>();
 143         // fill in methodHandlers.
 144         // first fill in sychronized versions
 145         for (JavaMethodImpl m : seiModel.getJavaMethods()) {
 146             if (!m.getMEP().isAsync) {
 147                 StubHandler handler = new StubHandler(m, packetFactory);
 148                 syncs.put(m.getOperationSignature(), m);
 149                 stubHandlers.put(m.getMethod(), handler);
 150             }
 151         }
 152         for (JavaMethodImpl jm : seiModel.getJavaMethods()) {
 153             JavaMethodImpl sync = syncs.get(jm.getOperationSignature());
 154             if (jm.getMEP() == MEP.ASYNC_CALLBACK || jm.getMEP() == MEP.ASYNC_POLL) {
 155                 Method m = jm.getMethod();
 156                 StubAsyncHandler handler = new StubAsyncHandler(jm, sync, packetFactory);
 157                 stubHandlers.put(m, handler);
 158             }
 159         }
 160     }
 161 
 162     JavaMethodImpl resolveJavaMethod(Packet req) throws DispatchException {
 163         WSDLOperationMapping m = req.getWSDLOperationMapping();
 164         if (m == null) {
 165             synchronized (this) {
 166                 m = (operationDispatcher != null)
 167                         ? operationDispatcher.getWSDLOperationMapping(req)
 168                         : operationDispatcherNoWsdl.getWSDLOperationMapping(req);
 169             }
 170         }
 171         return (JavaMethodImpl) m.getJavaMethod();
 172     }
 173 
 174     public JavaCallInfo deserializeRequest(Packet req) {
 175         com.sun.xml.internal.ws.api.databinding.JavaCallInfo call = new com.sun.xml.internal.ws.api.databinding.JavaCallInfo();
 176         try {
 177             JavaMethodImpl wsdlOp = resolveJavaMethod(req);
 178             TieHandler tie = wsdlOpMap.get(wsdlOp);
 179             call.setMethod(tie.getMethod());
 180             Object[] args = tie.readRequest(req.getMessage());
 181             call.setParameters(args);
 182         } catch (DispatchException e) {
 183             call.setException(e);
 184         }
 185         return call;
 186     }
 187 
 188     public JavaCallInfo deserializeResponse(Packet res, JavaCallInfo call) {
 189         StubHandler stubHandler = stubHandlers.get(call.getMethod());
 190         try {
 191             return stubHandler.readResponse(res, call);
 192         } catch (Throwable e) {
 193             call.setException(e);
 194             return call;
 195         }
 196     }
 197 
 198     public WebServiceFeature[] getFeatures() {
 199         // TODO Auto-generated method stub
 200         return null;
 201     }
 202 
 203     @Override
 204     public Packet serializeRequest(JavaCallInfo call) {
 205         StubHandler stubHandler = stubHandlers.get(call.getMethod());
 206         Packet p = stubHandler.createRequestPacket(call);
 207         p.setState(Packet.State.ClientRequest);
 208         return p;
 209     }
 210 
 211     @Override
 212     public Packet serializeResponse(JavaCallInfo call) {
 213         Method method = call.getMethod();
 214         Message message = null;
 215         if (method != null) {
 216             TieHandler th = tieHandlers.get(method);
 217             if (th != null) {
 218                 return th.serializeResponse(call);
 219             }
 220         }
 221         if (call.getException() instanceof DispatchException) {
 222             message = ((DispatchException) call.getException()).fault;
 223         }
 224         Packet p = (Packet) packetFactory.createContext(message);
 225         p.setState(Packet.State.ServerResponse);
 226         return p;
 227     }
 228 
 229     @Override
 230     public ClientCallBridge getClientBridge(Method method) {
 231         return stubHandlers.get(method);
 232     }
 233 
 234     @Override
 235     public void generateWSDL(WSDLGenInfo info) {
 236         com.sun.xml.internal.ws.wsdl.writer.WSDLGenerator wsdlGen = new com.sun.xml.internal.ws.wsdl.writer.WSDLGenerator(
 237                 seiModel,
 238                 info.getWsdlResolver(),
 239                 seiModel.getWSBinding(),
 240                 info.getContainer(), seiModel.getEndpointClass(),
 241                 info.isInlineSchemas(),
 242                 info.isSecureXmlProcessingDisabled(),
 243                 info.getExtensions());
 244         wsdlGen.doGeneration();
 245     }
 246 
 247     @Override
 248     public EndpointCallBridge getEndpointBridge(Packet req) throws DispatchException {
 249         JavaMethodImpl wsdlOp = resolveJavaMethod(req);
 250         return wsdlOpMap.get(wsdlOp);
 251     }
 252 
 253     Codec getCodec() {
 254         if (codec == null) {
 255             codec = ((BindingImpl) seiModel.getWSBinding()).createCodec();
 256         }
 257         return codec;
 258     }
 259 
 260     @Override
 261     public ContentType encode(Packet packet, OutputStream out) throws IOException {
 262         return getCodec().encode(packet, out);
 263     }
 264 
 265     @Override
 266     public void decode(InputStream in, String ct, Packet p) throws IOException {
 267         getCodec().decode(in, ct, p);
 268     }
 269 
 270     @Override
 271     public com.oracle.webservices.internal.api.databinding.JavaCallInfo createJavaCallInfo(Method method, Object[] args) {
 272         return new com.sun.xml.internal.ws.api.databinding.JavaCallInfo(method, args);
 273     }
 274 
 275     @Override
 276     public com.oracle.webservices.internal.api.databinding.JavaCallInfo deserializeResponse(
 277             MessageContext message, com.oracle.webservices.internal.api.databinding.JavaCallInfo call) {
 278         return deserializeResponse((Packet) message, (JavaCallInfo) call);
 279     }
 280 
 281     @Override
 282     public com.oracle.webservices.internal.api.databinding.JavaCallInfo deserializeRequest(MessageContext message) {
 283         return deserializeRequest((Packet) message);
 284     }
 285 
 286     @Override
 287     public MessageContextFactory getMessageContextFactory() {
 288         return packetFactory;
 289     }
 290 }