Initial import of web module
This commit is contained in:
parent
d1061e7e9f
commit
04eaa47ec1
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="org.springframework.orm">
|
||||
<property file="${basedir}/../build.properties"/>
|
||||
<import file="${basedir}/../build-spring-framework/package-bundle.xml"/>
|
||||
<import file="${basedir}/../spring-build/standard/default.xml"/>
|
||||
</project>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
|
||||
<ivy-module
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
|
||||
version="1.3">
|
||||
|
||||
<info organisation="org.springframework" module="${ant.project.name}">
|
||||
<license name="Apache 2.0" url="http://www.apache.org/licenses/LICENSE-2.0"/>
|
||||
</info>
|
||||
|
||||
<configurations>
|
||||
<include file="${spring.build.dir}/common/default-ivy-configurations.xml"/>
|
||||
</configurations>
|
||||
|
||||
<publications>
|
||||
<artifact name="${ant.project.name}"/>
|
||||
<artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
|
||||
</publications>
|
||||
|
||||
<dependencies>
|
||||
<!-- compile dependencies -->
|
||||
<dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1" conf="compile->runtime" />
|
||||
<dependency org="org.springframework" name="org.springframework.core" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.beans" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.context" rev="latest.integration" conf="optional->compile" />
|
||||
<!--
|
||||
<dependency org="org.springframework" name="org.springframework.aop" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.transaction" rev="latest.integration" conf="compile->compile" />
|
||||
<dependency org="org.springframework" name="org.springframework.jdbc" rev="latest.integration" conf="compile->compile" />
|
||||
-->
|
||||
<!-- optional dependencies -->
|
||||
<dependency org="javax.el" name="com.springsource.javax.el" rev="2.1.0" conf="optional->compile" />
|
||||
<dependency org="javax.servlet" name="com.springsource.javax.servlet" rev="2.5.0" conf="optional->compile" />
|
||||
<dependency org="javax.servlet" name="com.springsource.javax.servlet.jsp" rev="2.1.0" conf="optional->compile" />
|
||||
<dependency org="org.apache.myfaces" name="com.springsource.org.apache.myfaces.javax.faces" rev="1.2.2" conf="optional->compile" />
|
||||
<dependency org="org.apache.taglibs" name="com.springsource.org.apache.taglibs.standard" rev="1.1.2" conf="optional->compile" />
|
||||
<dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15" conf="optional->runtime" />
|
||||
<dependency org="javax.xml.rpc" name="com.springsource.javax.xml.rpc" rev="1.1.0" conf="optional->runtime" />
|
||||
<dependency org="org.apache.axis" name="com.springsource.org.apache.axis" rev="1.4.0" conf="optional->runtime" />
|
||||
<dependency org="com.caucho" name="com.springsource.com.caucho" rev="3.1.5" conf="optional->runtime" />
|
||||
<!-- test dependencies -->
|
||||
<dependency org="org.junit" name="com.springsource.org.junit" rev="4.4.0" conf="test->runtime" />
|
||||
|
||||
</dependencies>
|
||||
|
||||
</ivy-module>
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>org.springframework.core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Core Abstractions and Utilities</name>
|
||||
<version>3.0.0.M1</version>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>com.springsource.repository.bundles.external</id>
|
||||
<name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
|
||||
<url>http://repository.springsource.com/maven/bundles/external</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>com.springsource.org.apache.commons.logging</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.log4j</groupId>
|
||||
<artifactId>com.springsource.org.apache.log4j</artifactId>
|
||||
<version>1.2.15</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>com.springsource.org.apache.commons.collections</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
|
||||
<version>1.6.2.RELEASE</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.objectweb.asm</groupId>
|
||||
<artifactId>com.springsource.org.objectweb.asm.commons</artifactId>
|
||||
<version>2.2.3</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.burlap.client.BurlapProxyFactory;
|
||||
import com.caucho.burlap.client.BurlapRuntimeException;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
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 Burlap service.
|
||||
* Supports authentication via username and password.
|
||||
* The service URL must be an HTTP URL exposing a Burlap service.
|
||||
*
|
||||
* <p>Burlap is a slim, XML-based RPC protocol.
|
||||
* For information on Burlap, see the
|
||||
* <a href="http://www.caucho.com/burlap">Burlap website</a>
|
||||
*
|
||||
* <p>Note: There is no requirement for services accessed with this proxy factory
|
||||
* to have been exported using Spring's {@link BurlapServiceExporter}, 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.burlap.server.BurlapServlet}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 29.09.2003
|
||||
* @see #setServiceInterface
|
||||
* @see #setServiceUrl
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @see BurlapServiceExporter
|
||||
* @see BurlapProxyFactoryBean
|
||||
* @see com.caucho.burlap.client.BurlapProxyFactory
|
||||
* @see com.caucho.burlap.server.BurlapServlet
|
||||
*/
|
||||
public class BurlapClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
|
||||
|
||||
private BurlapProxyFactory proxyFactory = new BurlapProxyFactory();
|
||||
|
||||
private Object burlapProxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the BurlapProxyFactory instance to use.
|
||||
* If not specified, a default BurlapProxyFactory will be created.
|
||||
* <p>Allows to use an externally configured factory instance,
|
||||
* in particular a custom BurlapProxyFactory subclass.
|
||||
*/
|
||||
public void setProxyFactory(BurlapProxyFactory proxyFactory) {
|
||||
this.proxyFactory = (proxyFactory != null ? proxyFactory : new BurlapProxyFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username that this factory should use to access the remote service.
|
||||
* Default is none.
|
||||
* <p>The username will be sent by Burlap via HTTP Basic Authentication.
|
||||
* @see com.caucho.burlap.client.BurlapProxyFactory#setUser
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.proxyFactory.setUser(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password that this factory should use to access the remote service.
|
||||
* Default is none.
|
||||
* <p>The password will be sent by Burlap via HTTP Basic Authentication.
|
||||
* @see com.caucho.burlap.client.BurlapProxyFactory#setPassword
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.proxyFactory.setPassword(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether overloaded methods should be enabled for remote invocations.
|
||||
* Default is "false".
|
||||
* @see com.caucho.burlap.client.BurlapProxyFactory#setOverloadEnabled
|
||||
*/
|
||||
public void setOverloadEnabled(boolean overloadEnabled) {
|
||||
this.proxyFactory.setOverloadEnabled(overloadEnabled);
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
prepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Burlap proxy for this interceptor.
|
||||
* @throws RemoteLookupFailureException if the service URL is invalid
|
||||
*/
|
||||
public void prepare() throws RemoteLookupFailureException {
|
||||
try {
|
||||
this.burlapProxy = createBurlapProxy(this.proxyFactory);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Burlap proxy that is wrapped by this interceptor.
|
||||
* @param proxyFactory the proxy factory to use
|
||||
* @return the Burlap proxy
|
||||
* @throws MalformedURLException if thrown by the proxy factory
|
||||
* @see com.caucho.burlap.client.BurlapProxyFactory#create
|
||||
*/
|
||||
protected Object createBurlapProxy(BurlapProxyFactory proxyFactory) throws MalformedURLException {
|
||||
Assert.notNull(getServiceInterface(), "Property 'serviceInterface' is required");
|
||||
return proxyFactory.create(getServiceInterface(), getServiceUrl());
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
if (this.burlapProxy == null) {
|
||||
throw new IllegalStateException("BurlapClientInterceptor is not properly initialized - " +
|
||||
"invoke 'prepare' before attempting any operations");
|
||||
}
|
||||
|
||||
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
|
||||
try {
|
||||
return invocation.getMethod().invoke(this.burlapProxy, invocation.getArguments());
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof BurlapRuntimeException) {
|
||||
BurlapRuntimeException bre = (BurlapRuntimeException) ex.getTargetException();
|
||||
Throwable rootCause = (bre.getRootCause() != null ? bre.getRootCause() : bre);
|
||||
throw convertBurlapAccessException(rootCause);
|
||||
}
|
||||
else if (ex.getTargetException() instanceof UndeclaredThrowableException) {
|
||||
UndeclaredThrowableException utex = (UndeclaredThrowableException) ex.getTargetException();
|
||||
throw convertBurlapAccessException(utex.getUndeclaredThrowable());
|
||||
}
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new RemoteProxyFailureException(
|
||||
"Failed to invoke Burlap proxy for remote service [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
finally {
|
||||
resetThreadContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given Burlap access exception to an appropriate
|
||||
* Spring RemoteAccessException.
|
||||
* @param ex the exception to convert
|
||||
* @return the RemoteAccessException to throw
|
||||
*/
|
||||
protected RemoteAccessException convertBurlapAccessException(Throwable ex) {
|
||||
if (ex instanceof ConnectException) {
|
||||
return new RemoteConnectFailureException(
|
||||
"Cannot connect to Burlap remote service at [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
else {
|
||||
return new RemoteAccessException(
|
||||
"Cannot access Burlap remote service at [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import com.caucho.burlap.io.BurlapInput;
|
||||
import com.caucho.burlap.io.BurlapOutput;
|
||||
import com.caucho.burlap.server.BurlapSkeleton;
|
||||
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.remoting.support.RemoteExporter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* General stream-based protocol exporter for a Burlap endpoint.
|
||||
*
|
||||
* <p>Burlap is a slim, XML-based RPC protocol.
|
||||
* For information on Burlap, see the
|
||||
* <a href="http://www.caucho.com/burlap">Burlap website</a>.
|
||||
*
|
||||
* <p>This exporter will work with both Burlap 2.x and 3.x (respectively
|
||||
* Resin 2.x and 3.x), autodetecting the corresponding skeleton class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @see #invoke(java.io.InputStream, java.io.OutputStream)
|
||||
* @see BurlapServiceExporter
|
||||
* @see SimpleBurlapServiceExporter
|
||||
*/
|
||||
public class BurlapExporter extends RemoteExporter implements InitializingBean {
|
||||
|
||||
private BurlapSkeleton skeleton;
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
prepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this service exporter.
|
||||
*/
|
||||
public void prepare() {
|
||||
try {
|
||||
try {
|
||||
// Try Burlap 3.x (with service interface argument).
|
||||
Constructor ctor = BurlapSkeleton.class.getConstructor(new Class[] {Object.class, Class.class});
|
||||
checkService();
|
||||
checkServiceInterface();
|
||||
this.skeleton = (BurlapSkeleton)
|
||||
ctor.newInstance(new Object[] {getProxyForService(), getServiceInterface()});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
// Fall back to Burlap 2.x (without service interface argument).
|
||||
Constructor ctor = BurlapSkeleton.class.getConstructor(new Class[] {Object.class});
|
||||
this.skeleton = (BurlapSkeleton) ctor.newInstance(new Object[] {getProxyForService()});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BeanInitializationException("Burlap skeleton initialization failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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, "Burlap exporter has not been initialized");
|
||||
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
|
||||
try {
|
||||
this.skeleton.invoke(new BurlapInput(inputStream), new BurlapOutput(outputStream));
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
try {
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
resetThreadContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* FactoryBean for Burlap proxies. Exposes the proxied service for
|
||||
* use as a bean reference, using the specified service interface.
|
||||
*
|
||||
* <p>Burlap is a slim, XML-based RPC protocol.
|
||||
* For information on Burlap, see the
|
||||
* <a href="http://www.caucho.com/burlap">Burlap website</a>
|
||||
*
|
||||
* <p>The service URL must be an HTTP URL exposing a Burlap service.
|
||||
* For details, see the {@link BurlapClientInterceptor} javadoc.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 13.05.2003
|
||||
* @see #setServiceInterface
|
||||
* @see #setServiceUrl
|
||||
* @see BurlapClientInterceptor
|
||||
* @see BurlapServiceExporter
|
||||
* @see org.springframework.remoting.caucho.HessianProxyFactoryBean
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
|
||||
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
|
||||
*/
|
||||
public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements FactoryBean {
|
||||
|
||||
private Object serviceProxy;
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.serviceProxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return getServiceInterface();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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 Burlap service endpoint, accessible via a Burlap proxy.
|
||||
*
|
||||
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
|
||||
* for Sun's JRE 1.6 HTTP server: {@link SimpleBurlapServiceExporter}.
|
||||
*
|
||||
* <p>Burlap is a slim, XML-based RPC protocol.
|
||||
* For information on Burlap, see the
|
||||
* <a href="http://www.caucho.com/burlap">Burlap website</a>.
|
||||
*
|
||||
* <p>This exporter will work with both Burlap 2.x and 3.x (respectively
|
||||
* Resin 2.x and 3.x), autodetecting the corresponding skeleton class.
|
||||
*
|
||||
* <p>Note: Burlap services exported with this class can be accessed by
|
||||
* any Burlap client, as there isn't any special handling involved.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 13.05.2003
|
||||
* @see BurlapClientInterceptor
|
||||
* @see BurlapProxyFactoryBean
|
||||
* @see org.springframework.remoting.caucho.HessianServiceExporter
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
|
||||
* @see org.springframework.remoting.rmi.RmiServiceExporter
|
||||
*/
|
||||
public class BurlapServiceExporter extends BurlapExporter implements HttpRequestHandler {
|
||||
|
||||
/**
|
||||
* Processes the incoming Burlap request and creates a Burlap response.
|
||||
*/
|
||||
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (!"POST".equals(request.getMethod())) {
|
||||
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
|
||||
new String[] {"POST"}, "BurlapServiceExporter only supports POST requests");
|
||||
}
|
||||
|
||||
try {
|
||||
invoke(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new NestedServletException("Burlap skeleton invocation failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.caucho.hessian.io.HessianInput;
|
||||
import com.caucho.hessian.io.HessianOutput;
|
||||
import com.caucho.hessian.io.SerializerFactory;
|
||||
import com.caucho.hessian.server.HessianSkeleton;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Concrete HessianSkeletonInvoker for the Hessian 1 protocol
|
||||
* (version 3.0.19 or lower).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
class Hessian1SkeletonInvoker extends HessianSkeletonInvoker {
|
||||
|
||||
private static final Method invokeMethod;
|
||||
|
||||
private static final boolean applySerializerFactoryToOutput;
|
||||
|
||||
static {
|
||||
invokeMethod = ClassUtils.getMethodIfAvailable(
|
||||
HessianSkeleton.class, "invoke", new Class[] {HessianInput.class, HessianOutput.class});
|
||||
applySerializerFactoryToOutput =
|
||||
ClassUtils.hasMethod(HessianOutput.class, "setSerializerFactory", new Class[] {SerializerFactory.class});
|
||||
}
|
||||
|
||||
|
||||
public Hessian1SkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory) {
|
||||
super(skeleton, serializerFactory);
|
||||
if (invokeMethod == null) {
|
||||
throw new IllegalStateException("Hessian 1 (version 3.0.19-) not present");
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable {
|
||||
HessianInput in = new HessianInput(inputStream);
|
||||
HessianOutput out = new HessianOutput(outputStream);
|
||||
if (this.serializerFactory != null) {
|
||||
in.setSerializerFactory(this.serializerFactory);
|
||||
if (applySerializerFactoryToOutput) {
|
||||
out.setSerializerFactory(this.serializerFactory);
|
||||
}
|
||||
}
|
||||
try {
|
||||
invokeMethod.invoke(this.skeleton, new Object[] {in, out});
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
in.close();
|
||||
inputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
try {
|
||||
out.close();
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
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.HessianOutput;
|
||||
import com.caucho.hessian.io.SerializerFactory;
|
||||
import com.caucho.hessian.server.HessianSkeleton;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CommonsLogWriter;
|
||||
|
||||
/**
|
||||
* Concrete HessianSkeletonInvoker for the Hessian 2 protocol
|
||||
* (version 3.0.20 or higher).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Andy Piper
|
||||
* @since 2.0
|
||||
*/
|
||||
class Hessian2SkeletonInvoker extends HessianSkeletonInvoker {
|
||||
|
||||
private static final boolean debugOutputStreamAvailable = ClassUtils.isPresent(
|
||||
"com.caucho.hessian.io.HessianDebugOutputStream", Hessian2SkeletonInvoker.class.getClassLoader());
|
||||
|
||||
private final Log debugLogger;
|
||||
|
||||
|
||||
public Hessian2SkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory, Log debugLog) {
|
||||
super(skeleton, serializerFactory);
|
||||
this.debugLogger = debugLog;
|
||||
}
|
||||
|
||||
public void invoke(final InputStream inputStream, final OutputStream outputStream) throws Throwable {
|
||||
InputStream isToUse = inputStream;
|
||||
OutputStream osToUse = outputStream;
|
||||
|
||||
if (this.debugLogger != null && this.debugLogger.isDebugEnabled()) {
|
||||
PrintWriter debugWriter = new PrintWriter(new CommonsLogWriter(this.debugLogger));
|
||||
isToUse = new HessianDebugInputStream(inputStream, debugWriter);
|
||||
if (debugOutputStreamAvailable) {
|
||||
osToUse = DebugStreamFactory.createDebugOutputStream(outputStream, debugWriter);
|
||||
}
|
||||
}
|
||||
|
||||
Hessian2Input in = new Hessian2Input(isToUse);
|
||||
if (this.serializerFactory != null) {
|
||||
in.setSerializerFactory(this.serializerFactory);
|
||||
}
|
||||
|
||||
int code = in.read();
|
||||
if (code != 'c') {
|
||||
throw new IOException("expected 'c' in hessian input at " + code);
|
||||
}
|
||||
|
||||
AbstractHessianOutput out = null;
|
||||
int major = in.read();
|
||||
int minor = in.read();
|
||||
if (major >= 2) {
|
||||
out = new Hessian2Output(osToUse);
|
||||
}
|
||||
else {
|
||||
out = new HessianOutput(osToUse);
|
||||
}
|
||||
if (this.serializerFactory != null) {
|
||||
out.setSerializerFactory(this.serializerFactory);
|
||||
}
|
||||
|
||||
try {
|
||||
this.skeleton.invoke(in, out);
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
in.close();
|
||||
isToUse.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
try {
|
||||
out.close();
|
||||
osToUse.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard dependency on Hessian 3.1.3's HessianDebugOutputStream.
|
||||
*/
|
||||
private static class DebugStreamFactory {
|
||||
|
||||
public static OutputStream createDebugOutputStream(OutputStream os, PrintWriter debug) {
|
||||
return new HessianDebugOutputStream(os, debug);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.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.remoting.RemoteAccessException;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.RemoteProxyFailureException;
|
||||
import org.springframework.remoting.support.UrlBasedRemoteAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Hessian service.
|
||||
* Supports authentication via username and password.
|
||||
* The service URL must be an HTTP URL exposing a Hessian service.
|
||||
*
|
||||
* <p>Hessian is a slim, binary RPC protocol.
|
||||
* For information on Hessian, see the
|
||||
* <a href="http://www.caucho.com/hessian">Hessian website</a>
|
||||
*
|
||||
* <p>Note: There is no requirement for services accessed with this proxy factory
|
||||
* to have been exported using Spring's {@link HessianServiceExporter}, as there is
|
||||
* no special handling involved. As a consequence, you can also access services that
|
||||
* have been exported using Caucho's {@link com.caucho.hessian.server.HessianServlet}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 29.09.2003
|
||||
* @see #setServiceInterface
|
||||
* @see #setServiceUrl
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @see HessianServiceExporter
|
||||
* @see HessianProxyFactoryBean
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory
|
||||
* @see com.caucho.hessian.server.HessianServlet
|
||||
*/
|
||||
public class HessianClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
|
||||
|
||||
private HessianProxyFactory proxyFactory = new HessianProxyFactory();
|
||||
|
||||
private Object hessianProxy;
|
||||
|
||||
|
||||
/**
|
||||
* Set the HessianProxyFactory instance to use.
|
||||
* If not specified, a default HessianProxyFactory will be created.
|
||||
* <p>Allows to use an externally configured factory instance,
|
||||
* in particular a custom HessianProxyFactory subclass.
|
||||
*/
|
||||
public void setProxyFactory(HessianProxyFactory proxyFactory) {
|
||||
this.proxyFactory = (proxyFactory != null ? proxyFactory : new HessianProxyFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the Hessian SerializerFactory to use.
|
||||
* <p>This will typically be passed in as an inner bean definition
|
||||
* of type <code>com.caucho.hessian.io.SerializerFactory</code>,
|
||||
* 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 overloaded methods should be enabled for remote invocations.
|
||||
* Default is "false".
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory#setOverloadEnabled
|
||||
*/
|
||||
public void setOverloadEnabled(boolean overloadEnabled) {
|
||||
this.proxyFactory.setOverloadEnabled(overloadEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username that this factory should use to access the remote service.
|
||||
* Default is none.
|
||||
* <p>The username will be sent by Hessian via HTTP Basic Authentication.
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory#setUser
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.proxyFactory.setUser(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password that this factory should use to access the remote service.
|
||||
* Default is none.
|
||||
* <p>The password will be sent by Hessian via HTTP Basic Authentication.
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory#setPassword
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.proxyFactory.setPassword(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether Hessian's debug mode should be enabled.
|
||||
* Default is "false".
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory#setDebug
|
||||
*/
|
||||
public void setDebug(boolean debug) {
|
||||
this.proxyFactory.setDebug(debug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use a chunked post for sending a Hessian request.
|
||||
* @see com.caucho.hessian.client.HessianProxyFactory#setChunkedPost
|
||||
*/
|
||||
public void setChunkedPost(boolean chunkedPost) {
|
||||
this.proxyFactory.setChunkedPost(chunkedPost);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
if (ex.getTargetException() instanceof HessianRuntimeException) {
|
||||
HessianRuntimeException hre = (HessianRuntimeException) ex.getTargetException();
|
||||
Throwable rootCause = (hre.getRootCause() != null ? hre.getRootCause() : hre);
|
||||
throw convertHessianAccessException(rootCause);
|
||||
}
|
||||
else if (ex.getTargetException() instanceof UndeclaredThrowableException) {
|
||||
UndeclaredThrowableException utex = (UndeclaredThrowableException) ex.getTargetException();
|
||||
throw convertHessianAccessException(utex.getUndeclaredThrowable());
|
||||
}
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import com.caucho.hessian.io.SerializerFactory;
|
||||
import com.caucho.hessian.server.HessianSkeleton;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.remoting.support.RemoteExporter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* General stream-based protocol exporter for a Hessian endpoint.
|
||||
*
|
||||
* <p>Hessian is a slim, binary RPC protocol.
|
||||
* For information on Hessian, see the
|
||||
* <a href="http://www.caucho.com/hessian">Hessian website</a>.
|
||||
*
|
||||
* <p>This exporter will work with both Hessian 2.x and 3.x (respectively
|
||||
* Resin 2.x and 3.x), autodetecting the corresponding skeleton class.
|
||||
* As of Spring 2.0, it is also compatible with the new Hessian 2 protocol
|
||||
* (a.k.a. Hessian 3.0.20+), while remaining compatible with older versions.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @see #invoke(java.io.InputStream, java.io.OutputStream)
|
||||
* @see HessianServiceExporter
|
||||
* @see SimpleHessianServiceExporter
|
||||
*/
|
||||
public class HessianExporter extends RemoteExporter implements InitializingBean {
|
||||
|
||||
private static final boolean hessian2Available =
|
||||
ClassUtils.isPresent("com.caucho.hessian.io.Hessian2Input", HessianServiceExporter.class.getClassLoader());
|
||||
|
||||
|
||||
private SerializerFactory serializerFactory = new SerializerFactory();
|
||||
|
||||
private Log debugLogger;
|
||||
|
||||
private HessianSkeletonInvoker skeletonInvoker;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the Hessian SerializerFactory to use.
|
||||
* <p>This will typically be passed in as an inner bean definition
|
||||
* of type <code>com.caucho.hessian.io.SerializerFactory</code>,
|
||||
* with custom bean property values applied.
|
||||
*/
|
||||
public void setSerializerFactory(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 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);
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
prepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this exporter.
|
||||
*/
|
||||
public void prepare() {
|
||||
HessianSkeleton skeleton = null;
|
||||
|
||||
try {
|
||||
try {
|
||||
// Try Hessian 3.x (with service interface argument).
|
||||
Constructor ctor = HessianSkeleton.class.getConstructor(new Class[] {Object.class, Class.class});
|
||||
checkService();
|
||||
checkServiceInterface();
|
||||
skeleton = (HessianSkeleton)
|
||||
ctor.newInstance(new Object[] {getProxyForService(), getServiceInterface()});
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
// Fall back to Hessian 2.x (without service interface argument).
|
||||
Constructor ctor = HessianSkeleton.class.getConstructor(new Class[] {Object.class});
|
||||
skeleton = (HessianSkeleton) ctor.newInstance(new Object[] {getProxyForService()});
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new BeanInitializationException("Hessian skeleton initialization failed", ex);
|
||||
}
|
||||
|
||||
if (hessian2Available) {
|
||||
// Hessian 2 (version 3.0.20+).
|
||||
this.skeletonInvoker = new Hessian2SkeletonInvoker(skeleton, this.serializerFactory, this.debugLogger);
|
||||
}
|
||||
else {
|
||||
// Hessian 1 (version 3.0.19-).
|
||||
this.skeletonInvoker = new Hessian1SkeletonInvoker(skeleton, this.serializerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.skeletonInvoker, "Hessian exporter has not been initialized");
|
||||
ClassLoader originalClassLoader = overrideThreadContextClassLoader();
|
||||
try {
|
||||
this.skeletonInvoker.invoke(inputStream, outputStream);
|
||||
}
|
||||
finally {
|
||||
resetThreadContextClassLoader(originalClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* FactoryBean for Hessian proxies. Exposes the proxied service for
|
||||
* use as a bean reference, using the specified service interface.
|
||||
*
|
||||
* <p>Hessian is a slim, binary RPC protocol.
|
||||
* For information on Hessian, see the
|
||||
* <a href="http://www.caucho.com/hessian">Hessian website</a>
|
||||
*
|
||||
* <p>The service URL must be an HTTP URL exposing a Hessian service.
|
||||
* For details, see the {@link HessianClientInterceptor} javadoc.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 13.05.2003
|
||||
* @see #setServiceInterface
|
||||
* @see #setServiceUrl
|
||||
* @see HessianClientInterceptor
|
||||
* @see HessianServiceExporter
|
||||
* @see org.springframework.remoting.caucho.BurlapProxyFactoryBean
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
|
||||
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
|
||||
*/
|
||||
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean {
|
||||
|
||||
private Object serviceProxy;
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.serviceProxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return getServiceInterface();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.remoting.caucho;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.util.NestedServletException;
|
||||
|
||||
/**
|
||||
* Servlet-API-based HTTP request handler that exports the specified service bean
|
||||
* as Hessian service endpoint, accessible via a Hessian proxy.
|
||||
*
|
||||
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
|
||||
* for Sun's JRE 1.6 HTTP server: {@link SimpleHessianServiceExporter}.
|
||||
*
|
||||
* <p>Hessian is a slim, binary RPC protocol.
|
||||
* For information on Hessian, see the
|
||||
* <a href="http://www.caucho.com/hessian">Hessian website</a>.
|
||||
*
|
||||
* <p>This exporter will work with both Hessian 2.x and 3.x (respectively
|
||||
* Resin 2.x and 3.x), autodetecting the corresponding skeleton class.
|
||||
* As of Spring 2.0, it is also compatible with the new Hessian 2 protocol
|
||||
* (a.k.a. Hessian 3.0.20+), while remaining compatible with older versions.
|
||||
*
|
||||
* <p>Note: 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.caucho.BurlapServiceExporter
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
|
||||
* @see org.springframework.remoting.rmi.RmiServiceExporter
|
||||
*/
|
||||
public class HessianServiceExporter extends HessianExporter implements HttpRequestHandler {
|
||||
|
||||
/**
|
||||
* Processes the incoming Hessian request and creates a Hessian response.
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
try {
|
||||
invoke(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new NestedServletException("Hessian skeleton invocation failed", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import com.caucho.hessian.server.HessianSkeleton;
|
||||
import com.caucho.hessian.io.SerializerFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Internal invoker strategy for a Hessian skeleton.
|
||||
* Allows for common handling of Hessian protocol version 1 and 2.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class HessianSkeletonInvoker {
|
||||
|
||||
/**
|
||||
* Wrapped HessianSkeleton, available to subclasses.
|
||||
*/
|
||||
protected final HessianSkeleton skeleton;
|
||||
|
||||
/**
|
||||
* Hessian SerializerFactory (if any), available to subclasses.
|
||||
*/
|
||||
protected final SerializerFactory serializerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new HessianSkeletonInvoker for the given skeleton.
|
||||
* @param skeleton the HessianSkeleton to wrap
|
||||
* @param serializerFactory the Hessian SerializerFactory to use, if any
|
||||
*/
|
||||
public HessianSkeletonInvoker(HessianSkeleton skeleton, SerializerFactory serializerFactory) {
|
||||
Assert.notNull(skeleton, "HessianSkeleton must not be null");
|
||||
this.skeleton = skeleton;
|
||||
this.serializerFactory = serializerFactory;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invoke the given skeleton based on the given input/output streams.
|
||||
* @param inputStream the stream containing the Hessian input
|
||||
* @param outputStream the stream to receive the Hessian output
|
||||
* @throws Throwable if the skeleton invocation failed
|
||||
*/
|
||||
public abstract void invoke(InputStream inputStream, OutputStream outputStream) throws Throwable;
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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
|
||||
* Burlap service endpoint, accessible via a Burlap proxy.
|
||||
* Designed for Sun's JRE 1.6 HTTP server, implementing the
|
||||
* {@link com.sun.net.httpserver.HttpHandler} interface.
|
||||
*
|
||||
* <p>Burlap is a slim, XML-based RPC protocol.
|
||||
* For information on Burlap, see the
|
||||
* <a href="http://www.caucho.com/burlap">Burlap website</a>.
|
||||
* This exporter requires Burlap 3.x.
|
||||
*
|
||||
* <p>Note: Burlap services exported with this class can be accessed by
|
||||
* any Burlap client, as there isn't any special handling involved.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @see org.springframework.remoting.caucho.BurlapClientInterceptor
|
||||
* @see org.springframework.remoting.caucho.BurlapProxyFactoryBean
|
||||
* @see SimpleHessianServiceExporter
|
||||
* @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter
|
||||
*/
|
||||
public class SimpleBurlapServiceExporter extends BurlapExporter implements HttpHandler {
|
||||
|
||||
/**
|
||||
* Processes the incoming Burlap request and creates a Burlap response.
|
||||
*/
|
||||
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);
|
||||
throw new IOException("Burlap skeleton invocation failed", ex);
|
||||
}
|
||||
|
||||
exchange.sendResponseHeaders(200, output.size());
|
||||
FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.remoting.caucho;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* HTTP request handler that exports the specified service bean as
|
||||
* Hessian service endpoint, accessible via a Hessian proxy.
|
||||
* Designed for Sun's JRE 1.6 HTTP server, implementing the
|
||||
* {@link com.sun.net.httpserver.HttpHandler} interface.
|
||||
*
|
||||
* <p>Hessian is a slim, binary RPC protocol.
|
||||
* For information on Hessian, see the
|
||||
* <a href="http://www.caucho.com/hessian">Hessian website</a>.
|
||||
* This exporter requires Hessian 3.0.20 or above.
|
||||
*
|
||||
* <p>Note: 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
|
||||
* @see SimpleBurlapServiceExporter
|
||||
* @see org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExporter
|
||||
*/
|
||||
public class SimpleHessianServiceExporter extends HessianExporter implements HttpHandler {
|
||||
|
||||
/**
|
||||
* Processes the incoming Hessian request and creates a Hessian response.
|
||||
*/
|
||||
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);
|
||||
throw new IOException("Hessian skeleton invocation failed", ex);
|
||||
}
|
||||
|
||||
exchange.sendResponseHeaders(200, output.size());
|
||||
FileCopyUtils.copy(output.toByteArray(), exchange.getResponseBody());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
This package provides remoting classes for Caucho's Hessian and Burlap
|
||||
protocols: a proxy factory for accessing Hessian/Burlap services,
|
||||
and an exporter for making beans available to Hessian/Burlap clients.
|
||||
|
||||
<p>Hessian is a slim, binary RPC protocol over HTTP.
|
||||
For information on Hessian, see the
|
||||
<a href="http://www.caucho.com/hessian">Hessian website</a>
|
||||
|
||||
<p>Burlap is a slim, XML-based RPC protocol over HTTP.
|
||||
For information on Burlap, see the
|
||||
<a href="http://www.caucho.com/burlap">Burlap website</a>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.remoting.rmi.CodebaseAwareObjectInputStream;
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract base implementation of the HttpInvokerRequestExecutor interface.
|
||||
*
|
||||
* <p>Pre-implements serialization of RemoteInvocation objects and
|
||||
* deserialization of RemoteInvocationResults objects.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see #doExecuteRequest
|
||||
*/
|
||||
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";
|
||||
|
||||
|
||||
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";
|
||||
|
||||
|
||||
private static final int SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE = 1024;
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private String contentType = CONTENT_TYPE_SERIALIZED_OBJECT;
|
||||
|
||||
private boolean acceptGzipEncoding = true;
|
||||
|
||||
private ClassLoader beanClassLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the content type to use for sending HTTP invoker requests.
|
||||
* <p>Default is "application/x-java-serialized-object".
|
||||
*/
|
||||
public void setContentType(String contentType) {
|
||||
Assert.notNull(contentType, "'contentType' must not be null");
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content type to use for sending HTTP invoker requests.
|
||||
*/
|
||||
public String getContentType() {
|
||||
return this.contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to accept GZIP encoding, that is, whether to
|
||||
* send the HTTP "Accept-Encoding" header with "gzip" as value.
|
||||
* <p>Default is "true". Turn this flag off if you do not want
|
||||
* GZIP response compression even if enabled on the HTTP server.
|
||||
*/
|
||||
public void setAcceptGzipEncoding(boolean acceptGzipEncoding) {
|
||||
this.acceptGzipEncoding = acceptGzipEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to accept GZIP encoding, that is, whether to
|
||||
* send the HTTP "Accept-Encoding" header with "gzip" as value.
|
||||
*/
|
||||
public boolean isAcceptGzipEncoding() {
|
||||
return this.acceptGzipEncoding;
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean ClassLoader that this executor is supposed to use.
|
||||
*/
|
||||
protected ClassLoader getBeanClassLoader() {
|
||||
return this.beanClassLoader;
|
||||
}
|
||||
|
||||
|
||||
public final RemoteInvocationResult executeRequest(
|
||||
HttpInvokerClientConfiguration config, RemoteInvocation invocation) throws Exception {
|
||||
|
||||
ByteArrayOutputStream baos = getByteArrayOutputStream(invocation);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Sending HTTP invoker request for service at [" + config.getServiceUrl() +
|
||||
"], with size " + baos.size());
|
||||
}
|
||||
return doExecuteRequest(config, baos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the given RemoteInvocation into a ByteArrayOutputStream.
|
||||
* @param invocation the RemoteInvocation object
|
||||
* @return a ByteArrayOutputStream with the serialized RemoteInvocation
|
||||
* @throws IOException if thrown by I/O methods
|
||||
*/
|
||||
protected ByteArrayOutputStream getByteArrayOutputStream(RemoteInvocation invocation) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(SERIALIZED_INVOCATION_BYTE_ARRAY_INITIAL_SIZE);
|
||||
writeRemoteInvocation(invocation, baos);
|
||||
return baos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the given RemoteInvocation to the given OutputStream.
|
||||
* <p>The default implementation gives <code>decorateOutputStream</code> a chance
|
||||
* to decorate the stream first (for example, for custom encryption or compression).
|
||||
* Creates an <code>ObjectOutputStream</code> for the final stream and calls
|
||||
* <code>doWriteRemoteInvocation</code> to actually write the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param invocation the RemoteInvocation object
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see #decorateOutputStream
|
||||
* @see #doWriteRemoteInvocation
|
||||
*/
|
||||
protected void writeRemoteInvocation(RemoteInvocation invocation, OutputStream os) throws IOException {
|
||||
ObjectOutputStream oos = new ObjectOutputStream(decorateOutputStream(os));
|
||||
try {
|
||||
doWriteRemoteInvocation(invocation, oos);
|
||||
oos.flush();
|
||||
}
|
||||
finally {
|
||||
oos.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the OutputStream to use for writing remote invocations,
|
||||
* potentially decorating the given original OutputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param os the original OutputStream
|
||||
* @return the potentially decorated OutputStream
|
||||
*/
|
||||
protected OutputStream decorateOutputStream(OutputStream os) throws IOException {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual writing of the given invocation object to the
|
||||
* given ObjectOutputStream.
|
||||
* <p>The default implementation simply calls <code>writeObject</code>.
|
||||
* Can be overridden for serialization of a custom wrapper object rather
|
||||
* than the plain invocation, for example an encryption-aware holder.
|
||||
* @param invocation the RemoteInvocation object
|
||||
* @param oos the ObjectOutputStream to write to
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see java.io.ObjectOutputStream#writeObject
|
||||
*/
|
||||
protected void doWriteRemoteInvocation(RemoteInvocation invocation, ObjectOutputStream oos) throws IOException {
|
||||
oos.writeObject(invocation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a request to send the given serialized remote invocation.
|
||||
* <p>Implementations will usually call <code>readRemoteInvocationResult</code>
|
||||
* to deserialize a returned RemoteInvocationResult object.
|
||||
* @param config the HTTP invoker configuration that specifies the
|
||||
* target service
|
||||
* @param baos the ByteArrayOutputStream that contains the serialized
|
||||
* RemoteInvocation object
|
||||
* @return the RemoteInvocationResult object
|
||||
* @throws IOException if thrown by I/O operations
|
||||
* @throws ClassNotFoundException if thrown during deserialization
|
||||
* @throws Exception in case of general errors
|
||||
* @see #readRemoteInvocationResult(java.io.InputStream, String)
|
||||
*/
|
||||
protected abstract RemoteInvocationResult doExecuteRequest(
|
||||
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
|
||||
throws Exception;
|
||||
|
||||
/**
|
||||
* Deserialize a RemoteInvocationResult object from the given InputStream.
|
||||
* <p>Gives <code>decorateInputStream</code> a chance to decorate the stream
|
||||
* first (for example, for custom encryption or compression). Creates an
|
||||
* <code>ObjectInputStream</code> via <code>createObjectInputStream</code> and
|
||||
* calls <code>doReadRemoteInvocationResult</code> to actually read the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param is the InputStream to read from
|
||||
* @param codebaseUrl the codebase URL to load classes from if not found locally
|
||||
* @return the RemoteInvocationResult object
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @throws ClassNotFoundException if thrown during deserialization
|
||||
* @see #decorateInputStream
|
||||
* @see #createObjectInputStream
|
||||
* @see #doReadRemoteInvocationResult
|
||||
*/
|
||||
protected RemoteInvocationResult readRemoteInvocationResult(InputStream is, String codebaseUrl)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
ObjectInputStream ois = createObjectInputStream(decorateInputStream(is), codebaseUrl);
|
||||
try {
|
||||
return doReadRemoteInvocationResult(ois);
|
||||
}
|
||||
finally {
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InputStream to use for reading remote invocation results,
|
||||
* potentially decorating the given original InputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param is the original InputStream
|
||||
* @return the potentially decorated InputStream
|
||||
*/
|
||||
protected InputStream decorateInputStream(InputStream is) throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ObjectInputStream for the given InputStream and codebase.
|
||||
* The default implementation creates a CodebaseAwareObjectInputStream.
|
||||
* @param is the InputStream to read from
|
||||
* @param codebaseUrl the codebase URL to load classes from if not found locally
|
||||
* (can be <code>null</code>)
|
||||
* @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, String codebaseUrl) throws IOException {
|
||||
return new CodebaseAwareObjectInputStream(is, getBeanClassLoader(), codebaseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual reading of an invocation object from the
|
||||
* given ObjectInputStream.
|
||||
* <p>The default implementation simply calls <code>readObject</code>.
|
||||
* 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() + "]: " + obj);
|
||||
}
|
||||
return (RemoteInvocationResult) obj;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.zip.GZIPInputStream;
|
||||
|
||||
import org.apache.commons.httpclient.Header;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.HttpException;
|
||||
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
|
||||
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link HttpInvokerRequestExecutor} implementation that uses
|
||||
* <a href="http://jakarta.apache.org/commons/httpclient">Jakarta Commons HttpClient</a>
|
||||
* to execute POST requests. Requires Commons HttpClient 3.0 or higher.
|
||||
*
|
||||
* <p>Allows to use a pre-configured {@link org.apache.commons.httpclient.HttpClient}
|
||||
* instance, potentially with authentication, HTTP connection pooling, etc.
|
||||
* Also designed for easy subclassing, providing specific template methods.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @since 1.1
|
||||
* @see SimpleHttpInvokerRequestExecutor
|
||||
*/
|
||||
public class CommonsHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
|
||||
|
||||
/**
|
||||
* Default timeout value if no HttpClient is explicitly provided.
|
||||
*/
|
||||
private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);
|
||||
|
||||
private HttpClient httpClient;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new CommonsHttpInvokerRequestExecutor with a default
|
||||
* HttpClient that uses a default MultiThreadedHttpConnectionManager.
|
||||
* Sets the socket read timeout to {@link #DEFAULT_READ_TIMEOUT_MILLISECONDS}.
|
||||
* @see org.apache.commons.httpclient.HttpClient
|
||||
* @see org.apache.commons.httpclient.MultiThreadedHttpConnectionManager
|
||||
*/
|
||||
public CommonsHttpInvokerRequestExecutor() {
|
||||
this.httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
|
||||
this.setReadTimeout(DEFAULT_READ_TIMEOUT_MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new CommonsHttpInvokerRequestExecutor with the given
|
||||
* HttpClient instance. The socket read timeout of the provided
|
||||
* HttpClient will not be changed.
|
||||
* @param httpClient the HttpClient instance to use for this request executor
|
||||
*/
|
||||
public CommonsHttpInvokerRequestExecutor(HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the HttpClient instance to use for this request executor.
|
||||
*/
|
||||
public void setHttpClient(HttpClient httpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HttpClient instance that this request executor uses.
|
||||
*/
|
||||
public HttpClient getHttpClient() {
|
||||
return this.httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket read timeout for the underlying HttpClient. A value
|
||||
* of 0 means <emphasis>never</emphasis> timeout.
|
||||
* @param timeout the timeout value in milliseconds
|
||||
* @see org.apache.commons.httpclient.params.HttpConnectionManagerParams#setSoTimeout(int)
|
||||
* @see #DEFAULT_READ_TIMEOUT_MILLISECONDS
|
||||
*/
|
||||
public void setReadTimeout(int timeout) {
|
||||
if (timeout < 0) {
|
||||
throw new IllegalArgumentException("timeout must be a non-negative value");
|
||||
}
|
||||
this.httpClient.getHttpConnectionManager().getParams().setSoTimeout(timeout);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the given request through Commons HttpClient.
|
||||
* <p>This method implements the basic processing workflow:
|
||||
* The actual work happens in this class's template methods.
|
||||
* @see #createPostMethod
|
||||
* @see #setRequestBody
|
||||
* @see #executePostMethod
|
||||
* @see #validateResponse
|
||||
* @see #getResponseBody
|
||||
*/
|
||||
protected RemoteInvocationResult doExecuteRequest(
|
||||
HttpInvokerClientConfiguration config, ByteArrayOutputStream baos)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
PostMethod postMethod = createPostMethod(config);
|
||||
try {
|
||||
setRequestBody(config, postMethod, baos);
|
||||
executePostMethod(config, getHttpClient(), postMethod);
|
||||
validateResponse(config, postMethod);
|
||||
InputStream responseBody = getResponseBody(config, postMethod);
|
||||
return readRemoteInvocationResult(responseBody, config.getCodebaseUrl());
|
||||
}
|
||||
finally {
|
||||
// Need to explicitly release because it might be pooled.
|
||||
postMethod.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PostMethod for the given configuration.
|
||||
* <p>The default implementation creates a standard PostMethod with
|
||||
* "application/x-java-serialized-object" as "Content-Type" header.
|
||||
* @param config the HTTP invoker configuration that specifies the
|
||||
* target service
|
||||
* @return the PostMethod instance
|
||||
* @throws IOException if thrown by I/O methods
|
||||
*/
|
||||
protected PostMethod createPostMethod(HttpInvokerClientConfiguration config) throws IOException {
|
||||
PostMethod postMethod = new PostMethod(config.getServiceUrl());
|
||||
LocaleContext locale = LocaleContextHolder.getLocaleContext();
|
||||
if (locale != null) {
|
||||
postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale()));
|
||||
}
|
||||
if (isAcceptGzipEncoding()) {
|
||||
postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
|
||||
}
|
||||
return postMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given serialized remote invocation as request body.
|
||||
* <p>The default implementation simply sets the serialized invocation
|
||||
* as the PostMethod's request body. 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 postMethod the PostMethod to set the request body on
|
||||
* @param baos the ByteArrayOutputStream that contains the serialized
|
||||
* RemoteInvocation object
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see org.apache.commons.httpclient.methods.PostMethod#setRequestBody(java.io.InputStream)
|
||||
* @see org.apache.commons.httpclient.methods.PostMethod#setRequestEntity
|
||||
* @see org.apache.commons.httpclient.methods.InputStreamRequestEntity
|
||||
*/
|
||||
protected void setRequestBody(
|
||||
HttpInvokerClientConfiguration config, PostMethod postMethod, ByteArrayOutputStream baos)
|
||||
throws IOException {
|
||||
|
||||
postMethod.setRequestEntity(new ByteArrayRequestEntity(baos.toByteArray(), getContentType()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given PostMethod instance.
|
||||
* @param config the HTTP invoker configuration that specifies the target service
|
||||
* @param httpClient the HttpClient to execute on
|
||||
* @param postMethod the PostMethod to execute
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see org.apache.commons.httpclient.HttpClient#executeMethod(org.apache.commons.httpclient.HttpMethod)
|
||||
*/
|
||||
protected void executePostMethod(
|
||||
HttpInvokerClientConfiguration config, HttpClient httpClient, PostMethod postMethod)
|
||||
throws IOException {
|
||||
|
||||
httpClient.executeMethod(postMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given response as contained in the PostMethod object,
|
||||
* throwing an exception if it does not correspond to a successful HTTP response.
|
||||
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
|
||||
* parsing the response body and trying to deserialize from a corrupted stream.
|
||||
* @param config the HTTP invoker configuration that specifies the target service
|
||||
* @param postMethod the executed PostMethod to validate
|
||||
* @throws IOException if validation failed
|
||||
* @see org.apache.commons.httpclient.methods.PostMethod#getStatusCode()
|
||||
* @see org.apache.commons.httpclient.HttpException
|
||||
*/
|
||||
protected void validateResponse(HttpInvokerClientConfiguration config, PostMethod postMethod)
|
||||
throws IOException {
|
||||
|
||||
if (postMethod.getStatusCode() >= 300) {
|
||||
throw new HttpException(
|
||||
"Did not receive successful HTTP response: status code = " + postMethod.getStatusCode() +
|
||||
", status message = [" + postMethod.getStatusText() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the response body from the given executed remote invocation
|
||||
* request.
|
||||
* <p>The default implementation simply fetches the PostMethod'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 postMethod the PostMethod 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 org.apache.commons.httpclient.methods.PostMethod#getResponseBodyAsStream()
|
||||
* @see org.apache.commons.httpclient.methods.PostMethod#getResponseHeader(String)
|
||||
*/
|
||||
protected InputStream getResponseBody(HttpInvokerClientConfiguration config, PostMethod postMethod)
|
||||
throws IOException {
|
||||
|
||||
if (isGzipResponse(postMethod)) {
|
||||
return new GZIPInputStream(postMethod.getResponseBodyAsStream());
|
||||
}
|
||||
else {
|
||||
return postMethod.getResponseBodyAsStream();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given response indicates a GZIP response.
|
||||
* <p>Default implementation checks whether the HTTP "Content-Encoding"
|
||||
* header contains "gzip" (in any casing).
|
||||
* @param postMethod the PostMethod to check
|
||||
* @return whether the given response indicates a GZIP response
|
||||
*/
|
||||
protected boolean isGzipResponse(PostMethod postMethod) {
|
||||
Header encodingHeader = postMethod.getResponseHeader(HTTP_HEADER_CONTENT_ENCODING);
|
||||
return (encodingHeader != null && encodingHeader.getValue() != null &&
|
||||
encodingHeader.getValue().toLowerCase().indexOf(ENCODING_GZIP) != -1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* Configuration interface for executing HTTP invoker requests.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see HttpInvokerRequestExecutor
|
||||
* @see HttpInvokerClientInterceptor
|
||||
*/
|
||||
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</code> if none
|
||||
* @see java.rmi.server.RMIClassLoader
|
||||
*/
|
||||
String getCodebaseUrl();
|
||||
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.remoting.RemoteAccessException;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteInvocationFailureException;
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationBasedAccessor;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
|
||||
/**
|
||||
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing an
|
||||
* HTTP invoker service. The service URL must be an HTTP URL exposing
|
||||
* an HTTP invoker service.
|
||||
*
|
||||
* <p>Serializes remote invocation objects and deserializes remote invocation
|
||||
* result objects. Uses Java serialization just like RMI, but provides the
|
||||
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
|
||||
*
|
||||
* <P>HTTP invoker is a very extensible and customizable protocol.
|
||||
* It supports the RemoteInvocationFactory mechanism, like RMI invoker,
|
||||
* allowing to include additional invocation attributes (for example,
|
||||
* a security context). Furthermore, it allows to customize request
|
||||
* execution via the {@link HttpInvokerRequestExecutor} strategy.
|
||||
*
|
||||
* <p>Can use the JDK's {@link java.rmi.server.RMIClassLoader} to load
|
||||
* classes from a given {@link #setCodebaseUrl codebase}, performing
|
||||
* on-demand dynamic code download from a remote location. The codebase
|
||||
* can consist of multiple URLs, separated by spaces. Note that
|
||||
* RMIClassLoader requires a SecurityManager to be set, analogous to
|
||||
* when using dynamic class download with standard RMI!
|
||||
* (See the RMI documentation for details.)
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see #setServiceUrl
|
||||
* @see #setCodebaseUrl
|
||||
* @see #setRemoteInvocationFactory
|
||||
* @see #setHttpInvokerRequestExecutor
|
||||
* @see HttpInvokerServiceExporter
|
||||
* @see HttpInvokerProxyFactoryBean
|
||||
* @see java.rmi.server.RMIClassLoader
|
||||
*/
|
||||
public class HttpInvokerClientInterceptor extends RemoteInvocationBasedAccessor
|
||||
implements MethodInterceptor, HttpInvokerClientConfiguration {
|
||||
|
||||
private String codebaseUrl;
|
||||
|
||||
private HttpInvokerRequestExecutor httpInvokerRequestExecutor;
|
||||
|
||||
|
||||
/**
|
||||
* Set the codebase URL to download classes from if not found locally.
|
||||
* Can consists of multiple URLs, separated by spaces.
|
||||
* <p>Follows RMI's codebase conventions for dynamic class download.
|
||||
* In contrast to RMI, where the server determines the URL for class download
|
||||
* (via the "java.rmi.server.codebase" system property), it's the client
|
||||
* that determines the codebase URL here. The server will usually be the
|
||||
* same as for the service URL, just pointing to a different path there.
|
||||
* @see #setServiceUrl
|
||||
* @see org.springframework.remoting.rmi.CodebaseAwareObjectInputStream
|
||||
* @see java.rmi.server.RMIClassLoader
|
||||
*/
|
||||
public void setCodebaseUrl(String codebaseUrl) {
|
||||
this.codebaseUrl = codebaseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the codebase URL to download classes from if not found locally.
|
||||
*/
|
||||
public String getCodebaseUrl() {
|
||||
return this.codebaseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HttpInvokerRequestExecutor implementation to use for executing
|
||||
* remote invocations.
|
||||
* <p>Default is {@link SimpleHttpInvokerRequestExecutor}. Alternatively,
|
||||
* consider using {@link CommonsHttpInvokerRequestExecutor} for more
|
||||
* sophisticated needs.
|
||||
* @see SimpleHttpInvokerRequestExecutor
|
||||
* @see CommonsHttpInvokerRequestExecutor
|
||||
*/
|
||||
public void setHttpInvokerRequestExecutor(HttpInvokerRequestExecutor httpInvokerRequestExecutor) {
|
||||
this.httpInvokerRequestExecutor = httpInvokerRequestExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HttpInvokerRequestExecutor used by this remote accessor.
|
||||
* <p>Creates a default SimpleHttpInvokerRequestExecutor if no executor
|
||||
* has been initialized already.
|
||||
*/
|
||||
public HttpInvokerRequestExecutor getHttpInvokerRequestExecutor() {
|
||||
if (this.httpInvokerRequestExecutor == null) {
|
||||
SimpleHttpInvokerRequestExecutor executor = new SimpleHttpInvokerRequestExecutor();
|
||||
executor.setBeanClassLoader(getBeanClassLoader());
|
||||
this.httpInvokerRequestExecutor = executor;
|
||||
}
|
||||
return this.httpInvokerRequestExecutor;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
// Eagerly initialize the default HttpInvokerRequestExecutor, if needed.
|
||||
getHttpInvokerRequestExecutor();
|
||||
}
|
||||
|
||||
|
||||
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 = null;
|
||||
try {
|
||||
result = executeRequest(invocation, methodInvocation);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw convertHttpInvokerAccessException(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 HttpInvokerRequestExecutor.
|
||||
* <p>This implementation delegates to {@link #executeRequest(RemoteInvocation)}.
|
||||
* Can be overridden to react to the specific original MethodInvocation.
|
||||
* @param invocation the RemoteInvocation to execute
|
||||
* @param originalInvocation the original MethodInvocation (can e.g. be cast
|
||||
* to the ProxyMethodInvocation interface for accessing user attributes)
|
||||
* @return the RemoteInvocationResult object
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
protected RemoteInvocationResult executeRequest(
|
||||
RemoteInvocation invocation, MethodInvocation originalInvocation) throws Exception {
|
||||
|
||||
return executeRequest(invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given remote invocation via the HttpInvokerRequestExecutor.
|
||||
* <p>Can be overridden in subclasses to pass a different configuration object
|
||||
* to the executor. Alternatively, add further configuration properties in a
|
||||
* subclass of this accessor: By default, the accessor passed itself as
|
||||
* configuration object to the executor.
|
||||
* @param invocation the RemoteInvocation to execute
|
||||
* @return the RemoteInvocationResult object
|
||||
* @throws IOException if thrown by I/O operations
|
||||
* @throws ClassNotFoundException if thrown during deserialization
|
||||
* @throws Exception in case of general errors
|
||||
* @see #getHttpInvokerRequestExecutor
|
||||
* @see HttpInvokerClientConfiguration
|
||||
*/
|
||||
protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws Exception {
|
||||
return getHttpInvokerRequestExecutor().executeRequest(this, invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given HTTP invoker access exception to an appropriate
|
||||
* Spring RemoteAccessException.
|
||||
* @param ex the exception to convert
|
||||
* @return the RemoteAccessException to throw
|
||||
*/
|
||||
protected RemoteAccessException convertHttpInvokerAccessException(Throwable ex) {
|
||||
if (ex instanceof ConnectException) {
|
||||
throw new RemoteConnectFailureException(
|
||||
"Could not connect to HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
else if (ex instanceof ClassNotFoundException || ex instanceof NoClassDefFoundError ||
|
||||
ex instanceof InvalidClassException) {
|
||||
throw new RemoteAccessException(
|
||||
"Could not deserialize result from HTTP invoker remote service [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
else {
|
||||
throw new RemoteAccessException(
|
||||
"Could not access HTTP invoker remote service at [" + getServiceUrl() + "]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* FactoryBean for HTTP invoker proxies. Exposes the proxied service for
|
||||
* use as a bean reference, using the specified service interface.
|
||||
*
|
||||
* <p>The service URL must be an HTTP URL exposing an HTTP invoker service.
|
||||
* Optionally, a codebase URL can be specified for on-demand dynamic code download
|
||||
* from a remote location. For details, see HttpInvokerClientInterceptor docs.
|
||||
*
|
||||
* <p>Serializes remote invocation objects and deserializes remote invocation
|
||||
* result objects. Uses Java serialization just like RMI, but provides the
|
||||
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
|
||||
*
|
||||
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
|
||||
* It is more powerful and more extensible than Hessian and Burlap, at the
|
||||
* expense of being tied to Java. Nevertheless, it is as easy to set up as
|
||||
* Hessian and Burlap, which is its main advantage compared to RMI.
|
||||
*
|
||||
* @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
|
||||
* @see org.springframework.remoting.caucho.BurlapProxyFactoryBean
|
||||
*/
|
||||
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor
|
||||
implements FactoryBean {
|
||||
|
||||
private Object serviceProxy;
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
if (getServiceInterface() == null) {
|
||||
throw new IllegalArgumentException("Property 'serviceInterface' is required");
|
||||
}
|
||||
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(getBeanClassLoader());
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.serviceProxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return getServiceInterface();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.remoting.httpinvoker;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
|
||||
/**
|
||||
* Strategy interface for actual execution of an HTTP invoker request.
|
||||
* Used by HttpInvokerClientInterceptor and its subclass
|
||||
* HttpInvokerProxyFactoryBean.
|
||||
*
|
||||
* <p>Two implementations are provided out of the box:
|
||||
* <ul>
|
||||
* <li><b>SimpleHttpInvokerRequestExecutor:</b>
|
||||
* Uses J2SE facilities to execute POST requests, without support
|
||||
* for HTTP authentication or advanced configuration options.
|
||||
* <li><b>CommonsHttpInvokerRequestExecutor:</b>
|
||||
* Uses Jakarta's Commons HttpClient to execute POST requests,
|
||||
* allowing to use a preconfigured HttpClient instance
|
||||
* (potentially with authentication, HTTP connection pooling, etc).
|
||||
* </ul>
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see HttpInvokerClientInterceptor#setHttpInvokerRequestExecutor
|
||||
*/
|
||||
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;
|
||||
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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 javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter;
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.util.NestedServletException;
|
||||
|
||||
/**
|
||||
* Servlet-API-based HTTP request handler that exports the specified service bean
|
||||
* as HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
|
||||
*
|
||||
* <p><b>Note:</b> Spring also provides an alternative version of this exporter,
|
||||
* for Sun's JRE 1.6 HTTP server: {@link SimpleHttpInvokerServiceExporter}.
|
||||
*
|
||||
* <p>Deserializes remote invocation objects and serializes remote invocation
|
||||
* result objects. Uses Java serialization just like RMI, but provides the
|
||||
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
|
||||
*
|
||||
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
|
||||
* It is more powerful and more extensible than Hessian and Burlap, at the
|
||||
* expense of being tied to Java. Nevertheless, it is as easy to set up as
|
||||
* Hessian and Burlap, which is its main advantage compared to RMI.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see HttpInvokerClientInterceptor
|
||||
* @see HttpInvokerProxyFactoryBean
|
||||
* @see org.springframework.remoting.rmi.RmiServiceExporter
|
||||
* @see org.springframework.remoting.caucho.HessianServiceExporter
|
||||
* @see org.springframework.remoting.caucho.BurlapServiceExporter
|
||||
*/
|
||||
public class HttpInvokerServiceExporter extends 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)
|
||||
*/
|
||||
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
RemoteInvocation invocation = readRemoteInvocation(request);
|
||||
RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy());
|
||||
writeRemoteInvocationResult(request, response, result);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new NestedServletException("Class not found during deserialization", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a RemoteInvocation from the given HTTP request.
|
||||
* <p>Delegates to
|
||||
* {@link #readRemoteInvocation(javax.servlet.http.HttpServletRequest, java.io.InputStream)}
|
||||
* with the
|
||||
* {@link javax.servlet.ServletRequest#getInputStream() servlet request's input stream}.
|
||||
* @param request current HTTP request
|
||||
* @return the RemoteInvocation object
|
||||
* @throws IOException in case of I/O failure
|
||||
* @throws ClassNotFoundException if thrown by deserialization
|
||||
*/
|
||||
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
return readRemoteInvocation(request, request.getInputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a RemoteInvocation object from the given InputStream.
|
||||
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
|
||||
* first (for example, for custom encryption or compression). Creates a
|
||||
* {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
|
||||
* and calls {@link #doReadRemoteInvocation} to actually read the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param request current HTTP request
|
||||
* @param is the InputStream to read from
|
||||
* @return the RemoteInvocation object
|
||||
* @throws IOException in case of I/O failure
|
||||
* @throws ClassNotFoundException if thrown during deserialization
|
||||
*/
|
||||
protected RemoteInvocation readRemoteInvocation(HttpServletRequest request, InputStream is)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
ObjectInputStream ois = createObjectInputStream(decorateInputStream(request, is));
|
||||
try {
|
||||
return doReadRemoteInvocation(ois);
|
||||
}
|
||||
finally {
|
||||
ois.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InputStream to use for reading remote invocations,
|
||||
* potentially decorating the given original InputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param request current HTTP request
|
||||
* @param is the original InputStream
|
||||
* @return the potentially decorated InputStream
|
||||
* @throws IOException in case of I/O failure
|
||||
*/
|
||||
protected InputStream decorateInputStream(HttpServletRequest request, InputStream is) throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given RemoteInvocationResult to the given HTTP response.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param result the RemoteInvocationResult object
|
||||
* @throws IOException in case of I/O failure
|
||||
*/
|
||||
protected void writeRemoteInvocationResult(
|
||||
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result)
|
||||
throws IOException {
|
||||
|
||||
response.setContentType(getContentType());
|
||||
writeRemoteInvocationResult(request, response, result, response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the given RemoteInvocation to the given OutputStream.
|
||||
* <p>The default implementation gives {@link #decorateOutputStream} a chance
|
||||
* to decorate the stream first (for example, for custom encryption or compression).
|
||||
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
|
||||
* {@link #doWriteRemoteInvocationResult} to actually write the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param result the RemoteInvocationResult object
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException in case of I/O failure
|
||||
* @see #decorateOutputStream
|
||||
* @see #doWriteRemoteInvocationResult
|
||||
*/
|
||||
protected void writeRemoteInvocationResult(
|
||||
HttpServletRequest request, HttpServletResponse response, RemoteInvocationResult result, OutputStream os)
|
||||
throws IOException {
|
||||
|
||||
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(request, response, os));
|
||||
try {
|
||||
doWriteRemoteInvocationResult(result, oos);
|
||||
oos.flush();
|
||||
}
|
||||
finally {
|
||||
oos.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the OutputStream to use for writing remote invocation results,
|
||||
* potentially decorating the given original OutputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @param os the original OutputStream
|
||||
* @return the potentially decorated OutputStream
|
||||
* @throws IOException in case of I/O failure
|
||||
*/
|
||||
protected OutputStream decorateOutputStream(
|
||||
HttpServletRequest request, HttpServletResponse response, OutputStream os) throws IOException {
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.zip.GZIPInputStream;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContext;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* HttpInvokerRequestExecutor implementation that uses standard J2SE facilities
|
||||
* to execute POST requests, without support for HTTP authentication or
|
||||
* advanced configuration options.
|
||||
*
|
||||
* <p>Designed for easy subclassing, customizing specific template methods.
|
||||
* However, consider CommonsHttpInvokerRequestExecutor for more sophisticated
|
||||
* needs: The J2SE HttpURLConnection is rather limited in its capabilities.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
* @see CommonsHttpInvokerRequestExecutor
|
||||
* @see java.net.HttpURLConnection
|
||||
*/
|
||||
public class SimpleHttpInvokerRequestExecutor extends AbstractHttpInvokerRequestExecutor {
|
||||
|
||||
/**
|
||||
* Execute the given request through a standard J2SE HttpURLConnection.
|
||||
* <p>This method implements the basic processing workflow:
|
||||
* The actual work happens in this class's template methods.
|
||||
* @see #openConnection
|
||||
* @see #prepareConnection
|
||||
* @see #writeRequestBody
|
||||
* @see #validateResponse
|
||||
* @see #readResponseBody
|
||||
*/
|
||||
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 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() + "] is not an HTTP URL");
|
||||
}
|
||||
return (HttpURLConnection) con;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given HTTP connection.
|
||||
* <p>The default implementation specifies POST as method,
|
||||
* "application/x-java-serialized-object" as "Content-Type" header,
|
||||
* and the given content length as "Content-Length" header.
|
||||
* @param con 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 con, int contentLength) throws IOException {
|
||||
con.setDoOutput(true);
|
||||
con.setRequestMethod(HTTP_METHOD_POST);
|
||||
con.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, getContentType());
|
||||
con.setRequestProperty(HTTP_HEADER_CONTENT_LENGTH, Integer.toString(contentLength));
|
||||
LocaleContext locale = LocaleContextHolder.getLocaleContext();
|
||||
if (locale != null) {
|
||||
con.setRequestProperty(HTTP_HEADER_ACCEPT_LANGUAGE, StringUtils.toLanguageTag(locale.getLocale()));
|
||||
}
|
||||
if (isAcceptGzipEncoding()) {
|
||||
con.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given serialized remote invocation as request body.
|
||||
* <p>The default implementation simply write the serialized invocation to the
|
||||
* HttpURLConnection's OutputStream. This can be overridden, for example, to write
|
||||
* a specific encoding and potentially set appropriate HTTP request headers.
|
||||
* @param config the HTTP invoker configuration that specifies the target service
|
||||
* @param con the HttpURLConnection to write the request body to
|
||||
* @param baos the ByteArrayOutputStream that contains the serialized
|
||||
* RemoteInvocation object
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see java.net.HttpURLConnection#getOutputStream()
|
||||
* @see java.net.HttpURLConnection#setRequestProperty
|
||||
*/
|
||||
protected void writeRequestBody(
|
||||
HttpInvokerClientConfiguration config, HttpURLConnection con, ByteArrayOutputStream baos)
|
||||
throws IOException {
|
||||
|
||||
baos.writeTo(con.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given response as contained in the HttpURLConnection object,
|
||||
* throwing an exception if it does not correspond to a successful HTTP response.
|
||||
* <p>Default implementation rejects any HTTP status code beyond 2xx, to avoid
|
||||
* parsing the response body and trying to deserialize from a corrupted stream.
|
||||
* @param config the HTTP invoker configuration that specifies the target service
|
||||
* @param con the HttpURLConnection to validate
|
||||
* @throws IOException if validation failed
|
||||
* @see java.net.HttpURLConnection#getResponseCode()
|
||||
*/
|
||||
protected void validateResponse(HttpInvokerClientConfiguration config, HttpURLConnection con)
|
||||
throws IOException {
|
||||
|
||||
if (con.getResponseCode() >= 300) {
|
||||
throw new IOException(
|
||||
"Did not receive successful HTTP response: status code = " + con.getResponseCode() +
|
||||
", status message = [" + con.getResponseMessage() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the response body from the given executed remote invocation
|
||||
* request.
|
||||
* <p>The default implementation simply reads the serialized invocation
|
||||
* from the HttpURLConnection's InputStream. If the response is recognized
|
||||
* as GZIP response, the InputStream will get wrapped in a GZIPInputStream.
|
||||
* @param config the HTTP invoker configuration that specifies the target service
|
||||
* @param con the HttpURLConnection to read the response body from
|
||||
* @return an InputStream for the response body
|
||||
* @throws IOException if thrown by I/O methods
|
||||
* @see #isGzipResponse
|
||||
* @see java.util.zip.GZIPInputStream
|
||||
* @see java.net.HttpURLConnection#getInputStream()
|
||||
* @see java.net.HttpURLConnection#getHeaderField(int)
|
||||
* @see java.net.HttpURLConnection#getHeaderFieldKey(int)
|
||||
*/
|
||||
protected InputStream readResponseBody(HttpInvokerClientConfiguration config, HttpURLConnection con)
|
||||
throws IOException {
|
||||
|
||||
if (isGzipResponse(con)) {
|
||||
// GZIP response found - need to unzip.
|
||||
return new GZIPInputStream(con.getInputStream());
|
||||
}
|
||||
else {
|
||||
// Plain response found.
|
||||
return con.getInputStream();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given response is a GZIP response.
|
||||
* <p>Default implementation checks whether the HTTP "Content-Encoding"
|
||||
* header contains "gzip" (in any casing).
|
||||
* @param con the HttpURLConnection to check
|
||||
*/
|
||||
protected boolean isGzipResponse(HttpURLConnection con) {
|
||||
String encodingHeader = con.getHeaderField(HTTP_HEADER_CONTENT_ENCODING);
|
||||
return (encodingHeader != null && encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.rmi.RemoteInvocationSerializingExporter;
|
||||
import org.springframework.remoting.support.RemoteInvocation;
|
||||
import org.springframework.remoting.support.RemoteInvocationResult;
|
||||
|
||||
/**
|
||||
* HTTP request handler that exports the specified service bean as
|
||||
* HTTP invoker service endpoint, accessible via an HTTP invoker proxy.
|
||||
* Designed for Sun's JRE 1.6 HTTP server, implementing the
|
||||
* {@link com.sun.net.httpserver.HttpHandler} interface.
|
||||
*
|
||||
* <p>Deserializes remote invocation objects and serializes remote invocation
|
||||
* result objects. Uses Java serialization just like RMI, but provides the
|
||||
* same ease of setup as Caucho's HTTP-based Hessian and Burlap protocols.
|
||||
*
|
||||
* <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
|
||||
* It is more powerful and more extensible than Hessian and Burlap, at the
|
||||
* expense of being tied to Java. Nevertheless, it is as easy to set up as
|
||||
* Hessian and Burlap, which is its main advantage compared to RMI.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
|
||||
* @see org.springframework.remoting.caucho.SimpleHessianServiceExporter
|
||||
* @see org.springframework.remoting.caucho.SimpleBurlapServiceExporter
|
||||
*/
|
||||
public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter
|
||||
implements HttpHandler {
|
||||
|
||||
/**
|
||||
* Reads a remote invocation from the request, executes it,
|
||||
* and writes the remote invocation result to the response.
|
||||
* @see #readRemoteInvocation(com.sun.net.httpserver.HttpExchange)
|
||||
* @see #invokeAndCreateResult(org.springframework.remoting.support.RemoteInvocation, Object)
|
||||
* @see #writeRemoteInvocationResult(com.sun.net.httpserver.HttpExchange, org.springframework.remoting.support.RemoteInvocationResult)
|
||||
*/
|
||||
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) {
|
||||
throw new IOException("Class not found during deserialization", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a RemoteInvocation from the given HTTP request.
|
||||
* <p>Delegates to
|
||||
* {@link #readRemoteInvocation(com.sun.net.httpserver.HttpExchange, java.io.InputStream)}
|
||||
* with the
|
||||
* {@link com.sun.net.httpserver.HttpExchange#getRequestBody()} request's input stream}.
|
||||
* @param exchange current HTTP request/response
|
||||
* @return the RemoteInvocation object
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
* @throws ClassNotFoundException if thrown by deserialization
|
||||
*/
|
||||
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
return readRemoteInvocation(exchange, exchange.getRequestBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a RemoteInvocation object from the given InputStream.
|
||||
* <p>Gives {@link #decorateInputStream} a chance to decorate the stream
|
||||
* first (for example, for custom encryption or compression). Creates a
|
||||
* {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream}
|
||||
* and calls {@link #doReadRemoteInvocation} to actually read the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param exchange current HTTP request/response
|
||||
* @param is the InputStream to read from
|
||||
* @return the RemoteInvocation object
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
* @throws ClassNotFoundException if thrown during deserialization
|
||||
*/
|
||||
protected RemoteInvocation readRemoteInvocation(HttpExchange exchange, InputStream is)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
ObjectInputStream ois = createObjectInputStream(decorateInputStream(exchange, is));
|
||||
return doReadRemoteInvocation(ois);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the InputStream to use for reading remote invocations,
|
||||
* potentially decorating the given original InputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param exchange current HTTP request/response
|
||||
* @param is the original InputStream
|
||||
* @return the potentially decorated InputStream
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
*/
|
||||
protected InputStream decorateInputStream(HttpExchange exchange, InputStream is) throws IOException {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given RemoteInvocationResult to the given HTTP response.
|
||||
* @param exchange current HTTP request/response
|
||||
* @param result the RemoteInvocationResult object
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
*/
|
||||
protected void writeRemoteInvocationResult(HttpExchange exchange, RemoteInvocationResult result)
|
||||
throws IOException {
|
||||
|
||||
exchange.getResponseHeaders().set("Content-Type", getContentType());
|
||||
exchange.sendResponseHeaders(200, 0);
|
||||
writeRemoteInvocationResult(exchange, result, exchange.getResponseBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the given RemoteInvocation to the given OutputStream.
|
||||
* <p>The default implementation gives {@link #decorateOutputStream} a chance
|
||||
* to decorate the stream first (for example, for custom encryption or compression).
|
||||
* Creates an {@link java.io.ObjectOutputStream} for the final stream and calls
|
||||
* {@link #doWriteRemoteInvocationResult} to actually write the object.
|
||||
* <p>Can be overridden for custom serialization of the invocation.
|
||||
* @param exchange current HTTP request/response
|
||||
* @param result the RemoteInvocationResult object
|
||||
* @param os the OutputStream to write to
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
* @see #decorateOutputStream
|
||||
* @see #doWriteRemoteInvocationResult
|
||||
*/
|
||||
protected void writeRemoteInvocationResult(
|
||||
HttpExchange exchange, RemoteInvocationResult result, OutputStream os) throws IOException {
|
||||
|
||||
ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(exchange, os));
|
||||
doWriteRemoteInvocationResult(result, oos);
|
||||
oos.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the OutputStream to use for writing remote invocation results,
|
||||
* potentially decorating the given original OutputStream.
|
||||
* <p>The default implementation returns the given stream as-is.
|
||||
* Can be overridden, for example, for custom encryption or compression.
|
||||
* @param exchange current HTTP request/response
|
||||
* @param os the original OutputStream
|
||||
* @return the potentially decorated OutputStream
|
||||
* @throws java.io.IOException in case of I/O failure
|
||||
*/
|
||||
protected OutputStream decorateOutputStream(HttpExchange exchange, OutputStream os) throws IOException {
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
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 and Burlap protocols.
|
||||
|
||||
<p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b>
|
||||
It is more powerful and more extensible than Hessian and Burlap, at the
|
||||
expense of being tied to Java. Neverthelesss, it is as easy to set up as
|
||||
Hessian and Burlap, which is its main advantage compared to RMI.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,757 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.rpc.Call;
|
||||
import javax.xml.rpc.JAXRPCException;
|
||||
import javax.xml.rpc.Service;
|
||||
import javax.xml.rpc.ServiceException;
|
||||
import javax.xml.rpc.Stub;
|
||||
import javax.xml.rpc.soap.SOAPFaultException;
|
||||
|
||||
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.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.RemoteProxyFailureException;
|
||||
import org.springframework.remoting.rmi.RmiClientInterceptorUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a specific port
|
||||
* of a JAX-RPC service. Uses either {@link LocalJaxRpcServiceFactory}'s facilities
|
||||
* underneath or takes an explicit reference to an existing JAX-RPC Service instance
|
||||
* (e.g. obtained via a {@link org.springframework.jndi.JndiObjectFactoryBean}).
|
||||
*
|
||||
* <p>Allows to set JAX-RPC's standard stub properties directly, via the
|
||||
* "username", "password", "endpointAddress" and "maintainSession" properties.
|
||||
* For typical usage, it is not necessary to specify those.
|
||||
*
|
||||
* <p>In standard JAX-RPC style, this invoker is used with an RMI service interface.
|
||||
* Alternatively, this invoker can also proxy a JAX-RPC service with a matching
|
||||
* non-RMI business interface, that is, an interface that declares the service methods
|
||||
* without RemoteExceptions. In the latter case, RemoteExceptions thrown by JAX-RPC
|
||||
* will automatically get converted to Spring's unchecked RemoteAccessException.
|
||||
*
|
||||
* <p>Setting "serviceInterface" is usually sufficient: The invoker will automatically
|
||||
* use JAX-RPC "dynamic invocations" via the Call API in this case, no matter whether
|
||||
* the specified interface is an RMI or non-RMI interface. Alternatively, a corresponding
|
||||
* JAX-RPC port interface can be specified as "portInterface", which will turn this
|
||||
* invoker into "static invocation" mode (operating on a standard JAX-RPC port stub).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.12.2003
|
||||
* @see #setPortName
|
||||
* @see #setServiceInterface
|
||||
* @see #setPortInterface
|
||||
* @see javax.xml.rpc.Service#createCall
|
||||
* @see javax.xml.rpc.Service#getPort
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see org.springframework.jndi.JndiObjectFactoryBean
|
||||
*/
|
||||
public class JaxRpcPortClientInterceptor extends LocalJaxRpcServiceFactory
|
||||
implements MethodInterceptor, InitializingBean {
|
||||
|
||||
private Service jaxRpcService;
|
||||
|
||||
private Service serviceToUse;
|
||||
|
||||
private String portName;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String endpointAddress;
|
||||
|
||||
private boolean maintainSession;
|
||||
|
||||
/** Map of custom properties, keyed by property name (String) */
|
||||
private final Map customPropertyMap = new HashMap();
|
||||
|
||||
private Class serviceInterface;
|
||||
|
||||
private Class portInterface;
|
||||
|
||||
private boolean lookupServiceOnStartup = true;
|
||||
|
||||
private boolean refreshServiceAfterConnectFailure = false;
|
||||
|
||||
private QName portQName;
|
||||
|
||||
private Remote portStub;
|
||||
|
||||
private final Object preparationMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set a reference to an existing JAX-RPC Service instance,
|
||||
* for example obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}.
|
||||
* If not set, {@link LocalJaxRpcServiceFactory}'s properties have to be specified.
|
||||
* @see #setServiceFactoryClass
|
||||
* @see #setWsdlDocumentUrl
|
||||
* @see #setNamespaceUri
|
||||
* @see #setServiceName
|
||||
* @see org.springframework.jndi.JndiObjectFactoryBean
|
||||
*/
|
||||
public void setJaxRpcService(Service jaxRpcService) {
|
||||
this.jaxRpcService = jaxRpcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to an existing JAX-RPC Service instance, if any.
|
||||
*/
|
||||
public Service getJaxRpcService() {
|
||||
return this.jaxRpcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the port.
|
||||
* Corresponds to the "wsdl:port" name.
|
||||
*/
|
||||
public void setPortName(String portName) {
|
||||
this.portName = portName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the port.
|
||||
*/
|
||||
public String getPortName() {
|
||||
return this.portName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to specify on the stub or call.
|
||||
* @see javax.xml.rpc.Stub#USERNAME_PROPERTY
|
||||
* @see javax.xml.rpc.Call#USERNAME_PROPERTY
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the username to specify on the stub or call.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password to specify on the stub or call.
|
||||
* @see javax.xml.rpc.Stub#PASSWORD_PROPERTY
|
||||
* @see javax.xml.rpc.Call#PASSWORD_PROPERTY
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password to specify on the stub or call.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the endpoint address to specify on the stub or call.
|
||||
* @see javax.xml.rpc.Stub#ENDPOINT_ADDRESS_PROPERTY
|
||||
* @see javax.xml.rpc.Call#setTargetEndpointAddress
|
||||
*/
|
||||
public void setEndpointAddress(String endpointAddress) {
|
||||
this.endpointAddress = endpointAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the endpoint address to specify on the stub or call.
|
||||
*/
|
||||
public String getEndpointAddress() {
|
||||
return this.endpointAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maintain session flag to specify on the stub or call.
|
||||
* @see javax.xml.rpc.Stub#SESSION_MAINTAIN_PROPERTY
|
||||
* @see javax.xml.rpc.Call#SESSION_MAINTAIN_PROPERTY
|
||||
*/
|
||||
public void setMaintainSession(boolean maintainSession) {
|
||||
this.maintainSession = maintainSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maintain session flag to specify on the stub or call.
|
||||
*/
|
||||
public boolean isMaintainSession() {
|
||||
return this.maintainSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom properties to be set on the stub or call.
|
||||
* <p>Can be populated with a String "value" (parsed via PropertiesEditor)
|
||||
* or a "props" element in XML bean definitions.
|
||||
* @see javax.xml.rpc.Stub#_setProperty
|
||||
* @see javax.xml.rpc.Call#setProperty
|
||||
*/
|
||||
public void setCustomProperties(Properties customProperties) {
|
||||
CollectionUtils.mergePropertiesIntoMap(customProperties, this.customPropertyMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom properties to be set on the stub or call.
|
||||
* <p>Can be populated with a "map" or "props" element in XML bean definitions.
|
||||
* @see javax.xml.rpc.Stub#_setProperty
|
||||
* @see javax.xml.rpc.Call#setProperty
|
||||
*/
|
||||
public void setCustomPropertyMap(Map customProperties) {
|
||||
if (customProperties != null) {
|
||||
Iterator it = customProperties.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
if (!(entry.getKey() instanceof String)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal property key [" + entry.getKey() + "]: only Strings allowed");
|
||||
}
|
||||
addCustomProperty((String) entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow Map access to the custom properties to be set on the stub
|
||||
* or call, with the option to add or override specific entries.
|
||||
* <p>Useful for specifying entries directly, for example via
|
||||
* "customPropertyMap[myKey]". This is particularly useful for
|
||||
* adding or overriding entries in child bean definitions.
|
||||
*/
|
||||
public Map getCustomPropertyMap() {
|
||||
return this.customPropertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom property to this JAX-RPC Stub/Call.
|
||||
* @param name the name of the attribute to expose
|
||||
* @param value the attribute value to expose
|
||||
* @see javax.xml.rpc.Stub#_setProperty
|
||||
* @see javax.xml.rpc.Call#setProperty
|
||||
*/
|
||||
public void addCustomProperty(String name, Object value) {
|
||||
this.customPropertyMap.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interface of the service that this factory should create a proxy for.
|
||||
* This will typically be a non-RMI business interface, although you can also
|
||||
* use an RMI port interface as recommended by JAX-RPC here.
|
||||
* <p>Calls on the specified service interface will either be translated to the
|
||||
* underlying RMI port interface (in case of a "portInterface" being specified)
|
||||
* or to dynamic calls (using the JAX-RPC Dynamic Invocation Interface).
|
||||
* <p>The dynamic call mechanism has the advantage that you don't need to
|
||||
* maintain an RMI port interface in addition to an existing non-RMI business
|
||||
* interface. In terms of configuration, specifying the business interface
|
||||
* as "serviceInterface" will be enough; this interceptor will automatically
|
||||
* use dynamic calls in such a scenario.
|
||||
* @see javax.xml.rpc.Service#createCall
|
||||
* @see #setPortInterface
|
||||
*/
|
||||
public void setServiceInterface(Class serviceInterface) {
|
||||
if (serviceInterface != null && !serviceInterface.isInterface()) {
|
||||
throw new IllegalArgumentException("'serviceInterface' must be an interface");
|
||||
}
|
||||
this.serviceInterface = serviceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the interface of the service that this factory should create a proxy for.
|
||||
*/
|
||||
public Class getServiceInterface() {
|
||||
return this.serviceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JAX-RPC port interface to use. Only needs to be set if a JAX-RPC
|
||||
* port stub should be used instead of the dynamic call mechanism.
|
||||
* See the javadoc of the "serviceInterface" property for more details.
|
||||
* <p>The interface must be suitable for a JAX-RPC port, that is, it must be
|
||||
* an RMI service interface (that extends <code>java.rmi.Remote</code>).
|
||||
* <p><b>NOTE:</b> Check whether your JAX-RPC provider returns thread-safe
|
||||
* port stubs. If not, use the dynamic call mechanism instead, which will
|
||||
* always be thread-safe. In particular, do not use JAX-RPC port stubs
|
||||
* with Apache Axis, whose port stubs are known to be non-thread-safe.
|
||||
* @see javax.xml.rpc.Service#getPort
|
||||
* @see java.rmi.Remote
|
||||
* @see #setServiceInterface
|
||||
*/
|
||||
public void setPortInterface(Class portInterface) {
|
||||
if (portInterface != null &&
|
||||
(!portInterface.isInterface() || !Remote.class.isAssignableFrom(portInterface))) {
|
||||
throw new IllegalArgumentException(
|
||||
"'portInterface' must be an interface derived from [java.rmi.Remote]");
|
||||
}
|
||||
this.portInterface = portInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JAX-RPC port interface to use.
|
||||
*/
|
||||
public Class getPortInterface() {
|
||||
return this.portInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to look up the JAX-RPC service on startup.
|
||||
* <p>Default is "true". Turn this flag off to allow for late start
|
||||
* of the target server. In this case, the JAX-RPC service will be
|
||||
* lazily fetched on first access.
|
||||
*/
|
||||
public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) {
|
||||
this.lookupServiceOnStartup = lookupServiceOnStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to refresh the JAX-RPC service on connect failure,
|
||||
* that is, whenever a JAX-RPC invocation throws a RemoteException.
|
||||
* <p>Default is "false", keeping a reference to the JAX-RPC service
|
||||
* in any case, retrying the next invocation on the same service
|
||||
* even in case of failure. Turn this flag on to reinitialize the
|
||||
* entire service in case of connect failures.
|
||||
*/
|
||||
public void setRefreshServiceAfterConnectFailure(boolean refreshServiceAfterConnectFailure) {
|
||||
this.refreshServiceAfterConnectFailure = refreshServiceAfterConnectFailure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepares the JAX-RPC service and port if the "lookupServiceOnStartup"
|
||||
* is turned on (which it is by default).
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
if (this.lookupServiceOnStartup) {
|
||||
prepare();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and initialize the JAX-RPC service for the specified port.
|
||||
* <p>Prepares a JAX-RPC stub if possible (if an RMI interface is available);
|
||||
* falls back to JAX-RPC dynamic calls else. Using dynamic calls can be enforced
|
||||
* through overriding {@link #alwaysUseJaxRpcCall} to return <code>true</code>.
|
||||
* <p>{@link #postProcessJaxRpcService} and {@link #postProcessPortStub}
|
||||
* hooks are available for customization in subclasses. When using dynamic calls,
|
||||
* each can be post-processed via {@link #postProcessJaxRpcCall}.
|
||||
* @throws RemoteLookupFailureException if service initialization or port stub creation failed
|
||||
*/
|
||||
public void prepare() throws RemoteLookupFailureException {
|
||||
if (getPortName() == null) {
|
||||
throw new IllegalArgumentException("Property 'portName' is required");
|
||||
}
|
||||
|
||||
synchronized (this.preparationMonitor) {
|
||||
this.serviceToUse = null;
|
||||
|
||||
// Cache the QName for the port.
|
||||
this.portQName = getQName(getPortName());
|
||||
|
||||
try {
|
||||
Service service = getJaxRpcService();
|
||||
if (service == null) {
|
||||
service = createJaxRpcService();
|
||||
}
|
||||
else {
|
||||
postProcessJaxRpcService(service);
|
||||
}
|
||||
|
||||
Class portInterface = getPortInterface();
|
||||
if (portInterface != null && !alwaysUseJaxRpcCall()) {
|
||||
// JAX-RPC-compliant port interface -> using JAX-RPC stub for port.
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating JAX-RPC proxy for JAX-RPC port [" + this.portQName +
|
||||
"], using port interface [" + portInterface.getName() + "]");
|
||||
}
|
||||
Remote remoteObj = service.getPort(this.portQName, portInterface);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
Class serviceInterface = getServiceInterface();
|
||||
if (serviceInterface != null) {
|
||||
boolean isImpl = serviceInterface.isInstance(remoteObj);
|
||||
logger.debug("Using service interface [" + serviceInterface.getName() + "] for JAX-RPC port [" +
|
||||
this.portQName + "] - " + (!isImpl ? "not" : "") + " directly implemented");
|
||||
}
|
||||
}
|
||||
|
||||
if (!(remoteObj instanceof Stub)) {
|
||||
throw new RemoteLookupFailureException("Port stub of class [" + remoteObj.getClass().getName() +
|
||||
"] is not a valid JAX-RPC stub: it does not implement interface [javax.xml.rpc.Stub]");
|
||||
}
|
||||
Stub stub = (Stub) remoteObj;
|
||||
|
||||
// Apply properties to JAX-RPC stub.
|
||||
preparePortStub(stub);
|
||||
|
||||
// Allow for custom post-processing in subclasses.
|
||||
postProcessPortStub(stub);
|
||||
|
||||
this.portStub = remoteObj;
|
||||
}
|
||||
|
||||
else {
|
||||
// No JAX-RPC-compliant port interface -> using JAX-RPC dynamic calls.
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using JAX-RPC dynamic calls for JAX-RPC port [" + this.portQName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
this.serviceToUse = service;
|
||||
}
|
||||
catch (ServiceException ex) {
|
||||
throw new RemoteLookupFailureException(
|
||||
"Failed to initialize service for JAX-RPC port [" + this.portQName + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to always use JAX-RPC dynamic calls.
|
||||
* Called by <code>afterPropertiesSet</code>.
|
||||
* <p>Default is "false"; if an RMI interface is specified as "portInterface"
|
||||
* or "serviceInterface", it will be used to create a JAX-RPC port stub.
|
||||
* <p>Can be overridden to enforce the use of the JAX-RPC Call API,
|
||||
* for example if there is a need to customize at the Call level.
|
||||
* This just necessary if you you want to use an RMI interface as
|
||||
* "serviceInterface", though; in case of only a non-RMI interface being
|
||||
* available, this interceptor will fall back to the Call API anyway.
|
||||
* @see #postProcessJaxRpcCall
|
||||
*/
|
||||
protected boolean alwaysUseJaxRpcCall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the prepared service of this interceptor,
|
||||
* allowing for reinitialization on next access.
|
||||
*/
|
||||
protected void reset() {
|
||||
synchronized (this.preparationMonitor) {
|
||||
this.serviceToUse = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this client interceptor has already been prepared,
|
||||
* i.e. has already looked up the JAX-RPC service and port.
|
||||
*/
|
||||
protected boolean isPrepared() {
|
||||
synchronized (this.preparationMonitor) {
|
||||
return (this.serviceToUse != null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the prepared QName for the port.
|
||||
* @see #setPortName
|
||||
* @see #getQName
|
||||
*/
|
||||
protected final QName getPortQName() {
|
||||
return this.portQName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare the given JAX-RPC port stub, applying properties to it.
|
||||
* Called by {@link #prepare}.
|
||||
* <p>Just applied when actually creating a JAX-RPC port stub, in case of a
|
||||
* compliant port interface. Else, JAX-RPC dynamic calls will be used.
|
||||
* @param stub the current JAX-RPC port stub
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @see #setEndpointAddress
|
||||
* @see #setMaintainSession
|
||||
* @see #setCustomProperties
|
||||
* @see #setPortInterface
|
||||
* @see #prepareJaxRpcCall
|
||||
*/
|
||||
protected void preparePortStub(Stub stub) {
|
||||
String username = getUsername();
|
||||
if (username != null) {
|
||||
stub._setProperty(Stub.USERNAME_PROPERTY, username);
|
||||
}
|
||||
String password = getPassword();
|
||||
if (password != null) {
|
||||
stub._setProperty(Stub.PASSWORD_PROPERTY, password);
|
||||
}
|
||||
String endpointAddress = getEndpointAddress();
|
||||
if (endpointAddress != null) {
|
||||
stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, endpointAddress);
|
||||
}
|
||||
if (isMaintainSession()) {
|
||||
stub._setProperty(Stub.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
|
||||
}
|
||||
if (this.customPropertyMap != null) {
|
||||
for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) {
|
||||
String key = (String) it.next();
|
||||
stub._setProperty(key, this.customPropertyMap.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the given JAX-RPC port stub. Called by {@link #prepare}.
|
||||
* <p>The default implementation is empty.
|
||||
* <p>Just applied when actually creating a JAX-RPC port stub, in case of a
|
||||
* compliant port interface. Else, JAX-RPC dynamic calls will be used.
|
||||
* @param stub the current JAX-RPC port stub
|
||||
* (can be cast to an implementation-specific class if necessary)
|
||||
* @see #setPortInterface
|
||||
* @see #postProcessJaxRpcCall
|
||||
*/
|
||||
protected void postProcessPortStub(Stub stub) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying JAX-RPC port stub that this interceptor delegates to
|
||||
* for each method invocation on the proxy.
|
||||
*/
|
||||
protected Remote getPortStub() {
|
||||
return this.portStub;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates the method invocation into a JAX-RPC service invocation.
|
||||
* <p>Prepares the service on the fly, if necessary, in case of lazy
|
||||
* lookup or a connect failure having happened.
|
||||
* @see #prepare()
|
||||
* @see #doInvoke
|
||||
*/
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
if (AopUtils.isToStringMethod(invocation.getMethod())) {
|
||||
return "JAX-RPC 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-RPC service invocation based on the given method invocation.
|
||||
* <p>Uses traditional RMI stub invocation if a JAX-RPC port stub is available;
|
||||
* falls back to JAX-RPC dynamic calls else.
|
||||
* @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, java.rmi.Remote)
|
||||
* @see #performJaxRpcCall(org.aopalliance.intercept.MethodInvocation, javax.xml.rpc.Service)
|
||||
*/
|
||||
protected Object doInvoke(MethodInvocation invocation) throws Throwable {
|
||||
Remote stub = getPortStub();
|
||||
try {
|
||||
if (stub != null) {
|
||||
// JAX-RPC port stub available -> traditional RMI stub invocation.
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' on JAX-RPC port stub");
|
||||
}
|
||||
return doInvoke(invocation, stub);
|
||||
}
|
||||
else {
|
||||
// No JAX-RPC stub -> using JAX-RPC dynamic calls.
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Invoking operation '" + invocation.getMethod().getName() + "' as JAX-RPC dynamic call");
|
||||
}
|
||||
return performJaxRpcCall(invocation, this.serviceToUse);
|
||||
}
|
||||
}
|
||||
catch (RemoteException ex) {
|
||||
throw handleRemoteException(invocation.getMethod(), ex);
|
||||
}
|
||||
catch (SOAPFaultException ex) {
|
||||
throw new JaxRpcSoapFaultException(ex);
|
||||
}
|
||||
catch (JAXRPCException ex) {
|
||||
throw new RemoteProxyFailureException("Invalid JAX-RPC call configuration", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a JAX-RPC 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()
|
||||
* @see #doInvoke(org.aopalliance.intercept.MethodInvocation, java.rmi.Remote)
|
||||
* @see #performJaxRpcCall
|
||||
*/
|
||||
protected Object doInvoke(MethodInvocation invocation, Remote portStub) throws Throwable {
|
||||
try {
|
||||
return RmiClientInterceptorUtils.invokeRemoteMethod(invocation, portStub);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
throw ex.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a JAX-RPC dynamic call for the given AOP method invocation.
|
||||
* Delegates to {@link #prepareJaxRpcCall} and
|
||||
* {@link #postProcessJaxRpcCall} for setting up the call object.
|
||||
* <p>The default implementation uses method name as JAX-RPC operation name
|
||||
* and method arguments as arguments for the JAX-RPC call. Can be
|
||||
* overridden in subclasses for custom operation names and/or arguments.
|
||||
* @param invocation the current AOP MethodInvocation that should
|
||||
* be converted to a JAX-RPC call
|
||||
* @param service the JAX-RPC Service to use for the call
|
||||
* @return the return value of the invocation, if any
|
||||
* @throws Throwable the exception thrown by the invocation, if any
|
||||
* @see #prepareJaxRpcCall
|
||||
* @see #postProcessJaxRpcCall
|
||||
*/
|
||||
protected Object performJaxRpcCall(MethodInvocation invocation, Service service) throws Throwable {
|
||||
Method method = invocation.getMethod();
|
||||
QName portQName = this.portQName;
|
||||
|
||||
// Create JAX-RPC call object, using the method name as operation name.
|
||||
// Synchronized because of non-thread-safe Axis implementation!
|
||||
Call call = null;
|
||||
synchronized (service) {
|
||||
call = service.createCall(portQName, method.getName());
|
||||
}
|
||||
|
||||
// Apply properties to JAX-RPC stub.
|
||||
prepareJaxRpcCall(call);
|
||||
|
||||
// Allow for custom post-processing in subclasses.
|
||||
postProcessJaxRpcCall(call, invocation);
|
||||
|
||||
// Perform actual invocation.
|
||||
return call.invoke(invocation.getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given JAX-RPC call, applying properties to it. Called by {@link #invoke}.
|
||||
* <p>Just applied when actually using JAX-RPC dynamic calls, i.e. if no compliant
|
||||
* port interface was specified. Else, a JAX-RPC port stub will be used.
|
||||
* @param call the current JAX-RPC call object
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @see #setEndpointAddress
|
||||
* @see #setMaintainSession
|
||||
* @see #setCustomProperties
|
||||
* @see #setPortInterface
|
||||
* @see #preparePortStub
|
||||
*/
|
||||
protected void prepareJaxRpcCall(Call call) {
|
||||
String username = getUsername();
|
||||
if (username != null) {
|
||||
call.setProperty(Call.USERNAME_PROPERTY, username);
|
||||
}
|
||||
String password = getPassword();
|
||||
if (password != null) {
|
||||
call.setProperty(Call.PASSWORD_PROPERTY, password);
|
||||
}
|
||||
String endpointAddress = getEndpointAddress();
|
||||
if (endpointAddress != null) {
|
||||
call.setTargetEndpointAddress(endpointAddress);
|
||||
}
|
||||
if (isMaintainSession()) {
|
||||
call.setProperty(Call.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);
|
||||
}
|
||||
if (this.customPropertyMap != null) {
|
||||
for (Iterator it = this.customPropertyMap.keySet().iterator(); it.hasNext();) {
|
||||
String key = (String) it.next();
|
||||
call.setProperty(key, this.customPropertyMap.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the given JAX-RPC call. Called by {@link #invoke}.
|
||||
* <p>The default implementation is empty.
|
||||
* <p>Just applied when actually using JAX-RPC dynamic calls, i.e. if no compliant
|
||||
* port interface was specified. Else, a JAX-RPC port stub will be used.
|
||||
* @param call the current JAX-RPC call object
|
||||
* (can be cast to an implementation-specific class if necessary)
|
||||
* @param invocation the current AOP MethodInvocation that the call was
|
||||
* created for (can be used to check method name, method parameters
|
||||
* and/or passed-in arguments)
|
||||
* @see #setPortInterface
|
||||
* @see #postProcessPortStub
|
||||
*/
|
||||
protected void postProcessJaxRpcCall(Call call, MethodInvocation invocation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the given RemoteException that was thrown from a JAX-RPC port stub
|
||||
* or JAX-RPC call invocation.
|
||||
* @param method the service interface method that we invoked
|
||||
* @param ex the original RemoteException
|
||||
* @return the exception to rethrow (may be the original RemoteException
|
||||
* or an extracted/wrapped exception, but never <code>null</code>)
|
||||
*/
|
||||
protected Throwable handleRemoteException(Method method, RemoteException ex) {
|
||||
boolean isConnectFailure = isConnectFailure(ex);
|
||||
if (isConnectFailure && this.refreshServiceAfterConnectFailure) {
|
||||
reset();
|
||||
}
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause != null && ReflectionUtils.declaresException(method, cause.getClass())) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Rethrowing wrapped exception of type [" + cause.getClass().getName() + "] as-is");
|
||||
}
|
||||
// Declared on the service interface: probably a wrapped business exception.
|
||||
return ex.getCause();
|
||||
}
|
||||
else {
|
||||
// Throw either a RemoteAccessException or the original RemoteException,
|
||||
// depending on what the service interface declares.
|
||||
return RmiClientInterceptorUtils.convertRmiAccessException(
|
||||
method, ex, isConnectFailure, this.portQName.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given RMI exception indicates a connect failure.
|
||||
* <p>The default implementation returns <code>true</code> unless the
|
||||
* exception class name (or exception superclass name) contains the term
|
||||
* "Fault" (e.g. "AxisFault"), assuming that the JAX-RPC provider only
|
||||
* throws RemoteException in case of WSDL faults and connect failures.
|
||||
* @param ex the RMI exception to check
|
||||
* @return whether the exception should be treated as connect failure
|
||||
* @see org.springframework.remoting.rmi.RmiClientInterceptorUtils#isConnectFailure
|
||||
*/
|
||||
protected boolean isConnectFailure(RemoteException ex) {
|
||||
return (ex.getClass().getName().indexOf("Fault") == -1 &&
|
||||
ex.getClass().getSuperclass().getName().indexOf("Fault") == -1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} for a specific port of a
|
||||
* JAX-RPC service. Exposes a proxy for the port, to be used for bean references.
|
||||
* Inherits configuration properties from {@link JaxRpcPortClientInterceptor}.
|
||||
*
|
||||
* <p>This factory is typically used with an RMI service interface. Alternatively,
|
||||
* this factory can also proxy a JAX-RPC 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
|
||||
* JAX-RPC stub will automatically get converted to Spring's unchecked
|
||||
* RemoteAccessException.
|
||||
*
|
||||
* <p>If exposing the JAX-RPC port interface (i.e. an RMI interface) directly,
|
||||
* setting "serviceInterface" is sufficient. If exposing a non-RMI business
|
||||
* interface, the business interface needs to be set as "serviceInterface",
|
||||
* and the JAX-RPC port interface as "portInterface".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.12.2003
|
||||
* @see #setServiceInterface
|
||||
* @see #setPortInterface
|
||||
* @see LocalJaxRpcServiceFactoryBean
|
||||
*/
|
||||
public class JaxRpcPortProxyFactoryBean extends JaxRpcPortClientInterceptor
|
||||
implements FactoryBean, BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private Object serviceProxy;
|
||||
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (getServiceInterface() == null) {
|
||||
// Use JAX-RPC port interface (a traditional RMI interface)
|
||||
// as service interface if none explicitly specified.
|
||||
if (getPortInterface() != null) {
|
||||
setServiceInterface(getPortInterface());
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Property 'serviceInterface' is required");
|
||||
}
|
||||
}
|
||||
super.afterPropertiesSet();
|
||||
this.serviceProxy = new ProxyFactory(getServiceInterface(), this).getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.serviceProxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return getServiceInterface();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import javax.xml.rpc.Service;
|
||||
|
||||
/**
|
||||
* Callback interface for post-processing a JAX-RPC Service.
|
||||
*
|
||||
* <p>Implementations can be registered with {@link LocalJaxRpcServiceFactory}
|
||||
* or one of its subclasses: {@link LocalJaxRpcServiceFactoryBean},
|
||||
* {@link JaxRpcPortClientInterceptor}, or {@link JaxRpcPortProxyFactoryBean}.
|
||||
*
|
||||
* <p>Useful, for example, to register custom type mappings. See the
|
||||
* {@link org.springframework.remoting.jaxrpc.support.AxisBeanMappingServicePostProcessor}
|
||||
* class that registers Axis-specific bean mappings for specified bean classes.
|
||||
* This is defined for the domain objects in the JPetStore same application,
|
||||
* for example.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.4
|
||||
* @see LocalJaxRpcServiceFactory#setServicePostProcessors
|
||||
* @see LocalJaxRpcServiceFactoryBean#setServicePostProcessors
|
||||
* @see JaxRpcPortClientInterceptor#setServicePostProcessors
|
||||
* @see JaxRpcPortProxyFactoryBean#setServicePostProcessors
|
||||
* @see javax.xml.rpc.Service#getTypeMappingRegistry
|
||||
*/
|
||||
public interface JaxRpcServicePostProcessor {
|
||||
|
||||
/**
|
||||
* Post-process the given JAX-RPC {@link Service}.
|
||||
* @param service the current JAX-RPC <code>Service</code>
|
||||
* (can be cast to an implementation-specific class if necessary)
|
||||
*/
|
||||
void postProcessJaxRpcService(Service service);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.rpc.soap.SOAPFaultException;
|
||||
|
||||
import org.springframework.remoting.soap.SoapFaultException;
|
||||
|
||||
/**
|
||||
* Spring SoapFaultException adapter for the JAX-RPC
|
||||
* {@link javax.xml.rpc.soap.SOAPFaultException} class.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class JaxRpcSoapFaultException extends SoapFaultException {
|
||||
|
||||
/**
|
||||
* Constructor for JaxRpcSoapFaultException.
|
||||
* @param original the original JAX-RPC SOAPFaultException to wrap
|
||||
*/
|
||||
public JaxRpcSoapFaultException(SOAPFaultException original) {
|
||||
super(original.getMessage(), original);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the wrapped JAX-RPC SOAPFaultException.
|
||||
*/
|
||||
public final SOAPFaultException getOriginalException() {
|
||||
return (SOAPFaultException) getCause();
|
||||
}
|
||||
|
||||
|
||||
public String getFaultCode() {
|
||||
return getOriginalException().getFaultCode().toString();
|
||||
}
|
||||
|
||||
public QName getFaultCodeAsQName() {
|
||||
return getOriginalException().getFaultCode();
|
||||
}
|
||||
|
||||
public String getFaultString() {
|
||||
return getOriginalException().getFaultString();
|
||||
}
|
||||
|
||||
public String getFaultActor() {
|
||||
return getOriginalException().getFaultActor();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.rpc.Service;
|
||||
import javax.xml.rpc.ServiceException;
|
||||
import javax.xml.rpc.ServiceFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* Factory for locally defined JAX-RPC {@link javax.xml.rpc.Service} references.
|
||||
* Uses a JAX-RPC {@link javax.xml.rpc.ServiceFactory} underneath.
|
||||
*
|
||||
* <p>Serves as base class for {@link LocalJaxRpcServiceFactoryBean} as well as
|
||||
* {@link JaxRpcPortClientInterceptor} and {@link JaxRpcPortProxyFactoryBean}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.12.2003
|
||||
* @see javax.xml.rpc.ServiceFactory
|
||||
* @see javax.xml.rpc.Service
|
||||
* @see LocalJaxRpcServiceFactoryBean
|
||||
* @see JaxRpcPortClientInterceptor
|
||||
* @see JaxRpcPortProxyFactoryBean
|
||||
*/
|
||||
public class LocalJaxRpcServiceFactory {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ServiceFactory serviceFactory;
|
||||
|
||||
private Class serviceFactoryClass;
|
||||
|
||||
private URL wsdlDocumentUrl;
|
||||
|
||||
private String namespaceUri;
|
||||
|
||||
private String serviceName;
|
||||
|
||||
private Class jaxRpcServiceInterface;
|
||||
|
||||
private Properties jaxRpcServiceProperties;
|
||||
|
||||
private JaxRpcServicePostProcessor[] servicePostProcessors;
|
||||
|
||||
|
||||
/**
|
||||
* Set the ServiceFactory instance to use.
|
||||
* <p>This is an alternative to the common "serviceFactoryClass" property,
|
||||
* allowing for a pre-initialized ServiceFactory instance to be specified.
|
||||
* @see #setServiceFactoryClass
|
||||
*/
|
||||
public void setServiceFactory(ServiceFactory serviceFactory) {
|
||||
this.serviceFactory = serviceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified ServiceFactory instance, if any.
|
||||
*/
|
||||
public ServiceFactory getServiceFactory() {
|
||||
return this.serviceFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ServiceFactory class to use, for example
|
||||
* "org.apache.axis.client.ServiceFactory".
|
||||
* <p>Does not need to be set if the JAX-RPC implementation has registered
|
||||
* itself with the JAX-RPC system property "SERVICEFACTORY_PROPERTY".
|
||||
* @see javax.xml.rpc.ServiceFactory
|
||||
*/
|
||||
public void setServiceFactoryClass(Class serviceFactoryClass) {
|
||||
if (serviceFactoryClass != null && !ServiceFactory.class.isAssignableFrom(serviceFactoryClass)) {
|
||||
throw new IllegalArgumentException("'serviceFactoryClass' must implement [javax.xml.rpc.ServiceFactory]");
|
||||
}
|
||||
this.serviceFactoryClass = serviceFactoryClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ServiceFactory class to use, or <code>null</code> if default.
|
||||
*/
|
||||
public Class getServiceFactoryClass() {
|
||||
return this.serviceFactoryClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL of the WSDL document that describes the service.
|
||||
*/
|
||||
public void setWsdlDocumentUrl(URL wsdlDocumentUrl) {
|
||||
this.wsdlDocumentUrl = wsdlDocumentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL of the WSDL document that describes the service.
|
||||
*/
|
||||
public URL getWsdlDocumentUrl() {
|
||||
return this.wsdlDocumentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace URI of the service.
|
||||
* Corresponds to the WSDL "targetNamespace".
|
||||
*/
|
||||
public void setNamespaceUri(String namespaceUri) {
|
||||
this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the namespace URI of the service.
|
||||
*/
|
||||
public String getNamespaceUri() {
|
||||
return this.namespaceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the service to look up.
|
||||
* Corresponds to the "wsdl:service" name.
|
||||
* @see javax.xml.rpc.ServiceFactory#createService(javax.xml.namespace.QName)
|
||||
* @see javax.xml.rpc.ServiceFactory#createService(java.net.URL, javax.xml.namespace.QName)
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, javax.xml.namespace.QName, java.util.Properties)
|
||||
*/
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the service.
|
||||
*/
|
||||
public String getServiceName() {
|
||||
return this.serviceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JAX-RPC service interface to use for looking up the service.
|
||||
* If specified, this will override a "serviceName" setting.
|
||||
* <p>The specified interface will usually be a generated JAX-RPC service
|
||||
* interface that directly corresponds to the WSDL service declaration.
|
||||
* Note that this is not a port interface or the application-level service
|
||||
* interface to be exposed by a port proxy!
|
||||
* <p>Only supported by JAX-RPC 1.1 providers.
|
||||
* @see #setServiceName
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService(Class)
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, Class, java.util.Properties)
|
||||
*/
|
||||
public void setJaxRpcServiceInterface(Class jaxRpcServiceInterface) {
|
||||
this.jaxRpcServiceInterface = jaxRpcServiceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JAX-RPC service interface to use for looking up the service.
|
||||
*/
|
||||
public Class getJaxRpcServiceInterface() {
|
||||
return this.jaxRpcServiceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set JAX-RPC service properties to be passed to the ServiceFactory, if any.
|
||||
* <p>Only supported by JAX-RPC 1.1 providers.
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, javax.xml.namespace.QName, java.util.Properties)
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService(java.net.URL, Class, java.util.Properties)
|
||||
*/
|
||||
public void setJaxRpcServiceProperties(Properties jaxRpcServiceProperties) {
|
||||
this.jaxRpcServiceProperties = jaxRpcServiceProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JAX-RPC service properties to be passed to the ServiceFactory, if any.
|
||||
*/
|
||||
public Properties getJaxRpcServiceProperties() {
|
||||
return this.jaxRpcServiceProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JaxRpcServicePostProcessors to be applied to JAX-RPC Service
|
||||
* instances created by this factory.
|
||||
* <p>Such post-processors can, for example, register custom type mappings.
|
||||
* They are reusable across all pre-built subclasses of this factory:
|
||||
* LocalJaxRpcServiceFactoryBean, JaxRpcPortClientInterceptor,
|
||||
* JaxRpcPortProxyFactoryBean.
|
||||
* @see LocalJaxRpcServiceFactoryBean
|
||||
* @see JaxRpcPortClientInterceptor
|
||||
* @see JaxRpcPortProxyFactoryBean
|
||||
*/
|
||||
public void setServicePostProcessors(JaxRpcServicePostProcessor[] servicePostProcessors) {
|
||||
this.servicePostProcessors = servicePostProcessors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JaxRpcServicePostProcessors to be applied to JAX-RPC Service
|
||||
* instances created by this factory.
|
||||
*/
|
||||
public JaxRpcServicePostProcessor[] getServicePostProcessors() {
|
||||
return this.servicePostProcessors;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a JAX-RPC Service according to the parameters of this factory.
|
||||
* @see #setServiceName
|
||||
* @see #setWsdlDocumentUrl
|
||||
* @see #postProcessJaxRpcService
|
||||
*/
|
||||
public Service createJaxRpcService() throws ServiceException {
|
||||
ServiceFactory serviceFactory = getServiceFactory();
|
||||
if (serviceFactory == null) {
|
||||
serviceFactory = createServiceFactory();
|
||||
}
|
||||
|
||||
// Create service based on this factory's settings.
|
||||
Service service = createService(serviceFactory);
|
||||
|
||||
// Allow for custom post-processing in subclasses.
|
||||
postProcessJaxRpcService(service);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JAX-RPC ServiceFactory, either of the specified class
|
||||
* or the default.
|
||||
* @throws ServiceException if thrown by JAX-RPC methods
|
||||
* @see #setServiceFactoryClass
|
||||
* @see javax.xml.rpc.ServiceFactory#newInstance()
|
||||
*/
|
||||
protected ServiceFactory createServiceFactory() throws ServiceException {
|
||||
if (getServiceFactoryClass() != null) {
|
||||
return (ServiceFactory) BeanUtils.instantiateClass(getServiceFactoryClass());
|
||||
}
|
||||
else {
|
||||
return ServiceFactory.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually create the JAX-RPC Service instance,
|
||||
* based on this factory's settings.
|
||||
* @param serviceFactory the JAX-RPC ServiceFactory to use
|
||||
* @return the newly created JAX-RPC Service
|
||||
* @throws ServiceException if thrown by JAX-RPC methods
|
||||
* @see javax.xml.rpc.ServiceFactory#createService
|
||||
* @see javax.xml.rpc.ServiceFactory#loadService
|
||||
*/
|
||||
protected Service createService(ServiceFactory serviceFactory) throws ServiceException {
|
||||
if (getServiceName() == null && getJaxRpcServiceInterface() == null) {
|
||||
throw new IllegalArgumentException("Either 'serviceName' or 'jaxRpcServiceInterface' is required");
|
||||
}
|
||||
|
||||
if (getJaxRpcServiceInterface() != null) {
|
||||
// Create service via generated JAX-RPC service interface.
|
||||
// Only supported on JAX-RPC 1.1
|
||||
if (getWsdlDocumentUrl() != null || getJaxRpcServiceProperties() != null) {
|
||||
return serviceFactory.loadService(
|
||||
getWsdlDocumentUrl(), getJaxRpcServiceInterface(), getJaxRpcServiceProperties());
|
||||
}
|
||||
return serviceFactory.loadService(getJaxRpcServiceInterface());
|
||||
}
|
||||
|
||||
// Create service via specified JAX-RPC service name.
|
||||
QName serviceQName = getQName(getServiceName());
|
||||
if (getJaxRpcServiceProperties() != null) {
|
||||
// Only supported on JAX-RPC 1.1
|
||||
return serviceFactory.loadService(getWsdlDocumentUrl(), serviceQName, getJaxRpcServiceProperties());
|
||||
}
|
||||
if (getWsdlDocumentUrl() != null) {
|
||||
return serviceFactory.createService(getWsdlDocumentUrl(), serviceQName);
|
||||
}
|
||||
return serviceFactory.createService(serviceQName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-process the given JAX-RPC Service. Called by {@link #createJaxRpcService}.
|
||||
* Useful, for example, to register custom type mappings.
|
||||
* <p>The default implementation delegates to all registered
|
||||
* {@link JaxRpcServicePostProcessor JaxRpcServicePostProcessors}.
|
||||
* It is usually preferable to implement custom type mappings etc there rather
|
||||
* than in a subclass of this factory, to allow for reuse of the post-processors.
|
||||
* @param service the current JAX-RPC Service
|
||||
* (can be cast to an implementation-specific class if necessary)
|
||||
* @see #setServicePostProcessors
|
||||
* @see javax.xml.rpc.Service#getTypeMappingRegistry()
|
||||
*/
|
||||
protected void postProcessJaxRpcService(Service service) {
|
||||
JaxRpcServicePostProcessor[] postProcessors = getServicePostProcessors();
|
||||
if (postProcessors != null) {
|
||||
for (int i = 0; i < postProcessors.length; i++) {
|
||||
postProcessors[i].postProcessJaxRpcService(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import javax.xml.rpc.Service;
|
||||
import javax.xml.rpc.ServiceException;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} for locally
|
||||
* defined JAX-RPC Service references.
|
||||
* Uses {@link LocalJaxRpcServiceFactory}'s facilities underneath.
|
||||
*
|
||||
* <p>Alternatively, JAX-RPC Service references can be looked up
|
||||
* in the JNDI environment of the J2EE container.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.12.2003
|
||||
* @see javax.xml.rpc.Service
|
||||
* @see org.springframework.jndi.JndiObjectFactoryBean
|
||||
* @see JaxRpcPortProxyFactoryBean
|
||||
*/
|
||||
public class LocalJaxRpcServiceFactoryBean extends LocalJaxRpcServiceFactory
|
||||
implements FactoryBean, InitializingBean {
|
||||
|
||||
private Service service;
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws ServiceException {
|
||||
this.service = createJaxRpcService();
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return (this.service != null ? this.service.getClass() : Service.class);
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.xml.rpc.ServiceException;
|
||||
import javax.xml.rpc.server.ServiceLifecycle;
|
||||
import javax.xml.rpc.server.ServletEndpointContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.MessageSourceAccessor;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Convenience base class for JAX-RPC servlet endpoint implementations.
|
||||
* Provides a reference to the current Spring application context,
|
||||
* e.g. for bean lookup or resource loading.
|
||||
*
|
||||
* <p>The Web Service servlet needs to run in the same web application
|
||||
* as the Spring context to allow for access to Spring's facilities.
|
||||
* In case of Axis, copy the AxisServlet definition into your web.xml,
|
||||
* and set up the endpoint in "server-config.wsdd" (or use the deploy tool).
|
||||
*
|
||||
* <p>This class does not extend
|
||||
* {@link org.springframework.web.context.support.WebApplicationObjectSupport}
|
||||
* to not expose any public setters. For some reason, Axis tries to
|
||||
* resolve public setters in a special way...
|
||||
*
|
||||
* <p>JAX-RPC service endpoints are usually required to implement an
|
||||
* RMI port interface. However, many JAX-RPC implementations accept plain
|
||||
* service endpoint classes too, avoiding the need to maintain an RMI port
|
||||
* interface in addition to an existing non-RMI business interface.
|
||||
* Therefore, implementing the business interface will usually be sufficient.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 16.12.2003
|
||||
* @see #init
|
||||
* @see #getWebApplicationContext
|
||||
*/
|
||||
public abstract class ServletEndpointSupport implements ServiceLifecycle {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ServletEndpointContext servletEndpointContext;
|
||||
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
private MessageSourceAccessor messageSourceAccessor;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize this JAX-RPC servlet endpoint.
|
||||
* Calls onInit after successful context initialization.
|
||||
* @param context ServletEndpointContext
|
||||
* @throws ServiceException if the context is not a ServletEndpointContext
|
||||
* @see #onInit
|
||||
*/
|
||||
public final void init(Object context) throws ServiceException {
|
||||
if (!(context instanceof ServletEndpointContext)) {
|
||||
throw new ServiceException("ServletEndpointSupport needs ServletEndpointContext, not [" + context + "]");
|
||||
}
|
||||
this.servletEndpointContext = (ServletEndpointContext) context;
|
||||
ServletContext servletContext = this.servletEndpointContext.getServletContext();
|
||||
this.webApplicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
|
||||
this.messageSourceAccessor = new MessageSourceAccessor(this.webApplicationContext);
|
||||
onInit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current JAX-RPC ServletEndpointContext.
|
||||
*/
|
||||
protected final ServletEndpointContext getServletEndpointContext() {
|
||||
return this.servletEndpointContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Spring ApplicationContext.
|
||||
*/
|
||||
protected final ApplicationContext getApplicationContext() {
|
||||
return this.webApplicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current Spring WebApplicationContext.
|
||||
*/
|
||||
protected final WebApplicationContext getWebApplicationContext() {
|
||||
return this.webApplicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a MessageSourceAccessor for the application context
|
||||
* used by this object, for easy message access.
|
||||
*/
|
||||
protected final MessageSourceAccessor getMessageSourceAccessor() {
|
||||
return this.messageSourceAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current ServletContext.
|
||||
*/
|
||||
protected final ServletContext getServletContext() {
|
||||
return this.webApplicationContext.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the temporary directory for the current web application,
|
||||
* as provided by the servlet container.
|
||||
* @return the File representing the temporary directory
|
||||
*/
|
||||
protected final File getTempDir() {
|
||||
return WebUtils.getTempDir(getServletContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for custom initialization after the context has been set up.
|
||||
* @throws ServiceException if initialization failed
|
||||
*/
|
||||
protected void onInit() throws ServiceException {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation of destroy is empty.
|
||||
* Can be overridden in subclasses.
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Remoting classes for Web Services via JAX-RPC.
|
||||
This package provides proxy factories for accessing JAX-RPC
|
||||
services and ports, and a support class for implementing
|
||||
JAX-RPC Servlet endpoints.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.jaxrpc.support;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.rpc.Service;
|
||||
import javax.xml.rpc.encoding.TypeMapping;
|
||||
import javax.xml.rpc.encoding.TypeMappingRegistry;
|
||||
|
||||
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
|
||||
import org.apache.axis.encoding.ser.BeanSerializerFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.remoting.jaxrpc.JaxRpcServicePostProcessor;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Axis-specific {@link JaxRpcServicePostProcessor} that registers bean
|
||||
* mappings for domain objects that follow the JavaBean pattern.
|
||||
*
|
||||
* <p>The same mappings are usually also registered at the server in
|
||||
* Axis' "server-config.wsdd" file.
|
||||
*
|
||||
* <p>To be registered as a service post-processor on a
|
||||
* {@link org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean} or
|
||||
* {@link org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean},
|
||||
* carrying appropriate configuration.
|
||||
*
|
||||
* <p>Note: Without such explicit bean mappings, a complex type like a
|
||||
* domain object cannot be transferred via SOAP.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.apache.axis.encoding.ser.BeanSerializerFactory
|
||||
* @see org.apache.axis.encoding.ser.BeanDeserializerFactory
|
||||
* @see org.springframework.remoting.jaxrpc.LocalJaxRpcServiceFactoryBean#setServicePostProcessors
|
||||
* @see org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean#setServicePostProcessors
|
||||
*/
|
||||
public class AxisBeanMappingServicePostProcessor implements JaxRpcServicePostProcessor, BeanClassLoaderAware {
|
||||
|
||||
private String encodingStyleUri;
|
||||
|
||||
private String typeNamespaceUri;
|
||||
|
||||
private Map beanMappings;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
|
||||
/**
|
||||
* Set the encoding style URI to use for the type mapping.
|
||||
* <p>A typical value is "http://schemas.xmlsoap.org/soap/encoding/",
|
||||
* as suggested by the JAX-RPC javadoc. However, note that the default
|
||||
* behavior of this post-processor is to register the type mapping
|
||||
* as JAX-RPC default if no explicit encoding style URI is given.
|
||||
* @see javax.xml.rpc.encoding.TypeMappingRegistry#register
|
||||
* @see javax.xml.rpc.encoding.TypeMappingRegistry#registerDefault
|
||||
*/
|
||||
public void setEncodingStyleUri(String encodingStyleUri) {
|
||||
this.encodingStyleUri = encodingStyleUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the application-specific namespace to use for XML types,
|
||||
* for example "urn:JPetStore".
|
||||
* @see javax.xml.rpc.encoding.TypeMapping#register
|
||||
*/
|
||||
public void setTypeNamespaceUri(String typeNamespaceUri) {
|
||||
this.typeNamespaceUri = typeNamespaceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the bean mappings to register as String-String pairs,
|
||||
* with the Java type name as key and the WSDL type name as value.
|
||||
*/
|
||||
public void setBeanMappings(Properties beanMappingProps) {
|
||||
if (beanMappingProps != null) {
|
||||
this.beanMappings = new HashMap(beanMappingProps.size());
|
||||
Enumeration propertyNames = beanMappingProps.propertyNames();
|
||||
while (propertyNames.hasMoreElements()) {
|
||||
String javaTypeName = (String) propertyNames.nextElement();
|
||||
String wsdlTypeName = beanMappingProps.getProperty(javaTypeName);
|
||||
this.beanMappings.put(javaTypeName, wsdlTypeName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.beanMappings = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the bean mappings to register as Java types,
|
||||
* with the WSDL type names inferred from the Java type names
|
||||
* (using the short, that is, non-fully-qualified class name).
|
||||
*/
|
||||
public void setBeanClasses(Class[] beanClasses) {
|
||||
if (beanClasses != null) {
|
||||
this.beanMappings = new HashMap(beanClasses.length);
|
||||
for (int i = 0; i < beanClasses.length; i++) {
|
||||
Class beanClass = beanClasses[i];
|
||||
String wsdlTypeName = ClassUtils.getShortName(beanClass);
|
||||
this.beanMappings.put(beanClass, wsdlTypeName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.beanMappings = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
this.beanClassLoader = beanClassLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register the specified bean mappings on the given Service's
|
||||
* {@link TypeMappingRegistry}.
|
||||
* @see javax.xml.rpc.Service#getTypeMappingRegistry()
|
||||
* @see #setBeanMappings
|
||||
* @see #registerBeanMappings(javax.xml.rpc.encoding.TypeMapping)
|
||||
*/
|
||||
public void postProcessJaxRpcService(Service service) {
|
||||
TypeMappingRegistry registry = service.getTypeMappingRegistry();
|
||||
TypeMapping mapping = registry.createTypeMapping();
|
||||
|
||||
registerBeanMappings(mapping);
|
||||
|
||||
if (this.encodingStyleUri != null) {
|
||||
registry.register(this.encodingStyleUri, mapping);
|
||||
}
|
||||
else {
|
||||
registry.registerDefault(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the actual bean mapping registration.
|
||||
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
|
||||
* @see #setBeanMappings
|
||||
* @see #registerBeanMapping(javax.xml.rpc.encoding.TypeMapping, Class, String)
|
||||
*/
|
||||
protected void registerBeanMappings(TypeMapping mapping) {
|
||||
if (this.beanMappings != null) {
|
||||
for (Iterator it = this.beanMappings.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Object key = entry.getKey();
|
||||
Class javaType = null;
|
||||
if (key instanceof Class) {
|
||||
javaType = (Class) key;
|
||||
}
|
||||
else {
|
||||
javaType = ClassUtils.resolveClassName((String) key, this.beanClassLoader);
|
||||
}
|
||||
String wsdlTypeName = (String) entry.getValue();
|
||||
registerBeanMapping(mapping, javaType, wsdlTypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a bean mapping for the given Java type and WSDL type name.
|
||||
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
|
||||
* @param javaType the Java type
|
||||
* @param wsdlTypeName the WSDL type name (as a {@link String})
|
||||
*/
|
||||
protected void registerBeanMapping(TypeMapping mapping, Class javaType, String wsdlTypeName) {
|
||||
registerBeanMapping(mapping, javaType, getTypeQName(wsdlTypeName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a bean mapping for the given Java type and WSDL type.
|
||||
* @param mapping the JAX-RPC {@link TypeMapping} to operate on
|
||||
* @param javaType the Java type
|
||||
* @param wsdlType the WSDL type (as XML {@link QName})
|
||||
*/
|
||||
protected void registerBeanMapping(TypeMapping mapping, Class javaType, QName wsdlType) {
|
||||
mapping.register(javaType, wsdlType,
|
||||
new BeanSerializerFactory(javaType, wsdlType),
|
||||
new BeanDeserializerFactory(javaType, wsdlType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link QName} for the given name, relative to the
|
||||
* {@link #setTypeNamespaceUri namespace URI} of this post-processor, if given.
|
||||
*/
|
||||
protected final QName getTypeQName(String name) {
|
||||
return (this.typeNamespaceUri != null ? new QName(this.typeNamespaceUri, name) : new QName(name));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Support for specific JAX-RPC providers. Contains an Axis-specific
|
||||
JaxRpcServicePostProcessor for declaratively registering bean mappings.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.ws.Endpoint;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.core.task.support.ConcurrentExecutorAdapter;
|
||||
|
||||
/**
|
||||
* 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 method for actual
|
||||
* endpoint exposure.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.5
|
||||
* @see javax.jws.WebService
|
||||
* @see javax.xml.ws.Endpoint
|
||||
* @see SimpleJaxWsServiceExporter
|
||||
* @see SimpleHttpServerJaxWsServiceExporter
|
||||
*/
|
||||
public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean {
|
||||
|
||||
private Map<String, Object> endpointProperties;
|
||||
|
||||
private Executor executor;
|
||||
|
||||
private ListableBeanFactory beanFactory;
|
||||
|
||||
private final Set<Endpoint> publishedEndpoints = new LinkedHashSet<Endpoint>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the property bag for the endpoint, including properties such as
|
||||
* "javax.xml.ws.wsdl.service" or "javax.xml.ws.wsdl.port".
|
||||
* @see javax.xml.ws.Endpoint#setProperties
|
||||
* @see javax.xml.ws.Endpoint#WSDL_SERVICE
|
||||
* @see javax.xml.ws.Endpoint#WSDL_PORT
|
||||
*/
|
||||
public void setEndpointProperties(Map<String, Object> endpointProperties) {
|
||||
this.endpointProperties = endpointProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JDK concurrent executor to use for dispatching incoming requests
|
||||
* to exported service instances.
|
||||
* @see javax.xml.ws.Endpoint#setExecutor
|
||||
*/
|
||||
public void setExecutor(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Spring TaskExecutor to use for dispatching incoming requests
|
||||
* to exported service instances.
|
||||
* @see javax.xml.ws.Endpoint#setExecutor
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor executor) {
|
||||
this.executor = new ConcurrentExecutorAdapter(executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains all web service beans and publishes them as JAX-WS endpoints.
|
||||
*/
|
||||
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()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
publishEndpoints();
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish all {@link javax.jws.WebService} annotated beans in the
|
||||
* containing BeanFactory.
|
||||
* @see #publishEndpoint
|
||||
*/
|
||||
public void publishEndpoints() {
|
||||
String[] beanNames = this.beanFactory.getBeanNamesForType(Object.class, false, false);
|
||||
for (String beanName : beanNames) {
|
||||
Class<?> type = this.beanFactory.getType(beanName);
|
||||
WebService annotation = type.getAnnotation(WebService.class);
|
||||
if (annotation != null) {
|
||||
Endpoint endpoint = Endpoint.create(this.beanFactory.getBean(beanName));
|
||||
if (this.endpointProperties != null) {
|
||||
endpoint.setProperties(this.endpointProperties);
|
||||
}
|
||||
if (this.executor != null) {
|
||||
endpoint.setExecutor(this.executor);
|
||||
}
|
||||
publishEndpoint(endpoint, annotation);
|
||||
this.publishedEndpoints.add(endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
|
||||
/**
|
||||
* Stops all published endpoints, taking the web services offline.
|
||||
*/
|
||||
public void destroy() {
|
||||
for (Endpoint endpoint : this.publishedEndpoints) {
|
||||
endpoint.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.soap.SOAPFaultException;
|
||||
|
||||
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.remoting.RemoteAccessException;
|
||||
import org.springframework.remoting.RemoteConnectFailureException;
|
||||
import org.springframework.remoting.RemoteLookupFailureException;
|
||||
import org.springframework.remoting.RemoteProxyFailureException;
|
||||
|
||||
/**
|
||||
* {@link org.aopalliance.intercept.MethodInterceptor} for accessing a
|
||||
* specific port of a JAX-WS service.
|
||||
*
|
||||
* <p>Uses either {@link LocalJaxWsServiceFactory}'s facilities underneath,
|
||||
* or takes an explicit reference to an existing JAX-WS Service instance
|
||||
* (e.g. obtained via {@link org.springframework.jndi.JndiObjectFactoryBean}).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see #setPortName
|
||||
* @see #setServiceInterface
|
||||
* @see javax.xml.ws.Service#getPort
|
||||
* @see org.springframework.remoting.RemoteAccessException
|
||||
* @see org.springframework.jndi.JndiObjectFactoryBean
|
||||
*/
|
||||
public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory
|
||||
implements MethodInterceptor, InitializingBean {
|
||||
|
||||
private Service jaxWsService;
|
||||
|
||||
private String portName;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
private String endpointAddress;
|
||||
|
||||
private boolean maintainSession;
|
||||
|
||||
private boolean useSoapAction;
|
||||
|
||||
private String soapActionUri;
|
||||
|
||||
private Map<String, Object> customProperties;
|
||||
|
||||
private Class<?> serviceInterface;
|
||||
|
||||
private boolean lookupServiceOnStartup = true;
|
||||
|
||||
private QName portQName;
|
||||
|
||||
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(Service jaxWsService) {
|
||||
this.jaxWsService = jaxWsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to an existing JAX-WS Service instance, if any.
|
||||
*/
|
||||
public Service getJaxWsService() {
|
||||
return this.jaxWsService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the port.
|
||||
* Corresponds to the "wsdl:port" name.
|
||||
*/
|
||||
public void setPortName(String portName) {
|
||||
this.portName = portName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the port.
|
||||
*/
|
||||
public String getPortName() {
|
||||
return this.portName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username to specify on the stub.
|
||||
* @see javax.xml.ws.BindingProvider#USERNAME_PROPERTY
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the username to specify on the stub.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password to specify on the stub.
|
||||
* @see javax.xml.ws.BindingProvider#PASSWORD_PROPERTY
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the password to specify on the stub.
|
||||
*/
|
||||
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(String endpointAddress) {
|
||||
this.endpointAddress = endpointAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the endpoint address to specify on the stub.
|
||||
*/
|
||||
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(String soapActionUri) {
|
||||
this.soapActionUri = soapActionUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SOAP action URI to specify on the stub.
|
||||
*/
|
||||
public String getSoapActionUri() {
|
||||
return this.soapActionUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom properties to be set on the stub.
|
||||
* <p>Can be populated with a String "value" (parsed via PropertiesEditor)
|
||||
* or a "props" element in XML bean definitions.
|
||||
* @see javax.xml.ws.BindingProvider#getRequestContext()
|
||||
*/
|
||||
public void setCustomProperties(Map<String, Object> customProperties) {
|
||||
this.customProperties = customProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow Map access to the custom properties to be set on the stub,
|
||||
* with the option to add or override specific entries.
|
||||
* <p>Useful for specifying entries directly, for example via
|
||||
* "customProperties[myKey]". This is particularly useful for
|
||||
* adding or overriding entries in child bean definitions.
|
||||
*/
|
||||
public Map<String, Object> getCustomProperties() {
|
||||
if (this.customProperties == null) {
|
||||
this.customProperties = new HashMap<String, Object>();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interface of the service that this factory should create a proxy for.
|
||||
*/
|
||||
public void setServiceInterface(Class serviceInterface) {
|
||||
if (serviceInterface != null && !serviceInterface.isInterface()) {
|
||||
throw new IllegalArgumentException("'serviceInterface' must be an interface");
|
||||
}
|
||||
this.serviceInterface = serviceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the interface of the service that this factory should create a proxy for.
|
||||
*/
|
||||
public Class getServiceInterface() {
|
||||
return this.serviceInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to look up the JAX-WS service on startup.
|
||||
* <p>Default is "true". Turn this flag off to allow for late start
|
||||
* of the target server. In this case, the JAX-WS service will be
|
||||
* lazily fetched on first access.
|
||||
*/
|
||||
public void setLookupServiceOnStartup(boolean lookupServiceOnStartup) {
|
||||
this.lookupServiceOnStartup = lookupServiceOnStartup;
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.lookupServiceOnStartup) {
|
||||
prepare();
|
||||
}
|
||||
}
|
||||
|
||||
public void prepare() {
|
||||
if (getServiceInterface() == null) {
|
||||
throw new IllegalArgumentException("Property 'serviceInterface' is required");
|
||||
}
|
||||
Service serviceToUse = getJaxWsService();
|
||||
if (serviceToUse == null) {
|
||||
serviceToUse = createJaxWsService();
|
||||
}
|
||||
this.portQName = getQName(getPortName() != null ? getPortName() : getServiceInterface().getName());
|
||||
Object stub = (getPortName() != null ?
|
||||
serviceToUse.getPort(this.portQName, getServiceInterface()) : serviceToUse.getPort(getServiceInterface()));
|
||||
preparePortStub(stub);
|
||||
this.portStub = stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected final QName getPortQName() {
|
||||
return this.portQName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the given JAX-WS port stub, applying properties to it.
|
||||
* Called by {@link #prepare}.
|
||||
* @param stub the current JAX-WS port stub
|
||||
* @see #setUsername
|
||||
* @see #setPassword
|
||||
* @see #setEndpointAddress
|
||||
* @see #setMaintainSession
|
||||
* @see #setCustomProperties
|
||||
*/
|
||||
protected void preparePortStub(Object stub) {
|
||||
Map<String, Object> stubProperties = new HashMap<String, Object>();
|
||||
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.
|
||||
*/
|
||||
protected Object getPortStub() {
|
||||
return this.portStub;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
*/
|
||||
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 [" + this.portQName + "]", ex);
|
||||
}
|
||||
catch (WebServiceException ex) {
|
||||
throw new RemoteAccessException("Could not access remote service at [" + this.portQName + "]", 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()
|
||||
*/
|
||||
protected Object doInvoke(MethodInvocation invocation, 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@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, BeanClassLoaderAware {
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private Object serviceProxy;
|
||||
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
super.afterPropertiesSet();
|
||||
|
||||
// Build a proxy that also exposes the JAX-WS BindingProvider interface.
|
||||
ProxyFactory pf = new ProxyFactory();
|
||||
pf.addInterface(getServiceInterface());
|
||||
pf.addInterface(BindingProvider.class);
|
||||
pf.addAdvice(this);
|
||||
this.serviceProxy = pf.getProxy(this.beanClassLoader);
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.serviceProxy;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return getServiceInterface();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
public String getFaultCode() {
|
||||
return getFault().getFaultCode();
|
||||
}
|
||||
|
||||
public QName getFaultCodeAsQName() {
|
||||
return getFault().getFaultCodeAsQName();
|
||||
}
|
||||
|
||||
public String getFaultString() {
|
||||
return getFault().getFaultString();
|
||||
}
|
||||
|
||||
public String getFaultActor() {
|
||||
return getFault().getFaultActor();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.URL;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.ws.Service;
|
||||
import javax.xml.ws.handler.HandlerResolver;
|
||||
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.core.task.support.ConcurrentExecutorAdapter;
|
||||
|
||||
/**
|
||||
* Factory for locally defined JAX-WS {@link javax.xml.ws.Service} references.
|
||||
* Uses the JAX-WS {@link javax.xml.ws.Service#create} factory API underneath.
|
||||
*
|
||||
* <p>Serves as base class for {@link LocalJaxWsServiceFactoryBean} as well as
|
||||
* {@link JaxWsPortClientInterceptor} and {@link JaxWsPortProxyFactoryBean}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see javax.xml.ws.Service
|
||||
* @see LocalJaxWsServiceFactoryBean
|
||||
* @see JaxWsPortClientInterceptor
|
||||
* @see JaxWsPortProxyFactoryBean
|
||||
*/
|
||||
public class LocalJaxWsServiceFactory {
|
||||
|
||||
private URL wsdlDocumentUrl;
|
||||
|
||||
private String namespaceUri;
|
||||
|
||||
private String serviceName;
|
||||
|
||||
private Executor executor;
|
||||
|
||||
private HandlerResolver handlerResolver;
|
||||
|
||||
|
||||
/**
|
||||
* Set the URL of the WSDL document that describes the service.
|
||||
*/
|
||||
public void setWsdlDocumentUrl(URL wsdlDocumentUrl) {
|
||||
this.wsdlDocumentUrl = wsdlDocumentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL of the WSDL document that describes the service.
|
||||
*/
|
||||
public URL getWsdlDocumentUrl() {
|
||||
return this.wsdlDocumentUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the namespace URI of the service.
|
||||
* Corresponds to the WSDL "targetNamespace".
|
||||
*/
|
||||
public void setNamespaceUri(String namespaceUri) {
|
||||
this.namespaceUri = (namespaceUri != null ? namespaceUri.trim() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the namespace URI of the service.
|
||||
*/
|
||||
public String getNamespaceUri() {
|
||||
return this.namespaceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the service to look up.
|
||||
* Corresponds to the "wsdl:service" name.
|
||||
*/
|
||||
public void setServiceName(String serviceName) {
|
||||
this.serviceName = serviceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the service.
|
||||
*/
|
||||
public String getServiceName() {
|
||||
return this.serviceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Spring TaskExecutor to use for asynchronous executions
|
||||
* that require callbacks.
|
||||
* @see javax.xml.ws.Service#setExecutor
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor executor) {
|
||||
this.executor = new ConcurrentExecutorAdapter(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() {
|
||||
Service 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));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.FactoryBean} for locally
|
||||
* defined JAX-WS Service references.
|
||||
* Uses {@link LocalJaxWsServiceFactory}'s facilities underneath.
|
||||
*
|
||||
* <p>Alternatively, JAX-WS Service references can be looked up
|
||||
* in the JNDI environment of the J2EE 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 {
|
||||
|
||||
private Service service;
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.service = createJaxWsService();
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return (this.service != null ? this.service.getClass() : Service.class);
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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 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;
|
||||
|
||||
/**
|
||||
* Simple exporter for JAX-WS services, autodetecting annotated service beans
|
||||
* (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting
|
||||
* them through the HTTP server included in Sun's JDK 1.6. The full address
|
||||
* for each service will consist of the server's base address with the
|
||||
* service name appended (e.g. "http://localhost:8080/OrderService").
|
||||
*
|
||||
* <p>Note that this exporter will only work on Sun's JDK 1.6 or higher, as well
|
||||
* as on JDKs that ship Sun's entire class library as included in the Sun JDK.
|
||||
* For a portable JAX-WS exporter, have a look at {@link SimpleJaxWsServiceExporter}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.5
|
||||
* @see javax.jws.WebService
|
||||
* @see javax.xml.ws.Endpoint#publish(Object)
|
||||
* @see SimpleJaxWsServiceExporter
|
||||
*/
|
||||
public class SimpleHttpServerJaxWsServiceExporter extends AbstractJaxWsServiceExporter {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private HttpServer server;
|
||||
|
||||
private int port = 8080;
|
||||
|
||||
private String hostname;
|
||||
|
||||
private int backlog = -1;
|
||||
|
||||
private int shutdownDelay = 0;
|
||||
|
||||
private String basePath = "/";
|
||||
|
||||
private List<Filter> filters;
|
||||
|
||||
private Authenticator authenticator;
|
||||
|
||||
private boolean localServer = false;
|
||||
|
||||
|
||||
/**
|
||||
* Specify an existing HTTP server to register the web service contexts
|
||||
* with. This will typically be a server managed by the general Spring
|
||||
* {@link org.springframework.remoting.support.SimpleHttpServerFactoryBean}.
|
||||
* <p>Alternatively, configure a local HTTP server through the
|
||||
* {@link #setPort "port"}, {@link #setHostname "hostname"} and
|
||||
* {@link #setBacklog "backlog"} properties (or rely on the defaults there).
|
||||
*/
|
||||
public void setServer(HttpServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the HTTP server's port. Default is 8080.
|
||||
* <p>Only applicable for a locally configured HTTP server.
|
||||
* Ignored when the {@link #setServer "server"} property has been specified.
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the HTTP server's hostname to bind to. Default is localhost;
|
||||
* can be overridden with a specific network address to bind to.
|
||||
* <p>Only applicable for a locally configured HTTP server.
|
||||
* Ignored when the {@link #setServer "server"} property has been specified.
|
||||
*/
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the HTTP server's TCP backlog. Default is -1,
|
||||
* indicating the system's default value.
|
||||
* <p>Only applicable for a locally configured HTTP server.
|
||||
* Ignored when the {@link #setServer "server"} property has been specified.
|
||||
*/
|
||||
public void setBacklog(int backlog) {
|
||||
this.backlog = backlog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the number of seconds to wait until HTTP exchanges have
|
||||
* completed when shutting down the HTTP server. Default is 0.
|
||||
* <p>Only applicable for a locally configured HTTP server.
|
||||
* Ignored when the {@link #setServer "server"} property has been specified.
|
||||
*/
|
||||
public void setShutdownDelay(int shutdownDelay) {
|
||||
this.shutdownDelay = shutdownDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the base path for context publication. Default is "/".
|
||||
* <p>For each context publication path, the service name will be
|
||||
* appended to this base address. E.g. service name "OrderService"
|
||||
* -> "/OrderService".
|
||||
* @see javax.xml.ws.Endpoint#publish(Object)
|
||||
* @see javax.jws.WebService#serviceName()
|
||||
*/
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register common {@link com.sun.net.httpserver.Filter Filters} to be
|
||||
* applied to all detected {@link javax.jws.WebService} annotated beans.
|
||||
*/
|
||||
public void setFilters(List<Filter> filters) {
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a common {@link com.sun.net.httpserver.Authenticator} to be
|
||||
* applied to all detected {@link javax.jws.WebService} annotated beans.
|
||||
*/
|
||||
public void setAuthenticator(Authenticator authenticator) {
|
||||
this.authenticator = authenticator;
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.server == null) {
|
||||
InetSocketAddress address = (this.hostname != null ?
|
||||
new InetSocketAddress(this.hostname, this.port) : new InetSocketAddress(this.port));
|
||||
this.server = HttpServer.create(address, this.backlog);
|
||||
if (this.logger.isInfoEnabled()) {
|
||||
this.logger.info("Starting HttpServer at address " + address);
|
||||
}
|
||||
this.server.start();
|
||||
this.localServer = true;
|
||||
}
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
protected void publishEndpoint(Endpoint endpoint, WebService annotation) {
|
||||
String fullPath = this.basePath + annotation.serviceName();
|
||||
HttpContext httpContext = this.server.createContext(fullPath);
|
||||
if (this.filters != null) {
|
||||
httpContext.getFilters().addAll(this.filters);
|
||||
}
|
||||
if (this.authenticator != null) {
|
||||
httpContext.setAuthenticator(this.authenticator);
|
||||
}
|
||||
endpoint.publish(httpContext);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
if (this.localServer) {
|
||||
logger.info("Stopping HttpServer");
|
||||
this.server.stop(this.shutdownDelay);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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;
|
||||
|
||||
/**
|
||||
* Simple exporter for JAX-WS services, autodetecting annotated service beans
|
||||
* (through the JAX-WS {@link javax.jws.WebService} annotation) and exporting
|
||||
* them with a configured base address (by default "http://localhost:8080/")
|
||||
* using the JAX-WS provider's built-in publication support. The full address
|
||||
* for each service will consist of the base address with the service name
|
||||
* appended (e.g. "http://localhost:8080/OrderService").
|
||||
*
|
||||
* <p>Note that this exporter will only work if the JAX-WS runtime actually
|
||||
* supports publishing with an address argument, i.e. if the JAX-WS runtime
|
||||
* ships an internal HTTP server. This is the case with the JAX-WS runtime
|
||||
* that's inclued in Sun's JDK 1.6 but not with the standalone JAX-WS 2.1 RI.
|
||||
*
|
||||
* <p>For explicit configuration of JAX-WS endpoints with Sun's JDK 1.6
|
||||
* HTTP server, consider using {@link SimpleHttpServerJaxWsServiceExporter}!
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see javax.jws.WebService
|
||||
* @see javax.xml.ws.Endpoint#publish(String)
|
||||
* @see SimpleHttpServerJaxWsServiceExporter
|
||||
*/
|
||||
public class SimpleJaxWsServiceExporter extends AbstractJaxWsServiceExporter {
|
||||
|
||||
public static final String DEFAULT_BASE_ADDRESS = "http://localhost:8080/";
|
||||
|
||||
private String baseAddress = DEFAULT_BASE_ADDRESS;
|
||||
|
||||
|
||||
/**
|
||||
* Set the base address for exported services.
|
||||
* Default is "http://localhost:8080/".
|
||||
* <p>For each actual publication address, the service name will be
|
||||
* appended to this base address. E.g. service name "OrderService"
|
||||
* -> "http://localhost:8080/OrderService".
|
||||
* @see javax.xml.ws.Endpoint#publish(String)
|
||||
* @see javax.jws.WebService#serviceName()
|
||||
*/
|
||||
public void setBaseAddress(String baseAddress) {
|
||||
this.baseAddress = baseAddress;
|
||||
}
|
||||
|
||||
|
||||
protected void publishEndpoint(Endpoint endpoint, WebService annotation) {
|
||||
String fullAddress = this.baseAddress + annotation.serviceName();
|
||||
endpoint.publish(fullAddress);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
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.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Plain handler interface for components that process HTTP requests,
|
||||
* analogous to a Servlet. Only declares {@link javax.servlet.ServletException}
|
||||
* and {@link java.io.IOException}, to allow for usage within any
|
||||
* {@link javax.servlet.http.HttpServlet}}. This interface is ssentially the
|
||||
* direct equivalent of an HttpServlet, reduced to a central handle method.
|
||||
*
|
||||
* <p>The easiest way to expose an HttpRequestHandler bean in Spring style
|
||||
* is to define it in Spring's root web application context and define
|
||||
* an {@link org.springframework.web.context.support.HttpRequestHandlerServlet}
|
||||
* in <code>web.xml</code>, pointing at the target HttpRequestHandler bean
|
||||
* through its <code>servlet-name</code> which needs to match the target bean name.
|
||||
*
|
||||
* <p>Supported as a handler type within Spring's
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}, being able
|
||||
* to interact with the dispatcher's advanced mapping and interception
|
||||
* facilities. This is the recommended way of exposing an HttpRequestHandler,
|
||||
* while keeping the handler implementations free of direct dependencies
|
||||
* on a DispatcherServlet environment.
|
||||
*
|
||||
* <p>Typically implemented to generate binary responses directly,
|
||||
* with no separate view resource involved. This differentiates it from a
|
||||
* {@link org.springframework.web.servlet.mvc.Controller} within Spring's Web MVC
|
||||
* framework. The lack of a {@link org.springframework.web.servlet.ModelAndView}
|
||||
* return value gives a clearer signature to callers other than the
|
||||
* DispatcherServlet, indicating that there will never be a view to render.
|
||||
*
|
||||
* <p>As of Spring 2.0, Spring's HTTP-based remote exporters, such as
|
||||
* {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter}
|
||||
* and {@link org.springframework.remoting.caucho.HessianServiceExporter},
|
||||
* implement this interface rather than the more extensive Controller interface,
|
||||
* for minimal dependencies on Spring-specific web infrastructure.
|
||||
*
|
||||
* <p>Note that HttpRequestHandlers may optionally implement the
|
||||
* {@link org.springframework.web.servlet.mvc.LastModified} interface,
|
||||
* just like Controllers can, <i>provided that they run within Spring's
|
||||
* DispatcherServlet</i>. However, this is usually not necessary, since
|
||||
* HttpRequestHandlers typically only support POST requests to begin with.
|
||||
* Alternatively, a handler may implement the "If-Modified-Since" HTTP
|
||||
* header processing manually within its <code>handle</code> method.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.web.context.support.HttpRequestHandlerServlet
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.servlet.ModelAndView
|
||||
* @see org.springframework.web.servlet.mvc.Controller
|
||||
* @see org.springframework.web.servlet.mvc.LastModified
|
||||
* @see org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
|
||||
* @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
|
||||
* @see org.springframework.remoting.caucho.HessianServiceExporter
|
||||
* @see org.springframework.remoting.caucho.BurlapServiceExporter
|
||||
*/
|
||||
public interface HttpRequestHandler {
|
||||
|
||||
/**
|
||||
* Process the given request, generating a response.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @throws ServletException in case of general errors
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
void handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a request handler does not support a
|
||||
* specific request method.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestMethodNotSupportedException extends ServletException {
|
||||
|
||||
private String method;
|
||||
|
||||
private String[] supportedMethods;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new HttpRequestMethodNotSupportedException.
|
||||
* @param method the unsupported HTTP request method
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method) {
|
||||
this(method, (String[]) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HttpRequestMethodNotSupportedException.
|
||||
* @param method the unsupported HTTP request method
|
||||
* @param supportedMethods the actually supported HTTP methods
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods) {
|
||||
this(method, supportedMethods, "Request method '" + method + "' not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HttpRequestMethodNotSupportedException.
|
||||
* @param method the unsupported HTTP request method
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method, String msg) {
|
||||
this(method, null, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HttpRequestMethodNotSupportedException.
|
||||
* @param method the unsupported HTTP request method
|
||||
* @param supportedMethods the actually supported HTTP methods
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpRequestMethodNotSupportedException(String method, String[] supportedMethods, String msg) {
|
||||
super(msg);
|
||||
this.method = method;
|
||||
this.supportedMethods = supportedMethods;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the HTTP request method that caused the failure.
|
||||
*/
|
||||
public String getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actually supported HTTP methods, if known.
|
||||
*/
|
||||
public String[] getSupportedMethods() {
|
||||
return this.supportedMethods;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
/**
|
||||
* Exception thrown when an HTTP request handler requires a pre-existing session.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpSessionRequiredException extends ServletException {
|
||||
|
||||
/**
|
||||
* Create a new HttpSessionRequiredException.
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpSessionRequiredException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by configurable web application contexts.
|
||||
* Supported by {@link ContextLoader} and
|
||||
* {@link org.springframework.web.servlet.FrameworkServlet}.
|
||||
*
|
||||
* <p>Note: The setters of this interface need to be called before an
|
||||
* invocation of the {@link #refresh} method inherited from
|
||||
* {@link org.springframework.context.ConfigurableApplicationContext}.
|
||||
* They do not cause an initialization of the context on their own.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 05.12.2003
|
||||
* @see #refresh
|
||||
* @see ContextLoader#createWebApplicationContext
|
||||
* @see org.springframework.web.servlet.FrameworkServlet#createWebApplicationContext
|
||||
*/
|
||||
public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
|
||||
|
||||
/**
|
||||
* Set the ServletContext for this web application context.
|
||||
* <p>Does not cause an initialization of the context: refresh needs to be
|
||||
* called after the setting of all configuration properties.
|
||||
* @see #refresh()
|
||||
*/
|
||||
void setServletContext(ServletContext servletContext);
|
||||
|
||||
/**
|
||||
* Set the ServletConfig for this web application context.
|
||||
* Only called for a WebApplicationContext that belongs to a specific Servlet.
|
||||
* @see #refresh()
|
||||
*/
|
||||
void setServletConfig(ServletConfig servletConfig);
|
||||
|
||||
/**
|
||||
* Return the ServletConfig for this web application context, if any.
|
||||
*/
|
||||
ServletConfig getServletConfig();
|
||||
|
||||
/**
|
||||
* Set the namespace for this web application context,
|
||||
* to be used for building a default context config location.
|
||||
* The root web application context does not have a namespace.
|
||||
*/
|
||||
void setNamespace(String namespace);
|
||||
|
||||
/**
|
||||
* Return the namespace for this web application context, if any.
|
||||
*/
|
||||
String getNamespace();
|
||||
|
||||
/**
|
||||
* Set the config locations for this web application context in init-param style,
|
||||
* i.e. with distinct locations separated by commas, semicolons or whitespace.
|
||||
* <p>If not set, the implementation is supposed to use a default for the
|
||||
* given namespace or the root web application context, as appropriate.
|
||||
*/
|
||||
void setConfigLocation(String configLocation);
|
||||
|
||||
/**
|
||||
* Set the config locations for this web application context.
|
||||
* <p>If not set, the implementation is supposed to use a default for the
|
||||
* given namespace or the root web application context, as appropriate.
|
||||
*/
|
||||
void setConfigLocations(String[] configLocations);
|
||||
|
||||
/**
|
||||
* Return the config locations for this web application context,
|
||||
* or <code>null</code> if none specified.
|
||||
*/
|
||||
String[] getConfigLocations();
|
||||
|
||||
}
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Performs the actual initialization work for the root application context.
|
||||
* Called by {@link ContextLoaderListener} and {@link ContextLoaderServlet}.
|
||||
*
|
||||
* <p>Looks for a {@link #CONTEXT_CLASS_PARAM "contextClass"} parameter
|
||||
* at the <code>web.xml</code> context-param level to specify the context
|
||||
* class type, falling back to the default of
|
||||
* {@link org.springframework.web.context.support.XmlWebApplicationContext}
|
||||
* if not found. With the default ContextLoader implementation, any context class
|
||||
* specified needs to implement the ConfigurableWebApplicationContext interface.
|
||||
*
|
||||
* <p>Processes a {@link #CONFIG_LOCATION_PARAM "contextConfigLocation"}
|
||||
* context-param and passes its value to the context instance, parsing it into
|
||||
* potentially multiple file paths which can be separated by any number of
|
||||
* commas and spaces, e.g. "WEB-INF/applicationContext1.xml,
|
||||
* WEB-INF/applicationContext2.xml". Ant-style path patterns are supported as well,
|
||||
* e.g. "WEB-INF/*Context.xml,WEB-INF/spring*.xml" or "WEB-INF/**/*Context.xml".
|
||||
* If not explicitly specified, the context implementation is supposed to use a
|
||||
* default location (with XmlWebApplicationContext: "/WEB-INF/applicationContext.xml").
|
||||
*
|
||||
* <p>Note: In case of multiple config locations, later bean definitions will
|
||||
* override ones defined in previously loaded files, at least when using one of
|
||||
* Spring's default ApplicationContext implementations. This can be leveraged
|
||||
* to deliberately override certain bean definitions via an extra XML file.
|
||||
*
|
||||
* <p>Above and beyond loading the root application context, this class
|
||||
* can optionally load or obtain and hook up a shared parent context to
|
||||
* the root application context. See the
|
||||
* {@link #loadParentContext(ServletContext)} method for more information.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Colin Sampaleanu
|
||||
* @author Sam Brannen
|
||||
* @since 17.02.2003
|
||||
* @see ContextLoaderListener
|
||||
* @see ContextLoaderServlet
|
||||
* @see ConfigurableWebApplicationContext
|
||||
* @see org.springframework.web.context.support.XmlWebApplicationContext
|
||||
*/
|
||||
public class ContextLoader {
|
||||
|
||||
/**
|
||||
* Config param for the root WebApplicationContext implementation class to
|
||||
* use: "<code>contextClass</code>"
|
||||
*/
|
||||
public static final String CONTEXT_CLASS_PARAM = "contextClass";
|
||||
|
||||
/**
|
||||
* Name of servlet context parameter (i.e., "<code>contextConfigLocation</code>")
|
||||
* that can specify the config location for the root context, falling back
|
||||
* to the implementation's default otherwise.
|
||||
* @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
|
||||
*/
|
||||
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
|
||||
|
||||
/**
|
||||
* Optional servlet context parameter (i.e., "<code>locatorFactorySelector</code>")
|
||||
* used only when obtaining a parent context using the default implementation
|
||||
* of {@link #loadParentContext(ServletContext servletContext)}.
|
||||
* Specifies the 'selector' used in the
|
||||
* {@link ContextSingletonBeanFactoryLocator#getInstance(String selector)}
|
||||
* method call, which is used to obtain the BeanFactoryLocator instance from
|
||||
* which the parent context is obtained.
|
||||
* <p>The default is <code>classpath*:beanRefContext.xml</code>,
|
||||
* matching the default applied for the
|
||||
* {@link ContextSingletonBeanFactoryLocator#getInstance()} method.
|
||||
* Supplying the "parentContextKey" parameter is sufficient in this case.
|
||||
*/
|
||||
public static final String LOCATOR_FACTORY_SELECTOR_PARAM = "locatorFactorySelector";
|
||||
|
||||
/**
|
||||
* Optional servlet context parameter (i.e., "<code>parentContextKey</code>")
|
||||
* used only when obtaining a parent context using the default implementation
|
||||
* of {@link #loadParentContext(ServletContext servletContext)}.
|
||||
* Specifies the 'factoryKey' used in the
|
||||
* {@link BeanFactoryLocator#useBeanFactory(String factoryKey)} method call,
|
||||
* obtaining the parent application context from the BeanFactoryLocator instance.
|
||||
* <p>Supplying this "parentContextKey" parameter is sufficient when relying
|
||||
* on the default <code>classpath*:beanRefContext.xml</code> selector for
|
||||
* candidate factory references.
|
||||
*/
|
||||
public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey";
|
||||
|
||||
/**
|
||||
* Name of the class path resource (relative to the ContextLoader class)
|
||||
* that defines ContextLoader's default strategy names.
|
||||
*/
|
||||
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
|
||||
|
||||
|
||||
private static final Properties defaultStrategies;
|
||||
|
||||
static {
|
||||
// Load default strategy implementations from properties file.
|
||||
// This is currently strictly internal and not meant to be customized
|
||||
// by application developers.
|
||||
try {
|
||||
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
|
||||
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ContextLoader.class);
|
||||
|
||||
/**
|
||||
* Map from (thread context) ClassLoader to WebApplicationContext.
|
||||
* Often just holding one reference - if the ContextLoader class is
|
||||
* deployed in the web app ClassLoader itself!
|
||||
*/
|
||||
private static final Map currentContextPerThread = CollectionFactory.createConcurrentMapIfPossible(1);
|
||||
|
||||
/**
|
||||
* The root WebApplicationContext instance that this loader manages.
|
||||
*/
|
||||
private WebApplicationContext context;
|
||||
|
||||
/**
|
||||
* Holds BeanFactoryReference when loading parent factory via
|
||||
* ContextSingletonBeanFactoryLocator.
|
||||
*/
|
||||
private BeanFactoryReference parentContextRef;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize Spring's web application context for the given servlet context,
|
||||
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
|
||||
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
|
||||
* @param servletContext current servlet context
|
||||
* @return the new WebApplicationContext
|
||||
* @throws IllegalStateException if there is already a root application context present
|
||||
* @throws BeansException if the context failed to initialize
|
||||
* @see #CONTEXT_CLASS_PARAM
|
||||
* @see #CONFIG_LOCATION_PARAM
|
||||
*/
|
||||
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
|
||||
throws IllegalStateException, BeansException {
|
||||
|
||||
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot initialize context because there is already a root application context present - " +
|
||||
"check whether you have multiple ContextLoader* definitions in your web.xml!");
|
||||
}
|
||||
|
||||
servletContext.log("Initializing Spring root WebApplicationContext");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Root WebApplicationContext: initialization started");
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// Determine parent for root web application context, if any.
|
||||
ApplicationContext parent = loadParentContext(servletContext);
|
||||
|
||||
// Store context in local instance variable, to guarantee that
|
||||
// it is available on ServletContext shutdown.
|
||||
this.context = createWebApplicationContext(servletContext, parent);
|
||||
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
|
||||
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
|
||||
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
|
||||
}
|
||||
|
||||
return this.context;
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
logger.error("Context initialization failed", ex);
|
||||
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
|
||||
throw ex;
|
||||
}
|
||||
catch (Error err) {
|
||||
logger.error("Context initialization failed", err);
|
||||
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate the root WebApplicationContext for this loader, either the
|
||||
* default context class or a custom context class if specified.
|
||||
* <p>This implementation expects custom contexts to implement the
|
||||
* {@link ConfigurableWebApplicationContext} interface.
|
||||
* Can be overridden in subclasses.
|
||||
* <p>In addition, {@link #customizeContext} gets called prior to refreshing the
|
||||
* context, allowing subclasses to perform custom modifications to the context.
|
||||
* @param servletContext current servlet context
|
||||
* @param parent the parent ApplicationContext to use, or <code>null</code> if none
|
||||
* @return the root WebApplicationContext
|
||||
* @throws BeansException if the context couldn't be initialized
|
||||
* @see ConfigurableWebApplicationContext
|
||||
*/
|
||||
protected WebApplicationContext createWebApplicationContext(
|
||||
ServletContext servletContext, ApplicationContext parent) throws BeansException {
|
||||
|
||||
Class contextClass = determineContextClass(servletContext);
|
||||
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
|
||||
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
|
||||
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
|
||||
}
|
||||
|
||||
ConfigurableWebApplicationContext wac =
|
||||
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
|
||||
wac.setParent(parent);
|
||||
wac.setServletContext(servletContext);
|
||||
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
|
||||
customizeContext(servletContext, wac);
|
||||
wac.refresh();
|
||||
|
||||
return wac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the WebApplicationContext implementation class to use, either the
|
||||
* default XmlWebApplicationContext or a custom context class if specified.
|
||||
* @param servletContext current servlet context
|
||||
* @return the WebApplicationContext implementation class to use
|
||||
* @throws ApplicationContextException if the context class couldn't be loaded
|
||||
* @see #CONTEXT_CLASS_PARAM
|
||||
* @see org.springframework.web.context.support.XmlWebApplicationContext
|
||||
*/
|
||||
protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {
|
||||
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
|
||||
if (contextClassName != null) {
|
||||
try {
|
||||
return ClassUtils.forName(contextClassName);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"Failed to load custom context class [" + contextClassName + "]", ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
|
||||
try {
|
||||
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
throw new ApplicationContextException(
|
||||
"Failed to load default context class [" + contextClassName + "]", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the {@link ConfigurableWebApplicationContext} created by this
|
||||
* ContextLoader after config locations have been supplied to the context
|
||||
* but before the context is <em>refreshed</em>.
|
||||
* <p>The default implementation is empty but can be overridden in subclasses
|
||||
* to customize the application context.
|
||||
* @param servletContext the current servlet context
|
||||
* @param applicationContext the newly created application context
|
||||
* @see #createWebApplicationContext(ServletContext, ApplicationContext)
|
||||
*/
|
||||
protected void customizeContext(
|
||||
ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method with default implementation (which may be overridden by a
|
||||
* subclass), to load or obtain an ApplicationContext instance which will be
|
||||
* used as the parent context of the root WebApplicationContext. If the
|
||||
* return value from the method is null, no parent context is set.
|
||||
* <p>The main reason to load a parent context here is to allow multiple root
|
||||
* web application contexts to all be children of a shared EAR context, or
|
||||
* alternately to also share the same parent context that is visible to
|
||||
* EJBs. For pure web applications, there is usually no need to worry about
|
||||
* having a parent context to the root web application context.
|
||||
* <p>The default implementation uses
|
||||
* {@link org.springframework.context.access.ContextSingletonBeanFactoryLocator},
|
||||
* configured via {@link #LOCATOR_FACTORY_SELECTOR_PARAM} and
|
||||
* {@link #LOCATOR_FACTORY_KEY_PARAM}, to load a parent context
|
||||
* which will be shared by all other users of ContextsingletonBeanFactoryLocator
|
||||
* which also use the same configuration parameters.
|
||||
* @param servletContext current servlet context
|
||||
* @return the parent application context, or <code>null</code> if none
|
||||
* @throws BeansException if the context couldn't be initialized
|
||||
* @see org.springframework.context.access.ContextSingletonBeanFactoryLocator
|
||||
*/
|
||||
protected ApplicationContext loadParentContext(ServletContext servletContext)
|
||||
throws BeansException {
|
||||
|
||||
ApplicationContext parentContext = null;
|
||||
String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);
|
||||
String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);
|
||||
|
||||
if (parentContextKey != null) {
|
||||
// locatorFactorySelector may be null, indicating the default "classpath*:beanRefContext.xml"
|
||||
BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Getting parent context definition: using parent context key of '" +
|
||||
parentContextKey + "' with BeanFactoryLocator");
|
||||
}
|
||||
this.parentContextRef = locator.useBeanFactory(parentContextKey);
|
||||
parentContext = (ApplicationContext) this.parentContextRef.getFactory();
|
||||
}
|
||||
|
||||
return parentContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close Spring's web application context for the given servlet context. If
|
||||
* the default {@link #loadParentContext(ServletContext)} implementation,
|
||||
* which uses ContextSingletonBeanFactoryLocator, has loaded any shared
|
||||
* parent context, release one reference to that shared parent context.
|
||||
* <p>If overriding {@link #loadParentContext(ServletContext)}, you may have
|
||||
* to override this method as well.
|
||||
* @param servletContext the ServletContext that the WebApplicationContext runs in
|
||||
*/
|
||||
public void closeWebApplicationContext(ServletContext servletContext) {
|
||||
servletContext.log("Closing Spring root WebApplicationContext");
|
||||
try {
|
||||
if (this.context instanceof ConfigurableWebApplicationContext) {
|
||||
((ConfigurableWebApplicationContext) this.context).close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
currentContextPerThread.remove(Thread.currentThread().getContextClassLoader());
|
||||
servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
if (this.parentContextRef != null) {
|
||||
this.parentContextRef.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the Spring root web application context for the current thread
|
||||
* (i.e. for the current thread's context ClassLoader, which needs to be
|
||||
* the web application's ClassLoader).
|
||||
* @return the current root web application context, or <code>null</code>
|
||||
* if none found
|
||||
* @see org.springframework.web.context.support.SpringBeanAutowiringSupport
|
||||
*/
|
||||
public static WebApplicationContext getCurrentWebApplicationContext() {
|
||||
return (WebApplicationContext) currentContextPerThread.get(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# Default WebApplicationContext implementation class for ContextLoader.
|
||||
# Used as fallback when no explicit context implementation has been specified as context-param.
|
||||
# Not meant to be customized by application developers.
|
||||
|
||||
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
/**
|
||||
* Bootstrap listener to start up Spring's root {@link WebApplicationContext}.
|
||||
* Simply delegates to {@link ContextLoader}.
|
||||
*
|
||||
* <p>This listener should be registered after
|
||||
* {@link org.springframework.web.util.Log4jConfigListener}
|
||||
* in <code>web.xml</code>, if the latter is used.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 17.02.2003
|
||||
* @see ContextLoaderServlet
|
||||
* @see org.springframework.web.util.Log4jConfigListener
|
||||
*/
|
||||
public class ContextLoaderListener implements ServletContextListener {
|
||||
|
||||
private ContextLoader contextLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the root web application context.
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
this.contextLoader = createContextLoader();
|
||||
this.contextLoader.initWebApplicationContext(event.getServletContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ContextLoader to use. Can be overridden in subclasses.
|
||||
* @return the new ContextLoader
|
||||
*/
|
||||
protected ContextLoader createContextLoader() {
|
||||
return new ContextLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ContextLoader used by this listener.
|
||||
* @return the current ContextLoader
|
||||
*/
|
||||
public ContextLoader getContextLoader() {
|
||||
return this.contextLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the root web application context.
|
||||
*/
|
||||
public void contextDestroyed(ServletContextEvent event) {
|
||||
if (this.contextLoader != null) {
|
||||
this.contextLoader.closeWebApplicationContext(event.getServletContext());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Bootstrap servlet to start up Spring's root {@link WebApplicationContext}.
|
||||
* Simply delegates to {@link ContextLoader}.
|
||||
*
|
||||
* <p>This servlet should have a lower <code>load-on-startup</code> value
|
||||
* in <code>web.xml</code> than any servlets that access the root web
|
||||
* application context.
|
||||
*
|
||||
* <p><i>Note that this class has been deprecated for containers implementing
|
||||
* Servlet API 2.4 or higher, in favor of {@link ContextLoaderListener}.</i><br>
|
||||
* According to Servlet 2.4, listeners must be initialized before load-on-startup
|
||||
* servlets. Many Servlet 2.3 containers already enforce this behavior. If you
|
||||
* use such a container, this servlet can be replaced with ContextLoaderListener.
|
||||
*
|
||||
* <p>Servlet 2.3 containers known to work with bootstrap listeners are:
|
||||
* <ul>
|
||||
* <li>Apache Tomcat 4.x+
|
||||
* <li>Jetty 4.x+
|
||||
* <li>Resin 2.1.8+
|
||||
* <li>Orion 2.0.2+
|
||||
* <li>BEA WebLogic 8.1 SP3
|
||||
* </ul>
|
||||
* For working with any of them, ContextLoaderListener is recommended.
|
||||
*
|
||||
* <p>Servlet 2.3 containers known <i>not</i> to work with bootstrap listeners are:
|
||||
* <ul>
|
||||
* <li>BEA WebLogic up to 8.1 SP2
|
||||
* <li>IBM WebSphere 5.x
|
||||
* <li>Oracle OC4J 9.0.3
|
||||
* </ul>
|
||||
* If you happen to work with such a server, this servlet has to be used.
|
||||
*
|
||||
* <p>So unfortunately, the only context initialization option that is compatible
|
||||
* with <i>all</i> Servlet 2.3 containers is this servlet.
|
||||
*
|
||||
* <p>Note that a startup failure of this servlet will not stop the rest of the
|
||||
* web application from starting, in contrast to a listener failure. This can
|
||||
* lead to peculiar side effects if other servlets get started that depend on
|
||||
* initialization of the root web application context.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Darren Davison
|
||||
* @see ContextLoaderListener
|
||||
* @see org.springframework.web.util.Log4jConfigServlet
|
||||
*/
|
||||
public class ContextLoaderServlet extends HttpServlet {
|
||||
|
||||
private ContextLoader contextLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the root web application context.
|
||||
*/
|
||||
public void init() throws ServletException {
|
||||
this.contextLoader = createContextLoader();
|
||||
this.contextLoader.initWebApplicationContext(getServletContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ContextLoader to use. Can be overridden in subclasses.
|
||||
* @return the new ContextLoader
|
||||
*/
|
||||
protected ContextLoader createContextLoader() {
|
||||
return new ContextLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ContextLoader used by this servlet.
|
||||
* @return the current ContextLoader
|
||||
*/
|
||||
public ContextLoader getContextLoader() {
|
||||
return this.contextLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Close the root web application context.
|
||||
*/
|
||||
public void destroy() {
|
||||
if (this.contextLoader != null) {
|
||||
this.contextLoader.closeWebApplicationContext(getServletContext());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This should never even be called since no mapping to this servlet should
|
||||
* ever be created in web.xml. That's why a correctly invoked Servlet 2.3
|
||||
* listener is much more appropriate for initialization work ;-)
|
||||
*/
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
getServletContext().log(
|
||||
"Attempt to call service method on ContextLoaderServlet as [" +
|
||||
request.getRequestURI() + "] was ignored");
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
public String getServletInfo() {
|
||||
return "ContextLoaderServlet for Servlet API 2.3 " +
|
||||
"(deprecated in favor of ContextLoaderListener for Servlet API 2.4)";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the ServletConfig (typically determined by the WebApplicationContext)
|
||||
* that it runs in.
|
||||
*
|
||||
* <p>Only satisfied if actually running within a Servlet-specific
|
||||
* WebApplicationContext. If this callback interface is encountered
|
||||
* elsewhere, an exception will be thrown on bean creation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ServletContextAware
|
||||
*/
|
||||
public interface ServletConfigAware {
|
||||
|
||||
/**
|
||||
* Set the ServletConfig that this object runs in.
|
||||
* <p>Invoked after population of normal bean properties but before an init
|
||||
* callback like InitializingBean's <code>afterPropertiesSet</code> or a
|
||||
* custom init-method. Invoked after ApplicationContextAware's
|
||||
* <code>setApplicationContext</code>.
|
||||
* @param servletConfig ServletConfig object to be used by this object
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
|
||||
*/
|
||||
void setServletConfig(ServletConfig servletConfig);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
/**
|
||||
* Interface to be implemented by any object that wishes to be notified
|
||||
* of the ServletContext (typically determined by the WebApplicationContext)
|
||||
* that it runs in.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 12.03.2004
|
||||
* @see ServletConfigAware
|
||||
*/
|
||||
public interface ServletContextAware {
|
||||
|
||||
/**
|
||||
* Set the ServletContext that this object runs in.
|
||||
* <p>Invoked after population of normal bean properties but before an init
|
||||
* callback like InitializingBean's <code>afterPropertiesSet</code> or a
|
||||
* custom init-method. Invoked after ApplicationContextAware's
|
||||
* <code>setApplicationContext</code>.
|
||||
* @param servletContext ServletContext object to be used by this object
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext
|
||||
*/
|
||||
void setServletContext(ServletContext servletContext);
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web.context;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* Interface to provide configuration for a web application. This is read-only while
|
||||
* the application is running, but may be reloaded if the implementation supports this.
|
||||
*
|
||||
* <p>This interface adds a getServletContext method to the generic ApplicationContext
|
||||
* interface, and defines a well-known application attribute name that the root
|
||||
* context must be bound to in the bootstrap process.
|
||||
*
|
||||
* <p>Like generic application contexts, web application contexts are hierarchical.
|
||||
* There is a single root context per application, while each servlet in the application
|
||||
* (including a dispatcher servlet in the MVC framework) has its own child context.
|
||||
*
|
||||
* <p>In addition to standard application context lifecycle capabilities,
|
||||
* WebApplicationContext implementations need to detect ServletContextAware
|
||||
* beans and invoke the setServletContext method accordingly.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since January 19, 2001
|
||||
* @see ServletContextAware#setServletContext
|
||||
*/
|
||||
public interface WebApplicationContext extends ApplicationContext {
|
||||
|
||||
/**
|
||||
* Context attribute to bind root WebApplicationContext to on successful startup.
|
||||
* <p>Note: If the startup of the root context fails, this attribute can contain
|
||||
* an exception or error as value. Use WebApplicationContextUtils for convenient
|
||||
* lookup of the root WebApplicationContext.
|
||||
* @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext
|
||||
* @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext
|
||||
*/
|
||||
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
|
||||
|
||||
|
||||
/**
|
||||
* Scope identifier for request scope: "request".
|
||||
* Supported in addition to the standard scopes "singleton" and "prototype".
|
||||
*/
|
||||
String SCOPE_REQUEST = "request";
|
||||
|
||||
/**
|
||||
* Scope identifier for session scope: "session".
|
||||
* Supported in addition to the standard scopes "singleton" and "prototype".
|
||||
*/
|
||||
String SCOPE_SESSION = "session";
|
||||
|
||||
/**
|
||||
* Scope identifier for global session scope: "globalSession".
|
||||
* Supported in addition to the standard scopes "singleton" and "prototype".
|
||||
*/
|
||||
String SCOPE_GLOBAL_SESSION = "globalSession";
|
||||
|
||||
|
||||
/**
|
||||
* Return the standard Servlet API ServletContext for this application.
|
||||
*/
|
||||
ServletContext getServletContext();
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Contains a variant of the application context interface for web applications,
|
||||
and the ContextLoaderListener that bootstraps a root web application context.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Abstract support class for RequestAttributes implementations,
|
||||
* offering a request completion mechanism for request-specific destruction
|
||||
* callbacks and for updating accessed session attributes.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see #requestCompleted()
|
||||
*/
|
||||
public abstract class AbstractRequestAttributes implements RequestAttributes {
|
||||
|
||||
/** Map from attribute name String to destruction callback Runnable */
|
||||
protected final Map requestDestructionCallbacks = new LinkedHashMap(8);
|
||||
|
||||
private volatile boolean requestActive = true;
|
||||
|
||||
|
||||
/**
|
||||
* Signal that the request has been completed.
|
||||
* <p>Executes all request destruction callbacks and updates the
|
||||
* session attributes that have been accessed during request processing.
|
||||
*/
|
||||
public void requestCompleted() {
|
||||
executeRequestDestructionCallbacks();
|
||||
updateAccessedSessionAttributes();
|
||||
this.requestActive = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the original request is still active.
|
||||
* @see #requestCompleted()
|
||||
*/
|
||||
protected final boolean isRequestActive() {
|
||||
return this.requestActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given callback as to be executed after request completion.
|
||||
* @param name the name of the attribute to register the callback for
|
||||
* @param callback the callback to be executed for destruction
|
||||
*/
|
||||
protected final void registerRequestDestructionCallback(String name, Runnable callback) {
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
Assert.notNull(callback, "Callback must not be null");
|
||||
synchronized (this.requestDestructionCallbacks) {
|
||||
this.requestDestructionCallbacks.put(name, callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the request destruction callback for the specified attribute, if any.
|
||||
* @param name the name of the attribute to remove the callback for
|
||||
*/
|
||||
protected final void removeRequestDestructionCallback(String name) {
|
||||
Assert.notNull(name, "Name must not be null");
|
||||
synchronized (this.requestDestructionCallbacks) {
|
||||
this.requestDestructionCallbacks.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all callbacks that have been registered for execution
|
||||
* after request completion.
|
||||
*/
|
||||
private void executeRequestDestructionCallbacks() {
|
||||
synchronized (this.requestDestructionCallbacks) {
|
||||
for (Iterator it = this.requestDestructionCallbacks.values().iterator(); it.hasNext();) {
|
||||
((Runnable) it.next()).run();
|
||||
}
|
||||
this.requestDestructionCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all session attributes that have been accessed during request processing,
|
||||
* to expose their potentially updated state to the underlying session manager.
|
||||
*/
|
||||
protected abstract void updateAccessedSessionAttributes();
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.Scope;
|
||||
|
||||
/**
|
||||
* Abstract {@link Scope} implementation that reads from a particular scope
|
||||
* in the current thread-bound {@link RequestAttributes} object.
|
||||
*
|
||||
* <p>Subclasses simply need to implement {@link #getScope()} to instruct
|
||||
* this class which {@link RequestAttributes} scope to read attributes from.
|
||||
*
|
||||
* <p>Subclasses may wish to override the {@link #get} and {@link #remove}
|
||||
* methods to add synchronization around the call back into this super class.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractRequestAttributesScope implements Scope {
|
||||
|
||||
public Object get(String name, ObjectFactory objectFactory) {
|
||||
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
|
||||
Object scopedObject = attributes.getAttribute(name, getScope());
|
||||
if (scopedObject == null) {
|
||||
scopedObject = objectFactory.getObject();
|
||||
attributes.setAttribute(name, scopedObject, getScope());
|
||||
}
|
||||
return scopedObject;
|
||||
}
|
||||
|
||||
public Object remove(String name) {
|
||||
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
|
||||
Object scopedObject = attributes.getAttribute(name, getScope());
|
||||
if (scopedObject != null) {
|
||||
attributes.removeAttribute(name, getScope());
|
||||
return scopedObject;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void registerDestructionCallback(String name, Runnable callback) {
|
||||
RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
|
||||
attributes.registerDestructionCallback(name, callback, getScope());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method that determines the actual target scope.
|
||||
* @return the target scope, in the form of an appropriate
|
||||
* {@link RequestAttributes} constant
|
||||
* @see RequestAttributes#SCOPE_REQUEST
|
||||
* @see RequestAttributes#SCOPE_SESSION
|
||||
* @see RequestAttributes#SCOPE_GLOBAL_SESSION
|
||||
*/
|
||||
protected abstract int getScope();
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* {@link RequestAttributes} adapter for a JSF {@link javax.faces.context.FacesContext}.
|
||||
* Used as default in a JSF environment, wrapping the current FacesContext.
|
||||
*
|
||||
* <p><b>NOTE:</b> In contrast to {@link ServletRequestAttributes}, this variant does
|
||||
* <i>not</i> support destruction callbacks for scoped attributes, neither for the
|
||||
* request scope nor for the session scope. If you rely on such implicit destruction
|
||||
* callbacks, consider defining a Spring {@link RequestContextListener} in your
|
||||
* <code>web.xml</code>.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
* @see javax.faces.context.FacesContext#getExternalContext()
|
||||
* @see javax.faces.context.ExternalContext#getRequestMap()
|
||||
* @see javax.faces.context.ExternalContext#getSessionMap()
|
||||
* @see RequestContextHolder#currentRequestAttributes()
|
||||
*/
|
||||
public class FacesRequestAttributes implements RequestAttributes {
|
||||
|
||||
/**
|
||||
* We'll create a lot of these objects, so we don't want a new logger every time.
|
||||
*/
|
||||
private static final Log logger = LogFactory.getLog(FacesRequestAttributes.class);
|
||||
|
||||
private final FacesContext facesContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new FacesRequestAttributes adapter for the given FacesContext.
|
||||
* @param facesContext the current FacesContext
|
||||
* @see javax.faces.context.FacesContext#getCurrentInstance()
|
||||
*/
|
||||
public FacesRequestAttributes(FacesContext facesContext) {
|
||||
Assert.notNull(facesContext, "FacesContext must not be null");
|
||||
this.facesContext = facesContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the JSF FacesContext that this adapter operates on.
|
||||
*/
|
||||
protected FacesContext getFacesContext() {
|
||||
return this.facesContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSF ExternalContext that this adapter operates on.
|
||||
* @see javax.faces.context.FacesContext#getExternalContext()
|
||||
*/
|
||||
protected ExternalContext getExternalContext() {
|
||||
return getFacesContext().getExternalContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSF attribute Map for the specified scope
|
||||
* @param scope constant indicating request or session scope
|
||||
* @return the Map representation of the attributes in the specified scope
|
||||
* @see #SCOPE_REQUEST
|
||||
* @see #SCOPE_SESSION
|
||||
*/
|
||||
protected Map getAttributeMap(int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
return getExternalContext().getRequestMap();
|
||||
}
|
||||
else {
|
||||
return getExternalContext().getSessionMap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object getAttribute(String name, int scope) {
|
||||
return getAttributeMap(scope).get(name);
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value, int scope) {
|
||||
getAttributeMap(scope).put(name, value);
|
||||
}
|
||||
|
||||
public void removeAttribute(String name, int scope) {
|
||||
getAttributeMap(scope).remove(name);
|
||||
}
|
||||
|
||||
public String[] getAttributeNames(int scope) {
|
||||
return StringUtils.toStringArray(getAttributeMap(scope).entrySet());
|
||||
}
|
||||
|
||||
public void registerDestructionCallback(String name, Runnable callback, int scope) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Could not register destruction callback [" + callback + "] for attribute '" + name +
|
||||
"' because FacesRequestAttributes does not support such callbacks");
|
||||
}
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
Object session = getExternalContext().getSession(true);
|
||||
try {
|
||||
// Both HttpSession and PortletSession have a getId() method.
|
||||
Method getIdMethod = session.getClass().getMethod("getId", new Class[0]);
|
||||
return ReflectionUtils.invokeMethod(getIdMethod, session).toString();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("Session object [" + session + "] does not have a getId() method");
|
||||
}
|
||||
}
|
||||
|
||||
public Object getSessionMutex() {
|
||||
// Enforce presence of a session first to allow listeners
|
||||
// to create the mutex attribute, if any.
|
||||
Object session = getExternalContext().getSession(true);
|
||||
Object mutex = getExternalContext().getSessionMap().get(WebUtils.SESSION_MUTEX_ATTRIBUTE);
|
||||
if (mutex == null) {
|
||||
mutex = session;
|
||||
}
|
||||
return mutex;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link WebRequest} adapter for a JSF {@link javax.faces.context.FacesContext}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
*/
|
||||
public class FacesWebRequest extends FacesRequestAttributes implements NativeWebRequest {
|
||||
|
||||
/**
|
||||
* Create a new FacesWebRequest adapter for the given FacesContext.
|
||||
* @param facesContext the current FacesContext
|
||||
* @see javax.faces.context.FacesContext#getCurrentInstance()
|
||||
*/
|
||||
public FacesWebRequest(FacesContext facesContext) {
|
||||
super(facesContext);
|
||||
}
|
||||
|
||||
|
||||
public Object getNativeRequest() {
|
||||
return getExternalContext().getRequest();
|
||||
}
|
||||
|
||||
public Object getNativeResponse() {
|
||||
return getExternalContext().getResponse();
|
||||
}
|
||||
|
||||
|
||||
public String getParameter(String paramName) {
|
||||
return (String) getExternalContext().getRequestParameterMap().get(paramName);
|
||||
}
|
||||
|
||||
public String[] getParameterValues(String paramName) {
|
||||
return (String[]) getExternalContext().getRequestParameterMap().get(paramName);
|
||||
}
|
||||
|
||||
public Map getParameterMap() {
|
||||
return getExternalContext().getRequestParameterMap();
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return getFacesContext().getExternalContext().getRequestLocale();
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
return getFacesContext().getExternalContext().getRequestContextPath();
|
||||
}
|
||||
|
||||
public String getRemoteUser() {
|
||||
return getFacesContext().getExternalContext().getRemoteUser();
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal() {
|
||||
return getFacesContext().getExternalContext().getUserPrincipal();
|
||||
}
|
||||
|
||||
public boolean isUserInRole(String role) {
|
||||
return getFacesContext().getExternalContext().isUserInRole(role);
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean checkNotModified(long lastModifiedTimestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public String getDescription(boolean includeClientInfo) {
|
||||
ExternalContext externalContext = getExternalContext();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("context=").append(externalContext.getRequestContextPath());
|
||||
if (includeClientInfo) {
|
||||
Object session = externalContext.getSession(false);
|
||||
if (session != null) {
|
||||
buffer.append(";session=").append(getSessionId());
|
||||
}
|
||||
String user = externalContext.getRemoteUser();
|
||||
if (StringUtils.hasLength(user)) {
|
||||
buffer.append(";user=").append(user);
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "FacesWebRequest: " + getDescription(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.log4j.NDC;
|
||||
|
||||
import org.springframework.ui.ModelMap;
|
||||
|
||||
/**
|
||||
* Request logging interceptor that adds a request context message to the
|
||||
* Log4J nested diagnostic context (NDC) before the request is processed,
|
||||
* removing it again after the request is processed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
* @see org.apache.log4j.NDC#push(String)
|
||||
* @see org.apache.log4j.NDC#pop()
|
||||
*/
|
||||
public class Log4jNestedDiagnosticContextInterceptor implements WebRequestInterceptor {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Logger log4jLogger = Logger.getLogger(getClass());
|
||||
|
||||
private boolean includeClientInfo = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether or not the session id and user name should be included
|
||||
* in the log message.
|
||||
*/
|
||||
public void setIncludeClientInfo(boolean includeClientInfo) {
|
||||
this.includeClientInfo = includeClientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the session id and user name should be included
|
||||
* in the log message.
|
||||
*/
|
||||
protected boolean isIncludeClientInfo() {
|
||||
return this.includeClientInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a message the Log4J NDC before the request is processed.
|
||||
*/
|
||||
public void preHandle(WebRequest request) throws Exception {
|
||||
NDC.push(getNestedDiagnosticContextMessage(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the message to be pushed onto the Log4J nested diagnostic context.
|
||||
* <p>Default is the request object's <code>getDescription</code> result.
|
||||
* @param request current HTTP request
|
||||
* @return the message to be pushed onto the Log4J NDC
|
||||
* @see WebRequest#getDescription
|
||||
* @see #isIncludeClientInfo()
|
||||
*/
|
||||
protected String getNestedDiagnosticContextMessage(WebRequest request) {
|
||||
return request.getDescription(isIncludeClientInfo());
|
||||
}
|
||||
|
||||
public void postHandle(WebRequest request, ModelMap model) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the log message from the Log4J NDC after the request is processed.
|
||||
*/
|
||||
public void afterCompletion(WebRequest request, Exception ex) throws Exception {
|
||||
NDC.pop();
|
||||
if (NDC.getDepth() == 0) {
|
||||
NDC.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
/**
|
||||
* Extension of the {@link WebRequest} interface, exposing the
|
||||
* native request and response objects in a generic fashion.
|
||||
*
|
||||
* <p>Mainly intended for framework-internal usage,
|
||||
* in particular for generic argument resolution code.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
*/
|
||||
public interface NativeWebRequest extends WebRequest {
|
||||
|
||||
/**
|
||||
* Return the underlying native request object, if available.
|
||||
* @see javax.servlet.http.HttpServletRequest
|
||||
* @see javax.portlet.ActionRequest
|
||||
* @see javax.portlet.RenderRequest
|
||||
*/
|
||||
Object getNativeRequest();
|
||||
|
||||
/**
|
||||
* Return the underlying native response object, if available.
|
||||
* @see javax.servlet.http.HttpServletResponse
|
||||
* @see javax.portlet.ActionResponse
|
||||
* @see javax.portlet.RenderResponse
|
||||
*/
|
||||
Object getNativeResponse();
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
/**
|
||||
* Abstraction for accessing attribute objects associated with a request.
|
||||
* Supports access to request-scoped attributes as well as to session-scoped
|
||||
* attributes, with the optional notion of a "global session".
|
||||
*
|
||||
* <p>Can be implemented for any kind of request/session mechanism,
|
||||
* in particular for servlet requests and portlet requests.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ServletRequestAttributes
|
||||
* @see org.springframework.web.portlet.context.PortletRequestAttributes
|
||||
*/
|
||||
public interface RequestAttributes {
|
||||
|
||||
/**
|
||||
* Constant that indicates request scope.
|
||||
*/
|
||||
int SCOPE_REQUEST = 0;
|
||||
|
||||
/**
|
||||
* Constant that indicates session scope.
|
||||
* <p>This preferably refers to a locally isolated session, if such
|
||||
* a distinction is available (for example, in a Portlet environment).
|
||||
* Else, it simply refers to the common session.
|
||||
*/
|
||||
int SCOPE_SESSION = 1;
|
||||
|
||||
/**
|
||||
* Constant that indicates global session scope.
|
||||
* <p>This explicitly refers to a globally shared session, if such
|
||||
* a distinction is available (for example, in a Portlet environment).
|
||||
* Else, it simply refers to the common session.
|
||||
*/
|
||||
int SCOPE_GLOBAL_SESSION = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Return the value for the scoped attribute of the given name, if any.
|
||||
* @param name the name of the attribute
|
||||
* @param scope the scope identifier
|
||||
* @return the current attribute value, or <code>null</code> if not found
|
||||
*/
|
||||
Object getAttribute(String name, int scope);
|
||||
|
||||
/**
|
||||
* Set the value for the scoped attribute of the given name,
|
||||
* replacing an existing value (if any).
|
||||
* @param name the name of the attribute
|
||||
* @param scope the scope identifier
|
||||
* @param value the value for the attribute
|
||||
*/
|
||||
void setAttribute(String name, Object value, int scope);
|
||||
|
||||
/**
|
||||
* Remove the scoped attribute of the given name, if it exists.
|
||||
* <p>Note that an implementation should also remove a registered destruction
|
||||
* callback for the specified attribute, if any. It does, however, <i>not</i>
|
||||
* need to <i>execute</i> a registered destruction callback in this case,
|
||||
* since the object will be destroyed by the caller (if appropriate).
|
||||
* @param name the name of the attribute
|
||||
* @param scope the scope identifier
|
||||
*/
|
||||
void removeAttribute(String name, int scope);
|
||||
|
||||
/**
|
||||
* Retrieve the names of all attributes in the scope.
|
||||
* @param scope the scope identifier
|
||||
* @return the attribute names as String array
|
||||
*/
|
||||
String[] getAttributeNames(int scope);
|
||||
|
||||
/**
|
||||
* Register a callback to be executed on destruction of the
|
||||
* specified attribute in the given scope.
|
||||
* <p>Implementations should do their best to execute the callback
|
||||
* at the appropriate time: that is, at request completion or session
|
||||
* termination, respectively. If such a callback is not supported by the
|
||||
* underlying runtime environment, the callback <i>must be ignored</i>
|
||||
* and a corresponding warning should be logged.
|
||||
* <p>Note that 'destruction' usually corresponds to destruction of the
|
||||
* entire scope, not to the individual attribute having been explicitly
|
||||
* removed by the application. If an attribute gets removed via this
|
||||
* facade's {@link #removeAttribute(String, int)} method, any registered
|
||||
* destruction callback should be disabled as well, assuming that the
|
||||
* removed object will be reused or manually destroyed.
|
||||
* @param name the name of the attribute to register the callback for
|
||||
* @param callback the destruction callback to be executed
|
||||
* @param scope the scope identifier
|
||||
*/
|
||||
void registerDestructionCallback(String name, Runnable callback, int scope);
|
||||
|
||||
/**
|
||||
* Return an id for the current underlying session.
|
||||
* @return the session id as String (never <code>null</code>
|
||||
*/
|
||||
String getSessionId();
|
||||
|
||||
/**
|
||||
* Expose the best available mutex for the underlying session:
|
||||
* that is, an object to synchronize on for the underlying session.
|
||||
* @return the session mutex to use (never <code>null</code>
|
||||
*/
|
||||
Object getSessionMutex();
|
||||
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.springframework.core.NamedInheritableThreadLocal;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Holder class to expose the web request in the form of a thread-bound
|
||||
* {@link RequestAttributes} object.
|
||||
*
|
||||
* <p>Use {@link RequestContextListener} or
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} to expose
|
||||
* the current web request. Note that
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet} and
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet} already
|
||||
* expose the current request by default.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
* @since 2.0
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public abstract class RequestContextHolder {
|
||||
|
||||
private static final boolean jsfPresent =
|
||||
ClassUtils.isPresent("javax.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
|
||||
|
||||
private static final ThreadLocal requestAttributesHolder = new NamedThreadLocal("Request attributes");
|
||||
|
||||
private static final ThreadLocal inheritableRequestAttributesHolder =
|
||||
new NamedInheritableThreadLocal("Request context");
|
||||
|
||||
|
||||
/**
|
||||
* Reset the RequestAttributes for the current thread.
|
||||
*/
|
||||
public static void resetRequestAttributes() {
|
||||
requestAttributesHolder.set(null);
|
||||
inheritableRequestAttributesHolder.set(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the given RequestAttributes to the current thread,
|
||||
* <i>not</i> exposing it as inheritable for child threads.
|
||||
* @param attributes the RequestAttributes to expose
|
||||
* @see #setRequestAttributes(RequestAttributes, boolean)
|
||||
*/
|
||||
public static void setRequestAttributes(RequestAttributes attributes) {
|
||||
setRequestAttributes(attributes, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the given RequestAttributes to the current thread.
|
||||
* @param attributes the RequestAttributes to expose
|
||||
* @param inheritable whether to expose the RequestAttributes as inheritable
|
||||
* for child threads (using an {@link java.lang.InheritableThreadLocal})
|
||||
*/
|
||||
public static void setRequestAttributes(RequestAttributes attributes, boolean inheritable) {
|
||||
if (inheritable) {
|
||||
inheritableRequestAttributesHolder.set(attributes);
|
||||
requestAttributesHolder.set(null);
|
||||
}
|
||||
else {
|
||||
requestAttributesHolder.set(attributes);
|
||||
inheritableRequestAttributesHolder.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RequestAttributes currently bound to the thread.
|
||||
* @return the RequestAttributes currently bound to the thread,
|
||||
* or <code>null</code> if none bound
|
||||
*/
|
||||
public static RequestAttributes getRequestAttributes() {
|
||||
RequestAttributes attributes = (RequestAttributes) requestAttributesHolder.get();
|
||||
if (attributes == null) {
|
||||
attributes = (RequestAttributes) inheritableRequestAttributesHolder.get();
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the RequestAttributes currently bound to the thread.
|
||||
* <p>Exposes the previously bound RequestAttributes instance, if any.
|
||||
* Falls back to the current JSF FacesContext, if any.
|
||||
* @return the RequestAttributes currently bound to the thread
|
||||
* @throws IllegalStateException if no RequestAttributes object
|
||||
* is bound to the current thread
|
||||
* @see #setRequestAttributes
|
||||
* @see ServletRequestAttributes
|
||||
* @see FacesRequestAttributes
|
||||
* @see javax.faces.context.FacesContext#getCurrentInstance()
|
||||
*/
|
||||
public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
|
||||
RequestAttributes attributes = getRequestAttributes();
|
||||
if (attributes == null) {
|
||||
if (jsfPresent) {
|
||||
attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
|
||||
}
|
||||
if (attributes == null) {
|
||||
throw new IllegalStateException("No thread-bound request found: " +
|
||||
"Are you referring to request attributes outside of an actual web request, " +
|
||||
"or processing a request outside of the originally receiving thread? " +
|
||||
"If you are actually operating within a web request and still receive this message, " +
|
||||
"your code is probably running outside of DispatcherServlet/DispatcherPortlet: " +
|
||||
"In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard-coded JSF dependency.
|
||||
*/
|
||||
private static class FacesRequestAttributesFactory {
|
||||
|
||||
public static RequestAttributes getFacesRequestAttributes() {
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
return (facesContext != null ? new FacesRequestAttributes(facesContext) : null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
import javax.servlet.ServletRequestListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* Servlet 2.4+ listener that exposes the request to the current thread,
|
||||
* through both {@link org.springframework.context.i18n.LocaleContextHolder} and
|
||||
* {@link RequestContextHolder}. To be registered as listener in <code>web.xml</code>.
|
||||
*
|
||||
* <p>Alternatively, Spring's {@link org.springframework.web.filter.RequestContextFilter}
|
||||
* and Spring's {@link org.springframework.web.servlet.DispatcherServlet} also expose
|
||||
* the same request context to the current thread. In contrast to this listener,
|
||||
* advanced options are available there (e.g. "threadContextInheritable").
|
||||
*
|
||||
* <p>This listener is mainly for use with third-party servlets, e.g. the JSF FacesServlet.
|
||||
* Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see javax.servlet.ServletRequestListener
|
||||
* @see org.springframework.context.i18n.LocaleContextHolder
|
||||
* @see org.springframework.web.context.request.RequestContextHolder
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
*/
|
||||
public class RequestContextListener implements ServletRequestListener {
|
||||
|
||||
private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
|
||||
RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
|
||||
|
||||
/** Logger available to subclasses */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
public void requestInitialized(ServletRequestEvent requestEvent) {
|
||||
if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
|
||||
}
|
||||
HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
|
||||
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
|
||||
request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
|
||||
LocaleContextHolder.setLocale(request.getLocale());
|
||||
RequestContextHolder.setRequestAttributes(attributes);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bound request context to thread: " + request);
|
||||
}
|
||||
}
|
||||
|
||||
public void requestDestroyed(ServletRequestEvent requestEvent) {
|
||||
ServletRequestAttributes attributes =
|
||||
(ServletRequestAttributes) requestEvent.getServletRequest().getAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE);
|
||||
ServletRequestAttributes threadAttributes =
|
||||
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (threadAttributes != null) {
|
||||
// We're assumably within the original request thread...
|
||||
if (attributes == null) {
|
||||
attributes = threadAttributes;
|
||||
}
|
||||
RequestContextHolder.resetRequestAttributes();
|
||||
LocaleContextHolder.resetLocaleContext();
|
||||
}
|
||||
if (attributes != null) {
|
||||
attributes.requestCompleted();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cleared thread-bound request context: " + requestEvent.getServletRequest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
/**
|
||||
* Request-backed {@link org.springframework.beans.factory.config.Scope}
|
||||
* implementation.
|
||||
*
|
||||
* <p>Relies on a thread-bound {@link RequestAttributes} instance, which
|
||||
* can be exported through {@link RequestContextListener},
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} or
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
*
|
||||
* <p>This <code>Scope</code> will also work for Portlet environments,
|
||||
* through an alternate <code>RequestAttributes</code> implementation
|
||||
* (as exposed out-of-the-box by Spring's
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
* @see RequestContextHolder#currentRequestAttributes()
|
||||
* @see RequestAttributes#SCOPE_REQUEST
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public class RequestScope extends AbstractRequestAttributesScope {
|
||||
|
||||
protected int getScope() {
|
||||
return RequestAttributes.SCOPE_REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* There is no conversation id concept for a request, so this method
|
||||
* returns <code>null</code>.
|
||||
*/
|
||||
public String getConversationId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Servlet-based implementation of the {@link RequestAttributes} interface.
|
||||
*
|
||||
* <p>Accesses objects from servlet request and HTTP session scope,
|
||||
* with no distinction between "session" and "global session".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see javax.servlet.ServletRequest#getAttribute
|
||||
* @see javax.servlet.http.HttpSession#getAttribute
|
||||
*/
|
||||
public class ServletRequestAttributes extends AbstractRequestAttributes {
|
||||
|
||||
/**
|
||||
* Constant identifying the {@link String} prefixed to the name of a
|
||||
* destruction callback when it is stored in a {@link HttpSession}.
|
||||
*/
|
||||
public static final String DESTRUCTION_CALLBACK_NAME_PREFIX =
|
||||
ServletRequestAttributes.class.getName() + ".DESTRUCTION_CALLBACK.";
|
||||
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
private volatile HttpSession session;
|
||||
|
||||
private final Map sessionAttributesToUpdate = new HashMap();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletRequestAttributes instance for the given request.
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
public ServletRequestAttributes(HttpServletRequest request) {
|
||||
Assert.notNull(request, "Request must not be null");
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exposes the native {@link HttpServletRequest} that we're wrapping.
|
||||
*/
|
||||
public final HttpServletRequest getRequest() {
|
||||
return this.request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exposes the {@link HttpSession} that we're wrapping.
|
||||
* @param allowCreate whether to allow creation of a new session if none exists yet
|
||||
*/
|
||||
protected final HttpSession getSession(boolean allowCreate) {
|
||||
if (isRequestActive()) {
|
||||
return this.request.getSession(allowCreate);
|
||||
}
|
||||
else {
|
||||
// Access through stored session reference, if any...
|
||||
if (this.session == null && allowCreate) {
|
||||
throw new IllegalStateException(
|
||||
"No session found and request already completed - cannot create new session!");
|
||||
}
|
||||
return this.session;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object getAttribute(String name, int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
if (!isRequestActive()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot ask for request attribute - request is not active anymore!");
|
||||
}
|
||||
return this.request.getAttribute(name);
|
||||
}
|
||||
else {
|
||||
HttpSession session = getSession(false);
|
||||
if (session != null) {
|
||||
try {
|
||||
Object value = session.getAttribute(name);
|
||||
if (value != null) {
|
||||
synchronized (this.sessionAttributesToUpdate) {
|
||||
this.sessionAttributesToUpdate.put(name, value);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Session invalidated - shouldn't usually happen.
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value, int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
if (!isRequestActive()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot set request attribute - request is not active anymore!");
|
||||
}
|
||||
this.request.setAttribute(name, value);
|
||||
}
|
||||
else {
|
||||
HttpSession session = getSession(true);
|
||||
synchronized (this.sessionAttributesToUpdate) {
|
||||
this.sessionAttributesToUpdate.remove(name);
|
||||
}
|
||||
session.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAttribute(String name, int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
if (isRequestActive()) {
|
||||
this.request.removeAttribute(name);
|
||||
removeRequestDestructionCallback(name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
HttpSession session = getSession(false);
|
||||
if (session != null) {
|
||||
synchronized (this.sessionAttributesToUpdate) {
|
||||
this.sessionAttributesToUpdate.remove(name);
|
||||
}
|
||||
try {
|
||||
session.removeAttribute(name);
|
||||
// Remove any registered destruction callback as well.
|
||||
session.removeAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Session invalidated - shouldn't usually happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getAttributeNames(int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
if (!isRequestActive()) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot ask for request attributes - request is not active anymore!");
|
||||
}
|
||||
return StringUtils.toStringArray(this.request.getAttributeNames());
|
||||
}
|
||||
else {
|
||||
HttpSession session = getSession(false);
|
||||
if (session != null) {
|
||||
try {
|
||||
return StringUtils.toStringArray(session.getAttributeNames());
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Session invalidated - shouldn't usually happen.
|
||||
}
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void registerDestructionCallback(String name, Runnable callback, int scope) {
|
||||
if (scope == SCOPE_REQUEST) {
|
||||
registerRequestDestructionCallback(name, callback);
|
||||
}
|
||||
else {
|
||||
registerSessionDestructionCallback(name, callback);
|
||||
}
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return getSession(true).getId();
|
||||
}
|
||||
|
||||
public Object getSessionMutex() {
|
||||
return WebUtils.getSessionMutex(getSession(true));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update all accessed session attributes through <code>session.setAttribute</code>
|
||||
* calls, explicitly indicating to the container that they might have been modified.
|
||||
*/
|
||||
protected void updateAccessedSessionAttributes() {
|
||||
// Store session reference for access after request completion.
|
||||
this.session = this.request.getSession(false);
|
||||
// Update all affected session attributes.
|
||||
synchronized (this.sessionAttributesToUpdate) {
|
||||
if (this.session != null) {
|
||||
try {
|
||||
for (Iterator it = this.sessionAttributesToUpdate.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
String name = (String) entry.getKey();
|
||||
Object newValue = entry.getValue();
|
||||
Object oldValue = this.session.getAttribute(name);
|
||||
if (oldValue == newValue) {
|
||||
this.session.setAttribute(name, newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Session invalidated - shouldn't usually happen.
|
||||
}
|
||||
}
|
||||
this.sessionAttributesToUpdate.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given callback as to be executed after session termination.
|
||||
* @param name the name of the attribute to register the callback for
|
||||
* @param callback the callback to be executed for destruction
|
||||
*/
|
||||
private void registerSessionDestructionCallback(String name, Runnable callback) {
|
||||
HttpSession session = getSession(true);
|
||||
session.setAttribute(DESTRUCTION_CALLBACK_NAME_PREFIX + name,
|
||||
new DestructionCallbackBindingListener(callback));
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return this.request.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapter that implements the Servlet 2.3 HttpSessionBindingListener
|
||||
* interface, wrapping a session destruction callback.
|
||||
*/
|
||||
private static class DestructionCallbackBindingListener implements HttpSessionBindingListener, Serializable {
|
||||
|
||||
private final Runnable destructionCallback;
|
||||
|
||||
public DestructionCallbackBindingListener(Runnable destructionCallback) {
|
||||
this.destructionCallback = destructionCallback;
|
||||
}
|
||||
|
||||
public void valueBound(HttpSessionBindingEvent event) {
|
||||
}
|
||||
|
||||
public void valueUnbound(HttpSessionBindingEvent event) {
|
||||
this.destructionCallback.run();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ServletWebRequest extends ServletRequestAttributes implements NativeWebRequest {
|
||||
|
||||
private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
|
||||
|
||||
private static final String HEADER_LAST_MODIFIED = "Last-Modified";
|
||||
|
||||
|
||||
private HttpServletResponse response;
|
||||
|
||||
private boolean notModified = false;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletWebRequest instance for the given request.
|
||||
* @param request current HTTP request
|
||||
*/
|
||||
public ServletWebRequest(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ServletWebRequest instance for the given request/response pair.
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response (for automatic last-modified handling)
|
||||
*/
|
||||
public ServletWebRequest(HttpServletRequest request, HttpServletResponse response) {
|
||||
super(request);
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exposes the native {@link HttpServletRequest} that we're wrapping (if any).
|
||||
*/
|
||||
public final HttpServletResponse getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
public Object getNativeRequest() {
|
||||
return getRequest();
|
||||
}
|
||||
|
||||
public Object getNativeResponse() {
|
||||
return getResponse();
|
||||
}
|
||||
|
||||
|
||||
public String getParameter(String paramName) {
|
||||
return getRequest().getParameter(paramName);
|
||||
}
|
||||
|
||||
public String[] getParameterValues(String paramName) {
|
||||
return getRequest().getParameterValues(paramName);
|
||||
}
|
||||
|
||||
public Map getParameterMap() {
|
||||
return getRequest().getParameterMap();
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return getRequest().getLocale();
|
||||
}
|
||||
|
||||
public String getContextPath() {
|
||||
return getRequest().getContextPath();
|
||||
}
|
||||
|
||||
public String getRemoteUser() {
|
||||
return getRequest().getRemoteUser();
|
||||
}
|
||||
|
||||
public Principal getUserPrincipal() {
|
||||
return getRequest().getUserPrincipal();
|
||||
}
|
||||
|
||||
public boolean isUserInRole(String role) {
|
||||
return getRequest().isUserInRole(role);
|
||||
}
|
||||
|
||||
public boolean isSecure() {
|
||||
return getRequest().isSecure();
|
||||
}
|
||||
|
||||
|
||||
public boolean checkNotModified(long lastModifiedTimestamp) {
|
||||
if (lastModifiedTimestamp >= 0 && !this.notModified &&
|
||||
(this.response == null || !this.response.containsHeader(HEADER_LAST_MODIFIED))) {
|
||||
long ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE);
|
||||
this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000));
|
||||
if (this.response != null) {
|
||||
if (this.notModified) {
|
||||
this.response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
}
|
||||
else {
|
||||
this.response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.notModified;
|
||||
}
|
||||
|
||||
public boolean isNotModified() {
|
||||
return this.notModified;
|
||||
}
|
||||
|
||||
|
||||
public String getDescription(boolean includeClientInfo) {
|
||||
HttpServletRequest request = getRequest();
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("uri=").append(request.getRequestURI());
|
||||
if (includeClientInfo) {
|
||||
String client = request.getRemoteAddr();
|
||||
if (StringUtils.hasLength(client)) {
|
||||
buffer.append(";client=").append(client);
|
||||
}
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
buffer.append(";session=").append(session.getId());
|
||||
}
|
||||
String user = request.getRemoteUser();
|
||||
if (StringUtils.hasLength(user)) {
|
||||
buffer.append(";user=").append(user);
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ServletWebRequest: " + getDescription(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
|
||||
/**
|
||||
* Session-backed {@link org.springframework.beans.factory.config.Scope}
|
||||
* implementation.
|
||||
*
|
||||
* <p>Relies on a thread-bound {@link RequestAttributes} instance, which
|
||||
* can be exported through {@link RequestContextListener},
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} or
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
*
|
||||
* <p>This <code>Scope</code> will also work for Portlet environments,
|
||||
* through an alternate <code>RequestAttributes</code> implementation
|
||||
* (as exposed out-of-the-box by Spring's
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
* @see RequestContextHolder#currentRequestAttributes()
|
||||
* @see RequestAttributes#SCOPE_SESSION
|
||||
* @see RequestAttributes#SCOPE_GLOBAL_SESSION
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public class SessionScope extends AbstractRequestAttributesScope {
|
||||
|
||||
private final int scope;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SessionScope, storing attributes in a locally
|
||||
* isolated session (or default session, if there is no distinction
|
||||
* between a global session and a component-specific session).
|
||||
*/
|
||||
public SessionScope() {
|
||||
this.scope = RequestAttributes.SCOPE_SESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SessionScope, specifying whether to store attributes
|
||||
* in the global session, provided that such a distinction is available.
|
||||
* <p>This distinction is important for Portlet environments, where there
|
||||
* are two notions of a session: "portlet scope" and "application scope".
|
||||
* If this flag is on, objects will be put into the "application scope" session;
|
||||
* else they will end up in the "portlet scope" session (the typical default).
|
||||
* <p>In a Servlet environment, this flag is effectively ignored.
|
||||
* @param globalSession <code>true</code> in case of the global session as target;
|
||||
* <code>false</code> in case of a component-specific session as target
|
||||
* @see org.springframework.web.portlet.context.PortletRequestAttributes
|
||||
* @see org.springframework.web.context.request.ServletRequestAttributes
|
||||
*/
|
||||
public SessionScope(boolean globalSession) {
|
||||
this.scope = (globalSession ? RequestAttributes.SCOPE_GLOBAL_SESSION : RequestAttributes.SCOPE_SESSION);
|
||||
}
|
||||
|
||||
|
||||
protected int getScope() {
|
||||
return this.scope;
|
||||
}
|
||||
|
||||
public String getConversationId() {
|
||||
return RequestContextHolder.currentRequestAttributes().getSessionId();
|
||||
}
|
||||
|
||||
public Object get(String name, ObjectFactory objectFactory) {
|
||||
Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
|
||||
synchronized (mutex) {
|
||||
return super.get(name, objectFactory);
|
||||
}
|
||||
}
|
||||
|
||||
public Object remove(String name) {
|
||||
Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
|
||||
synchronized (mutex) {
|
||||
return super.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Generic interface for a web request. Mainly intended for generic web
|
||||
* request interceptors, giving them access to general request metadata,
|
||||
* not for actual handling of the request.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see WebRequestInterceptor
|
||||
*/
|
||||
public interface WebRequest extends RequestAttributes {
|
||||
|
||||
/**
|
||||
* Return the request parameter of the given name, or <code>null</code> if none.
|
||||
* <p>Retrieves the first parameter value in case of a multi-value parameter.
|
||||
* @see javax.servlet.http.HttpServletRequest#getParameter(String)
|
||||
*/
|
||||
String getParameter(String paramName);
|
||||
|
||||
/**
|
||||
* Return the request parameter values for the given parameter name,
|
||||
* or <code>null</code> if none.
|
||||
* <p>A single-value parameter will be exposed as an array with a single element.
|
||||
* @see javax.servlet.http.HttpServletRequest#getParameterValues(String)
|
||||
*/
|
||||
String[] getParameterValues(String paramName);
|
||||
|
||||
/**
|
||||
* Return a immutable Map of the request parameters, with parameter names as map keys
|
||||
* and parameter values as map values. The map values will be of type String array.
|
||||
* <p>A single-value parameter will be exposed as an array with a single element.
|
||||
* @see javax.servlet.http.HttpServletRequest#getParameterMap()
|
||||
*/
|
||||
Map getParameterMap();
|
||||
|
||||
/**
|
||||
* Return the primary Locale for this request.
|
||||
* @see javax.servlet.http.HttpServletRequest#getLocale()
|
||||
*/
|
||||
Locale getLocale();
|
||||
|
||||
/**
|
||||
* Return the context path for this request
|
||||
* (usually the base path that the current web application is mapped to).
|
||||
* @see javax.servlet.http.HttpServletRequest#getContextPath()
|
||||
*/
|
||||
String getContextPath();
|
||||
|
||||
/**
|
||||
* Return the remote user for this request, if any.
|
||||
* @see javax.servlet.http.HttpServletRequest#getRemoteUser()
|
||||
*/
|
||||
String getRemoteUser();
|
||||
|
||||
/**
|
||||
* Return the user principal for this request, if any.
|
||||
* @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
|
||||
*/
|
||||
Principal getUserPrincipal();
|
||||
|
||||
/**
|
||||
* Determine whether the user is in the given role for this request.
|
||||
* @see javax.servlet.http.HttpServletRequest#isUserInRole(String)
|
||||
*/
|
||||
boolean isUserInRole(String role);
|
||||
|
||||
/**
|
||||
* Return whether this request has been sent over a secure transport
|
||||
* mechanism (such as SSL).
|
||||
* @see javax.servlet.http.HttpServletRequest#isSecure()
|
||||
*/
|
||||
boolean isSecure();
|
||||
|
||||
/**
|
||||
* Check whether the request qualifies as not modified given the
|
||||
* supplied last-modified timestamp (as determined by the application).
|
||||
* <p>This will also transparently set the appropriate response headers,
|
||||
* for both the modified case and the not-modified case.
|
||||
* <p>Typical usage:
|
||||
* <pre class="code">
|
||||
* public String myHandleMethod(WebRequest webRequest, Model model) {
|
||||
* long lastModified = // application-specific calculation
|
||||
* if (request.checkNotModified(lastModified)) {
|
||||
* // shortcut exit - no further processing necessary
|
||||
* return null;
|
||||
* }
|
||||
* // further request processing, actually building content
|
||||
* model.addAttribute(...);
|
||||
* return "myViewName";
|
||||
* }</pre>
|
||||
* @param lastModifiedTimestamp the last-modified timestamp that
|
||||
* the application determined for the underlying resource
|
||||
* @return whether the request qualifies as not modified,
|
||||
* allowing to abort request processing and relying on the response
|
||||
* telling the client that the content has not been modified
|
||||
*/
|
||||
boolean checkNotModified(long lastModifiedTimestamp);
|
||||
|
||||
/**
|
||||
* Get a short description of this request,
|
||||
* typically containing request URI and session id.
|
||||
* @param includeClientInfo whether to include client-specific
|
||||
* information such as session id and user name
|
||||
* @return the requested description as String
|
||||
*/
|
||||
String getDescription(boolean includeClientInfo);
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web.context.request;
|
||||
|
||||
import org.springframework.ui.ModelMap;
|
||||
|
||||
/**
|
||||
* Interface for general web request interception. Allows for being applied
|
||||
* to Servlet request as well as Portlet request environments, through
|
||||
* building on the {@link WebRequest} abstraction.
|
||||
*
|
||||
* <p>This interface assumes MVC-style request processing: A handler gets executed,
|
||||
* exposes a set of model objects, then a view gets rendered based on that model.
|
||||
* Alternatively, a handler may also process the request completely, with no
|
||||
* view to be rendered.
|
||||
*
|
||||
* <p>This interface is deliberatly minimalistic to keep the dependencies of
|
||||
* generic request interceptors as minimal as feasible.
|
||||
*
|
||||
* <p><b>NOTE:</b> While this interceptor is applied to the entire request processing
|
||||
* in a Servlet environment, it is by default only applied to the <i>render</i> phase
|
||||
* in a Portlet environment, preparing and rendering a Portlet view. To apply
|
||||
* WebRequestInterceptors to the <i>action</i> phase as well, set the HandlerMapping's
|
||||
* "applyWebRequestInterceptorsToRenderPhaseOnly" flag to "false". Alternatively,
|
||||
* consider using the Portlet-specific HandlerInterceptor mechanism for such needs.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ServletWebRequest
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.servlet.handler.AbstractHandlerMapping#setInterceptors
|
||||
* @see org.springframework.web.servlet.HandlerInterceptor
|
||||
* @see org.springframework.web.portlet.context.PortletWebRequest
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
* @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setInterceptors
|
||||
* @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setApplyWebRequestInterceptorsToRenderPhaseOnly
|
||||
* @see org.springframework.web.portlet.HandlerInterceptor
|
||||
*/
|
||||
public interface WebRequestInterceptor {
|
||||
|
||||
/**
|
||||
* Intercept the execution of a request handler <i>before</i> its invocation.
|
||||
* <p>Allows for preparing context resources (such as a Hibernate Session)
|
||||
* and expose them as request attributes or as thread-local objects.
|
||||
* @param request the current web request
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
void preHandle(WebRequest request) throws Exception;
|
||||
|
||||
/**
|
||||
* Intercept the execution of a request handler <i>after</i> its successful
|
||||
* invocation, right before view rendering (if any).
|
||||
* <p>Allows for modifying context resources after successful handler
|
||||
* execution (for example, flushing a Hibernate Session).
|
||||
* @param request the current web request
|
||||
* @param model the map of model objects that will be exposed to the view
|
||||
* (may be <code>null</code>). Can be used to analyze the exposed model
|
||||
* and/or to add further model attributes, if desired.
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
void postHandle(WebRequest request, ModelMap model) throws Exception;
|
||||
|
||||
/**
|
||||
* Callback after completion of request processing, that is, after rendering
|
||||
* the view. Will be called on any outcome of handler execution, thus allows
|
||||
* for proper resource cleanup.
|
||||
* <p>Note: Will only be called if this interceptor's <code>preHandle</code>
|
||||
* method has successfully completed!
|
||||
* @param request the current web request
|
||||
* @param ex exception thrown on handler execution, if any
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
void afterCompletion(WebRequest request, Exception ex) throws Exception;
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Support for generic request context holding, in particular for
|
||||
scoping of application objects per HTTP request or HTTP session.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.support.AbstractRefreshableConfigApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.ui.context.Theme;
|
||||
import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.ui.context.support.UiApplicationContextUtils;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.ServletConfigAware;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.context.support.AbstractRefreshableApplicationContext}
|
||||
* subclass which implements the
|
||||
* {@link org.springframework.web.context.ConfigurableWebApplicationContext}
|
||||
* interface for web environments. Provides a "configLocations" property,
|
||||
* to be populated through the ConfigurableWebApplicationContext interface
|
||||
* on web application startup.
|
||||
*
|
||||
* <p>This class is as easy to subclass as AbstractRefreshableApplicationContext:
|
||||
* All you need to implements is the {@link #loadBeanDefinitions} method;
|
||||
* see the superclass javadoc for details. Note that implementations are supposed
|
||||
* to load bean definitions from the files specified by the locations returned
|
||||
* by the {@link #getConfigLocations} method.
|
||||
*
|
||||
* <p>Interprets resource paths as servlet context resources, i.e. as paths beneath
|
||||
* the web application root. Absolute paths, e.g. for files outside the web app root,
|
||||
* can be accessed via "file:" URLs, as implemented by
|
||||
* {@link org.springframework.core.io.DefaultResourceLoader}.
|
||||
*
|
||||
* <p>In addition to the special beans detected by
|
||||
* {@link org.springframework.context.support.AbstractApplicationContext},
|
||||
* this class detects a bean of type {@link org.springframework.ui.context.ThemeSource}
|
||||
* in the context, under the special bean name "themeSource".
|
||||
*
|
||||
* <p><b>This is the web context to be subclassed for a different bean definition format.</b>
|
||||
* Such a context implementation can be specified as "contextClass" context-param
|
||||
* for {@link org.springframework.web.context.ContextLoader} or as "contextClass"
|
||||
* init-param for {@link org.springframework.web.servlet.FrameworkServlet},
|
||||
* replacing the default {@link XmlWebApplicationContext}. It will then automatically
|
||||
* receive the "contextConfigLocation" context-param or init-param, respectively.
|
||||
*
|
||||
* <p>Note that WebApplicationContext implementations are generally supposed
|
||||
* to configure themselves based on the configuration received through the
|
||||
* {@link ConfigurableWebApplicationContext} interface. In contrast, a standalone
|
||||
* application context might allow for configuration in custom startup code
|
||||
* (for example, {@link org.springframework.context.support.GenericApplicationContext}).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.3
|
||||
* @see #loadBeanDefinitions
|
||||
* @see org.springframework.web.context.ConfigurableWebApplicationContext#setConfigLocations
|
||||
* @see org.springframework.ui.context.ThemeSource
|
||||
* @see XmlWebApplicationContext
|
||||
*/
|
||||
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
|
||||
implements ConfigurableWebApplicationContext, ThemeSource {
|
||||
|
||||
/** Servlet context that this context runs in */
|
||||
private ServletContext servletContext;
|
||||
|
||||
/** Servlet config that this context runs in, if any */
|
||||
private ServletConfig servletConfig;
|
||||
|
||||
/** Namespace of this context, or <code>null</code> if root */
|
||||
private String namespace;
|
||||
|
||||
/** the ThemeSource for this ApplicationContext */
|
||||
private ThemeSource themeSource;
|
||||
|
||||
|
||||
public AbstractRefreshableWebApplicationContext() {
|
||||
setDisplayName("Root WebApplicationContext");
|
||||
}
|
||||
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
public void setServletConfig(ServletConfig servletConfig) {
|
||||
this.servletConfig = servletConfig;
|
||||
if (servletConfig != null && this.servletContext == null) {
|
||||
this.servletContext = servletConfig.getServletContext();
|
||||
}
|
||||
}
|
||||
|
||||
public ServletConfig getServletConfig() {
|
||||
return this.servletConfig;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
if (namespace != null) {
|
||||
setDisplayName("WebApplicationContext for namespace '" + namespace + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
public String[] getConfigLocations() {
|
||||
return super.getConfigLocations();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
|
||||
*/
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
|
||||
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
|
||||
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
|
||||
beanFactory.registerResolvableDependency(ServletContext.class, this.servletContext);
|
||||
beanFactory.registerResolvableDependency(ServletConfig.class, this.servletConfig);
|
||||
|
||||
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports file paths beneath the root of the ServletContext.
|
||||
* @see ServletContextResource
|
||||
*/
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ServletContextResource(this.servletContext, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports pattern matching in unexpanded WARs too.
|
||||
* @see ServletContextResourcePatternResolver
|
||||
*/
|
||||
protected ResourcePatternResolver getResourcePatternResolver() {
|
||||
return new ServletContextResourcePatternResolver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the theme capability.
|
||||
*/
|
||||
protected void onRefresh() {
|
||||
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
|
||||
}
|
||||
|
||||
public Theme getTheme(String themeName) {
|
||||
return this.themeSource.getTheme(themeName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* HttpServletRequest decorator that makes all Spring beans in a
|
||||
* given WebApplicationContext accessible as request attributes,
|
||||
* through lazy checking once an attribute gets accessed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public class ContextExposingHttpServletRequest extends HttpServletRequestWrapper {
|
||||
|
||||
private final WebApplicationContext webApplicationContext;
|
||||
|
||||
private final Set exposedContextBeanNames;
|
||||
|
||||
private Set explicitAttributes;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ContextExposingHttpServletRequest for the given request.
|
||||
* @param originalRequest the original HttpServletRequest
|
||||
* @param context the WebApplicationContext that this request runs in
|
||||
*/
|
||||
public ContextExposingHttpServletRequest(HttpServletRequest originalRequest, WebApplicationContext context) {
|
||||
this(originalRequest, context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ContextExposingHttpServletRequest for the given request.
|
||||
* @param originalRequest the original HttpServletRequest
|
||||
* @param context the WebApplicationContext that this request runs in
|
||||
* @param exposedContextBeanNames the names of beans in the context which
|
||||
* are supposed to be exposed (if this is non-null, only the beans in this
|
||||
* Set are eligible for exposure as attributes)
|
||||
*/
|
||||
public ContextExposingHttpServletRequest(
|
||||
HttpServletRequest originalRequest, WebApplicationContext context, Set exposedContextBeanNames) {
|
||||
|
||||
super(originalRequest);
|
||||
Assert.notNull(context, "WebApplicationContext must not be null");
|
||||
this.webApplicationContext = context;
|
||||
this.exposedContextBeanNames = exposedContextBeanNames;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the WebApplicationContext that this request runs in.
|
||||
*/
|
||||
public final WebApplicationContext getWebApplicationContext() {
|
||||
return this.webApplicationContext;
|
||||
}
|
||||
|
||||
|
||||
public Object getAttribute(String name) {
|
||||
if ((this.explicitAttributes == null || !this.explicitAttributes.contains(name)) &&
|
||||
(this.exposedContextBeanNames == null || this.exposedContextBeanNames.contains(name)) &&
|
||||
this.webApplicationContext.containsBean(name)) {
|
||||
return this.webApplicationContext.getBean(name);
|
||||
}
|
||||
else {
|
||||
return super.getAttribute(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value) {
|
||||
super.setAttribute(name, value);
|
||||
if (this.explicitAttributes == null) {
|
||||
this.explicitAttributes = new HashSet(8);
|
||||
}
|
||||
this.explicitAttributes.add(name);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.ui.context.Theme;
|
||||
import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.ui.context.support.UiApplicationContextUtils;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Subclass of {@link GenericApplicationContext}, suitable for web environments.
|
||||
*
|
||||
* <p>Implements the {@link WebApplicationContext} interface, but not
|
||||
* {@link org.springframework.web.context.ConfigurableWebApplicationContext},
|
||||
* as it is not intended for declarative setup in <code>web.xml</code>. Instead,
|
||||
* it is designed for programmatic setup, for example for building nested contexts.
|
||||
*
|
||||
* <p><b>If you intend to implement a WebApplicationContext that reads bean definitions
|
||||
* from configuration files, consider deriving from AbstractRefreshableWebApplicationContext,
|
||||
* reading the bean definitions in an implementation of the <code>loadBeanDefinitions</code>
|
||||
* method.</b>
|
||||
*
|
||||
* <p>Interprets resource paths as servlet context resources, i.e. as paths beneath
|
||||
* the web application root. Absolute paths, e.g. for files outside the web app root,
|
||||
* can be accessed via "file:" URLs, as implemented by AbstractApplicationContext.
|
||||
*
|
||||
* <p>In addition to the special beans detected by
|
||||
* {@link org.springframework.context.support.AbstractApplicationContext},
|
||||
* this class detects a ThemeSource bean in the context, with the name "themeSource".
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2
|
||||
*/
|
||||
public class GenericWebApplicationContext extends GenericApplicationContext
|
||||
implements WebApplicationContext, ThemeSource {
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private ThemeSource themeSource;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new GenericWebApplicationContext.
|
||||
* @see #setServletContext
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericWebApplicationContext() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new GenericWebApplicationContext with the given DefaultListableBeanFactory.
|
||||
* @param beanFactory the DefaultListableBeanFactory instance to use for this context
|
||||
* @see #setServletContext
|
||||
* @see #registerBeanDefinition
|
||||
* @see #refresh
|
||||
*/
|
||||
public GenericWebApplicationContext(DefaultListableBeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the ServletContext that this WebApplicationContext runs in.
|
||||
*/
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register ServletContextAwareProcessor.
|
||||
* @see ServletContextAwareProcessor
|
||||
*/
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
|
||||
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
|
||||
beanFactory.registerResolvableDependency(ServletContext.class, this.servletContext);
|
||||
|
||||
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports file paths beneath the root of the ServletContext.
|
||||
* @see ServletContextResource
|
||||
*/
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ServletContextResource(this.servletContext, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports pattern matching in unexpanded WARs too.
|
||||
* @see ServletContextResourcePatternResolver
|
||||
*/
|
||||
protected ResourcePatternResolver getResourcePatternResolver() {
|
||||
return new ServletContextResourcePatternResolver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the theme capability.
|
||||
*/
|
||||
protected void onRefresh() {
|
||||
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
|
||||
}
|
||||
|
||||
public Theme getTheme(String themeName) {
|
||||
return this.themeSource.getTheme(themeName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Simple HttpServlet that delegates to an {@link HttpRequestHandler} bean defined
|
||||
* in Spring's root web application context. The target bean name must match the
|
||||
* HttpRequestHandlerServlet servlet-name as defined in <code>web.xml</code>.
|
||||
*
|
||||
* <p>This can for example be used to expose a single Spring remote exporter,
|
||||
* such as {@link org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter}
|
||||
* or {@link org.springframework.remoting.caucho.HessianServiceExporter},
|
||||
* per HttpRequestHandlerServlet definition. This is a minimal alternative
|
||||
* to defining remote exporters as beans in a DispatcherServlet context
|
||||
* (with advanced mapping and interception facilities being available there).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.web.HttpRequestHandler
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
*/
|
||||
public class HttpRequestHandlerServlet extends HttpServlet {
|
||||
|
||||
private HttpRequestHandler target;
|
||||
|
||||
|
||||
public void init() throws ServletException {
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
|
||||
this.target = (HttpRequestHandler) wac.getBean(getServletName(), HttpRequestHandler.class);
|
||||
}
|
||||
|
||||
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
LocaleContextHolder.setLocale(request.getLocale());
|
||||
try {
|
||||
this.target.handleRequest(request, response);
|
||||
}
|
||||
catch (HttpRequestMethodNotSupportedException ex) {
|
||||
String[] supportedMethods = ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods();
|
||||
if (supportedMethods != null) {
|
||||
response.setHeader("Allow", StringUtils.arrayToDelimitedString(supportedMethods, ", "));
|
||||
}
|
||||
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage());
|
||||
}
|
||||
finally {
|
||||
LocaleContextHolder.resetLocaleContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.util.ResponseTimeMonitorImpl;
|
||||
|
||||
/**
|
||||
* Listener that logs the response times of web requests.
|
||||
* To be registered as bean in a WebApplicationContext.
|
||||
*
|
||||
* <p>Logs performance statistics using Commons Logging at "trace" level.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since January 21, 2001
|
||||
* @see RequestHandledEvent
|
||||
* @deprecated as of Spring 2.5, to be removed in Spring 3.0.
|
||||
* Use a custom ApplicationListener specific to your needs instead.
|
||||
*/
|
||||
public class PerformanceMonitorListener implements ApplicationListener {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected final ResponseTimeMonitorImpl responseTimeMonitor = new ResponseTimeMonitorImpl();
|
||||
|
||||
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof RequestHandledEvent) {
|
||||
RequestHandledEvent rhe = (RequestHandledEvent) event;
|
||||
this.responseTimeMonitor.recordResponseTime(rhe.getProcessingTimeMillis());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("PerformanceMonitorListener: last=[" + rhe.getProcessingTimeMillis() + "ms]; " +
|
||||
this.responseTimeMonitor + "; " + rhe.getShortDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Event raised when a request is handled within an ApplicationContext.
|
||||
*
|
||||
* <p>Supported by Spring's own FrameworkServlet (through a specific
|
||||
* ServletRequestHandledEvent subclass), but can also be raised by any
|
||||
* other web component. Used, for example, by Spring's out-of-the-box
|
||||
* PerformanceMonitorListener.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @since January 17, 2001
|
||||
* @see ServletRequestHandledEvent
|
||||
* @see PerformanceMonitorListener
|
||||
* @see org.springframework.web.servlet.FrameworkServlet
|
||||
* @see org.springframework.context.ApplicationContext#publishEvent
|
||||
*/
|
||||
public class RequestHandledEvent extends ApplicationEvent {
|
||||
|
||||
/** Session id that applied to the request, if any */
|
||||
private String sessionId;
|
||||
|
||||
/** Usually the UserPrincipal */
|
||||
private String userName;
|
||||
|
||||
/** Request processing time */
|
||||
private final long processingTimeMillis;
|
||||
|
||||
/** Cause of failure, if any */
|
||||
private Throwable failureCause;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new RequestHandledEvent with session information.
|
||||
* @param source the component that published the event
|
||||
* @param sessionId the id of the HTTP session, if any
|
||||
* @param userName the name of the user that was associated with the
|
||||
* request, if any (usually the UserPrincipal)
|
||||
* @param processingTimeMillis the processing time of the request in milliseconds
|
||||
*/
|
||||
public RequestHandledEvent(Object source, String sessionId, String userName, long processingTimeMillis) {
|
||||
super(source);
|
||||
this.sessionId = sessionId;
|
||||
this.userName = userName;
|
||||
this.processingTimeMillis = processingTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RequestHandledEvent with session information.
|
||||
* @param source the component that published the event
|
||||
* @param sessionId the id of the HTTP session, if any
|
||||
* @param userName the name of the user that was associated with the
|
||||
* request, if any (usually the UserPrincipal)
|
||||
* @param processingTimeMillis the processing time of the request in milliseconds
|
||||
* @param failureCause the cause of failure, if any
|
||||
*/
|
||||
public RequestHandledEvent(
|
||||
Object source, String sessionId, String userName, long processingTimeMillis, Throwable failureCause) {
|
||||
|
||||
this(source, sessionId, userName, processingTimeMillis);
|
||||
this.failureCause = failureCause;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the processing time of the request in milliseconds.
|
||||
*/
|
||||
public long getProcessingTimeMillis() {
|
||||
return this.processingTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the id of the HTTP session, if any.
|
||||
*/
|
||||
public String getSessionId() {
|
||||
return this.sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the user that was associated with the request
|
||||
* (usually the UserPrincipal).
|
||||
* @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
|
||||
*/
|
||||
public String getUserName() {
|
||||
return this.userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the request failed.
|
||||
*/
|
||||
public boolean wasFailure() {
|
||||
return (this.failureCause != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cause of failure, if any.
|
||||
*/
|
||||
public Throwable getFailureCause() {
|
||||
return this.failureCause;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a short description of this event, only involving
|
||||
* the most important context data.
|
||||
*/
|
||||
public String getShortDescription() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("session=[").append(this.sessionId).append("]; ");
|
||||
sb.append("user=[").append(this.userName).append("]; ");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a full description of this event, involving
|
||||
* all available context data.
|
||||
*/
|
||||
public String getDescription() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("session=[").append(this.sessionId).append("]; ");
|
||||
sb.append("user=[").append(this.userName).append("]; ");
|
||||
sb.append("time=[").append(this.processingTimeMillis).append("ms]; ");
|
||||
sb.append("status=[");
|
||||
if (!wasFailure()) {
|
||||
sb.append("OK");
|
||||
}
|
||||
else {
|
||||
sb.append("failed: ").append(this.failureCause);
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("RequestHandledEvent: " + getDescription());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* Exporter that takes Spring-defined objects and exposes them as
|
||||
* ServletContext attributes. Usually, bean references will be used
|
||||
* to export Spring-defined beans as ServletContext attributes.
|
||||
*
|
||||
* <p>Useful to make Spring-defined beans available to code that is
|
||||
* not aware of Spring at all, but rather just of the Servlet API.
|
||||
* Client code can then use plain ServletContext attribute lookups
|
||||
* to access those objects, despite them being defined in a Spring
|
||||
* application context.
|
||||
*
|
||||
* <p>Alternatively, consider using the WebApplicationContextUtils
|
||||
* class to access Spring-defined beans via the WebApplicationContext
|
||||
* interface. This makes client code aware of Spring API, of course.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.4
|
||||
* @see javax.servlet.ServletContext#getAttribute
|
||||
* @see WebApplicationContextUtils#getWebApplicationContext
|
||||
*/
|
||||
public class ServletContextAttributeExporter implements ServletContextAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private Map attributes;
|
||||
|
||||
/**
|
||||
* Set the ServletContext attributes to expose as key-value pairs.
|
||||
* Each key will be considered a ServletContext attributes key,
|
||||
* and each value will be used as corresponding attribute value.
|
||||
* <p>Usually, you will use bean references for the values,
|
||||
* to export Spring-defined beans as ServletContext attributes.
|
||||
* Of course, it is also possible to define plain values to export.
|
||||
* @param attributes Map with String keys and Object values
|
||||
*/
|
||||
public void setAttributes(Map attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
for (Iterator it = this.attributes.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
String attributeName = (String) entry.getKey();
|
||||
if (logger.isWarnEnabled()) {
|
||||
if (servletContext.getAttribute(attributeName) != null) {
|
||||
logger.warn("Overwriting existing ServletContext attribute with name '" + attributeName + "'");
|
||||
}
|
||||
}
|
||||
servletContext.setAttribute(attributeName, entry.getValue());
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Exported ServletContext attribute with name '" + attributeName + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* FactoryBean that fetches a specific, existing ServletContext attribute.
|
||||
* Exposes that ServletContext attribute when used as bean reference,
|
||||
* effectively making it available as named Spring bean instance.
|
||||
*
|
||||
* <p>Intended to link in ServletContext attributes that exist before
|
||||
* the startup of the Spring application context. Typically, such
|
||||
* attributes will have been put there by third-party web frameworks.
|
||||
* In a purely Spring-based web application, no such linking in of
|
||||
* ServletContext attrutes will be necessary.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.4
|
||||
* @see ServletContextParameterFactoryBean
|
||||
*/
|
||||
public class ServletContextAttributeFactoryBean implements FactoryBean, ServletContextAware {
|
||||
|
||||
private String attributeName;
|
||||
|
||||
private Object attribute;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the ServletContext attribute to expose.
|
||||
*/
|
||||
public void setAttributeName(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
if (this.attributeName == null) {
|
||||
throw new IllegalArgumentException("attributeName is required");
|
||||
}
|
||||
this.attribute = servletContext.getAttribute(this.attributeName);
|
||||
if (this.attribute == null) {
|
||||
throw new IllegalStateException("No ServletContext attribute '" + this.attributeName + "' found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return this.attribute;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return (this.attribute != null ? this.attribute.getClass() : null);
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.web.context.ServletConfigAware;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.config.BeanPostProcessor}
|
||||
* implementation that passes the ServletContext to beans that implement
|
||||
* the {@link ServletContextAware} interface.
|
||||
*
|
||||
* <p>Web application contexts will automatically register this with their
|
||||
* underlying bean factory. Applications do not use this directly.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 12.03.2004
|
||||
* @see org.springframework.web.context.ServletContextAware
|
||||
* @see org.springframework.web.context.support.XmlWebApplicationContext#postProcessBeanFactory
|
||||
*/
|
||||
public class ServletContextAwareProcessor implements BeanPostProcessor {
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private ServletConfig servletConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletContextAwareProcessor for the given context.
|
||||
*/
|
||||
public ServletContextAwareProcessor(ServletContext servletContext) {
|
||||
this(servletContext, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ServletContextAwareProcessor for the given config.
|
||||
*/
|
||||
public ServletContextAwareProcessor(ServletConfig servletConfig) {
|
||||
this(null, servletConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ServletContextAwareProcessor for the given context and config.
|
||||
*/
|
||||
public ServletContextAwareProcessor(ServletContext servletContext, ServletConfig servletConfig) {
|
||||
this.servletContext = servletContext;
|
||||
this.servletConfig = servletConfig;
|
||||
if (servletContext == null && servletConfig != null) {
|
||||
this.servletContext = servletConfig.getServletContext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (this.servletContext != null && bean instanceof ServletContextAware) {
|
||||
((ServletContextAware) bean).setServletContext(this.servletContext);
|
||||
}
|
||||
if (this.servletConfig != null && bean instanceof ServletConfigAware) {
|
||||
((ServletConfigAware) bean).setServletConfig(this.servletConfig);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2002-2006 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* Simple FactoryBean that exposes the ServletContext for bean references.
|
||||
* Can be used as alternative to implementing the ServletContextAware
|
||||
* callback interface. Allows for passing the ServletContext reference
|
||||
* to a constructor argument or any custom bean property.
|
||||
*
|
||||
* <p>Note that there's a special FactoryBean for exposing a specific
|
||||
* ServletContext attribute, named ServletContextAttributeFactoryBean.
|
||||
* So if all you need from the ServletContext is access to a specific
|
||||
* attribute, ServletContextAttributeFactoryBean allows you to expose
|
||||
* a constructor argument or bean property of the attribute type,
|
||||
* which is a preferable to a dependency on the full ServletContext.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.4
|
||||
* @see javax.servlet.ServletContext
|
||||
* @see org.springframework.web.context.ServletContextAware
|
||||
* @see ServletContextAttributeFactoryBean
|
||||
*/
|
||||
public class ServletContextFactoryBean implements FactoryBean, ServletContextAware {
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return (this.servletContext != null ? this.servletContext.getClass() : ServletContext.class);
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* FactoryBean that retrieves a specific ServletContext init parameter
|
||||
* (that is, a "context-param" defined in <code>web.xml</code>).
|
||||
* Exposes that ServletContext init parameter when used as bean reference,
|
||||
* effectively making it available as named Spring bean instance.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.4
|
||||
* @see ServletContextAttributeFactoryBean
|
||||
*/
|
||||
public class ServletContextParameterFactoryBean implements FactoryBean, ServletContextAware {
|
||||
|
||||
private String initParamName;
|
||||
|
||||
private String paramValue;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the ServletContext init parameter to expose.
|
||||
*/
|
||||
public void setInitParamName(String initParamName) {
|
||||
this.initParamName = initParamName;
|
||||
}
|
||||
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
if (this.initParamName == null) {
|
||||
throw new IllegalArgumentException("initParamName is required");
|
||||
}
|
||||
this.paramValue = servletContext.getInitParameter(this.initParamName);
|
||||
if (this.paramValue == null) {
|
||||
throw new IllegalStateException("No ServletContext init parameter '" + this.initParamName + "' found");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return this.paramValue;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
/**
|
||||
* Subclass of PropertyPlaceholderConfigurer that resolves placeholders as
|
||||
* ServletContext init parameters (that is, <code>web.xml</code> context-param
|
||||
* entries).
|
||||
*
|
||||
* <p>Can be combined with "locations" and/or "properties" values in addition
|
||||
* to web.xml context-params. Alternatively, can be defined without local
|
||||
* properties, to resolve all placeholders as <code>web.xml</code> context-params
|
||||
* (or JVM system properties).
|
||||
*
|
||||
* <p>If a placeholder could not be resolved against the provided local
|
||||
* properties within the application, this configurer will fall back to
|
||||
* ServletContext parameters. Can also be configured to let ServletContext
|
||||
* init parameters override local properties (contextOverride=true).
|
||||
*
|
||||
* <p>Optionally supports searching for ServletContext <i>attributes</i>: If turned
|
||||
* on, an otherwise unresolvable placeholder will matched against the corresponding
|
||||
* ServletContext attribute, using its stringified value if found. This can be
|
||||
* used to feed dynamic values into Spring's placeholder resolution.
|
||||
*
|
||||
* <p>If not running within a WebApplicationContext (or any other context that
|
||||
* is able to satisfy the ServletContextAware callback), this class will behave
|
||||
* like the default PropertyPlaceholderConfigurer. This allows for keeping
|
||||
* ServletContextPropertyPlaceholderConfigurer definitions in test suites.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.4
|
||||
* @see #setLocations
|
||||
* @see #setProperties
|
||||
* @see #setSystemPropertiesModeName
|
||||
* @see #setContextOverride
|
||||
* @see #setSearchContextAttributes
|
||||
* @see javax.servlet.ServletContext#getInitParameter(String)
|
||||
* @see javax.servlet.ServletContext#getAttribute(String)
|
||||
*/
|
||||
public class ServletContextPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer
|
||||
implements ServletContextAware {
|
||||
|
||||
private boolean contextOverride = false;
|
||||
|
||||
private boolean searchContextAttributes = false;
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether ServletContext init parameters (and optionally also ServletContext
|
||||
* attributes) should override local properties within the application.
|
||||
* Default is "false": ServletContext settings serve as fallback.
|
||||
* <p>Note that system properties will still override ServletContext settings,
|
||||
* if the system properties mode is set to "SYSTEM_PROPERTIES_MODE_OVERRIDE".
|
||||
* @see #setSearchContextAttributes
|
||||
* @see #setSystemPropertiesModeName
|
||||
* @see #SYSTEM_PROPERTIES_MODE_OVERRIDE
|
||||
*/
|
||||
public void setContextOverride(boolean contextOverride) {
|
||||
this.contextOverride = contextOverride;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to search for matching a ServletContext attribute before
|
||||
* checking a ServletContext init parameter. Default is "false": only
|
||||
* checking init parameters.
|
||||
* <p>If turned on, the configurer will look for a ServletContext attribute with
|
||||
* the same name as the placeholder, and use its stringified value if found.
|
||||
* Exposure of such ServletContext attributes can be used to dynamically override
|
||||
* init parameters defined in <code>web.xml</code>, for example in a custom
|
||||
* context listener.
|
||||
* @see javax.servlet.ServletContext#getInitParameter(String)
|
||||
* @see javax.servlet.ServletContext#getAttribute(String)
|
||||
*/
|
||||
public void setSearchContextAttributes(boolean searchContextAttributes) {
|
||||
this.searchContextAttributes = searchContextAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ServletContext to resolve placeholders against.
|
||||
* Will be auto-populated when running in a WebApplicationContext.
|
||||
* <p>If not set, this configurer will simply not resolve placeholders
|
||||
* against the ServletContext: It will effectively behave like a plain
|
||||
* PropertyPlaceholderConfigurer in such a scenario.
|
||||
*/
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
|
||||
protected String resolvePlaceholder(String placeholder, Properties props) {
|
||||
String value = null;
|
||||
if (this.contextOverride && this.servletContext != null) {
|
||||
value = resolvePlaceholder(placeholder, this.servletContext, this.searchContextAttributes);
|
||||
}
|
||||
if (value == null) {
|
||||
value = super.resolvePlaceholder(placeholder, props);
|
||||
}
|
||||
if (value == null && this.servletContext != null) {
|
||||
value = resolvePlaceholder(placeholder, this.servletContext, this.searchContextAttributes);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given placeholder using the init parameters
|
||||
* and optionally also the attributes of the given ServletContext.
|
||||
* <p>Default implementation checks ServletContext attributes before
|
||||
* init parameters. Can be overridden to customize this behavior,
|
||||
* potentially also applying specific naming patterns for parameters
|
||||
* and/or attributes (instead of using the exact placeholder name).
|
||||
* @param placeholder the placeholder to resolve
|
||||
* @param servletContext the ServletContext to check
|
||||
* @param searchContextAttributes whether to search for a matching
|
||||
* ServletContext attribute
|
||||
* @return the resolved value, of null if none
|
||||
* @see javax.servlet.ServletContext#getInitParameter(String)
|
||||
* @see javax.servlet.ServletContext#getAttribute(String)
|
||||
*/
|
||||
protected String resolvePlaceholder(
|
||||
String placeholder, ServletContext servletContext, boolean searchContextAttributes) {
|
||||
|
||||
String value = null;
|
||||
if (searchContextAttributes) {
|
||||
Object attrValue = servletContext.getAttribute(placeholder);
|
||||
if (attrValue != null) {
|
||||
value = attrValue.toString();
|
||||
}
|
||||
}
|
||||
if (value == null) {
|
||||
value = servletContext.getInitParameter(placeholder);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.core.io.AbstractResource;
|
||||
import org.springframework.core.io.ContextResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.core.io.Resource} implementation for
|
||||
* {@link javax.servlet.ServletContext} resources, interpreting
|
||||
* relative paths within the web application root directory.
|
||||
*
|
||||
* <p>Always supports stream access and URL access, but only allows
|
||||
* <code>java.io.File</code> access when the web application archive
|
||||
* is expanded.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 28.12.2003
|
||||
* @see javax.servlet.ServletContext#getResourceAsStream
|
||||
* @see javax.servlet.ServletContext#getResource
|
||||
* @see javax.servlet.ServletContext#getRealPath
|
||||
*/
|
||||
public class ServletContextResource extends AbstractResource implements ContextResource {
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
private final String path;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletContextResource.
|
||||
* <p>The Servlet spec requires that resource paths start with a slash,
|
||||
* even if many containers accept paths without leading slash too.
|
||||
* Consequently, the given path will be prepended with a slash if it
|
||||
* doesn't already start with one.
|
||||
* @param servletContext the ServletContext to load from
|
||||
* @param path the path of the resource
|
||||
*/
|
||||
public ServletContextResource(ServletContext servletContext, String path) {
|
||||
// check ServletContext
|
||||
Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext");
|
||||
this.servletContext = servletContext;
|
||||
|
||||
// check path
|
||||
Assert.notNull(path, "Path is required");
|
||||
String pathToUse = StringUtils.cleanPath(path);
|
||||
if (!pathToUse.startsWith("/")) {
|
||||
pathToUse = "/" + pathToUse;
|
||||
}
|
||||
this.path = pathToUse;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ServletContext for this resource.
|
||||
*/
|
||||
public final ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path for this resource.
|
||||
*/
|
||||
public final String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation checks <code>ServletContext.getResource</code>.
|
||||
* @see javax.servlet.ServletContext#getResource(String)
|
||||
*/
|
||||
public boolean exists() {
|
||||
try {
|
||||
URL url = this.servletContext.getResource(this.path);
|
||||
return (url != null);
|
||||
}
|
||||
catch (MalformedURLException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to <code>ServletContext.getResourceAsStream</code>,
|
||||
* but throws a FileNotFoundException if no resource found.
|
||||
* @see javax.servlet.ServletContext#getResourceAsStream(String)
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
InputStream is = this.servletContext.getResourceAsStream(this.path);
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException("Could not open " + getDescription());
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to <code>ServletContext.getResource</code>,
|
||||
* but throws a FileNotFoundException if no resource found.
|
||||
* @see javax.servlet.ServletContext#getResource(String)
|
||||
*/
|
||||
public URL getURL() throws IOException {
|
||||
URL url = this.servletContext.getResource(this.path);
|
||||
if (url == null) {
|
||||
throw new FileNotFoundException(
|
||||
getDescription() + " cannot be resolved to URL because it does not exist");
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to <code>ServletContext.getRealPath</code>,
|
||||
* but throws a FileNotFoundException if not found or not resolvable.
|
||||
* @see javax.servlet.ServletContext#getRealPath(String)
|
||||
*/
|
||||
public File getFile() throws IOException {
|
||||
String realPath = WebUtils.getRealPath(this.servletContext, this.path);
|
||||
return new File(realPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation creates a ServletContextResource, applying the given path
|
||||
* relative to the path of the underlying file of this resource descriptor.
|
||||
* @see org.springframework.util.StringUtils#applyRelativePath(String, String)
|
||||
*/
|
||||
public Resource createRelative(String relativePath) {
|
||||
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
|
||||
return new ServletContextResource(this.servletContext, pathToUse);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the name of the file that this ServletContext
|
||||
* resource refers to.
|
||||
* @see org.springframework.util.StringUtils#getFilename(String)
|
||||
*/
|
||||
public String getFilename() {
|
||||
return StringUtils.getFilename(this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns a description that includes the ServletContext
|
||||
* resource location.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return "ServletContext resource [" + this.path + "]";
|
||||
}
|
||||
|
||||
public String getPathWithinContext() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This implementation compares the underlying ServletContext resource locations.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ServletContextResource) {
|
||||
ServletContextResource otherRes = (ServletContextResource) obj;
|
||||
return (this.servletContext.equals(otherRes.servletContext) && this.path.equals(otherRes.path));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the hash code of the underlying
|
||||
* ServletContext resource location.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return this.path.hashCode();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* ResourceLoader implementation that resolves paths as ServletContext
|
||||
* resources, for use outside a WebApplicationContext (for example,
|
||||
* in a HttpServletBean or GenericFilterBean subclass).
|
||||
*
|
||||
* <p>Within a WebApplicationContext, resource paths are automatically
|
||||
* resolved as ServletContext resources by the context implementation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.0.2
|
||||
* @see #getResourceByPath
|
||||
* @see ServletContextResource
|
||||
* @see org.springframework.web.context.WebApplicationContext
|
||||
* @see org.springframework.web.servlet.HttpServletBean
|
||||
* @see org.springframework.web.filter.GenericFilterBean
|
||||
*/
|
||||
public class ServletContextResourceLoader extends DefaultResourceLoader {
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletContextResourceLoader.
|
||||
* @param servletContext the ServletContext to load resources with
|
||||
*/
|
||||
public ServletContextResourceLoader(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports file paths beneath the root of the web application.
|
||||
* @see ServletContextResource
|
||||
*/
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ServletContextResource(this.servletContext, path);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* ServletContext-aware subclass of {@link PathMatchingResourcePatternResolver},
|
||||
* able to find matching resources below the web application root directory
|
||||
* via Servlet 2.3's <code>ServletContext.getResourcePaths</code>.
|
||||
* Falls back to the superclass' file system checking for other resources.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1.2
|
||||
*/
|
||||
public class ServletContextResourcePatternResolver extends PathMatchingResourcePatternResolver {
|
||||
|
||||
/**
|
||||
* Create a new ServletContextResourcePatternResolver.
|
||||
* @param servletContext the ServletContext to load resources with
|
||||
* @see ServletContextResourceLoader#ServletContextResourceLoader(javax.servlet.ServletContext)
|
||||
*/
|
||||
public ServletContextResourcePatternResolver(ServletContext servletContext) {
|
||||
super(new ServletContextResourceLoader(servletContext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ServletContextResourcePatternResolver.
|
||||
* @param resourceLoader the ResourceLoader to load root directories and
|
||||
* actual resources with
|
||||
*/
|
||||
public ServletContextResourcePatternResolver(ResourceLoader resourceLoader) {
|
||||
super(resourceLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridden version which checks for ServletContextResource
|
||||
* and uses <code>ServletContext.getResourcePaths</code> to find
|
||||
* matching resources below the web application root directory.
|
||||
* In case of other resources, delegates to the superclass version.
|
||||
* @see #doRetrieveMatchingServletContextResources
|
||||
* @see ServletContextResource
|
||||
* @see javax.servlet.ServletContext#getResourcePaths
|
||||
*/
|
||||
protected Set doFindPathMatchingFileResources(Resource rootDirResource, String subPattern) throws IOException {
|
||||
if (rootDirResource instanceof ServletContextResource) {
|
||||
ServletContextResource scResource = (ServletContextResource) rootDirResource;
|
||||
ServletContext sc = scResource.getServletContext();
|
||||
String fullPattern = scResource.getPath() + subPattern;
|
||||
Set result = new LinkedHashSet(8);
|
||||
doRetrieveMatchingServletContextResources(sc, fullPattern, scResource.getPath(), result);
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return super.doFindPathMatchingFileResources(rootDirResource, subPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively retrieve ServletContextResources that match the given pattern,
|
||||
* adding them to the given result set.
|
||||
* @param servletContext the ServletContext to work on
|
||||
* @param fullPattern the pattern to match against,
|
||||
* with preprended root directory path
|
||||
* @param dir the current directory
|
||||
* @param result the Set of matching Resources to add to
|
||||
* @throws IOException if directory contents could not be retrieved
|
||||
* @see ServletContextResource
|
||||
* @see javax.servlet.ServletContext#getResourcePaths
|
||||
*/
|
||||
protected void doRetrieveMatchingServletContextResources(
|
||||
ServletContext servletContext, String fullPattern, String dir, Set result) throws IOException {
|
||||
|
||||
Set candidates = servletContext.getResourcePaths(dir);
|
||||
if (candidates != null) {
|
||||
boolean dirDepthNotFixed = (fullPattern.indexOf("**") != -1);
|
||||
for (Iterator it = candidates.iterator(); it.hasNext();) {
|
||||
String currPath = (String) it.next();
|
||||
if (!currPath.startsWith(dir)) {
|
||||
// Returned resource path does not start with relative directory:
|
||||
// assuming absolute path returned -> strip absolute path.
|
||||
int dirIndex = currPath.indexOf(dir);
|
||||
if (dirIndex != -1) {
|
||||
currPath = currPath.substring(dirIndex);
|
||||
}
|
||||
}
|
||||
if (currPath.endsWith("/") &&
|
||||
(dirDepthNotFixed ||
|
||||
StringUtils.countOccurrencesOf(currPath, "/") <= StringUtils.countOccurrencesOf(fullPattern, "/"))) {
|
||||
// Search subdirectories recursively: ServletContext.getResourcePaths
|
||||
// only returns entries for one directory level.
|
||||
doRetrieveMatchingServletContextResources(servletContext, fullPattern, currPath, result);
|
||||
}
|
||||
if (getPathMatcher().match(fullPattern, currPath)) {
|
||||
result.add(new ServletContextResource(servletContext, currPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
/**
|
||||
* Servlet-specific subclass of RequestHandledEvent,
|
||||
* adding servlet-specific context information.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see org.springframework.web.servlet.FrameworkServlet
|
||||
* @see org.springframework.context.ApplicationContext#publishEvent
|
||||
*/
|
||||
public class ServletRequestHandledEvent extends RequestHandledEvent {
|
||||
|
||||
/** URL that the triggered the request */
|
||||
private final String requestUrl;
|
||||
|
||||
/** IP address that the request came from */
|
||||
private final String clientAddress;
|
||||
|
||||
/** Usually GET or POST */
|
||||
private final String method;
|
||||
|
||||
/** Name of the servlet that handled the request */
|
||||
private final String servletName;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ServletRequestHandledEvent.
|
||||
* @param source the component that published the event
|
||||
* @param requestUrl the URL of the request
|
||||
* @param clientAddress the IP address that the request came from
|
||||
* @param method the HTTP method of the request (usually GET or POST)
|
||||
* @param servletName the name of the servlet that handled the request
|
||||
* @param sessionId the id of the HTTP session, if any
|
||||
* @param userName the name of the user that was associated with the
|
||||
* request, if any (usually the UserPrincipal)
|
||||
* @param processingTimeMillis the processing time of the request in milliseconds
|
||||
*/
|
||||
public ServletRequestHandledEvent(Object source, String requestUrl,
|
||||
String clientAddress, String method, String servletName,
|
||||
String sessionId, String userName, long processingTimeMillis) {
|
||||
|
||||
super(source, sessionId, userName, processingTimeMillis);
|
||||
this.requestUrl = requestUrl;
|
||||
this.clientAddress = clientAddress;
|
||||
this.method = method;
|
||||
this.servletName = servletName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ServletRequestHandledEvent.
|
||||
* @param source the component that published the event
|
||||
* @param requestUrl the URL of the request
|
||||
* @param clientAddress the IP address that the request came from
|
||||
* @param method the HTTP method of the request (usually GET or POST)
|
||||
* @param servletName the name of the servlet that handled the request
|
||||
* @param sessionId the id of the HTTP session, if any
|
||||
* @param userName the name of the user that was associated with the
|
||||
* request, if any (usually the UserPrincipal)
|
||||
* @param processingTimeMillis the processing time of the request in milliseconds
|
||||
* @param failureCause the cause of failure, if any
|
||||
*/
|
||||
public ServletRequestHandledEvent(Object source, String requestUrl,
|
||||
String clientAddress, String method, String servletName, String sessionId,
|
||||
String userName, long processingTimeMillis, Throwable failureCause) {
|
||||
|
||||
super(source, sessionId, userName, processingTimeMillis, failureCause);
|
||||
this.requestUrl = requestUrl;
|
||||
this.clientAddress = clientAddress;
|
||||
this.method = method;
|
||||
this.servletName = servletName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the URL of the request.
|
||||
*/
|
||||
public String getRequestUrl() {
|
||||
return this.requestUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the IP address that the request came from.
|
||||
*/
|
||||
public String getClientAddress() {
|
||||
return this.clientAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP method of the request (usually GET or POST).
|
||||
*/
|
||||
public String getMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the servlet that handled the request.
|
||||
*/
|
||||
public String getServletName() {
|
||||
return this.servletName;
|
||||
}
|
||||
|
||||
|
||||
public String getShortDescription() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("url=[").append(getRequestUrl()).append("]; ");
|
||||
sb.append("client=[").append(getClientAddress()).append("]; ");
|
||||
sb.append(super.getShortDescription());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("url=[").append(getRequestUrl()).append("]; ");
|
||||
sb.append("client=[").append(getClientAddress()).append("]; ");
|
||||
sb.append("method=[").append(getMethod()).append("]; ");
|
||||
sb.append("servlet=[").append(getServletName()).append("]; ");
|
||||
sb.append(super.getDescription());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ServletRequestHandledEvent: " + getDescription();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Convenient base class for self-autowiring classes that gets constructed
|
||||
* within a Spring-based web application. Resolves <code>@Autowired</code>
|
||||
* annotations in the endpoint class against beans in the current Spring
|
||||
* root web application context (as determined by the current thread's
|
||||
* context ClassLoader, which needs to be the web application's ClassLoader).
|
||||
* Can alternatively be used as a delegate instead of as a base class.
|
||||
*
|
||||
* <p>A typical usage of this base class is a JAX-WS endpoint class:
|
||||
* Such a Spring-based JAX-WS endpoint implementation will follow the
|
||||
* standard JAX-WS contract for endpoint classes but will be 'thin'
|
||||
* in that it delegates the actual work to one or more Spring-managed
|
||||
* service beans - typically obtained using <code>@Autowired</code>.
|
||||
* The lifecycle of such an endpoint instance will be managed by the
|
||||
* JAX-WS runtime, hence the need for this base class to provide
|
||||
* <code>@Autowired</code> processing based on the current Spring context.
|
||||
*
|
||||
* <p><b>NOTE:</b> If there is an explicit way to access the ServletContext,
|
||||
* prefer such a way over using this class. The {@link WebApplicationContextUtils}
|
||||
* class allows for easy access to the Spring root web application context
|
||||
* based on the ServletContext.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.1
|
||||
* @see WebApplicationObjectSupport
|
||||
*/
|
||||
public abstract class SpringBeanAutowiringSupport {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SpringBeanAutowiringSupport.class);
|
||||
|
||||
|
||||
/**
|
||||
* This constructor performs injection on this instance,
|
||||
* based on the current web application context.
|
||||
* <p>Intended for use as a base class.
|
||||
* @see #processInjectionBasedOnCurrentContext
|
||||
*/
|
||||
public SpringBeanAutowiringSupport() {
|
||||
processInjectionBasedOnCurrentContext(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process <code>@Autowired</code> injection for the given target object,
|
||||
* based on the current web application context.
|
||||
* <p>Intended for use as a delegate.
|
||||
* @param target the target object to process
|
||||
* @see org.springframework.web.context.ContextLoader#getCurrentWebApplicationContext()
|
||||
*/
|
||||
public static void processInjectionBasedOnCurrentContext(Object target) {
|
||||
Assert.notNull(target, "Target object must not be null");
|
||||
WebApplicationContext cc = ContextLoader.getCurrentWebApplicationContext();
|
||||
if (cc != null) {
|
||||
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||
bpp.setBeanFactory(cc.getAutowireCapableBeanFactory());
|
||||
bpp.processInjection(target);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Current WebApplicationContext is not available for processing of " +
|
||||
ClassUtils.getShortName(target.getClass()) + ": " +
|
||||
"Make sure this class gets constructed in a Spring web application. Proceeding without injection.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.ui.context.Theme;
|
||||
import org.springframework.ui.context.ThemeSource;
|
||||
import org.springframework.ui.context.support.UiApplicationContextUtils;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.ServletConfigAware;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.context.request.RequestScope;
|
||||
import org.springframework.web.context.request.SessionScope;
|
||||
|
||||
/**
|
||||
* Static {@link org.springframework.web.context.WebApplicationContext}
|
||||
* implementation for testing. Not intended for use in production applications.
|
||||
*
|
||||
* <p>Implements the {@link org.springframework.web.context.ConfigurableWebApplicationContext}
|
||||
* interface to allow for direct replacement of an {@link XmlWebApplicationContext},
|
||||
* despite not actually supporting external configuration files.
|
||||
*
|
||||
* <p>Interprets resource paths as servlet context resources, i.e. as paths beneath
|
||||
* the web application root. Absolute paths, e.g. for files outside the web app root,
|
||||
* can be accessed via "file:" URLs, as implemented by
|
||||
* {@link org.springframework.core.io.DefaultResourceLoader}.
|
||||
*
|
||||
* <p>In addition to the special beans detected by
|
||||
* {@link org.springframework.context.support.AbstractApplicationContext},
|
||||
* this class detects a bean of type {@link org.springframework.ui.context.ThemeSource}
|
||||
* in the context, under the special bean name "themeSource".
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.ui.context.ThemeSource
|
||||
*/
|
||||
public class StaticWebApplicationContext extends StaticApplicationContext
|
||||
implements ConfigurableWebApplicationContext, ThemeSource {
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
private ServletConfig servletConfig;
|
||||
|
||||
private String namespace;
|
||||
|
||||
private ThemeSource themeSource;
|
||||
|
||||
|
||||
public StaticWebApplicationContext() {
|
||||
setDisplayName("Root WebApplicationContext");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the ServletContext that this WebApplicationContext runs in.
|
||||
*/
|
||||
public void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
public void setServletConfig(ServletConfig servletConfig) {
|
||||
this.servletConfig = servletConfig;
|
||||
if (servletConfig != null && this.servletContext == null) {
|
||||
this.servletContext = servletConfig.getServletContext();
|
||||
}
|
||||
}
|
||||
|
||||
public ServletConfig getServletConfig() {
|
||||
return this.servletConfig;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
if (namespace != null) {
|
||||
setDisplayName("WebApplicationContext for namespace '" + namespace + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link StaticWebApplicationContext} class does not support this method.
|
||||
* @throws UnsupportedOperationException <b>always</b>
|
||||
*/
|
||||
public void setConfigLocation(String configLocation) {
|
||||
if (configLocation != null) {
|
||||
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link StaticWebApplicationContext} class does not support this method.
|
||||
* @throws UnsupportedOperationException <b>always</b>
|
||||
*/
|
||||
public void setConfigLocations(String[] configLocations) {
|
||||
if (configLocations != null) {
|
||||
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getConfigLocations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
|
||||
*/
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory.registerScope(SCOPE_REQUEST, new RequestScope());
|
||||
beanFactory.registerScope(SCOPE_SESSION, new SessionScope(false));
|
||||
beanFactory.registerScope(SCOPE_GLOBAL_SESSION, new SessionScope(true));
|
||||
|
||||
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
|
||||
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
|
||||
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports file paths beneath the root of the ServletContext.
|
||||
* @see ServletContextResource
|
||||
*/
|
||||
protected Resource getResourceByPath(String path) {
|
||||
return new ServletContextResource(this.servletContext, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports pattern matching in unexpanded WARs too.
|
||||
* @see ServletContextResourcePatternResolver
|
||||
*/
|
||||
protected ResourcePatternResolver getResourcePatternResolver() {
|
||||
return new ServletContextResourcePatternResolver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the theme capability.
|
||||
*/
|
||||
protected void onRefresh() {
|
||||
this.themeSource = UiApplicationContextUtils.initThemeSource(this);
|
||||
}
|
||||
|
||||
public Theme getTheme(String themeName) {
|
||||
return this.themeSource.getTheme(themeName);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.RequestScope;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.context.request.SessionScope;
|
||||
|
||||
/**
|
||||
* Convenience methods for retrieving the root
|
||||
* {@link org.springframework.web.context.WebApplicationContext} for a given
|
||||
* <code>ServletContext</code>. This is e.g. useful for accessing a Spring
|
||||
* context from within custom web views or Struts actions.
|
||||
*
|
||||
* <p>Note that there are more convenient ways of accessing the root context for
|
||||
* many web frameworks, either part of Spring or available as external library.
|
||||
* This helper class is just the most generic way to access the root context.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @see org.springframework.web.context.ContextLoader
|
||||
* @see org.springframework.web.servlet.FrameworkServlet
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.struts.ActionSupport
|
||||
* @see org.springframework.web.struts.DelegatingActionProxy
|
||||
* @see org.springframework.web.jsf.FacesContextUtils
|
||||
* @see org.springframework.web.jsf.DelegatingVariableResolver
|
||||
*/
|
||||
public abstract class WebApplicationContextUtils {
|
||||
|
||||
/**
|
||||
* Find the root WebApplicationContext for this web application, which is
|
||||
* typically loaded via {@link org.springframework.web.context.ContextLoaderListener} or
|
||||
* {@link org.springframework.web.context.ContextLoaderServlet}.
|
||||
* <p>Will rethrow an exception that happened on root context startup,
|
||||
* to differentiate between a failed context startup and no context at all.
|
||||
* @param sc ServletContext to find the web application context for
|
||||
* @return the root WebApplicationContext for this web app
|
||||
* @throws IllegalStateException if the root WebApplicationContext could not be found
|
||||
* @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
|
||||
*/
|
||||
public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
|
||||
throws IllegalStateException {
|
||||
|
||||
WebApplicationContext wac = getWebApplicationContext(sc);
|
||||
if (wac == null) {
|
||||
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
|
||||
}
|
||||
return wac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the root WebApplicationContext for this web application, which is
|
||||
* typically loaded via {@link org.springframework.web.context.ContextLoaderListener} or
|
||||
* {@link org.springframework.web.context.ContextLoaderServlet}.
|
||||
* <p>Will rethrow an exception that happened on root context startup,
|
||||
* to differentiate between a failed context startup and no context at all.
|
||||
* @param sc ServletContext to find the web application context for
|
||||
* @return the root WebApplicationContext for this web app, or <code>null</code> if none
|
||||
* @see org.springframework.web.context.WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
|
||||
*/
|
||||
public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
|
||||
return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a custom WebApplicationContext for this web application.
|
||||
* @param sc ServletContext to find the web application context for
|
||||
* @param attrName the name of the ServletContext attribute to look for
|
||||
* @return the desired WebApplicationContext for this web app, or <code>null</code> if none
|
||||
*/
|
||||
public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
|
||||
Assert.notNull(sc, "ServletContext must not be null");
|
||||
Object attr = sc.getAttribute(attrName);
|
||||
if (attr == null) {
|
||||
return null;
|
||||
}
|
||||
if (attr instanceof RuntimeException) {
|
||||
throw (RuntimeException) attr;
|
||||
}
|
||||
if (attr instanceof Error) {
|
||||
throw (Error) attr;
|
||||
}
|
||||
if (attr instanceof Exception) {
|
||||
IllegalStateException ex = new IllegalStateException();
|
||||
ex.initCause((Exception) attr);
|
||||
throw ex;
|
||||
}
|
||||
if (!(attr instanceof WebApplicationContext)) {
|
||||
throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
|
||||
}
|
||||
return (WebApplicationContext) attr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register web-specific scopes with the given BeanFactory,
|
||||
* as used by the WebApplicationContext.
|
||||
* @param beanFactory the BeanFactory to configure
|
||||
*/
|
||||
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory) {
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
|
||||
|
||||
beanFactory.registerResolvableDependency(ServletRequest.class, new ObjectFactory() {
|
||||
public Object getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest();
|
||||
}
|
||||
});
|
||||
beanFactory.registerResolvableDependency(HttpSession.class, new ObjectFactory() {
|
||||
public Object getObject() {
|
||||
RequestAttributes requestAttr = RequestContextHolder.currentRequestAttributes();
|
||||
if (!(requestAttr instanceof ServletRequestAttributes)) {
|
||||
throw new IllegalStateException("Current request is not a servlet request");
|
||||
}
|
||||
return ((ServletRequestAttributes) requestAttr).getRequest().getSession();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ApplicationObjectSupport;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
/**
|
||||
* Convenient superclass for application objects running in a WebApplicationContext.
|
||||
* Provides <code>getWebApplicationContext()</code>, <code>getServletContext()</code>,
|
||||
* and <code>getTempDir()</code> methods.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 28.08.2003
|
||||
* @see SpringBeanAutowiringSupport
|
||||
*/
|
||||
public abstract class WebApplicationObjectSupport extends ApplicationObjectSupport
|
||||
implements ServletContextAware {
|
||||
|
||||
private ServletContext servletContext;
|
||||
|
||||
|
||||
public final void setServletContext(ServletContext servletContext) {
|
||||
this.servletContext = servletContext;
|
||||
if (servletContext != null) {
|
||||
initServletContext(servletContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the base class behavior to enforce running in an ApplicationContext.
|
||||
* All accessors will throw IllegalStateException if not running in a context.
|
||||
* @see #getApplicationContext()
|
||||
* @see #getMessageSourceAccessor()
|
||||
* @see #getWebApplicationContext()
|
||||
* @see #getServletContext()
|
||||
* @see #getTempDir()
|
||||
*/
|
||||
protected boolean isContextRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
|
||||
* given ApplicationContext is a {@link WebApplicationContext}.
|
||||
*/
|
||||
protected void initApplicationContext(ApplicationContext context) {
|
||||
super.initApplicationContext(context);
|
||||
if (context instanceof WebApplicationContext) {
|
||||
ServletContext servletContext = ((WebApplicationContext) context).getServletContext();
|
||||
if (servletContext != null) {
|
||||
initServletContext(servletContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this for custom initialization based
|
||||
* on the ServletContext that this application object runs in.
|
||||
* <p>The default implementation is empty. Called by
|
||||
* {@link #initApplicationContext(org.springframework.context.ApplicationContext)}
|
||||
* as well as {@link #setServletContext(javax.servlet.ServletContext)}.
|
||||
* @param servletContext the ServletContext that this application object runs in
|
||||
* (never <code>null</code>)
|
||||
*/
|
||||
protected void initServletContext(ServletContext servletContext) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current application context as WebApplicationContext.
|
||||
* <p><b>NOTE:</b> Only use this if you actually need to access
|
||||
* WebApplicationContext-specific functionality. Preferably use
|
||||
* <code>getApplicationContext()</code> or <code>getServletContext()</code>
|
||||
* else, to be able to run in non-WebApplicationContext environments as well.
|
||||
* @throws IllegalStateException if not running in a WebApplicationContext
|
||||
* @see #getApplicationContext()
|
||||
*/
|
||||
protected final WebApplicationContext getWebApplicationContext() throws IllegalStateException {
|
||||
ApplicationContext ctx = getApplicationContext();
|
||||
if (ctx instanceof WebApplicationContext) {
|
||||
return (WebApplicationContext) getApplicationContext();
|
||||
}
|
||||
else if (isContextRequired()) {
|
||||
throw new IllegalStateException("WebApplicationObjectSupport instance [" + this +
|
||||
"] does not run in a WebApplicationContext but in: " + ctx);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current ServletContext.
|
||||
* @throws IllegalStateException if not running within a ServletContext
|
||||
*/
|
||||
protected final ServletContext getServletContext() throws IllegalStateException {
|
||||
if (this.servletContext != null) {
|
||||
return this.servletContext;
|
||||
}
|
||||
ServletContext servletContext = getWebApplicationContext().getServletContext();
|
||||
if (servletContext == null && isContextRequired()) {
|
||||
throw new IllegalStateException("WebApplicationObjectSupport instance [" + this +
|
||||
"] does not run within a ServletContext. Make sure the object is fully configured!");
|
||||
}
|
||||
return servletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the temporary directory for the current web application,
|
||||
* as provided by the servlet container.
|
||||
* @return the File representing the temporary directory
|
||||
* @throws IllegalStateException if not running within a ServletContext
|
||||
* @see org.springframework.web.util.WebUtils#getTempDir(javax.servlet.ServletContext)
|
||||
*/
|
||||
protected final File getTempDir() throws IllegalStateException {
|
||||
return WebUtils.getTempDir(getServletContext());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.context.support;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.ResourceEntityResolver;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.web.context.WebApplicationContext} implementation
|
||||
* which takes its configuration from XML documents, understood by an
|
||||
* {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}.
|
||||
* This is essentially the equivalent of
|
||||
* {@link org.springframework.context.support.AbstractXmlApplicationContext}
|
||||
* for a web environment.
|
||||
*
|
||||
* <p>By default, the configuration will be taken from "/WEB-INF/applicationContext.xml"
|
||||
* for the root context, and "/WEB-INF/test-servlet.xml" for a context with the namespace
|
||||
* "test-servlet" (like for a DispatcherServlet instance with the servlet-name "test").
|
||||
*
|
||||
* <p>The config location defaults can be overridden via the "contextConfigLocation"
|
||||
* context-param of {@link org.springframework.web.context.ContextLoader} and servlet
|
||||
* init-param of {@link org.springframework.web.servlet.FrameworkServlet}. Config locations
|
||||
* can either denote concrete files like "/WEB-INF/context.xml" or Ant-style patterns
|
||||
* like "/WEB-INF/*-context.xml" (see {@link org.springframework.util.PathMatcher}
|
||||
* javadoc for pattern details).
|
||||
*
|
||||
* <p>Note: In case of multiple config locations, later bean definitions will
|
||||
* override ones defined in earlier loaded files. This can be leveraged to
|
||||
* deliberately override certain bean definitions via an extra XML file.
|
||||
*
|
||||
* <p><b>For a WebApplicationContext that reads in a different bean definition format,
|
||||
* create an analogous subclass of {@link AbstractRefreshableWebApplicationContext}.</b>
|
||||
* Such a context implementation can be specified as "contextClass" context-param
|
||||
* for ContextLoader or "contextClass" init-param for FrameworkServlet.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @see #setNamespace
|
||||
* @see #setConfigLocations
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
* @see org.springframework.web.context.ContextLoader#initWebApplicationContext
|
||||
* @see org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
|
||||
*/
|
||||
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
|
||||
|
||||
/** Default config location for the root context */
|
||||
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
|
||||
|
||||
/** Default prefix for building a config location for a namespace */
|
||||
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
|
||||
|
||||
/** Default suffix for building a config location for a namespace */
|
||||
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
|
||||
|
||||
|
||||
/**
|
||||
* Loads the bean definitions via an XmlBeanDefinitionReader.
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
|
||||
* @see #initBeanDefinitionReader
|
||||
* @see #loadBeanDefinitions
|
||||
*/
|
||||
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
|
||||
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
|
||||
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
|
||||
|
||||
// Configure the bean definition reader with this context's
|
||||
// resource loading environment.
|
||||
beanDefinitionReader.setResourceLoader(this);
|
||||
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
|
||||
|
||||
// Allow a subclass to provide custom initialization of the reader,
|
||||
// then proceed with actually loading the bean definitions.
|
||||
initBeanDefinitionReader(beanDefinitionReader);
|
||||
loadBeanDefinitions(beanDefinitionReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the bean definition reader used for loading the bean
|
||||
* definitions of this context. Default implementation is empty.
|
||||
* <p>Can be overridden in subclasses, e.g. for turning off XML validation
|
||||
* or using a different XmlBeanDefinitionParser implementation.
|
||||
* @param beanDefinitionReader the bean definition reader used by this context
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode
|
||||
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass
|
||||
*/
|
||||
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the bean definitions with the given XmlBeanDefinitionReader.
|
||||
* <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method;
|
||||
* therefore this method is just supposed to load and/or register bean definitions.
|
||||
* <p>Delegates to a ResourcePatternResolver for resolving location patterns
|
||||
* into Resource instances.
|
||||
* @throws org.springframework.beans.BeansException in case of bean registration errors
|
||||
* @throws java.io.IOException if the required XML document isn't found
|
||||
* @see #refreshBeanFactory
|
||||
* @see #getConfigLocations
|
||||
* @see #getResources
|
||||
* @see #getResourcePatternResolver
|
||||
*/
|
||||
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
|
||||
String[] configLocations = getConfigLocations();
|
||||
if (configLocations != null) {
|
||||
for (int i = 0; i < configLocations.length; i++) {
|
||||
reader.loadBeanDefinitions(configLocations[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default location for the root context is "/WEB-INF/applicationContext.xml",
|
||||
* and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
|
||||
* (like for a DispatcherServlet instance with the servlet-name "test").
|
||||
*/
|
||||
protected String[] getDefaultConfigLocations() {
|
||||
if (getNamespace() != null) {
|
||||
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
|
||||
}
|
||||
else {
|
||||
return new String[] {DEFAULT_CONFIG_LOCATION};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<html>
|
||||
<body>
|
||||
|
||||
Classes supporting the <code>org.springframework.web.context</code> package,
|
||||
such as WebApplicationContext implementations and various utility classes.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Base class for <code>Filter</code>s that perform logging operations before and after a
|
||||
* request is processed.
|
||||
*
|
||||
* <p>Subclasses should override the <code>beforeRequest(HttpServletRequest, String)</code>
|
||||
* and <code>afterRequest(HttpServletRequest, String)</code> methods to perform the actual
|
||||
* logging around the request.
|
||||
*
|
||||
* <p>Subclasses are passed the message to write to the log in the <code>beforeRequest</code>
|
||||
* and <code>afterRequest</code> methods. By default, only the URI of the request is logged.
|
||||
* However, setting the <code>includeQueryString</code> property to <code>true</code> will
|
||||
* cause the query string of the request to be included also.
|
||||
*
|
||||
* <p>Prefixes and suffixes for the before and after messages can be configured
|
||||
* using the <code>beforeMessagePrefix</code>, <code>afterMessagePrefix</code>,
|
||||
* <code>beforeMessageSuffix</code> and <code>afterMessageSuffix</code> properties,
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.2.5
|
||||
* @see #beforeRequest
|
||||
* @see #afterRequest
|
||||
*/
|
||||
public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final String DEFAULT_BEFORE_MESSAGE_PREFIX = "Before request [";
|
||||
|
||||
public static final String DEFAULT_BEFORE_MESSAGE_SUFFIX = "]";
|
||||
|
||||
public static final String DEFAULT_AFTER_MESSAGE_PREFIX = "After request [";
|
||||
|
||||
public static final String DEFAULT_AFTER_MESSAGE_SUFFIX = "]";
|
||||
|
||||
|
||||
private boolean includeQueryString = false;
|
||||
|
||||
private boolean includeClientInfo = false;
|
||||
|
||||
private String beforeMessagePrefix = DEFAULT_BEFORE_MESSAGE_PREFIX;
|
||||
|
||||
private String beforeMessageSuffix = DEFAULT_BEFORE_MESSAGE_SUFFIX;
|
||||
|
||||
private String afterMessagePrefix = DEFAULT_AFTER_MESSAGE_PREFIX;
|
||||
|
||||
private String afterMessageSuffix = DEFAULT_AFTER_MESSAGE_SUFFIX;
|
||||
|
||||
|
||||
/**
|
||||
* Set whether or not the query string should be included in the log message.
|
||||
* <p>Should be configured using an <code><init-param></code> for parameter
|
||||
* name "includeQueryString" in the filter definition in <code>web.xml</code>.
|
||||
*/
|
||||
public void setIncludeQueryString(boolean includeQueryString) {
|
||||
this.includeQueryString = includeQueryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the query string should be included in the log message.
|
||||
*/
|
||||
protected boolean isIncludeQueryString() {
|
||||
return this.includeQueryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the client address and session id should be included
|
||||
* in the log message.
|
||||
* <p>Should be configured using an <code><init-param></code> for parameter
|
||||
* name "includeClientInfo" in the filter definition in <code>web.xml</code>.
|
||||
*/
|
||||
public void setIncludeClientInfo(boolean includeClientInfo) {
|
||||
this.includeClientInfo = includeClientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the client address and session id should be included
|
||||
* in the log message.
|
||||
*/
|
||||
protected boolean isIncludeClientInfo() {
|
||||
return this.includeClientInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value that should be prepended to the log message written
|
||||
* <i>before</i> a request is processed.
|
||||
*/
|
||||
public void setBeforeMessagePrefix(String beforeMessagePrefix) {
|
||||
this.beforeMessagePrefix = beforeMessagePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value that should be apppended to the log message written
|
||||
* <i>before</i> a request is processed.
|
||||
*/
|
||||
public void setBeforeMessageSuffix(String beforeMessageSuffix) {
|
||||
this.beforeMessageSuffix = beforeMessageSuffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value that should be prepended to the log message written
|
||||
* <i>after</i> a request is processed.
|
||||
*/
|
||||
public void setAfterMessagePrefix(String afterMessagePrefix) {
|
||||
this.afterMessagePrefix = afterMessagePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value that should be appended to the log message written
|
||||
* <i>after</i> a request is processed.
|
||||
*/
|
||||
public void setAfterMessageSuffix(String afterMessageSuffix) {
|
||||
this.afterMessageSuffix = afterMessageSuffix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forwards the request to the next filter in the chain and delegates
|
||||
* down to the subclasses to perform the actual request logging both
|
||||
* before and after the request is processed.
|
||||
* @see #beforeRequest
|
||||
* @see #afterRequest
|
||||
*/
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
beforeRequest(request, getBeforeMessage(request));
|
||||
try {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
finally {
|
||||
afterRequest(request, getAfterMessage(request));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the message to write to the log before the request.
|
||||
* @see #createMessage
|
||||
*/
|
||||
private String getBeforeMessage(HttpServletRequest request) {
|
||||
return createMessage(request, this.beforeMessagePrefix, this.beforeMessageSuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message to write to the log after the request.
|
||||
* @see #createMessage
|
||||
*/
|
||||
private String getAfterMessage(HttpServletRequest request) {
|
||||
return createMessage(request, this.afterMessagePrefix, this.afterMessageSuffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a log message for the given request, prefix and suffix.
|
||||
* <p>If <code>includeQueryString</code> is <code>true</code> then
|
||||
* the inner part of the log message will take the form
|
||||
* <code>request_uri?query_string</code> otherwise the message will
|
||||
* simply be of the form <code>request_uri</code>.
|
||||
* <p>The final message is composed of the inner part as described
|
||||
* and the supplied prefix and suffix.
|
||||
*/
|
||||
protected String createMessage(HttpServletRequest request, String prefix, String suffix) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append(prefix);
|
||||
buffer.append("uri=").append(request.getRequestURI());
|
||||
if (isIncludeQueryString()) {
|
||||
buffer.append('?').append(request.getQueryString());
|
||||
}
|
||||
if (isIncludeClientInfo()) {
|
||||
String client = request.getRemoteAddr();
|
||||
if (StringUtils.hasLength(client)) {
|
||||
buffer.append(";client=").append(client);
|
||||
}
|
||||
HttpSession session = request.getSession(false);
|
||||
if (session != null) {
|
||||
buffer.append(";session=").append(session.getId());
|
||||
}
|
||||
String user = request.getRemoteUser();
|
||||
if (user != null) {
|
||||
buffer.append(";user=").append(user);
|
||||
}
|
||||
}
|
||||
buffer.append(suffix);
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Concrete subclasses should implement this method to write a log message
|
||||
* <i>before</i> the request is processed.
|
||||
* @param request current HTTP request
|
||||
* @param message the message to log
|
||||
*/
|
||||
protected abstract void beforeRequest(HttpServletRequest request, String message);
|
||||
|
||||
/**
|
||||
* Concrete subclasses should implement this method to write a log message
|
||||
* <i>after</i> the request is processed.
|
||||
* @param request current HTTP request
|
||||
* @param message the message to log
|
||||
*/
|
||||
protected abstract void afterRequest(HttpServletRequest request, String message);
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* http://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.web.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Servlet 2.3/2.4 Filter that allows one to specify a character encoding for
|
||||
* requests. This is useful because current browsers typically do not set a
|
||||
* character encoding even if specified in the HTML page or form.
|
||||
*
|
||||
* <p>This filter can either apply its encoding if the request does not
|
||||
* already specify an encoding, or enforce this filter's encoding in any case
|
||||
* ("forceEncoding"="true"). In the latter case, the encoding will also be
|
||||
* applied as default response encoding on Servlet 2.4+ containers (although
|
||||
* this will usually be overridden by a full content type set in the view).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 15.03.2004
|
||||
* @see #setEncoding
|
||||
* @see #setForceEncoding
|
||||
* @see javax.servlet.http.HttpServletRequest#setCharacterEncoding
|
||||
* @see javax.servlet.http.HttpServletResponse#setCharacterEncoding
|
||||
*/
|
||||
public class CharacterEncodingFilter extends OncePerRequestFilter {
|
||||
|
||||
// Determine whether the Servlet 2.4 HttpServletResponse.setCharacterEncoding(String)
|
||||
// method is available, for use in the "doFilterInternal" implementation.
|
||||
private final static boolean responseSetCharacterEncodingAvailable = ClassUtils.hasMethod(
|
||||
HttpServletResponse.class, "setCharacterEncoding", new Class[] {String.class});
|
||||
|
||||
|
||||
private String encoding;
|
||||
|
||||
private boolean forceEncoding = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the encoding to use for requests. This encoding will be passed into a
|
||||
* {@link javax.servlet.http.HttpServletRequest#setCharacterEncoding} call.
|
||||
* <p>Whether this encoding will override existing request encodings
|
||||
* (and whether it will be applied as default response encoding as well)
|
||||
* depends on the {@link #setForceEncoding "forceEncoding"} flag.
|
||||
*/
|
||||
public void setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the configured {@link #setEncoding encoding} of this filter
|
||||
* is supposed to override existing request and response encodings.
|
||||
* <p>Default is "false", i.e. do not modify the encoding if
|
||||
* {@link javax.servlet.http.HttpServletRequest#getCharacterEncoding()}
|
||||
* returns a non-null value. Switch this to "true" to enforce the specified
|
||||
* encoding in any case, applying it as default response encoding as well.
|
||||
* <p>Note that the response encoding will only be set on Servlet 2.4+
|
||||
* containers, since Servlet 2.3 did not provide a facility for setting
|
||||
* a default response encoding.
|
||||
*/
|
||||
public void setForceEncoding(boolean forceEncoding) {
|
||||
this.forceEncoding = forceEncoding;
|
||||
}
|
||||
|
||||
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
|
||||
request.setCharacterEncoding(this.encoding);
|
||||
if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
|
||||
response.setCharacterEncoding(this.encoding);
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2002-2005 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
|
||||
*
|
||||
* http://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.web.filter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Simple request logging filter that writes the request URI
|
||||
* (and optionally the query string) to the Commons Log.
|
||||
*
|
||||
* @author Rob Harrop
|
||||
* @since 1.2.5
|
||||
* @see #setIncludeQueryString
|
||||
* @see #setBeforeMessagePrefix
|
||||
* @see #setBeforeMessageSuffix
|
||||
* @see #setAfterMessagePrefix
|
||||
* @see #setAfterMessageSuffix
|
||||
* @see org.apache.commons.logging.Log#debug(Object)
|
||||
*/
|
||||
public class CommonsRequestLoggingFilter extends AbstractRequestLoggingFilter {
|
||||
|
||||
/**
|
||||
* Writes a log message before the request is processed.
|
||||
*/
|
||||
protected void beforeRequest(HttpServletRequest request, String message) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a log message after the request is processed.
|
||||
*/
|
||||
protected void afterRequest(HttpServletRequest request, String message) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright 2002-2008 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
|
||||
*
|
||||
* http://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.web.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
|
||||
/**
|
||||
* Proxy for a standard Servlet 2.3 Filter, delegating to a Spring-managed
|
||||
* bean that implements the Filter interface. Supports a "targetBeanName"
|
||||
* filter init-param in <code>web.xml</code>, specifying the name of the
|
||||
* target bean in the Spring application context.
|
||||
*
|
||||
* <p><code>web.xml</code> will usually contain a DelegatingFilterProxy definition,
|
||||
* with the specified <code>filter-name</code> corresponding to a bean name in
|
||||
* Spring's root application context. All calls to the filter proxy will then
|
||||
* be delegated to that bean in the Spring context, which is required to implement
|
||||
* the standard Servlet 2.3 Filter interface.
|
||||
*
|
||||
* <p>This approach is particularly useful for Filter implementation with complex
|
||||
* setup needs, allowing to apply the full Spring bean definition machinery to
|
||||
* Filter instances. Alternatively, consider standard Filter setup in combination
|
||||
* with looking up service beans from the Spring root application context.
|
||||
*
|
||||
* <p><b>NOTE:</b> The lifecycle methods defined by the Servlet Filter interface
|
||||
* will by default <i>not</i> be delegated to the target bean, relying on the
|
||||
* Spring application context to manage the lifecycle of that bean. Specifying
|
||||
* the "targetFilterLifecycle" filter init-param as "true" will enforce invocation
|
||||
* of the <code>Filter.init</code> and <code>Filter.destroy</code> lifecycle methods
|
||||
* on the target bean, letting the servlet container manage the filter lifecycle.
|
||||
*
|
||||
* <p>This class is inspired by Acegi Security's FilterToBeanProxy class,
|
||||
* written by Ben Alex.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 1.2
|
||||
* @see #setTargetBeanName
|
||||
* @see #setTargetFilterLifecycle
|
||||
* @see javax.servlet.Filter#doFilter
|
||||
* @see javax.servlet.Filter#init
|
||||
* @see javax.servlet.Filter#destroy
|
||||
*/
|
||||
public class DelegatingFilterProxy extends GenericFilterBean {
|
||||
|
||||
private String contextAttribute;
|
||||
|
||||
private String targetBeanName;
|
||||
|
||||
private boolean targetFilterLifecycle = false;
|
||||
|
||||
private Filter delegate;
|
||||
|
||||
private final Object delegateMonitor = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the ServletContext attribute which should be used to retrieve the
|
||||
* {@link WebApplicationContext} from which to load the delegate {@link Filter} bean.
|
||||
*/
|
||||
public void setContextAttribute(String contextAttribute) {
|
||||
this.contextAttribute = contextAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the ServletContext attribute which should be used to retrieve the
|
||||
* {@link WebApplicationContext} from which to load the delegate {@link Filter} bean.
|
||||
*/
|
||||
public String getContextAttribute() {
|
||||
return this.contextAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the target bean in the Spring application context.
|
||||
* The target bean must implement the standard Servlet 2.3 Filter interface.
|
||||
* <p>By default, the <code>filter-name</code> as specified for the
|
||||
* DelegatingFilterProxy in <code>web.xml</code> will be used.
|
||||
*/
|
||||
public void setTargetBeanName(String targetBeanName) {
|
||||
this.targetBeanName = targetBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the target bean in the Spring application context.
|
||||
*/
|
||||
protected String getTargetBeanName() {
|
||||
return this.targetBeanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to invoke the <code>Filter.init</code> and
|
||||
* <code>Filter.destroy</code> lifecycle methods on the target bean.
|
||||
* <p>Default is "false"; target beans usually rely on the Spring application
|
||||
* context for managing their lifecycle. Setting this flag to "true" means
|
||||
* that the servlet container will control the lifecycle of the target
|
||||
* Filter, with this proxy delegating the corresponding calls.
|
||||
*/
|
||||
public void setTargetFilterLifecycle(boolean targetFilterLifecycle) {
|
||||
this.targetFilterLifecycle = targetFilterLifecycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether to invoke the <code>Filter.init</code> and
|
||||
* <code>Filter.destroy</code> lifecycle methods on the target bean.
|
||||
*/
|
||||
protected boolean isTargetFilterLifecycle() {
|
||||
return this.targetFilterLifecycle;
|
||||
}
|
||||
|
||||
|
||||
protected void initFilterBean() throws ServletException {
|
||||
// If no target bean name specified, use filter name.
|
||||
if (this.targetBeanName == null) {
|
||||
this.targetBeanName = getFilterName();
|
||||
}
|
||||
|
||||
// Fetch Spring root application context and initialize the delegate early,
|
||||
// if possible. If the root application context will be started after this
|
||||
// filter proxy, we'll have to resort to lazy initialization.
|
||||
synchronized (this.delegateMonitor) {
|
||||
WebApplicationContext wac = findWebApplicationContext();
|
||||
if (wac != null) {
|
||||
this.delegate = initDelegate(wac);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
// Lazily initialize the delegate if necessary.
|
||||
Filter delegateToUse = null;
|
||||
synchronized (this.delegateMonitor) {
|
||||
if (this.delegate == null) {
|
||||
WebApplicationContext wac = findWebApplicationContext();
|
||||
if (wac == null) {
|
||||
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
|
||||
}
|
||||
this.delegate = initDelegate(wac);
|
||||
}
|
||||
delegateToUse = this.delegate;
|
||||
}
|
||||
|
||||
// Let the delegate perform the actual doFilter operation.
|
||||
invokeDelegate(delegateToUse, request, response, filterChain);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
Filter delegateToUse = null;
|
||||
synchronized (this.delegateMonitor) {
|
||||
delegateToUse = this.delegate;
|
||||
}
|
||||
if (delegateToUse != null) {
|
||||
destroyDelegate(delegateToUse);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a <code>WebApplicationContext</code> from the <code>ServletContext</code>
|
||||
* attribute with the {@link #setContextAttribute configured name}. The
|
||||
* <code>WebApplicationContext</code> must have already been loaded and stored in the
|
||||
* <code>ServletContext</code> before this filter gets initialized (or invoked).
|
||||
* <p>Subclasses may override this method to provide a different
|
||||
* <code>WebApplicationContext</code> retrieval strategy.
|
||||
* @return the WebApplicationContext for this proxy, or <code>null</code> if not found
|
||||
* @see #getContextAttribute()
|
||||
*/
|
||||
protected WebApplicationContext findWebApplicationContext() {
|
||||
String attrName = getContextAttribute();
|
||||
if (attrName != null) {
|
||||
return WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
|
||||
}
|
||||
else {
|
||||
return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Filter delegate, defined as bean the given Spring
|
||||
* application context.
|
||||
* <p>Default implementation fetches the bean from the application context
|
||||
* and calls the standard <code>Filter.init</code> method on it, passing
|
||||
* in the FilterConfig of this Filter proxy.
|
||||
* @param wac the root application context
|
||||
* @return the initialized delegate Filter
|
||||
* @throws ServletException if thrown by the Filter
|
||||
* @see #getTargetBeanName()
|
||||
* @see #isTargetFilterLifecycle()
|
||||
* @see #getFilterConfig()
|
||||
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
|
||||
*/
|
||||
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
|
||||
Filter delegate = (Filter) wac.getBean(getTargetBeanName(), Filter.class);
|
||||
if (isTargetFilterLifecycle()) {
|
||||
delegate.init(getFilterConfig());
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually invoke the delegate Filter with the given request and response.
|
||||
* @param delegate the delegate Filter
|
||||
* @param request the current HTTP request
|
||||
* @param response the current HTTP response
|
||||
* @param filterChain the current FilterChain
|
||||
* @throws ServletException if thrown by the Filter
|
||||
* @throws IOException if thrown by the Filter
|
||||
*/
|
||||
protected void invokeDelegate(
|
||||
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
delegate.doFilter(request, response, filterChain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the Filter delegate.
|
||||
* Default implementation simply calls <code>Filter.destroy</code> on it.
|
||||
* @param delegate the Filter delegate (never <code>null</code>)
|
||||
* @see #isTargetFilterLifecycle()
|
||||
* @see javax.servlet.Filter#destroy()
|
||||
*/
|
||||
protected void destroyDelegate(Filter delegate) {
|
||||
if (isTargetFilterLifecycle()) {
|
||||
delegate.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue