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: */package org.apache.geronimo.jaxws.builder;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.ArrayList;
023: import java.util.Enumeration;
024: import java.util.HashMap;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.jar.JarEntry;
028: import java.util.jar.JarFile;
029:
030: import javax.jws.WebService;
031: import javax.xml.ws.WebServiceProvider;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.apache.geronimo.common.DeploymentException;
036: import org.apache.geronimo.deployment.util.DeploymentUtil;
037: import org.apache.geronimo.j2ee.deployment.Module;
038: import org.apache.geronimo.j2ee.deployment.WebModule;
039: import org.apache.geronimo.jaxws.JAXWSUtils;
040: import org.apache.geronimo.jaxws.PortInfo;
041: import org.apache.geronimo.kernel.classloader.JarFileClassLoader;
042: import org.apache.geronimo.xbeans.javaee.ServletMappingType;
043: import org.apache.geronimo.xbeans.javaee.ServletType;
044: import org.apache.geronimo.xbeans.javaee.WebAppType;
045: import org.apache.xbean.finder.ClassFinder;
046:
047: public class WARWebServiceFinder implements WebServiceFinder {
048:
049: private static final Log LOG = LogFactory
050: .getLog(WARWebServiceFinder.class);
051:
052: public Map<String, PortInfo> discoverWebServices(Module module,
053: boolean isEJB, Map correctedPortLocations)
054: throws DeploymentException {
055: Map<String, PortInfo> map = new HashMap<String, PortInfo>();
056: discoverPOJOWebServices(module, correctedPortLocations, map);
057: return map;
058: }
059:
060: private void discoverPOJOWebServices(Module module,
061: Map correctedPortLocations, Map<String, PortInfo> map)
062: throws DeploymentException {
063: ClassLoader classLoader = module.getEarContext()
064: .getClassLoader();
065: WebAppType webApp = (WebAppType) module.getSpecDD();
066:
067: // find web services
068: ServletType[] servletTypes = webApp.getServletArray();
069:
070: if (webApp.getDomNode().getChildNodes().getLength() == 0) {
071: // web.xml not present (empty really), discover annotated
072: // classes and update DD
073: List<Class> services = discoverWebServices(module
074: .getModuleFile(), false);
075: String contextRoot = ((WebModule) module).getContextRoot();
076: for (Class service : services) {
077: // skip interfaces and such
078: if (!JAXWSUtils.isWebService(service)) {
079: continue;
080: }
081:
082: LOG.debug("Discovered POJO Web Service: "
083: + service.getName());
084:
085: // add new <servlet/> element
086: ServletType servlet = webApp.addNewServlet();
087: servlet.addNewServletName().setStringValue(
088: service.getName());
089: servlet.addNewServletClass().setStringValue(
090: service.getName());
091:
092: // add new <servlet-mapping/> element
093: String location = "/"
094: + JAXWSUtils.getServiceName(service);
095: ServletMappingType servletMapping = webApp
096: .addNewServletMapping();
097: servletMapping.addNewServletName().setStringValue(
098: service.getName());
099: servletMapping.addNewUrlPattern().setStringValue(
100: location);
101:
102: // map service
103: PortInfo portInfo = new PortInfo();
104: portInfo.setLocation(contextRoot + location);
105: map.put(service.getName(), portInfo);
106: }
107: } else {
108: // web.xml present, examine servlet classes and check for web
109: // services
110: for (ServletType servletType : servletTypes) {
111: String servletName = servletType.getServletName()
112: .getStringValue().trim();
113: if (servletType.isSetServletClass()) {
114: String servletClassName = servletType
115: .getServletClass().getStringValue().trim();
116: try {
117: Class servletClass = classLoader
118: .loadClass(servletClassName);
119: if (JAXWSUtils.isWebService(servletClass)) {
120: LOG.debug("Found POJO Web Service: "
121: + servletName);
122: PortInfo portInfo = new PortInfo();
123: map.put(servletName, portInfo);
124: }
125: } catch (Exception e) {
126: throw new DeploymentException(
127: "Failed to load servlet class "
128: + servletClassName, e);
129: }
130: }
131: }
132:
133: // update web service locations
134: for (Map.Entry entry : map.entrySet()) {
135: String servletName = (String) entry.getKey();
136: PortInfo portInfo = (PortInfo) entry.getValue();
137:
138: String location = (String) correctedPortLocations
139: .get(servletName);
140: if (location != null) {
141: portInfo.setLocation(location);
142: }
143: }
144: }
145: }
146:
147: /**
148: * Returns a list of any classes annotated with @WebService or
149: * @WebServiceProvider annotation.
150: */
151: private List<Class> discoverWebServices(JarFile moduleFile,
152: boolean isEJB) throws DeploymentException {
153: LOG.debug("Discovering web service classes");
154:
155: File tmpDir = null;
156: List<URL> urlList = new ArrayList<URL>();
157: if (isEJB) {
158: File jarFile = new File(moduleFile.getName());
159: try {
160: urlList.add(jarFile.toURL());
161: } catch (MalformedURLException e) {
162: // this should not happen
163: throw new DeploymentException(e);
164: }
165: } else {
166: /*
167: * Can't get ClassLoader to load nested Jar files, so
168: * unpack the module Jar file and discover all nested Jar files
169: * within it and the classes/ directory.
170: */
171: try {
172: tmpDir = DeploymentUtil.createTempDir();
173: /*
174: * This is needed becuase DeploymentUtil.unzipToDirectory()
175: * always closes the passed JarFile.
176: */
177: JarFile module = new JarFile(moduleFile.getName());
178: DeploymentUtil.unzipToDirectory(module, tmpDir);
179: } catch (IOException e) {
180: if (tmpDir != null) {
181: DeploymentUtil.recursiveDelete(tmpDir);
182: }
183: throw new DeploymentException(
184: "Failed to expand the module archive", e);
185: }
186:
187: // create URL list
188: Enumeration<JarEntry> jarEnum = moduleFile.entries();
189: while (jarEnum.hasMoreElements()) {
190: JarEntry entry = jarEnum.nextElement();
191: String name = entry.getName();
192: if (name.equals("WEB-INF/classes/")) {
193: // ensure it is first
194: File classesDir = new File(tmpDir,
195: "WEB-INF/classes/");
196: try {
197: urlList.add(0, classesDir.toURL());
198: } catch (MalformedURLException e) {
199: // this should not happen, ignore
200: }
201: } else if (name.startsWith("WEB-INF/lib/")
202: && name.endsWith(".jar")) {
203: File jarFile = new File(tmpDir, name);
204: try {
205: urlList.add(jarFile.toURL());
206: } catch (MalformedURLException e) {
207: // this should not happen, ignore
208: }
209: }
210: }
211: }
212:
213: URL[] urls = urlList.toArray(new URL[] {});
214: JarFileClassLoader tempClassLoader = new JarFileClassLoader(
215: null, urls, this .getClass().getClassLoader());
216: ClassFinder classFinder = new ClassFinder(tempClassLoader,
217: urlList);
218:
219: List<Class> classes = new ArrayList<Class>();
220:
221: classes.addAll(classFinder
222: .findAnnotatedClasses(WebService.class));
223: classes.addAll(classFinder
224: .findAnnotatedClasses(WebServiceProvider.class));
225:
226: tempClassLoader.destroy();
227:
228: if (tmpDir != null) {
229: DeploymentUtil.recursiveDelete(tmpDir);
230: }
231:
232: return classes;
233: }
234: }
|