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.util.ArrayList;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.geronimo.common.DeploymentException;
028    import org.apache.geronimo.j2ee.deployment.Module;
029    import org.apache.geronimo.j2ee.deployment.WebModule;
030    import org.apache.geronimo.jaxws.JAXWSUtils;
031    import org.apache.geronimo.jaxws.PortInfo;
032    import org.apache.geronimo.xbeans.javaee.ServletMappingType;
033    import org.apache.geronimo.xbeans.javaee.ServletType;
034    import org.apache.geronimo.xbeans.javaee.WebAppType;
035    
036    public class AdvancedWARWebServiceFinder implements WebServiceFinder {
037    
038        private static final Log LOG = LogFactory.getLog(AdvancedWARWebServiceFinder.class);
039        
040        public Map<String, PortInfo> discoverWebServices(Module module, 
041                                                         boolean isEJB,
042                                                         Map correctedPortLocations)
043                throws DeploymentException {
044            Map<String, PortInfo> map = new HashMap<String, PortInfo>();
045            discoverPOJOWebServices(module, correctedPortLocations, map);
046            return map;
047        }
048    
049        private void discoverPOJOWebServices(Module module,
050                                             Map portLocations,
051                                             Map<String, PortInfo> map) 
052            throws DeploymentException {
053            ClassLoader classLoader = module.getEarContext().getClassLoader();
054            WebAppType webApp = (WebAppType) module.getSpecDD();
055    
056            if (webApp.isSetMetadataComplete()) {
057                // full web.xml, just examine all servlet entries for web services
058                
059                ServletType[] servletTypes = webApp.getServletArray();
060                for (ServletType servletType : servletTypes) {
061                    String servletName = servletType.getServletName().getStringValue().trim();
062                    PortInfo portInfo = getPortInfo(servletType, classLoader, portLocations);
063                    if (portInfo != null) {
064                        LOG.debug("Found POJO Web Service: " + servletName);
065                        map.put(servletName, portInfo);
066                    }
067                }
068                
069            } else {
070                // partial web.xml, discover all web service classes 
071                
072                Map<String, List<String>> classServletMap = createClassServetMap(webApp);
073                List<Class> services = WARWebServiceFinder.discoverWebServices(module.getModuleFile(), false, classLoader);
074                String contextRoot = ((WebModule) module).getContextRoot();
075                for (Class service : services) {
076                    // skip interfaces and such
077                    if (!JAXWSUtils.isWebService(service)) {
078                        continue;
079                    }
080    
081                    LOG.debug("Discovered POJO Web Service class: " + service.getName());
082                    
083                    List<String> mappedServlets = classServletMap.get(service.getName());
084                    if (mappedServlets == null) {
085                        // no <servlet/> entry, add one
086                        
087                        LOG.debug("POJO Web Service class " + service.getName() + " is not mapped to any servlet");
088                        
089                        ServletType servlet = webApp.addNewServlet();
090                        servlet.addNewServletName().setStringValue(service.getName());
091                        servlet.addNewServletClass().setStringValue(service.getName());
092                        
093                        String location = (String)portLocations.get(service.getName());
094                        if (location == null) {
095                            // add new <servlet-mapping/> element
096                            location = "/" + JAXWSUtils.getServiceName(service);
097                            ServletMappingType servletMapping = webApp.addNewServletMapping();
098                            servletMapping.addNewServletName().setStringValue(service.getName());
099                            servletMapping.addNewUrlPattern().setStringValue(location);
100                        } else {
101                            // weird, there was no servlet entry for this class but 
102                            // servlet-mapping exists
103                            LOG.warn("Found <servlet-mapping> but corresponding <servlet> was not defined");
104                        }
105    
106                        // map service
107                        PortInfo portInfo = new PortInfo();
108                        portInfo.setLocation(contextRoot + location);
109                        map.put(service.getName(), portInfo);
110                    } else {
111                        // found at least one mapped <servlet/> entry
112                        for (String servlet : mappedServlets) {
113                            LOG.debug("POJO Web Service class " + service.getName() + " is mapped to " + servlet + " servlet");
114                            PortInfo portInfo = createPortInfo(servlet, portLocations);
115                            map.put(servlet, portInfo);
116                        }
117                    }                
118                }
119                
120                // double check servlets in case we missed something
121                ServletType[] servletTypes = webApp.getServletArray();
122                for (ServletType servletType : servletTypes) {
123                    String servletName = servletType.getServletName().getStringValue().trim();
124                    if (map.get(servletName) == null) {
125                        PortInfo portInfo = getPortInfo(servletType, classLoader, portLocations);
126                        if (portInfo != null) {
127                            LOG.debug("Found POJO Web Service: " + servletName);
128                            map.put(servletName, portInfo);
129                        }
130                    }
131                }
132            }               
133        } 
134            
135        private PortInfo getPortInfo(ServletType servletType, 
136                                     ClassLoader classLoader, 
137                                     Map portLocations) throws DeploymentException {
138            PortInfo portInfo = null;
139            if (servletType.isSetServletClass()) {
140                String servletClassName = servletType.getServletClass().getStringValue().trim();
141                try {
142                    Class servletClass = classLoader.loadClass(servletClassName);
143                    if (JAXWSUtils.isWebService(servletClass)) {      
144                        String servletName = servletType.getServletName().getStringValue().trim();
145                        portInfo = createPortInfo(servletName, portLocations);
146                    }
147                } catch (ClassNotFoundException e) {
148                    throw new DeploymentException("Failed to load servlet class "
149                                                  + servletClassName, e);
150                }
151            }
152            return portInfo;
153        }
154        
155        private PortInfo createPortInfo(String servlet, Map portLocations) { 
156            PortInfo portInfo = new PortInfo();            
157            String location = (String)portLocations.get(servlet);
158            if (location != null) {
159                portInfo.setLocation(location);
160            }        
161            return portInfo;
162        }
163        
164        /*
165         * Create servlet-class to servlet-names mapping
166         */
167        private Map<String, List<String>> createClassServetMap(WebAppType webApp) {
168            Map<String, List<String>> map = new HashMap<String, List<String>>();
169            
170            ServletType[] servletTypes = webApp.getServletArray();
171            if (servletTypes != null) {
172                for (ServletType servletType : servletTypes) {
173                    String servletName = servletType.getServletName().getStringValue().trim();
174                    if (servletType.isSetServletClass()) {
175                        String servletClassName = servletType.getServletClass().getStringValue().trim();
176                        List<String> servlets = map.get(servletClassName);
177                        if (servlets == null) {
178                            servlets = new ArrayList<String>();
179                            map.put(servletClassName, servlets);
180                        }
181                        servlets.add(servletName);
182                    }
183                }
184            }
185            
186            return map;
187        }
188        
189    }