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.File;
021    import java.io.IOException;
022    import java.net.MalformedURLException;
023    import java.net.URL;
024    import java.util.ArrayList;
025    import java.util.Enumeration;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.jar.JarEntry;
029    import java.util.jar.JarFile;
030    
031    import javax.jws.WebService;
032    import javax.xml.ws.WebServiceProvider;
033    
034    import org.apache.commons.logging.Log;
035    import org.apache.commons.logging.LogFactory;
036    import org.apache.geronimo.common.DeploymentException;
037    import org.apache.geronimo.deployment.util.DeploymentUtil;
038    import org.apache.geronimo.deployment.util.NestedJarFile;
039    import org.apache.geronimo.deployment.util.UnpackedJarFile;
040    import org.apache.geronimo.j2ee.deployment.Module;
041    import org.apache.geronimo.jaxws.PortInfo;
042    import org.apache.geronimo.kernel.classloader.JarFileClassLoader;
043    import org.apache.xbean.finder.ClassFinder;
044    
045    public class WARWebServiceFinder implements WebServiceFinder {
046    
047        private static final Log LOG = LogFactory.getLog(WARWebServiceFinder.class);
048        
049        private static final WebServiceFinder webServiceFinder = getWebServiceFinder();
050                    
051        private static WebServiceFinder getWebServiceFinder() {
052            boolean useSimpleFinder = 
053                Boolean.getBoolean("org.apache.geronimo.jaxws.builder.useSimpleFinder");
054            
055            WebServiceFinder webServiceFinder = null;
056            
057            if (useSimpleFinder) {
058                webServiceFinder = new SimpleWARWebServiceFinder();
059            } else {
060                webServiceFinder = new AdvancedWARWebServiceFinder();
061            }
062            
063            return webServiceFinder;
064        }
065        
066        public Map<String, PortInfo> discoverWebServices(Module module, 
067                                                         boolean isEJB,
068                                                         Map correctedPortLocations)
069                throws DeploymentException {                
070            return webServiceFinder.discoverWebServices(module, isEJB, correctedPortLocations);
071        }
072    
073        /**
074         * Returns a list of any classes annotated with @WebService or
075         * @WebServiceProvider annotation.
076         */
077        static List<Class> discoverWebServices(JarFile moduleFile,
078                                               boolean isEJB,
079                                               ClassLoader parentClassLoader)                                                      
080                throws DeploymentException {
081            LOG.debug("Discovering web service classes");
082    
083            File tmpDir = null;
084            List<URL> urlList = new ArrayList<URL>();
085            if (isEJB) {
086                File jarFile = new File(moduleFile.getName());
087                try {
088                    urlList.add(jarFile.toURL());
089                } catch (MalformedURLException e) {
090                    // this should not happen
091                    throw new DeploymentException(e);
092                }
093            } else {
094                File baseDir = null;
095                
096                if (moduleFile instanceof UnpackedJarFile) {
097                    // war directory is being deployed (--inPlace)
098                    baseDir = ((UnpackedJarFile)moduleFile).getBaseDir();
099                } else if (moduleFile instanceof NestedJarFile && ((NestedJarFile)moduleFile).isUnpacked()) {
100                    // ear directory is being deployed (--inPlace)
101                    baseDir = new File(moduleFile.getName());                
102                } else {
103                    // war file or ear file is being deployed                
104                    /*
105                     * Can't get ClassLoader to load nested Jar files, so
106                     * unpack the module Jar file and discover all nested Jar files
107                     * within it and the classes/ directory.
108                     */
109                    try {
110                        tmpDir = DeploymentUtil.createTempDir();
111                        /*
112                         * This is needed becuase DeploymentUtil.unzipToDirectory()
113                         * always closes the passed JarFile.
114                         */
115                        JarFile module = new JarFile(moduleFile.getName());
116                        DeploymentUtil.unzipToDirectory(module, tmpDir);
117                    } catch (IOException e) {
118                        if (tmpDir != null) {
119                            DeploymentUtil.recursiveDelete(tmpDir);
120                        }
121                        throw new DeploymentException("Failed to expand the module archive", e);
122                    }
123                    
124                    baseDir = tmpDir;
125                }
126    
127                // create URL list
128                Enumeration<JarEntry> jarEnum = moduleFile.entries();
129                while (jarEnum.hasMoreElements()) {
130                    JarEntry entry = jarEnum.nextElement();
131                    String name = entry.getName();
132                    if (name.equals("WEB-INF/classes/")) {
133                        // ensure it is first
134                        File classesDir = new File(baseDir, "WEB-INF/classes/");
135                        try {
136                            urlList.add(0, classesDir.toURL());
137                        } catch (MalformedURLException e) {
138                            // this should not happen, ignore
139                        }
140                    } else if (name.startsWith("WEB-INF/lib/")
141                            && name.endsWith(".jar")) {
142                        File jarFile = new File(baseDir, name);
143                        try {
144                            urlList.add(jarFile.toURL());
145                        } catch (MalformedURLException e) {
146                            // this should not happen, ignore
147                        }
148                    }
149                }
150            }
151            
152            URL[] urls = urlList.toArray(new URL[] {});
153            JarFileClassLoader tempClassLoader = new JarFileClassLoader(null, urls, parentClassLoader);
154            ClassFinder classFinder = new ClassFinder(tempClassLoader, urlList);
155    
156            List<Class> classes = new ArrayList<Class>();
157    
158            classes.addAll(classFinder.findAnnotatedClasses(WebService.class));
159            classes.addAll(classFinder.findAnnotatedClasses(WebServiceProvider.class));       
160    
161            tempClassLoader.destroy();
162    
163            if (tmpDir != null) {
164                DeploymentUtil.recursiveDelete(tmpDir);
165            }
166    
167            return classes;
168        }
169    }