View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  
18  package ch.elca.el4j.services.remoting;
19  
20  import java.lang.reflect.Proxy;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  import org.springframework.beans.factory.BeanNameAware;
25  import org.springframework.beans.factory.FactoryBean;
26  import org.springframework.context.ApplicationContext;
27  import org.springframework.context.ApplicationContextAware;
28  
29  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
30  import ch.elca.el4j.util.interfaceenrichment.EnrichmentDecorator;
31  import ch.elca.el4j.util.interfaceenrichment.InterfaceEnricher;
32  
33  
34  /**
35   * This class is the global remote service exporter bean.
36   *
37   * @svnLink $Revision: 3883 $;$Date: 2009-08-04 15:35:01 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/remoting_core/src/main/java/ch/elca/el4j/services/remoting/RemotingServiceExporter.java $
38   *
39   * @author Martin Zeltner (MZE)
40   */
41  public class RemotingServiceExporter extends AbstractRemotingBase implements
42  	FactoryBean, BeanNameAware, ApplicationContextAware {
43  	/**
44  	 * Private logger.
45  	 */
46  	private static Logger s_logger = LoggerFactory
47  		.getLogger(RemotingServiceExporter.class);
48  
49  	/**
50  	 * This is the application context, which was used to create this bean.
51  	 */
52  	private ApplicationContext m_parentApplicationContext;
53  
54  	/**
55  	 * This the name of this bean. This is used in the url mapping.
56  	 */
57  	private String m_beanName;
58  
59  	/**
60  	 * This is the internally created exporter bean.
61  	 */
62  	private Object m_exporterBean;
63  
64  	/**
65  	 * The cached enriched service interface.
66  	 */
67  	private Class m_serviceInterfaceWithContext;
68  
69  	/**
70  	 * Name of the service bean.
71  	 */
72  	private String m_service;
73  
74  	/**
75  	 * Whether the objects returned by the factory are singletons.
76  	 */
77  	private boolean m_singleton = true;
78  
79  	/**
80  	 * {@inheritDoc}
81  	 */
82  	public void afterPropertiesSet() throws Exception {
83  		super.afterPropertiesSet();
84  
85  		CoreNotificationHelper.notifyIfEssentialPropertyIsEmpty(getService(),
86  			"service", this);
87  		getRemoteProtocol().checkRemotingExporter(this);
88  	}
89  
90  	/**
91  	 * Lazily enriches the service's interface, adding the implicit context
92  	 * passing stuff.
93  	 *
94  	 * @param serviceInterface
95  	 *            The interface to enrich.
96  	 *
97  	 * @return Returns the enriched class.
98  	 */
99  	public Class getServiceInterfaceWithContext(Class serviceInterface) {
100 		if (m_serviceInterfaceWithContext == null) {
101 
102 			ClassLoader cl = Thread.currentThread().getContextClassLoader();
103 
104 			/**
105 			 * Create the service interface to be able to send context
106 			 * information.
107 			 */
108 			InterfaceEnricher interfaceIndirector = new InterfaceEnricher();
109 			EnrichmentDecorator interfaceDecorator = new ContextEnrichmentDecorator();
110 			m_serviceInterfaceWithContext = interfaceIndirector
111 				.createShadowInterfaceAndLoadItDirectly(serviceInterface,
112 					interfaceDecorator, cl);
113 		}
114 
115 		return m_serviceInterfaceWithContext;
116 	}
117 
118 	/**
119 	 * Creates a fresh exporter bean wraps a potentially enriched service
120 	 * interface.
121 	 *
122 	 * @return Returns the exporter bean.
123 	 */
124 	protected Object getFreshExporterBean() {
125 
126 		Object exporterBean;
127 
128 		boolean useImplicitContextPassing = getRemoteProtocol()
129 			.getImplicitContextPassingRegistry() != null;
130 
131 		/**
132 		 * Get service from application context. This allows to delegate
133 		 * lifecycle handling.
134 		 */
135 		Object service = getApplicationContext().getBean(getService());
136 
137 		if (useImplicitContextPassing
138 			&& !getRemoteProtocol().getProtocolSpecificContextPassing()) {
139 			s_logger.info("Implicit context passing in enabled.");
140 
141 			/**
142 			 * Get the context class loader from current thread.
143 			 */
144 			ClassLoader cl = Thread.currentThread().getContextClassLoader();
145 
146 			Class serviceInterfaceWithContext = getServiceInterfaceWithContext(getServiceInterface());
147 
148 			/**
149 			 * Wrap the service implementation with the generated interface to
150 			 * be able to extract context information.
151 			 */
152 			ServerContextInvocationHandler invocationHandler = new ServerContextInvocationHandler(
153 				service, getServiceInterface(), getRemoteProtocol()
154 					.getImplicitContextPassingRegistry());
155 			Object serviceProxy = Proxy.newProxyInstance(cl,
156 				new Class[] {serviceInterfaceWithContext}, invocationHandler);
157 
158 			/**
159 			 * Create the exporter servlet.
160 			 */
161 			exporterBean = getRemoteProtocol().createExporterBean(this,
162 				serviceInterfaceWithContext, serviceProxy);
163 		} else {
164 			if (!getRemoteProtocol().getProtocolSpecificContextPassing()) {
165 				s_logger.warn("Implicit context passing in disabled.");
166 			} else {
167 				s_logger
168 					.info("Protocol Specific implicit context passing in enabled.");
169 			}
170 
171 			exporterBean = getRemoteProtocol().createExporterBean(this,
172 				getServiceInterface(), service);
173 		}
174 
175 		/**
176 		 * Prepare exporter dependent beans.
177 		 */
178 		getRemoteProtocol().prepareExporterDependentBeans(this);
179 
180 		return exporterBean;
181 	}
182 
183 	/**
184 	 * {@inheritDoc}
185 	 */
186 	public Object getObject() throws Exception {
187 		Object exporterBean;
188 
189 		if (isSingleton()) {
190 			if (m_exporterBean == null) {
191 				m_exporterBean = getFreshExporterBean();
192 			}
193 			exporterBean = m_exporterBean;
194 
195 		} else {
196 			s_logger.info("I'm a prototype");
197 			exporterBean = getFreshExporterBean();
198 		}
199 
200 		/**
201 		 * Finalize exporter dependent beans before returning the exporter.
202 		 */
203 		getRemoteProtocol().finalizeExporterDependentBeans(this);
204 
205 		return exporterBean;
206 	}
207 
208 	/**
209 	 * {@inheritDoc}
210 	 */
211 	public Class getObjectType() {
212 		if (getRemoteProtocol() != null) {
213 			return getRemoteProtocol().getExporterObjectType();
214 		} else {
215 			return null;
216 		}
217 	}
218 
219 	/**
220 	 * Sets whether the objects returned by the factory are singltons or
221 	 * prototypes. Default is singletons.
222 	 *
223 	 * @param singleton
224 	 *            <code>true</code> for returning singletons.
225 	 */
226 	public void setSingleton(boolean singleton) {
227 		m_singleton = singleton;
228 	}
229 
230 	/**
231 	 * {@inheritDoc}
232 	 */
233 	public boolean isSingleton() {
234 		return m_singleton;
235 	}
236 
237 	/**
238 	 * @return Returns the beanName.
239 	 */
240 	public String getBeanName() {
241 		return m_beanName;
242 	}
243 
244 	/**
245 	 * {@inheritDoc}
246 	 */
247 	public void setBeanName(String name) {
248 		m_beanName = name;
249 	}
250 
251 	/**
252 	 * @return Returns the applicationContext.
253 	 */
254 	public ApplicationContext getApplicationContext() {
255 		return m_parentApplicationContext;
256 	}
257 
258 	/**
259 	 * {@inheritDoc}
260 	 */
261 	public void setApplicationContext(ApplicationContext applicationContext) {
262 		m_parentApplicationContext = applicationContext;
263 	}
264 
265 	/**
266 	 * @return Returns the service's bean name.
267 	 */
268 	public String getService() {
269 		return m_service;
270 	}
271 
272 	/**
273 	 * Sets the service's bean name.
274 	 *
275 	 * @param service
276 	 *            The bean name to set.
277 	 */
278 	public void setService(String service) {
279 		m_service = service;
280 	}
281 }