001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.remoting.rmi;
018:
019: import java.rmi.NoSuchObjectException;
020: import java.rmi.Remote;
021: import java.rmi.RemoteException;
022: import java.util.Properties;
023:
024: import javax.naming.NamingException;
025: import javax.rmi.PortableRemoteObject;
026:
027: import org.springframework.beans.factory.DisposableBean;
028: import org.springframework.beans.factory.InitializingBean;
029: import org.springframework.jndi.JndiTemplate;
030:
031: /**
032: * Service exporter which binds RMI services to JNDI.
033: * Typically used for RMI-IIOP (CORBA).
034: *
035: * <p>Exports services via the {@link javax.rmi.PortableRemoteObject} class.
036: * You need to run "rmic" with the "-iiop" option to generate corresponding
037: * stubs and skeletons for each exported service.
038: *
039: * <p>Also supports exposing any non-RMI service via RMI invokers, to be accessed
040: * via {@link JndiRmiClientInterceptor} / {@link JndiRmiProxyFactoryBean}'s
041: * automatic detection of such invokers.
042: *
043: * <p>With an RMI invoker, RMI communication works on the {@link RmiInvocationHandler}
044: * level, needing only one stub for any service. Service interfaces do not have to
045: * extend <code>java.rmi.Remote</code> or throw <code>java.rmi.RemoteException</code>
046: * on all methods, but in and out parameters have to be serializable.
047: *
048: * <p>The JNDI environment can be specified as "jndiEnvironment" bean property,
049: * or be configured in a <code>jndi.properties</code> file or as system properties.
050: * For example:
051: *
052: * <pre class="code"><property name="jndiEnvironment">
053: * <props>
054: * <prop key="java.naming.factory.initial">com.sun.jndi.cosnaming.CNCtxFactory</prop>
055: * <prop key="java.naming.provider.url">iiop://localhost:1050</prop>
056: * </props>
057: * </property></pre>
058: *
059: * @author Juergen Hoeller
060: * @since 1.1
061: * @see #setService
062: * @see #setJndiTemplate
063: * @see #setJndiEnvironment
064: * @see #setJndiName
065: * @see JndiRmiClientInterceptor
066: * @see JndiRmiProxyFactoryBean
067: * @see javax.rmi.PortableRemoteObject#exportObject
068: */
069: public class JndiRmiServiceExporter extends RmiBasedExporter implements
070: InitializingBean, DisposableBean {
071:
072: private JndiTemplate jndiTemplate = new JndiTemplate();
073:
074: private String jndiName;
075:
076: private Remote exportedObject;
077:
078: /**
079: * Set the JNDI template to use for JNDI lookups.
080: * You can also specify JNDI environment settings via "jndiEnvironment".
081: * @see #setJndiEnvironment
082: */
083: public void setJndiTemplate(JndiTemplate jndiTemplate) {
084: this .jndiTemplate = (jndiTemplate != null ? jndiTemplate
085: : new JndiTemplate());
086: }
087:
088: /**
089: * Set the JNDI environment to use for JNDI lookups.
090: * Creates a JndiTemplate with the given environment settings.
091: * @see #setJndiTemplate
092: */
093: public void setJndiEnvironment(Properties jndiEnvironment) {
094: this .jndiTemplate = new JndiTemplate(jndiEnvironment);
095: }
096:
097: /**
098: * Set the JNDI name of the exported RMI service.
099: */
100: public void setJndiName(String jndiName) {
101: this .jndiName = jndiName;
102: }
103:
104: public void afterPropertiesSet() throws NamingException,
105: RemoteException {
106: prepare();
107: }
108:
109: /**
110: * Initialize this service exporter, binding the specified service to JNDI.
111: * @throws NamingException if service binding failed
112: * @throws RemoteException if service export failed
113: */
114: public void prepare() throws NamingException, RemoteException {
115: if (this .jndiName == null) {
116: throw new IllegalArgumentException(
117: "Property 'jndiName' is required");
118: }
119:
120: // Initialize and cache exported object.
121: this .exportedObject = getObjectToExport();
122: PortableRemoteObject.exportObject(this .exportedObject);
123:
124: rebind();
125: }
126:
127: /**
128: * Rebind the specified service to JNDI, for recovering in case
129: * of the target registry having been restarted.
130: * @throws NamingException if service binding failed
131: */
132: public void rebind() throws NamingException {
133: if (logger.isInfoEnabled()) {
134: logger.info("Binding RMI service to JNDI location ["
135: + this .jndiName + "]");
136: }
137: this .jndiTemplate.rebind(this .jndiName, this .exportedObject);
138: }
139:
140: /**
141: * Unbind the RMI service from JNDI on bean factory shutdown.
142: */
143: public void destroy() throws NamingException, NoSuchObjectException {
144: if (logger.isInfoEnabled()) {
145: logger.info("Unbinding RMI service from JNDI location ["
146: + this .jndiName + "]");
147: }
148: this.jndiTemplate.unbind(this.jndiName);
149: PortableRemoteObject.unexportObject(this.exportedObject);
150: }
151:
152: }
|