diff -r 000000000000 -r 373ffda63c9a src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSEndpointImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/server/WSEndpointImpl.java Wed Apr 27 01:27:09 2016 +0800 @@ -0,0 +1,698 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.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.stream.buffer.XMLStreamBuffer; +import com.sun.xml.internal.ws.addressing.EPRSDDocumentFilter; +import com.sun.xml.internal.ws.addressing.WSEPRExtension; +import com.sun.xml.internal.ws.api.Component; +import com.sun.xml.internal.ws.api.ComponentFeature; +import com.sun.xml.internal.ws.api.ComponentsFeature; +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.*; +import com.sun.xml.internal.ws.api.server.*; +import com.sun.xml.internal.ws.binding.BindingImpl; +import com.sun.xml.internal.ws.fault.SOAPFaultBuilder; +import com.sun.xml.internal.ws.model.wsdl.WSDLDirectProperties; +import com.sun.xml.internal.ws.model.wsdl.WSDLPortProperties; +import com.sun.xml.internal.ws.model.wsdl.WSDLProperties; +import com.sun.xml.internal.ws.policy.PolicyMap; +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 com.sun.xml.internal.ws.util.ServiceFinder; +import com.sun.xml.internal.ws.wsdl.OperationDispatcher; +import com.sun.org.glassfish.gmbal.ManagedObjectManager; +import org.w3c.dom.Element; + +import javax.annotation.PreDestroy; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import javax.xml.ws.EndpointReference; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.handler.Handler; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.ObjectName; + +/** + * {@link WSEndpoint} implementation. + * + * @author Kohsuke Kawaguchi + * @author Jitendra Kotamraju + */ +public /*final*/ class WSEndpointImpl extends WSEndpoint implements LazyMOMProvider.WSEndpointScopeChangeListener { + + private static final Logger logger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.endpoint"); + + private final @NotNull QName serviceName; + private final @NotNull QName portName; + protected final WSBinding binding; + private final SEIModel seiModel; + private final @NotNull Container container; + private final WSDLPort port; + + protected final Tube masterTubeline; + private final ServiceDefinitionImpl serviceDef; + private final SOAPVersion soapVersion; + private final Engine engine; + private final @NotNull Codec masterCodec; + private final @NotNull PolicyMap endpointPolicy; + private final Pool tubePool; + private final OperationDispatcher operationDispatcher; + private @NotNull ManagedObjectManager managedObjectManager; + private boolean managedObjectManagerClosed = false; + private final Object managedObjectManagerLock = new Object(); + private LazyMOMProvider.Scope lazyMOMProviderScope = LazyMOMProvider.Scope.STANDALONE; + private final @NotNull ServerTubeAssemblerContext context; + + private Map endpointReferenceExtensions = new HashMap(); + /** + * 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 implementationClass; + private final @NotNull + WSDLProperties wsdlProperties; + private final Set componentRegistry = new CopyOnWriteArraySet(); + + protected WSEndpointImpl(@NotNull QName serviceName, @NotNull QName portName, WSBinding binding, + Container container, SEIModel seiModel, WSDLPort port, + Class implementationClass, + @Nullable ServiceDefinitionImpl serviceDef, + EndpointAwareTube terminalTube, boolean isSynchronous, + PolicyMap endpointPolicy) { + 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; + this.endpointPolicy = endpointPolicy; + + LazyMOMProvider.INSTANCE.registerEndpoint(this); + initManagedObjectManager(); + + if (serviceDef != null) { + serviceDef.setOwner(this); + } + + ComponentFeature cf = binding.getFeature(ComponentFeature.class); + if (cf != null) { + switch (cf.getTarget()) { + case ENDPOINT: + componentRegistry.add(cf.getComponent()); + break; + case CONTAINER: + container.getComponents().add(cf.getComponent()); + break; + default: + throw new IllegalArgumentException(); + } + } + ComponentsFeature csf = binding.getFeature(ComponentsFeature.class); + if (csf != null) { + for (ComponentFeature cfi : csf.getComponentFeatures()) { + switch (cfi.getTarget()) { + case ENDPOINT: + componentRegistry.add(cfi.getComponent()); + break; + case CONTAINER: + container.getComponents().add(cfi.getComponent()); + break; + default: + throw new IllegalArgumentException(); + } + } + } + + TubelineAssembler assembler = TubelineAssemblerFactory.create( + Thread.currentThread().getContextClassLoader(), binding.getBindingId(), container); + assert assembler != null; + + this.operationDispatcher = (port == null) ? null : new OperationDispatcher(port, binding, seiModel); + + context = createServerTubeAssemblerContext(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(), container); + wsdlProperties = (port == null) ? new WSDLDirectProperties(serviceName, portName, seiModel) : new WSDLPortProperties(port, seiModel); + + Map eprExtensions = new HashMap(); + try { + if (port != null) { + //gather EPR extrensions from WSDL Model + WSEndpointReference wsdlEpr = port.getEPR(); + if (wsdlEpr != null) { + for (WSEndpointReference.EPRExtension extnEl : wsdlEpr.getEPRExtensions()) { + eprExtensions.put(extnEl.getQName(), extnEl); + } + } + } + + EndpointReferenceExtensionContributor[] eprExtnContributors = ServiceFinder.find(EndpointReferenceExtensionContributor.class).toArray(); + for(EndpointReferenceExtensionContributor eprExtnContributor :eprExtnContributors) { + WSEndpointReference.EPRExtension wsdlEPRExtn = eprExtensions.remove(eprExtnContributor.getQName()); + WSEndpointReference.EPRExtension endpointEprExtn = eprExtnContributor.getEPRExtension(this,wsdlEPRExtn); + if (endpointEprExtn != null) { + eprExtensions.put(endpointEprExtn.getQName(), endpointEprExtn); + } + } + for (WSEndpointReference.EPRExtension extn : eprExtensions.values()) { + endpointReferenceExtensions.put(extn.getQName(), new WSEPRExtension( + XMLStreamBuffer.createNewBufferFromXMLStreamReader(extn.readAsXMLStreamReader()),extn.getQName())); + } + } catch (XMLStreamException ex) { + throw new WebServiceException(ex); + } + if(!eprExtensions.isEmpty()) { + serviceDef.addFilter(new EPRSDDocumentFilter(this)); + } + } + + protected ServerTubeAssemblerContext createServerTubeAssemblerContext( + EndpointAwareTube terminalTube, boolean isSynchronous) { + ServerTubeAssemblerContext ctx = new ServerPipeAssemblerContext( + seiModel, port, this, terminalTube, isSynchronous); + return ctx; + } + + protected WSEndpointImpl(@NotNull QName serviceName, @NotNull QName portName, WSBinding binding, Container container, + SEIModel seiModel, WSDLPort port, + Tube masterTubeline) { + this.serviceName = serviceName; + this.portName = portName; + this.binding = binding; + this.soapVersion = binding.getSOAPVersion(); + this.container = container; + this.endpointPolicy = null; + this.port = port; + this.seiModel = seiModel; + this.serviceDef = null; + this.implementationClass = null; + this.masterTubeline = masterTubeline; + this.masterCodec = ((BindingImpl) this.binding).createCodec(); + + LazyMOMProvider.INSTANCE.registerEndpoint(this); + initManagedObjectManager(); + + this.operationDispatcher = (port == null) ? null : new OperationDispatcher(port, binding, seiModel); + this.context = new ServerPipeAssemblerContext( + seiModel, port, this, null /* not known */, false); + + tubePool = new TubePool(masterTubeline); + engine = new Engine(toString(), container); + wsdlProperties = (port == null) ? new WSDLDirectProperties(serviceName, portName, seiModel) : new WSDLPortProperties(port, seiModel); + } + + public Collection getEndpointReferenceExtensions() { + return endpointReferenceExtensions.values(); + } + + /** + * Nullable when there is no associated WSDL Model + * @return + */ + public @Nullable OperationDispatcher getOperationDispatcher() { + return operationDispatcher; + } + + public PolicyMap getPolicyMap() { + return endpointPolicy; + } + + public @NotNull Class getImplementationClass() { + return implementationClass; + } + + public @NotNull WSBinding getBinding() { + return binding; + } + + public @NotNull Container getContainer() { + return container; + } + + public WSDLPort getPort() { + return port; + } + + @Override + public @Nullable SEIModel getSEIModel() { + return seiModel; + } + + public void setExecutor(Executor exec) { + engine.setExecutor(exec); + } + + @Override + public Engine getEngine() { + return engine; + } + + public void schedule(final Packet request, final CompletionCallback callback, FiberContextSwitchInterceptor interceptor) { + processAsync(request, callback, interceptor, true); + } + + private void processAsync(final Packet request, + final CompletionCallback callback, + FiberContextSwitchInterceptor interceptor, boolean schedule) { + Container old = ContainerResolver.getDefault().enterContainer(container); + try { + request.endpoint = WSEndpointImpl.this; + request.addSatellite(wsdlProperties); + + Fiber fiber = engine.createFiber(); + fiber.setDeliverThrowableInPacket(true); + if (interceptor != null) { + fiber.addInterceptor(interceptor); + } + final Tube tube = tubePool.take(); + Fiber.CompletionCallback cbak = new Fiber.CompletionCallback() { + public void onCompletion(@NotNull Packet response) { + ThrowableContainerPropertySet tc = response.getSatellite(ThrowableContainerPropertySet.class); + if (tc == null) { + // Only recycle tubes in non-exception path as some Tubes may be + // in invalid state following exception + tubePool.recycle(tube); + } + + if (callback != null) { + if (tc != null) { + response = createServiceResponseForException(tc, + response, + soapVersion, + request.endpoint.getPort(), + null, + request.endpoint.getBinding()); + } + callback.onCompletion(response); + } + } + + public void onCompletion(@NotNull Throwable error) { + // will never be called now that we are using + // fiber.setDeliverThrowableInPacket(true); + throw new IllegalStateException(); + } + }; + + fiber.start(tube, request, cbak, + binding.isFeatureEnabled(SyncStartForAsyncFeature.class) + || !schedule); + } finally { + ContainerResolver.getDefault().exitContainer(old); + } + } + + @Override + public Packet createServiceResponseForException(final ThrowableContainerPropertySet tc, + final Packet responsePacket, + final SOAPVersion soapVersion, + final WSDLPort wsdlPort, + final SEIModel seiModel, + final WSBinding binding) + { + // This will happen in addressing if it is enabled. + if (tc.isFaultCreated()) return responsePacket; + + final Message faultMessage = SOAPFaultBuilder.createSOAPFaultMessage(soapVersion, null, tc.getThrowable()); + final Packet result = responsePacket.createServerResponse(faultMessage, wsdlPort, seiModel, binding); + // Pass info to upper layers + tc.setFaultMessage(faultMessage); + tc.setResponsePacket(responsePacket); + tc.setFaultCreated(true); + return result; + } + + @Override + public void process(final Packet request, final CompletionCallback callback, FiberContextSwitchInterceptor interceptor) { + processAsync(request, callback, interceptor, false); + } + + public @NotNull + PipeHead createPipeHead() { + return new PipeHead() { + private final Tube tube = TubeCloner.clone(masterTubeline); + + public @NotNull + Packet process(Packet request, WebServiceContextDelegate wscd, + TransportBackChannel tbc) { + Container old = ContainerResolver.getDefault().enterContainer(container); + try { + request.webServiceContextDelegate = wscd; + request.transportBackChannel = tbc; + request.endpoint = WSEndpointImpl.this; + 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 + Message faultMsg = SOAPFaultBuilder + .createSOAPFaultMessage(soapVersion, null, re); + response = request.createServerResponse(faultMsg, + request.endpoint.getPort(), null, + request.endpoint.getBinding()); + } + return response; + } finally { + ContainerResolver.getDefault().exitContainer(old); + } + } + }; + } + + 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; + } + } + closeManagedObjectManager(); + LazyMOMProvider.INSTANCE.unregisterEndpoint(this); + } + + public ServiceDefinitionImpl getServiceDefinition() { + return serviceDef; + } + + public Set getComponentRegistry() { + Set sec = new EndpointComponentSet(); + for (Component c : componentRegistry) { + sec.add(c instanceof EndpointComponentWrapper ? + ((EndpointComponentWrapper) c).component : + new ComponentWrapper(c)); + } + return sec; + } + + private class EndpointComponentSet extends HashSet { + + @Override + public Iterator iterator() { + final Iterator it = super.iterator(); + return new Iterator() { + private EndpointComponent last = null; + + public boolean hasNext() { + return it.hasNext(); + } + + public EndpointComponent next() { + last = it.next(); + return last; + } + + public void remove() { + it.remove(); + if (last != null) { + componentRegistry.remove(last instanceof ComponentWrapper ? + ((ComponentWrapper) last).component : + new EndpointComponentWrapper(last)); + } + last = null; + } + }; + } + + @Override + public boolean add(EndpointComponent e) { + boolean result = super.add(e); + if (result) { + componentRegistry.add(new EndpointComponentWrapper(e)); + } + return result; + } + + @Override + public boolean remove(Object o) { + boolean result = super.remove(o); + if (result) { + componentRegistry.remove(o instanceof ComponentWrapper ? + ((ComponentWrapper) o).component : + new EndpointComponentWrapper((EndpointComponent)o)); + } + return result; + } + + } + + private static class ComponentWrapper implements EndpointComponent { + private final Component component; + + public ComponentWrapper(Component component) { + this.component = component; + } + + public S getSPI(Class spiType) { + return component.getSPI(spiType); + } + + @Override + public int hashCode() { + return component.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return component.equals(obj); + } + } + + private static class EndpointComponentWrapper implements Component { + private final EndpointComponent component; + + public EndpointComponentWrapper(EndpointComponent component) { + this.component = component; + } + + public S getSPI(Class spiType) { + return component.getSPI(spiType); + } + + @Override + public int hashCode() { + return component.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return component.equals(obj); + } + } + + @Override + public @NotNull Set getComponents() { + return componentRegistry; + } + + public T getEndpointReference(Class clazz, String address, String wsdlAddress, Element... referenceParameters) { + List refParams = null; + if (referenceParameters != null) { + refParams = Arrays.asList(referenceParameters); + } + return getEndpointReference(clazz, address, wsdlAddress, null, refParams); + } + + public T getEndpointReference(Class clazz, + String address, String wsdlAddress, List metadata, + List referenceParameters) { + QName portType = null; + if (port != null) { + portType = port.getBinding().getPortTypeName(); + } + + AddressingVersion av = AddressingVersion.fromSpecClass(clazz); + return new WSEndpointReference( + av, address, serviceName, portName, portType, metadata, wsdlAddress, referenceParameters, endpointReferenceExtensions.values(), null).toSpec(clazz); + + } + + public @NotNull QName getPortName() { + return portName; + } + + + public @NotNull Codec createCodec() { + return masterCodec.copy(); + } + + public @NotNull QName getServiceName() { + return serviceName; + } + + private void initManagedObjectManager() { + synchronized (managedObjectManagerLock) { + if (managedObjectManager == null) { + switch (this.lazyMOMProviderScope) { + case GLASSFISH_NO_JMX: + managedObjectManager = new WSEndpointMOMProxy(this); + break; + default: + managedObjectManager = obtainManagedObjectManager(); + } + } + } + } + + public @NotNull ManagedObjectManager getManagedObjectManager() { + return managedObjectManager; + } + + /** + * Obtains a real instance of {@code ManagedObjectManager} class no matter what lazyMOMProviderScope is this endpoint in (or if the + * Gmbal API calls should be deferred). + * + * @see com.sun.xml.internal.ws.api.server.LazyMOMProvider.Scope + * @return an instance of {@code ManagedObjectManager} + */ + @NotNull ManagedObjectManager obtainManagedObjectManager() { + final MonitorRootService monitorRootService = new MonitorRootService(this); + final ManagedObjectManager mOM = monitorRootService.createManagedObjectManager(this); + + // ManagedObjectManager was suspended due to root creation (see MonitorBase#initMOM) + mOM.resumeJMXRegistration(); + + return mOM; + } + + public void scopeChanged(LazyMOMProvider.Scope scope) { + synchronized (managedObjectManagerLock) { + if (managedObjectManagerClosed) { + return; + } + + this.lazyMOMProviderScope = scope; + + // possible lazyMOMProviderScope change can be LazyMOMProvider.Scope.GLASSFISH_NO_JMX or LazyMOMProvider.Scope.GLASSFISH_JMX + if (managedObjectManager == null) { + if (scope != LazyMOMProvider.Scope.GLASSFISH_NO_JMX) { + managedObjectManager = obtainManagedObjectManager(); + } else { + managedObjectManager = new WSEndpointMOMProxy(this); + } + } else { + // if ManagedObjectManager for this endpoint has already been created and is uninitialized proxy then + // fill it with a real instance + if (managedObjectManager instanceof WSEndpointMOMProxy + && !((WSEndpointMOMProxy)managedObjectManager).isInitialized()) { + ((WSEndpointMOMProxy)managedObjectManager).setManagedObjectManager(obtainManagedObjectManager()); + } + } + } + } + + private static final Logger monitoringLogger = Logger.getLogger(com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".monitoring"); + + // This can be called independently of WSEndpoint.dispose. + // Example: the WSCM framework calls this before dispose. + @Override + public void closeManagedObjectManager() { + synchronized (managedObjectManagerLock) { + if (managedObjectManagerClosed == true) { + return; + } + if (managedObjectManager != null) { + boolean close = true; + + // ManagedObjectManager doesn't need to be closed because it exists only as a proxy + if (managedObjectManager instanceof WSEndpointMOMProxy + && !((WSEndpointMOMProxy)managedObjectManager).isInitialized()) { + close = false; + } + + if (close) { + try { + final ObjectName name = managedObjectManager.getObjectName(managedObjectManager.getRoot()); + // The name is null when the MOM is a NOOP. + if (name != null) { + monitoringLogger.log(Level.INFO, "Closing Metro monitoring root: {0}", name); + } + managedObjectManager.close(); + } catch (java.io.IOException e) { + monitoringLogger.log(Level.WARNING, "Ignoring error when closing Managed Object Manager", e); + } + } + } + managedObjectManagerClosed = true; + } + } + + public @NotNull @Override ServerTubeAssemblerContext getAssemblerContext() { + return context; + } +}