001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.config;
018:
019: import org.apache.openejb.OpenEJBException;
020: import org.apache.openejb.core.webservices.JaxWsUtils;
021: import org.apache.openejb.jee.EnterpriseBean;
022: import org.apache.openejb.jee.JndiConsumer;
023: import org.apache.openejb.jee.PortComponent;
024: import org.apache.openejb.jee.ServiceImplBean;
025: import org.apache.openejb.jee.ServiceRef;
026: import org.apache.openejb.jee.Servlet;
027: import org.apache.openejb.jee.ServletMapping;
028: import org.apache.openejb.jee.SessionBean;
029: import org.apache.openejb.jee.SessionType;
030: import org.apache.openejb.jee.WebApp;
031: import org.apache.openejb.jee.WebserviceDescription;
032: import org.apache.openejb.jee.Webservices;
033: import org.apache.openejb.jee.HandlerChains;
034: import org.apache.openejb.jee.oejb3.EjbDeployment;
035: import org.apache.openejb.util.LogCategory;
036: import org.apache.openejb.util.Logger;
037:
038: import javax.wsdl.Definition;
039: import javax.wsdl.Port;
040: import javax.wsdl.extensions.http.HTTPAddress;
041: import javax.wsdl.extensions.soap.SOAPAddress;
042: import javax.xml.namespace.QName;
043: import javax.xml.ws.WebServiceProvider;
044: import javax.jws.HandlerChain;
045: import java.io.File;
046: import java.net.MalformedURLException;
047: import java.net.URI;
048: import java.net.URL;
049: import java.util.Map;
050: import java.util.Set;
051: import java.util.TreeMap;
052:
053: public class WsDeployer implements DynamicDeployer {
054: public static final Logger logger = Logger.getInstance(
055: LogCategory.OPENEJB_STARTUP, WsDeployer.class.getPackage()
056: .getName());
057:
058: public AppModule deploy(AppModule appModule)
059: throws OpenEJBException {
060: // process all webservice port
061: for (EjbModule ejbModule : appModule.getEjbModules()) {
062: processPorts(ejbModule);
063: }
064: for (WebModule webModule : appModule.getWebModules()) {
065: processPorts(webModule);
066: }
067:
068: // Resolve service-refs
069: for (EjbModule ejbModule : appModule.getEjbModules()) {
070: for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar()
071: .getEnterpriseBeans()) {
072: resolveServiceRefs(ejbModule, enterpriseBean);
073: }
074: }
075: for (WebModule webModule : appModule.getWebModules()) {
076: resolveServiceRefs(webModule, webModule.getWebApp());
077: }
078: for (ClientModule clientModule : appModule.getClientModules()) {
079: resolveServiceRefs(clientModule, clientModule
080: .getApplicationClient());
081: }
082:
083: return appModule;
084: }
085:
086: private void resolveServiceRefs(DeploymentModule module,
087: JndiConsumer jndiConsumer) {
088: for (ServiceRef serviceRef : jndiConsumer.getServiceRef()) {
089: if (serviceRef.getServiceQname() == null
090: && serviceRef.getWsdlFile() != null) {
091: // parse the wsdl and get the serviceQname
092: try {
093: String wsdlFile = serviceRef.getWsdlFile();
094: Definition definition = getWsdl(module, wsdlFile);
095:
096: Set serviceQNames = definition.getServices()
097: .keySet();
098: if (serviceQNames.size() == 1) {
099: QName serviceQName = (QName) serviceQNames
100: .iterator().next();
101: serviceRef.setServiceQname(serviceQName);
102: } else if (serviceQNames.isEmpty()) {
103: logger
104: .error("The service-ref "
105: + serviceRef.getName()
106: + " must define service-qname because the wsdl-file "
107: + serviceRef.getWsdlFile()
108: + " does not constain any service definitions ");
109: } else {
110: logger
111: .error("The service-ref "
112: + serviceRef.getName()
113: + " must define service-qname because the wsdl-file "
114: + serviceRef.getWsdlFile()
115: + " constain more then one service definitions "
116: + serviceQNames);
117: }
118: } catch (Exception e) {
119: logger.error("Unable to read wsdl file "
120: + serviceRef.getWsdlFile());
121: }
122: }
123: }
124: }
125:
126: private void processPorts(WebModule webModule)
127: throws OpenEJBException {
128: // map existing webservice port declarations by servlet link
129: Webservices webservices = webModule.getWebservices();
130: Map<String, PortComponent> portMap = new TreeMap<String, PortComponent>();
131: if (webservices != null) {
132: for (WebserviceDescription webserviceDescription : webservices
133: .getWebserviceDescription()) {
134: for (PortComponent portComponent : webserviceDescription
135: .getPortComponent()) {
136: ServiceImplBean serviceImplBean = portComponent
137: .getServiceImplBean();
138: if (serviceImplBean != null
139: && serviceImplBean.getServletLink() != null) {
140: portMap.put(serviceImplBean.getServletLink(),
141: portComponent);
142: }
143: }
144: }
145: }
146:
147: // map existing servlet-mapping declarations
148: WebApp webApp = webModule.getWebApp();
149: Map<String, ServletMapping> servletMappings = new TreeMap<String, ServletMapping>();
150: for (ServletMapping servletMapping : webApp.getServletMapping()) {
151: servletMappings.put(servletMapping.getServletName(),
152: servletMapping);
153: }
154:
155: // add port declarations for webservices
156: WebserviceDescription webserviceDescription;
157: for (Servlet servlet : webApp.getServlet()) {
158: String className = servlet.getServletClass();
159:
160: try {
161: Class<?> clazz = webModule.getClassLoader().loadClass(
162: className);
163: if (JaxWsUtils.isWebService(clazz)) {
164: // add servlet mapping if not already declared
165: ServletMapping servletMapping = servletMappings
166: .get(servlet.getServletName());
167: String serviceName = JaxWsUtils
168: .getServiceName(clazz);
169: if (servletMapping == null) {
170: servletMapping = new ServletMapping();
171: servletMapping.setServletName(servlet
172: .getServletName());
173:
174: String location = "/" + serviceName;
175: servletMapping.getUrlPattern().add(location);
176: webApp.getServletMapping().add(servletMapping);
177: }
178:
179: // if we don't have a webservices document yet, we're gonna need one now
180: if (webservices == null) {
181: webservices = new Webservices();
182: webModule.setWebservices(webservices);
183: }
184:
185: // add web service description element (maps to service)
186: webserviceDescription = webservices
187: .getWebserviceDescriptionMap().get(
188: serviceName);
189: if (webserviceDescription == null) {
190: webserviceDescription = new WebserviceDescription();
191: webserviceDescription
192: .setWebserviceDescriptionName(serviceName);
193: webservices.getWebserviceDescription().add(
194: webserviceDescription);
195: }
196:
197: // define port if not already declared
198: PortComponent portComponent = portMap.get(servlet
199: .getServletName());
200: if (portComponent == null) {
201: portComponent = new PortComponent();
202: portComponent.setPortComponentName(clazz
203: .getSimpleName());
204: ServiceImplBean serviceImplBean = new ServiceImplBean();
205: serviceImplBean.setServletLink(servlet
206: .getServletName());
207: portComponent
208: .setServiceImplBean(serviceImplBean);
209:
210: webserviceDescription.getPortComponent().add(
211: portComponent);
212: }
213:
214: // default portId == moduleId.servletName
215: if (portComponent.getId() == null) {
216: portComponent.setId(webModule.getModuleId()
217: + "." + servlet.getServletName());
218: }
219: if (webserviceDescription.getId() == null) {
220: webserviceDescription.setId(webModule
221: .getModuleId()
222: + "." + servlet.getServletName());
223: }
224:
225: // set port values from annotations if not already set
226: if (portComponent.getServiceEndpointInterface() == null) {
227: portComponent
228: .setServiceEndpointInterface(JaxWsUtils
229: .getServiceInterface(clazz));
230: }
231: if (portComponent.getWsdlPort() == null) {
232: portComponent.setWsdlPort(JaxWsUtils
233: .getPortQName(clazz));
234: }
235: if (webserviceDescription.getWsdlFile() == null) {
236: webserviceDescription.setWsdlFile(JaxWsUtils
237: .getServiceWsdlLocation(clazz,
238: webModule.getClassLoader()));
239: }
240: if (portComponent.getWsdlService() == null) {
241: Definition definition = getWsdl(webModule,
242: webserviceDescription.getWsdlFile());
243: if (definition != null
244: && definition.getServices().size() == 1) {
245: QName serviceQName = (QName) definition
246: .getServices().keySet().iterator()
247: .next();
248: portComponent.setWsdlService(serviceQName);
249: } else {
250: portComponent.setWsdlService(JaxWsUtils
251: .getServiceQName(clazz));
252: }
253: }
254: if (portComponent.getProtocolBinding() == null) {
255: portComponent.setProtocolBinding(JaxWsUtils
256: .getBindingUriFromAnn(clazz));
257: }
258:
259: // handlers
260: if (portComponent.getHandlerChains() == null) {
261: HandlerChains handlerChains = getHandlerChains(
262: clazz, portComponent
263: .getServiceEndpointInterface(),
264: webModule.getClassLoader());
265: portComponent.setHandlerChains(handlerChains);
266:
267: }
268: }
269: } catch (Exception e) {
270: throw new OpenEJBException(
271: "Unable to load servlet class: " + className, e);
272: }
273: }
274: }
275:
276: private void processPorts(EjbModule ejbModule)
277: throws OpenEJBException {
278: // map existing webservice port declarations by servlet link
279: Webservices webservices = ejbModule.getWebservices();
280: Map<String, PortComponent> portMap = new TreeMap<String, PortComponent>();
281: if (webservices != null) {
282: for (WebserviceDescription webserviceDescription : webservices
283: .getWebserviceDescription()) {
284: for (PortComponent portComponent : webserviceDescription
285: .getPortComponent()) {
286: ServiceImplBean serviceImplBean = portComponent
287: .getServiceImplBean();
288: if (serviceImplBean != null
289: && serviceImplBean.getEjbLink() != null) {
290: portMap.put(serviceImplBean.getEjbLink(),
291: portComponent);
292: }
293: }
294: }
295: }
296:
297: Map<String, EjbDeployment> deploymentsByEjbName = ejbModule
298: .getOpenejbJar().getDeploymentsByEjbName();
299:
300: WebserviceDescription webserviceDescription = null;
301: for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar()
302: .getEnterpriseBeans()) {
303: // skip if this is not a webservices endpoint
304: if (!(enterpriseBean instanceof SessionBean))
305: continue;
306: SessionBean sessionBean = (SessionBean) enterpriseBean;
307: if (sessionBean.getSessionType() != SessionType.STATELESS)
308: continue;
309: if (sessionBean.getServiceEndpoint() == null)
310: continue;
311:
312: EjbDeployment deployment = deploymentsByEjbName
313: .get(sessionBean.getEjbName());
314: if (deployment == null)
315: continue;
316:
317: Class<?> ejbClass;
318: try {
319: ejbClass = ejbModule.getClassLoader().loadClass(
320: sessionBean.getEjbClass());
321: } catch (ClassNotFoundException e) {
322: throw new OpenEJBException("Unable to load ejb class: "
323: + sessionBean.getEjbClass(), e);
324: }
325:
326: // for now, skip all non jaxws beans
327: if (!JaxWsUtils.isWebService(ejbClass))
328: continue;
329:
330: // create webservices dd if not defined
331: if (webservices == null) {
332: webservices = new Webservices();
333: ejbModule.setWebservices(webservices);
334: }
335: if (webserviceDescription == null) {
336: webserviceDescription = new WebserviceDescription();
337: if (JaxWsUtils.isWebService(ejbClass)) {
338: webserviceDescription
339: .setWebserviceDescriptionName(JaxWsUtils
340: .getServiceName(ejbClass));
341: } else {
342: // todo create webserviceDescription name using some sort of jaxrpc data
343: }
344: webservices.getWebserviceDescription().add(
345: webserviceDescription);
346: }
347:
348: // add a port component if we don't alrady have one
349: PortComponent portComponent = portMap.get(sessionBean
350: .getEjbName());
351: if (portComponent == null) {
352: portComponent = new PortComponent();
353: if (ejbClass
354: .isAnnotationPresent(WebServiceProvider.class)) {
355: portComponent.setPortComponentName(ejbClass
356: .getName());
357: } else {
358: portComponent.setPortComponentName(ejbClass
359: .getSimpleName());
360: }
361: webserviceDescription.getPortComponent().add(
362: portComponent);
363:
364: ServiceImplBean serviceImplBean = new ServiceImplBean();
365: serviceImplBean.setEjbLink(sessionBean.getEjbName());
366: portComponent.setServiceImplBean(serviceImplBean);
367: }
368:
369: // default portId == deploymentId
370: if (portComponent.getId() == null) {
371: portComponent.setId(deployment.getDeploymentId());
372: }
373: if (webserviceDescription.getId() == null) {
374: webserviceDescription.setId(deployment
375: .getDeploymentId());
376: }
377:
378: // set service endpoint interface
379: if (portComponent.getServiceEndpointInterface() == null) {
380: portComponent.setServiceEndpointInterface(sessionBean
381: .getServiceEndpoint());
382: }
383:
384: // default location is /@WebService.serviceName/@WebService.name
385: if (JaxWsUtils.isWebService(ejbClass)) {
386: if (portComponent.getWsdlPort() == null) {
387: portComponent.setWsdlPort(JaxWsUtils
388: .getPortQName(ejbClass));
389: }
390: if (webserviceDescription.getWsdlFile() == null) {
391: webserviceDescription.setWsdlFile(JaxWsUtils
392: .getServiceWsdlLocation(ejbClass, ejbModule
393: .getClassLoader()));
394: }
395: if (portComponent.getWsdlService() == null) {
396: Definition definition = getWsdl(ejbModule,
397: webserviceDescription.getWsdlFile());
398: if (definition != null
399: && definition.getServices().size() == 1) {
400: QName serviceQName = (QName) definition
401: .getServices().keySet().iterator()
402: .next();
403: portComponent.setWsdlService(serviceQName);
404: } else {
405: portComponent.setWsdlService(JaxWsUtils
406: .getServiceQName(ejbClass));
407: }
408: }
409: if (portComponent.getLocation() == null
410: && webserviceDescription.getWsdlFile() != null) {
411: // set location based on wsdl port
412: Definition definition = getWsdl(ejbModule,
413: webserviceDescription.getWsdlFile());
414: String locationURI = getLocationFromWsdl(
415: definition, portComponent);
416: portComponent.setLocation(locationURI);
417: }
418: if (portComponent.getProtocolBinding() == null) {
419: portComponent.setProtocolBinding(JaxWsUtils
420: .getBindingUriFromAnn(ejbClass));
421: }
422:
423: // handlers
424: if (portComponent.getHandlerChains() == null) {
425: HandlerChains handlerChains = getHandlerChains(
426: ejbClass, sessionBean.getServiceEndpoint(),
427: ejbModule.getClassLoader());
428: portComponent.setHandlerChains(handlerChains);
429:
430: }
431: } else {
432: // todo location JAX-RPC services comes from wsdl file
433: }
434: }
435: }
436:
437: private Definition getWsdl(DeploymentModule module, String wsdlFile) {
438: if (wsdlFile == null)
439: return null;
440:
441: Object object = module.getAltDDs().get(wsdlFile);
442: if (object instanceof Definition) {
443: Definition definition = (Definition) object;
444: return definition;
445: }
446:
447: try {
448: URL wsdlUrl;
449: if (object instanceof URL) {
450: wsdlUrl = (URL) object;
451: } else {
452: URL baseUrl = getBaseUrl(module);
453: wsdlUrl = new URL(baseUrl, wsdlFile);
454: }
455:
456: Definition definition = ReadDescriptors.readWsdl(wsdlUrl);
457: module.getAltDDs().put(wsdlFile, definition);
458: return definition;
459: } catch (Exception e) {
460: logger.error("Unable to read wsdl file " + wsdlFile);
461: }
462:
463: return null;
464: }
465:
466: private URL getBaseUrl(DeploymentModule module)
467: throws MalformedURLException {
468: File file = new File(module.getJarLocation());
469: if (!file.exists()) {
470: return new URL(module.getJarLocation());
471: }
472:
473: URL baseUrl = file.toURL();
474: if (file.isFile()) {
475: baseUrl = new URL("jar", null, baseUrl.toExternalForm()
476: + "!/");
477: }
478: return baseUrl;
479: }
480:
481: private String getLocationFromWsdl(Definition definition,
482: PortComponent portComponent) {
483: if (definition == null)
484: return null;
485:
486: try {
487: javax.wsdl.Service service = definition
488: .getService(portComponent.getWsdlService());
489: if (service == null)
490: return null;
491:
492: Port port = service.getPort(portComponent.getWsdlPort()
493: .getLocalPart());
494: if (port == null)
495: return null;
496:
497: for (Object element : port.getExtensibilityElements()) {
498: if (element instanceof SOAPAddress) {
499: SOAPAddress soapAddress = (SOAPAddress) element;
500: URI uri = new URI(soapAddress.getLocationURI());
501: return uri.getPath();
502: } else if (element instanceof HTTPAddress) {
503: HTTPAddress httpAddress = (HTTPAddress) element;
504: URI uri = new URI(httpAddress.getLocationURI());
505: return uri.getPath();
506: }
507: }
508: } catch (Exception e) {
509: }
510: return null;
511: }
512:
513: public static HandlerChains getHandlerChains(
514: Class<?> declaringClass, String serviceEndpoint,
515: ClassLoader classLoader) throws OpenEJBException {
516: HandlerChain handlerChain = declaringClass
517: .getAnnotation(HandlerChain.class);
518: if (handlerChain == null && serviceEndpoint != null) {
519: try {
520: declaringClass = classLoader.loadClass(serviceEndpoint);
521: handlerChain = declaringClass
522: .getAnnotation(HandlerChain.class);
523: } catch (ClassNotFoundException ignored) {
524: }
525: }
526: HandlerChains handlerChains = null;
527: if (handlerChain != null) {
528: try {
529: URL handlerFileURL = declaringClass
530: .getResource(handlerChain.file());
531: handlerChains = ReadDescriptors
532: .readHandlerChains(handlerFileURL);
533: } catch (Throwable e) {
534: throw new OpenEJBException(
535: "Unable to load handler chain file: "
536: + handlerChain.file(), e);
537: }
538: }
539: return handlerChains;
540: }
541: }
|