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) 2006 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  package ch.elca.el4j.services.remoting.protocol;
18  
19  import java.lang.reflect.Method;
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Map;
23  
24  import javax.xml.ws.BindingProvider;
25  import javax.xml.ws.Service;
26  import javax.xml.ws.handler.Handler;
27  import javax.xml.ws.handler.HandlerResolver;
28  import javax.xml.ws.handler.PortInfo;
29  
30  import org.apache.commons.collections.CollectionUtils;
31  import org.jvnet.jax_ws_commons.spring.SpringService;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  import com.sun.xml.ws.client.sei.SEIStub;
36  import com.sun.xml.ws.transport.http.servlet.SpringBinding;
37  
38  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
39  import ch.elca.el4j.services.remoting.AbstractRemotingBase;
40  import ch.elca.el4j.services.remoting.ProtocolSpecificConfiguration;
41  import ch.elca.el4j.services.remoting.RemotingProxyFactoryBean;
42  import ch.elca.el4j.services.remoting.RemotingServiceExporter;
43  import ch.elca.el4j.util.codingsupport.AopHelper;
44  
45  /**
46   * This class implements all needed things for the soap protocol using JAX-WS.
47   * Since <b>EL4J 1.7</b> it is possible to define JaxWs handlers.
48   *
49   * @svnLink $Revision: 4204 $;$Date: 2010-11-02 11:44:37 +0100 (Di, 02. Nov 2010) $;$Author: swisswheel $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/remoting_jaxws/src/main/java/ch/elca/el4j/services/remoting/protocol/Jaxws.java $
50   *
51   * @author Stefan Wismer (SWI)
52   * @author Reynald Borer (RBR)
53   */
54  public class Jaxws extends AbstractInetSocketAddressWebProtocol {
55  	/**
56  	 * Private logger.
57  	 */
58  	protected static final Logger s_logger = LoggerFactory.getLogger(Jaxws.class);
59  
60  	/**
61  	 * List of JaxWs handlers.
62  	 */
63  	@SuppressWarnings("unchecked")
64  	private List<Handler> handlers = new ArrayList<Handler>();
65  	
66  	/** {@inheritDoc} */
67  	@SuppressWarnings("unchecked")
68  	@Override
69  	public Object createExporterBean(RemotingServiceExporter exporterBean,
70  			Class serviceInterfaceWithContext, Object serviceProxy) {
71  		
72  		Object bean = exporterBean.getApplicationContext().getBean(
73  			exporterBean.getService());
74  		
75  		SpringService service = new SpringService();
76  		service.setBean(bean);
77  		
78  		// JAX-WS look for web-service annotation on the target class and not the interface; in case it is a dynamic
79  		// proxy, we should set the correct class in SpringService!
80  		if (AopHelper.isAopProxy(bean)) {
81  			service.setImpl(AopHelper.getTargetClass(bean));
82  		}
83  		
84  		// give potential subclasses the chance to adapt the service
85  		adaptExporterService(service);
86  		
87  		SpringBinding binding = new SpringBinding();
88  		binding.setUrl("/" + exporterBean.getServiceName());
89  		try {
90  			binding.setService(service.getObject());
91  		} catch (Exception e) {
92  			CoreNotificationHelper.notifyMisconfiguration(
93  				"Could not create JAX-WS binding for " + bean, e);
94  		}
95  		
96  		return binding;
97  	}
98  
99  	/** {@inheritDoc} */
100 	@SuppressWarnings("unchecked")
101 	@Override
102 	public Object createProxyBean(RemotingProxyFactoryBean proxyBean,
103 			Class serviceInterfaceWithContext) {
104 		Object createdProxy = null;
105 
106 		Class serviceInterface = proxyBean.getServiceInterface();
107 		String serviceName = serviceInterface.getName();
108 		
109 		try {
110 			Class wsServiceClass;
111 			String portName;
112 			
113 			ProtocolSpecificConfiguration cfg
114 				= proxyBean.getProtocolSpecificConfiguration();
115 			if (cfg != null && cfg instanceof JaxwsProtocolConfiguration) {
116 				JaxwsProtocolConfiguration jaxWsConfig
117 					= (JaxwsProtocolConfiguration) cfg;
118 				
119 				// use wsimport-generated classes directly (no dynamic proxies)
120 				wsServiceClass = jaxWsConfig.getServiceImplementation();
121 				portName = "get" + serviceInterface.getSimpleName();
122 			} else {
123 				// use generated classes directly (no dynamic proxies)
124 				wsServiceClass = Class.forName(serviceName + "Service");
125 				portName = "get" + serviceInterface.getSimpleName() + "Port";
126 			}
127 			
128 			Service clientService = (Service) wsServiceClass.newInstance();
129 			
130 			// give potential subclasses the chance to adapt the service
131 			adaptProxyService(clientService);
132 			
133 			Method portGetter = wsServiceClass.getMethod(portName);
134 			Object port = portGetter.invoke(clientService);
135 
136 			// overwrite endpoint address
137 			BindingProvider bindingProvider = (BindingProvider) port;
138 			Map<String, Object> context = bindingProvider.getRequestContext();
139 			
140 			context.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, generateUrl(proxyBean));
141 			
142 			createdProxy = port;
143 		} catch (Exception e) {
144 			CoreNotificationHelper.notifyMisconfiguration(
145 				"Could not create JAX-WS binding for "
146 				+ serviceInterface, e);
147 		}
148 		return createdProxy;
149 	}
150 	
151 	/**
152 	 * Does this protocol handle context passing on its own? Yes.
153 	 * @return Whether this protocol handles the context (<code>true</code>)
154 	 */
155 	public boolean getProtocolSpecificContextPassing() {
156 		return true;
157 	}
158 
159 	/** {@inheritDoc} */
160 	@Override
161 	public String generateUrl(AbstractRemotingBase remoteBase) {
162 		StringBuffer sb = new StringBuffer();
163 		sb.append(getServiceProtocol());
164 		sb.append("://");
165 		sb.append(getServiceHost());
166 		sb.append(":");
167 		sb.append(getServicePort());
168 		sb.append("/");
169 		sb.append(getContextPath());
170 		sb.append("/");
171 		sb.append(remoteBase.getServiceName());
172 		return sb.toString();
173 	}
174 
175 	/** {@inheritDoc} */
176 	@SuppressWarnings("unchecked")
177 	@Override
178 	public Class getExporterObjectType() {
179 		return SpringBinding.class;
180 	}
181 
182 	/** {@inheritDoc} */
183 	@SuppressWarnings("unchecked")
184 	@Override
185 	public Class getProxyObjectType() {
186 		return SEIStub.class;
187 	}
188 
189 	/**
190 	 * Method providing an extension point do adapt the proxy service.
191 	 * @param service The service
192 	 */
193 	protected void adaptProxyService(Service service) {
194 		if (CollectionUtils.isNotEmpty(handlers)) {
195 			service.setHandlerResolver(new HandlerResolver() {
196 				@SuppressWarnings("unchecked")
197 				public List<Handler> getHandlerChain(PortInfo portInfo) {
198 					List<Handler> list = new ArrayList<Handler>(handlers.size());
199 					list.addAll(handlers);
200 					return list;
201 				}
202 			});
203 		}
204 	}
205 
206 	/**
207 	 * Method providing an extension point do adapt the exporter service.
208 	 * @param service The service
209 	 */
210 	protected void adaptExporterService(SpringService service) {
211 		if (CollectionUtils.isNotEmpty(handlers)) {
212 			service.setHandlers(handlers);
213 		}
214 	}
215 	
216 	/**
217 	 * @return Returns the JaxWs handlers.
218 	 * @since 1.7
219 	 */
220 	@SuppressWarnings("unchecked")
221 	public List<Handler> getHandlers() {
222 		return handlers;
223 	}
224 
225 	/**
226 	 * @param handlers Are the JaxWs handlers to set.
227 	 * @since 1.7
228 	 */
229 	@SuppressWarnings("unchecked")
230 	public void setHandlers(List<Handler> handlers) {
231 		this.handlers = handlers;
232 	}
233 }