diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteAccessException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteAccessException.java deleted file mode 100644 index 0d6cde82e5..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteAccessException.java +++ /dev/null @@ -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; - -import org.springframework.core.NestedRuntimeException; - -/** - * Generic remote access exception. A service proxy for any remoting - * protocol should throw this exception or subclasses of it, in order - * to transparently expose a plain Java business interface. - * - *

When using conforming proxies, switching the actual remoting protocol - * e.g. from Hessian does not affect client code. Clients work with a plain - * natural Java business interface that the service exposes. A client object - * simply receives an implementation for the interface that it needs via a - * bean reference, like it does for a local bean as well. - * - *

A client may catch RemoteAccessException if it wants to, but as - * remote access errors are typically unrecoverable, it will probably let - * such exceptions propagate to a higher level that handles them generically. - * In this case, the client code doesn't show any signs of being involved in - * remote access, as there aren't any remoting-specific dependencies. - * - *

Even when switching from a remote service proxy to a local implementation - * of the same interface, this amounts to just a matter of configuration. Obviously, - * the client code should be somewhat aware that it might be working - * against a remote service, for example in terms of repeated method calls that - * cause unnecessary roundtrips etc. However, it doesn't have to be aware whether - * it is actually working against a remote service or a local implementation, - * or with which remoting protocol it is working under the hood. - * - * @author Juergen Hoeller - * @since 14.05.2003 - */ -public class RemoteAccessException extends NestedRuntimeException { - - /** Use serialVersionUID from Spring 1.2 for interoperability. */ - private static final long serialVersionUID = -4906825139312227864L; - - - /** - * Constructor for RemoteAccessException. - * @param msg the detail message - */ - public RemoteAccessException(String msg) { - super(msg); - } - - /** - * Constructor for RemoteAccessException. - * @param msg the detail message - * @param cause the root cause (usually from using an underlying - * remoting API such as RMI) - */ - public RemoteAccessException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteConnectFailureException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteConnectFailureException.java deleted file mode 100644 index 99857c3694..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteConnectFailureException.java +++ /dev/null @@ -1,38 +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; - -/** - * RemoteAccessException subclass to be thrown when no connection - * could be established with a remote service. - * - * @author Juergen Hoeller - * @since 1.1 - */ -@SuppressWarnings("serial") -public class RemoteConnectFailureException extends RemoteAccessException { - - /** - * Constructor for RemoteConnectFailureException. - * @param msg the detail message - * @param cause the root cause from the remoting API in use - */ - public RemoteConnectFailureException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteInvocationFailureException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteInvocationFailureException.java deleted file mode 100644 index 40e9521399..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteInvocationFailureException.java +++ /dev/null @@ -1,40 +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; - -/** - * RemoteAccessException subclass to be thrown when the execution - * of the target method failed on the server side, for example - * when a method was not found on the target object. - * - * @author Juergen Hoeller - * @since 2.5 - * @see RemoteProxyFailureException - */ -@SuppressWarnings("serial") -public class RemoteInvocationFailureException extends RemoteAccessException { - - /** - * Constructor for RemoteInvocationFailureException. - * @param msg the detail message - * @param cause the root cause from the remoting API in use - */ - public RemoteInvocationFailureException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteLookupFailureException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteLookupFailureException.java deleted file mode 100644 index ee0e9fa042..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteLookupFailureException.java +++ /dev/null @@ -1,46 +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; - -/** - * RemoteAccessException subclass to be thrown in case of a lookup failure, - * typically if the lookup happens on demand for each method invocation. - * - * @author Juergen Hoeller - * @since 1.1 - */ -@SuppressWarnings("serial") -public class RemoteLookupFailureException extends RemoteAccessException { - - /** - * Constructor for RemoteLookupFailureException. - * @param msg the detail message - */ - public RemoteLookupFailureException(String msg) { - super(msg); - } - - /** - * Constructor for RemoteLookupFailureException. - * @param msg message - * @param cause the root cause from the remoting API in use - */ - public RemoteLookupFailureException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteProxyFailureException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteProxyFailureException.java deleted file mode 100644 index ce36152f4c..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteProxyFailureException.java +++ /dev/null @@ -1,40 +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; - -/** - * RemoteAccessException subclass to be thrown in case of a failure - * within the client-side proxy for a remote service, for example - * when a method was not found on the underlying RMI stub. - * - * @author Juergen Hoeller - * @since 1.2.8 - * @see RemoteInvocationFailureException - */ -@SuppressWarnings("serial") -public class RemoteProxyFailureException extends RemoteAccessException { - - /** - * Constructor for RemoteProxyFailureException. - * @param msg the detail message - * @param cause the root cause from the remoting API in use - */ - public RemoteProxyFailureException(String msg, Throwable cause) { - super(msg, cause); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/RemoteTimeoutException.java b/spring-context/src/main/java/org/springframework/remoting/RemoteTimeoutException.java deleted file mode 100644 index 8dbff587c6..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/RemoteTimeoutException.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2015 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; - -/** - * RemoteAccessException subclass to be thrown when the execution - * of the target method did not complete before a configurable - * timeout, for example when a reply message was not received. - * @author Stephane Nicoll - * @since 4.2 - */ -@SuppressWarnings("serial") -public class RemoteTimeoutException extends RemoteAccessException { - - /** - * Constructor for RemoteTimeoutException. - * @param msg the detail message - */ - public RemoteTimeoutException(String msg) { - super(msg); - } - - /** - * Constructor for RemoteTimeoutException. - * @param msg the detail message - * @param cause the root cause from the remoting API in use - */ - public RemoteTimeoutException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/spring-context/src/main/java/org/springframework/remoting/package-info.java b/spring-context/src/main/java/org/springframework/remoting/package-info.java deleted file mode 100644 index a4b3e95f5d..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Exception hierarchy for Spring's remoting infrastructure, - * independent of any specific remote method invocation system. - */ -@NonNullApi -@NonNullFields -package org.springframework.remoting; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java b/spring-context/src/main/java/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java deleted file mode 100644 index 9c897b8a76..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/CodebaseAwareObjectInputStream.java +++ /dev/null @@ -1,122 +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.rmi; - -import java.io.IOException; -import java.io.InputStream; -import java.rmi.server.RMIClassLoader; - -import org.springframework.core.ConfigurableObjectInputStream; -import org.springframework.lang.Nullable; - -/** - * Special ObjectInputStream subclass that falls back to a specified codebase - * to load classes from if not found locally. In contrast to standard RMI - * conventions for dynamic class download, it is the client that determines - * the codebase URL here, rather than the "java.rmi.server.codebase" system - * property on the server. - * - *

Uses the JDK's RMIClassLoader to load classes from the specified codebase. - * The codebase can consist of multiple URLs, separated by spaces. - * Note that RMIClassLoader requires a SecurityManager to be set, like when - * using dynamic class download with standard RMI! (See the RMI documentation - * for details.) - * - *

Despite residing in the RMI package, this class is not used for - * RmiClientInterceptor, which uses the standard RMI infrastructure instead - * and thus is only able to rely on RMI's standard dynamic class download via - * "java.rmi.server.codebase". CodebaseAwareObjectInputStream is used by - * HttpInvokerClientInterceptor (see the "codebaseUrl" property there). - * - *

Thanks to Lionel Mestre for suggesting the option and providing - * a prototype! - * - * @author Juergen Hoeller - * @since 1.1.3 - * @see java.rmi.server.RMIClassLoader - * @see RemoteInvocationSerializingExporter#createObjectInputStream - * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor#setCodebaseUrl - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class CodebaseAwareObjectInputStream extends ConfigurableObjectInputStream { - - private final String codebaseUrl; - - - /** - * Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase. - * @param in the InputStream to read from - * @param codebaseUrl the codebase URL to load classes from if not found locally - * (can consist of multiple URLs, separated by spaces) - * @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream) - */ - public CodebaseAwareObjectInputStream(InputStream in, String codebaseUrl) throws IOException { - this(in, null, codebaseUrl); - } - - /** - * Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase. - * @param in the InputStream to read from - * @param classLoader the ClassLoader to use for loading local classes - * (may be {@code null} to indicate RMI's default ClassLoader) - * @param codebaseUrl the codebase URL to load classes from if not found locally - * (can consist of multiple URLs, separated by spaces) - * @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream) - */ - public CodebaseAwareObjectInputStream( - InputStream in, @Nullable ClassLoader classLoader, String codebaseUrl) throws IOException { - - super(in, classLoader); - this.codebaseUrl = codebaseUrl; - } - - /** - * Create a new CodebaseAwareObjectInputStream for the given InputStream and codebase. - * @param in the InputStream to read from - * @param classLoader the ClassLoader to use for loading local classes - * (may be {@code null} to indicate RMI's default ClassLoader) - * @param acceptProxyClasses whether to accept deserialization of proxy classes - * (may be deactivated as a security measure) - * @see java.io.ObjectInputStream#ObjectInputStream(java.io.InputStream) - */ - public CodebaseAwareObjectInputStream( - InputStream in, @Nullable ClassLoader classLoader, boolean acceptProxyClasses) throws IOException { - - super(in, classLoader, acceptProxyClasses); - this.codebaseUrl = null; - } - - - @Override - protected Class resolveFallbackIfPossible(String className, ClassNotFoundException ex) - throws IOException, ClassNotFoundException { - - // If codebaseUrl is set, try to load the class with the RMIClassLoader. - // Else, propagate the ClassNotFoundException. - if (this.codebaseUrl == null) { - throw ex; - } - return RMIClassLoader.loadClass(this.codebaseUrl, className); - } - - @Override - protected ClassLoader getFallbackClassLoader() throws IOException { - return RMIClassLoader.getClassLoader(this.codebaseUrl); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java b/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java deleted file mode 100644 index d90dd6a1a3..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiClientInterceptor.java +++ /dev/null @@ -1,452 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.rmi.RemoteException; - -import javax.naming.Context; -import javax.naming.NamingException; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.jndi.JndiObjectLocator; -import org.springframework.lang.Nullable; -import org.springframework.remoting.RemoteConnectFailureException; -import org.springframework.remoting.RemoteInvocationFailureException; -import org.springframework.remoting.RemoteLookupFailureException; -import org.springframework.remoting.support.DefaultRemoteInvocationFactory; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationFactory; -import org.springframework.util.Assert; - -/** - * {@link org.aopalliance.intercept.MethodInterceptor} for accessing RMI services - * from JNDI. Typically used for RMI-IIOP but can also be used for EJB home objects - * (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup, - * this accessor also performs narrowing through PortableRemoteObject. - * - *

With conventional RMI services, this invoker is typically used with the RMI - * service interface. Alternatively, this invoker can also proxy a remote RMI service - * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI - * service methods but does not declare RemoteExceptions. In the latter case, - * RemoteExceptions thrown by the RMI stub will automatically get converted to - * Spring's unchecked RemoteAccessException. - * - *

The JNDI environment can be specified as "jndiEnvironment" property, - * or be configured in a {@code jndi.properties} file or as system properties. - * For example: - * - *

<property name="jndiEnvironment">
- * 	 <props>
- *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
- *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
- *	 </props>
- * </property>
- * - * @author Juergen Hoeller - * @since 1.1 - * @see #setJndiTemplate - * @see #setJndiEnvironment - * @see #setJndiName - * @see JndiRmiServiceExporter - * @see JndiRmiProxyFactoryBean - * @see org.springframework.remoting.RemoteAccessException - * @see java.rmi.RemoteException - * @see java.rmi.Remote - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JndiRmiClientInterceptor extends JndiObjectLocator implements MethodInterceptor, InitializingBean { - - private Class serviceInterface; - - private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); - - private boolean lookupStubOnStartup = true; - - private boolean cacheStub = true; - - private boolean refreshStubOnConnectFailure = false; - - private boolean exposeAccessContext = false; - - private Object cachedStub; - - private final Object stubMonitor = new Object(); - - - /** - * Set the interface of the service to access. - * The interface must be suitable for the particular service and remoting tool. - *

Typically required to be able to create a suitable service proxy, - * but can also be optional if the lookup returns a typed stub. - */ - public void setServiceInterface(Class serviceInterface) { - Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); - Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); - this.serviceInterface = serviceInterface; - } - - /** - * Return the interface of the service to access. - */ - public Class getServiceInterface() { - return this.serviceInterface; - } - - /** - * Set the RemoteInvocationFactory to use for this accessor. - * Default is a {@link DefaultRemoteInvocationFactory}. - *

A custom invocation factory can add further context information - * to the invocation, for example user credentials. - */ - public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) { - this.remoteInvocationFactory = remoteInvocationFactory; - } - - /** - * Return the RemoteInvocationFactory used by this accessor. - */ - public RemoteInvocationFactory getRemoteInvocationFactory() { - return this.remoteInvocationFactory; - } - - /** - * Set whether to look up the RMI stub on startup. Default is "true". - *

Can be turned off to allow for late start of the RMI server. - * In this case, the RMI stub will be fetched on first access. - * @see #setCacheStub - */ - public void setLookupStubOnStartup(boolean lookupStubOnStartup) { - this.lookupStubOnStartup = lookupStubOnStartup; - } - - /** - * Set whether to cache the RMI stub once it has been located. - * Default is "true". - *

Can be turned off to allow for hot restart of the RMI server. - * In this case, the RMI stub will be fetched for each invocation. - * @see #setLookupStubOnStartup - */ - public void setCacheStub(boolean cacheStub) { - this.cacheStub = cacheStub; - } - - /** - * Set whether to refresh the RMI stub on connect failure. - * Default is "false". - *

Can be turned on to allow for hot restart of the RMI server. - * If a cached RMI stub throws an RMI exception that indicates a - * remote connect failure, a fresh proxy will be fetched and the - * invocation will be retried. - * @see java.rmi.ConnectException - * @see java.rmi.ConnectIOException - * @see java.rmi.NoSuchObjectException - */ - public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) { - this.refreshStubOnConnectFailure = refreshStubOnConnectFailure; - } - - /** - * Set whether to expose the JNDI environment context for all access to the target - * RMI stub, i.e. for all method invocations on the exposed object reference. - *

Default is "false", i.e. to only expose the JNDI context for object lookup. - * Switch this flag to "true" in order to expose the JNDI environment (including - * the authorization context) for each RMI invocation, as needed by WebLogic - * for RMI stubs with authorization requirements. - */ - public void setExposeAccessContext(boolean exposeAccessContext) { - this.exposeAccessContext = exposeAccessContext; - } - - - @Override - public void afterPropertiesSet() throws NamingException { - super.afterPropertiesSet(); - prepare(); - } - - /** - * Fetches the RMI stub on startup, if necessary. - * @throws RemoteLookupFailureException if RMI stub creation failed - * @see #setLookupStubOnStartup - * @see #lookupStub - */ - public void prepare() throws RemoteLookupFailureException { - // Cache RMI stub on initialization? - if (this.lookupStubOnStartup) { - Object remoteObj = lookupStub(); - if (logger.isDebugEnabled()) { - if (remoteObj instanceof RmiInvocationHandler) { - logger.debug("JNDI RMI object [" + getJndiName() + "] is an RMI invoker"); - } - else if (getServiceInterface() != null) { - boolean isImpl = getServiceInterface().isInstance(remoteObj); - logger.debug("Using service interface [" + getServiceInterface().getName() + - "] for JNDI RMI object [" + getJndiName() + "] - " + - (!isImpl ? "not " : "") + "directly implemented"); - } - } - if (this.cacheStub) { - this.cachedStub = remoteObj; - } - } - } - - /** - * Create the RMI stub, typically by looking it up. - *

Called on interceptor initialization if "cacheStub" is "true"; - * else called for each invocation by {@link #getStub()}. - *

The default implementation retrieves the service from the - * JNDI environment. This can be overridden in subclasses. - * @return the RMI stub to store in this interceptor - * @throws RemoteLookupFailureException if RMI stub creation failed - * @see #setCacheStub - * @see #lookup - */ - protected Object lookupStub() throws RemoteLookupFailureException { - try { - return lookup(); - } - catch (NamingException ex) { - throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); - } - } - - /** - * Return the RMI stub to use. Called for each invocation. - *

The default implementation returns the stub created on initialization, - * if any. Else, it invokes {@link #lookupStub} to get a new stub for - * each invocation. This can be overridden in subclasses, for example in - * order to cache a stub for a given amount of time before recreating it, - * or to test the stub whether it is still alive. - * @return the RMI stub to use for an invocation - * @throws NamingException if stub creation failed - * @throws RemoteLookupFailureException if RMI stub creation failed - */ - protected Object getStub() throws NamingException, RemoteLookupFailureException { - if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) { - return (this.cachedStub != null ? this.cachedStub : lookupStub()); - } - else { - synchronized (this.stubMonitor) { - if (this.cachedStub == null) { - this.cachedStub = lookupStub(); - } - return this.cachedStub; - } - } - } - - - /** - * Fetches an RMI stub and delegates to {@link #doInvoke}. - * If configured to refresh on connect failure, it will call - * {@link #refreshAndRetry} on corresponding RMI exceptions. - * @see #getStub - * @see #doInvoke - * @see #refreshAndRetry - * @see java.rmi.ConnectException - * @see java.rmi.ConnectIOException - * @see java.rmi.NoSuchObjectException - */ - @Override - @Nullable - public Object invoke(MethodInvocation invocation) throws Throwable { - Object stub; - try { - stub = getStub(); - } - catch (NamingException ex) { - throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex); - } - - Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null); - try { - return doInvoke(invocation, stub); - } - catch (RemoteConnectFailureException ex) { - return handleRemoteConnectFailure(invocation, ex); - } - catch (RemoteException ex) { - if (isConnectFailure(ex)) { - return handleRemoteConnectFailure(invocation, ex); - } - else { - throw ex; - } - } - finally { - getJndiTemplate().releaseContext(ctx); - } - } - - /** - * Determine whether the given RMI exception indicates a connect failure. - *

The default implementation delegates to - * {@link RmiClientInterceptorUtils#isConnectFailure}. - * @param ex the RMI exception to check - * @return whether the exception should be treated as connect failure - */ - protected boolean isConnectFailure(RemoteException ex) { - return RmiClientInterceptorUtils.isConnectFailure(ex); - } - - /** - * Refresh the stub and retry the remote invocation if necessary. - *

If not configured to refresh on connect failure, this method - * simply rethrows the original exception. - * @param invocation the invocation that failed - * @param ex the exception raised on remote invocation - * @return the result value of the new invocation, if succeeded - * @throws Throwable an exception raised by the new invocation, if failed too. - */ - private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { - if (this.refreshStubOnConnectFailure) { - if (logger.isDebugEnabled()) { - logger.debug("Could not connect to RMI service [" + getJndiName() + "] - retrying", ex); - } - else if (logger.isInfoEnabled()) { - logger.info("Could not connect to RMI service [" + getJndiName() + "] - retrying"); - } - return refreshAndRetry(invocation); - } - else { - throw ex; - } - } - - /** - * Refresh the RMI stub and retry the given invocation. - * Called by invoke on connect failure. - * @param invocation the AOP method invocation - * @return the invocation result, if any - * @throws Throwable in case of invocation failure - * @see #invoke - */ - @Nullable - protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable { - Object freshStub; - synchronized (this.stubMonitor) { - this.cachedStub = null; - freshStub = lookupStub(); - if (this.cacheStub) { - this.cachedStub = freshStub; - } - } - return doInvoke(invocation, freshStub); - } - - - /** - * Perform the given invocation on the given RMI stub. - * @param invocation the AOP method invocation - * @param stub the RMI stub to invoke - * @return the invocation result, if any - * @throws Throwable in case of invocation failure - */ - @Nullable - protected Object doInvoke(MethodInvocation invocation, Object stub) throws Throwable { - if (stub instanceof RmiInvocationHandler) { - // RMI invoker - try { - return doInvoke(invocation, (RmiInvocationHandler) stub); - } - catch (RemoteException ex) { - throw convertRmiAccessException(ex, invocation.getMethod()); - } - catch (InvocationTargetException ex) { - throw ex.getTargetException(); - } - catch (Throwable ex) { - throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() + - "] failed in RMI service [" + getJndiName() + "]", ex); - } - } - else { - // traditional RMI stub - try { - return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub); - } - catch (InvocationTargetException ex) { - Throwable targetEx = ex.getTargetException(); - if (targetEx instanceof RemoteException) { - throw convertRmiAccessException((RemoteException) targetEx, invocation.getMethod()); - } - else { - throw targetEx; - } - } - } - } - - /** - * Apply the given AOP method invocation to the given {@link RmiInvocationHandler}. - *

The default implementation delegates to {@link #createRemoteInvocation}. - * @param methodInvocation the current AOP method invocation - * @param invocationHandler the RmiInvocationHandler to apply the invocation to - * @return the invocation result - * @throws RemoteException in case of communication errors - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - * @see org.springframework.remoting.support.RemoteInvocation - */ - protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) - throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { - return "RMI invoker proxy for service URL [" + getJndiName() + "]"; - } - - return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); - } - - /** - * Create a new RemoteInvocation object for the given AOP method invocation. - *

The default implementation delegates to the configured - * {@link #setRemoteInvocationFactory RemoteInvocationFactory}. - * This can be overridden in subclasses in order to provide custom RemoteInvocation - * subclasses, containing additional invocation parameters (e.g. user credentials). - *

Note that it is preferable to build a custom RemoteInvocationFactory - * as a reusable strategy, instead of overriding this method. - * @param methodInvocation the current AOP method invocation - * @return the RemoteInvocation object - * @see RemoteInvocationFactory#createRemoteInvocation - */ - protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { - return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation); - } - - /** - * Convert the given RMI RemoteException that happened during remote access - * to Spring's RemoteAccessException if the method signature does not declare - * RemoteException. Else, return the original RemoteException. - * @param method the invoked method - * @param ex the RemoteException that happened - * @return the exception to be thrown to the caller - */ - private Exception convertRmiAccessException(RemoteException ex, Method method) { - return RmiClientInterceptorUtils.convertRmiAccessException(method, ex, isConnectFailure(ex), getJndiName()); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java deleted file mode 100644 index a9d33d8973..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiProxyFactoryBean.java +++ /dev/null @@ -1,104 +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.rmi; - -import javax.naming.NamingException; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * {@link FactoryBean} for RMI proxies from JNDI. - * - *

Typically used for RMI-IIOP (CORBA), but can also be used for EJB home objects - * (for example, a Stateful Session Bean home). In contrast to a plain JNDI lookup, - * this accessor also performs narrowing through {@link javax.rmi.PortableRemoteObject}. - * - *

With conventional RMI services, this invoker is typically used with the RMI - * service interface. Alternatively, this invoker can also proxy a remote RMI service - * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI - * service methods but does not declare RemoteExceptions. In the latter case, - * RemoteExceptions thrown by the RMI stub will automatically get converted to - * Spring's unchecked RemoteAccessException. - * - *

The JNDI environment can be specified as "jndiEnvironment" property, - * or be configured in a {@code jndi.properties} file or as system properties. - * For example: - * - *

<property name="jndiEnvironment">
- * 	 <props>
- *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
- *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
- *	 </props>
- * </property>
- * - * @author Juergen Hoeller - * @since 1.1 - * @see #setServiceInterface - * @see #setJndiName - * @see #setJndiTemplate - * @see #setJndiEnvironment - * @see #setJndiName - * @see JndiRmiServiceExporter - * @see org.springframework.remoting.RemoteAccessException - * @see java.rmi.RemoteException - * @see java.rmi.Remote - * @see javax.rmi.PortableRemoteObject#narrow - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JndiRmiProxyFactoryBean extends JndiRmiClientInterceptor - implements FactoryBean, BeanClassLoaderAware { - - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - private Object serviceProxy; - - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - @Override - public void afterPropertiesSet() throws NamingException { - super.afterPropertiesSet(); - Class ifc = getServiceInterface(); - Assert.notNull(ifc, "Property 'serviceInterface' is required"); - this.serviceProxy = new ProxyFactory(ifc, this).getProxy(this.beanClassLoader); - } - - - @Override - public Object getObject() { - return this.serviceProxy; - } - - @Override - public Class getObjectType() { - return getServiceInterface(); - } - - @Override - public boolean isSingleton() { - return true; - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java b/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java deleted file mode 100644 index 49b2db295a..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java +++ /dev/null @@ -1,194 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.util.Properties; - -import javax.naming.NamingException; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.jndi.JndiTemplate; -import org.springframework.lang.Nullable; -import org.springframework.util.ReflectionUtils; - -/** - * Service exporter which binds RMI services to JNDI. - * Typically used for RMI-IIOP (CORBA). - * - *

Exports services via the {@link javax.rmi.PortableRemoteObject} class. - * You need to run "rmic" with the "-iiop" option to generate corresponding - * stubs and skeletons for each exported service. - * - *

Also supports exposing any non-RMI service via RMI invokers, to be accessed - * via {@link JndiRmiClientInterceptor} / {@link JndiRmiProxyFactoryBean}'s - * automatic detection of such invokers. - * - *

With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler} - * level, needing only one stub for any service. Service interfaces do not have to - * extend {@code java.rmi.Remote} or throw {@code java.rmi.RemoteException} - * on all methods, but in and out parameters have to be serializable. - * - *

The JNDI environment can be specified as "jndiEnvironment" bean property, - * or be configured in a {@code jndi.properties} file or as system properties. - * For example: - * - *

<property name="jndiEnvironment">
- * 	 <props>
- *		 <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
- *		 <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
- *	 </props>
- * </property>
- * - * @author Juergen Hoeller - * @since 1.1 - * @see #setService - * @see #setJndiTemplate - * @see #setJndiEnvironment - * @see #setJndiName - * @see JndiRmiClientInterceptor - * @see JndiRmiProxyFactoryBean - * @see javax.rmi.PortableRemoteObject#exportObject - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JndiRmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { - - @Nullable - private static Method exportObject; - - @Nullable - private static Method unexportObject; - - static { - try { - Class portableRemoteObject = - JndiRmiServiceExporter.class.getClassLoader().loadClass("javax.rmi.PortableRemoteObject"); - exportObject = portableRemoteObject.getMethod("exportObject", Remote.class); - unexportObject = portableRemoteObject.getMethod("unexportObject", Remote.class); - } - catch (Throwable ex) { - // java.corba module not available on JDK 9+ - exportObject = null; - unexportObject = null; - } - } - - - private JndiTemplate jndiTemplate = new JndiTemplate(); - - private String jndiName; - - private Remote exportedObject; - - - /** - * Set the JNDI template to use for JNDI lookups. - * You can also specify JNDI environment settings via "jndiEnvironment". - * @see #setJndiEnvironment - */ - public void setJndiTemplate(JndiTemplate jndiTemplate) { - this.jndiTemplate = (jndiTemplate != null ? jndiTemplate : new JndiTemplate()); - } - - /** - * Set the JNDI environment to use for JNDI lookups. - * Creates a JndiTemplate with the given environment settings. - * @see #setJndiTemplate - */ - public void setJndiEnvironment(Properties jndiEnvironment) { - this.jndiTemplate = new JndiTemplate(jndiEnvironment); - } - - /** - * Set the JNDI name of the exported RMI service. - */ - public void setJndiName(String jndiName) { - this.jndiName = jndiName; - } - - - @Override - public void afterPropertiesSet() throws NamingException, RemoteException { - prepare(); - } - - /** - * Initialize this service exporter, binding the specified service to JNDI. - * @throws NamingException if service binding failed - * @throws RemoteException if service export failed - */ - public void prepare() throws NamingException, RemoteException { - if (this.jndiName == null) { - throw new IllegalArgumentException("Property 'jndiName' is required"); - } - - // Initialize and cache exported object. - this.exportedObject = getObjectToExport(); - invokePortableRemoteObject(exportObject); - - rebind(); - } - - /** - * Rebind the specified service to JNDI, for recovering in case - * of the target registry having been restarted. - * @throws NamingException if service binding failed - */ - public void rebind() throws NamingException { - if (logger.isDebugEnabled()) { - logger.debug("Binding RMI service to JNDI location [" + this.jndiName + "]"); - } - this.jndiTemplate.rebind(this.jndiName, this.exportedObject); - } - - /** - * Unbind the RMI service from JNDI on bean factory shutdown. - */ - @Override - public void destroy() throws NamingException, RemoteException { - if (logger.isDebugEnabled()) { - logger.debug("Unbinding RMI service from JNDI location [" + this.jndiName + "]"); - } - this.jndiTemplate.unbind(this.jndiName); - invokePortableRemoteObject(unexportObject); - } - - - private void invokePortableRemoteObject(@Nullable Method method) throws RemoteException { - if (method != null) { - try { - method.invoke(null, this.exportedObject); - } - catch (InvocationTargetException ex) { - Throwable targetEx = ex.getTargetException(); - if (targetEx instanceof RemoteException) { - throw (RemoteException) targetEx; - } - ReflectionUtils.rethrowRuntimeException(targetEx); - } - catch (Throwable ex) { - throw new IllegalStateException("PortableRemoteObject invocation failed", ex); - } - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java deleted file mode 100644 index 99e81a4e27..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RemoteInvocationSerializingExporter.java +++ /dev/null @@ -1,183 +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.rmi; - -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.springframework.beans.factory.InitializingBean; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationBasedExporter; -import org.springframework.remoting.support.RemoteInvocationResult; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Abstract base class for remote service exporters that explicitly deserialize - * {@link org.springframework.remoting.support.RemoteInvocation} objects and serialize - * {@link org.springframework.remoting.support.RemoteInvocationResult} objects, - * for example Spring's HTTP invoker. - * - *

Provides template methods for {@code ObjectInputStream} and - * {@code ObjectOutputStream} handling. - * - * @author Juergen Hoeller - * @since 2.5.1 - * @see java.io.ObjectInputStream - * @see java.io.ObjectOutputStream - * @see #doReadRemoteInvocation - * @see #doWriteRemoteInvocationResult - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public abstract class RemoteInvocationSerializingExporter extends RemoteInvocationBasedExporter - implements InitializingBean { - - /** - * Default content type: "application/x-java-serialized-object". - */ - public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object"; - - - private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT; - - private boolean acceptProxyClasses = true; - - private Object proxy; - - - /** - * Specify the content type to use for sending remote invocation responses. - *

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 remote invocation responses. - */ - public String getContentType() { - return this.contentType; - } - - /** - * Set whether to accept deserialization of proxy classes. - *

Default is "true". May be deactivated as a security measure. - */ - public void setAcceptProxyClasses(boolean acceptProxyClasses) { - this.acceptProxyClasses = acceptProxyClasses; - } - - /** - * Return whether to accept deserialization of proxy classes. - */ - public boolean isAcceptProxyClasses() { - return this.acceptProxyClasses; - } - - - @Override - public void afterPropertiesSet() { - prepare(); - } - - /** - * Initialize this service exporter. - */ - public void prepare() { - this.proxy = getProxyForService(); - } - - protected final Object getProxy() { - if (this.proxy == null) { - throw new IllegalStateException(ClassUtils.getShortName(getClass()) + " has not been initialized"); - } - return this.proxy; - } - - - /** - * Create an ObjectInputStream for the given InputStream. - *

The default implementation creates a Spring {@link CodebaseAwareObjectInputStream}. - * @param is the InputStream to read from - * @return the new ObjectInputStream instance to use - * @throws java.io.IOException if creation of the ObjectInputStream failed - */ - protected ObjectInputStream createObjectInputStream(InputStream is) throws IOException { - return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), isAcceptProxyClasses()); - } - - /** - * Perform the actual reading of an invocation result object from the - * given ObjectInputStream. - *

The default implementation simply calls - * {@link java.io.ObjectInputStream#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 java.io.IOException in case of I/O failure - * @throws ClassNotFoundException if case of a transferred class not - * being found in the local ClassLoader - */ - protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois) - throws IOException, ClassNotFoundException { - - Object obj = ois.readObject(); - if (!(obj instanceof RemoteInvocation)) { - throw new RemoteException("Deserialized object needs to be assignable to type [" + - RemoteInvocation.class.getName() + "]: " + ClassUtils.getDescriptiveType(obj)); - } - return (RemoteInvocation) obj; - } - - /** - * Create an ObjectOutputStream for the given OutputStream. - *

The default implementation creates a plain - * {@link java.io.ObjectOutputStream}. - * @param os the OutputStream to write to - * @return the new ObjectOutputStream instance to use - * @throws java.io.IOException if creation of the ObjectOutputStream failed - */ - protected ObjectOutputStream createObjectOutputStream(OutputStream os) throws IOException { - return new ObjectOutputStream(os); - } - - /** - * Perform the actual writing of the given invocation result object - * to the given ObjectOutputStream. - *

The default implementation simply calls - * {@link java.io.ObjectOutputStream#writeObject}. - * Can be overridden for serialization of a custom wrapper object rather - * than the plain invocation, for example an encryption-aware holder. - * @param result the RemoteInvocationResult object - * @param oos the ObjectOutputStream to write to - * @throws java.io.IOException if thrown by I/O methods - */ - protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos) - throws IOException { - - oos.writeObject(result); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiBasedExporter.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiBasedExporter.java deleted file mode 100644 index e6ae6529af..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiBasedExporter.java +++ /dev/null @@ -1,78 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.rmi.Remote; - -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationBasedExporter; - -/** - * Convenient superclass for RMI-based remote exporters. Provides a facility - * to automatically wrap a given plain Java service object with an - * RmiInvocationWrapper, exposing the {@link RmiInvocationHandler} remote interface. - * - *

Using the RMI invoker mechanism, RMI communication operates at the {@link RmiInvocationHandler} - * level, sharing a common invoker stub for any number of services. Service interfaces are not - * required to extend {@code java.rmi.Remote} or declare {@code java.rmi.RemoteException} - * on all service methods. However, in and out parameters still have to be serializable. - * - * @author Juergen Hoeller - * @since 1.2.5 - * @see RmiServiceExporter - * @see JndiRmiServiceExporter - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public abstract class RmiBasedExporter extends RemoteInvocationBasedExporter { - - /** - * Determine the object to export: either the service object itself - * or a RmiInvocationWrapper in case of a non-RMI service object. - * @return the RMI object to export - * @see #setService - * @see #setServiceInterface - */ - protected Remote getObjectToExport() { - // determine remote object - if (getService() instanceof Remote && - (getServiceInterface() == null || Remote.class.isAssignableFrom(getServiceInterface()))) { - // conventional RMI service - return (Remote) getService(); - } - else { - // RMI invoker - if (logger.isDebugEnabled()) { - logger.debug("RMI service [" + getService() + "] is an RMI invoker"); - } - return new RmiInvocationWrapper(getProxyForService(), this); - } - } - - /** - * Redefined here to be visible to RmiInvocationWrapper. - * Simply delegates to the corresponding superclass method. - */ - @Override - protected Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - return super.invoke(invocation, targetObject); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptor.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptor.java deleted file mode 100644 index 8d8569a8f1..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptor.java +++ /dev/null @@ -1,424 +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.rmi; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; -import java.rmi.Naming; -import java.rmi.NotBoundException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; - -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.RemoteConnectFailureException; -import org.springframework.remoting.RemoteInvocationFailureException; -import org.springframework.remoting.RemoteLookupFailureException; -import org.springframework.remoting.support.RemoteInvocationBasedAccessor; -import org.springframework.remoting.support.RemoteInvocationUtils; - -/** - * {@link org.aopalliance.intercept.MethodInterceptor} for accessing conventional - * RMI services or RMI invokers. The service URL must be a valid RMI URL - * (e.g. "rmi://localhost:1099/myservice"). - * - *

RMI invokers work at the RmiInvocationHandler level, needing only one stub for - * any service. Service interfaces do not have to extend {@code java.rmi.Remote} - * or throw {@code java.rmi.RemoteException}. Spring's unchecked - * RemoteAccessException will be thrown on remote invocation failure. - * Of course, in and out parameters have to be serializable. - * - *

With conventional RMI services, this invoker is typically used with the RMI - * service interface. Alternatively, this invoker can also proxy a remote RMI service - * with a matching non-RMI business interface, i.e. an interface that mirrors the RMI - * service methods but does not declare RemoteExceptions. In the latter case, - * RemoteExceptions thrown by the RMI stub will automatically get converted to - * Spring's unchecked RemoteAccessException. - * - * @author Juergen Hoeller - * @since 29.09.2003 - * @see RmiServiceExporter - * @see RmiProxyFactoryBean - * @see RmiInvocationHandler - * @see org.springframework.remoting.RemoteAccessException - * @see java.rmi.RemoteException - * @see java.rmi.Remote - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class RmiClientInterceptor extends RemoteInvocationBasedAccessor - implements MethodInterceptor { - - private boolean lookupStubOnStartup = true; - - private boolean cacheStub = true; - - private boolean refreshStubOnConnectFailure = false; - - private RMIClientSocketFactory registryClientSocketFactory; - - private Remote cachedStub; - - private final Object stubMonitor = new Object(); - - - /** - * Set whether to look up the RMI stub on startup. Default is "true". - *

Can be turned off to allow for late start of the RMI server. - * In this case, the RMI stub will be fetched on first access. - * @see #setCacheStub - */ - public void setLookupStubOnStartup(boolean lookupStubOnStartup) { - this.lookupStubOnStartup = lookupStubOnStartup; - } - - /** - * Set whether to cache the RMI stub once it has been located. - * Default is "true". - *

Can be turned off to allow for hot restart of the RMI server. - * In this case, the RMI stub will be fetched for each invocation. - * @see #setLookupStubOnStartup - */ - public void setCacheStub(boolean cacheStub) { - this.cacheStub = cacheStub; - } - - /** - * Set whether to refresh the RMI stub on connect failure. - * Default is "false". - *

Can be turned on to allow for hot restart of the RMI server. - * If a cached RMI stub throws an RMI exception that indicates a - * remote connect failure, a fresh proxy will be fetched and the - * invocation will be retried. - * @see java.rmi.ConnectException - * @see java.rmi.ConnectIOException - * @see java.rmi.NoSuchObjectException - */ - public void setRefreshStubOnConnectFailure(boolean refreshStubOnConnectFailure) { - this.refreshStubOnConnectFailure = refreshStubOnConnectFailure; - } - - /** - * Set a custom RMI client socket factory to use for accessing the RMI registry. - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.registry.LocateRegistry#getRegistry(String, int, RMIClientSocketFactory) - */ - public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) { - this.registryClientSocketFactory = registryClientSocketFactory; - } - - - @Override - public void afterPropertiesSet() { - super.afterPropertiesSet(); - prepare(); - } - - /** - * Fetches RMI stub on startup, if necessary. - * @throws RemoteLookupFailureException if RMI stub creation failed - * @see #setLookupStubOnStartup - * @see #lookupStub - */ - public void prepare() throws RemoteLookupFailureException { - // Cache RMI stub on initialization? - if (this.lookupStubOnStartup) { - Remote remoteObj = lookupStub(); - if (logger.isDebugEnabled()) { - if (remoteObj instanceof RmiInvocationHandler) { - logger.debug("RMI stub [" + getServiceUrl() + "] is an RMI invoker"); - } - else if (getServiceInterface() != null) { - boolean isImpl = getServiceInterface().isInstance(remoteObj); - logger.debug("Using service interface [" + getServiceInterface().getName() + - "] for RMI stub [" + getServiceUrl() + "] - " + - (!isImpl ? "not " : "") + "directly implemented"); - } - } - if (this.cacheStub) { - this.cachedStub = remoteObj; - } - } - } - - /** - * Create the RMI stub, typically by looking it up. - *

Called on interceptor initialization if "cacheStub" is "true"; - * else called for each invocation by {@link #getStub()}. - *

The default implementation looks up the service URL via - * {@code java.rmi.Naming}. This can be overridden in subclasses. - * @return the RMI stub to store in this interceptor - * @throws RemoteLookupFailureException if RMI stub creation failed - * @see #setCacheStub - * @see java.rmi.Naming#lookup - */ - protected Remote lookupStub() throws RemoteLookupFailureException { - try { - Remote stub = null; - if (this.registryClientSocketFactory != null) { - // RMIClientSocketFactory specified for registry access. - // Unfortunately, due to RMI API limitations, this means - // that we need to parse the RMI URL ourselves and perform - // straight LocateRegistry.getRegistry/Registry.lookup calls. - URL url = new URL(null, getServiceUrl(), new DummyURLStreamHandler()); - String protocol = url.getProtocol(); - if (protocol != null && !"rmi".equals(protocol)) { - throw new MalformedURLException("Invalid URL scheme '" + protocol + "'"); - } - String host = url.getHost(); - int port = url.getPort(); - String name = url.getPath(); - if (name != null && name.startsWith("/")) { - name = name.substring(1); - } - Registry registry = LocateRegistry.getRegistry(host, port, this.registryClientSocketFactory); - stub = registry.lookup(name); - } - else { - // Can proceed with standard RMI lookup API... - stub = Naming.lookup(getServiceUrl()); - } - if (logger.isDebugEnabled()) { - logger.debug("Located RMI stub with URL [" + getServiceUrl() + "]"); - } - return stub; - } - catch (MalformedURLException ex) { - throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex); - } - catch (NotBoundException ex) { - throw new RemoteLookupFailureException( - "Could not find RMI service [" + getServiceUrl() + "] in RMI registry", ex); - } - catch (RemoteException ex) { - throw new RemoteLookupFailureException("Lookup of RMI stub failed", ex); - } - } - - /** - * Return the RMI stub to use. Called for each invocation. - *

The default implementation returns the stub created on initialization, - * if any. Else, it invokes {@link #lookupStub} to get a new stub for - * each invocation. This can be overridden in subclasses, for example in - * order to cache a stub for a given amount of time before recreating it, - * or to test the stub whether it is still alive. - * @return the RMI stub to use for an invocation - * @throws RemoteLookupFailureException if RMI stub creation failed - * @see #lookupStub - */ - protected Remote getStub() throws RemoteLookupFailureException { - if (!this.cacheStub || (this.lookupStubOnStartup && !this.refreshStubOnConnectFailure)) { - return (this.cachedStub != null ? this.cachedStub : lookupStub()); - } - else { - synchronized (this.stubMonitor) { - if (this.cachedStub == null) { - this.cachedStub = lookupStub(); - } - return this.cachedStub; - } - } - } - - - /** - * Fetches an RMI stub and delegates to {@code doInvoke}. - * If configured to refresh on connect failure, it will call - * {@link #refreshAndRetry} on corresponding RMI exceptions. - * @see #getStub - * @see #doInvoke(MethodInvocation, Remote) - * @see #refreshAndRetry - * @see java.rmi.ConnectException - * @see java.rmi.ConnectIOException - * @see java.rmi.NoSuchObjectException - */ - @Override - @Nullable - public Object invoke(MethodInvocation invocation) throws Throwable { - Remote stub = getStub(); - try { - return doInvoke(invocation, stub); - } - catch (RemoteConnectFailureException ex) { - return handleRemoteConnectFailure(invocation, ex); - } - catch (RemoteException ex) { - if (isConnectFailure(ex)) { - return handleRemoteConnectFailure(invocation, ex); - } - else { - throw ex; - } - } - } - - /** - * Determine whether the given RMI exception indicates a connect failure. - *

The default implementation delegates to - * {@link RmiClientInterceptorUtils#isConnectFailure}. - * @param ex the RMI exception to check - * @return whether the exception should be treated as connect failure - */ - protected boolean isConnectFailure(RemoteException ex) { - return RmiClientInterceptorUtils.isConnectFailure(ex); - } - - /** - * Refresh the stub and retry the remote invocation if necessary. - *

If not configured to refresh on connect failure, this method - * simply rethrows the original exception. - * @param invocation the invocation that failed - * @param ex the exception raised on remote invocation - * @return the result value of the new invocation, if succeeded - * @throws Throwable an exception raised by the new invocation, - * if it failed as well - * @see #setRefreshStubOnConnectFailure - * @see #doInvoke - */ - @Nullable - private Object handleRemoteConnectFailure(MethodInvocation invocation, Exception ex) throws Throwable { - if (this.refreshStubOnConnectFailure) { - String msg = "Could not connect to RMI service [" + getServiceUrl() + "] - retrying"; - if (logger.isDebugEnabled()) { - logger.warn(msg, ex); - } - else if (logger.isWarnEnabled()) { - logger.warn(msg); - } - return refreshAndRetry(invocation); - } - else { - throw ex; - } - } - - /** - * Refresh the RMI stub and retry the given invocation. - * Called by invoke on connect failure. - * @param invocation the AOP method invocation - * @return the invocation result, if any - * @throws Throwable in case of invocation failure - * @see #invoke - */ - @Nullable - protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable { - Remote freshStub = null; - synchronized (this.stubMonitor) { - this.cachedStub = null; - freshStub = lookupStub(); - if (this.cacheStub) { - this.cachedStub = freshStub; - } - } - return doInvoke(invocation, freshStub); - } - - /** - * Perform the given invocation on the given RMI stub. - * @param invocation the AOP method invocation - * @param stub the RMI stub to invoke - * @return the invocation result, if any - * @throws Throwable in case of invocation failure - */ - @Nullable - protected Object doInvoke(MethodInvocation invocation, Remote stub) throws Throwable { - if (stub instanceof RmiInvocationHandler) { - // RMI invoker - try { - return doInvoke(invocation, (RmiInvocationHandler) stub); - } - catch (RemoteException ex) { - throw RmiClientInterceptorUtils.convertRmiAccessException( - invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl()); - } - catch (InvocationTargetException ex) { - Throwable exToThrow = ex.getTargetException(); - RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow); - throw exToThrow; - } - catch (Throwable ex) { - throw new RemoteInvocationFailureException("Invocation of method [" + invocation.getMethod() + - "] failed in RMI service [" + getServiceUrl() + "]", ex); - } - } - else { - // traditional RMI stub - try { - return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, stub); - } - catch (InvocationTargetException ex) { - Throwable targetEx = ex.getTargetException(); - if (targetEx instanceof RemoteException) { - RemoteException rex = (RemoteException) targetEx; - throw RmiClientInterceptorUtils.convertRmiAccessException( - invocation.getMethod(), rex, isConnectFailure(rex), getServiceUrl()); - } - else { - throw targetEx; - } - } - } - } - - /** - * Apply the given AOP method invocation to the given {@link RmiInvocationHandler}. - *

The default implementation delegates to {@link #createRemoteInvocation}. - * @param methodInvocation the current AOP method invocation - * @param invocationHandler the RmiInvocationHandler to apply the invocation to - * @return the invocation result - * @throws RemoteException in case of communication errors - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - * @see org.springframework.remoting.support.RemoteInvocation - */ - @Nullable - protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler) - throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { - return "RMI invoker proxy for service URL [" + getServiceUrl() + "]"; - } - - return invocationHandler.invoke(createRemoteInvocation(methodInvocation)); - } - - - /** - * Dummy URLStreamHandler that's just specified to suppress the standard - * {@code java.net.URL} URLStreamHandler lookup, to be able to - * use the standard URL class for parsing "rmi:..." URLs. - */ - private static class DummyURLStreamHandler extends URLStreamHandler { - - @Override - protected URLConnection openConnection(URL url) throws IOException { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java deleted file mode 100644 index 2842e06143..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiClientInterceptorUtils.java +++ /dev/null @@ -1,176 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.SocketException; -import java.rmi.ConnectException; -import java.rmi.ConnectIOException; -import java.rmi.NoSuchObjectException; -import java.rmi.RemoteException; -import java.rmi.StubNotFoundException; -import java.rmi.UnknownHostException; - -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.lang.Nullable; -import org.springframework.remoting.RemoteAccessException; -import org.springframework.remoting.RemoteConnectFailureException; -import org.springframework.remoting.RemoteProxyFailureException; -import org.springframework.util.ReflectionUtils; - -/** - * Factored-out methods for performing invocations within an RMI client. - * Can handle both RMI and non-RMI service interfaces working on an RMI stub. - * - *

Note: This is an SPI class, not intended to be used by applications. - * - * @author Juergen Hoeller - * @since 1.1 - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public abstract class RmiClientInterceptorUtils { - - private static final Log logger = LogFactory.getLog(RmiClientInterceptorUtils.class); - - - /** - * Perform a raw method invocation on the given RMI stub, - * letting reflection exceptions through as-is. - * @param invocation the AOP MethodInvocation - * @param stub the RMI stub - * @return the invocation result, if any - * @throws InvocationTargetException if thrown by reflection - */ - @Nullable - public static Object invokeRemoteMethod(MethodInvocation invocation, Object stub) - throws InvocationTargetException { - - Method method = invocation.getMethod(); - try { - if (method.getDeclaringClass().isInstance(stub)) { - // directly implemented - return method.invoke(stub, invocation.getArguments()); - } - else { - // not directly implemented - Method stubMethod = stub.getClass().getMethod(method.getName(), method.getParameterTypes()); - return stubMethod.invoke(stub, invocation.getArguments()); - } - } - catch (InvocationTargetException ex) { - throw ex; - } - catch (NoSuchMethodException ex) { - throw new RemoteProxyFailureException("No matching RMI stub method found for: " + method, ex); - } - catch (Throwable ex) { - throw new RemoteProxyFailureException("Invocation of RMI stub method failed: " + method, ex); - } - } - - /** - * Wrap the given arbitrary exception that happened during remote access - * in either a RemoteException or a Spring RemoteAccessException (if the - * method signature does not support RemoteException). - *

Only call this for remote access exceptions, not for exceptions - * thrown by the target service itself! - * @param method the invoked method - * @param ex the exception that happened, to be used as cause for the - * RemoteAccessException or RemoteException - * @param message the message for the RemoteAccessException respectively - * RemoteException - * @return the exception to be thrown to the caller - */ - public static Exception convertRmiAccessException(Method method, Throwable ex, String message) { - if (logger.isDebugEnabled()) { - logger.debug(message, ex); - } - if (ReflectionUtils.declaresException(method, RemoteException.class)) { - return new RemoteException(message, ex); - } - else { - return new RemoteAccessException(message, ex); - } - } - - /** - * Convert the given RemoteException that happened during remote access - * to Spring's RemoteAccessException if the method signature does not - * support RemoteException. Else, return the original RemoteException. - * @param method the invoked method - * @param ex the RemoteException that happened - * @param serviceName the name of the service (for debugging purposes) - * @return the exception to be thrown to the caller - */ - public static Exception convertRmiAccessException(Method method, RemoteException ex, String serviceName) { - return convertRmiAccessException(method, ex, isConnectFailure(ex), serviceName); - } - - /** - * Convert the given RemoteException that happened during remote access - * to Spring's RemoteAccessException if the method signature does not - * support RemoteException. Else, return the original RemoteException. - * @param method the invoked method - * @param ex the RemoteException that happened - * @param isConnectFailure whether the given exception should be considered - * a connect failure - * @param serviceName the name of the service (for debugging purposes) - * @return the exception to be thrown to the caller - */ - public static Exception convertRmiAccessException( - Method method, RemoteException ex, boolean isConnectFailure, String serviceName) { - - if (logger.isDebugEnabled()) { - logger.debug("Remote service [" + serviceName + "] threw exception", ex); - } - if (ReflectionUtils.declaresException(method, ex.getClass())) { - return ex; - } - else { - if (isConnectFailure) { - return new RemoteConnectFailureException("Could not connect to remote service [" + serviceName + "]", ex); - } - else { - return new RemoteAccessException("Could not access remote service [" + serviceName + "]", ex); - } - } - } - - /** - * Determine whether the given RMI exception indicates a connect failure. - *

Treats RMI's ConnectException, ConnectIOException, UnknownHostException, - * NoSuchObjectException and StubNotFoundException as connect failure. - * @param ex the RMI exception to check - * @return whether the exception should be treated as connect failure - * @see java.rmi.ConnectException - * @see java.rmi.ConnectIOException - * @see java.rmi.UnknownHostException - * @see java.rmi.NoSuchObjectException - * @see java.rmi.StubNotFoundException - */ - public static boolean isConnectFailure(RemoteException ex) { - return (ex instanceof ConnectException || ex instanceof ConnectIOException || - ex instanceof UnknownHostException || ex instanceof NoSuchObjectException || - ex instanceof StubNotFoundException || ex.getCause() instanceof SocketException); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationHandler.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationHandler.java deleted file mode 100644 index fb26b071f5..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationHandler.java +++ /dev/null @@ -1,64 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.rmi.Remote; -import java.rmi.RemoteException; - -import org.springframework.lang.Nullable; -import org.springframework.remoting.support.RemoteInvocation; - -/** - * Interface for RMI invocation handlers instances on the server, - * wrapping exported services. A client uses a stub implementing - * this interface to access such a service. - * - *

This is an SPI interface, not to be used directly by applications. - * - * @author Juergen Hoeller - * @since 14.05.2003 - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public interface RmiInvocationHandler extends Remote { - - /** - * Return the name of the target interface that this invoker operates on. - * @return the name of the target interface, or {@code null} if none - * @throws RemoteException in case of communication errors - * @see RmiServiceExporter#getServiceInterface() - */ - @Nullable - public String getTargetInterfaceName() throws RemoteException; - - /** - * Apply the given invocation to the target object. - *

Called by - * {@link RmiClientInterceptor#doInvoke(org.aopalliance.intercept.MethodInvocation, RmiInvocationHandler)}. - * @param invocation object that encapsulates invocation parameters - * @return the object returned from the invoked method, if any - * @throws RemoteException in case of communication errors - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - */ - @Nullable - public Object invoke(RemoteInvocation invocation) - throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException; - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationWrapper.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationWrapper.java deleted file mode 100644 index 1f030b327c..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiInvocationWrapper.java +++ /dev/null @@ -1,81 +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.rmi; - -import java.lang.reflect.InvocationTargetException; -import java.rmi.RemoteException; - -import org.springframework.lang.Nullable; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.util.Assert; - -/** - * Server-side implementation of {@link RmiInvocationHandler}. An instance - * of this class exists for each remote object. Automatically created - * by {@link RmiServiceExporter} for non-RMI service implementations. - * - *

This is an SPI class, not to be used directly by applications. - * - * @author Juergen Hoeller - * @since 14.05.2003 - * @see RmiServiceExporter - */ -@Deprecated -class RmiInvocationWrapper implements RmiInvocationHandler { - - private final Object wrappedObject; - - private final RmiBasedExporter rmiExporter; - - - /** - * Create a new RmiInvocationWrapper for the given object. - * @param wrappedObject the object to wrap with an RmiInvocationHandler - * @param rmiExporter the RMI exporter to handle the actual invocation - */ - public RmiInvocationWrapper(Object wrappedObject, RmiBasedExporter rmiExporter) { - Assert.notNull(wrappedObject, "Object to wrap is required"); - Assert.notNull(rmiExporter, "RMI exporter is required"); - this.wrappedObject = wrappedObject; - this.rmiExporter = rmiExporter; - } - - - /** - * Exposes the exporter's service interface, if any, as target interface. - * @see RmiBasedExporter#getServiceInterface() - */ - @Override - @Nullable - public String getTargetInterfaceName() { - Class ifc = this.rmiExporter.getServiceInterface(); - return (ifc != null ? ifc.getName() : null); - } - - /** - * Delegates the actual invocation handling to the RMI exporter. - * @see RmiBasedExporter#invoke(org.springframework.remoting.support.RemoteInvocation, Object) - */ - @Override - @Nullable - public Object invoke(RemoteInvocation invocation) - throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - return this.rmiExporter.invoke(invocation, this.wrappedObject); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiProxyFactoryBean.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiProxyFactoryBean.java deleted file mode 100644 index 142640926d..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiProxyFactoryBean.java +++ /dev/null @@ -1,92 +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.rmi; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.util.Assert; - -/** - * {@link FactoryBean} for RMI proxies, supporting both conventional RMI services - * and RMI invokers. Exposes the proxied service for use as a bean reference, - * using the specified service interface. Proxies will throw Spring's unchecked - * RemoteAccessException on remote invocation failure instead of RMI's RemoteException. - * - *

The service URL must be a valid RMI URL like "rmi://localhost:1099/myservice". - * RMI invokers work at the RmiInvocationHandler level, using the same invoker stub - * for any service. Service interfaces do not have to extend {@code java.rmi.Remote} - * or throw {@code java.rmi.RemoteException}. Of course, in and out parameters - * have to be serializable. - * - *

With conventional RMI services, this proxy factory is typically used with the - * RMI service interface. Alternatively, this factory can also proxy a remote RMI - * service with a matching non-RMI business interface, i.e. an interface that mirrors - * the RMI service methods but does not declare RemoteExceptions. In the latter case, - * RemoteExceptions thrown by the RMI stub will automatically get converted to - * Spring's unchecked RemoteAccessException. - * - *

The major advantage of RMI, compared to Hessian, is serialization. - * Effectively, any serializable Java object can be transported without hassle. - * Hessian has its own (de-)serialization mechanisms, but is HTTP-based and thus - * much easier to setup than RMI. Alternatively, consider Spring's HTTP invoker - * to combine Java serialization with HTTP-based transport. - * - * @author Juergen Hoeller - * @since 13.05.2003 - * @see #setServiceInterface - * @see #setServiceUrl - * @see RmiClientInterceptor - * @see RmiServiceExporter - * @see java.rmi.Remote - * @see java.rmi.RemoteException - * @see org.springframework.remoting.RemoteAccessException - * @see org.springframework.remoting.caucho.HessianProxyFactoryBean - * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class RmiProxyFactoryBean extends RmiClientInterceptor implements FactoryBean, BeanClassLoaderAware { - - 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 - public Object getObject() { - return this.serviceProxy; - } - - @Override - public Class getObjectType() { - return getServiceInterface(); - } - - @Override - public boolean isSingleton() { - return true; - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java deleted file mode 100644 index e0b9cf6015..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiRegistryFactoryBean.java +++ /dev/null @@ -1,317 +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.rmi; - -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; -import java.rmi.server.RMIServerSocketFactory; -import java.rmi.server.UnicastRemoteObject; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.lang.Nullable; - -/** - * {@link FactoryBean} that locates a {@link java.rmi.registry.Registry} and - * exposes it for bean references. Can also create a local RMI registry - * on the fly if none exists already. - * - *

Can be used to set up and pass around the actual Registry object to - * applications objects that need to work with RMI. One example for such an - * object that needs to work with RMI is Spring's {@link RmiServiceExporter}, - * which either works with a passed-in Registry reference or falls back to - * the registry as specified by its local properties and defaults. - * - *

Also useful to enforce creation of a local RMI registry at a given port, - * for example for a JMX connector. If used in conjunction with - * {@link org.springframework.jmx.support.ConnectorServerFactoryBean}, - * it is recommended to mark the connector definition (ConnectorServerFactoryBean) - * as "depends-on" the registry definition (RmiRegistryFactoryBean), - * to guarantee starting up the registry first. - * - *

Note: The implementation of this class mirrors the corresponding logic - * in {@link RmiServiceExporter}, and also offers the same customization hooks. - * RmiServiceExporter implements its own registry lookup as a convenience: - * It is very common to simply rely on the registry defaults. - * - * @author Juergen Hoeller - * @since 1.2.3 - * @see RmiServiceExporter#setRegistry - * @see org.springframework.jmx.support.ConnectorServerFactoryBean - * @see java.rmi.registry.Registry - * @see java.rmi.registry.LocateRegistry - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class RmiRegistryFactoryBean implements FactoryBean, InitializingBean, DisposableBean { - - protected final Log logger = LogFactory.getLog(getClass()); - - private String host; - - private int port = Registry.REGISTRY_PORT; - - private RMIClientSocketFactory clientSocketFactory; - - private RMIServerSocketFactory serverSocketFactory; - - private Registry registry; - - private boolean alwaysCreate = false; - - private boolean created = false; - - - /** - * Set the host of the registry for the exported RMI service, - * i.e. {@code rmi://HOST:port/name} - *

Default is localhost. - */ - public void setHost(String host) { - this.host = host; - } - - /** - * Return the host of the registry for the exported RMI service. - */ - public String getHost() { - return this.host; - } - - /** - * Set the port of the registry for the exported RMI service, - * i.e. {@code rmi://host:PORT/name} - *

Default is {@code Registry.REGISTRY_PORT} (1099). - */ - public void setPort(int port) { - this.port = port; - } - - /** - * Return the port of the registry for the exported RMI service. - */ - public int getPort() { - return this.port; - } - - /** - * Set a custom RMI client socket factory to use for the RMI registry. - *

If the given object also implements {@code java.rmi.server.RMIServerSocketFactory}, - * it will automatically be registered as server socket factory too. - * @see #setServerSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see java.rmi.registry.LocateRegistry#getRegistry(String, int, java.rmi.server.RMIClientSocketFactory) - */ - public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) { - this.clientSocketFactory = clientSocketFactory; - } - - /** - * Set a custom RMI server socket factory to use for the RMI registry. - *

Only needs to be specified when the client socket factory does not - * implement {@code java.rmi.server.RMIServerSocketFactory} already. - * @see #setClientSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see java.rmi.registry.LocateRegistry#createRegistry(int, RMIClientSocketFactory, java.rmi.server.RMIServerSocketFactory) - */ - public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) { - this.serverSocketFactory = serverSocketFactory; - } - - /** - * Set whether to always create the registry in-process, - * not attempting to locate an existing registry at the specified port. - *

Default is "false". Switch this flag to "true" in order to avoid - * the overhead of locating an existing registry when you always - * intend to create a new registry in any case. - */ - public void setAlwaysCreate(boolean alwaysCreate) { - this.alwaysCreate = alwaysCreate; - } - - - @Override - public void afterPropertiesSet() throws Exception { - // Check socket factories for registry. - if (this.clientSocketFactory instanceof RMIServerSocketFactory) { - this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory; - } - if ((this.clientSocketFactory != null && this.serverSocketFactory == null) || - (this.clientSocketFactory == null && this.serverSocketFactory != null)) { - throw new IllegalArgumentException( - "Both RMIClientSocketFactory and RMIServerSocketFactory or none required"); - } - - // Fetch RMI registry to expose. - this.registry = getRegistry(this.host, this.port, this.clientSocketFactory, this.serverSocketFactory); - } - - - /** - * Locate or create the RMI registry. - * @param registryHost the registry host to use (if this is specified, - * no implicit creation of a RMI registry will happen) - * @param registryPort the registry port to use - * @param clientSocketFactory the RMI client socket factory for the registry (if any) - * @param serverSocketFactory the RMI server socket factory for the registry (if any) - * @return the RMI registry - * @throws java.rmi.RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(String registryHost, int registryPort, - @Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory) - throws RemoteException { - - if (registryHost != null) { - // Host explicitly specified: only lookup possible. - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]"); - } - Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory); - testRegistry(reg); - return reg; - } - - else { - return getRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - } - - /** - * Locate or create the RMI registry. - * @param registryPort the registry port to use - * @param clientSocketFactory the RMI client socket factory for the registry (if any) - * @param serverSocketFactory the RMI server socket factory for the registry (if any) - * @return the RMI registry - * @throws RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(int registryPort, - @Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory) - throws RemoteException { - - if (clientSocketFactory != null) { - if (this.alwaysCreate) { - logger.debug("Creating new RMI registry"); - this.created = true; - return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "', using custom socket factory"); - } - synchronized (LocateRegistry.class) { - try { - // Retrieve existing registry. - Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory); - testRegistry(reg); - return reg; - } - catch (RemoteException ex) { - logger.trace("RMI registry access threw exception", ex); - logger.debug("Could not detect RMI registry - creating new one"); - // Assume no registry found -> create new one. - this.created = true; - return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - } - } - - else { - return getRegistry(registryPort); - } - } - - /** - * Locate or create the RMI registry. - * @param registryPort the registry port to use - * @return the RMI registry - * @throws RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(int registryPort) throws RemoteException { - if (this.alwaysCreate) { - logger.debug("Creating new RMI registry"); - this.created = true; - return LocateRegistry.createRegistry(registryPort); - } - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "'"); - } - synchronized (LocateRegistry.class) { - try { - // Retrieve existing registry. - Registry reg = LocateRegistry.getRegistry(registryPort); - testRegistry(reg); - return reg; - } - catch (RemoteException ex) { - logger.trace("RMI registry access threw exception", ex); - logger.debug("Could not detect RMI registry - creating new one"); - // Assume no registry found -> create new one. - this.created = true; - return LocateRegistry.createRegistry(registryPort); - } - } - } - - /** - * Test the given RMI registry, calling some operation on it to - * check whether it is still active. - *

Default implementation calls {@code Registry.list()}. - * @param registry the RMI registry to test - * @throws RemoteException if thrown by registry methods - * @see java.rmi.registry.Registry#list() - */ - protected void testRegistry(Registry registry) throws RemoteException { - registry.list(); - } - - - @Override - public Registry getObject() throws Exception { - return this.registry; - } - - @Override - public Class getObjectType() { - return (this.registry != null ? this.registry.getClass() : Registry.class); - } - - @Override - public boolean isSingleton() { - return true; - } - - - /** - * Unexport the RMI registry on bean factory shutdown, - * provided that this bean actually created a registry. - */ - @Override - public void destroy() throws RemoteException { - if (this.created) { - logger.debug("Unexporting RMI registry"); - UnicastRemoteObject.unexportObject(this.registry, true); - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiServiceExporter.java b/spring-context/src/main/java/org/springframework/remoting/rmi/RmiServiceExporter.java deleted file mode 100644 index 9ee3a6c112..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/RmiServiceExporter.java +++ /dev/null @@ -1,464 +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.rmi; - -import java.rmi.AlreadyBoundException; -import java.rmi.NoSuchObjectException; -import java.rmi.NotBoundException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; -import java.rmi.server.RMIServerSocketFactory; -import java.rmi.server.UnicastRemoteObject; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.lang.Nullable; - -/** - * RMI exporter that exposes the specified service as RMI object with the specified name. - * Such services can be accessed via plain RMI or via {@link RmiProxyFactoryBean}. - * Also supports exposing any non-RMI service via RMI invokers, to be accessed via - * {@link RmiClientInterceptor} / {@link RmiProxyFactoryBean}'s automatic detection - * of such invokers. - * - *

With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler} - * level, needing only one stub for any service. Service interfaces do not have to - * extend {@code java.rmi.Remote} or throw {@code java.rmi.RemoteException} - * on all methods, but in and out parameters have to be serializable. - * - *

The major advantage of RMI, compared to Hessian, is serialization. - * Effectively, any serializable Java object can be transported without hassle. - * Hessian has its own (de-)serialization mechanisms, but is HTTP-based and thus - * much easier to setup than RMI. Alternatively, consider Spring's HTTP invoker - * to combine Java serialization with HTTP-based transport. - * - *

Note: RMI makes a best-effort attempt to obtain the fully qualified host name. - * If one cannot be determined, it will fall back and use the IP address. Depending - * on your network configuration, in some cases it will resolve the IP to the loopback - * address. To ensure that RMI will use the host name bound to the correct network - * interface, you should pass the {@code java.rmi.server.hostname} property to the - * JVM that will export the registry and/or the service using the "-D" JVM argument. - * For example: {@code -Djava.rmi.server.hostname=myserver.com} - * - * @author Juergen Hoeller - * @since 13.05.2003 - * @see RmiClientInterceptor - * @see RmiProxyFactoryBean - * @see java.rmi.Remote - * @see java.rmi.RemoteException - * @see org.springframework.remoting.caucho.HessianServiceExporter - * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class RmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { - - private String serviceName; - - private int servicePort = 0; // anonymous port - - private RMIClientSocketFactory clientSocketFactory; - - private RMIServerSocketFactory serverSocketFactory; - - private Registry registry; - - private String registryHost; - - private int registryPort = Registry.REGISTRY_PORT; - - private RMIClientSocketFactory registryClientSocketFactory; - - private RMIServerSocketFactory registryServerSocketFactory; - - private boolean alwaysCreateRegistry = false; - - private boolean replaceExistingBinding = true; - - private Remote exportedObject; - - private boolean createdRegistry = false; - - - /** - * Set the name of the exported RMI service, - * i.e. {@code rmi://host:port/NAME} - */ - public void setServiceName(String serviceName) { - this.serviceName = serviceName; - } - - /** - * Set the port that the exported RMI service will use. - *

Default is 0 (anonymous port). - */ - public void setServicePort(int servicePort) { - this.servicePort = servicePort; - } - - /** - * Set a custom RMI client socket factory to use for exporting the service. - *

If the given object also implements {@code java.rmi.server.RMIServerSocketFactory}, - * it will automatically be registered as server socket factory too. - * @see #setServerSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory) - */ - public void setClientSocketFactory(RMIClientSocketFactory clientSocketFactory) { - this.clientSocketFactory = clientSocketFactory; - } - - /** - * Set a custom RMI server socket factory to use for exporting the service. - *

Only needs to be specified when the client socket factory does not - * implement {@code java.rmi.server.RMIServerSocketFactory} already. - * @see #setClientSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see UnicastRemoteObject#exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory) - */ - public void setServerSocketFactory(RMIServerSocketFactory serverSocketFactory) { - this.serverSocketFactory = serverSocketFactory; - } - - /** - * Specify the RMI registry to register the exported service with. - * Typically used in combination with RmiRegistryFactoryBean. - *

Alternatively, you can specify all registry properties locally. - * This exporter will then try to locate the specified registry, - * automatically creating a new local one if appropriate. - *

Default is a local registry at the default port (1099), - * created on the fly if necessary. - * @see RmiRegistryFactoryBean - * @see #setRegistryHost - * @see #setRegistryPort - * @see #setRegistryClientSocketFactory - * @see #setRegistryServerSocketFactory - */ - public void setRegistry(Registry registry) { - this.registry = registry; - } - - /** - * Set the host of the registry for the exported RMI service, - * i.e. {@code rmi://HOST:port/name} - *

Default is localhost. - */ - public void setRegistryHost(String registryHost) { - this.registryHost = registryHost; - } - - /** - * Set the port of the registry for the exported RMI service, - * i.e. {@code rmi://host:PORT/name} - *

Default is {@code Registry.REGISTRY_PORT} (1099). - * @see java.rmi.registry.Registry#REGISTRY_PORT - */ - public void setRegistryPort(int registryPort) { - this.registryPort = registryPort; - } - - /** - * Set a custom RMI client socket factory to use for the RMI registry. - *

If the given object also implements {@code java.rmi.server.RMIServerSocketFactory}, - * it will automatically be registered as server socket factory too. - * @see #setRegistryServerSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see LocateRegistry#getRegistry(String, int, RMIClientSocketFactory) - */ - public void setRegistryClientSocketFactory(RMIClientSocketFactory registryClientSocketFactory) { - this.registryClientSocketFactory = registryClientSocketFactory; - } - - /** - * Set a custom RMI server socket factory to use for the RMI registry. - *

Only needs to be specified when the client socket factory does not - * implement {@code java.rmi.server.RMIServerSocketFactory} already. - * @see #setRegistryClientSocketFactory - * @see java.rmi.server.RMIClientSocketFactory - * @see java.rmi.server.RMIServerSocketFactory - * @see LocateRegistry#createRegistry(int, RMIClientSocketFactory, RMIServerSocketFactory) - */ - public void setRegistryServerSocketFactory(RMIServerSocketFactory registryServerSocketFactory) { - this.registryServerSocketFactory = registryServerSocketFactory; - } - - /** - * Set whether to always create the registry in-process, - * not attempting to locate an existing registry at the specified port. - *

Default is "false". Switch this flag to "true" in order to avoid - * the overhead of locating an existing registry when you always - * intend to create a new registry in any case. - */ - public void setAlwaysCreateRegistry(boolean alwaysCreateRegistry) { - this.alwaysCreateRegistry = alwaysCreateRegistry; - } - - /** - * Set whether to replace an existing binding in the RMI registry, - * that is, whether to simply override an existing binding with the - * specified service in case of a naming conflict in the registry. - *

Default is "true", assuming that an existing binding for this - * exporter's service name is an accidental leftover from a previous - * execution. Switch this to "false" to make the exporter fail in such - * a scenario, indicating that there was already an RMI object bound. - */ - public void setReplaceExistingBinding(boolean replaceExistingBinding) { - this.replaceExistingBinding = replaceExistingBinding; - } - - - @Override - public void afterPropertiesSet() throws RemoteException { - prepare(); - } - - /** - * Initialize this service exporter, registering the service as RMI object. - *

Creates an RMI registry on the specified port if none exists. - * @throws RemoteException if service registration failed - */ - public void prepare() throws RemoteException { - checkService(); - - if (this.serviceName == null) { - throw new IllegalArgumentException("Property 'serviceName' is required"); - } - - // Check socket factories for exported object. - if (this.clientSocketFactory instanceof RMIServerSocketFactory) { - this.serverSocketFactory = (RMIServerSocketFactory) this.clientSocketFactory; - } - if ((this.clientSocketFactory != null && this.serverSocketFactory == null) || - (this.clientSocketFactory == null && this.serverSocketFactory != null)) { - throw new IllegalArgumentException( - "Both RMIClientSocketFactory and RMIServerSocketFactory or none required"); - } - - // Check socket factories for RMI registry. - if (this.registryClientSocketFactory instanceof RMIServerSocketFactory) { - this.registryServerSocketFactory = (RMIServerSocketFactory) this.registryClientSocketFactory; - } - if (this.registryClientSocketFactory == null && this.registryServerSocketFactory != null) { - throw new IllegalArgumentException( - "RMIServerSocketFactory without RMIClientSocketFactory for registry not supported"); - } - - this.createdRegistry = false; - - // Determine RMI registry to use. - if (this.registry == null) { - this.registry = getRegistry(this.registryHost, this.registryPort, - this.registryClientSocketFactory, this.registryServerSocketFactory); - this.createdRegistry = true; - } - - // Initialize and cache exported object. - this.exportedObject = getObjectToExport(); - - if (logger.isDebugEnabled()) { - logger.debug("Binding service '" + this.serviceName + "' to RMI registry: " + this.registry); - } - - // Export RMI object. - if (this.clientSocketFactory != null) { - UnicastRemoteObject.exportObject( - this.exportedObject, this.servicePort, this.clientSocketFactory, this.serverSocketFactory); - } - else { - UnicastRemoteObject.exportObject(this.exportedObject, this.servicePort); - } - - // Bind RMI object to registry. - try { - if (this.replaceExistingBinding) { - this.registry.rebind(this.serviceName, this.exportedObject); - } - else { - this.registry.bind(this.serviceName, this.exportedObject); - } - } - catch (AlreadyBoundException ex) { - // Already an RMI object bound for the specified service name... - unexportObjectSilently(); - throw new IllegalStateException( - "Already an RMI object bound for name '" + this.serviceName + "': " + ex.toString()); - } - catch (RemoteException ex) { - // Registry binding failed: let's unexport the RMI object as well. - unexportObjectSilently(); - throw ex; - } - } - - - /** - * Locate or create the RMI registry for this exporter. - * @param registryHost the registry host to use (if this is specified, - * no implicit creation of a RMI registry will happen) - * @param registryPort the registry port to use - * @param clientSocketFactory the RMI client socket factory for the registry (if any) - * @param serverSocketFactory the RMI server socket factory for the registry (if any) - * @return the RMI registry - * @throws RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(String registryHost, int registryPort, - @Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory) - throws RemoteException { - - if (registryHost != null) { - // Host explicitly specified: only lookup possible. - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "' of host [" + registryHost + "]"); - } - Registry reg = LocateRegistry.getRegistry(registryHost, registryPort, clientSocketFactory); - testRegistry(reg); - return reg; - } - - else { - return getRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - } - - /** - * Locate or create the RMI registry for this exporter. - * @param registryPort the registry port to use - * @param clientSocketFactory the RMI client socket factory for the registry (if any) - * @param serverSocketFactory the RMI server socket factory for the registry (if any) - * @return the RMI registry - * @throws RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(int registryPort, - @Nullable RMIClientSocketFactory clientSocketFactory, @Nullable RMIServerSocketFactory serverSocketFactory) - throws RemoteException { - - if (clientSocketFactory != null) { - if (this.alwaysCreateRegistry) { - logger.debug("Creating new RMI registry"); - return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "', using custom socket factory"); - } - synchronized (LocateRegistry.class) { - try { - // Retrieve existing registry. - Registry reg = LocateRegistry.getRegistry(null, registryPort, clientSocketFactory); - testRegistry(reg); - return reg; - } - catch (RemoteException ex) { - logger.trace("RMI registry access threw exception", ex); - logger.debug("Could not detect RMI registry - creating new one"); - // Assume no registry found -> create new one. - return LocateRegistry.createRegistry(registryPort, clientSocketFactory, serverSocketFactory); - } - } - } - - else { - return getRegistry(registryPort); - } - } - - /** - * Locate or create the RMI registry for this exporter. - * @param registryPort the registry port to use - * @return the RMI registry - * @throws RemoteException if the registry couldn't be located or created - */ - protected Registry getRegistry(int registryPort) throws RemoteException { - if (this.alwaysCreateRegistry) { - logger.debug("Creating new RMI registry"); - return LocateRegistry.createRegistry(registryPort); - } - if (logger.isDebugEnabled()) { - logger.debug("Looking for RMI registry at port '" + registryPort + "'"); - } - synchronized (LocateRegistry.class) { - try { - // Retrieve existing registry. - Registry reg = LocateRegistry.getRegistry(registryPort); - testRegistry(reg); - return reg; - } - catch (RemoteException ex) { - logger.trace("RMI registry access threw exception", ex); - logger.debug("Could not detect RMI registry - creating new one"); - // Assume no registry found -> create new one. - return LocateRegistry.createRegistry(registryPort); - } - } - } - - /** - * Test the given RMI registry, calling some operation on it to - * check whether it is still active. - *

Default implementation calls {@code Registry.list()}. - * @param registry the RMI registry to test - * @throws RemoteException if thrown by registry methods - * @see java.rmi.registry.Registry#list() - */ - protected void testRegistry(Registry registry) throws RemoteException { - registry.list(); - } - - - /** - * Unbind the RMI service from the registry on bean factory shutdown. - */ - @Override - public void destroy() throws RemoteException { - if (logger.isDebugEnabled()) { - logger.debug("Unbinding RMI service '" + this.serviceName + - "' from registry" + (this.createdRegistry ? (" at port '" + this.registryPort + "'") : "")); - } - try { - this.registry.unbind(this.serviceName); - } - catch (NotBoundException ex) { - if (logger.isInfoEnabled()) { - logger.info("RMI service '" + this.serviceName + "' is not bound to registry" + - (this.createdRegistry ? (" at port '" + this.registryPort + "' anymore") : ""), ex); - } - } - finally { - unexportObjectSilently(); - } - } - - /** - * Unexport the registered RMI object, logging any exception that arises. - */ - private void unexportObjectSilently() { - try { - UnicastRemoteObject.unexportObject(this.exportedObject, true); - } - catch (NoSuchObjectException ex) { - if (logger.isInfoEnabled()) { - logger.info("RMI object for service '" + this.serviceName + "' is not exported anymore", ex); - } - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/package-info.java b/spring-context/src/main/java/org/springframework/remoting/rmi/package-info.java deleted file mode 100644 index 8296464c34..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Remoting classes for conventional RMI and transparent remoting via - * RMI invokers. Provides a proxy factory for accessing RMI services, - * and an exporter for making beans available to RMI clients. - */ -package org.springframework.remoting.rmi; diff --git a/spring-context/src/main/java/org/springframework/remoting/soap/SoapFaultException.java b/spring-context/src/main/java/org/springframework/remoting/soap/SoapFaultException.java deleted file mode 100644 index 175c351cf3..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/soap/SoapFaultException.java +++ /dev/null @@ -1,65 +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.soap; - -import javax.xml.namespace.QName; - -import org.springframework.remoting.RemoteInvocationFailureException; - -/** - * RemoteInvocationFailureException subclass that provides the details - * of a SOAP fault. - * - * @author Juergen Hoeller - * @since 2.5 - * @see javax.xml.rpc.soap.SOAPFaultException - * @see javax.xml.ws.soap.SOAPFaultException - */ -@SuppressWarnings("serial") -public abstract class SoapFaultException extends RemoteInvocationFailureException { - - /** - * Constructor for SoapFaultException. - * @param msg the detail message - * @param cause the root cause from the SOAP API in use - */ - protected SoapFaultException(String msg, Throwable cause) { - super(msg, cause); - } - - - /** - * Return the SOAP fault code. - */ - public abstract String getFaultCode(); - - /** - * Return the SOAP fault code as a {@code QName} object. - */ - public abstract QName getFaultCodeAsQName(); - - /** - * Return the descriptive SOAP fault string. - */ - public abstract String getFaultString(); - - /** - * Return the actor that caused this fault. - */ - public abstract String getFaultActor(); - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/soap/package-info.java b/spring-context/src/main/java/org/springframework/remoting/soap/package-info.java deleted file mode 100644 index e1e1107409..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/soap/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * SOAP-specific exceptions and support classes for Spring's remoting subsystem. - */ -package org.springframework.remoting.soap; diff --git a/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java b/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java deleted file mode 100644 index 870fe87ff1..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationExecutor.java +++ /dev/null @@ -1,42 +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.support; - -import java.lang.reflect.InvocationTargetException; - -import org.springframework.util.Assert; - -/** - * Default implementation of the {@link RemoteInvocationExecutor} interface. - * Simply delegates to {@link RemoteInvocation}'s invoke method. - * - * @author Juergen Hoeller - * @since 1.1 - * @see RemoteInvocation#invoke - */ -public class DefaultRemoteInvocationExecutor implements RemoteInvocationExecutor { - - @Override - public Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException{ - - Assert.notNull(invocation, "RemoteInvocation must not be null"); - Assert.notNull(targetObject, "Target object must not be null"); - return invocation.invoke(targetObject); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java b/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java deleted file mode 100644 index 10f3ab184a..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/DefaultRemoteInvocationFactory.java +++ /dev/null @@ -1,35 +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.support; - -import org.aopalliance.intercept.MethodInvocation; - -/** - * Default implementation of the {@link RemoteInvocationFactory} interface. - * Simply creates a new standard {@link RemoteInvocation} object. - * - * @author Juergen Hoeller - * @since 1.1 - */ -public class DefaultRemoteInvocationFactory implements RemoteInvocationFactory { - - @Override - public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { - return new RemoteInvocation(methodInvocation); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteAccessor.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteAccessor.java deleted file mode 100644 index f26ca9a849..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteAccessor.java +++ /dev/null @@ -1,63 +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.support; - -import org.springframework.util.Assert; - -/** - * Abstract base class for classes that access a remote service. - * Provides a "serviceInterface" bean property. - * - *

Note that the service interface being used will show some signs of - * remotability, like the granularity of method calls that it offers. - * Furthermore, it has to have serializable arguments etc. - * - *

Accessors are supposed to throw Spring's generic - * {@link org.springframework.remoting.RemoteAccessException} in case - * of remote invocation failure, provided that the service interface - * does not declare {@code java.rmi.RemoteException}. - * - * @author Juergen Hoeller - * @since 13.05.2003 - * @see org.springframework.remoting.RemoteAccessException - * @see java.rmi.RemoteException - */ -public abstract class RemoteAccessor extends RemotingSupport { - - private Class serviceInterface; - - - /** - * Set the interface of the service to access. - * The interface must be suitable for the particular service and remoting strategy. - *

Typically required to be able to create a suitable service proxy, - * but can also be optional if the lookup returns a typed proxy. - */ - public void setServiceInterface(Class serviceInterface) { - Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); - Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); - this.serviceInterface = serviceInterface; - } - - /** - * Return the interface of the service to access. - */ - public Class getServiceInterface() { - return this.serviceInterface; - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteExporter.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteExporter.java deleted file mode 100644 index 2c590ff548..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteExporter.java +++ /dev/null @@ -1,186 +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.support; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry; -import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * Abstract base class for classes that export a remote service. - * Provides "service" and "serviceInterface" bean properties. - * - *

Note that the service interface being used will show some signs of - * remotability, like the granularity of method calls that it offers. - * Furthermore, it has to have serializable arguments etc. - * - * @author Juergen Hoeller - * @since 26.12.2003 - */ -public abstract class RemoteExporter extends RemotingSupport { - - private Object service; - - private Class serviceInterface; - - private Boolean registerTraceInterceptor; - - private Object[] interceptors; - - - /** - * Set the service to export. - * Typically populated via a bean reference. - */ - public void setService(Object service) { - this.service = service; - } - - /** - * Return the service to export. - */ - public Object getService() { - return this.service; - } - - /** - * Set the interface of the service to export. - * The interface must be suitable for the particular service and remoting strategy. - */ - public void setServiceInterface(Class serviceInterface) { - Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); - Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); - this.serviceInterface = serviceInterface; - } - - /** - * Return the interface of the service to export. - */ - public Class getServiceInterface() { - return this.serviceInterface; - } - - /** - * Set whether to register a RemoteInvocationTraceInterceptor for exported - * services. Only applied when a subclass uses {@code getProxyForService} - * for creating the proxy to expose. - *

Default is "true". RemoteInvocationTraceInterceptor's most important value - * is that it logs exception stacktraces on the server, before propagating an - * exception to the client. Note that RemoteInvocationTraceInterceptor will not - * be registered by default if the "interceptors" property has been specified. - * @see #setInterceptors - * @see #getProxyForService - * @see RemoteInvocationTraceInterceptor - */ - public void setRegisterTraceInterceptor(boolean registerTraceInterceptor) { - this.registerTraceInterceptor = registerTraceInterceptor; - } - - /** - * Set additional interceptors (or advisors) to be applied before the - * remote endpoint, e.g. a PerformanceMonitorInterceptor. - *

You may specify any AOP Alliance MethodInterceptors or other - * Spring AOP Advices, as well as Spring AOP Advisors. - * @see #getProxyForService - * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor - */ - public void setInterceptors(Object[] interceptors) { - this.interceptors = interceptors; - } - - - /** - * Check whether the service reference has been set. - * @see #setService - */ - protected void checkService() throws IllegalArgumentException { - Assert.notNull(getService(), "Property 'service' is required"); - } - - /** - * Check whether a service reference has been set, - * and whether it matches the specified service. - * @see #setServiceInterface - * @see #setService - */ - protected void checkServiceInterface() throws IllegalArgumentException { - Class serviceInterface = getServiceInterface(); - Assert.notNull(serviceInterface, "Property 'serviceInterface' is required"); - - Object service = getService(); - if (service instanceof String) { - throw new IllegalArgumentException("Service [" + service + "] is a String " + - "rather than an actual service reference: Have you accidentally specified " + - "the service bean name as value instead of as reference?"); - } - if (!serviceInterface.isInstance(service)) { - throw new IllegalArgumentException("Service interface [" + serviceInterface.getName() + - "] needs to be implemented by service [" + service + "] of class [" + - service.getClass().getName() + "]"); - } - } - - /** - * Get a proxy for the given service object, implementing the specified - * service interface. - *

Used to export a proxy that does not expose any internals but just - * a specific interface intended for remote access. Furthermore, a - * {@link RemoteInvocationTraceInterceptor} will be registered (by default). - * @return the proxy - * @see #setServiceInterface - * @see #setRegisterTraceInterceptor - * @see RemoteInvocationTraceInterceptor - */ - protected Object getProxyForService() { - checkService(); - checkServiceInterface(); - - ProxyFactory proxyFactory = new ProxyFactory(); - proxyFactory.addInterface(getServiceInterface()); - - if (this.registerTraceInterceptor != null ? this.registerTraceInterceptor : this.interceptors == null) { - proxyFactory.addAdvice(new RemoteInvocationTraceInterceptor(getExporterName())); - } - if (this.interceptors != null) { - AdvisorAdapterRegistry adapterRegistry = GlobalAdvisorAdapterRegistry.getInstance(); - for (Object interceptor : this.interceptors) { - proxyFactory.addAdvisor(adapterRegistry.wrap(interceptor)); - } - } - - proxyFactory.setTarget(getService()); - proxyFactory.setOpaque(true); - - return proxyFactory.getProxy(getBeanClassLoader()); - } - - /** - * Return a short name for this exporter. - * Used for tracing of remote invocations. - *

Default is the unqualified class name (without package). - * Can be overridden in subclasses. - * @see #getProxyForService - * @see RemoteInvocationTraceInterceptor - * @see org.springframework.util.ClassUtils#getShortName - */ - protected String getExporterName() { - return ClassUtils.getShortName(getClass()); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocation.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocation.java deleted file mode 100644 index fec43c6bb2..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocation.java +++ /dev/null @@ -1,225 +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.support; - -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; - -/** - * Encapsulates a remote invocation, providing core method invocation properties - * in a serializable fashion. Used for RMI and HTTP-based serialization invokers. - * - *

This is an SPI class, typically not used directly by applications. - * Can be subclassed for additional invocation parameters. - * - *

Both {@link RemoteInvocation} and {@link RemoteInvocationResult} are designed - * for use with standard Java serialization as well as JavaBean-style serialization. - * - * @author Juergen Hoeller - * @since 25.02.2004 - * @see RemoteInvocationResult - * @see RemoteInvocationFactory - * @see RemoteInvocationExecutor - * @see org.springframework.remoting.rmi.RmiProxyFactoryBean - * @see org.springframework.remoting.rmi.RmiServiceExporter - * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean - * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter - */ -public class RemoteInvocation implements Serializable { - - /** use serialVersionUID from Spring 1.1 for interoperability. */ - private static final long serialVersionUID = 6876024250231820554L; - - - private String methodName; - - private Class[] parameterTypes; - - private Object[] arguments; - - private Map attributes; - - - /** - * Create a new RemoteInvocation for the given AOP method invocation. - * @param methodInvocation the AOP invocation to convert - */ - public RemoteInvocation(MethodInvocation methodInvocation) { - this.methodName = methodInvocation.getMethod().getName(); - this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); - this.arguments = methodInvocation.getArguments(); - } - - /** - * Create a new RemoteInvocation for the given parameters. - * @param methodName the name of the method to invoke - * @param parameterTypes the parameter types of the method - * @param arguments the arguments for the invocation - */ - public RemoteInvocation(String methodName, Class[] parameterTypes, Object[] arguments) { - this.methodName = methodName; - this.parameterTypes = parameterTypes; - this.arguments = arguments; - } - - /** - * Create a new RemoteInvocation for JavaBean-style deserialization - * (e.g. with Jackson). - */ - public RemoteInvocation() { - } - - - /** - * Set the name of the target method. - *

This setter is intended for JavaBean-style deserialization. - */ - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - /** - * Return the name of the target method. - */ - public String getMethodName() { - return this.methodName; - } - - /** - * Set the parameter types of the target method. - *

This setter is intended for JavaBean-style deserialization. - */ - public void setParameterTypes(Class[] parameterTypes) { - this.parameterTypes = parameterTypes; - } - - /** - * Return the parameter types of the target method. - */ - public Class[] getParameterTypes() { - return this.parameterTypes; - } - - /** - * Set the arguments for the target method call. - *

This setter is intended for JavaBean-style deserialization. - */ - public void setArguments(Object[] arguments) { - this.arguments = arguments; - } - - /** - * Return the arguments for the target method call. - */ - public Object[] getArguments() { - return this.arguments; - } - - - /** - * Add an additional invocation attribute. Useful to add additional - * invocation context without having to subclass RemoteInvocation. - *

Attribute keys have to be unique, and no overriding of existing - * attributes is allowed. - *

The implementation avoids to unnecessarily create the attributes - * Map, to minimize serialization size. - * @param key the attribute key - * @param value the attribute value - * @throws IllegalStateException if the key is already bound - */ - public void addAttribute(String key, Serializable value) throws IllegalStateException { - if (this.attributes == null) { - this.attributes = new HashMap<>(); - } - if (this.attributes.containsKey(key)) { - throw new IllegalStateException("There is already an attribute with key '" + key + "' bound"); - } - this.attributes.put(key, value); - } - - /** - * Retrieve the attribute for the given key, if any. - *

The implementation avoids to unnecessarily create the attributes - * Map, to minimize serialization size. - * @param key the attribute key - * @return the attribute value, or {@code null} if not defined - */ - @Nullable - public Serializable getAttribute(String key) { - if (this.attributes == null) { - return null; - } - return this.attributes.get(key); - } - - /** - * Set the attributes Map. Only here for special purposes: - * Preferably, use {@link #addAttribute} and {@link #getAttribute}. - * @param attributes the attributes Map - * @see #addAttribute - * @see #getAttribute - */ - public void setAttributes(@Nullable Map attributes) { - this.attributes = attributes; - } - - /** - * Return the attributes Map. Mainly here for debugging purposes: - * Preferably, use {@link #addAttribute} and {@link #getAttribute}. - * @return the attributes Map, or {@code null} if none created - * @see #addAttribute - * @see #getAttribute - */ - @Nullable - public Map getAttributes() { - return this.attributes; - } - - - /** - * Perform this invocation on the given target object. - * Typically called when a RemoteInvocation is received on the server. - * @param targetObject the target object to apply the invocation to - * @return the invocation result - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - * @see java.lang.reflect.Method#invoke - */ - public Object invoke(Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes); - return method.invoke(targetObject, this.arguments); - } - - - @Override - public String toString() { - return "RemoteInvocation: method name '" + this.methodName + "'; parameter types " + - ClassUtils.classNamesToString(this.parameterTypes); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java deleted file mode 100644 index c7f58152c0..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedAccessor.java +++ /dev/null @@ -1,91 +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.support; - -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.lang.Nullable; - -/** - * Abstract base class for remote service accessors that are based - * on serialization of {@link RemoteInvocation} objects. - * - * Provides a "remoteInvocationFactory" property, with a - * {@link DefaultRemoteInvocationFactory} as default strategy. - * - * @author Juergen Hoeller - * @since 1.1 - * @see #setRemoteInvocationFactory - * @see RemoteInvocation - * @see RemoteInvocationFactory - * @see DefaultRemoteInvocationFactory - */ -public abstract class RemoteInvocationBasedAccessor extends UrlBasedRemoteAccessor { - - private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); - - - /** - * Set the RemoteInvocationFactory to use for this accessor. - * Default is a {@link DefaultRemoteInvocationFactory}. - *

A custom invocation factory can add further context information - * to the invocation, for example user credentials. - */ - public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) { - this.remoteInvocationFactory = - (remoteInvocationFactory != null ? remoteInvocationFactory : new DefaultRemoteInvocationFactory()); - } - - /** - * Return the RemoteInvocationFactory used by this accessor. - */ - public RemoteInvocationFactory getRemoteInvocationFactory() { - return this.remoteInvocationFactory; - } - - /** - * Create a new RemoteInvocation object for the given AOP method invocation. - *

The default implementation delegates to the configured - * {@link #setRemoteInvocationFactory RemoteInvocationFactory}. - * This can be overridden in subclasses in order to provide custom RemoteInvocation - * subclasses, containing additional invocation parameters (e.g. user credentials). - *

Note that it is preferable to build a custom RemoteInvocationFactory - * as a reusable strategy, instead of overriding this method. - * @param methodInvocation the current AOP method invocation - * @return the RemoteInvocation object - * @see RemoteInvocationFactory#createRemoteInvocation - */ - protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { - return getRemoteInvocationFactory().createRemoteInvocation(methodInvocation); - } - - /** - * Recreate the invocation result contained in the given RemoteInvocationResult object. - *

The default implementation calls the default {@code recreate()} method. - * This can be overridden in subclass to provide custom recreation, potentially - * processing the returned result object. - * @param result the RemoteInvocationResult to recreate - * @return a return value if the invocation result is a successful return - * @throws Throwable if the invocation result is an exception - * @see RemoteInvocationResult#recreate() - */ - @Nullable - protected Object recreateRemoteInvocationResult(RemoteInvocationResult result) throws Throwable { - return result.recreate(); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedExporter.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedExporter.java deleted file mode 100644 index a25aae4a74..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationBasedExporter.java +++ /dev/null @@ -1,122 +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.support; - -import java.lang.reflect.InvocationTargetException; - -/** - * Abstract base class for remote service exporters that are based - * on deserialization of {@link RemoteInvocation} objects. - * - *

Provides a "remoteInvocationExecutor" property, with a - * {@link DefaultRemoteInvocationExecutor} as default strategy. - * - * @author Juergen Hoeller - * @since 1.1 - * @see RemoteInvocationExecutor - * @see DefaultRemoteInvocationExecutor - */ -public abstract class RemoteInvocationBasedExporter extends RemoteExporter { - - private RemoteInvocationExecutor remoteInvocationExecutor = new DefaultRemoteInvocationExecutor(); - - - /** - * Set the RemoteInvocationExecutor to use for this exporter. - * Default is a DefaultRemoteInvocationExecutor. - *

A custom invocation executor can extract further context information - * from the invocation, for example user credentials. - */ - public void setRemoteInvocationExecutor(RemoteInvocationExecutor remoteInvocationExecutor) { - this.remoteInvocationExecutor = remoteInvocationExecutor; - } - - /** - * Return the RemoteInvocationExecutor used by this exporter. - */ - public RemoteInvocationExecutor getRemoteInvocationExecutor() { - return this.remoteInvocationExecutor; - } - - - /** - * Apply the given remote invocation to the given target object. - * The default implementation delegates to the RemoteInvocationExecutor. - *

Can be overridden in subclasses for custom invocation behavior, - * possibly for applying additional invocation parameters from a - * custom RemoteInvocation subclass. Note that it is preferable to use - * a custom RemoteInvocationExecutor which is a reusable strategy. - * @param invocation the remote invocation - * @param targetObject the target object to apply the invocation to - * @return the invocation result - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - * @see RemoteInvocationExecutor#invoke - */ - protected Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - - if (logger.isTraceEnabled()) { - logger.trace("Executing " + invocation); - } - try { - return getRemoteInvocationExecutor().invoke(invocation, targetObject); - } - catch (NoSuchMethodException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Could not find target method for " + invocation, ex); - } - throw ex; - } - catch (IllegalAccessException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Could not access target method for " + invocation, ex); - } - throw ex; - } - catch (InvocationTargetException ex) { - if (logger.isDebugEnabled()) { - logger.debug("Target method failed for " + invocation, ex.getTargetException()); - } - throw ex; - } - } - - /** - * Apply the given remote invocation to the given target object, wrapping - * the invocation result in a serializable RemoteInvocationResult object. - * The default implementation creates a plain RemoteInvocationResult. - *

Can be overridden in subclasses for custom invocation behavior, - * for example to return additional context information. Note that this - * is not covered by the RemoteInvocationExecutor strategy! - * @param invocation the remote invocation - * @param targetObject the target object to apply the invocation to - * @return the invocation result - * @see #invoke - */ - protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) { - try { - Object value = invoke(invocation, targetObject); - return new RemoteInvocationResult(value); - } - catch (Throwable ex) { - return new RemoteInvocationResult(ex); - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationExecutor.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationExecutor.java deleted file mode 100644 index 02d456b3a4..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationExecutor.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2007 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.support; - -import java.lang.reflect.InvocationTargetException; - -/** - * Strategy interface for executing a {@link RemoteInvocation} on a target object. - * - *

Used by {@link org.springframework.remoting.rmi.RmiServiceExporter} (for RMI invokers) - * and by {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter}. - * - * @author Juergen Hoeller - * @since 1.1 - * @see DefaultRemoteInvocationFactory - * @see org.springframework.remoting.rmi.RmiServiceExporter#setRemoteInvocationExecutor - * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter#setRemoteInvocationExecutor - */ -public interface RemoteInvocationExecutor { - - /** - * Perform this invocation on the given target object. - * Typically called when a RemoteInvocation is received on the server. - * @param invocation the RemoteInvocation - * @param targetObject the target object to apply the invocation to - * @return the invocation result - * @throws NoSuchMethodException if the method name could not be resolved - * @throws IllegalAccessException if the method could not be accessed - * @throws InvocationTargetException if the method invocation resulted in an exception - * @see java.lang.reflect.Method#invoke - */ - Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException; - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationFactory.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationFactory.java deleted file mode 100644 index 5fba21f81b..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2007 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.support; - -import org.aopalliance.intercept.MethodInvocation; - -/** - * Strategy interface for creating a {@link RemoteInvocation} from an AOP Alliance - * {@link org.aopalliance.intercept.MethodInvocation}. - * - *

Used by {@link org.springframework.remoting.rmi.RmiClientInterceptor} (for RMI invokers) - * and by {@link org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor}. - * - * @author Juergen Hoeller - * @since 1.1 - * @see DefaultRemoteInvocationFactory - * @see org.springframework.remoting.rmi.RmiClientInterceptor#setRemoteInvocationFactory - * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor#setRemoteInvocationFactory - */ -public interface RemoteInvocationFactory { - - /** - * Create a serializable RemoteInvocation object from the given AOP - * MethodInvocation. - *

Can be implemented to add custom context information to the - * remote invocation, for example user credentials. - * @param methodInvocation the original AOP MethodInvocation object - * @return the RemoteInvocation object - */ - RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation); - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationResult.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationResult.java deleted file mode 100644 index 76de6b8b4a..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationResult.java +++ /dev/null @@ -1,164 +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.support; - -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; - -import org.springframework.lang.Nullable; - -/** - * Encapsulates a remote invocation result, holding a result value or an exception. - * Used for HTTP-based serialization invokers. - * - *

This is an SPI class, typically not used directly by applications. - * Can be subclassed for additional invocation parameters. - * - *

Both {@link RemoteInvocation} and {@link RemoteInvocationResult} are designed - * for use with standard Java serialization as well as JavaBean-style serialization. - * - * @author Juergen Hoeller - * @since 1.1 - * @see RemoteInvocation - */ -public class RemoteInvocationResult implements Serializable { - - /** Use serialVersionUID from Spring 1.1 for interoperability. */ - private static final long serialVersionUID = 2138555143707773549L; - - - @Nullable - private Object value; - - @Nullable - private Throwable exception; - - - /** - * Create a new RemoteInvocationResult for the given result value. - * @param value the result value returned by a successful invocation - * of the target method - */ - public RemoteInvocationResult(@Nullable Object value) { - this.value = value; - } - - /** - * Create a new RemoteInvocationResult for the given exception. - * @param exception the exception thrown by an unsuccessful invocation - * of the target method - */ - public RemoteInvocationResult(@Nullable Throwable exception) { - this.exception = exception; - } - - /** - * Create a new RemoteInvocationResult for JavaBean-style deserialization - * (e.g. with Jackson). - * @see #setValue - * @see #setException - */ - public RemoteInvocationResult() { - } - - - /** - * Set the result value returned by a successful invocation of the - * target method, if any. - *

This setter is intended for JavaBean-style deserialization. - * Use {@link #RemoteInvocationResult(Object)} otherwise. - * @see #RemoteInvocationResult() - */ - public void setValue(@Nullable Object value) { - this.value = value; - } - - /** - * Return the result value returned by a successful invocation - * of the target method, if any. - * @see #hasException - */ - @Nullable - public Object getValue() { - return this.value; - } - - /** - * Set the exception thrown by an unsuccessful invocation of the - * target method, if any. - *

This setter is intended for JavaBean-style deserialization. - * Use {@link #RemoteInvocationResult(Throwable)} otherwise. - * @see #RemoteInvocationResult() - */ - public void setException(@Nullable Throwable exception) { - this.exception = exception; - } - - /** - * Return the exception thrown by an unsuccessful invocation - * of the target method, if any. - * @see #hasException - */ - @Nullable - public Throwable getException() { - return this.exception; - } - - /** - * Return whether this invocation result holds an exception. - * If this returns {@code false}, the result value applies - * (even if it is {@code null}). - * @see #getValue - * @see #getException - */ - public boolean hasException() { - return (this.exception != null); - } - - /** - * Return whether this invocation result holds an InvocationTargetException, - * thrown by an invocation of the target method itself. - * @see #hasException() - */ - public boolean hasInvocationTargetException() { - return (this.exception instanceof InvocationTargetException); - } - - - /** - * Recreate the invocation result, either returning the result value - * in case of a successful invocation of the target method, or - * rethrowing the exception thrown by the target method. - * @return the result value, if any - * @throws Throwable the exception, if any - */ - @Nullable - public Object recreate() throws Throwable { - if (this.exception != null) { - Throwable exToThrow = this.exception; - if (this.exception instanceof InvocationTargetException) { - exToThrow = ((InvocationTargetException) this.exception).getTargetException(); - } - RemoteInvocationUtils.fillInClientStackTraceIfPossible(exToThrow); - throw exToThrow; - } - else { - return this.value; - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java deleted file mode 100644 index 2d5dc8e392..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationTraceInterceptor.java +++ /dev/null @@ -1,104 +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.support; - -import java.lang.reflect.Method; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.lang.Nullable; -import org.springframework.util.ClassUtils; - -/** - * AOP Alliance MethodInterceptor for tracing remote invocations. - * Automatically applied by RemoteExporter and its subclasses. - * - *

Logs an incoming remote call as well as the finished processing of a remote call - * at DEBUG level. If the processing of a remote call results in a checked exception, - * the exception will get logged at INFO level; if it results in an unchecked - * exception (or error), the exception will get logged at WARN level. - * - *

The logging of exceptions is particularly useful to save the stacktrace - * information on the server-side rather than just propagating the exception - * to the client (who might or might not log it properly). - * - * @author Juergen Hoeller - * @since 1.2 - * @see RemoteExporter#setRegisterTraceInterceptor - * @see RemoteExporter#getProxyForService - */ -public class RemoteInvocationTraceInterceptor implements MethodInterceptor { - - protected static final Log logger = LogFactory.getLog(RemoteInvocationTraceInterceptor.class); - - private final String exporterNameClause; - - - /** - * Create a new RemoteInvocationTraceInterceptor. - */ - public RemoteInvocationTraceInterceptor() { - this.exporterNameClause = ""; - } - - /** - * Create a new RemoteInvocationTraceInterceptor. - * @param exporterName the name of the remote exporter - * (to be used as context information in log messages) - */ - public RemoteInvocationTraceInterceptor(String exporterName) { - this.exporterNameClause = exporterName + " "; - } - - - @Override - @Nullable - public Object invoke(MethodInvocation invocation) throws Throwable { - Method method = invocation.getMethod(); - if (logger.isDebugEnabled()) { - logger.debug("Incoming " + this.exporterNameClause + "remote call: " + - ClassUtils.getQualifiedMethodName(method)); - } - try { - Object retVal = invocation.proceed(); - if (logger.isDebugEnabled()) { - logger.debug("Finished processing of " + this.exporterNameClause + "remote call: " + - ClassUtils.getQualifiedMethodName(method)); - } - return retVal; - } - catch (Throwable ex) { - if (ex instanceof RuntimeException || ex instanceof Error) { - if (logger.isWarnEnabled()) { - logger.warn("Processing of " + this.exporterNameClause + "remote call resulted in fatal exception: " + - ClassUtils.getQualifiedMethodName(method), ex); - } - } - else { - if (logger.isInfoEnabled()) { - logger.info("Processing of " + this.exporterNameClause + "remote call resulted in exception: " + - ClassUtils.getQualifiedMethodName(method), ex); - } - } - throw ex; - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationUtils.java b/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationUtils.java deleted file mode 100644 index 612b73c2e9..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemoteInvocationUtils.java +++ /dev/null @@ -1,60 +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.support; - -import java.util.HashSet; -import java.util.Set; - -/** - * General utilities for handling remote invocations. - * - *

Mainly intended for use within the remoting framework. - * - * @author Juergen Hoeller - * @since 2.0 - */ -public abstract class RemoteInvocationUtils { - - /** - * Fill the current client-side stack trace into the given exception. - *

The given exception is typically thrown on the server and serialized - * as-is, with the client wanting it to contain the client-side portion - * of the stack trace as well. What we can do here is to update the - * {@code StackTraceElement} array with the current client-side stack - * trace, provided that we run on JDK 1.4+. - * @param ex the exception to update - * @see Throwable#getStackTrace() - * @see Throwable#setStackTrace(StackTraceElement[]) - */ - public static void fillInClientStackTraceIfPossible(Throwable ex) { - if (ex != null) { - StackTraceElement[] clientStack = new Throwable().getStackTrace(); - Set visitedExceptions = new HashSet<>(); - Throwable exToUpdate = ex; - while (exToUpdate != null && !visitedExceptions.contains(exToUpdate)) { - StackTraceElement[] serverStack = exToUpdate.getStackTrace(); - StackTraceElement[] combinedStack = new StackTraceElement[serverStack.length + clientStack.length]; - System.arraycopy(serverStack, 0, combinedStack, 0, serverStack.length); - System.arraycopy(clientStack, 0, combinedStack, serverStack.length, clientStack.length); - exToUpdate.setStackTrace(combinedStack); - visitedExceptions.add(exToUpdate); - exToUpdate = exToUpdate.getCause(); - } - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/RemotingSupport.java b/spring-context/src/main/java/org/springframework/remoting/support/RemotingSupport.java deleted file mode 100644 index 51acfdf4f4..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/RemotingSupport.java +++ /dev/null @@ -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.support; - -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.util.ClassUtils; - -/** - * Generic support base class for remote accessor and exporters, - * providing common bean ClassLoader handling. - * - * @author Juergen Hoeller - * @since 2.5.2 - */ -public abstract class RemotingSupport implements BeanClassLoaderAware { - - /** Logger available to subclasses. */ - protected final Log logger = LogFactory.getLog(getClass()); - - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - /** - * Return the ClassLoader that this accessor operates in, - * to be used for deserializing and for generating proxies. - */ - protected ClassLoader getBeanClassLoader() { - return this.beanClassLoader; - } - - - /** - * Override the thread context ClassLoader with the environment's bean ClassLoader - * if necessary, i.e. if the bean ClassLoader is not equivalent to the thread - * context ClassLoader already. - * @return the original thread context ClassLoader, or {@code null} if not overridden - */ - @Nullable - protected ClassLoader overrideThreadContextClassLoader() { - return ClassUtils.overrideThreadContextClassLoader(getBeanClassLoader()); - } - - /** - * Reset the original thread context ClassLoader if necessary. - * @param original the original thread context ClassLoader, - * or {@code null} if not overridden (and hence nothing to reset) - */ - protected void resetThreadContextClassLoader(@Nullable ClassLoader original) { - if (original != null) { - Thread.currentThread().setContextClassLoader(original); - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java b/spring-context/src/main/java/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java deleted file mode 100644 index f72fb9fdba..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/SimpleHttpServerFactoryBean.java +++ /dev/null @@ -1,194 +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.support; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -import com.sun.net.httpserver.Authenticator; -import com.sun.net.httpserver.Filter; -import com.sun.net.httpserver.HttpContext; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; - -/** - * {@link org.springframework.beans.factory.FactoryBean} that creates a simple - * HTTP server, based on the HTTP server that is included in Sun's JRE 1.6. - * Starts the HTTP server on initialization and stops it on destruction. - * Exposes the resulting {@link com.sun.net.httpserver.HttpServer} object. - * - *

Allows for registering {@link com.sun.net.httpserver.HttpHandler HttpHandlers} - * for specific {@link #setContexts context paths}. Alternatively, - * register such context-specific handlers programmatically on the - * {@link com.sun.net.httpserver.HttpServer} itself. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @since 2.5.1 - * @see #setPort - * @see #setContexts - * @deprecated as of Spring Framework 5.1, in favor of embedded Tomcat/Jetty/Undertow - */ -@Deprecated -@org.springframework.lang.UsesSunHttpServer -public class SimpleHttpServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean { - - protected final Log logger = LogFactory.getLog(getClass()); - - private int port = 8080; - - private String hostname; - - private int backlog = -1; - - private int shutdownDelay = 0; - - private Executor executor; - - private Map contexts; - - private List filters; - - private Authenticator authenticator; - - private HttpServer server; - - - /** - * Specify the HTTP server's port. Default is 8080. - */ - 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. - */ - public void setHostname(String hostname) { - this.hostname = hostname; - } - - /** - * Specify the HTTP server's TCP backlog. Default is -1, - * indicating the system's default value. - */ - 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. - */ - public void setShutdownDelay(int shutdownDelay) { - this.shutdownDelay = shutdownDelay; - } - - /** - * Set the JDK concurrent executor to use for dispatching incoming requests. - * @see com.sun.net.httpserver.HttpServer#setExecutor - */ - public void setExecutor(Executor executor) { - this.executor = executor; - } - - /** - * Register {@link com.sun.net.httpserver.HttpHandler HttpHandlers} - * for specific context paths. - * @param contexts a Map with context paths as keys and HttpHandler - * objects as values - * @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter - * @see org.springframework.remoting.caucho.SimpleHessianServiceExporter - */ - public void setContexts(Map contexts) { - this.contexts = contexts; - } - - /** - * Register common {@link com.sun.net.httpserver.Filter Filters} to be - * applied to all locally registered {@link #setContexts contexts}. - */ - public void setFilters(List filters) { - this.filters = filters; - } - - /** - * Register a common {@link com.sun.net.httpserver.Authenticator} to be - * applied to all locally registered {@link #setContexts contexts}. - */ - public void setAuthenticator(Authenticator authenticator) { - this.authenticator = authenticator; - } - - - @Override - public void afterPropertiesSet() throws IOException { - InetSocketAddress address = (this.hostname != null ? - new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port)); - this.server = HttpServer.create(address, this.backlog); - if (this.executor != null) { - this.server.setExecutor(this.executor); - } - if (this.contexts != null) { - this.contexts.forEach((key, context) -> { - HttpContext httpContext = this.server.createContext(key, context); - if (this.filters != null) { - httpContext.getFilters().addAll(this.filters); - } - if (this.authenticator != null) { - httpContext.setAuthenticator(this.authenticator); - } - }); - } - if (logger.isInfoEnabled()) { - logger.info("Starting HttpServer at address " + address); - } - this.server.start(); - } - - @Override - public HttpServer getObject() { - return this.server; - } - - @Override - public Class getObjectType() { - return (this.server != null ? this.server.getClass() : HttpServer.class); - } - - @Override - public boolean isSingleton() { - return true; - } - - @Override - public void destroy() { - logger.info("Stopping HttpServer"); - this.server.stop(this.shutdownDelay); - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/UrlBasedRemoteAccessor.java b/spring-context/src/main/java/org/springframework/remoting/support/UrlBasedRemoteAccessor.java deleted file mode 100644 index 93c65ac220..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/UrlBasedRemoteAccessor.java +++ /dev/null @@ -1,56 +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.support; - -import org.springframework.beans.factory.InitializingBean; - -/** - * Abstract base class for classes that access remote services via URLs. - * Provides a "serviceUrl" bean property, which is considered as required. - * - * @author Juergen Hoeller - * @since 15.12.2003 - */ -public abstract class UrlBasedRemoteAccessor extends RemoteAccessor implements InitializingBean { - - private String serviceUrl; - - - /** - * Set the URL of this remote accessor's target service. - * The URL must be compatible with the rules of the particular remoting provider. - */ - public void setServiceUrl(String serviceUrl) { - this.serviceUrl = serviceUrl; - } - - /** - * Return the URL of this remote accessor's target service. - */ - public String getServiceUrl() { - return this.serviceUrl; - } - - - @Override - public void afterPropertiesSet() { - if (getServiceUrl() == null) { - throw new IllegalArgumentException("Property 'serviceUrl' is required"); - } - } - -} diff --git a/spring-context/src/main/java/org/springframework/remoting/support/package-info.java b/spring-context/src/main/java/org/springframework/remoting/support/package-info.java deleted file mode 100644 index 316306149a..0000000000 --- a/spring-context/src/main/java/org/springframework/remoting/support/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Generic support classes for remoting implementations. - * Provides abstract base classes for remote proxy factories. - */ -package org.springframework.remoting.support; diff --git a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java b/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java deleted file mode 100644 index 82780251a5..0000000000 --- a/spring-context/src/test/java/org/springframework/remoting/rmi/RmiSupportTests.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright 2002-2019 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.rmi; - -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.rmi.ConnectException; -import java.rmi.ConnectIOException; -import java.rmi.MarshalException; -import java.rmi.NoSuchObjectException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.StubNotFoundException; -import java.rmi.UnknownHostException; -import java.rmi.UnmarshalException; - -import org.aopalliance.intercept.MethodInvocation; -import org.junit.jupiter.api.Test; - -import org.springframework.remoting.RemoteAccessException; -import org.springframework.remoting.RemoteConnectFailureException; -import org.springframework.remoting.RemoteProxyFailureException; -import org.springframework.remoting.support.RemoteInvocation; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -/** - * @author Juergen Hoeller - * @since 16.05.2003 - */ -public class RmiSupportTests { - - @Test - public void rmiProxyFactoryBean() throws Exception { - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IRemoteBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.afterPropertiesSet(); - assertThat(factory.isSingleton()).as("Correct singleton value").isTrue(); - boolean condition = factory.getObject() instanceof IRemoteBean; - assertThat(condition).isTrue(); - IRemoteBean proxy = (IRemoteBean) factory.getObject(); - proxy.setName("myName"); - assertThat(RemoteBean.name).isEqualTo("myName"); - assertThat(factory.counter).isEqualTo(1); - } - - @Test - public void rmiProxyFactoryBeanWithRemoteException() throws Exception { - doTestRmiProxyFactoryBeanWithException(RemoteException.class); - } - - @Test - public void rmiProxyFactoryBeanWithConnectException() throws Exception { - doTestRmiProxyFactoryBeanWithException(ConnectException.class); - } - - @Test - public void rmiProxyFactoryBeanWithConnectIOException() throws Exception { - doTestRmiProxyFactoryBeanWithException(ConnectIOException.class); - } - - @Test - public void rmiProxyFactoryBeanWithUnknownHostException() throws Exception { - doTestRmiProxyFactoryBeanWithException(UnknownHostException.class); - } - - @Test - public void rmiProxyFactoryBeanWithNoSuchObjectException() throws Exception { - doTestRmiProxyFactoryBeanWithException(NoSuchObjectException.class); - } - - @Test - public void rmiProxyFactoryBeanWithStubNotFoundException() throws Exception { - doTestRmiProxyFactoryBeanWithException(StubNotFoundException.class); - } - - @Test - public void rmiProxyFactoryBeanWithMarshalException() throws Exception { - doTestRmiProxyFactoryBeanWithException(MarshalException.class); - } - - @Test - public void rmiProxyFactoryBeanWithUnmarshalException() throws Exception { - doTestRmiProxyFactoryBeanWithException(UnmarshalException.class); - } - - private void doTestRmiProxyFactoryBeanWithException(Class exceptionClass) throws Exception { - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IRemoteBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IRemoteBean; - assertThat(condition).isTrue(); - IRemoteBean proxy = (IRemoteBean) factory.getObject(); - assertThatExceptionOfType(exceptionClass).isThrownBy(() -> - proxy.setName(exceptionClass.getName())); - assertThat(factory.counter).isEqualTo(1); - } - - @Test - public void rmiProxyFactoryBeanWithConnectExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithExceptionAndRefresh(ConnectException.class); - } - - @Test - public void rmiProxyFactoryBeanWithConnectIOExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithExceptionAndRefresh(ConnectIOException.class); - } - - @Test - public void rmiProxyFactoryBeanWithUnknownHostExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithExceptionAndRefresh(UnknownHostException.class); - } - - @Test - public void rmiProxyFactoryBeanWithNoSuchObjectExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithExceptionAndRefresh(NoSuchObjectException.class); - } - - @Test - public void rmiProxyFactoryBeanWithStubNotFoundExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithExceptionAndRefresh(StubNotFoundException.class); - } - - private void doTestRmiProxyFactoryBeanWithExceptionAndRefresh(Class exceptionClass) throws Exception { - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IRemoteBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.setRefreshStubOnConnectFailure(true); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IRemoteBean; - assertThat(condition).isTrue(); - IRemoteBean proxy = (IRemoteBean) factory.getObject(); - assertThatExceptionOfType(exceptionClass).isThrownBy(() -> - proxy.setName(exceptionClass.getName())); - assertThat(factory.counter).isEqualTo(2); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterface() throws Exception { - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IBusinessBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IBusinessBean; - assertThat(condition).isTrue(); - IBusinessBean proxy = (IBusinessBean) factory.getObject(); - boolean condition1 = proxy instanceof IRemoteBean; - assertThat(condition1).isFalse(); - proxy.setName("myName"); - assertThat(RemoteBean.name).isEqualTo("myName"); - assertThat(factory.counter).isEqualTo(1); - } - - @Test - public void rmiProxyFactoryBeanWithWrongBusinessInterface() throws Exception { - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IWrongBusinessBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IWrongBusinessBean; - assertThat(condition).isTrue(); - IWrongBusinessBean proxy = (IWrongBusinessBean) factory.getObject(); - boolean condition1 = proxy instanceof IRemoteBean; - assertThat(condition1).isFalse(); - assertThatExceptionOfType(RemoteProxyFailureException.class).isThrownBy(() -> - proxy.setOtherName("name")) - .withCauseInstanceOf(NoSuchMethodException.class) - .withMessageContaining("setOtherName") - .withMessageContaining("IWrongBusinessBean"); - assertThat(factory.counter).isEqualTo(1); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndRemoteException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - RemoteException.class, RemoteAccessException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndConnectException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - ConnectException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndConnectIOException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - ConnectIOException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndUnknownHostException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - UnknownHostException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndNoSuchObjectExceptionException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - NoSuchObjectException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndStubNotFoundException() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - StubNotFoundException.class, RemoteConnectFailureException.class); - } - - private void doTestRmiProxyFactoryBeanWithBusinessInterfaceAndException( - Class rmiExceptionClass, Class springExceptionClass) throws Exception { - - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IBusinessBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IBusinessBean; - assertThat(condition).isTrue(); - IBusinessBean proxy = (IBusinessBean) factory.getObject(); - boolean condition1 = proxy instanceof IRemoteBean; - assertThat(condition1).isFalse(); - assertThatExceptionOfType(springExceptionClass).isThrownBy(() -> - proxy.setName(rmiExceptionClass.getName())); - assertThat(factory.counter).isEqualTo(1); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndRemoteExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - RemoteException.class, RemoteAccessException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndConnectExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - ConnectException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndConnectIOExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - ConnectIOException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndUnknownHostExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - UnknownHostException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndNoSuchObjectExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - NoSuchObjectException.class, RemoteConnectFailureException.class); - } - - @Test - public void rmiProxyFactoryBeanWithBusinessInterfaceAndStubNotFoundExceptionAndRefresh() throws Exception { - doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - StubNotFoundException.class, RemoteConnectFailureException.class); - } - - private void doTestRmiProxyFactoryBeanWithBusinessInterfaceAndExceptionAndRefresh( - Class rmiExceptionClass, Class springExceptionClass) throws Exception { - - CountingRmiProxyFactoryBean factory = new CountingRmiProxyFactoryBean(); - factory.setServiceInterface(IBusinessBean.class); - factory.setServiceUrl("rmi://localhost:1090/test"); - factory.setRefreshStubOnConnectFailure(true); - factory.afterPropertiesSet(); - boolean condition = factory.getObject() instanceof IBusinessBean; - assertThat(condition).isTrue(); - IBusinessBean proxy = (IBusinessBean) factory.getObject(); - boolean condition1 = proxy instanceof IRemoteBean; - assertThat(condition1).isFalse(); - assertThatExceptionOfType(springExceptionClass).isThrownBy(() -> - proxy.setName(rmiExceptionClass.getName())); - boolean isRemoteConnectFailure = RemoteConnectFailureException.class.isAssignableFrom(springExceptionClass); - assertThat(factory.counter).isEqualTo(isRemoteConnectFailure ? 2 : 1); - } - - @Test - public void rmiClientInterceptorRequiresUrl() throws Exception{ - RmiClientInterceptor client = new RmiClientInterceptor(); - client.setServiceInterface(IRemoteBean.class); - assertThatIllegalArgumentException().isThrownBy(client::afterPropertiesSet); - } - - @Test - public void remoteInvocation() throws NoSuchMethodException { - // let's see if the remote invocation object works - - final RemoteBean rb = new RemoteBean(); - final Method setNameMethod = rb.getClass().getDeclaredMethod("setName", String.class); - - MethodInvocation mi = new MethodInvocation() { - @Override - public Method getMethod() { - return setNameMethod; - } - @Override - public Object[] getArguments() { - return new Object[] {"bla"}; - } - @Override - public Object proceed() throws Throwable { - throw new UnsupportedOperationException(); - } - @Override - public Object getThis() { - return rb; - } - @Override - public AccessibleObject getStaticPart() { - return setNameMethod; - } - }; - - RemoteInvocation inv = new RemoteInvocation(mi); - - assertThat(inv.getMethodName()).isEqualTo("setName"); - assertThat(inv.getArguments()[0]).isEqualTo("bla"); - assertThat(inv.getParameterTypes()[0]).isEqualTo(String.class); - - // this is a bit BS, but we need to test it - inv = new RemoteInvocation(); - inv.setArguments(new Object[] { "bla" }); - assertThat(inv.getArguments()[0]).isEqualTo("bla"); - inv.setMethodName("setName"); - assertThat(inv.getMethodName()).isEqualTo("setName"); - inv.setParameterTypes(new Class[] {String.class}); - assertThat(inv.getParameterTypes()[0]).isEqualTo(String.class); - - inv = new RemoteInvocation("setName", new Class[] {String.class}, new Object[] {"bla"}); - assertThat(inv.getArguments()[0]).isEqualTo("bla"); - assertThat(inv.getMethodName()).isEqualTo("setName"); - assertThat(inv.getParameterTypes()[0]).isEqualTo(String.class); - } - - @Test - public void rmiInvokerWithSpecialLocalMethods() throws Exception { - String serviceUrl = "rmi://localhost:1090/test"; - RmiProxyFactoryBean factory = new RmiProxyFactoryBean() { - @Override - protected Remote lookupStub() { - return new RmiInvocationHandler() { - @Override - public String getTargetInterfaceName() { - return null; - } - @Override - public Object invoke(RemoteInvocation invocation) throws RemoteException { - throw new RemoteException(); - } - }; - } - }; - factory.setServiceInterface(IBusinessBean.class); - factory.setServiceUrl(serviceUrl); - factory.afterPropertiesSet(); - IBusinessBean proxy = (IBusinessBean) factory.getObject(); - - // shouldn't go through to remote service - assertThat(proxy.toString().contains("RMI invoker")).isTrue(); - assertThat(proxy.toString().contains(serviceUrl)).isTrue(); - assertThat(proxy.hashCode()).isEqualTo(proxy.hashCode()); - assertThat(proxy.equals(proxy)).isTrue(); - - // should go through - assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(() -> - proxy.setName("test")); - } - - - private static class CountingRmiProxyFactoryBean extends RmiProxyFactoryBean { - - private int counter = 0; - - @Override - protected Remote lookupStub() { - counter++; - return new RemoteBean(); - } - } - - - public interface IBusinessBean { - - void setName(String name); - } - - - public interface IWrongBusinessBean { - - void setOtherName(String name); - } - - - public interface IRemoteBean extends Remote { - - void setName(String name) throws RemoteException; - } - - - public static class RemoteBean implements IRemoteBean { - - private static String name; - - @Override - public void setName(String nam) throws RemoteException { - if (nam != null && nam.endsWith("Exception")) { - RemoteException rex; - try { - Class exClass = Class.forName(nam); - Constructor ctor = exClass.getConstructor(String.class); - rex = (RemoteException) ctor.newInstance("myMessage"); - } - catch (Exception ex) { - throw new RemoteException("Illegal exception class name: " + nam, ex); - } - throw rex; - } - name = nam; - } - } - -} diff --git a/spring-context/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java b/spring-context/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java deleted file mode 100644 index dbaa7a4294..0000000000 --- a/spring-context/src/test/java/org/springframework/remoting/support/RemoteInvocationUtilsTests.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2019 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.support; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Rick Evans - */ -public class RemoteInvocationUtilsTests { - - @Test - public void fillInClientStackTraceIfPossibleSunnyDay() throws Exception { - try { - throw new IllegalStateException("Mmm"); - } - catch (Exception ex) { - int originalStackTraceLngth = ex.getStackTrace().length; - RemoteInvocationUtils.fillInClientStackTraceIfPossible(ex); - assertThat(ex.getStackTrace().length > originalStackTraceLngth).as("Stack trace not being filled in").isTrue(); - } - } - - @Test - public void fillInClientStackTraceIfPossibleWithNullThrowable() throws Exception { - // just want to ensure that it doesn't bomb - RemoteInvocationUtils.fillInClientStackTraceIfPossible(null); - } - -} diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java deleted file mode 100644 index 04566b4109..0000000000 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerClientInterceptor.java +++ /dev/null @@ -1,437 +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.jms.remoting; - -import javax.jms.Connection; -import javax.jms.ConnectionFactory; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageFormatException; -import javax.jms.MessageProducer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TemporaryQueue; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.jms.connection.ConnectionFactoryUtils; -import org.springframework.jms.support.JmsUtils; -import org.springframework.jms.support.converter.MessageConverter; -import org.springframework.jms.support.converter.SimpleMessageConverter; -import org.springframework.jms.support.destination.DestinationResolver; -import org.springframework.jms.support.destination.DynamicDestinationResolver; -import org.springframework.lang.Nullable; -import org.springframework.remoting.RemoteAccessException; -import org.springframework.remoting.RemoteInvocationFailureException; -import org.springframework.remoting.RemoteTimeoutException; -import org.springframework.remoting.support.DefaultRemoteInvocationFactory; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationFactory; -import org.springframework.remoting.support.RemoteInvocationResult; -import org.springframework.util.Assert; - -/** - * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a - * JMS-based remote service. - * - *

Serializes remote invocation objects and deserializes remote invocation - * result objects. Uses Java serialization just like RMI, but with the JMS - * provider as communication infrastructure. - * - *

To be configured with a {@link javax.jms.QueueConnectionFactory} and a - * target queue (either as {@link javax.jms.Queue} reference or as queue name). - * - *

Thanks to James Strachan for the original prototype that this - * JMS invoker mechanism was inspired by! - * - * @author Juergen Hoeller - * @author James Strachan - * @author Stephane Nicoll - * @since 2.0 - * @see #setConnectionFactory - * @see #setQueue - * @see #setQueueName - * @see org.springframework.jms.remoting.JmsInvokerServiceExporter - * @see org.springframework.jms.remoting.JmsInvokerProxyFactoryBean - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JmsInvokerClientInterceptor implements MethodInterceptor, InitializingBean { - - @Nullable - private ConnectionFactory connectionFactory; - - @Nullable - private Object queue; - - private DestinationResolver destinationResolver = new DynamicDestinationResolver(); - - private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); - - private MessageConverter messageConverter = new SimpleMessageConverter(); - - private long receiveTimeout = 0; - - - /** - * Set the QueueConnectionFactory to use for obtaining JMS QueueConnections. - */ - public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) { - this.connectionFactory = connectionFactory; - } - - /** - * Return the QueueConnectionFactory to use for obtaining JMS QueueConnections. - */ - @Nullable - protected ConnectionFactory getConnectionFactory() { - return this.connectionFactory; - } - - /** - * Set the target Queue to send invoker requests to. - */ - public void setQueue(Queue queue) { - this.queue = queue; - } - - /** - * Set the name of target queue to send invoker requests to. - *

The specified name will be dynamically resolved via the - * {@link #setDestinationResolver DestinationResolver}. - */ - public void setQueueName(String queueName) { - this.queue = queueName; - } - - /** - * Set the DestinationResolver that is to be used to resolve Queue - * references for this accessor. - *

The default resolver is a {@code DynamicDestinationResolver}. Specify a - * {@code JndiDestinationResolver} for resolving destination names as JNDI locations. - * @see org.springframework.jms.support.destination.DynamicDestinationResolver - * @see org.springframework.jms.support.destination.JndiDestinationResolver - */ - public void setDestinationResolver(@Nullable DestinationResolver destinationResolver) { - this.destinationResolver = - (destinationResolver != null ? destinationResolver : new DynamicDestinationResolver()); - } - - /** - * Set the {@link RemoteInvocationFactory} to use for this accessor. - *

Default is a {@link DefaultRemoteInvocationFactory}. - *

A custom invocation factory can add further context information - * to the invocation, for example user credentials. - */ - public void setRemoteInvocationFactory(@Nullable RemoteInvocationFactory remoteInvocationFactory) { - this.remoteInvocationFactory = - (remoteInvocationFactory != null ? remoteInvocationFactory : new DefaultRemoteInvocationFactory()); - } - - /** - * Specify the {@link MessageConverter} to use for turning - * {@link org.springframework.remoting.support.RemoteInvocation} - * objects into request messages, as well as response messages into - * {@link org.springframework.remoting.support.RemoteInvocationResult} objects. - *

Default is a {@link SimpleMessageConverter}, using a standard JMS - * {@link javax.jms.ObjectMessage} for each invocation / invocation result - * object. - *

Custom implementations may generally adapt {@link java.io.Serializable} - * objects into special kinds of messages, or might be specifically tailored for - * translating {@code RemoteInvocation(Result)s} into specific kinds of messages. - */ - public void setMessageConverter(@Nullable MessageConverter messageConverter) { - this.messageConverter = (messageConverter != null ? messageConverter : new SimpleMessageConverter()); - } - - /** - * Set the timeout to use for receiving the response message for a request - * (in milliseconds). - *

The default is 0, which indicates a blocking receive without timeout. - * @see javax.jms.MessageConsumer#receive(long) - * @see javax.jms.MessageConsumer#receive() - */ - public void setReceiveTimeout(long receiveTimeout) { - this.receiveTimeout = receiveTimeout; - } - - /** - * Return the timeout to use for receiving the response message for a request - * (in milliseconds). - */ - protected long getReceiveTimeout() { - return this.receiveTimeout; - } - - - @Override - public void afterPropertiesSet() { - if (getConnectionFactory() == null) { - throw new IllegalArgumentException("Property 'connectionFactory' is required"); - } - if (this.queue == null) { - throw new IllegalArgumentException("'queue' or 'queueName' is required"); - } - } - - - @Override - @Nullable - public Object invoke(MethodInvocation methodInvocation) throws Throwable { - if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { - return "JMS invoker proxy for queue [" + this.queue + "]"; - } - - RemoteInvocation invocation = createRemoteInvocation(methodInvocation); - RemoteInvocationResult result; - try { - result = executeRequest(invocation); - } - catch (JMSException ex) { - throw convertJmsInvokerAccessException(ex); - } - try { - return recreateRemoteInvocationResult(result); - } - catch (Throwable ex) { - if (result.hasInvocationTargetException()) { - throw ex; - } - else { - throw new RemoteInvocationFailureException("Invocation of method [" + methodInvocation.getMethod() + - "] failed in JMS invoker remote service at queue [" + this.queue + "]", ex); - } - } - } - - /** - * Create a new {@code RemoteInvocation} object for the given AOP method invocation. - *

The default implementation delegates to the {@link RemoteInvocationFactory}. - *

Can be overridden in subclasses to provide custom {@code RemoteInvocation} - * subclasses, containing additional invocation parameters like user credentials. - * Note that it is preferable to use a custom {@code RemoteInvocationFactory} which - * is a reusable strategy. - * @param methodInvocation the current AOP method invocation - * @return the RemoteInvocation object - * @see RemoteInvocationFactory#createRemoteInvocation - */ - protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { - return this.remoteInvocationFactory.createRemoteInvocation(methodInvocation); - } - - /** - * Execute the given remote invocation, sending an invoker request message - * to this accessor's target queue and waiting for a corresponding response. - * @param invocation the RemoteInvocation to execute - * @return the RemoteInvocationResult object - * @throws JMSException in case of JMS failure - * @see #doExecuteRequest - */ - protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws JMSException { - Connection con = createConnection(); - Session session = null; - try { - session = createSession(con); - Queue queueToUse = resolveQueue(session); - Message requestMessage = createRequestMessage(session, invocation); - con.start(); - Message responseMessage = doExecuteRequest(session, queueToUse, requestMessage); - if (responseMessage != null) { - return extractInvocationResult(responseMessage); - } - else { - return onReceiveTimeout(invocation); - } - } - finally { - JmsUtils.closeSession(session); - ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory(), true); - } - } - - /** - * Create a new JMS Connection for this JMS invoker. - */ - protected Connection createConnection() throws JMSException { - ConnectionFactory connectionFactory = getConnectionFactory(); - Assert.state(connectionFactory != null, "No ConnectionFactory set"); - return connectionFactory.createConnection(); - } - - /** - * Create a new JMS Session for this JMS invoker. - */ - protected Session createSession(Connection con) throws JMSException { - return con.createSession(false, Session.AUTO_ACKNOWLEDGE); - } - - /** - * Resolve this accessor's target queue. - * @param session the current JMS Session - * @return the resolved target Queue - * @throws JMSException if resolution failed - */ - protected Queue resolveQueue(Session session) throws JMSException { - if (this.queue instanceof Queue) { - return (Queue) this.queue; - } - else if (this.queue instanceof String) { - return resolveQueueName(session, (String) this.queue); - } - else { - throw new javax.jms.IllegalStateException( - "Queue object [" + this.queue + "] is neither a [javax.jms.Queue] nor a queue name String"); - } - } - - /** - * Resolve the given queue name into a JMS {@link javax.jms.Queue}, - * via this accessor's {@link DestinationResolver}. - * @param session the current JMS Session - * @param queueName the name of the queue - * @return the located Queue - * @throws JMSException if resolution failed - * @see #setDestinationResolver - */ - protected Queue resolveQueueName(Session session, String queueName) throws JMSException { - return (Queue) this.destinationResolver.resolveDestinationName(session, queueName, false); - } - - /** - * Create the invoker request message. - *

The default implementation creates a JMS {@link javax.jms.ObjectMessage} - * for the given RemoteInvocation object. - * @param session the current JMS Session - * @param invocation the remote invocation to send - * @return the JMS Message to send - * @throws JMSException if the message could not be created - */ - protected Message createRequestMessage(Session session, RemoteInvocation invocation) throws JMSException { - return this.messageConverter.toMessage(invocation, session); - } - - /** - * Actually execute the given request, sending the invoker request message - * to the specified target queue and waiting for a corresponding response. - *

The default implementation is based on standard JMS send/receive, - * using a {@link javax.jms.TemporaryQueue} for receiving the response. - * @param session the JMS Session to use - * @param queue the resolved target Queue to send to - * @param requestMessage the JMS Message to send - * @return the RemoteInvocationResult object - * @throws JMSException in case of JMS failure - */ - @Nullable - protected Message doExecuteRequest(Session session, Queue queue, Message requestMessage) throws JMSException { - TemporaryQueue responseQueue = null; - MessageProducer producer = null; - MessageConsumer consumer = null; - try { - responseQueue = session.createTemporaryQueue(); - producer = session.createProducer(queue); - consumer = session.createConsumer(responseQueue); - requestMessage.setJMSReplyTo(responseQueue); - producer.send(requestMessage); - long timeout = getReceiveTimeout(); - return (timeout > 0 ? consumer.receive(timeout) : consumer.receive()); - } - finally { - JmsUtils.closeMessageConsumer(consumer); - JmsUtils.closeMessageProducer(producer); - if (responseQueue != null) { - responseQueue.delete(); - } - } - } - - /** - * Extract the invocation result from the response message. - *

The default implementation expects a JMS {@link javax.jms.ObjectMessage} - * carrying a {@link RemoteInvocationResult} object. If an invalid response - * message is encountered, the {@code onInvalidResponse} callback gets invoked. - * @param responseMessage the response message - * @return the invocation result - * @throws JMSException is thrown if a JMS exception occurs - * @see #onInvalidResponse - */ - protected RemoteInvocationResult extractInvocationResult(Message responseMessage) throws JMSException { - Object content = this.messageConverter.fromMessage(responseMessage); - if (content instanceof RemoteInvocationResult) { - return (RemoteInvocationResult) content; - } - return onInvalidResponse(responseMessage); - } - - /** - * Callback that is invoked by {@link #executeRequest} when the receive - * timeout has expired for the specified {@link RemoteInvocation}. - *

By default, an {@link RemoteTimeoutException} is thrown. Sub-classes - * can choose to either throw a more dedicated exception or even return - * a default {@link RemoteInvocationResult} as a fallback. - * @param invocation the invocation - * @return a default result when the receive timeout has expired - */ - protected RemoteInvocationResult onReceiveTimeout(RemoteInvocation invocation) { - throw new RemoteTimeoutException("Receive timeout after " + this.receiveTimeout + " ms for " + invocation); - } - - /** - * Callback that is invoked by {@link #extractInvocationResult} when - * it encounters an invalid response message. - *

The default implementation throws a {@link MessageFormatException}. - * @param responseMessage the invalid response message - * @return an alternative invocation result that should be returned to - * the caller (if desired) - * @throws JMSException if the invalid response should lead to an - * infrastructure exception propagated to the caller - * @see #extractInvocationResult - */ - protected RemoteInvocationResult onInvalidResponse(Message responseMessage) throws JMSException { - throw new MessageFormatException("Invalid response message: " + responseMessage); - } - - /** - * Recreate the invocation result contained in the given {@link RemoteInvocationResult} - * object. - *

The default implementation calls the default {@code recreate()} method. - *

Can be overridden in subclasses to provide custom recreation, potentially - * processing the returned result object. - * @param result the RemoteInvocationResult to recreate - * @return a return value if the invocation result is a successful return - * @throws Throwable if the invocation result is an exception - * @see org.springframework.remoting.support.RemoteInvocationResult#recreate() - */ - @Nullable - protected Object recreateRemoteInvocationResult(RemoteInvocationResult result) throws Throwable { - return result.recreate(); - } - - /** - * Convert the given JMS invoker access exception to an appropriate - * Spring {@link RemoteAccessException}. - * @param ex the exception to convert - * @return the RemoteAccessException to throw - */ - protected RemoteAccessException convertJmsInvokerAccessException(JMSException ex) { - return new RemoteAccessException("Could not access JMS invoker queue [" + this.queue + "]", ex); - } - -} diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java deleted file mode 100644 index 4562b602a5..0000000000 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerProxyFactoryBean.java +++ /dev/null @@ -1,101 +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.jms.remoting; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; - -/** - * FactoryBean for JMS invoker proxies. Exposes the proxied service for use - * as a bean reference, using the specified service interface. - * - *

Serializes remote invocation objects and deserializes remote invocation - * result objects. Uses Java serialization just like RMI, but with the JMS - * provider as communication infrastructure. - * - *

To be configured with a {@link javax.jms.QueueConnectionFactory} and a - * target queue (either as {@link javax.jms.Queue} reference or as queue name). - * - * @author Juergen Hoeller - * @since 2.0 - * @see #setConnectionFactory - * @see #setQueueName - * @see #setServiceInterface - * @see org.springframework.jms.remoting.JmsInvokerClientInterceptor - * @see org.springframework.jms.remoting.JmsInvokerServiceExporter - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JmsInvokerProxyFactoryBean extends JmsInvokerClientInterceptor - implements FactoryBean, BeanClassLoaderAware { - - @Nullable - private Class serviceInterface; - - @Nullable - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); - - @Nullable - private Object serviceProxy; - - - /** - * Set the interface that the proxy must implement. - * @param serviceInterface the interface that the proxy must implement - * @throws IllegalArgumentException if the supplied {@code serviceInterface} - * is not an interface type - */ - public void setServiceInterface(Class serviceInterface) { - Assert.notNull(serviceInterface, "'serviceInterface' must not be null"); - Assert.isTrue(serviceInterface.isInterface(), "'serviceInterface' must be an interface"); - this.serviceInterface = serviceInterface; - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - - @Override - public void afterPropertiesSet() { - super.afterPropertiesSet(); - Assert.notNull(this.serviceInterface, "Property 'serviceInterface' is required"); - this.serviceProxy = new ProxyFactory(this.serviceInterface, this).getProxy(this.beanClassLoader); - } - - - @Override - @Nullable - public Object getObject() { - return this.serviceProxy; - } - - @Override - public Class getObjectType() { - return this.serviceInterface; - } - - @Override - public boolean isSingleton() { - return true; - } - -} diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerServiceExporter.java b/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerServiceExporter.java deleted file mode 100644 index 80e5f51b47..0000000000 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/JmsInvokerServiceExporter.java +++ /dev/null @@ -1,199 +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.jms.remoting; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageFormatException; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.jms.listener.SessionAwareMessageListener; -import org.springframework.jms.support.JmsUtils; -import org.springframework.jms.support.converter.MessageConverter; -import org.springframework.jms.support.converter.SimpleMessageConverter; -import org.springframework.lang.Nullable; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationBasedExporter; -import org.springframework.remoting.support.RemoteInvocationResult; - -/** - * JMS message listener that exports the specified service bean as a - * JMS service endpoint, accessible via a JMS invoker proxy. - * - *

Note that this class implements Spring's - * {@link org.springframework.jms.listener.SessionAwareMessageListener} - * interface, since it requires access to the active JMS Session. - * Hence, this class can only be used with message listener containers - * which support the SessionAwareMessageListener interface (e.g. Spring's - * {@link org.springframework.jms.listener.DefaultMessageListenerContainer}). - * - *

Thanks to James Strachan for the original prototype that this - * JMS invoker mechanism was inspired by! - * - * @author Juergen Hoeller - * @author James Strachan - * @since 2.0 - * @see JmsInvokerClientInterceptor - * @see JmsInvokerProxyFactoryBean - * @deprecated as of 5.3 (phasing out serialization-based remoting) - */ -@Deprecated -public class JmsInvokerServiceExporter extends RemoteInvocationBasedExporter - implements SessionAwareMessageListener, InitializingBean { - - private MessageConverter messageConverter = new SimpleMessageConverter(); - - private boolean ignoreInvalidRequests = true; - - @Nullable - private Object proxy; - - - /** - * Specify the MessageConverter to use for turning request messages into - * {@link org.springframework.remoting.support.RemoteInvocation} objects, - * as well as {@link org.springframework.remoting.support.RemoteInvocationResult} - * objects into response messages. - *

Default is a {@link org.springframework.jms.support.converter.SimpleMessageConverter}, - * using a standard JMS {@link javax.jms.ObjectMessage} for each invocation / - * invocation result object. - *

Custom implementations may generally adapt Serializables into - * special kinds of messages, or might be specifically tailored for - * translating RemoteInvocation(Result)s into specific kinds of messages. - */ - public void setMessageConverter(@Nullable MessageConverter messageConverter) { - this.messageConverter = (messageConverter != null ? messageConverter : new SimpleMessageConverter()); - } - - /** - * Set whether invalidly formatted messages should be discarded. - * Default is "true". - *

Switch this flag to "false" to throw an exception back to the - * listener container. This will typically lead to redelivery of - * the message, which is usually undesirable - since the message - * content will be the same (that is, still invalid). - */ - public void setIgnoreInvalidRequests(boolean ignoreInvalidRequests) { - this.ignoreInvalidRequests = ignoreInvalidRequests; - } - - @Override - public void afterPropertiesSet() { - this.proxy = getProxyForService(); - } - - - @Override - public void onMessage(Message requestMessage, Session session) throws JMSException { - RemoteInvocation invocation = readRemoteInvocation(requestMessage); - if (invocation != null) { - RemoteInvocationResult result = invokeAndCreateResult(invocation, this.proxy); - writeRemoteInvocationResult(requestMessage, session, result); - } - } - - /** - * Read a RemoteInvocation from the given JMS message. - * @param requestMessage current request message - * @return the RemoteInvocation object (or {@code null} - * in case of an invalid message that will simply be ignored) - * @throws javax.jms.JMSException in case of message access failure - */ - @Nullable - protected RemoteInvocation readRemoteInvocation(Message requestMessage) throws JMSException { - Object content = this.messageConverter.fromMessage(requestMessage); - if (content instanceof RemoteInvocation) { - return (RemoteInvocation) content; - } - return onInvalidRequest(requestMessage); - } - - - /** - * Send the given RemoteInvocationResult as a JMS message to the originator. - * @param requestMessage current request message - * @param session the JMS Session to use - * @param result the RemoteInvocationResult object - * @throws javax.jms.JMSException if thrown by trying to send the message - */ - protected void writeRemoteInvocationResult( - Message requestMessage, Session session, RemoteInvocationResult result) throws JMSException { - - Message response = createResponseMessage(requestMessage, session, result); - MessageProducer producer = session.createProducer(requestMessage.getJMSReplyTo()); - try { - producer.send(response); - } - finally { - JmsUtils.closeMessageProducer(producer); - } - } - - /** - * Create the invocation result response message. - *

The default implementation creates a JMS ObjectMessage for the given - * RemoteInvocationResult object. It sets the response's correlation id - * to the request message's correlation id, if any; otherwise to the - * request message id. - * @param request the original request message - * @param session the JMS session to use - * @param result the invocation result - * @return the message response to send - * @throws javax.jms.JMSException if creating the message failed - */ - protected Message createResponseMessage(Message request, Session session, RemoteInvocationResult result) - throws JMSException { - - Message response = this.messageConverter.toMessage(result, session); - String correlation = request.getJMSCorrelationID(); - if (correlation == null) { - correlation = request.getJMSMessageID(); - } - response.setJMSCorrelationID(correlation); - return response; - } - - /** - * Callback that is invoked by {@link #readRemoteInvocation} - * when it encounters an invalid request message. - *

The default implementation either discards the invalid message or - * throws a MessageFormatException - according to the "ignoreInvalidRequests" - * flag, which is set to "true" (that is, discard invalid messages) by default. - * @param requestMessage the invalid request message - * @return the RemoteInvocation to expose for the invalid request (typically - * {@code null} in case of an invalid message that will simply be ignored) - * @throws javax.jms.JMSException in case of the invalid request supposed - * to lead to an exception (instead of ignoring it) - * @see #readRemoteInvocation - * @see #setIgnoreInvalidRequests - */ - @Nullable - protected RemoteInvocation onInvalidRequest(Message requestMessage) throws JMSException { - if (this.ignoreInvalidRequests) { - if (logger.isDebugEnabled()) { - logger.debug("Invalid request message will be discarded: " + requestMessage); - } - return null; - } - else { - throw new MessageFormatException("Invalid request message: " + requestMessage); - } - } - -} diff --git a/spring-jms/src/main/java/org/springframework/jms/remoting/package-info.java b/spring-jms/src/main/java/org/springframework/jms/remoting/package-info.java deleted file mode 100644 index 20e030430c..0000000000 --- a/spring-jms/src/main/java/org/springframework/jms/remoting/package-info.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Remoting classes for transparent Java-to-Java remoting via a JMS provider. - * - *

Allows the target service to be load-balanced across a number of queue - * receivers, and provides a level of indirection between the client and the - * service: They only need to agree on a queue name and a service interface. - */ -@NonNullApi -@NonNullFields -package org.springframework.jms.remoting; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; diff --git a/spring-jms/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java b/spring-jms/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java deleted file mode 100644 index 299ee9321f..0000000000 --- a/spring-jms/src/test/java/org/springframework/jms/remoting/JmsInvokerTests.java +++ /dev/null @@ -1,511 +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.jms.remoting; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Enumeration; - -import javax.jms.CompletionListener; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.ObjectMessage; -import javax.jms.Queue; -import javax.jms.QueueConnection; -import javax.jms.QueueConnectionFactory; -import javax.jms.QueueSession; -import javax.jms.Session; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.testfixture.beans.ITestBean; -import org.springframework.beans.testfixture.beans.TestBean; -import org.springframework.jms.support.converter.MessageConversionException; -import org.springframework.jms.support.converter.SimpleMessageConverter; -import org.springframework.remoting.RemoteTimeoutException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * @author Juergen Hoeller - * @author Stephane Nicoll - */ -class JmsInvokerTests { - - private QueueConnectionFactory mockConnectionFactory = mock(QueueConnectionFactory.class); - - private QueueConnection mockConnection = mock(QueueConnection.class); - - private QueueSession mockSession = mock(QueueSession.class); - - private Queue mockQueue = mock(Queue.class); - - - @BeforeEach - void setUpMocks() throws Exception { - given(mockConnectionFactory.createConnection()).willReturn(mockConnection); - given(mockConnection.createSession(false, Session.AUTO_ACKNOWLEDGE)).willReturn(mockSession); - } - - - @Test - void jmsInvokerProxyFactoryBeanAndServiceExporter() throws Throwable { - doTestJmsInvokerProxyFactoryBeanAndServiceExporter(false); - } - - @Test - void jmsInvokerProxyFactoryBeanAndServiceExporterWithDynamicQueue() throws Throwable { - given(mockSession.createQueue("myQueue")).willReturn(mockQueue); - doTestJmsInvokerProxyFactoryBeanAndServiceExporter(true); - } - - @Test - @SuppressWarnings("deprecation") - void receiveTimeoutExpired() { - JmsInvokerProxyFactoryBean pfb = new JmsInvokerProxyFactoryBean() { - @Override - protected Message doExecuteRequest(Session session, Queue queue, Message requestMessage) throws JMSException { - return null; // faking no message received - } - }; - pfb.setServiceInterface(ITestBean.class); - pfb.setConnectionFactory(this.mockConnectionFactory); - pfb.setQueue(this.mockQueue); - pfb.setReceiveTimeout(1500); - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - - assertThatExceptionOfType(RemoteTimeoutException.class).isThrownBy(() -> - proxy.getAge()) - .withMessageContaining("1500 ms") - .withMessageContaining("getAge"); - } - - @SuppressWarnings("deprecation") - private void doTestJmsInvokerProxyFactoryBeanAndServiceExporter(boolean dynamicQueue) throws Throwable { - TestBean target = new TestBean("myname", 99); - - final JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter(); - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.setMessageConverter(new MockSimpleMessageConverter()); - exporter.afterPropertiesSet(); - - JmsInvokerProxyFactoryBean pfb = new JmsInvokerProxyFactoryBean() { - @Override - protected Message doExecuteRequest(Session session, Queue queue, Message requestMessage) throws JMSException { - Session mockExporterSession = mock(Session.class); - ResponseStoringProducer mockProducer = new ResponseStoringProducer(); - given(mockExporterSession.createProducer(requestMessage.getJMSReplyTo())).willReturn(mockProducer); - exporter.onMessage(requestMessage, mockExporterSession); - assertThat(mockProducer.closed).isTrue(); - return mockProducer.response; - } - }; - pfb.setServiceInterface(ITestBean.class); - pfb.setConnectionFactory(this.mockConnectionFactory); - if (dynamicQueue) { - pfb.setQueueName("myQueue"); - } - else { - pfb.setQueue(this.mockQueue); - } - pfb.setMessageConverter(new MockSimpleMessageConverter()); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - proxy.setAge(50); - assertThat(proxy.getAge()).isEqualTo(50); - proxy.setStringArray(new String[] {"str1", "str2"}); - assertThat(Arrays.equals(new String[] {"str1", "str2"}, proxy.getStringArray())).isTrue(); - assertThatIllegalStateException().isThrownBy(() -> - proxy.exceptional(new IllegalStateException())); - assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(() -> - proxy.exceptional(new IllegalAccessException())); - } - - - private static class ResponseStoringProducer implements MessageProducer { - - Message response; - - boolean closed = false; - - @Override - public void setDisableMessageID(boolean b) throws JMSException { - } - - @Override - public boolean getDisableMessageID() throws JMSException { - return false; - } - - @Override - public void setDisableMessageTimestamp(boolean b) throws JMSException { - } - - @Override - public boolean getDisableMessageTimestamp() throws JMSException { - return false; - } - - @Override - public void setDeliveryMode(int i) throws JMSException { - } - - @Override - public int getDeliveryMode() throws JMSException { - return 0; - } - - @Override - public void setPriority(int i) throws JMSException { - } - - @Override - public int getPriority() throws JMSException { - return 0; - } - - @Override - public void setTimeToLive(long l) throws JMSException { - } - - @Override - public long getTimeToLive() throws JMSException { - return 0; - } - - @Override - public void setDeliveryDelay(long deliveryDelay) throws JMSException { - } - - @Override - public long getDeliveryDelay() throws JMSException { - return 0; - } - - @Override - public Destination getDestination() throws JMSException { - return null; - } - - @Override - public void close() throws JMSException { - this.closed = true; - } - - @Override - public void send(Message message) throws JMSException { - this.response = message; - } - - @Override - public void send(Message message, int i, int i1, long l) throws JMSException { - } - - @Override - public void send(Destination destination, Message message) throws JMSException { - } - - @Override - public void send(Destination destination, Message message, int i, int i1, long l) throws JMSException { - } - - @Override - public void send(Message message, CompletionListener completionListener) throws JMSException { - } - - @Override - public void send(Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener) throws JMSException { - } - - @Override - public void send(Destination destination, Message message, CompletionListener completionListener) throws JMSException { - } - - @Override - public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive, CompletionListener completionListener) throws JMSException { - } - } - - - private static class MockObjectMessage implements ObjectMessage { - - private Serializable serializable; - - private Destination replyTo; - - public MockObjectMessage(Serializable serializable) { - this.serializable = serializable; - } - - @Override - public void setObject(Serializable serializable) throws JMSException { - this.serializable = serializable; - } - - @Override - public Serializable getObject() throws JMSException { - return serializable; - } - - @Override - public String getJMSMessageID() throws JMSException { - return null; - } - - @Override - public void setJMSMessageID(String string) throws JMSException { - } - - @Override - public long getJMSTimestamp() throws JMSException { - return 0; - } - - @Override - public void setJMSTimestamp(long l) throws JMSException { - } - - @Override - public byte[] getJMSCorrelationIDAsBytes() throws JMSException { - return new byte[0]; - } - - @Override - public void setJMSCorrelationIDAsBytes(byte[] bytes) throws JMSException { - } - - @Override - public void setJMSCorrelationID(String string) throws JMSException { - } - - @Override - public String getJMSCorrelationID() throws JMSException { - return null; - } - - @Override - public Destination getJMSReplyTo() throws JMSException { - return replyTo; - } - - @Override - public void setJMSReplyTo(Destination destination) throws JMSException { - this.replyTo = destination; - } - - @Override - public Destination getJMSDestination() throws JMSException { - return null; - } - - @Override - public void setJMSDestination(Destination destination) throws JMSException { - } - - @Override - public int getJMSDeliveryMode() throws JMSException { - return 0; - } - - @Override - public void setJMSDeliveryMode(int i) throws JMSException { - } - - @Override - public boolean getJMSRedelivered() throws JMSException { - return false; - } - - @Override - public void setJMSRedelivered(boolean b) throws JMSException { - } - - @Override - public String getJMSType() throws JMSException { - return null; - } - - @Override - public void setJMSType(String string) throws JMSException { - } - - @Override - public long getJMSExpiration() throws JMSException { - return 0; - } - - @Override - public void setJMSExpiration(long l) throws JMSException { - } - - @Override - public int getJMSPriority() throws JMSException { - return 0; - } - - @Override - public void setJMSPriority(int i) throws JMSException { - } - - @Override - public long getJMSDeliveryTime() throws JMSException { - return 0; - } - - @Override - public void setJMSDeliveryTime(long deliveryTime) throws JMSException { - } - - @Override - public T getBody(Class c) throws JMSException { - return null; - } - - @Override - @SuppressWarnings("rawtypes") - public boolean isBodyAssignableTo(Class c) throws JMSException { - return false; - } - - @Override - public void clearProperties() throws JMSException { - } - - @Override - public boolean propertyExists(String string) throws JMSException { - return false; - } - - @Override - public boolean getBooleanProperty(String string) throws JMSException { - return false; - } - - @Override - public byte getByteProperty(String string) throws JMSException { - return 0; - } - - @Override - public short getShortProperty(String string) throws JMSException { - return 0; - } - - @Override - public int getIntProperty(String string) throws JMSException { - return 0; - } - - @Override - public long getLongProperty(String string) throws JMSException { - return 0; - } - - @Override - public float getFloatProperty(String string) throws JMSException { - return 0; - } - - @Override - public double getDoubleProperty(String string) throws JMSException { - return 0; - } - - @Override - public String getStringProperty(String string) throws JMSException { - return null; - } - - @Override - public Object getObjectProperty(String string) throws JMSException { - return null; - } - - @Override - @SuppressWarnings("rawtypes") - public Enumeration getPropertyNames() throws JMSException { - return null; - } - - @Override - public void setBooleanProperty(String string, boolean b) throws JMSException { - } - - @Override - public void setByteProperty(String string, byte b) throws JMSException { - } - - @Override - public void setShortProperty(String string, short i) throws JMSException { - } - - @Override - public void setIntProperty(String string, int i) throws JMSException { - } - - @Override - public void setLongProperty(String string, long l) throws JMSException { - } - - @Override - public void setFloatProperty(String string, float v) throws JMSException { - } - - @Override - public void setDoubleProperty(String string, double v) throws JMSException { - } - - @Override - public void setStringProperty(String string, String string1) throws JMSException { - } - - @Override - public void setObjectProperty(String string, Object object) throws JMSException { - } - - @Override - public void acknowledge() throws JMSException { - } - - @Override - public void clearBody() throws JMSException { - } - } - - - private static class MockSimpleMessageConverter extends SimpleMessageConverter { - - @Override - public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException { - return new MockObjectMessage((Serializable) object); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java deleted file mode 100644 index 241a8580e1..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianClientInterceptor.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol. - * For information on Hessian, see the - * Hessian website - * Note: As of Spring 4.0, this client requires Hessian 4.0 or above. - * - *

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. - *

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. - *

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. - *

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. - *

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); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java deleted file mode 100644 index b6c70e5fd7..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianExporter.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol. - * For information on Hessian, see the - * Hessian website. - * Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above. - * - * @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. - *

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); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianProxyFactoryBean.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianProxyFactoryBean.java deleted file mode 100644 index 45a66eacf5..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianProxyFactoryBean.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol. - * For information on Hessian, see the - * Hessian website - * Note: As of Spring 4.0, this proxy factory requires Hessian 4.0 or above. - * - *

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 { - - @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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/caucho/HessianServiceExporter.java deleted file mode 100644 index f25139ccf2..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/HessianServiceExporter.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol. - * For information on Hessian, see the - * Hessian website. - * Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above. - * - *

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); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java deleted file mode 100644 index cc96b28bfa..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/SimpleHessianServiceExporter.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol. - * For information on Hessian, see the - * Hessian website. - * Note: As of Spring 4.0, this exporter requires Hessian 4.0 or above. - * - *

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()); - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/caucho/package-info.java b/spring-web/src/main/java/org/springframework/remoting/caucho/package-info.java deleted file mode 100644 index 30d03c5176..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/caucho/package-info.java +++ /dev/null @@ -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. - * - *

Hessian is a slim, binary RPC protocol over HTTP. - * For information on Hessian, see the - * Hessian website - */ -@NonNullApi -@NonNullFields -package org.springframework.remoting.caucho; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java deleted file mode 100644 index b1a34258ad..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/AbstractHttpInvokerRequestExecutor.java +++ /dev/null @@ -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. - * - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java deleted file mode 100644 index c8a278fec4..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutor.java +++ /dev/null @@ -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 - * Apache HttpComponents HttpClient - * to execute POST requests. - * - *

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. - * - *

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 schemeRegistry = RegistryBuilder.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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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)); - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java deleted file mode 100644 index 9e81e1d289..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientConfiguration.java +++ /dev/null @@ -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(); - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java deleted file mode 100644 index 361101475e..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerClientInterceptor.java +++ /dev/null @@ -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. - * - *

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. - * - *

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. - * - *

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.) - * - *

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. - * 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. - *

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. - *

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. - *

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}. - *

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}. - *

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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java deleted file mode 100644 index ae483e45ff..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerProxyFactoryBean.java +++ /dev/null @@ -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. - * - *

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. - * - *

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. - * - *

HTTP invoker is the recommended protocol for Java-to-Java remoting. - * 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. - * - *

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. - * 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 { - - @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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java deleted file mode 100644 index d5236e5179..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerRequestExecutor.java +++ /dev/null @@ -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. - * - *

Two implementations are provided out of the box: - *

    - *
  • {@code SimpleHttpInvokerRequestExecutor}: - * Uses JDK facilities to execute POST requests, without support - * for HTTP authentication or advanced configuration options. - *
  • {@code HttpComponentsHttpInvokerRequestExecutor}: - * Uses Apache's Commons HttpClient to execute POST requests, - * allowing to use a preconfigured HttpClient instance - * (potentially with authentication, HTTP connection pooling, etc). - *
- * - * @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; - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java deleted file mode 100644 index dc1a0ac746..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/HttpInvokerServiceExporter.java +++ /dev/null @@ -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. - * - *

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. - * - *

HTTP invoker is the recommended protocol for Java-to-Java remoting. - * 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. - * - *

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. - * 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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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 SPR-14040 - */ - private static class FlushGuardedOutputStream extends FilterOutputStream { - - public FlushGuardedOutputStream(OutputStream out) { - super(out); - } - - @Override - public void flush() throws IOException { - // Do nothing on flush - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java deleted file mode 100644 index b4c8f31c36..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerRequestExecutor.java +++ /dev/null @@ -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. - * - *

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. - *

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. - *

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}. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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)); - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java deleted file mode 100644 index 5c8e431fba..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/SimpleHttpInvokerServiceExporter.java +++ /dev/null @@ -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. - * - *

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. - * - *

HTTP invoker is the recommended protocol for Java-to-Java remoting. - * 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. - * - *

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. - * 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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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. - *

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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/package-info.java b/spring-web/src/main/java/org/springframework/remoting/httpinvoker/package-info.java deleted file mode 100644 index e0dfd03aa6..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/httpinvoker/package-info.java +++ /dev/null @@ -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. - * - *

HTTP invoker is the recommended protocol for Java-to-Java remoting. - * 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; diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java deleted file mode 100644 index 610651bef2..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java +++ /dev/null @@ -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). - * - *

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 endpointProperties; - - @Nullable - private Executor executor; - - @Nullable - private String bindingType; - - @Nullable - private WebServiceFeature[] endpointFeatures; - - @Nullable - private ListableBeanFactory beanFactory; - - private final Set 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 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 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(); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java deleted file mode 100644 index e8ff14889a..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java +++ /dev/null @@ -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. - * - *

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 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. - *

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 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. - *

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 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. - *

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 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); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java deleted file mode 100644 index 3788d0e0e7..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java +++ /dev/null @@ -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 { - - @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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java deleted file mode 100644 index 0205f56e68..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/JaxWsSoapFaultException.java +++ /dev/null @@ -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(); - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java deleted file mode 100644 index 8abc4f1b02..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactory.java +++ /dev/null @@ -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. - * - *

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)); - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java deleted file mode 100644 index d512f7de6f..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/LocalJaxWsServiceFactoryBean.java +++ /dev/null @@ -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. - * - *

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, InitializingBean { - - @Nullable - private Service service; - - - @Override - public void afterPropertiesSet() { - this.service = createJaxWsService(); - } - - @Override - @Nullable - public Service getObject() { - return this.service; - } - - @Override - public Class getObjectType() { - return (this.service != null ? this.service.getClass() : Service.class); - } - - @Override - public boolean isSingleton() { - return true; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java deleted file mode 100644 index 54382b30d6..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleHttpServerJaxWsServiceExporter.java +++ /dev/null @@ -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"). - * - *

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 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}. - *

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. - *

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. - *

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. - *

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. - *

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 "/". - *

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 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); - } - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java deleted file mode 100644 index 06786578f9..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/SimpleJaxWsServiceExporter.java +++ /dev/null @@ -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"). - * - *

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/". - *

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; - } - -} diff --git a/spring-web/src/main/java/org/springframework/remoting/jaxws/package-info.java b/spring-web/src/main/java/org/springframework/remoting/jaxws/package-info.java deleted file mode 100644 index 6dc1423ab6..0000000000 --- a/spring-web/src/main/java/org/springframework/remoting/jaxws/package-info.java +++ /dev/null @@ -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; diff --git a/spring-web/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java b/spring-web/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java deleted file mode 100644 index 58d1846bcf..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/caucho/CauchoRemotingTests.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2002-2019 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 java.net.InetSocketAddress; - -import com.caucho.hessian.client.HessianProxyFactory; -import com.sun.net.httpserver.HttpServer; -import org.junit.jupiter.api.Test; - -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.testfixture.beans.ITestBean; -import org.springframework.beans.testfixture.beans.TestBean; -import org.springframework.remoting.RemoteAccessException; -import org.springframework.util.SocketUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; - -/** - * @author Juergen Hoeller - * @author Sam Brannen - * @since 16.05.2003 - */ -public class CauchoRemotingTests { - - @Test - public void hessianProxyFactoryBeanWithClassInsteadOfInterface() throws Exception { - HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); - assertThatIllegalArgumentException().isThrownBy(() -> - factory.setServiceInterface(TestBean.class)); - } - - @Test - public void hessianProxyFactoryBeanWithAccessError() throws Exception { - HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); - factory.setServiceInterface(ITestBean.class); - factory.setServiceUrl("http://localhosta/testbean"); - factory.afterPropertiesSet(); - - assertThat(factory.isSingleton()).as("Correct singleton value").isTrue(); - boolean condition = factory.getObject() instanceof ITestBean; - assertThat(condition).isTrue(); - ITestBean bean = (ITestBean) factory.getObject(); - - assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(() -> - bean.setName("test")); - } - - @Test - public void hessianProxyFactoryBeanWithAuthenticationAndAccessError() throws Exception { - HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); - factory.setServiceInterface(ITestBean.class); - factory.setServiceUrl("http://localhosta/testbean"); - factory.setUsername("test"); - factory.setPassword("bean"); - factory.setOverloadEnabled(true); - factory.afterPropertiesSet(); - - assertThat(factory.isSingleton()).as("Correct singleton value").isTrue(); - boolean condition = factory.getObject() instanceof ITestBean; - assertThat(condition).isTrue(); - ITestBean bean = (ITestBean) factory.getObject(); - - assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(() -> - bean.setName("test")); - } - - @Test - public void hessianProxyFactoryBeanWithCustomProxyFactory() throws Exception { - TestHessianProxyFactory proxyFactory = new TestHessianProxyFactory(); - HessianProxyFactoryBean factory = new HessianProxyFactoryBean(); - factory.setServiceInterface(ITestBean.class); - factory.setServiceUrl("http://localhosta/testbean"); - factory.setProxyFactory(proxyFactory); - factory.setUsername("test"); - factory.setPassword("bean"); - factory.setOverloadEnabled(true); - factory.afterPropertiesSet(); - assertThat(factory.isSingleton()).as("Correct singleton value").isTrue(); - boolean condition = factory.getObject() instanceof ITestBean; - assertThat(condition).isTrue(); - ITestBean bean = (ITestBean) factory.getObject(); - - assertThat(proxyFactory.user).isEqualTo("test"); - assertThat(proxyFactory.password).isEqualTo("bean"); - assertThat(proxyFactory.overloadEnabled).isTrue(); - - assertThatExceptionOfType(RemoteAccessException.class).isThrownBy(() -> - bean.setName("test")); - } - - @Test - @SuppressWarnings("deprecation") - public void simpleHessianServiceExporter() throws IOException { - final int port = SocketUtils.findAvailableTcpPort(); - - TestBean tb = new TestBean("tb"); - SimpleHessianServiceExporter exporter = new SimpleHessianServiceExporter(); - exporter.setService(tb); - exporter.setServiceInterface(ITestBean.class); - exporter.setDebug(true); - exporter.prepare(); - - HttpServer server = HttpServer.create(new InetSocketAddress(port), -1); - server.createContext("/hessian", exporter); - server.start(); - try { - HessianClientInterceptor client = new HessianClientInterceptor(); - client.setServiceUrl("http://localhost:" + port + "/hessian"); - client.setServiceInterface(ITestBean.class); - //client.setHessian2(true); - client.prepare(); - ITestBean proxy = ProxyFactory.getProxy(ITestBean.class, client); - assertThat(proxy.getName()).isEqualTo("tb"); - proxy.setName("test"); - assertThat(proxy.getName()).isEqualTo("test"); - } - finally { - server.stop(Integer.MAX_VALUE); - } - } - - - private static class TestHessianProxyFactory extends HessianProxyFactory { - - private String user; - private String password; - private boolean overloadEnabled; - - @Override - public void setUser(String user) { - this.user = user; - } - - @Override - public void setPassword(String password) { - this.password = password; - } - - @Override - public void setOverloadEnabled(boolean overloadEnabled) { - this.overloadEnabled = overloadEnabled; - } - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutorTests.java b/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutorTests.java deleted file mode 100644 index c5d486f05e..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpComponentsHttpInvokerRequestExecutorTests.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2002-2019 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.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.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.withSettings; - -/** - * @author Stephane Nicoll - */ -public class HttpComponentsHttpInvokerRequestExecutorTests { - - @Test - public void customizeConnectionTimeout() throws IOException { - HttpComponentsHttpInvokerRequestExecutor executor = new HttpComponentsHttpInvokerRequestExecutor(); - executor.setConnectTimeout(5000); - - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - assertThat(httpPost.getConfig().getConnectTimeout()).isEqualTo(5000); - } - - @Test - public void customizeConnectionRequestTimeout() throws IOException { - HttpComponentsHttpInvokerRequestExecutor executor = new HttpComponentsHttpInvokerRequestExecutor(); - executor.setConnectionRequestTimeout(7000); - - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - assertThat(httpPost.getConfig().getConnectionRequestTimeout()).isEqualTo(7000); - } - - @Test - public void customizeReadTimeout() throws IOException { - HttpComponentsHttpInvokerRequestExecutor executor = new HttpComponentsHttpInvokerRequestExecutor(); - executor.setReadTimeout(10000); - - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - assertThat(httpPost.getConfig().getSocketTimeout()).isEqualTo(10000); - } - - @Test - public void defaultSettingsOfHttpClientMergedOnExecutorCustomization() throws IOException { - RequestConfig defaultConfig = RequestConfig.custom().setConnectTimeout(1234).build(); - CloseableHttpClient client = mock(CloseableHttpClient.class, - withSettings().extraInterfaces(Configurable.class)); - Configurable configurable = (Configurable) client; - given(configurable.getConfig()).willReturn(defaultConfig); - - HttpComponentsHttpInvokerRequestExecutor executor = - new HttpComponentsHttpInvokerRequestExecutor(client); - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - assertThat(httpPost.getConfig()).as("Default client configuration is expected").isSameAs(defaultConfig); - - executor.setConnectionRequestTimeout(4567); - HttpPost httpPost2 = executor.createHttpPost(config); - assertThat(httpPost2.getConfig()).isNotNull(); - assertThat(httpPost2.getConfig().getConnectionRequestTimeout()).isEqualTo(4567); - // Default connection timeout merged - assertThat(httpPost2.getConfig().getConnectTimeout()).isEqualTo(1234); - } - - @Test - public void localSettingsOverrideClientDefaultSettings() throws Exception { - RequestConfig defaultConfig = RequestConfig.custom() - .setConnectTimeout(1234).setConnectionRequestTimeout(6789).build(); - CloseableHttpClient client = mock(CloseableHttpClient.class, - withSettings().extraInterfaces(Configurable.class)); - Configurable configurable = (Configurable) client; - given(configurable.getConfig()).willReturn(defaultConfig); - - HttpComponentsHttpInvokerRequestExecutor executor = - new HttpComponentsHttpInvokerRequestExecutor(client); - executor.setConnectTimeout(5000); - - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - RequestConfig requestConfig = httpPost.getConfig(); - assertThat(requestConfig.getConnectTimeout()).isEqualTo(5000); - assertThat(requestConfig.getConnectionRequestTimeout()).isEqualTo(6789); - assertThat(requestConfig.getSocketTimeout()).isEqualTo(-1); - } - - @Test - public void mergeBasedOnCurrentHttpClient() throws Exception { - RequestConfig defaultConfig = RequestConfig.custom() - .setSocketTimeout(1234).build(); - final CloseableHttpClient client = mock(CloseableHttpClient.class, - withSettings().extraInterfaces(Configurable.class)); - Configurable configurable = (Configurable) client; - given(configurable.getConfig()).willReturn(defaultConfig); - - HttpComponentsHttpInvokerRequestExecutor executor = - new HttpComponentsHttpInvokerRequestExecutor() { - @Override - public HttpClient getHttpClient() { - return client; - } - }; - executor.setReadTimeout(5000); - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - RequestConfig requestConfig = httpPost.getConfig(); - assertThat(requestConfig.getConnectTimeout()).isEqualTo(-1); - assertThat(requestConfig.getConnectionRequestTimeout()).isEqualTo(-1); - assertThat(requestConfig.getSocketTimeout()).isEqualTo(5000); - - // Update the Http client so that it returns an updated config - RequestConfig updatedDefaultConfig = RequestConfig.custom() - .setConnectTimeout(1234).build(); - given(configurable.getConfig()).willReturn(updatedDefaultConfig); - executor.setReadTimeout(7000); - HttpPost httpPost2 = executor.createHttpPost(config); - RequestConfig requestConfig2 = httpPost2.getConfig(); - assertThat(requestConfig2.getConnectTimeout()).isEqualTo(1234); - assertThat(requestConfig2.getConnectionRequestTimeout()).isEqualTo(-1); - assertThat(requestConfig2.getSocketTimeout()).isEqualTo(7000); - } - - @Test - public void ignoreFactorySettings() throws IOException { - CloseableHttpClient httpClient = HttpClientBuilder.create().build(); - HttpComponentsHttpInvokerRequestExecutor executor = new HttpComponentsHttpInvokerRequestExecutor(httpClient) { - @Override - protected RequestConfig createRequestConfig(HttpInvokerClientConfiguration config) { - return null; - } - }; - - HttpInvokerClientConfiguration config = mockHttpInvokerClientConfiguration("https://fake-service"); - HttpPost httpPost = executor.createHttpPost(config); - assertThat(httpPost.getConfig()).as("custom request config should not be set").isNull(); - } - - private HttpInvokerClientConfiguration mockHttpInvokerClientConfiguration(String serviceUrl) { - HttpInvokerClientConfiguration config = mock(HttpInvokerClientConfiguration.class); - given(config.getServiceUrl()).willReturn(serviceUrl); - return config; - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerFactoryBeanIntegrationTests.java b/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerFactoryBeanIntegrationTests.java deleted file mode 100644 index a53d1e2e38..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerFactoryBeanIntegrationTests.java +++ /dev/null @@ -1,145 +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 org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.core.env.Environment; -import org.springframework.remoting.support.RemoteInvocationResult; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor; -import org.springframework.stereotype.Component; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Stephane Nicoll - */ -class HttpInvokerFactoryBeanIntegrationTests { - - @Test - @SuppressWarnings("resource") - void testLoadedConfigClass() { - ApplicationContext context = new AnnotationConfigApplicationContext(InvokerAutowiringConfig.class); - MyBean myBean = context.getBean("myBean", MyBean.class); - assertThat(myBean.myService).isSameAs(context.getBean("myService")); - myBean.myService.handle(); - myBean.myService.handleAsync(); - } - - @Test - @SuppressWarnings("resource") - void testNonLoadedConfigClass() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.registerBeanDefinition("config", new RootBeanDefinition(InvokerAutowiringConfig.class.getName())); - context.refresh(); - MyBean myBean = context.getBean("myBean", MyBean.class); - assertThat(myBean.myService).isSameAs(context.getBean("myService")); - myBean.myService.handle(); - myBean.myService.handleAsync(); - } - - @Test - @SuppressWarnings("resource") - void withConfigurationClassWithPlainFactoryBean() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(ConfigWithPlainFactoryBean.class); - context.refresh(); - MyBean myBean = context.getBean("myBean", MyBean.class); - assertThat(myBean.myService).isSameAs(context.getBean("myService")); - myBean.myService.handle(); - myBean.myService.handleAsync(); - } - - - interface MyService { - - void handle(); - - @Async - public void handleAsync(); - } - - - @Component("myBean") - static class MyBean { - - @Autowired - MyService myService; - } - - - @Configuration - @ComponentScan - @Lazy - static class InvokerAutowiringConfig { - - @Bean - AsyncAnnotationBeanPostProcessor aabpp() { - return new AsyncAnnotationBeanPostProcessor(); - } - - @Bean - @SuppressWarnings("deprecation") - HttpInvokerProxyFactoryBean myService() { - HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean(); - factory.setServiceUrl("/svc/dummy"); - factory.setServiceInterface(MyService.class); - factory.setHttpInvokerRequestExecutor((config, invocation) -> new RemoteInvocationResult()); - return factory; - } - - @Bean - FactoryBean myOtherService() { - throw new IllegalStateException("Don't ever call me"); - } - } - - - @Configuration - static class ConfigWithPlainFactoryBean { - - @Autowired - Environment env; - - @Bean - MyBean myBean() { - return new MyBean(); - } - - @Bean - @SuppressWarnings("deprecation") - HttpInvokerProxyFactoryBean myService() { - String name = env.getProperty("testbean.name"); - HttpInvokerProxyFactoryBean factory = new HttpInvokerProxyFactoryBean(); - factory.setServiceUrl("/svc/" + name); - factory.setServiceInterface(MyService.class); - factory.setHttpInvokerRequestExecutor((config, invocation) -> new RemoteInvocationResult()); - return factory; - } - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java b/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java deleted file mode 100644 index 8a2c697b69..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/httpinvoker/HttpInvokerTests.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright 2002-2021 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.ByteArrayInputStream; -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.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.aopalliance.intercept.MethodInvocation; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.testfixture.beans.ITestBean; -import org.springframework.beans.testfixture.beans.TestBean; -import org.springframework.remoting.RemoteAccessException; -import org.springframework.remoting.support.DefaultRemoteInvocationExecutor; -import org.springframework.remoting.support.RemoteInvocation; -import org.springframework.remoting.support.RemoteInvocationResult; -import org.springframework.web.testfixture.servlet.MockHttpServletRequest; -import org.springframework.web.testfixture.servlet.MockHttpServletResponse; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; - -/** - * @author Juergen Hoeller - * @since 09.08.2004 - */ -@SuppressWarnings("deprecation") -class HttpInvokerTests { - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporter() { - doTestHttpInvokerProxyFactoryBeanAndServiceExporter(false); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithExplicitClassLoader() { - doTestHttpInvokerProxyFactoryBeanAndServiceExporter(true); - } - - private void doTestHttpInvokerProxyFactoryBeanAndServiceExporter(boolean explicitClassLoader) { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - - pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { - @Override - protected RemoteInvocationResult doExecuteRequest( - HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { - assertThat(config.getServiceUrl()).isEqualTo("https://myurl"); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - request.setContent(baos.toByteArray()); - exporter.handleRequest(request, response); - return readRemoteInvocationResult( - new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); - } - }); - if (explicitClassLoader) { - ((BeanClassLoaderAware) pfb.getHttpInvokerRequestExecutor()).setBeanClassLoader(getClass().getClassLoader()); - } - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - proxy.setAge(50); - assertThat(proxy.getAge()).isEqualTo(50); - proxy.setStringArray(new String[] {"str1", "str2"}); - assertThat(Arrays.equals(new String[] {"str1", "str2"}, proxy.getStringArray())).isTrue(); - proxy.setSomeIntegerArray(new Integer[] {1, 2, 3}); - assertThat(Arrays.equals(new Integer[] {1, 2, 3}, proxy.getSomeIntegerArray())).isTrue(); - proxy.setNestedIntegerArray(new Integer[][] {{1, 2, 3}, {4, 5, 6}}); - Integer[][] integerArray = proxy.getNestedIntegerArray(); - assertThat(Arrays.equals(new Integer[] {1, 2, 3}, integerArray[0])).isTrue(); - assertThat(Arrays.equals(new Integer[] {4, 5, 6}, integerArray[1])).isTrue(); - proxy.setSomeIntArray(new int[] {1, 2, 3}); - assertThat(Arrays.equals(new int[] {1, 2, 3}, proxy.getSomeIntArray())).isTrue(); - proxy.setNestedIntArray(new int[][] {{1, 2, 3}, {4, 5, 6}}); - int[][] intArray = proxy.getNestedIntArray(); - assertThat(Arrays.equals(new int[] {1, 2, 3}, intArray[0])).isTrue(); - assertThat(Arrays.equals(new int[] {4, 5, 6}, intArray[1])).isTrue(); - - assertThatIllegalStateException().isThrownBy(() -> - proxy.exceptional(new IllegalStateException())); - assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(() -> - proxy.exceptional(new IllegalAccessException())); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithIOException() throws Exception { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - - pfb.setHttpInvokerRequestExecutor((config, invocation) -> { throw new IOException("argh"); }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThatExceptionOfType(RemoteAccessException.class) - .isThrownBy(() -> proxy.setAge(50)) - .withCauseInstanceOf(IOException.class); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithGzipCompression() { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter() { - @Override - protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException { - if ("gzip".equals(request.getHeader("Compression"))) { - return new GZIPInputStream(is); - } - else { - return is; - } - } - @Override - protected OutputStream decorateOutputStream( - HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException { - if ("gzip".equals(request.getHeader("Compression"))) { - return new GZIPOutputStream(os); - } - else { - return os; - } - } - }; - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - - pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { - @Override - protected RemoteInvocationResult doExecuteRequest( - HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) - throws IOException, ClassNotFoundException { - assertThat(config.getServiceUrl()).isEqualTo("https://myurl"); - MockHttpServletRequest request = new MockHttpServletRequest(); - request.addHeader("Compression", "gzip"); - MockHttpServletResponse response = new MockHttpServletResponse(); - request.setContent(baos.toByteArray()); - try { - exporter.handleRequest(request, response); - } - catch (ServletException ex) { - throw new IOException(ex.toString()); - } - return readRemoteInvocationResult( - new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); - } - @Override - protected OutputStream decorateOutputStream(OutputStream os) throws IOException { - return new GZIPOutputStream(os); - } - @Override - protected InputStream decorateInputStream(InputStream is) throws IOException { - return new GZIPInputStream(is); - } - }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - proxy.setAge(50); - assertThat(proxy.getAge()).isEqualTo(50); - - assertThatIllegalStateException().isThrownBy(() -> - proxy.exceptional(new IllegalStateException())); - assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(() -> - proxy.exceptional(new IllegalAccessException())); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithWrappedInvocations() { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter() { - @Override - protected RemoteInvocation doReadRemoteInvocation(ObjectInputStream ois) - throws IOException, ClassNotFoundException { - Object obj = ois.readObject(); - if (!(obj instanceof TestRemoteInvocationWrapper)) { - throw new IOException("Deserialized object needs to be assignable to type [" + - TestRemoteInvocationWrapper.class.getName() + "]: " + obj); - } - return ((TestRemoteInvocationWrapper) obj).remoteInvocation; - } - @Override - protected void doWriteRemoteInvocationResult(RemoteInvocationResult result, ObjectOutputStream oos) - throws IOException { - oos.writeObject(new TestRemoteInvocationResultWrapper(result)); - } - }; - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - - pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { - @Override - protected RemoteInvocationResult doExecuteRequest( - HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { - assertThat(config.getServiceUrl()).isEqualTo("https://myurl"); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - request.setContent(baos.toByteArray()); - exporter.handleRequest(request, response); - return readRemoteInvocationResult( - new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); - } - @Override - protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException { - oos.writeObject(new TestRemoteInvocationWrapper(invocation)); - } - @Override - protected RemoteInvocationResult doReadRemoteInvocationResult(ObjectInputStream ois) - throws IOException, ClassNotFoundException { - Object obj = ois.readObject(); - if (!(obj instanceof TestRemoteInvocationResultWrapper)) { - throw new IOException("Deserialized object needs to be assignable to type [" - + TestRemoteInvocationResultWrapper.class.getName() + "]: " + obj); - } - return ((TestRemoteInvocationResultWrapper) obj).remoteInvocationResult; - } - }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - proxy.setAge(50); - assertThat(proxy.getAge()).isEqualTo(50); - - assertThatIllegalStateException().isThrownBy(() -> - proxy.exceptional(new IllegalStateException())); - assertThatExceptionOfType(IllegalAccessException.class).isThrownBy(() -> - proxy.exceptional(new IllegalAccessException())); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithInvocationAttributes() { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.setRemoteInvocationExecutor(new DefaultRemoteInvocationExecutor() { - @Override - public Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - assertThat(invocation.getAttributes()).isNotNull(); - assertThat(invocation.getAttributes().size()).isEqualTo(1); - assertThat(invocation.getAttributes().get("myKey")).isEqualTo("myValue"); - assertThat(invocation.getAttribute("myKey")).isEqualTo("myValue"); - return super.invoke(invocation, targetObject); - } - }); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - pfb.setRemoteInvocationFactory(methodInvocation -> { - RemoteInvocation invocation = new RemoteInvocation(methodInvocation); - invocation.addAttribute("myKey", "myValue"); - assertThatIllegalStateException().isThrownBy(() -> - invocation.addAttribute("myKey", "myValue")); - assertThat(invocation.getAttributes()).isNotNull(); - assertThat(invocation.getAttributes().size()).isEqualTo(1); - assertThat(invocation.getAttributes().get("myKey")).isEqualTo("myValue"); - assertThat(invocation.getAttribute("myKey")).isEqualTo("myValue"); - return invocation; - }); - - pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { - @Override - protected RemoteInvocationResult doExecuteRequest( - HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { - assertThat(config.getServiceUrl()).isEqualTo("https://myurl"); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - request.setContent(baos.toByteArray()); - exporter.handleRequest(request, response); - return readRemoteInvocationResult( - new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); - } - }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - } - - @Test - void httpInvokerProxyFactoryBeanAndServiceExporterWithCustomInvocationObject() { - TestBean target = new TestBean("myname", 99); - - final HttpInvokerServiceExporter exporter = new HttpInvokerServiceExporter(); - exporter.setServiceInterface(ITestBean.class); - exporter.setService(target); - exporter.setRemoteInvocationExecutor(new DefaultRemoteInvocationExecutor() { - @Override - public Object invoke(RemoteInvocation invocation, Object targetObject) - throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { - boolean condition = invocation instanceof TestRemoteInvocation; - assertThat(condition).isTrue(); - assertThat(invocation.getAttributes()).isNull(); - assertThat(invocation.getAttribute("myKey")).isNull(); - return super.invoke(invocation, targetObject); - } - }); - exporter.afterPropertiesSet(); - - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl("https://myurl"); - pfb.setRemoteInvocationFactory(methodInvocation -> { - RemoteInvocation invocation = new TestRemoteInvocation(methodInvocation); - assertThat(invocation.getAttributes()).isNull(); - assertThat(invocation.getAttribute("myKey")).isNull(); - return invocation; - }); - - pfb.setHttpInvokerRequestExecutor(new AbstractHttpInvokerRequestExecutor() { - @Override - protected RemoteInvocationResult doExecuteRequest( - HttpInvokerClientConfiguration config, ByteArrayOutputStream baos) throws Exception { - assertThat(config.getServiceUrl()).isEqualTo("https://myurl"); - MockHttpServletRequest request = new MockHttpServletRequest(); - MockHttpServletResponse response = new MockHttpServletResponse(); - request.setContent(baos.toByteArray()); - exporter.handleRequest(request, response); - return readRemoteInvocationResult( - new ByteArrayInputStream(response.getContentAsByteArray()), config.getCodebaseUrl()); - } - }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - assertThat(proxy.getName()).isEqualTo("myname"); - assertThat(proxy.getAge()).isEqualTo(99); - } - - @Test - void httpInvokerWithSpecialLocalMethods() { - String serviceUrl = "https://myurl"; - HttpInvokerProxyFactoryBean pfb = new HttpInvokerProxyFactoryBean(); - pfb.setServiceInterface(ITestBean.class); - pfb.setServiceUrl(serviceUrl); - - pfb.setHttpInvokerRequestExecutor((config, invocation) -> { throw new IOException("argh"); }); - - pfb.afterPropertiesSet(); - ITestBean proxy = (ITestBean) pfb.getObject(); - - // shouldn't go through to remote service - assertThat(proxy.toString().contains("HTTP invoker")).isTrue(); - assertThat(proxy.toString().contains(serviceUrl)).isTrue(); - assertThat(proxy.hashCode()).isEqualTo(proxy.hashCode()); - assertThat(proxy.equals(proxy)).isTrue(); - - // should go through - assertThatExceptionOfType(RemoteAccessException.class) - .isThrownBy(() -> proxy.setAge(50)) - .withCauseInstanceOf(IOException.class); - } - - - @SuppressWarnings("serial") - private static class TestRemoteInvocation extends RemoteInvocation { - - TestRemoteInvocation(MethodInvocation methodInvocation) { - super(methodInvocation); - } - } - - - @SuppressWarnings("serial") - private static class TestRemoteInvocationWrapper implements Serializable { - - private final RemoteInvocation remoteInvocation; - - TestRemoteInvocationWrapper(RemoteInvocation remoteInvocation) { - this.remoteInvocation = remoteInvocation; - } - } - - - @SuppressWarnings("serial") - private static class TestRemoteInvocationResultWrapper implements Serializable { - - private final RemoteInvocationResult remoteInvocationResult; - - TestRemoteInvocationResultWrapper(RemoteInvocationResult remoteInvocationResult) { - this.remoteInvocationResult = remoteInvocationResult; - } - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java b/spring-web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java deleted file mode 100644 index 1a2d4f06a5..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2002-2019 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.MalformedURLException; -import java.net.URL; - -import javax.xml.namespace.QName; -import javax.xml.ws.BindingProvider; -import javax.xml.ws.Service; -import javax.xml.ws.WebServiceClient; -import javax.xml.ws.WebServiceException; -import javax.xml.ws.WebServiceFeature; -import javax.xml.ws.WebServiceRef; -import javax.xml.ws.soap.AddressingFeature; - -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.annotation.AnnotationConfigUtils; -import org.springframework.context.support.GenericApplicationContext; -import org.springframework.remoting.RemoteAccessException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -/** - * @author Juergen Hoeller - * @since 2.5 - */ -public class JaxWsSupportTests { - - @Test - public void testJaxWsPortAccess() throws Exception { - doTestJaxWsPortAccess((WebServiceFeature[]) null); - } - - @Test - public void testJaxWsPortAccessWithFeature() throws Exception { - doTestJaxWsPortAccess(new AddressingFeature()); - } - - private void doTestJaxWsPortAccess(WebServiceFeature... features) throws Exception { - GenericApplicationContext ac = new GenericApplicationContext(); - - GenericBeanDefinition serviceDef = new GenericBeanDefinition(); - serviceDef.setBeanClass(OrderServiceImpl.class); - ac.registerBeanDefinition("service", serviceDef); - - GenericBeanDefinition exporterDef = new GenericBeanDefinition(); - exporterDef.setBeanClass(SimpleJaxWsServiceExporter.class); - exporterDef.getPropertyValues().add("baseAddress", "http://localhost:9999/"); - ac.registerBeanDefinition("exporter", exporterDef); - - GenericBeanDefinition clientDef = new GenericBeanDefinition(); - clientDef.setBeanClass(JaxWsPortProxyFactoryBean.class); - clientDef.getPropertyValues().add("wsdlDocumentUrl", "http://localhost:9999/OrderService?wsdl"); - clientDef.getPropertyValues().add("namespaceUri", "http://jaxws.remoting.springframework.org/"); - clientDef.getPropertyValues().add("username", "juergen"); - clientDef.getPropertyValues().add("password", "hoeller"); - clientDef.getPropertyValues().add("serviceName", "OrderService"); - clientDef.getPropertyValues().add("serviceInterface", OrderService.class); - clientDef.getPropertyValues().add("lookupServiceOnStartup", Boolean.FALSE); - if (features != null) { - clientDef.getPropertyValues().add("portFeatures", features); - } - ac.registerBeanDefinition("client", clientDef); - - GenericBeanDefinition serviceFactoryDef = new GenericBeanDefinition(); - serviceFactoryDef.setBeanClass(LocalJaxWsServiceFactoryBean.class); - serviceFactoryDef.getPropertyValues().add("wsdlDocumentUrl", "http://localhost:9999/OrderService?wsdl"); - serviceFactoryDef.getPropertyValues().add("namespaceUri", "http://jaxws.remoting.springframework.org/"); - serviceFactoryDef.getPropertyValues().add("serviceName", "OrderService"); - ac.registerBeanDefinition("orderService", serviceFactoryDef); - - ac.registerBeanDefinition("accessor", new RootBeanDefinition(ServiceAccessor.class)); - AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); - - try { - ac.refresh(); - - OrderService orderService = ac.getBean("client", OrderService.class); - boolean condition = orderService instanceof BindingProvider; - assertThat(condition).isTrue(); - ((BindingProvider) orderService).getRequestContext(); - - String order = orderService.getOrder(1000); - assertThat(order).isEqualTo("order 1000"); - assertThatExceptionOfType(Exception.class).isThrownBy(() -> - orderService.getOrder(0)) - .matches(ex -> ex instanceof OrderNotFoundException || - ex instanceof RemoteAccessException); - // ignore RemoteAccessException as probably setup issue with JAX-WS provider vs JAXB - - ServiceAccessor serviceAccessor = ac.getBean("accessor", ServiceAccessor.class); - order = serviceAccessor.orderService.getOrder(1000); - assertThat(order).isEqualTo("order 1000"); - assertThatExceptionOfType(Exception.class).isThrownBy(() -> - serviceAccessor.orderService.getOrder(0)) - .matches(ex -> ex instanceof OrderNotFoundException || - ex instanceof WebServiceException); - // ignore WebServiceException as probably setup issue with JAX-WS provider vs JAXB - } - catch (BeanCreationException ex) { - if ("exporter".equals(ex.getBeanName()) && ex.getRootCause() instanceof ClassNotFoundException) { - // ignore - probably running on JDK without the JAX-WS impl present - } - else { - throw ex; - } - } - finally { - ac.close(); - } - } - - - public static class ServiceAccessor { - - @WebServiceRef - public OrderService orderService; - - public OrderService myService; - - @WebServiceRef(value = OrderServiceService.class, wsdlLocation = "http://localhost:9999/OrderService?wsdl") - public void setMyService(OrderService myService) { - this.myService = myService; - } - } - - - @WebServiceClient(targetNamespace = "http://jaxws.remoting.springframework.org/", name="OrderService") - public static class OrderServiceService extends Service { - - public OrderServiceService() throws MalformedURLException { - super(new URL("http://localhost:9999/OrderService?wsdl"), - new QName("http://jaxws.remoting.springframework.org/", "OrderService")); - } - - public OrderServiceService(URL wsdlDocumentLocation, QName serviceName) { - super(wsdlDocumentLocation, serviceName); - } - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java b/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java deleted file mode 100644 index 58cc650d10..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderNotFoundException.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2002-2019 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.WebFault; - -/** - * @author Juergen Hoeller - */ -@WebFault -@SuppressWarnings("serial") -public class OrderNotFoundException extends Exception { - - private final String faultInfo; - - public OrderNotFoundException(String message) { - super(message); - this.faultInfo = null; - } - - public OrderNotFoundException(String message, String faultInfo) { - super(message); - this.faultInfo = faultInfo; - } - - public String getFaultInfo() { - return this.faultInfo; - } - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderService.java b/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderService.java deleted file mode 100644 index 2b29d13cb3..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderService.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2002-2007 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.jws.soap.SOAPBinding; - -/** - * @author Juergen Hoeller - */ -@WebService -@SOAPBinding(style = SOAPBinding.Style.RPC) -public interface OrderService { - - String getOrder(int id) throws OrderNotFoundException; - -} diff --git a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java b/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java deleted file mode 100644 index 3f9c9781b3..0000000000 --- a/spring-web/src/test/java/org/springframework/remoting/jaxws/OrderServiceImpl.java +++ /dev/null @@ -1,44 +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.annotation.Resource; -import javax.jws.WebService; -import javax.xml.ws.WebServiceContext; - -import org.springframework.util.Assert; - -/** - * @author Juergen Hoeller - */ -@WebService(serviceName="OrderService", portName="OrderService", - endpointInterface = "org.springframework.remoting.jaxws.OrderService") -public class OrderServiceImpl implements OrderService { - - @Resource - private WebServiceContext webServiceContext; - - @Override - public String getOrder(int id) throws OrderNotFoundException { - Assert.notNull(this.webServiceContext, "WebServiceContext has not been injected"); - if (id == 0) { - throw new OrderNotFoundException("Order 0 not found"); - } - return "order " + id; - } - -}