Drop RPC-style remoting

Closes gh-27422
This commit is contained in:
Juergen Hoeller
2021-09-17 08:59:58 +02:00
parent 3c8724ba3d
commit 5822f1bf85
79 changed files with 0 additions and 11653 deletions

View File

@@ -1,302 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.caucho;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import com.caucho.hessian.HessianException;
import com.caucho.hessian.client.HessianConnectionException;
import com.caucho.hessian.client.HessianConnectionFactory;
import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.hessian.client.HessianRuntimeException;
import com.caucho.hessian.io.SerializerFactory;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.lang.Nullable;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteConnectFailureException;
import org.springframework.remoting.RemoteLookupFailureException;
import org.springframework.remoting.RemoteProxyFailureException;
import org.springframework.remoting.support.UrlBasedRemoteAccessor;
import org.springframework.util.Assert;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Hessian service.
* Supports authentication via username and password.
* The service URL must be an HTTP URL exposing a Hessian service.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
* <b>Note: As of Spring 4.0, this client requires Hessian 4.0 or above.</b>
*
* <p>Note: There is no requirement for services accessed with this proxy factory
* to have been exported using Spring's {@link HessianServiceExporter}, as there is
* no special handling involved. As a consequence, you can also access services that
* have been exported using Caucho's {@link com.caucho.hessian.server.HessianServlet}.
*
* @author Juergen Hoeller
* @since 29.09.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see #setUsername
* @see #setPassword
* @see HessianServiceExporter
* @see HessianProxyFactoryBean
* @see com.caucho.hessian.client.HessianProxyFactory
* @see com.caucho.hessian.server.HessianServlet
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
private HessianProxyFactory proxyFactory = new HessianProxyFactory();
@Nullable
private Object hessianProxy;
/**
* Set the HessianProxyFactory instance to use.
* If not specified, a default HessianProxyFactory will be created.
* <p>Allows to use an externally configured factory instance,
* in particular a custom HessianProxyFactory subclass.
*/
public void setProxyFactory(@Nullable HessianProxyFactory proxyFactory) {
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
}
/**
* Specify the Hessian SerializerFactory to use.
* <p>This will typically be passed in as an inner bean definition
* of type {@code com.caucho.hessian.io.SerializerFactory},
* with custom bean property values applied.
*/
public void setSerializerFactory(SerializerFactory serializerFactory) {
this.proxyFactory.setSerializerFactory(serializerFactory);
}
/**
* Set whether to send the Java collection type for each serialized
* collection. Default is "true".
*/
public void setSendCollectionType(boolean sendCollectionType) {
this.proxyFactory.getSerializerFactory().setSendCollectionType(sendCollectionType);
}
/**
* Set whether to allow non-serializable types as Hessian arguments
* and return values. Default is "true".
*/
public void setAllowNonSerializable(boolean allowNonSerializable) {
this.proxyFactory.getSerializerFactory().setAllowNonSerializable(allowNonSerializable);
}
/**
* Set whether overloaded methods should be enabled for remote invocations.
* Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setOverloadEnabled
*/
public void setOverloadEnabled(boolean overloadEnabled) {
this.proxyFactory.setOverloadEnabled(overloadEnabled);
}
/**
* Set the username that this factory should use to access the remote service.
* Default is none.
* <p>The username will be sent by Hessian via HTTP Basic Authentication.
* @see com.caucho.hessian.client.HessianProxyFactory#setUser
*/
public void setUsername(String username) {
this.proxyFactory.setUser(username);
}
/**
* Set the password that this factory should use to access the remote service.
* Default is none.
* <p>The password will be sent by Hessian via HTTP Basic Authentication.
* @see com.caucho.hessian.client.HessianProxyFactory#setPassword
*/
public void setPassword(String password) {
this.proxyFactory.setPassword(password);
}
/**
* Set whether Hessian's debug mode should be enabled.
* Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setDebug
*/
public void setDebug(boolean debug) {
this.proxyFactory.setDebug(debug);
}
/**
* Set whether to use a chunked post for sending a Hessian request.
* @see com.caucho.hessian.client.HessianProxyFactory#setChunkedPost
*/
public void setChunkedPost(boolean chunkedPost) {
this.proxyFactory.setChunkedPost(chunkedPost);
}
/**
* Specify a custom HessianConnectionFactory to use for the Hessian client.
*/
public void setConnectionFactory(HessianConnectionFactory connectionFactory) {
this.proxyFactory.setConnectionFactory(connectionFactory);
}
/**
* Set the socket connect timeout to use for the Hessian client.
* @see com.caucho.hessian.client.HessianProxyFactory#setConnectTimeout
*/
public void setConnectTimeout(long timeout) {
this.proxyFactory.setConnectTimeout(timeout);
}
/**
* Set the timeout to use when waiting for a reply from the Hessian service.
* @see com.caucho.hessian.client.HessianProxyFactory#setReadTimeout
*/
public void setReadTimeout(long timeout) {
this.proxyFactory.setReadTimeout(timeout);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing requests and replies. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request
*/
public void setHessian2(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
this.proxyFactory.setHessian2Reply(hessian2);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing requests. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Request
*/
public void setHessian2Request(boolean hessian2) {
this.proxyFactory.setHessian2Request(hessian2);
}
/**
* Set whether version 2 of the Hessian protocol should be used for
* parsing replies. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setHessian2Reply
*/
public void setHessian2Reply(boolean hessian2) {
this.proxyFactory.setHessian2Reply(hessian2);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
prepare();
}
/**
* Initialize the Hessian proxy for this interceptor.
* @throws RemoteLookupFailureException if the service URL is invalid
*/
public void prepare() throws RemoteLookupFailureException {
try {
this.hessianProxy = createHessianProxy(this.proxyFactory);
}
catch (MalformedURLException ex) {
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
}
}
/**
* Create the Hessian proxy that is wrapped by this interceptor.
* @param proxyFactory the proxy factory to use
* @return the Hessian proxy
* @throws MalformedURLException if thrown by the proxy factory
* @see com.caucho.hessian.client.HessianProxyFactory#create
*/
protected Object createHessianProxy(HessianProxyFactory proxyFactory) throws MalformedURLException {
Assert.notNull(getServiceInterface(), "'serviceInterface' is required");
return proxyFactory.create(getServiceInterface(), getServiceUrl(), getBeanClassLoader());
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
if (this.hessianProxy == null) {
throw new IllegalStateException("HessianClientInterceptor is not properly initialized - " +
"invoke 'prepare' before attempting any operations");
}
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
return invocation.getMethod().invoke(this.hessianProxy, invocation.getArguments());
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
// Hessian 4.0 check: another layer of InvocationTargetException.
if (targetEx instanceof InvocationTargetException) {
targetEx = ((InvocationTargetException) targetEx).getTargetException();
}
if (targetEx instanceof HessianConnectionException) {
throw convertHessianAccessException(targetEx);
}
else if (targetEx instanceof HessianException || targetEx instanceof HessianRuntimeException) {
Throwable cause = targetEx.getCause();
throw convertHessianAccessException(cause != null ? cause : targetEx);
}
else if (targetEx instanceof UndeclaredThrowableException) {
UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
throw convertHessianAccessException(utex.getUndeclaredThrowable());
}
else {
throw targetEx;
}
}
catch (Throwable ex) {
throw new RemoteProxyFailureException(
"Failed to invoke Hessian proxy for remote service [" + getServiceUrl() + "]", ex);
}
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
/**
* Convert the given Hessian access exception to an appropriate
* Spring RemoteAccessException.
* @param ex the exception to convert
* @return the RemoteAccessException to throw
*/
protected RemoteAccessException convertHessianAccessException(Throwable ex) {
if (ex instanceof HessianConnectionException || ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Cannot connect to Hessian remote service at [" + getServiceUrl() + "]", ex);
}
else {
return new RemoteAccessException(
"Cannot access Hessian remote service at [" + getServiceUrl() + "]", ex);
}
}
}

View File

@@ -1,254 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.caucho;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianDebugInputStream;
import com.caucho.hessian.io.HessianDebugOutputStream;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import com.caucho.hessian.io.HessianRemoteResolver;
import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;
import org.apache.commons.logging.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.remoting.support.RemoteExporter;
import org.springframework.util.Assert;
import org.springframework.util.CommonsLogWriter;
/**
* General stream-based protocol exporter for a Hessian endpoint.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* @author Juergen Hoeller
* @since 2.5.1
* @see #invoke(java.io.InputStream, java.io.OutputStream)
* @see HessianServiceExporter
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HessianExporter extends RemoteExporter implements InitializingBean {
/**
* The content type for hessian ({@code application/x-hessian}).
*/
public static final String CONTENT_TYPE_HESSIAN = "application/x-hessian";
private SerializerFactory serializerFactory = new SerializerFactory();
@Nullable
private HessianRemoteResolver remoteResolver;
@Nullable
private Log debugLogger;
@Nullable
private HessianSkeleton skeleton;
/**
* Specify the Hessian SerializerFactory to use.
* <p>This will typically be passed in as an inner bean definition
* of type {@code com.caucho.hessian.io.SerializerFactory},
* with custom bean property values applied.
*/
public void setSerializerFactory(@Nullable SerializerFactory serializerFactory) {
this.serializerFactory = (serializerFactory != null ? serializerFactory : new SerializerFactory());
}
/**
* Set whether to send the Java collection type for each serialized
* collection. Default is "true".
*/
public void setSendCollectionType(boolean sendCollectionType) {
this.serializerFactory.setSendCollectionType(sendCollectionType);
}
/**
* Set whether to allow non-serializable types as Hessian arguments
* and return values. Default is "true".
*/
public void setAllowNonSerializable(boolean allowNonSerializable) {
this.serializerFactory.setAllowNonSerializable(allowNonSerializable);
}
/**
* Specify a custom HessianRemoteResolver to use for resolving remote
* object references.
*/
public void setRemoteResolver(HessianRemoteResolver remoteResolver) {
this.remoteResolver = remoteResolver;
}
/**
* Set whether Hessian's debug mode should be enabled, logging to
* this exporter's Commons Logging log. Default is "false".
* @see com.caucho.hessian.client.HessianProxyFactory#setDebug
*/
public void setDebug(boolean debug) {
this.debugLogger = (debug ? logger : null);
}
@Override
public void afterPropertiesSet() {
prepare();
}
/**
* Initialize this exporter.
*/
public void prepare() {
checkService();
checkServiceInterface();
this.skeleton = new HessianSkeleton(getProxyForService(), getServiceInterface());
}
/**
* Perform an invocation on the exported object.
* @param inputStream the request stream
* @param outputStream the response stream
* @throws Throwable if invocation failed
*/
public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable {
Assert.notNull(this.skeleton, "Hessian exporter has not been initialized");
doInvoke(this.skeleton, inputStream, outputStream);
}
/**
* Actually invoke the skeleton with the given streams.
* @param skeleton the skeleton to invoke
* @param inputStream the request stream
* @param outputStream the response stream
* @throws Throwable if invocation failed
*/
protected void doInvoke(HessianSkeleton skeleton, InputStream inputStream, OutputStream outputStream)
throws Throwable {
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
try {
InputStream isToUse = inputStream;
OutputStream osToUse = outputStream;
if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) {
try (PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger))){
@SuppressWarnings("resource")
HessianDebugInputStream dis = new HessianDebugInputStream(inputStream, debugWriter);
@SuppressWarnings("resource")
HessianDebugOutputStream dos = new HessianDebugOutputStream(outputStream, debugWriter);
dis.startTop2();
dos.startTop2();
isToUse = dis;
osToUse = dos;
}
}
if (!isToUse.markSupported()) {
isToUse = new BufferedInputStream(isToUse);
isToUse.mark(1);
}
int code = isToUse.read();
int major;
int minor;
AbstractHessianInput in;
AbstractHessianOutput out;
if (code == 'H') {
// Hessian 2.0 stream
major = isToUse.read();
minor = isToUse.read();
if (major != 0x02) {
throw new IOException("Version " + major + '.' + minor + " is not understood");
}
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
else if (code == 'C') {
// Hessian 2.0 call... for some reason not handled in HessianServlet!
isToUse.reset();
in = new Hessian2Input(isToUse);
out = new Hessian2Output(osToUse);
in.readCall();
}
else if (code == 'c') {
// Hessian 1.0 call
major = isToUse.read();
minor = isToUse.read();
in = new HessianInput(isToUse);
if (major >= 2) {
out = new Hessian2Output(osToUse);
}
else {
out = new HessianOutput(osToUse);
}
}
else {
throw new IOException("Expected 'H'/'C' (Hessian 2.0) or 'c' (Hessian 1.0) in hessian input at " + code);
}
in.setSerializerFactory(this.serializerFactory);
out.setSerializerFactory(this.serializerFactory);
if (this.remoteResolver != null) {
in.setRemoteResolver(this.remoteResolver);
}
try {
skeleton.invoke(in, out);
}
finally {
try {
in.close();
isToUse.close();
}
catch (IOException ex) {
// ignore
}
try {
out.close();
osToUse.close();
}
catch (IOException ex) {
// ignore
}
}
}
finally {
resetThreadContextClassLoader(originalClassLoader);
}
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.caucho;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
/**
* {@link FactoryBean} for Hessian proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
* <b>Note: As of Spring 4.0, this proxy factory requires Hessian 4.0 or above.</b>
*
* <p>The service URL must be an HTTP URL exposing a Hessian service.
* For details, see the {@link HessianClientInterceptor} javadoc.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see #setServiceInterface
* @see #setServiceUrl
* @see HessianClientInterceptor
* @see HessianServiceExporter
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object> {
@Nullable
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
}
@Override
@Nullable
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.caucho;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.util.NestedServletException;
/**
* Servlet-API-based HTTP request handler that exports the specified service bean
* as Hessian service endpoint, accessible via a Hessian proxy.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* <p>Hessian services exported with this class can be accessed by
* any Hessian client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 13.05.2003
* @see HessianClientInterceptor
* @see HessianProxyFactoryBean
* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
* @see org.springframework.remoting.rmi.RmiServiceExporter
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HessianServiceExporter extends HessianExporter implements HttpRequestHandler {
/**
* Processes the incoming Hessian request and creates a Hessian response.
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if (!"POST".equals(request.getMethod())) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
new String[] {"POST"}, "HessianServiceExporter only supports POST requests");
}
response.setContentType(CONTENT_TYPE_HESSIAN);
try {
invoke(request.getInputStream(), response.getOutputStream());
}
catch (Throwable ex) {
throw new NestedServletException("Hessian skeleton invocation failed", ex);
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.caucho;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.springframework.util.FileCopyUtils;
/**
* HTTP request handler that exports the specified service bean as
* Hessian service endpoint, accessible via a Hessian proxy.
* Designed for Sun's JRE 1.6 HTTP server, implementing the
* {@link com.sun.net.httpserver.HttpHandler} interface.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>.
* <b>Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above.</b>
*
* <p>Hessian services exported with this class can be accessed by
* any Hessian client, as there isn't any special handling involved.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see org.springframework.remoting.caucho.HessianClientInterceptor
* @see org.springframework.remoting.caucho.HessianProxyFactoryBean
* @deprecated as of Spring Framework 5.1, in favor of {@link HessianServiceExporter}
*/
@Deprecated
@org.springframework.lang.UsesSunHttpServer
public class SimpleHessianServiceExporter extends HessianExporter implements HttpHandler {
/**
* Processes the incoming Hessian request and creates a Hessian response.
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
if (!"POST".equals(exchange.getRequestMethod())) {
exchange.getResponseHeaders().set("Allow", "POST");
exchange.sendResponseHeaders(405, -1);
return;
}
ByteArrayOutputStream output = new ByteArrayOutputStream(1024);
try {
invoke(exchange.getRequestBody(), output);
}
catch (Throwable ex) {
exchange.sendResponseHeaders(500, -1);
logger.error("Hessian skeleton invocation failed", ex);
return;
}
exchange.getResponseHeaders().set("Content-Type", CONTENT_TYPE_HESSIAN);
exchange.sendResponseHeaders(200, output.size());
FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody());
}
}

View File

@@ -1,15 +0,0 @@
/**
* This package provides remoting classes for Caucho's Hessian protocol:
* a proxy factory for accessing Hessian services, and an exporter for
* making beans available to Hessian clients.
*
* <p>Hessian is a slim, binary RPC protocol over HTTP.
* For information on Hessian, see the
* <a href="http://hessian.caucho.com">Hessian website</a>
*/
@NonNullApi
@NonNullFields
package org.springframework.remoting.caucho;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,295 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* Abstract base implementation of the HttpInvokerRequestExecutor interface.
*
* <p>Pre-implements serialization of RemoteInvocation objects and
* deserialization of RemoteInvocationResults objects.
*
* @author Juergen Hoeller
* @since 1.1
* @see #doExecuteRequest
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public abstract class AbstractHttpInvokerRequestExecutor implements HttpInvokerRequestExecutor, BeanClassLoaderAware {
/**
* Default content type: "application/x-java-serialized-object".
*/
public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
protected static final String HTTP_METHOD_POST = "POST";
protected static final String HTTP_HEADER_ACCEPT_LANGUAGE = "Accept-Language";
protected static final String HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding";
protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
protected static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
protected static final String HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
protected static final String ENCODING_GZIP = "gzip";
protected final Log logger = LogFactory.getLog(getClass());
private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
private boolean acceptGzipEncoding = true;
@Nullable
private ClassLoader beanClassLoader;
/**
* Specify the content type to use for sending HTTP invoker requests.
* <p>Default is "application/x-java-serialized-object".
*/
public void setContentType(String contentType) {
Assert.notNull(contentType, "'contentType' must not be null");
this.contentType = contentType;
}
/**
* Return the content type to use for sending HTTP invoker requests.
*/
public String getContentType() {
return this.contentType;
}
/**
* Set whether to accept GZIP encoding, that is, whether to
* send the HTTP "Accept-Encoding" header with "gzip" as value.
* <p>Default is "true". Turn this flag off if you do not want
* GZIP response compression even if enabled on the HTTP server.
*/
public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
this.acceptGzipEncoding = acceptGzipEncoding;
}
/**
* Return whether to accept GZIP encoding, that is, whether to
* send the HTTP "Accept-Encoding" header with "gzip" as value.
*/
public boolean isAcceptGzipEncoding() {
return this.acceptGzipEncoding;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
/**
* Return the bean ClassLoader that this executor is supposed to use.
*/
@Nullable
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
@Override
public final RemoteInvocationResult executeRequest(
HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception {
ByteArrayOutputStream baos = getByteArrayOutputStream(invocation);
if (logger.isDebugEnabled()) {
logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
"], with size " + baos.size());
}
return doExecuteRequest(config, baos);
}
/**
* Serialize the given RemoteInvocation into a ByteArrayOutputStream.
* @param invocation the RemoteInvocation object
* @return a ByteArrayOutputStream with the serialized RemoteInvocation
* @throws IOException if thrown by I/O methods
*/
protected ByteArrayOutputStream getByteArrayOutputStream(RemoteInvocation invocation) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream(SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE);
writeRemoteInvocation(invocation, baos);
return baos;
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@code decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@code ObjectOutputStream} for the final stream and calls
* {@code doWriteRemoteInvocation} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param invocation the RemoteInvocation object
* @param os the OutputStream to write to
* @throws IOException if thrown by I/O methods
* @see #decorateOutputStream
* @see #doWriteRemoteInvocation
*/
protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(decorateOutputStream(os))) {
doWriteRemoteInvocation(invocation, oos);
}
}
/**
* Return the OutputStream to use for writing remote invocations,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param os the original OutputStream
* @return the potentially decorated OutputStream
*/
protected OutputStream decorateOutputStream(OutputStream os) throws IOException {
return os;
}
/**
* Perform the actual writing of the given invocation object to the
* given ObjectOutputStream.
* <p>The default implementation simply calls {@code writeObject}.
* Can be overridden for serialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param invocation the RemoteInvocation object
* @param oos the ObjectOutputStream to write to
* @throws IOException if thrown by I/O methods
* @see java.io.ObjectOutputStream#writeObject
*/
protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException {
oos.writeObject(invocation);
}
/**
* Execute a request to send the given serialized remote invocation.
* <p>Implementations will usually call {@code readRemoteInvocationResult}
* to deserialize a returned RemoteInvocationResult object.
* @param config the HTTP invoker configuration that specifies the
* target service
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
* @see #readRemoteInvocationResult(java.io.InputStream, String)
*/
protected abstract RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws Exception;
/**
* Deserialize a RemoteInvocationResult object from the given InputStream.
* <p>Gives {@code decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates an
* {@code ObjectInputStream} via {@code createObjectInputStream} and
* calls {@code doReadRemoteInvocationResult} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param is the InputStream to read from
* @param codebaseUrl the codebase URL to load classes from if not found locally
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O methods
* @throws ClassNotFoundException if thrown during deserialization
* @see #decorateInputStream
* @see #createObjectInputStream
* @see #doReadRemoteInvocationResult
*/
protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, @Nullable String codebaseUrl)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl)) {
return doReadRemoteInvocationResult(ois);
}
}
/**
* Return the InputStream to use for reading remote invocation results,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param is the original InputStream
* @return the potentially decorated InputStream
*/
protected InputStream decorateInputStream(InputStream is) throws IOException {
return is;
}
/**
* Create an ObjectInputStream for the given InputStream and codebase.
* The default implementation creates a CodebaseAwareObjectInputStream.
* @param is the InputStream to read from
* @param codebaseUrl the codebase URL to load classes from if not found locally
* (can be {@code null})
* @return the new ObjectInputStream instance to use
* @throws IOException if creation of the ObjectInputStream failed
* @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream
*/
protected ObjectInputStream createObjectInputStream(InputStream is, @Nullable String codebaseUrl) throws IOException {
return new org.springframework.remoting.rmi.CodebaseAwareObjectInputStream(is, getBeanClassLoader(), codebaseUrl);
}
/**
* Perform the actual reading of an invocation object from the
* given ObjectInputStream.
* <p>The default implementation simply calls {@code readObject}.
* Can be overridden for deserialization of a custom wrapper object rather
* than the plain invocation, for example an encryption-aware holder.
* @param ois the ObjectInputStream to read from
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O methods
* @throws ClassNotFoundException if the class name of a serialized object
* couldn't get resolved
* @see java.io.ObjectOutputStream#writeObject
*/
protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
Object obj = ois.readObject();
if (!(obj instanceof RemoteInvocationResult)) {
throw new RemoteException("Deserialized object needs to be assignable to type [" +
RemoteInvocationResult.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj));
}
return (RemoteInvocationResult) obj;
}
}

View File

@@ -1,370 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NoHttpResponseException;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.Configurable;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.lang.Nullable;
import org.springframework.remoting.support.RemoteInvocationResult;
import org.springframework.util.Assert;
/**
* {@link org.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor} implementation that uses
* <a href="https://hc.apache.org/httpcomponents-client-ga/httpclient/">Apache HttpComponents HttpClient</a>
* to execute POST requests.
*
* <p>Allows to use a pre-configured {@link org.apache.http.client.HttpClient}
* instance, potentially with authentication, HTTP connection pooling, etc.
* Also designed for easy subclassing, providing specific template methods.
*
* <p>As of Spring 4.1, this request executor requires Apache HttpComponents 4.3 or higher.
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
* @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HttpComponentsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;
private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);
private HttpClient httpClient;
@Nullable
private RequestConfig requestConfig;
/**
* Create a new instance of the HttpComponentsHttpInvokerRequestExecutor with a default
* {@link HttpClient} that uses a default {@code org.apache.http.impl.conn.PoolingClientConnectionManager}.
*/
public HttpComponentsHttpInvokerRequestExecutor() {
this(createDefaultHttpClient(), RequestConfig.custom()
.setSocketTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS).build());
}
/**
* Create a new instance of the HttpComponentsClientHttpRequestFactory
* with the given {@link HttpClient} instance.
* @param httpClient the HttpClient instance to use for this request executor
*/
public HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient) {
this(httpClient, null);
}
private HttpComponentsHttpInvokerRequestExecutor(HttpClient httpClient, @Nullable RequestConfig requestConfig) {
this.httpClient = httpClient;
this.requestConfig = requestConfig;
}
private static HttpClient createDefaultHttpClient() {
Registry<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(schemeRegistry);
connectionManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
connectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
}
/**
* Set the {@link HttpClient} instance to use for this request executor.
*/
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
/**
* Return the {@link HttpClient} instance that this request executor uses.
*/
public HttpClient getHttpClient() {
return this.httpClient;
}
/**
* Set the connection timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param timeout the timeout value in milliseconds
* @see RequestConfig#getConnectTimeout()
*/
public void setConnectTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
this.requestConfig = cloneRequestConfig().setConnectTimeout(timeout).build();
}
/**
* Set the timeout in milliseconds used when requesting a connection from the connection
* manager using the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param connectionRequestTimeout the timeout value to request a connection in milliseconds
* @see RequestConfig#getConnectionRequestTimeout()
*/
public void setConnectionRequestTimeout(int connectionRequestTimeout) {
this.requestConfig = cloneRequestConfig().setConnectionRequestTimeout(connectionRequestTimeout).build();
}
/**
* Set the socket read timeout for the underlying HttpClient.
* A timeout value of 0 specifies an infinite timeout.
* <p>Additional properties can be configured by specifying a
* {@link RequestConfig} instance on a custom {@link HttpClient}.
* @param timeout the timeout value in milliseconds
* @see #DEFAULT_READ_TIMEOUT_MILLISECONDS
* @see RequestConfig#getSocketTimeout()
*/
public void setReadTimeout(int timeout) {
Assert.isTrue(timeout >= 0, "Timeout must be a non-negative value");
this.requestConfig = cloneRequestConfig().setSocketTimeout(timeout).build();
}
private RequestConfig.Builder cloneRequestConfig() {
return (this.requestConfig != null ? RequestConfig.copy(this.requestConfig) : RequestConfig.custom());
}
/**
* Execute the given request through the HttpClient.
* <p>This method implements the basic processing workflow:
* The actual work happens in this class's template methods.
* @see #createHttpPost
* @see #setRequestBody
* @see #executeHttpPost
* @see #validateResponse
* @see #getResponseBody
*/
@Override
protected RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws IOException, ClassNotFoundException {
HttpPost postMethod = createHttpPost(config);
setRequestBody(config, postMethod, baos);
try {
HttpResponse response = executeHttpPost(config, getHttpClient(), postMethod);
validateResponse(config, response);
InputStream responseBody = getResponseBody(config, response);
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
}
finally {
postMethod.releaseConnection();
}
}
/**
* Create an HttpPost for the given configuration.
* <p>The default implementation creates a standard HttpPost with
* "application/x-java-serialized-object" as "Content-Type" header.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the HttpPost instance
* @throws java.io.IOException if thrown by I/O methods
*/
protected HttpPost createHttpPost(HttpInvokerClientConfiguration config) throws IOException {
HttpPost httpPost = new HttpPost(config.getServiceUrl());
RequestConfig requestConfig = createRequestConfig(config);
if (requestConfig != null) {
httpPost.setConfig(requestConfig);
}
LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
if (localeContext != null) {
Locale locale = localeContext.getLocale();
if (locale != null) {
httpPost.addHeader(HTTP_HEADER_ACCEPT_LANGUAGE, locale.toLanguageTag());
}
}
if (isAcceptGzipEncoding()) {
httpPost.addHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
return httpPost;
}
/**
* Create a {@link RequestConfig} for the given configuration. Can return {@code null}
* to indicate that no custom request config should be set and the defaults of the
* {@link HttpClient} should be used.
* <p>The default implementation tries to merge the defaults of the client with the
* local customizations of the instance, if any.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the RequestConfig to use
*/
@Nullable
protected RequestConfig createRequestConfig(HttpInvokerClientConfiguration config) {
HttpClient client = getHttpClient();
if (client instanceof Configurable) {
RequestConfig clientRequestConfig = ((Configurable) client).getConfig();
return mergeRequestConfig(clientRequestConfig);
}
return this.requestConfig;
}
private RequestConfig mergeRequestConfig(RequestConfig defaultRequestConfig) {
if (this.requestConfig == null) { // nothing to merge
return defaultRequestConfig;
}
RequestConfig.Builder builder = RequestConfig.copy(defaultRequestConfig);
int connectTimeout = this.requestConfig.getConnectTimeout();
if (connectTimeout >= 0) {
builder.setConnectTimeout(connectTimeout);
}
int connectionRequestTimeout = this.requestConfig.getConnectionRequestTimeout();
if (connectionRequestTimeout >= 0) {
builder.setConnectionRequestTimeout(connectionRequestTimeout);
}
int socketTimeout = this.requestConfig.getSocketTimeout();
if (socketTimeout >= 0) {
builder.setSocketTimeout(socketTimeout);
}
return builder.build();
}
/**
* Set the given serialized remote invocation as request body.
* <p>The default implementation simply sets the serialized invocation as the
* HttpPost's request body. This can be overridden, for example, to write a
* specific encoding and to potentially set appropriate HTTP request headers.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpPost the HttpPost to set the request body on
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @throws java.io.IOException if thrown by I/O methods
*/
protected void setRequestBody(
HttpInvokerClientConfiguration config, HttpPost httpPost, ByteArrayOutputStream baos)
throws IOException {
ByteArrayEntity entity = new ByteArrayEntity(baos.toByteArray());
entity.setContentType(getContentType());
httpPost.setEntity(entity);
}
/**
* Execute the given HttpPost instance.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpClient the HttpClient to execute on
* @param httpPost the HttpPost to execute
* @return the resulting HttpResponse
* @throws java.io.IOException if thrown by I/O methods
*/
protected HttpResponse executeHttpPost(
HttpInvokerClientConfiguration config, HttpClient httpClient, HttpPost httpPost)
throws IOException {
return httpClient.execute(httpPost);
}
/**
* Validate the given response as contained in the HttpPost object,
* throwing an exception if it does not correspond to a successful HTTP response.
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
* parsing the response body and trying to deserialize from a corrupted stream.
* @param config the HTTP invoker configuration that specifies the target service
* @param response the resulting HttpResponse to validate
* @throws java.io.IOException if validation failed
*/
protected void validateResponse(HttpInvokerClientConfiguration config, HttpResponse response)
throws IOException {
StatusLine status = response.getStatusLine();
if (status.getStatusCode() >= 300) {
throw new NoHttpResponseException(
"Did not receive successful HTTP response: status code = " + status.getStatusCode() +
", status message = [" + status.getReasonPhrase() + "]");
}
}
/**
* Extract the response body from the given executed remote invocation request.
* <p>The default implementation simply fetches the HttpPost's response body stream.
* If the response is recognized as GZIP response, the InputStream will get wrapped
* in a GZIPInputStream.
* @param config the HTTP invoker configuration that specifies the target service
* @param httpResponse the resulting HttpResponse to read the response body from
* @return an InputStream for the response body
* @throws java.io.IOException if thrown by I/O methods
* @see #isGzipResponse
* @see java.util.zip.GZIPInputStream
*/
protected InputStream getResponseBody(HttpInvokerClientConfiguration config, HttpResponse httpResponse)
throws IOException {
if (isGzipResponse(httpResponse)) {
return new GZIPInputStream(httpResponse.getEntity().getContent());
}
else {
return httpResponse.getEntity().getContent();
}
}
/**
* Determine whether the given response indicates a GZIP response.
* <p>The default implementation checks whether the HTTP "Content-Encoding"
* header contains "gzip" (in any casing).
* @param httpResponse the resulting HttpResponse to check
* @return whether the given response indicates a GZIP response
*/
protected boolean isGzipResponse(HttpResponse httpResponse) {
Header encodingHeader = httpResponse.getFirstHeader(HTTP_HEADER_CONTENT_ENCODING);
return (encodingHeader != null && encodingHeader.getValue() != null &&
encodingHeader.getValue().toLowerCase().contains(ENCODING_GZIP));
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import org.springframework.lang.Nullable;
/**
* Configuration interface for executing HTTP invoker requests.
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerRequestExecutor
* @see HttpInvokerClientInterceptor
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public interface HttpInvokerClientConfiguration {
/**
* Return the HTTP URL of the target service.
*/
String getServiceUrl();
/**
* Return the codebase URL to download classes from if not found locally.
* Can consist of multiple URLs, separated by spaces.
* @return the codebase URL, or {@code null} if none
* @see java.rmi.server.RMIClassLoader
*/
@Nullable
String getCodebaseUrl();
}

View File

@@ -1,241 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.IOException;
import java.io.InvalidClassException;
import java.net.ConnectException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.lang.Nullable;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteConnectFailureException;
import org.springframework.remoting.RemoteInvocationFailureException;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationBasedAccessor;
import org.springframework.remoting.support.RemoteInvocationResult;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing an
* HTTP invoker service. The service URL must be an HTTP URL exposing
* an HTTP invoker service.
*
* <p>Serializes remote invocation objects and deserializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian protocol.
*
* <P>HTTP invoker is a very extensible and customizable protocol.
* It supports the RemoteInvocationFactory mechanism, like RMI invoker,
* allowing to include additional invocation attributes (for example,
* a security context). Furthermore, it allows to customize request
* execution via the {@link HttpInvokerRequestExecutor} strategy.
*
* <p>Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load classes
* from a given {@link #setCodebaseUrl codebase}, performing on-demand dynamic
* code download from a remote location. The codebase can consist of multiple
* URLs, separated by spaces. Note that RMIClassLoader requires a SecurityManager
* to be set, analogous to when using dynamic class download with standard RMI!
* (See the RMI documentation for details.)
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceUrl
* @see #setCodebaseUrl
* @see #setRemoteInvocationFactory
* @see #setHttpInvokerRequestExecutor
* @see HttpInvokerServiceExporter
* @see HttpInvokerProxyFactoryBean
* @see java.rmi.server.RMIClassLoader
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor
implements MethodInterceptor, HttpInvokerClientConfiguration {
@Nullable
private String codebaseUrl;
@Nullable
private HttpInvokerRequestExecutor httpInvokerRequestExecutor;
/**
* Set the codebase URL to download classes from if not found locally.
* Can consists of multiple URLs, separated by spaces.
* <p>Follows RMI's codebase conventions for dynamic class download.
* In contrast to RMI, where the server determines the URL for class download
* (via the "java.rmi.server.codebase" system property), it's the client
* that determines the codebase URL here. The server will usually be the
* same as for the service URL, just pointing to a different path there.
* @see #setServiceUrl
* @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream
* @see java.rmi.server.RMIClassLoader
*/
public void setCodebaseUrl(@Nullable String codebaseUrl) {
this.codebaseUrl = codebaseUrl;
}
/**
* Return the codebase URL to download classes from if not found locally.
*/
@Override
@Nullable
public String getCodebaseUrl() {
return this.codebaseUrl;
}
/**
* Set the HttpInvokerRequestExecutor implementation to use for executing
* remote invocations.
* <p>Default is {@link SimpleHttpInvokerRequestExecutor}. Alternatively,
* consider using {@link HttpComponentsHttpInvokerRequestExecutor} for more
* sophisticated needs.
* @see SimpleHttpInvokerRequestExecutor
* @see HttpComponentsHttpInvokerRequestExecutor
*/
public void setHttpInvokerRequestExecutor(HttpInvokerRequestExecutor httpInvokerRequestExecutor) {
this.httpInvokerRequestExecutor = httpInvokerRequestExecutor;
}
/**
* Return the HttpInvokerRequestExecutor used by this remote accessor.
* <p>Creates a default SimpleHttpInvokerRequestExecutor if no executor
* has been initialized already.
*/
public HttpInvokerRequestExecutor getHttpInvokerRequestExecutor() {
if (this.httpInvokerRequestExecutor == null) {
SimpleHttpInvokerRequestExecutor executor = new SimpleHttpInvokerRequestExecutor();
executor.setBeanClassLoader(getBeanClassLoader());
this.httpInvokerRequestExecutor = executor;
}
return this.httpInvokerRequestExecutor;
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Eagerly initialize the default HttpInvokerRequestExecutor, if needed.
getHttpInvokerRequestExecutor();
}
@Override
@Nullable
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "HTTP invoker proxy for service URL [" + getServiceUrl() + "]";
}
RemoteInvocation invocation = createRemoteInvocation(methodInvocation);
RemoteInvocationResult result;
try {
result = executeRequest(invocation, methodInvocation);
}
catch (Throwable ex) {
RemoteAccessException rae = convertHttpInvokerAccessException(ex);
throw (rae != null ? rae : ex);
}
try {
return recreateRemoteInvocationResult(result);
}
catch (Throwable ex) {
if (result.hasInvocationTargetException()) {
throw ex;
}
else {
throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() +
"] failed in HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
}
}
/**
* Execute the given remote invocation via the {@link HttpInvokerRequestExecutor}.
* <p>This implementation delegates to {@link #executeRequest(RemoteInvocation)}.
* Can be overridden to react to the specific original MethodInvocation.
* @param invocation the RemoteInvocation to execute
* @param originalInvocation the original MethodInvocation (can e.g. be cast
* to the ProxyMethodInvocation interface for accessing user attributes)
* @return the RemoteInvocationResult object
* @throws Exception in case of errors
*/
protected RemoteInvocationResult executeRequest(
RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {
return executeRequest(invocation);
}
/**
* Execute the given remote invocation via the {@link HttpInvokerRequestExecutor}.
* <p>Can be overridden in subclasses to pass a different configuration object
* to the executor. Alternatively, add further configuration properties in a
* subclass of this accessor: By default, the accessor passed itself as
* configuration object to the executor.
* @param invocation the RemoteInvocation to execute
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
* @see #getHttpInvokerRequestExecutor
* @see HttpInvokerClientConfiguration
*/
protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception {
return getHttpInvokerRequestExecutor().executeRequest(this, invocation);
}
/**
* Convert the given HTTP invoker access exception to an appropriate
* Spring {@link RemoteAccessException}.
* @param ex the exception to convert
* @return the RemoteAccessException to throw, or {@code null} to have the
* original exception propagated to the caller
*/
@Nullable
protected RemoteAccessException convertHttpInvokerAccessException(Throwable ex) {
if (ex instanceof ConnectException) {
return new RemoteConnectFailureException(
"Could not connect to HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
if (ex instanceof ClassNotFoundException || ex instanceof NoClassDefFoundError ||
ex instanceof InvalidClassException) {
return new RemoteAccessException(
"Could not deserialize result from HTTP invoker remote service [" + getServiceUrl() + "]", ex);
}
if (ex instanceof Exception) {
return new RemoteAccessException(
"Could not access HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
}
// For any other Throwable, e.g. OutOfMemoryError: let it get propagated as-is.
return null;
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link FactoryBean} for HTTP invoker proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>The service URL must be an HTTP URL exposing an HTTP invoker service.
* Optionally, a codebase URL can be specified for on-demand dynamic code download
* from a remote location. For details, see HttpInvokerClientInterceptor docs.
*
* <p>Serializes remote invocation objects and deserializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian protocol.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian, at the expense of
* being tied to Java. Nevertheless, it is as easy to set up as Hessian,
* which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see #setServiceInterface
* @see #setServiceUrl
* @see #setCodebaseUrl
* @see HttpInvokerClientInterceptor
* @see HttpInvokerServiceExporter
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
* @see org.springframework.remoting.caucho.HessianProxyFactoryBean
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor implements FactoryBean<Object> {
@Nullable
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Class<?> ifc = getServiceInterface();
Assert.notNull(ifc, "Property 'serviceInterface' is required");
this.serviceProxy = new ProxyFactory(ifc, this).getProxy(getBeanClassLoader());
}
@Override
@Nullable
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.IOException;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;
/**
* Strategy interface for actual execution of an HTTP invoker request.
* Used by HttpInvokerClientInterceptor and its subclass
* HttpInvokerProxyFactoryBean.
*
* <p>Two implementations are provided out of the box:
* <ul>
* <li><b>{@code SimpleHttpInvokerRequestExecutor}:</b>
* Uses JDK facilities to execute POST requests, without support
* for HTTP authentication or advanced configuration options.
* <li><b>{@code HttpComponentsHttpInvokerRequestExecutor}:</b>
* Uses Apache's Commons HttpClient to execute POST requests,
* allowing to use a preconfigured HttpClient instance
* (potentially with authentication, HTTP connection pooling, etc).
* </ul>
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerClientInterceptor#setHttpInvokerRequestExecutor
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
@FunctionalInterface
public interface HttpInvokerRequestExecutor {
/**
* Execute a request to send the given remote invocation.
* @param config the HTTP invoker configuration that specifies the
* target service
* @param invocation the RemoteInvocation to execute
* @return the RemoteInvocationResult object
* @throws IOException if thrown by I/O operations
* @throws ClassNotFoundException if thrown during deserialization
* @throws Exception in case of general errors
*/
RemoteInvocationResult executeRequest(HttpInvokerClientConfiguration config, RemoteInvocation invocation)
throws Exception;
}

View File

@@ -1,215 +0,0 @@
/*
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.util.NestedServletException;
/**
* Servlet-API-based HTTP request handler that exports the specified service bean
* as HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
*
* <p>Deserializes remote invocation objects and serializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian protocol.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian, at the expense of
* being tied to Java. Nevertheless, it is as easy to set up as Hessian,
* which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 1.1
* @see HttpInvokerClientInterceptor
* @see HttpInvokerProxyFactoryBean
* @see org.springframework.remoting.rmi.RmiServiceExporter
* @see org.springframework.remoting.caucho.HessianServiceExporter
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class HttpInvokerServiceExporter extends org.springframework.remoting.rmi.RemoteInvocationSerializingExporter implements HttpRequestHandler {
/**
* Reads a remote invocation from the request, executes it,
* and writes the remote invocation result to the response.
* @see #readRemoteInvocation(HttpServletRequest)
* @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(HttpServletRequest, HttpServletResponse, RemoteInvocationResult)
*/
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
RemoteInvocation invocation = readRemoteInvocation(request);
RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
writeRemoteInvocationResult(request, response, result);
}
catch (ClassNotFoundException ex) {
throw new NestedServletException("Class not found during deserialization", ex);
}
}
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to {@link #readRemoteInvocation(HttpServletRequest, InputStream)} with
* the {@link HttpServletRequest#getInputStream() servlet request's input stream}.
* @param request current HTTP request
* @return the RemoteInvocation object
* @throws IOException in case of I/O failure
* @throws ClassNotFoundException if thrown by deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request)
throws IOException, ClassNotFoundException {
return readRemoteInvocation(request, request.getInputStream());
}
/**
* Deserialize a RemoteInvocation object from the given InputStream.
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates a
* {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
* and calls {@link #doReadRemoteInvocation} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param request current HTTP request
* @param is the InputStream to read from
* @return the RemoteInvocation object
* @throws IOException in case of I/O failure
* @throws ClassNotFoundException if thrown during deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)
throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is))) {
return doReadRemoteInvocation(ois);
}
}
/**
* Return the InputStream to use for reading remote invocations,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param request current HTTP request
* @param is the original InputStream
* @return the potentially decorated InputStream
* @throws IOException in case of I/O failure
*/
protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException {
return is;
}
/**
* Write the given RemoteInvocationResult to the given HTTP response.
* @param request current HTTP request
* @param response current HTTP response
* @param result the RemoteInvocationResult object
* @throws IOException in case of I/O failure
*/
protected void writeRemoteInvocationResult(
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)
throws IOException {
response.setContentType(getContentType());
writeRemoteInvocationResult(request, response, result, response.getOutputStream());
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@link #decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
* {@link #doWriteRemoteInvocationResult} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param request current HTTP request
* @param response current HTTP response
* @param result the RemoteInvocationResult object
* @param os the OutputStream to write to
* @throws IOException in case of I/O failure
* @see #decorateOutputStream
* @see #doWriteRemoteInvocationResult
*/
protected void writeRemoteInvocationResult(
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
throws IOException {
try (ObjectOutputStream oos =
createObjectOutputStream(new FlushGuardedOutputStream(decorateOutputStream(request, response, os)))) {
doWriteRemoteInvocationResult(result, oos);
}
}
/**
* Return the OutputStream to use for writing remote invocation results,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param request current HTTP request
* @param response current HTTP response
* @param os the original OutputStream
* @return the potentially decorated OutputStream
* @throws IOException in case of I/O failure
*/
protected OutputStream decorateOutputStream(
HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException {
return os;
}
/**
* Decorate an {@code OutputStream} to guard against {@code flush()} calls,
* which are turned into no-ops.
* <p>Because {@link ObjectOutputStream#close()} will in fact flush/drain
* the underlying stream twice, this {@link FilterOutputStream} will
* guard against individual flush calls. Multiple flush calls can lead
* to performance issues, since writes aren't gathered as they should be.
* @see <a href="https://jira.spring.io/browse/SPR-14040">SPR-14040</a>
*/
private static class FlushGuardedOutputStream extends FilterOutputStream {
public FlushGuardedOutputStream(OutputStream out) {
super(out);
}
@Override
public void flush() throws IOException {
// Do nothing on flush
}
}
}

View File

@@ -1,233 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.zip.GZIPInputStream;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.remoting.support.RemoteInvocationResult;
/**
* {@link org.springframework.remoting.httpinvoker.HttpInvokerRequestExecutor} implementation
* that uses standard Java facilities to execute POST requests, without support for HTTP
* authentication or advanced configuration options.
*
* <p>Designed for easy subclassing, customizing specific template methods. However,
* consider {@code HttpComponentsHttpInvokerRequestExecutor} for more sophisticated needs:
* The standard {@link HttpURLConnection} class is rather limited in its capabilities.
*
* @author Juergen Hoeller
* @since 1.1
* @see java.net.HttpURLConnection
* @deprecated as of 5.3 (phasing out serialization-based remoting)
*/
@Deprecated
public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
private int connectTimeout = -1;
private int readTimeout = -1;
/**
* Set the underlying URLConnection's connect timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* <p>Default is the system's default timeout.
* @see URLConnection#setConnectTimeout(int)
*/
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
/**
* Set the underlying URLConnection's read timeout (in milliseconds).
* A timeout value of 0 specifies an infinite timeout.
* <p>Default is the system's default timeout.
* @see URLConnection#setReadTimeout(int)
*/
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/**
* Execute the given request through a standard {@link HttpURLConnection}.
* <p>This method implements the basic processing workflow:
* The actual work happens in this class's template methods.
* @see #openConnection
* @see #prepareConnection
* @see #writeRequestBody
* @see #validateResponse
* @see #readResponseBody
*/
@Override
protected RemoteInvocationResult doExecuteRequest(
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
throws IOException, ClassNotFoundException {
HttpURLConnection con = openConnection(config);
prepareConnection(con, baos.size());
writeRequestBody(config, con, baos);
validateResponse(config, con);
InputStream responseBody = readResponseBody(config, con);
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
}
/**
* Open an {@link HttpURLConnection} for the given remote invocation request.
* @param config the HTTP invoker configuration that specifies the
* target service
* @return the HttpURLConnection for the given request
* @throws IOException if thrown by I/O methods
* @see java.net.URL#openConnection()
*/
protected HttpURLConnection openConnection(HttpInvokerClientConfiguration config) throws IOException {
URLConnection con = new URL(config.getServiceUrl()).openConnection();
if (!(con instanceof HttpURLConnection)) {
throw new IOException(
"Service URL [" + config.getServiceUrl() + "] does not resolve to an HTTP connection");
}
return (HttpURLConnection) con;
}
/**
* Prepare the given HTTP connection.
* <p>The default implementation specifies POST as method,
* "application/x-java-serialized-object" as "Content-Type" header,
* and the given content length as "Content-Length" header.
* @param connection the HTTP connection to prepare
* @param contentLength the length of the content to send
* @throws IOException if thrown by HttpURLConnection methods
* @see java.net.HttpURLConnection#setRequestMethod
* @see java.net.HttpURLConnection#setRequestProperty
*/
protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
if (this.connectTimeout >= 0) {
connection.setConnectTimeout(this.connectTimeout);
}
if (this.readTimeout >= 0) {
connection.setReadTimeout(this.readTimeout);
}
connection.setDoOutput(true);
connection.setRequestMethod(HTTP_METHOD_POST);
connection.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
connection.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));
LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
if (localeContext != null) {
Locale locale = localeContext.getLocale();
if (locale != null) {
connection.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, locale.toLanguageTag());
}
}
if (isAcceptGzipEncoding()) {
connection.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
}
}
/**
* Set the given serialized remote invocation as request body.
* <p>The default implementation simply write the serialized invocation to the
* HttpURLConnection's OutputStream. This can be overridden, for example, to write
* a specific encoding and potentially set appropriate HTTP request headers.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to write the request body to
* @param baos the ByteArrayOutputStream that contains the serialized
* RemoteInvocation object
* @throws IOException if thrown by I/O methods
* @see java.net.HttpURLConnection#getOutputStream()
* @see java.net.HttpURLConnection#setRequestProperty
*/
protected void writeRequestBody(
HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)
throws IOException {
baos.writeTo(con.getOutputStream());
}
/**
* Validate the given response as contained in the {@link HttpURLConnection} object,
* throwing an exception if it does not correspond to a successful HTTP response.
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
* parsing the response body and trying to deserialize from a corrupted stream.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to validate
* @throws IOException if validation failed
* @see java.net.HttpURLConnection#getResponseCode()
*/
protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)
throws IOException {
if (con.getResponseCode() >= 300) {
throw new IOException(
"Did not receive successful HTTP response: status code = " + con.getResponseCode() +
", status message = [" + con.getResponseMessage() + "]");
}
}
/**
* Extract the response body from the given executed remote invocation
* request.
* <p>The default implementation simply reads the serialized invocation
* from the HttpURLConnection's InputStream. If the response is recognized
* as GZIP response, the InputStream will get wrapped in a GZIPInputStream.
* @param config the HTTP invoker configuration that specifies the target service
* @param con the HttpURLConnection to read the response body from
* @return an InputStream for the response body
* @throws IOException if thrown by I/O methods
* @see #isGzipResponse
* @see java.util.zip.GZIPInputStream
* @see java.net.HttpURLConnection#getInputStream()
* @see java.net.HttpURLConnection#getHeaderField(int)
* @see java.net.HttpURLConnection#getHeaderFieldKey(int)
*/
protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)
throws IOException {
if (isGzipResponse(con)) {
// GZIP response found - need to unzip.
return new GZIPInputStream(con.getInputStream());
}
else {
// Plain response found.
return con.getInputStream();
}
}
/**
* Determine whether the given response is a GZIP response.
* <p>Default implementation checks whether the HTTP "Content-Encoding"
* header contains "gzip" (in any casing).
* @param con the HttpURLConnection to check
*/
protected boolean isGzipResponse(HttpURLConnection con) {
String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
return (encodingHeader != null && encodingHeader.toLowerCase().contains(ENCODING_GZIP));
}
}

View File

@@ -1,182 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.httpinvoker;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;
/**
* HTTP request handler that exports the specified service bean as
* HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
* Designed for Sun's JRE 1.6 HTTP server, implementing the
* {@link com.sun.net.httpserver.HttpHandler} interface.
*
* <p>Deserializes remote invocation objects and serializes remote invocation
* result objects. Uses Java serialization just like RMI, but provides the
* same ease of setup as Caucho's HTTP-based Hessian protocol.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian, at the expense of
* being tied to Java. Nevertheless, it is as easy to set up as Hessian,
* which is its main advantage compared to RMI.
*
* <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization:
* Manipulated input streams could lead to unwanted code execution on the server
* during the deserialization step. As a consequence, do not expose HTTP invoker
* endpoints to untrusted clients but rather just between your own services.</b>
* In general, we strongly recommend any other message format (e.g. JSON) instead.
*
* @author Juergen Hoeller
* @since 2.5.1
* @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @deprecated as of Spring Framework 5.1, in favor of {@link HttpInvokerServiceExporter}
*/
@Deprecated
@org.springframework.lang.UsesSunHttpServer
public class SimpleHttpInvokerServiceExporter extends org.springframework.remoting.rmi.RemoteInvocationSerializingExporter implements HttpHandler {
/**
* Reads a remote invocation from the request, executes it,
* and writes the remote invocation result to the response.
* @see #readRemoteInvocation(HttpExchange)
* @see #invokeAndCreateResult(RemoteInvocation, Object)
* @see #writeRemoteInvocationResult(HttpExchange, RemoteInvocationResult)
*/
@Override
public void handle(HttpExchange exchange) throws IOException {
try {
RemoteInvocation invocation = readRemoteInvocation(exchange);
RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
writeRemoteInvocationResult(exchange, result);
exchange.close();
}
catch (ClassNotFoundException ex) {
exchange.sendResponseHeaders(500, -1);
logger.error("Class not found during deserialization", ex);
}
}
/**
* Read a RemoteInvocation from the given HTTP request.
* <p>Delegates to {@link #readRemoteInvocation(HttpExchange, InputStream)}
* with the {@link HttpExchange#getRequestBody()} request's input stream}.
* @param exchange current HTTP request/response
* @return the RemoteInvocation object
* @throws java.io.IOException in case of I/O failure
* @throws ClassNotFoundException if thrown by deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange)
throws IOException, ClassNotFoundException {
return readRemoteInvocation(exchange, exchange.getRequestBody());
}
/**
* Deserialize a RemoteInvocation object from the given InputStream.
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
* first (for example, for custom encryption or compression). Creates a
* {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
* and calls {@link #doReadRemoteInvocation} to actually read the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param exchange current HTTP request/response
* @param is the InputStream to read from
* @return the RemoteInvocation object
* @throws java.io.IOException in case of I/O failure
* @throws ClassNotFoundException if thrown during deserialization
*/
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange, InputStream is)
throws IOException, ClassNotFoundException {
ObjectInputStream ois = createObjectInputStream(decorateInputStream(exchange, is));
return doReadRemoteInvocation(ois);
}
/**
* Return the InputStream to use for reading remote invocations,
* potentially decorating the given original InputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param exchange current HTTP request/response
* @param is the original InputStream
* @return the potentially decorated InputStream
* @throws java.io.IOException in case of I/O failure
*/
protected InputStream decorateInputStream(HttpExchange exchange, InputStream is) throws IOException {
return is;
}
/**
* Write the given RemoteInvocationResult to the given HTTP response.
* @param exchange current HTTP request/response
* @param result the RemoteInvocationResult object
* @throws java.io.IOException in case of I/O failure
*/
protected void writeRemoteInvocationResult(HttpExchange exchange, RemoteInvocationResult result)
throws IOException {
exchange.getResponseHeaders().set("Content-Type", getContentType());
exchange.sendResponseHeaders(200, 0);
writeRemoteInvocationResult(exchange, result, exchange.getResponseBody());
}
/**
* Serialize the given RemoteInvocation to the given OutputStream.
* <p>The default implementation gives {@link #decorateOutputStream} a chance
* to decorate the stream first (for example, for custom encryption or compression).
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
* {@link #doWriteRemoteInvocationResult} to actually write the object.
* <p>Can be overridden for custom serialization of the invocation.
* @param exchange current HTTP request/response
* @param result the RemoteInvocationResult object
* @param os the OutputStream to write to
* @throws java.io.IOException in case of I/O failure
* @see #decorateOutputStream
* @see #doWriteRemoteInvocationResult
*/
protected void writeRemoteInvocationResult(
HttpExchange exchange, RemoteInvocationResult result, OutputStream os) throws IOException {
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(exchange, os));
doWriteRemoteInvocationResult(result, oos);
oos.flush();
}
/**
* Return the OutputStream to use for writing remote invocation results,
* potentially decorating the given original OutputStream.
* <p>The default implementation returns the given stream as-is.
* Can be overridden, for example, for custom encryption or compression.
* @param exchange current HTTP request/response
* @param os the original OutputStream
* @return the potentially decorated OutputStream
* @throws java.io.IOException in case of I/O failure
*/
protected OutputStream decorateOutputStream(HttpExchange exchange, OutputStream os) throws IOException {
return os;
}
}

View File

@@ -1,16 +0,0 @@
/**
* Remoting classes for transparent Java-to-Java remoting via HTTP invokers.
* Uses Java serialization just like RMI, but provides the same ease of setup
* as Caucho's HTTP-based Hessian protocol.
*
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
* It is more powerful and more extensible than Hessian, at the expense of
* being tied to Java. Nevertheless, it is as easy to set up as Hessian,
* which is its main advantage compared to RMI.
*/
@NonNullApi
@NonNullFields
package org.springframework.remoting.httpinvoker;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;

View File

@@ -1,214 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.WebServiceProvider;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Abstract exporter for JAX-WS services, autodetecting annotated service beans
* (through the JAX-WS {@link javax.jws.WebService} annotation).
*
* <p>Subclasses need to implement the {@link #publishEndpoint} template methods
* for actual endpoint exposure.
*
* @author Juergen Hoeller
* @since 2.5.5
* @see javax.jws.WebService
* @see javax.xml.ws.Endpoint
* @see SimpleJaxWsServiceExporter
*/
public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean {
@Nullable
private Map<String, Object> endpointProperties;
@Nullable
private Executor executor;
@Nullable
private String bindingType;
@Nullable
private WebServiceFeature[] endpointFeatures;
@Nullable
private ListableBeanFactory beanFactory;
private final Set<Endpoint> publishedEndpoints = new LinkedHashSet<>();
/**
* Set the property bag for the endpoint, including properties such as
* "javax.xml.ws.wsdl.service" or "javax.xml.ws.wsdl.port".
* @see javax.xml.ws.Endpoint#setProperties
* @see javax.xml.ws.Endpoint#WSDL_SERVICE
* @see javax.xml.ws.Endpoint#WSDL_PORT
*/
public void setEndpointProperties(Map<String, Object> endpointProperties) {
this.endpointProperties = endpointProperties;
}
/**
* Set the JDK concurrent executor to use for dispatching incoming requests
* to exported service instances.
* @see javax.xml.ws.Endpoint#setExecutor
*/
public void setExecutor(Executor executor) {
this.executor = executor;
}
/**
* Specify the binding type to use, overriding the value of
* the JAX-WS {@link javax.xml.ws.BindingType} annotation.
*/
public void setBindingType(String bindingType) {
this.bindingType = bindingType;
}
/**
* Specify WebServiceFeature objects (e.g. as inner bean definitions)
* to apply to JAX-WS endpoint creation.
* @since 4.0
*/
public void setEndpointFeatures(WebServiceFeature... endpointFeatures) {
this.endpointFeatures = endpointFeatures;
}
/**
* Obtains all web service beans and publishes them as JAX-WS endpoints.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ListableBeanFactory)) {
throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
}
this.beanFactory = (ListableBeanFactory) beanFactory;
}
/**
* Immediately publish all endpoints when fully configured.
* @see #publishEndpoints()
*/
@Override
public void afterPropertiesSet() throws Exception {
publishEndpoints();
}
/**
* Publish all {@link javax.jws.WebService} annotated beans in the
* containing BeanFactory.
* @see #publishEndpoint
*/
public void publishEndpoints() {
Assert.state(this.beanFactory != null, "No BeanFactory set");
Set<String> beanNames = new LinkedHashSet<>(this.beanFactory.getBeanDefinitionCount());
Collections.addAll(beanNames, this.beanFactory.getBeanDefinitionNames());
if (this.beanFactory instanceof ConfigurableBeanFactory) {
Collections.addAll(beanNames, ((ConfigurableBeanFactory) this.beanFactory).getSingletonNames());
}
for (String beanName : beanNames) {
try {
Class<?> type = this.beanFactory.getType(beanName);
if (type != null && !type.isInterface()) {
WebService wsAnnotation = type.getAnnotation(WebService.class);
WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
if (wsAnnotation != null || wsProviderAnnotation != null) {
Endpoint endpoint = createEndpoint(this.beanFactory.getBean(beanName));
if (this.endpointProperties != null) {
endpoint.setProperties(this.endpointProperties);
}
if (this.executor != null) {
endpoint.setExecutor(this.executor);
}
if (wsAnnotation != null) {
publishEndpoint(endpoint, wsAnnotation);
}
else {
publishEndpoint(endpoint, wsProviderAnnotation);
}
this.publishedEndpoints.add(endpoint);
}
}
}
catch (CannotLoadBeanClassException ex) {
// ignore beans where the class is not resolvable
}
}
}
/**
* Create the actual Endpoint instance.
* @param bean the service object to wrap
* @return the Endpoint instance
* @see Endpoint#create(Object)
* @see Endpoint#create(String, Object)
*/
protected Endpoint createEndpoint(Object bean) {
return (this.endpointFeatures != null ?
Endpoint.create(this.bindingType, bean, this.endpointFeatures) :
Endpoint.create(this.bindingType, bean));
}
/**
* Actually publish the given endpoint. To be implemented by subclasses.
* @param endpoint the JAX-WS Endpoint object
* @param annotation the service bean's WebService annotation
*/
protected abstract void publishEndpoint(Endpoint endpoint, WebService annotation);
/**
* Actually publish the given provider endpoint. To be implemented by subclasses.
* @param endpoint the JAX-WS Provider Endpoint object
* @param annotation the service bean's WebServiceProvider annotation
*/
protected abstract void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation);
/**
* Stops all published endpoints, taking the web services offline.
*/
@Override
public void destroy() {
for (Endpoint endpoint : this.publishedEndpoints) {
endpoint.stop();
}
}
}

View File

@@ -1,561 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.jws.WebService;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.ProtocolException;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.soap.SOAPFaultException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.RemoteConnectFailureException;
import org.springframework.remoting.RemoteLookupFailureException;
import org.springframework.remoting.RemoteProxyFailureException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a
* specific port of a JAX-WS service.
*
* <p>Uses either {@link LocalJaxWsServiceFactory}'s facilities underneath,
* or takes an explicit reference to an existing JAX-WS Service instance
* (e.g. obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}).
*
* @author Juergen Hoeller
* @since 2.5
* @see #setPortName
* @see #setServiceInterface
* @see javax.xml.ws.Service#getPort
* @see org.springframework.remoting.RemoteAccessException
* @see org.springframework.jndi.JndiObjectFactoryBean
*/
public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
implements MethodInterceptor, BeanClassLoaderAware, InitializingBean {
@Nullable
private Service jaxWsService;
@Nullable
private String portName;
@Nullable
private String username;
@Nullable
private String password;
@Nullable
private String endpointAddress;
private boolean maintainSession;
private boolean useSoapAction;
@Nullable
private String soapActionUri;
@Nullable
private Map<String, Object> customProperties;
@Nullable
private WebServiceFeature[] portFeatures;
@Nullable
private Class<?> serviceInterface;
private boolean lookupServiceOnStartup = true;
@Nullable
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@Nullable
private QName portQName;
@Nullable
private Object portStub;
private final Object preparationMonitor = new Object();
/**
* Set a reference to an existing JAX-WS Service instance,
* for example obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}.
* If not set, {@link LocalJaxWsServiceFactory}'s properties have to be specified.
* @see #setWsdlDocumentUrl
* @see #setNamespaceUri
* @see #setServiceName
* @see org.springframework.jndi.JndiObjectFactoryBean
*/
public void setJaxWsService(@Nullable Service jaxWsService) {
this.jaxWsService = jaxWsService;
}
/**
* Return a reference to an existing JAX-WS Service instance, if any.
*/
@Nullable
public Service getJaxWsService() {
return this.jaxWsService;
}
/**
* Set the name of the port.
* Corresponds to the "wsdl:port" name.
*/
public void setPortName(@Nullable String portName) {
this.portName = portName;
}
/**
* Return the name of the port.
*/
@Nullable
public String getPortName() {
return this.portName;
}
/**
* Set the username to specify on the stub.
* @see javax.xml.ws.BindingProvider#USERNAME_PROPERTY
*/
public void setUsername(@Nullable String username) {
this.username = username;
}
/**
* Return the username to specify on the stub.
*/
@Nullable
public String getUsername() {
return this.username;
}
/**
* Set the password to specify on the stub.
* @see javax.xml.ws.BindingProvider#PASSWORD_PROPERTY
*/
public void setPassword(@Nullable String password) {
this.password = password;
}
/**
* Return the password to specify on the stub.
*/
@Nullable
public String getPassword() {
return this.password;
}
/**
* Set the endpoint address to specify on the stub.
* @see javax.xml.ws.BindingProvider#ENDPOINT_ADDRESS_PROPERTY
*/
public void setEndpointAddress(@Nullable String endpointAddress) {
this.endpointAddress = endpointAddress;
}
/**
* Return the endpoint address to specify on the stub.
*/
@Nullable
public String getEndpointAddress() {
return this.endpointAddress;
}
/**
* Set the "session.maintain" flag to specify on the stub.
* @see javax.xml.ws.BindingProvider#SESSION_MAINTAIN_PROPERTY
*/
public void setMaintainSession(boolean maintainSession) {
this.maintainSession = maintainSession;
}
/**
* Return the "session.maintain" flag to specify on the stub.
*/
public boolean isMaintainSession() {
return this.maintainSession;
}
/**
* Set the "soapaction.use" flag to specify on the stub.
* @see javax.xml.ws.BindingProvider#SOAPACTION_USE_PROPERTY
*/
public void setUseSoapAction(boolean useSoapAction) {
this.useSoapAction = useSoapAction;
}
/**
* Return the "soapaction.use" flag to specify on the stub.
*/
public boolean isUseSoapAction() {
return this.useSoapAction;
}
/**
* Set the SOAP action URI to specify on the stub.
* @see javax.xml.ws.BindingProvider#SOAPACTION_URI_PROPERTY
*/
public void setSoapActionUri(@Nullable String soapActionUri) {
this.soapActionUri = soapActionUri;
}
/**
* Return the SOAP action URI to specify on the stub.
*/
@Nullable
public String getSoapActionUri() {
return this.soapActionUri;
}
/**
* Set custom properties to be set on the stub.
* <p>Can be populated with a String "value" (parsed via PropertiesEditor)
* or a "props" element in XML bean definitions.
* @see javax.xml.ws.BindingProvider#getRequestContext()
*/
public void setCustomProperties(Map<String, Object> customProperties) {
this.customProperties = customProperties;
}
/**
* Allow Map access to the custom properties to be set on the stub,
* with the option to add or override specific entries.
* <p>Useful for specifying entries directly, for example via
* "customProperties[myKey]". This is particularly useful for
* adding or overriding entries in child bean definitions.
*/
public Map<String, Object> getCustomProperties() {
if (this.customProperties == null) {
this.customProperties = new HashMap<>();
}
return this.customProperties;
}
/**
* Add a custom property to this JAX-WS BindingProvider.
* @param name the name of the attribute to expose
* @param value the attribute value to expose
* @see javax.xml.ws.BindingProvider#getRequestContext()
*/
public void addCustomProperty(String name, Object value) {
getCustomProperties().put(name, value);
}
/**
* Specify WebServiceFeature objects (e.g. as inner bean definitions)
* to apply to JAX-WS port stub creation.
* @since 4.0
* @see Service#getPort(Class, javax.xml.ws.WebServiceFeature...)
* @see #setServiceFeatures
*/
public void setPortFeatures(WebServiceFeature... features) {
this.portFeatures = features;
}
/**
* Set the interface of the service that this factory should create a proxy for.
*/
public void setServiceInterface(@Nullable Class<?> serviceInterface) {
if (serviceInterface != null) {
Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface");
}
this.serviceInterface = serviceInterface;
}
/**
* Return the interface of the service that this factory should create a proxy for.
*/
@Nullable
public Class<?> getServiceInterface() {
return this.serviceInterface;
}
/**
* Set whether to look up the JAX-WS service on startup.
* <p>Default is "true". Turn this flag off to allow for late start
* of the target server. In this case, the JAX-WS service will be
* lazily fetched on first access.
*/
public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) {
this.lookupServiceOnStartup = lookupServiceOnStartup;
}
/**
* Set the bean ClassLoader to use for this interceptor: primarily for
* building a client proxy in the {@link JaxWsPortProxyFactoryBean} subclass.
*/
@Override
public void setBeanClassLoader(@Nullable ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
/**
* Return the bean ClassLoader to use for this interceptor.
*/
@Nullable
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
@Override
public void afterPropertiesSet() {
if (this.lookupServiceOnStartup) {
prepare();
}
}
/**
* Initialize the JAX-WS port for this interceptor.
*/
public void prepare() {
Class<?> ifc = getServiceInterface();
Assert.notNull(ifc, "Property 'serviceInterface' is required");
WebService ann = ifc.getAnnotation(WebService.class);
if (ann != null) {
applyDefaultsFromAnnotation(ann);
}
Service serviceToUse = getJaxWsService();
if (serviceToUse == null) {
serviceToUse = createJaxWsService();
}
this.portQName = getQName(getPortName() != null ? getPortName() : ifc.getName());
Object stub = getPortStub(serviceToUse, (getPortName() != null ? this.portQName : null));
preparePortStub(stub);
this.portStub = stub;
}
/**
* Initialize this client interceptor's properties from the given WebService annotation,
* if necessary and possible (i.e. if "wsdlDocumentUrl", "namespaceUri", "serviceName"
* and "portName" haven't been set but corresponding values are declared at the
* annotation level of the specified service interface).
* @param ann the WebService annotation found on the specified service interface
*/
protected void applyDefaultsFromAnnotation(WebService ann) {
if (getWsdlDocumentUrl() == null) {
String wsdl = ann.wsdlLocation();
if (StringUtils.hasText(wsdl)) {
try {
setWsdlDocumentUrl(new URL(wsdl));
}
catch (MalformedURLException ex) {
throw new IllegalStateException(
"Encountered invalid @Service wsdlLocation value [" + wsdl + "]", ex);
}
}
}
if (getNamespaceUri() == null) {
String ns = ann.targetNamespace();
if (StringUtils.hasText(ns)) {
setNamespaceUri(ns);
}
}
if (getServiceName() == null) {
String sn = ann.serviceName();
if (StringUtils.hasText(sn)) {
setServiceName(sn);
}
}
if (getPortName() == null) {
String pn = ann.portName();
if (StringUtils.hasText(pn)) {
setPortName(pn);
}
}
}
/**
* Return whether this client interceptor has already been prepared,
* i.e. has already looked up the JAX-WS service and port.
*/
protected boolean isPrepared() {
synchronized (this.preparationMonitor) {
return (this.portStub != null);
}
}
/**
* Return the prepared QName for the port.
* @see #setPortName
* @see #getQName
*/
@Nullable
protected final QName getPortQName() {
return this.portQName;
}
/**
* Obtain the port stub from the given JAX-WS Service.
* @param service the Service object to obtain the port from
* @param portQName the name of the desired port, if specified
* @return the corresponding port object as returned from
* {@code Service.getPort(...)}
*/
protected Object getPortStub(Service service, @Nullable QName portQName) {
if (this.portFeatures != null) {
return (portQName != null ? service.getPort(portQName, getServiceInterface(), this.portFeatures) :
service.getPort(getServiceInterface(), this.portFeatures));
}
else {
return (portQName != null ? service.getPort(portQName, getServiceInterface()) :
service.getPort(getServiceInterface()));
}
}
/**
* Prepare the given JAX-WS port stub, applying properties to it.
* Called by {@link #prepare}.
* @param stub the current JAX-WS port stub
* @see #setUsername
* @see #setPassword
* @see #setEndpointAddress
* @see #setMaintainSession
* @see #setCustomProperties
*/
protected void preparePortStub(Object stub) {
Map<String, Object> stubProperties = new HashMap<>();
String username = getUsername();
if (username != null) {
stubProperties.put(BindingProvider.USERNAME_PROPERTY, username);
}
String password = getPassword();
if (password != null) {
stubProperties.put(BindingProvider.PASSWORD_PROPERTY, password);
}
String endpointAddress = getEndpointAddress();
if (endpointAddress != null) {
stubProperties.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress);
}
if (isMaintainSession()) {
stubProperties.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
}
if (isUseSoapAction()) {
stubProperties.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
}
String soapActionUri = getSoapActionUri();
if (soapActionUri != null) {
stubProperties.put(BindingProvider.SOAPACTION_URI_PROPERTY, soapActionUri);
}
stubProperties.putAll(getCustomProperties());
if (!stubProperties.isEmpty()) {
if (!(stub instanceof BindingProvider)) {
throw new RemoteLookupFailureException("Port stub of class [" + stub.getClass().getName() +
"] is not a customizable JAX-WS stub: it does not implement interface [javax.xml.ws.BindingProvider]");
}
((BindingProvider) stub).getRequestContext().putAll(stubProperties);
}
}
/**
* Return the underlying JAX-WS port stub that this interceptor delegates to
* for each method invocation on the proxy.
*/
@Nullable
protected Object getPortStub() {
return this.portStub;
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
if (AopUtils.isToStringMethod(invocation.getMethod())) {
return "JAX-WS proxy for port [" + getPortName() + "] of service [" + getServiceName() + "]";
}
// Lazily prepare service and stub if necessary.
synchronized (this.preparationMonitor) {
if (!isPrepared()) {
prepare();
}
}
return doInvoke(invocation);
}
/**
* Perform a JAX-WS service invocation based on the given method invocation.
* @param invocation the AOP method invocation
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
* @see #getPortStub()
* @see #doInvoke(org.aopalliance.intercept.MethodInvocation, Object)
*/
@Nullable
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
try {
return doInvoke(invocation, getPortStub());
}
catch (SOAPFaultException ex) {
throw new JaxWsSoapFaultException(ex);
}
catch (ProtocolException ex) {
throw new RemoteConnectFailureException(
"Could not connect to remote service [" + getEndpointAddress() + "]", ex);
}
catch (WebServiceException ex) {
throw new RemoteAccessException(
"Could not access remote service at [" + getEndpointAddress() + "]", ex);
}
}
/**
* Perform a JAX-WS service invocation on the given port stub.
* @param invocation the AOP method invocation
* @param portStub the RMI port stub to invoke
* @return the invocation result, if any
* @throws Throwable in case of invocation failure
* @see #getPortStub()
*/
@Nullable
protected Object doInvoke(MethodInvocation invocation, @Nullable Object portStub) throws Throwable {
Method method = invocation.getMethod();
try {
return method.invoke(portStub, invocation.getArguments());
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
catch (Throwable ex) {
throw new RemoteProxyFailureException("Invocation of stub method failed: " + method, ex);
}
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import javax.xml.ws.BindingProvider;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link org.springframework.beans.factory.FactoryBean} for a specific port of a
* JAX-WS service. Exposes a proxy for the port, to be used for bean references.
* Inherits configuration properties from {@link JaxWsPortClientInterceptor}.
*
* @author Juergen Hoeller
* @since 2.5
* @see #setServiceInterface
* @see LocalJaxWsServiceFactoryBean
*/
public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor implements FactoryBean<Object> {
@Nullable
private Object serviceProxy;
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Class<?> ifc = getServiceInterface();
Assert.notNull(ifc, "Property 'serviceInterface' is required");
// Build a proxy that also exposes the JAX-WS BindingProvider interface.
ProxyFactory pf = new ProxyFactory();
pf.addInterface(ifc);
pf.addInterface(BindingProvider.class);
pf.addAdvice(this);
this.serviceProxy = pf.getProxy(getBeanClassLoader());
}
@Override
@Nullable
public Object getObject() {
return this.serviceProxy;
}
@Override
public Class<?> getObjectType() {
return getServiceInterface();
}
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPFault;
import javax.xml.ws.soap.SOAPFaultException;
import org.springframework.remoting.soap.SoapFaultException;
/**
* Spring SoapFaultException adapter for the JAX-WS
* {@link javax.xml.ws.soap.SOAPFaultException} class.
*
* @author Juergen Hoeller
* @since 2.5
*/
@SuppressWarnings("serial")
public class JaxWsSoapFaultException extends SoapFaultException {
/**
* Constructor for JaxWsSoapFaultException.
* @param original the original JAX-WS SOAPFaultException to wrap
*/
public JaxWsSoapFaultException(SOAPFaultException original) {
super(original.getMessage(), original);
}
/**
* Return the wrapped JAX-WS SOAPFault.
*/
public final SOAPFault getFault() {
return ((SOAPFaultException) getCause()).getFault();
}
@Override
public String getFaultCode() {
return getFault().getFaultCode();
}
@Override
public QName getFaultCodeAsQName() {
return getFault().getFaultCodeAsQName();
}
@Override
public String getFaultString() {
return getFault().getFaultString();
}
@Override
public String getFaultActor() {
return getFault().getFaultActor();
}
}

View File

@@ -1,192 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.Executor;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.handler.HandlerResolver;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Factory for locally defined JAX-WS {@link javax.xml.ws.Service} references.
* Uses the JAX-WS {@link javax.xml.ws.Service#create} factory API underneath.
*
* <p>Serves as base class for {@link LocalJaxWsServiceFactoryBean} as well as
* {@link JaxWsPortClientInterceptor} and {@link JaxWsPortProxyFactoryBean}.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.xml.ws.Service
* @see LocalJaxWsServiceFactoryBean
* @see JaxWsPortClientInterceptor
* @see JaxWsPortProxyFactoryBean
*/
public class LocalJaxWsServiceFactory {
@Nullable
private URL wsdlDocumentUrl;
@Nullable
private String namespaceUri;
@Nullable
private String serviceName;
@Nullable
private WebServiceFeature[] serviceFeatures;
@Nullable
private Executor executor;
@Nullable
private HandlerResolver handlerResolver;
/**
* Set the URL of the WSDL document that describes the service.
* @see #setWsdlDocumentResource(Resource)
*/
public void setWsdlDocumentUrl(@Nullable URL wsdlDocumentUrl) {
this.wsdlDocumentUrl = wsdlDocumentUrl;
}
/**
* Set the WSDL document URL as a {@link Resource}.
* @since 3.2
*/
public void setWsdlDocumentResource(Resource wsdlDocumentResource) throws IOException {
Assert.notNull(wsdlDocumentResource, "WSDL Resource must not be null");
this.wsdlDocumentUrl = wsdlDocumentResource.getURL();
}
/**
* Return the URL of the WSDL document that describes the service.
*/
@Nullable
public URL getWsdlDocumentUrl() {
return this.wsdlDocumentUrl;
}
/**
* Set the namespace URI of the service.
* Corresponds to the WSDL "targetNamespace".
*/
public void setNamespaceUri(@Nullable String namespaceUri) {
this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null);
}
/**
* Return the namespace URI of the service.
*/
@Nullable
public String getNamespaceUri() {
return this.namespaceUri;
}
/**
* Set the name of the service to look up.
* Corresponds to the "wsdl:service" name.
*/
public void setServiceName(@Nullable String serviceName) {
this.serviceName = serviceName;
}
/**
* Return the name of the service.
*/
@Nullable
public String getServiceName() {
return this.serviceName;
}
/**
* Specify WebServiceFeature objects (e.g. as inner bean definitions)
* to apply to JAX-WS service creation.
* @since 4.0
* @see Service#create(QName, WebServiceFeature...)
*/
public void setServiceFeatures(WebServiceFeature... serviceFeatures) {
this.serviceFeatures = serviceFeatures;
}
/**
* Set the JDK concurrent executor to use for asynchronous executions
* that require callbacks.
* @see javax.xml.ws.Service#setExecutor
*/
public void setExecutor(Executor executor) {
this.executor = executor;
}
/**
* Set the JAX-WS HandlerResolver to use for all proxies and dispatchers
* created through this factory.
* @see javax.xml.ws.Service#setHandlerResolver
*/
public void setHandlerResolver(HandlerResolver handlerResolver) {
this.handlerResolver = handlerResolver;
}
/**
* Create a JAX-WS Service according to the parameters of this factory.
* @see #setServiceName
* @see #setWsdlDocumentUrl
*/
public Service createJaxWsService() {
Assert.notNull(this.serviceName, "No service name specified");
Service service;
if (this.serviceFeatures != null) {
service = (this.wsdlDocumentUrl != null ?
Service.create(this.wsdlDocumentUrl, getQName(this.serviceName), this.serviceFeatures) :
Service.create(getQName(this.serviceName), this.serviceFeatures));
}
else {
service = (this.wsdlDocumentUrl != null ?
Service.create(this.wsdlDocumentUrl, getQName(this.serviceName)) :
Service.create(getQName(this.serviceName)));
}
if (this.executor != null) {
service.setExecutor(this.executor);
}
if (this.handlerResolver != null) {
service.setHandlerResolver(this.handlerResolver);
}
return service;
}
/**
* Return a QName for the given name, relative to the namespace URI
* of this factory, if given.
* @see #setNamespaceUri
*/
protected QName getQName(String name) {
return (getNamespaceUri() != null ? new QName(getNamespaceUri(), name) : new QName(name));
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import javax.xml.ws.Service;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.beans.factory.FactoryBean} for locally
* defined JAX-WS Service references.
* Uses {@link LocalJaxWsServiceFactory}'s facilities underneath.
*
* <p>Alternatively, JAX-WS Service references can be looked up
* in the JNDI environment of the Java EE container.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.xml.ws.Service
* @see org.springframework.jndi.JndiObjectFactoryBean
* @see JaxWsPortProxyFactoryBean
*/
public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory
implements FactoryBean<Service>, InitializingBean {
@Nullable
private Service service;
@Override
public void afterPropertiesSet() {
this.service = createJaxWsService();
}
@Override
@Nullable
public Service getObject() {
return this.service;
}
@Override
public Class<? extends Service> getObjectType() {
return (this.service != null ? this.service.getClass() : Service.class);
}
@Override
public boolean isSingleton() {
return true;
}
}

View File

@@ -1,228 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import java.net.InetSocketAddress;
import java.util.List;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import javax.xml.ws.WebServiceProvider;
import com.sun.net.httpserver.Authenticator;
import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpServer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple exporter for JAX-WS services, autodetecting annotated service beans
* (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting
* them through the HTTP server included in Sun's JDK 1.6. The full address
* for each service will consist of the server's base address with the
* service name appended (e.g. "http://localhost:8080/OrderService").
*
* <p>Note that this exporter will only work on Sun's JDK 1.6 or higher, as well
* as on JDKs that ship Sun's entire class library as included in the Sun JDK.
* For a portable JAX-WS exporter, have a look at {@link SimpleJaxWsServiceExporter}.
*
* @author Juergen Hoeller
* @since 2.5.5
* @see javax.jws.WebService
* @see javax.xml.ws.Endpoint#publish(Object)
* @see SimpleJaxWsServiceExporter
* @deprecated as of Spring Framework 5.1, in favor of {@link SimpleJaxWsServiceExporter}
*/
@Deprecated
@org.springframework.lang.UsesSunHttpServer
public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceExporter {
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private HttpServer server;
private int port = 8080;
@Nullable
private String hostname;
private int backlog = -1;
private int shutdownDelay = 0;
private String basePath = "/";
@Nullable
private List<Filter> filters;
@Nullable
private Authenticator authenticator;
private boolean localServer = false;
/**
* Specify an existing HTTP server to register the web service contexts
* with. This will typically be a server managed by the general Spring
* {@link org.springframework.remoting.support.SimpleHttpServerFactoryBean}.
* <p>Alternatively, configure a local HTTP server through the
* {@link #setPort "port"}, {@link #setHostname "hostname"} and
* {@link #setBacklog "backlog"} properties (or rely on the defaults there).
*/
public void setServer(HttpServer server) {
this.server = server;
}
/**
* Specify the HTTP server's port. Default is 8080.
* <p>Only applicable for a locally configured HTTP server.
* Ignored when the {@link #setServer "server"} property has been specified.
*/
public void setPort(int port) {
this.port = port;
}
/**
* Specify the HTTP server's hostname to bind to. Default is localhost;
* can be overridden with a specific network address to bind to.
* <p>Only applicable for a locally configured HTTP server.
* Ignored when the {@link #setServer "server"} property has been specified.
*/
public void setHostname(String hostname) {
this.hostname = hostname;
}
/**
* Specify the HTTP server's TCP backlog. Default is -1,
* indicating the system's default value.
* <p>Only applicable for a locally configured HTTP server.
* Ignored when the {@link #setServer "server"} property has been specified.
*/
public void setBacklog(int backlog) {
this.backlog = backlog;
}
/**
* Specify the number of seconds to wait until HTTP exchanges have
* completed when shutting down the HTTP server. Default is 0.
* <p>Only applicable for a locally configured HTTP server.
* Ignored when the {@link #setServer "server"} property has been specified.
*/
public void setShutdownDelay(int shutdownDelay) {
this.shutdownDelay = shutdownDelay;
}
/**
* Set the base path for context publication. Default is "/".
* <p>For each context publication path, the service name will be
* appended to this base address. E.g. service name "OrderService"
* -> "/OrderService".
* @see javax.xml.ws.Endpoint#publish(Object)
* @see javax.jws.WebService#serviceName()
*/
public void setBasePath(String basePath) {
this.basePath = basePath;
}
/**
* Register common {@link com.sun.net.httpserver.Filter Filters} to be
* applied to all detected {@link javax.jws.WebService} annotated beans.
*/
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
/**
* Register a common {@link com.sun.net.httpserver.Authenticator} to be
* applied to all detected {@link javax.jws.WebService} annotated beans.
*/
public void setAuthenticator(Authenticator authenticator) {
this.authenticator = authenticator;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.server == null) {
InetSocketAddress address = (this.hostname != null ?
new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port));
HttpServer server = HttpServer.create(address, this.backlog);
if (logger.isInfoEnabled()) {
logger.info("Starting HttpServer at address " + address);
}
server.start();
this.server = server;
this.localServer = true;
}
super.afterPropertiesSet();
}
@Override
protected void publishEndpoint(Endpoint endpoint, WebService annotation) {
endpoint.publish(buildHttpContext(endpoint, annotation.serviceName()));
}
@Override
protected void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation) {
endpoint.publish(buildHttpContext(endpoint, annotation.serviceName()));
}
/**
* Build the HttpContext for the given endpoint.
* @param endpoint the JAX-WS Provider Endpoint object
* @param serviceName the given service name
* @return the fully populated HttpContext
*/
protected HttpContext buildHttpContext(Endpoint endpoint, String serviceName) {
Assert.state(this.server != null, "No HttpServer available");
String fullPath = calculateEndpointPath(endpoint, serviceName);
HttpContext httpContext = this.server.createContext(fullPath);
if (this.filters != null) {
httpContext.getFilters().addAll(this.filters);
}
if (this.authenticator != null) {
httpContext.setAuthenticator(this.authenticator);
}
return httpContext;
}
/**
* Calculate the full endpoint path for the given endpoint.
* @param endpoint the JAX-WS Provider Endpoint object
* @param serviceName the given service name
* @return the full endpoint path
*/
protected String calculateEndpointPath(Endpoint endpoint, String serviceName) {
return this.basePath + serviceName;
}
@Override
public void destroy() {
super.destroy();
if (this.server != null && this.localServer) {
logger.info("Stopping HttpServer");
this.server.stop(this.shutdownDelay);
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.remoting.jaxws;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
import javax.xml.ws.WebServiceProvider;
/**
* Simple exporter for JAX-WS services, autodetecting annotated service beans
* (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting
* them with a configured base address (by default "http://localhost:8080/")
* using the JAX-WS provider's built-in publication support. The full address
* for each service will consist of the base address with the service name
* appended (e.g. "http://localhost:8080/OrderService").
*
* <p>Note that this exporter will only work if the JAX-WS runtime actually
* supports publishing with an address argument, i.e. if the JAX-WS runtime
* ships an internal HTTP server.
*
* @author Juergen Hoeller
* @since 2.5
* @see javax.jws.WebService
* @see javax.xml.ws.Endpoint#publish(String)
*/
public class SimpleJaxWsServiceExporter extends AbstractJaxWsServiceExporter {
/**
* The default base address.
*/
public static final String DEFAULT_BASE_ADDRESS = "http://localhost:8080/";
private String baseAddress = DEFAULT_BASE_ADDRESS;
/**
* Set the base address for exported services.
* Default is "http://localhost:8080/".
* <p>For each actual publication address, the service name will be
* appended to this base address. E.g. service name "OrderService"
* -> "http://localhost:8080/OrderService".
* @see javax.xml.ws.Endpoint#publish(String)
* @see javax.jws.WebService#serviceName()
*/
public void setBaseAddress(String baseAddress) {
this.baseAddress = baseAddress;
}
@Override
protected void publishEndpoint(Endpoint endpoint, WebService annotation) {
endpoint.publish(calculateEndpointAddress(endpoint, annotation.serviceName()));
}
@Override
protected void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation) {
endpoint.publish(calculateEndpointAddress(endpoint, annotation.serviceName()));
}
/**
* Calculate the full endpoint address for the given endpoint.
* @param endpoint the JAX-WS Provider Endpoint object
* @param serviceName the given service name
* @return the full endpoint address
*/
protected String calculateEndpointAddress(Endpoint endpoint, String serviceName) {
String fullAddress = this.baseAddress + serviceName;
if (endpoint.getClass().getName().startsWith("weblogic.")) {
// Workaround for WebLogic 10.3
fullAddress = fullAddress + "/";
}
return fullAddress;
}
}

View File

@@ -1,11 +0,0 @@
/**
* Remoting classes for Web Services via JAX-WS (the successor of JAX-RPC),
* as included in Java 6 and Java EE 5. This package provides proxy
* factories for accessing JAX-WS services and ports.
*/
@NonNullApi
@NonNullFields
package org.springframework.remoting.jaxws;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;