package com.sun.xml.internal.ws.transport.http.server;
import com.sun.istack.internal.Nullable;
import com.sun.xml.internal.stream.buffer.XMLStreamBufferResult;
import com.sun.xml.internal.ws.api.Component;
import com.sun.xml.internal.ws.api.WSBinding;
import com.sun.xml.internal.ws.api.BindingID;
import com.sun.xml.internal.ws.api.databinding.MetadataReader;
import com.sun.xml.internal.ws.api.message.Packet;
import com.sun.xml.internal.ws.binding.BindingImpl;
import com.sun.xml.internal.ws.api.server.*;
import com.sun.xml.internal.ws.server.EndpointFactory;
import com.sun.xml.internal.ws.server.ServerRtException;
import com.sun.xml.internal.ws.util.xml.XmlUtil;
import com.sun.xml.internal.ws.transport.http.HttpAdapterList;
import com.sun.xml.internal.ws.transport.http.HttpAdapter;
import com.sun.istack.internal.NotNull;
import java.net.MalformedURLException;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.ws.*;
import javax.xml.ws.spi.http.HttpContext;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;
import org.w3c.dom.Element;
public class EndpointImpl extends Endpoint {
private static final WebServicePermission ENDPOINT_PUBLISH_PERMISSION =
new WebServicePermission("publishEndpoint");
private Object actualEndpoint;
private final WSBinding binding;
private @Nullable final Object implementor;
private List<Source> metadata;
private Executor executor;
private Map<String, Object> properties = Collections.emptyMap();
private boolean stopped;
private @Nullable EndpointContext endpointContext;
private @NotNull final Class<?> implClass;
private final Invoker invoker;
private Container container;
public EndpointImpl(@NotNull BindingID bindingId, @NotNull Object impl,
WebServiceFeature ... features) {
this(bindingId, impl, impl.getClass(),
InstanceResolver.createSingleton(impl).createInvoker(), features);
}
public EndpointImpl(@NotNull BindingID bindingId, @NotNull Class implClass,
javax.xml.ws.spi.Invoker invoker,
WebServiceFeature ... features) {
this(bindingId, null, implClass, new InvokerImpl(invoker), features);
}
private EndpointImpl(@NotNull BindingID bindingId, Object impl, @NotNull Class implClass,
Invoker invoker, WebServiceFeature ... features) {
binding = BindingImpl.create(bindingId, features);
this.implClass = implClass;
this.invoker = invoker;
this.implementor = impl;
}
public EndpointImpl(WSEndpoint wse, Object serverContext) {
this(wse, serverContext, null);
}
public EndpointImpl(WSEndpoint wse, Object serverContext, EndpointContext ctxt) {
endpointContext = ctxt;
actualEndpoint = new HttpEndpoint(null, getAdapter(wse, ""));
((HttpEndpoint) actualEndpoint).publish(serverContext);
binding = wse.getBinding();
implementor = null;
implClass = null;
invoker = null;
}
public EndpointImpl(WSEndpoint wse, String address) {
this(wse, address, null);
}
public EndpointImpl(WSEndpoint wse, String address, EndpointContext ctxt) {
URL url;
try {
url = new URL(address);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException("Cannot create URL for this address " + address);
}
if (!url.getProtocol().equals("http")) {
throw new IllegalArgumentException(url.getProtocol() + " protocol based address is not supported");
}
if (!url.getPath().startsWith("/")) {
throw new IllegalArgumentException("Incorrect WebService address=" + address +
". The address's path should start with /");
}
endpointContext = ctxt;
actualEndpoint = new HttpEndpoint(null, getAdapter(wse, url.getPath()));
((HttpEndpoint) actualEndpoint).publish(address);
binding = wse.getBinding();
implementor = null;
implClass = null;
invoker = null;
}
@Override
public Binding getBinding() {
return binding;
}
@Override
public Object getImplementor() {
return implementor;
}
@Override
public void publish(String address) {
canPublish();
URL url;
try {
url = new URL(address);
} catch (MalformedURLException ex) {
throw new IllegalArgumentException("Cannot create URL for this address " + address);
}
if (!url.getProtocol().equals("http")) {
throw new IllegalArgumentException(url.getProtocol() + " protocol based address is not supported");
}
if (!url.getPath().startsWith("/")) {
throw new IllegalArgumentException("Incorrect WebService address=" + address +
". The address's path should start with /");
}
createEndpoint(url.getPath());
((HttpEndpoint) actualEndpoint).publish(address);
}
@Override
public void publish(Object serverContext) {
canPublish();
if (!com.sun.net.httpserver.HttpContext.class.isAssignableFrom(serverContext.getClass())) {
throw new IllegalArgumentException(serverContext.getClass() + " is not a supported context.");
}
createEndpoint(((com.sun.net.httpserver.HttpContext)serverContext).getPath());
((HttpEndpoint) actualEndpoint).publish(serverContext);
}
@Override
public void publish(HttpContext serverContext) {
canPublish();
createEndpoint(serverContext.getPath());
((HttpEndpoint) actualEndpoint).publish(serverContext);
}
@Override
public void stop() {
if (isPublished()) {
((HttpEndpoint) actualEndpoint).stop();
actualEndpoint = null;
stopped = true;
}
}
@Override
public boolean isPublished() {
return actualEndpoint != null;
}
@Override
public List<Source> getMetadata() {
return metadata;
}
@Override
public void setMetadata(java.util.List<Source> metadata) {
if (isPublished()) {
throw new IllegalStateException("Cannot set Metadata. Endpoint is already published");
}
this.metadata = metadata;
}
@Override
public Executor getExecutor() {
return executor;
}
@Override
public void setExecutor(Executor executor) {
this.executor = executor;
}
@Override
public Map<String, Object> getProperties() {
return new HashMap<>(properties);
}
@Override
public void setProperties(Map<String, Object> map) {
this.properties = new HashMap<>(map);
}
private void createEndpoint(String urlPattern) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(ENDPOINT_PUBLISH_PERMISSION);
}
try {
Class.forName("com.sun.net.httpserver.HttpServer");
} catch (Exception e) {
throw new UnsupportedOperationException("Couldn't load light weight http server", e);
}
container = getContainer();
MetadataReader metadataReader = EndpointFactory.getExternalMetadatReader(implClass, binding);
WSEndpoint wse = WSEndpoint.create(
implClass, true,
invoker,
getProperty(QName.class, Endpoint.WSDL_SERVICE),
getProperty(QName.class, Endpoint.WSDL_PORT),
container,
binding,
getPrimaryWsdl(metadataReader),
buildDocList(),
(EntityResolver) null,
false
);
actualEndpoint = new HttpEndpoint(executor, getAdapter(wse, urlPattern));
}
private <T> T getProperty(Class<T> type, String key) {
Object o = properties.get(key);
if (o == null) return null;
if (type.isInstance(o))
return type.cast(o);
else
throw new IllegalArgumentException("Property " + key + " has to be of type " + type);
}
private List<SDDocumentSource> buildDocList() {
List<SDDocumentSource> r = new ArrayList<>();
if (metadata != null) {
for (Source source : metadata) {
try {
XMLStreamBufferResult xsbr = XmlUtil.identityTransform(source, new XMLStreamBufferResult());
String systemId = source.getSystemId();
r.add(SDDocumentSource.create(new URL(systemId), xsbr.getXMLStreamBuffer()));
} catch (TransformerException | IOException | SAXException | ParserConfigurationException te) {
throw new ServerRtException("server.rt.err", te);
}
}
}
return r;
}
private @Nullable SDDocumentSource getPrimaryWsdl(MetadataReader metadataReader) {
EndpointFactory.verifyImplementorClass(implClass, metadataReader);
String wsdlLocation = EndpointFactory.getWsdlLocation(implClass, metadataReader);
if (wsdlLocation != null) {
return SDDocumentSource.create(implClass, wsdlLocation);
}
return null;
}
private void canPublish() {
if (isPublished()) {
throw new IllegalStateException(
"Cannot publish this endpoint. Endpoint has been already published.");
}
if (stopped) {
throw new IllegalStateException(
"Cannot publish this endpoint. Endpoint has been already stopped.");
}
}
@Override
public EndpointReference getEndpointReference(Element...referenceParameters) {
return getEndpointReference(W3CEndpointReference.class, referenceParameters);
}
@Override
public <T extends EndpointReference> T getEndpointReference(Class<T> clazz, Element...referenceParameters) {
if (!isPublished()) {
throw new WebServiceException("Endpoint is not published yet");
}
return ((HttpEndpoint)actualEndpoint).getEndpointReference(clazz,referenceParameters);
}
@Override
public void setEndpointContext(EndpointContext ctxt) {
this.endpointContext = ctxt;
}
private HttpAdapter getAdapter(WSEndpoint endpoint, String urlPattern) {
HttpAdapterList adapterList = null;
if (endpointContext != null) {
if (endpointContext instanceof Component) {
adapterList = ((Component) endpointContext).getSPI(HttpAdapterList.class);
}
if (adapterList == null) {
for(Endpoint e : endpointContext.getEndpoints()) {
if (e.isPublished() && e != this) {
adapterList = ((HttpEndpoint)(((EndpointImpl)e).actualEndpoint)).getAdapterOwner();
assert adapterList != null;
break;
}
}
}
}
if (adapterList == null) {
adapterList = new ServerAdapterList();
}
return adapterList.createAdapter("", urlPattern, endpoint);
}
private Container getContainer() {
if (endpointContext != null) {
if (endpointContext instanceof Component) {
Container c = ((Component) endpointContext).getSPI(Container.class);
if (c != null)
return c;
}
for(Endpoint e : endpointContext.getEndpoints()) {
if (e.isPublished() && e != this) {
return ((EndpointImpl)e).container;
}
}
}
return new ServerContainer();
}
private static class InvokerImpl extends Invoker {
private javax.xml.ws.spi.Invoker spiInvoker;
InvokerImpl(javax.xml.ws.spi.Invoker spiInvoker) {
this.spiInvoker = spiInvoker;
}
@Override
public void start(@NotNull WSWebServiceContext wsc, @NotNull WSEndpoint endpoint) {
try {
spiInvoker.inject(wsc);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new WebServiceException(e);
}
}
@Override
public Object invoke(@NotNull Packet p, @NotNull Method m, @NotNull Object... args) throws InvocationTargetException, IllegalAccessException {
return spiInvoker.invoke(m, args);
}
}
}