blob: db1271ad71ebab4e339cbf8fc32caca54be891cd [file] [log] [blame]
/*
* 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;
}
}