blob: da16c8438819125e074b2eefab3a167f22d8913d [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.geronimo.jaxws.builder;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBException;
import javax.xml.ws.http.HTTPBinding;
import javax.xml.ws.soap.AddressingFeature;
import org.apache.geronimo.common.DeploymentException;
import org.apache.geronimo.deployment.Deployable;
import org.apache.geronimo.deployment.DeploymentContext;
import org.apache.geronimo.deployment.service.EnvironmentBuilder;
import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.gbean.GBeanData;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.j2ee.annotation.Holder;
import org.apache.geronimo.j2ee.deployment.EARContext;
import org.apache.geronimo.j2ee.deployment.Module;
import org.apache.geronimo.j2ee.deployment.NamingBuilder;
import org.apache.geronimo.j2ee.deployment.WebModule;
import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
import org.apache.geronimo.jaxws.JAXWSEJBApplicationContext;
import org.apache.geronimo.jaxws.JAXWSUtils;
import org.apache.geronimo.jaxws.JAXWSWebApplicationContext;
import org.apache.geronimo.jaxws.PortInfo;
import org.apache.geronimo.jaxws.annotations.AnnotationHolder;
import org.apache.geronimo.jaxws.feature.AddressingFeatureInfo;
import org.apache.geronimo.jaxws.feature.MTOMFeatureInfo;
import org.apache.geronimo.jaxws.feature.RespectBindingFeatureInfo;
import org.apache.geronimo.jaxws.handler.HandlerChainsInfoBuilder;
import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
import org.apache.geronimo.kernel.GBeanNotFoundException;
import org.apache.geronimo.kernel.repository.Environment;
import org.apache.geronimo.kernel.util.IOUtils;
import org.apache.openejb.jee.Addressing;
import org.apache.openejb.jee.JaxbJavaee;
import org.apache.openejb.jee.PortComponent;
import org.apache.openejb.jee.ServiceImplBean;
import org.apache.openejb.jee.WebserviceDescription;
import org.apache.openejb.jee.Webservices;
import org.osgi.framework.Bundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class JAXWSServiceBuilder implements WebServiceBuilder {
private static final Logger LOG = LoggerFactory.getLogger(JAXWSServiceBuilder.class);
private HandlerChainsInfoBuilder handlerChainsInfoBuilder = new HandlerChainsInfoBuilder();
protected final Environment defaultEnvironment;
protected WebServiceFinder webServiceFinder;
public JAXWSServiceBuilder(Environment defaultEnvironment) {
this.defaultEnvironment = defaultEnvironment;
}
protected void setWebServiceFinder(WebServiceFinder finder) {
this.webServiceFinder = finder;
}
protected String getKey() {
return getClass().getName();
}
@Override
public void findWebServices(Module module, boolean isEJB, Map<String, String> servletLocations, Environment environment, Map sharedContext) throws DeploymentException {
Map<String, PortInfo> serviceLinkPortInfoMap = discoverWebServices(module, isEJB, servletLocations);
String path = isEJB ? "META-INF/webservices.xml" : "WEB-INF/webservices.xml";
Deployable deployable = module.getDeployable();
URL wsDDUrl = deployable.getResource(path);
if (wsDDUrl != null) {
InputStream in = null;
try {
in = new BufferedInputStream(wsDDUrl.openStream());
Webservices wst = (Webservices) JaxbJavaee.unmarshalJavaee(Webservices.class, in);
for (WebserviceDescription desc : wst.getWebserviceDescription()) {
String wsdlFile = null;
if (desc.getWsdlFile() != null) {
wsdlFile = getString(desc.getWsdlFile());
}
String serviceName = desc.getWebserviceDescriptionName();
for (PortComponent port : desc.getPortComponent()) {
String serviceLink = null;
ServiceImplBean beanType = port.getServiceImplBean();
if (beanType.getEjbLink() != null) {
serviceLink = beanType.getEjbLink();
} else if (beanType.getServletLink() != null) {
serviceLink = beanType.getServletLink();
}
PortInfo portInfo = serviceLinkPortInfoMap.get(serviceLink);
if (portInfo == null) {
portInfo = new PortInfo();
portInfo.setServiceLink(serviceLink);
serviceLinkPortInfoMap.put(serviceLink, portInfo);
}
if (port.getServiceEndpointInterface() != null) {
String sei = port.getServiceEndpointInterface();
portInfo.setServiceEndpointInterfaceName(sei);
}
if (port.getPortComponentName() != null) {
portInfo.setPortName(port.getPortComponentName());
}
if (port.getProtocolBinding() != null) {
portInfo.setProtocolBinding(port.getProtocolBinding());
}
portInfo.setServiceName(serviceName);
if (wsdlFile != null) {
portInfo.setWsdlFile(wsdlFile);
}
if (port.getHandlerChains() != null) {
portInfo.setHandlerChainsInfo(handlerChainsInfoBuilder.build(port.getHandlerChains()));
}
if (port.getWsdlPort() != null) {
portInfo.setWsdlPort(port.getWsdlPort());
}
if (port.getWsdlService() != null) {
portInfo.setWsdlService(port.getWsdlService());
}
String location = servletLocations.get(serviceLink);
portInfo.setLocation(location);
Addressing addressing = port.getAddressing();
if (addressing != null) {
AddressingFeatureInfo addressingFeatureInfo = portInfo.getAddressingFeatureInfo();
if (addressingFeatureInfo == null) {
addressingFeatureInfo = new AddressingFeatureInfo();
portInfo.setAddressingFeatureInfo(addressingFeatureInfo);
}
if (addressing.getEnabled() != null) {
addressingFeatureInfo.setEnabled(addressing.getEnabled());
}
if (addressing.getRequired() != null) {
addressingFeatureInfo.setRequired(addressing.getRequired());
}
if (addressing.getResponses() != null) {
addressingFeatureInfo.setResponses(AddressingFeature.Responses.valueOf(addressing.getResponses().name()));
}
}
if (port.getEnableMtom() != null || port.getMtomThreshold() != null) {
MTOMFeatureInfo mtomFeatureInfo = portInfo.getMtomFeatureInfo();
if (mtomFeatureInfo == null) {
mtomFeatureInfo = new MTOMFeatureInfo();
portInfo.setMtomFeatureInfo(mtomFeatureInfo);
}
if (port.getEnableMtom() != null) {
mtomFeatureInfo.setEnabled(port.getEnableMtom());
}
if (port.getMtomThreshold() != null) {
mtomFeatureInfo.setThreshold(port.getMtomThreshold());
}
}
if (port.getRespectBinding() != null && port.getRespectBinding().getEnabled() != null) {
RespectBindingFeatureInfo respectBindingFeatureInfo = portInfo.getRespectBindingFeatureInfo();
if (respectBindingFeatureInfo == null) {
respectBindingFeatureInfo = new RespectBindingFeatureInfo();
portInfo.setRespectBindingFeatureInfo(respectBindingFeatureInfo);
}
respectBindingFeatureInfo.setEnabled(port.getRespectBinding().getEnabled());
}
}
}
} catch (JAXBException e) {
//we hope it's jax-rpc
LOG.debug("Descriptor ignored (not a Java EE 5 descriptor)");
} catch (Exception e) {
throw new DeploymentException("Failed to parse " + path, e);
} finally {
IOUtils.close(in);
}
}
if (serviceLinkPortInfoMap != null && !serviceLinkPortInfoMap.isEmpty()) {
EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
sharedContext.put(getKey(), serviceLinkPortInfoMap);
}
}
private String getString(String in) {
if (in != null) {
in = in.trim();
if (in.length() == 0) {
return null;
}
}
return in;
}
private Map<String, PortInfo> discoverWebServices(Module module,
boolean isEJB,
Map<String, String> correctedPortLocations)
throws DeploymentException {
if (webServiceFinder == null) {
throw new DeploymentException("WebServiceFinder not configured");
}
return webServiceFinder.discoverWebServices(module, correctedPortLocations);
}
@Override
public boolean configurePOJO(GBeanData targetGBean,
String servletName,
Module module,
String servletClassName,
DeploymentContext context)
throws DeploymentException {
Map sharedContext = ((WebModule) module).getSharedContext();
Map<String, PortInfo> portInfoMap = (Map<String, PortInfo>) sharedContext.get(getKey());
if (portInfoMap == null) {
// not ours
return false;
}
PortInfo portInfo = portInfoMap.get(servletName);
if (portInfo == null) {
// not ours
return false;
}
// verify that the class is loadable and is a JAX-WS web service
Bundle bundle = context.getDeploymentBundle();
Class<?> servletClass = loadClass(servletClassName, bundle);
if (!JAXWSUtils.isWebService(servletClass)) {
return false;
}
Map<String, PortInfo> servletNamePortInfoMap = null;
AbstractName jaxwsWebApplicationContextName = context.getNaming().createChildName(module.getModuleName(), "JAXWSWebApplicationContext", "JAXWSWebApplicationContext");
try {
servletNamePortInfoMap = (Map<String, PortInfo>)(context.getGBeanInstance(jaxwsWebApplicationContextName).getAttribute("servletNamePortInfoMap"));
} catch (GBeanNotFoundException e) {
GBeanData jaxwsWebApplicationContextGBeanData = new GBeanData(jaxwsWebApplicationContextName, JAXWSWebApplicationContext.class);
try {
context.addGBean(jaxwsWebApplicationContextGBeanData);
} catch (GBeanAlreadyExistsException e1) {
}
servletNamePortInfoMap = new HashMap<String, PortInfo>();
jaxwsWebApplicationContextGBeanData.setAttribute("servletNamePortInfoMap", servletNamePortInfoMap);
}
targetGBean.addDependency(jaxwsWebApplicationContextName);
servletNamePortInfoMap.put(servletName, portInfo);
Map componentContext = null;
Holder moduleHolder = null;
try {
//TODO Now we share the same DeploymentContext in the ear package, which means all the gbeans are saved in the one EARContext
//Might need to update while we have real EAR support
moduleHolder = (Holder) module.getSharedContext().get(NamingBuilder.INJECTION_KEY);
GBeanData contextSourceGBean = context.getGBeanInstance(context.getNaming().createChildName(module.getModuleName(), "ContextSource", "ContextSource"));
componentContext = (Map) contextSourceGBean.getAttribute("componentContext");
} catch (GBeanNotFoundException e) {
LOG.warn("ModuleGBean not found. JNDI resource injection will not work.");
}
AnnotationHolder serviceHolder =
(AnnotationHolder)sharedContext.get(WebServiceContextAnnotationHelper.class.getName());
if (serviceHolder == null) {
serviceHolder = new AnnotationHolder(moduleHolder);
sharedContext.put(WebServiceContextAnnotationHelper.class.getName(), serviceHolder);
}
WebServiceContextAnnotationHelper.addWebServiceContextInjections(serviceHolder, servletClass);
String location = portInfo.getLocation();
LOG.info("Configuring JAX-WS Web Service: " + servletName + " at " + location);
AbstractName containerFactoryName = context.getNaming().createChildName(targetGBean.getAbstractName(), getContainerFactoryGBeanInfo().getName(), GBeanInfoBuilder.DEFAULT_J2EE_TYPE);
GBeanData containerFactoryData = new GBeanData(containerFactoryName, getContainerFactoryGBeanInfo());
containerFactoryData.setAttribute("portInfo", portInfo);
containerFactoryData.setAttribute("endpointClassName", servletClassName);
containerFactoryData.setAttribute("componentContext", componentContext);
containerFactoryData.setAttribute("holder", serviceHolder);
containerFactoryData.setAttribute("contextRoot", ((WebModule) module).getContextRoot());
containerFactoryData.setAttribute("catalogName", JAXWSBuilderUtils.normalizeCatalogPath(module, JAXWSUtils.DEFAULT_CATALOG_WEB));
try {
context.addGBean(containerFactoryData);
} catch (GBeanAlreadyExistsException e) {
throw new DeploymentException("Could not add web service container factory gbean", e);
}
targetGBean.setReferencePattern("WebServiceContainerFactory", containerFactoryName);
// our web container does not use that property
targetGBean.setAttribute("pojoClassName", "java.lang.Object");
if (context instanceof EARContext) {
containerFactoryData.setReferencePattern("TransactionManager",
((EARContext)context).getTransactionManagerName());
}
initialize(containerFactoryData, servletClass, portInfo, module, bundle);
return true;
}
protected abstract GBeanInfo getContainerFactoryGBeanInfo();
@Override
public boolean configureEJB(GBeanData targetGBean,
String ejbName,
Module module,
Map sharedContext,
Bundle bundle)
throws DeploymentException {
Map<String, PortInfo> portInfoMap = (Map<String, PortInfo>) sharedContext.get(getKey());
if (portInfoMap == null) {
// not ours
return false;
}
PortInfo portInfo = portInfoMap.get(ejbName);
if (portInfo == null) {
// not ours
return false;
}
String beanClassName = (String)targetGBean.getAttribute("ejbClass");
// verify that the class is loadable and is a JAX-WS web service
Class<?> beanClass = loadClass(beanClassName, bundle);
if (!JAXWSUtils.isWebService(beanClass)) {
return false;
}
String location = portInfo.getLocation();
if (location == null) {
throw new DeploymentException("Endpoint URI for EJB WebService is missing");
}
Map<String, PortInfo> ejbNamePortInfoMap = null;
DeploymentContext context = module.getEarContext();
AbstractName jaxwsEJBApplicationContextName = context.getNaming().createChildName(module.getModuleName(), "JAXWSEJBApplicationContext", "JAXWSEJBApplicationContext");
try {
ejbNamePortInfoMap = (Map<String, PortInfo>)(context.getGBeanInstance(jaxwsEJBApplicationContextName).getAttribute("ejbNamePortInfoMap"));
} catch (GBeanNotFoundException e) {
GBeanData jaxwsEJBApplicationContextGBeanData = new GBeanData(jaxwsEJBApplicationContextName, JAXWSEJBApplicationContext.class);
try {
context.addGBean(jaxwsEJBApplicationContextGBeanData);
} catch (GBeanAlreadyExistsException e1) {
}
ejbNamePortInfoMap = new HashMap<String, PortInfo>();
jaxwsEJBApplicationContextGBeanData.setAttribute("ejbNamePortInfoMap", ejbNamePortInfoMap);
}
targetGBean.addDependency(jaxwsEJBApplicationContextName);
ejbNamePortInfoMap.put(ejbName, portInfo);
LOG.info("Configuring EJB JAX-WS Web Service: " + ejbName + " at " + location);
targetGBean.setAttribute("portInfo", portInfo);
targetGBean.setAttribute("catalogName", JAXWSBuilderUtils.normalizeCatalogPath(module, JAXWSUtils.DEFAULT_CATALOG_EJB));
initialize(targetGBean, beanClass, portInfo, module, bundle);
return true;
}
protected void initialize(GBeanData targetGBean, Class wsClass, PortInfo info, Module module, Bundle bundle) throws DeploymentException {
}
Class<?> loadClass(String className, Bundle bundle) throws DeploymentException {
try {
return bundle.loadClass(className);
} catch (ClassNotFoundException ex) {
throw new DeploymentException("Unable to load Web Service class: " + className, ex);
}
}
protected boolean isWsdlSet(PortInfo portInfo, Class serviceClass, Bundle bundle) {
return (portInfo.getWsdlFile() != null && !portInfo.getWsdlFile().trim().equals("")) || JAXWSUtils.containsWsdlLocation(serviceClass, bundle);
}
protected boolean isHTTPBinding(PortInfo portInfo, Class serviceClass) {
String bindingURI = "";
String bindingURIFromAnnot;
if (portInfo.getProtocolBinding() != null) {
bindingURI = JAXWSUtils.getBindingURI(portInfo.getProtocolBinding());
}
bindingURIFromAnnot = JAXWSUtils.getBindingURIFromAnnot(serviceClass);
if (bindingURI != null && !bindingURI.trim().equals("")) {
return bindingURI.equals(HTTPBinding.HTTP_BINDING);
} else if (bindingURIFromAnnot != null && !bindingURIFromAnnot.trim().equals("")) {
return bindingURIFromAnnot.equals(HTTPBinding.HTTP_BINDING);
}
return false;
}
}