| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.openejb.config; |
| |
| import org.apache.openejb.OpenEJBException; |
| import org.apache.openejb.core.webservices.JaxWsUtils; |
| import org.apache.openejb.jee.EnterpriseBean; |
| import org.apache.openejb.jee.HandlerChains; |
| import org.apache.openejb.jee.JndiConsumer; |
| import org.apache.openejb.jee.PortComponent; |
| import org.apache.openejb.jee.ServiceImplBean; |
| import org.apache.openejb.jee.ServiceRef; |
| import org.apache.openejb.jee.Servlet; |
| import org.apache.openejb.jee.ServletMapping; |
| import org.apache.openejb.jee.SessionBean; |
| import org.apache.openejb.jee.SessionType; |
| import org.apache.openejb.jee.WebApp; |
| import org.apache.openejb.jee.WebserviceDescription; |
| import org.apache.openejb.jee.Webservices; |
| import org.apache.openejb.jee.oejb3.EjbDeployment; |
| import org.apache.openejb.util.LogCategory; |
| import org.apache.openejb.util.Logger; |
| import org.apache.openejb.util.URLs; |
| |
| import javax.jws.HandlerChain; |
| import javax.wsdl.Definition; |
| import javax.wsdl.Port; |
| import javax.wsdl.extensions.http.HTTPAddress; |
| import javax.wsdl.extensions.soap.SOAPAddress; |
| import javax.xml.namespace.QName; |
| import javax.xml.ws.soap.SOAPBinding; |
| import java.io.File; |
| import java.net.MalformedURLException; |
| import java.net.URI; |
| import java.net.URL; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| |
| public class WsDeployer implements DynamicDeployer { |
| public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, WsDeployer.class.getPackage().getName()); |
| |
| public AppModule deploy(AppModule appModule) throws OpenEJBException { |
| // process all webservice port |
| for (EjbModule ejbModule : appModule.getEjbModules()) { |
| processPorts(ejbModule); |
| } |
| for (WebModule webModule : appModule.getWebModules()) { |
| processPorts(webModule); |
| } |
| |
| // Resolve service-refs |
| for (EjbModule ejbModule : appModule.getEjbModules()) { |
| for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar().getEnterpriseBeans()) { |
| resolveServiceRefs(ejbModule, enterpriseBean); |
| } |
| } |
| for (WebModule webModule : appModule.getWebModules()) { |
| resolveServiceRefs(webModule, webModule.getWebApp()); |
| } |
| for (ClientModule clientModule : appModule.getClientModules()) { |
| resolveServiceRefs(clientModule, clientModule.getApplicationClient()); |
| } |
| |
| return appModule; |
| } |
| |
| private void resolveServiceRefs(DeploymentModule module, JndiConsumer jndiConsumer) { |
| for (ServiceRef serviceRef : jndiConsumer.getServiceRef()) { |
| if (serviceRef.getServiceQname() == null && serviceRef.getWsdlFile() != null) { |
| // parse the wsdl and get the serviceQname |
| try { |
| String wsdlFile = serviceRef.getWsdlFile(); |
| Definition definition = getWsdl(module, wsdlFile); |
| |
| Set serviceQNames = definition.getServices().keySet(); |
| if (serviceQNames.size() == 1) { |
| QName serviceQName = (QName) serviceQNames.iterator().next(); |
| serviceRef.setServiceQname(serviceQName); |
| } else if (serviceQNames.isEmpty()) { |
| logger.error("The service-ref " + serviceRef.getName() + " must define service-qname because the wsdl-file " + serviceRef.getWsdlFile() + " does not constain any service definitions "); |
| } else { |
| logger.error("The service-ref " + serviceRef.getName() + " must define service-qname because the wsdl-file " + serviceRef.getWsdlFile() + " constain more then one service definitions " + serviceQNames); |
| } |
| } catch(Exception e) { |
| logger.error("Unable to read wsdl file " + serviceRef.getWsdlFile()); |
| } |
| } |
| } |
| } |
| |
| private void processPorts(WebModule webModule) throws OpenEJBException { |
| // map existing webservice port declarations by servlet link |
| Webservices webservices = webModule.getWebservices(); |
| Map<String, PortComponent> portMap = new TreeMap<String, PortComponent>(); |
| if (webservices != null) { |
| for (WebserviceDescription webserviceDescription : webservices.getWebserviceDescription()) { |
| for (PortComponent portComponent : webserviceDescription.getPortComponent()) { |
| ServiceImplBean serviceImplBean = portComponent.getServiceImplBean(); |
| if (serviceImplBean != null && serviceImplBean.getServletLink() != null) { |
| portMap.put(serviceImplBean.getServletLink(), portComponent); |
| } |
| } |
| } |
| } |
| |
| |
| // map existing servlet-mapping declarations |
| WebApp webApp = webModule.getWebApp(); |
| Map<String, ServletMapping> servletMappings = new TreeMap<String, ServletMapping>(); |
| for (ServletMapping servletMapping : webApp.getServletMapping()) { |
| servletMappings.put(servletMapping.getServletName(), servletMapping); |
| } |
| |
| // add port declarations for Pojo webservices |
| WebserviceDescription webserviceDescription; |
| for (Servlet servlet : webApp.getServlet()) { |
| // the implementation class will be replaced by the WsServlet in the WsRegistry |
| String className = servlet.getServletClass(); |
| |
| // Skip JSPs |
| if (className == null) continue; |
| |
| try { |
| Class<?> clazz = webModule.getClassLoader().loadClass(className); |
| if (JaxWsUtils.isWebService(clazz)) { |
| // add servlet mapping if not already declared |
| ServletMapping servletMapping = servletMappings.get(servlet.getServletName()); |
| String serviceName = JaxWsUtils.getServiceName(clazz); |
| if (servletMapping == null) { |
| servletMapping = new ServletMapping(); |
| servletMapping.setServletName(servlet.getServletName()); |
| |
| String location = "/" + serviceName; |
| servletMapping.getUrlPattern().add(location); |
| webApp.getServletMapping().add(servletMapping); |
| } |
| |
| // if we don't have a webservices document yet, we're gonna need one now |
| if (webservices == null) { |
| webservices = new Webservices(); |
| webModule.setWebservices(webservices); |
| } |
| |
| // add web service description element (maps to service) |
| webserviceDescription = webservices.getWebserviceDescriptionMap().get(serviceName); |
| if (webserviceDescription == null) { |
| webserviceDescription = new WebserviceDescription(); |
| webserviceDescription.setWebserviceDescriptionName(serviceName); |
| webservices.getWebserviceDescription().add(webserviceDescription); |
| } |
| |
| // define port if not already declared |
| PortComponent portComponent = portMap.get(servlet.getServletName()); |
| if (portComponent == null) { |
| portComponent = new PortComponent(); |
| portComponent.setPortComponentName(clazz.getSimpleName()); |
| ServiceImplBean serviceImplBean = new ServiceImplBean(); |
| serviceImplBean.setServletLink(servlet.getServletName()); |
| portComponent.setServiceImplBean(serviceImplBean); |
| |
| webserviceDescription.getPortComponent().add(portComponent); |
| } |
| |
| // default portId == moduleId.servletName |
| if (portComponent.getId() == null) { |
| portComponent.setId(webModule.getModuleId() + "." + servlet.getServletName()); |
| } |
| if (webserviceDescription.getId() == null) { |
| webserviceDescription.setId(webModule.getModuleId() + "." + servlet.getServletName()); |
| } |
| |
| // set port values from annotations if not already set |
| if (portComponent.getServiceEndpointInterface() == null) { |
| portComponent.setServiceEndpointInterface(JaxWsUtils.getServiceInterface(clazz)); |
| } |
| if (portComponent.getWsdlPort() == null) { |
| portComponent.setWsdlPort(JaxWsUtils.getPortQName(clazz)); |
| } |
| if (webserviceDescription.getWsdlFile() == null) { |
| webserviceDescription.setWsdlFile(JaxWsUtils.getServiceWsdlLocation(clazz, webModule.getClassLoader())); |
| } |
| if (portComponent.getWsdlService() == null) { |
| Definition definition = getWsdl(webModule, webserviceDescription.getWsdlFile()); |
| if (definition != null && definition.getServices().size() == 1) { |
| QName serviceQName = (QName) definition.getServices().keySet().iterator().next(); |
| portComponent.setWsdlService(serviceQName); |
| } else { |
| portComponent.setWsdlService(JaxWsUtils.getServiceQName(clazz)); |
| } |
| } |
| if (portComponent.getProtocolBinding() == null) { |
| portComponent.setProtocolBinding(JaxWsUtils.getBindingUriFromAnn(clazz)); |
| } |
| if (SOAPBinding.SOAP12HTTP_MTOM_BINDING.equals(portComponent.getProtocolBinding()) || |
| SOAPBinding.SOAP11HTTP_MTOM_BINDING.equals(portComponent.getProtocolBinding())) { |
| portComponent.setEnableMtom(true); |
| } |
| |
| // handlers |
| if (portComponent.getHandlerChains() == null) { |
| HandlerChains handlerChains = getHandlerChains(clazz, portComponent.getServiceEndpointInterface(), webModule.getClassLoader()); |
| portComponent.setHandlerChains(handlerChains); |
| |
| } |
| } |
| } catch (Exception e) { |
| throw new OpenEJBException("Unable to load servlet class: " + className, e); |
| } |
| } |
| } |
| |
| private void processPorts(EjbModule ejbModule) throws OpenEJBException { |
| // map existing webservice port declarations by servlet link |
| Webservices webservices = ejbModule.getWebservices(); |
| Map<String, PortComponent> portMap = new TreeMap<String, PortComponent>(); |
| if (webservices != null) { |
| for (WebserviceDescription webserviceDescription : webservices.getWebserviceDescription()) { |
| for (PortComponent portComponent : webserviceDescription.getPortComponent()) { |
| ServiceImplBean serviceImplBean = portComponent.getServiceImplBean(); |
| if (serviceImplBean != null && serviceImplBean.getEjbLink() != null) { |
| portMap.put(serviceImplBean.getEjbLink(), portComponent); |
| } |
| } |
| } |
| } |
| |
| Map<String, EjbDeployment> deploymentsByEjbName = ejbModule.getOpenejbJar().getDeploymentsByEjbName(); |
| |
| WebserviceDescription webserviceDescription = null; |
| for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar().getEnterpriseBeans()) { |
| // skip if this is not a webservices endpoint |
| if (!(enterpriseBean instanceof SessionBean)) continue; |
| SessionBean sessionBean = (SessionBean) enterpriseBean; |
| if (sessionBean.getSessionType() == SessionType.STATEFUL) continue; |
| if (sessionBean.getSessionType() == SessionType.MANAGED) continue; |
| if (sessionBean.getServiceEndpoint() == null) continue; |
| |
| |
| EjbDeployment deployment = deploymentsByEjbName.get(sessionBean.getEjbName()); |
| if (deployment == null) continue; |
| |
| Class<?> ejbClass; |
| try { |
| ejbClass = ejbModule.getClassLoader().loadClass(sessionBean.getEjbClass()); |
| } catch (ClassNotFoundException e) { |
| throw new OpenEJBException("Unable to load ejb class: " + sessionBean.getEjbClass(), e); |
| } |
| |
| // for now, skip all non jaxws beans |
| if (!JaxWsUtils.isWebService(ejbClass)) continue; |
| |
| // create webservices dd if not defined |
| if (webservices == null) { |
| webservices = new Webservices(); |
| ejbModule.setWebservices(webservices); |
| } |
| |
| webserviceDescription = webservices.getWebserviceDescriptionMap().get(JaxWsUtils.getServiceName(ejbClass)); |
| if (webserviceDescription == null) { |
| webserviceDescription = new WebserviceDescription(); |
| if (JaxWsUtils.isWebService(ejbClass)) { |
| webserviceDescription.setWebserviceDescriptionName(JaxWsUtils.getServiceName(ejbClass)); |
| } else { |
| // todo create webserviceDescription name using some sort of jaxrpc data |
| } |
| webservices.getWebserviceDescription().add(webserviceDescription); |
| } |
| |
| // add a port component if we don't alrady have one |
| PortComponent portComponent = portMap.get(sessionBean.getEjbName()); |
| if (portComponent == null) { |
| portComponent = new PortComponent(); |
| if (webserviceDescription.getPortComponentMap().containsKey(JaxWsUtils.getPortQName(ejbClass).getLocalPart())) { |
| // when to webservices.xml is defined and when we want to |
| // publish more than one port for the same implementation by configuration |
| portComponent.setPortComponentName(sessionBean.getEjbName()); |
| |
| } else { // JAX-WS Metadata specification default |
| portComponent.setPortComponentName(JaxWsUtils.getPortQName(ejbClass).getLocalPart()); |
| |
| } |
| webserviceDescription.getPortComponent().add(portComponent); |
| |
| ServiceImplBean serviceImplBean = new ServiceImplBean(); |
| serviceImplBean.setEjbLink(sessionBean.getEjbName()); |
| portComponent.setServiceImplBean(serviceImplBean); |
| |
| // Checking if MTOM must be enabled |
| if (SOAPBinding.SOAP12HTTP_MTOM_BINDING.equals(portComponent.getProtocolBinding()) || |
| SOAPBinding.SOAP11HTTP_MTOM_BINDING.equals(portComponent.getProtocolBinding())) { |
| portComponent.setEnableMtom(true); |
| } |
| |
| } |
| |
| // default portId == deploymentId |
| if (portComponent.getId() == null) { |
| portComponent.setId(deployment.getDeploymentId()); |
| } |
| if (webserviceDescription.getId() == null) { |
| webserviceDescription.setId(deployment.getDeploymentId()); |
| } |
| |
| // set service endpoint interface |
| if (portComponent.getServiceEndpointInterface() == null) { |
| portComponent.setServiceEndpointInterface(sessionBean.getServiceEndpoint()); |
| } |
| |
| // default location is /@WebService.serviceName/@WebService.name |
| if (JaxWsUtils.isWebService(ejbClass)) { |
| if (portComponent.getWsdlPort() == null) { |
| portComponent.setWsdlPort(JaxWsUtils.getPortQName(ejbClass)); |
| } |
| if (webserviceDescription.getWsdlFile() == null) { |
| webserviceDescription.setWsdlFile(JaxWsUtils.getServiceWsdlLocation(ejbClass, ejbModule.getClassLoader())); |
| } |
| if (portComponent.getWsdlService() == null) { |
| Definition definition = getWsdl(ejbModule, webserviceDescription.getWsdlFile()); |
| if (definition != null && definition.getServices().size() == 1) { |
| QName serviceQName = (QName) definition.getServices().keySet().iterator().next(); |
| portComponent.setWsdlService(serviceQName); |
| } else { |
| portComponent.setWsdlService(JaxWsUtils.getServiceQName(ejbClass)); |
| } |
| } |
| if (portComponent.getLocation() == null && webserviceDescription.getWsdlFile() != null) { |
| // set location based on wsdl port |
| Definition definition = getWsdl(ejbModule, webserviceDescription.getWsdlFile()); |
| String locationURI = getLocationFromWsdl(definition, portComponent); |
| portComponent.setLocation(locationURI); |
| } |
| if (portComponent.getProtocolBinding() == null) { |
| portComponent.setProtocolBinding(JaxWsUtils.getBindingUriFromAnn(ejbClass)); |
| } |
| |
| // handlers |
| if (portComponent.getHandlerChains() == null) { |
| HandlerChains handlerChains = getHandlerChains(ejbClass, sessionBean.getServiceEndpoint(), ejbModule.getClassLoader()); |
| portComponent.setHandlerChains(handlerChains); |
| |
| } |
| } else { |
| // todo location JAX-RPC services comes from wsdl file |
| } |
| } |
| } |
| |
| private Definition getWsdl(DeploymentModule module, String wsdlFile) { |
| if (wsdlFile == null) return null; |
| |
| Object object = module.getAltDDs().get(wsdlFile); |
| if (object instanceof Definition) { |
| Definition definition = (Definition) object; |
| return definition; |
| } |
| |
| try { |
| URL wsdlUrl; |
| if (object instanceof URL) { |
| wsdlUrl = (URL) object; |
| } else { |
| URL baseUrl = getBaseUrl(module); |
| wsdlUrl = new URL(baseUrl, wsdlFile); |
| } |
| |
| Definition definition = ReadDescriptors.readWsdl(wsdlUrl); |
| module.getAltDDs().put(wsdlFile, definition); |
| return definition; |
| } catch (Exception e) { |
| logger.error("Unable to read wsdl file " + wsdlFile); |
| } |
| |
| return null; |
| } |
| |
| private URL getBaseUrl(DeploymentModule module) throws MalformedURLException { |
| File file = new File(module.getJarLocation()); |
| if (!file.exists()) { |
| return new URL(module.getJarLocation()); |
| } |
| |
| URL baseUrl = file.toURI().toURL(); |
| if (file.isFile()) { |
| baseUrl = new URL("jar", null, baseUrl.toExternalForm() + "!/"); |
| } |
| return baseUrl; |
| } |
| |
| private String getLocationFromWsdl(Definition definition, PortComponent portComponent) { |
| if (definition == null) return null; |
| |
| try { |
| javax.wsdl.Service service = definition.getService(portComponent.getWsdlService()); |
| if (service == null) return null; |
| |
| Port port = service.getPort(portComponent.getWsdlPort().getLocalPart()); |
| if (port == null) return null; |
| |
| for (Object element : port.getExtensibilityElements()) { |
| if (element instanceof SOAPAddress) { |
| SOAPAddress soapAddress = (SOAPAddress) element; |
| URI uri = URLs.uri(soapAddress.getLocationURI()); |
| return uri.getPath(); |
| } else if (element instanceof HTTPAddress) { |
| HTTPAddress httpAddress = (HTTPAddress) element; |
| URI uri = URLs.uri(httpAddress.getLocationURI()); |
| return uri.getPath(); |
| } |
| } |
| } catch (Exception e) { |
| } |
| return null; |
| } |
| |
| public static HandlerChains getHandlerChains(Class<?> declaringClass, String serviceEndpoint, ClassLoader classLoader) throws OpenEJBException { |
| HandlerChain handlerChain = declaringClass.getAnnotation(HandlerChain.class); |
| if (handlerChain == null && serviceEndpoint != null) { |
| try { |
| declaringClass = classLoader.loadClass(serviceEndpoint); |
| handlerChain = declaringClass.getAnnotation(HandlerChain.class); |
| } catch (ClassNotFoundException ignored) { |
| } |
| } |
| HandlerChains handlerChains = null; |
| if (handlerChain != null) { |
| try { |
| URL handlerFileURL = declaringClass.getResource(handlerChain.file()); |
| handlerChains = ReadDescriptors.readHandlerChains(handlerFileURL); |
| } catch (Throwable e) { |
| throw new OpenEJBException("Unable to load handler chain file: " + handlerChain.file(), e); |
| } |
| } |
| return handlerChains; |
| } |
| } |