/* * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package com.sun.xml.internal.ws.server; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; import com.sun.xml.internal.ws.api.SOAPVersion; import com.sun.xml.internal.ws.api.WSBinding; import com.sun.xml.internal.ws.api.addressing.AddressingVersion; import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; import com.sun.xml.internal.ws.api.message.Message; import com.sun.xml.internal.ws.api.message.Packet; import com.sun.xml.internal.ws.api.model.SEIModel; import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort; import com.sun.xml.internal.ws.api.pipe.Codec; import com.sun.xml.internal.ws.api.pipe.Engine; import com.sun.xml.internal.ws.api.pipe.Fiber; import com.sun.xml.internal.ws.api.pipe.FiberContextSwitchInterceptor; import com.sun.xml.internal.ws.api.pipe.ServerPipeAssemblerContext; import com.sun.xml.internal.ws.api.pipe.ServerTubeAssemblerContext; import com.sun.xml.internal.ws.api.pipe.Tube; import com.sun.xml.internal.ws.api.pipe.TubeCloner; import com.sun.xml.internal.ws.api.pipe.TubelineAssembler; import com.sun.xml.internal.ws.api.pipe.TubelineAssemblerFactory; import com.sun.xml.internal.ws.api.server.Container; import com.sun.xml.internal.ws.api.server.EndpointAwareCodec; import com.sun.xml.internal.ws.api.server.TransportBackChannel; import com.sun.xml.internal.ws.api.server.WSEndpoint; import com.sun.xml.internal.ws.api.server.WebServiceContextDelegate; import com.sun.xml.internal.ws.fault.SOAPFaultBuilder; import com.sun.xml.internal.ws.model.wsdl.WSDLProperties; import com.sun.xml.internal.ws.resources.HandlerMessages; import com.sun.xml.internal.ws.util.Pool; import com.sun.xml.internal.ws.util.Pool.TubePool; import org.w3c.dom.Element; import javax.annotation.PreDestroy; import javax.xml.namespace.QName; import javax.xml.ws.EndpointReference; import javax.xml.ws.handler.Handler; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; /** * {@link WSEndpoint} implementation. * * @author Kohsuke Kawaguchi * @author Jitendra Kotamraju */ public final class WSEndpointImpl<T> extends WSEndpoint<T> { private final @NotNull QName serviceName; private final @NotNull QName portName; private final WSBinding binding; private final SEIModel seiModel; private final @NotNull Container container; private final WSDLPort port; private final Tube masterTubeline; private final ServiceDefinitionImpl serviceDef; private final SOAPVersion soapVersion; private final Engine engine; private final @NotNull Codec masterCodec; private final Pool<Tube> tubePool; /** * Set to true once we start shutting down this endpoint. * Used to avoid running the clean up processing twice. * * @see #dispose() */ private boolean disposed; private final Class<T> implementationClass; private final @Nullable WSDLProperties wsdlProperties; WSEndpointImpl(@NotNull QName serviceName, @NotNull QName portName, WSBinding binding, Container container, SEIModel seiModel, WSDLPort port, Class<T> implementationClass, @Nullable ServiceDefinitionImpl serviceDef, InvokerTube terminalTube, boolean isSynchronous) { this.serviceName = serviceName; this.portName = portName; this.binding = binding; this.soapVersion = binding.getSOAPVersion(); this.container = container; this.port = port; this.implementationClass = implementationClass; this.serviceDef = serviceDef; this.seiModel = seiModel; if (serviceDef != null) { serviceDef.setOwner(this); } TubelineAssembler assembler = TubelineAssemblerFactory.create( Thread.currentThread().getContextClassLoader(), binding.getBindingId(), container); assert assembler!=null; ServerTubeAssemblerContext context = new ServerPipeAssemblerContext(seiModel, port, this, terminalTube, isSynchronous); this.masterTubeline = assembler.createServer(context); Codec c = context.getCodec(); if(c instanceof EndpointAwareCodec) { // create a copy to avoid sharing the codec between multiple endpoints c = c.copy(); ((EndpointAwareCodec)c).setEndpoint(this); } this.masterCodec = c; tubePool = new TubePool(masterTubeline); terminalTube.setEndpoint(this); engine = new Engine(toString()); wsdlProperties = (port==null) ? null : new WSDLProperties(port); } public @NotNull Class<T> getImplementationClass() { return implementationClass; } public @NotNull WSBinding getBinding() { return binding; } public @NotNull Container getContainer() { return container; } public WSDLPort getPort() { return port; } /** * Gets the {@link SEIModel} that represents the relationship * between WSDL and Java SEI. * * <p> * This method returns a non-null value if and only if this * endpoint is ultimately serving an application through an SEI. * * @return * maybe null. See above for more discussion. * Always the same value. */ public @Nullable SEIModel getSEIModel() { return seiModel; } public void setExecutor(Executor exec) { engine.setExecutor(exec); } public void schedule(final Packet request, final CompletionCallback callback, FiberContextSwitchInterceptor interceptor) { request.endpoint = WSEndpointImpl.this; if (wsdlProperties != null) { request.addSatellite(wsdlProperties); } Fiber fiber = engine.createFiber(); if (interceptor != null) { fiber.addInterceptor(interceptor); } final Tube tube = tubePool.take(); fiber.start(tube, request, new Fiber.CompletionCallback() { public void onCompletion(@NotNull Packet response) { tubePool.recycle(tube); if (callback!=null) { callback.onCompletion(response); } } public void onCompletion(@NotNull Throwable error) { // let's not reuse tubes as they might be in a wrong state, so not // calling tubePool.recycle() error.printStackTrace(); // Convert all runtime exceptions to Packet so that transport doesn't // have to worry about converting to wire message // TODO XML/HTTP binding Message faultMsg = SOAPFaultBuilder.createSOAPFaultMessage( soapVersion, null, error); Packet response = request.createServerResponse(faultMsg, request.endpoint.getPort(), null, request.endpoint.getBinding()); if (callback!=null) { callback.onCompletion(response); } } }); } public @NotNull PipeHead createPipeHead() { return new PipeHead() { private final Tube tube = TubeCloner.clone(masterTubeline); public @NotNull Packet process(Packet request, WebServiceContextDelegate wscd, TransportBackChannel tbc) { request.webServiceContextDelegate = wscd; request.transportBackChannel = tbc; request.endpoint = WSEndpointImpl.this; if (wsdlProperties != null) { request.addSatellite(wsdlProperties); } Fiber fiber = engine.createFiber(); Packet response; try { response = fiber.runSync(tube,request); } catch (RuntimeException re) { // Catch all runtime exceptions so that transport doesn't // have to worry about converting to wire message // TODO XML/HTTP binding re.printStackTrace(); Message faultMsg = SOAPFaultBuilder.createSOAPFaultMessage( soapVersion, null, re); response = request.createServerResponse(faultMsg, request.endpoint.getPort(), null, request.endpoint.getBinding()); } return response; } }; } public synchronized void dispose() { if(disposed) return; disposed = true; masterTubeline.preDestroy(); for (Handler handler : binding.getHandlerChain()) { for (Method method : handler.getClass().getMethods()) { if (method.getAnnotation(PreDestroy.class) == null) { continue; } try { method.invoke(handler); } catch (Exception e) { logger.log(Level.WARNING, HandlerMessages.HANDLER_PREDESTROY_IGNORE(e.getMessage()), e); } break; } } } public ServiceDefinitionImpl getServiceDefinition() { return serviceDef; } private static final Logger logger = Logger.getLogger( com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); public <T extends EndpointReference> T getEndpointReference(Class<T> clazz, String address, String wsdlAddress, Element...referenceParameters) { QName portType = null; if(port != null) { portType = port.getBinding().getPortTypeName(); } List<Element> refParams = null; if(referenceParameters != null) { refParams = Arrays.asList(referenceParameters); } AddressingVersion av = AddressingVersion.fromSpecClass(clazz); if (av == AddressingVersion.W3C) { // Supress writing ServiceName and EndpointName in W3C EPR, // Until the ns for those metadata elements is resolved. return new WSEndpointReference( AddressingVersion.W3C, address,null /*serviceName*/,null /*portName*/, null /*portType*/, null, null /*wsdlAddress*/, refParams).toSpec(clazz); } else { return new WSEndpointReference( AddressingVersion.MEMBER, address, serviceName, portName, portType, null, wsdlAddress, refParams).toSpec(clazz); } } public @NotNull QName getPortName() { return portName; } public @NotNull Codec createCodec() { return masterCodec.copy(); } public @NotNull QName getServiceName() { return serviceName; } }