001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.jaxws.builder;
019
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.net.URL;
023 import java.util.Map;
024 import java.util.jar.JarFile;
025
026 import org.apache.commons.logging.Log;
027 import org.apache.commons.logging.LogFactory;
028 import org.apache.geronimo.common.DeploymentException;
029 import org.apache.geronimo.deployment.DeploymentContext;
030 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
031 import org.apache.geronimo.deployment.util.DeploymentUtil;
032 import org.apache.geronimo.gbean.AbstractName;
033 import org.apache.geronimo.gbean.GBeanData;
034 import org.apache.geronimo.gbean.GBeanInfo;
035 import org.apache.geronimo.j2ee.annotation.Holder;
036 import org.apache.geronimo.j2ee.deployment.EARContext;
037 import org.apache.geronimo.j2ee.deployment.Module;
038 import org.apache.geronimo.j2ee.deployment.WebModule;
039 import org.apache.geronimo.j2ee.deployment.WebServiceBuilder;
040 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
041 import org.apache.geronimo.jaxws.JAXWSUtils;
042 import org.apache.geronimo.jaxws.PortInfo;
043 import org.apache.geronimo.jaxws.annotations.AnnotationHolder;
044 import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
045 import org.apache.geronimo.kernel.GBeanNotFoundException;
046 import org.apache.geronimo.kernel.repository.Environment;
047
048 public abstract class JAXWSServiceBuilder implements WebServiceBuilder {
049 private static final Log LOG = LogFactory.getLog(JAXWSServiceBuilder.class);
050
051 protected final Environment defaultEnvironment;
052 protected WebServiceFinder webServiceFinder;
053
054 public JAXWSServiceBuilder(Environment defaultEnvironment) {
055 this.defaultEnvironment = defaultEnvironment;
056 }
057
058 protected void setWebServiceFinder(WebServiceFinder finder) {
059 this.webServiceFinder = finder;
060 }
061
062 protected String getKey() {
063 return getClass().getName();
064 }
065
066 public void findWebServices(Module module,
067 boolean isEJB,
068 Map servletLocations,
069 Environment environment,
070 Map sharedContext) throws DeploymentException {
071 Map portMap = null;
072 String path = isEJB ? "META-INF/webservices.xml" : "WEB-INF/webservices.xml";
073 JarFile moduleFile = module.getModuleFile();
074 try {
075 URL wsDDUrl = DeploymentUtil.createJarURL(moduleFile, path);
076 InputStream in = wsDDUrl.openStream();
077 portMap = parseWebServiceDescriptor(in, wsDDUrl, moduleFile, isEJB, servletLocations);
078 } catch (IOException e) {
079 // webservices.xml does not exist
080 portMap = discoverWebServices(module, isEJB, servletLocations);
081 }
082
083 if (portMap != null && !portMap.isEmpty()) {
084 EnvironmentBuilder.mergeEnvironments(environment, defaultEnvironment);
085 sharedContext.put(getKey(), portMap);
086 }
087
088 }
089
090 private Map<String, PortInfo> discoverWebServices(Module module,
091 boolean isEJB,
092 Map correctedPortLocations)
093 throws DeploymentException {
094 if (this.webServiceFinder == null) {
095 throw new DeploymentException("WebServiceFinder not configured");
096 }
097 return this.webServiceFinder.discoverWebServices(module, isEJB, correctedPortLocations);
098 }
099
100 protected abstract Map<String, PortInfo> parseWebServiceDescriptor(InputStream in,
101 URL wsDDUrl,
102 JarFile moduleFile,
103 boolean isEJB,
104 Map correctedPortLocations)
105 throws DeploymentException;
106
107 public boolean configurePOJO(GBeanData targetGBean,
108 String servletName,
109 Module module,
110 String servletClassName,
111 DeploymentContext context)
112 throws DeploymentException {
113 Map sharedContext = ((WebModule) module).getSharedContext();
114 Map portInfoMap = (Map) sharedContext.get(getKey());
115 if (portInfoMap == null) {
116 // not ours
117 return false;
118 }
119 PortInfo portInfo = (PortInfo) portInfoMap.get(servletName);
120 if (portInfo == null) {
121 // not ours
122 return false;
123 }
124
125 // verify that the class is loadable and is a JAX-WS web service
126 ClassLoader classLoader = context.getClassLoader();
127 Class servletClass = loadClass(servletClassName, classLoader);
128 if (!JAXWSUtils.isWebService(servletClass)) {
129 return false;
130 }
131
132 Map componentContext = null;
133 Holder moduleHolder = null;
134 try {
135 GBeanData moduleGBean = context.getGBeanInstance(context.getModuleName());
136 componentContext = (Map)moduleGBean.getAttribute("componentContext");
137 moduleHolder = (Holder)moduleGBean.getAttribute("holder");
138 } catch (GBeanNotFoundException e) {
139 LOG.warn("ModuleGBean not found. JNDI resource injection will not work.");
140 }
141
142 AnnotationHolder serviceHolder =
143 (AnnotationHolder)sharedContext.get(WebServiceContextAnnotationHelper.class.getName());
144 if (serviceHolder == null) {
145 serviceHolder = new AnnotationHolder(moduleHolder);
146 sharedContext.put(WebServiceContextAnnotationHelper.class.getName(), serviceHolder);
147 }
148 WebServiceContextAnnotationHelper.addWebServiceContextInjections(serviceHolder, servletClass);
149
150 String location = portInfo.getLocation();
151 LOG.info("Configuring JAX-WS Web Service: " + servletName + " at " + location);
152
153 AbstractName containerFactoryName = context.getNaming().createChildName(targetGBean.getAbstractName(), getContainerFactoryGBeanInfo().getName(), NameFactory.GERONIMO_SERVICE);
154 GBeanData containerFactoryData = new GBeanData(containerFactoryName, getContainerFactoryGBeanInfo());
155 containerFactoryData.setAttribute("portInfo", portInfo);
156 containerFactoryData.setAttribute("endpointClassName", servletClassName);
157 containerFactoryData.setAttribute("componentContext", componentContext);
158 containerFactoryData.setAttribute("holder", serviceHolder);
159 containerFactoryData.setAttribute("contextRoot", ((WebModule) module).getContextRoot());
160 try {
161 context.addGBean(containerFactoryData);
162 } catch (GBeanAlreadyExistsException e) {
163 throw new DeploymentException("Could not add web service container factory gbean", e);
164 }
165
166 targetGBean.setReferencePattern("WebServiceContainerFactory", containerFactoryName);
167 // our web container does not use that property
168 targetGBean.setAttribute("pojoClassName", "java.lang.Object");
169
170 if (context instanceof EARContext) {
171 containerFactoryData.setReferencePattern("TransactionManager",
172 ((EARContext)context).getTransactionManagerName());
173 }
174
175 initialize(containerFactoryData, servletClass, portInfo, module);
176
177 return true;
178 }
179
180 protected abstract GBeanInfo getContainerFactoryGBeanInfo();
181
182 public boolean configureEJB(GBeanData targetGBean,
183 String ejbName,
184 Module module,
185 Map sharedContext,
186 ClassLoader classLoader)
187 throws DeploymentException {
188 Map portInfoMap = (Map) sharedContext.get(getKey());
189 if (portInfoMap == null) {
190 // not ours
191 return false;
192 }
193 PortInfo portInfo = (PortInfo) portInfoMap.get(ejbName);
194 if (portInfo == null) {
195 // not ours
196 return false;
197 }
198
199 String beanClassName = (String)targetGBean.getAttribute("ejbClass");
200 // verify that the class is loadable and is a JAX-WS web service
201 Class beanClass = loadClass(beanClassName, classLoader);
202 if (!JAXWSUtils.isWebService(beanClass)) {
203 return false;
204 }
205
206 String location = portInfo.getLocation();
207 if (location == null) {
208 throw new DeploymentException("Endpoint URI for EJB WebService is missing");
209 }
210
211 LOG.info("Configuring EJB JAX-WS Web Service: " + ejbName + " at " + location);
212
213 targetGBean.setAttribute("portInfo", portInfo);
214
215 initialize(targetGBean, beanClass, portInfo, module);
216
217 return true;
218 }
219
220 protected void initialize(GBeanData targetGBean, Class wsClass, PortInfo info, Module module)
221 throws DeploymentException {
222 }
223
224 Class<?> loadClass(String className, ClassLoader loader) throws DeploymentException {
225 try {
226 return loader.loadClass(className);
227 } catch (ClassNotFoundException ex) {
228 throw new DeploymentException("Unable to load Web Service class: " + className, ex);
229 }
230 }
231 }