View Javadoc
1   package org.codehaus.mojo.gwt.webxml;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.LinkedHashSet;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.codehaus.plexus.component.annotations.Component;
29  import org.codehaus.plexus.logging.AbstractLogEnabled;
30  import org.springframework.core.io.Resource;
31  import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
32  import org.springframework.core.io.support.ResourcePatternResolver;
33  import org.springframework.core.type.classreading.MetadataReader;
34  import org.springframework.core.type.classreading.MetadataReaderFactory;
35  import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
36  import org.springframework.core.type.AnnotationMetadata;
37  import org.springframework.core.type.ClassMetadata;
38  import org.springframework.util.ClassUtils;
39  
40  import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
41  
42  
43  
44  /**
45   * The goal is to find classed annotated with {@link RemoteServiceRelativePath}
46   * to generated {@link ServletDescriptor}
47   * 
48   * @author <a href="mailto:olamy@apache.org">Olivier Lamy</a>
49   * @since 2.1.0-1
50   */
51  @Component(role = ServletAnnotationFinder.class)
52  public class ServletAnnotationFinder
53      extends AbstractLogEnabled
54  {
55  
56      public ServletAnnotationFinder()
57      {
58          // no op
59      }
60  
61  	private MetadataReader getMetadataReader(String className,
62  											 MetadataReaderFactory factory,
63  											 PathMatchingResourcePatternResolver resourceResolver)
64  		throws IOException
65  	{
66  		String resourcePath = ClassUtils.convertClassNameToResourcePath(className);
67  		Resource resource = resourceResolver.getResource(resourcePath + ".class");
68  		if (resource.exists()) {
69  			return factory.getMetadataReader(resource);
70  		}
71  		return null;
72  	}
73  
74  	private boolean extendsRemoteServlet(ClassMetadata classMetadata,
75  										 MetadataReaderFactory factory,
76  										 PathMatchingResourcePatternResolver resourceResolver)
77  		throws IOException
78  	{
79  		if (classMetadata.hasSuperClass()) {
80  			String name = classMetadata.getSuperClassName();
81  			if (name.equals("com.google.gwt.user.server.rpc.RemoteServiceServlet")) {
82  				return true;
83  			}
84  			MetadataReader r = getMetadataReader(classMetadata.getSuperClassName(), factory, resourceResolver);
85  			return extendsRemoteServlet(r.getClassMetadata(), factory, resourceResolver);
86  		}
87  		return false;
88  	}
89  
90  	private AnnotationMetadata getAnnotationMetadataIfServlet(MetadataReader metadataReader,
91  															  MetadataReaderFactory factory,
92  															  PathMatchingResourcePatternResolver resourceResolver)
93  	{
94  		ClassMetadata classMetadata = metadataReader.getClassMetadata();
95  
96  		try {
97  			if (classMetadata.isConcrete() && extendsRemoteServlet(classMetadata, factory, resourceResolver)) {
98  				for (String i : metadataReader.getClassMetadata().getInterfaceNames()) {
99  					MetadataReader r = getMetadataReader(i, factory, resourceResolver);
100 					if (r != null && r.getAnnotationMetadata()
101 						.hasAnnotation( RemoteServiceRelativePath.class.getName() )) {
102 						return r.getAnnotationMetadata();
103 					}
104 				}
105 			}
106 		} catch (IOException e) {
107 			getLogger().warn("Failed to read class metadata: " + e);
108 		}
109 		return null;
110 	}
111 
112     /**
113      * @param packageName
114      * @return cannot return <code>null</code>
115      * @throws IOException
116      */
117     public Set<ServletDescriptor> findServlets( String packageName, String startPath, ClassLoader classLoader )
118         throws IOException
119     {
120         Set<ServletDescriptor> servlets = new LinkedHashSet<ServletDescriptor>();
121         PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver(
122                                                                                                                            classLoader );
123         String patternFinder = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
124             + ClassUtils.convertClassNameToResourcePath( packageName ) + "/**/*.class";
125 
126         Resource[] resources = pathMatchingResourcePatternResolver.getResources( patternFinder );
127         SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
128         getLogger().debug( "springresource " + resources.length + " for pattern " + patternFinder );
129         for ( Resource resource : resources )
130         {
131             getLogger().debug( "springresource " + resource.getFilename() );
132             MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader( resource );
133 
134 			AnnotationMetadata annotationMetadata = getAnnotationMetadataIfServlet(metadataReader,
135 																				   simpleMetadataReaderFactory,
136 																				   pathMatchingResourcePatternResolver);
137             if ( annotationMetadata != null )
138             {
139                 Map<String, Object> annotationAttributes = annotationMetadata
140                     .getAnnotationAttributes( RemoteServiceRelativePath.class.getName() );
141                 getLogger().debug( "found RemoteServiceRelativePath annotation for class "
142                                        + metadataReader.getClassMetadata().getClassName() );
143                 if ( StringUtils.isNotBlank( startPath ) )
144                 {
145                     StringBuilder path = new StringBuilder();
146                     if ( !startPath.startsWith( "/" ) )
147                     {
148                         path.append( '/' );
149                     }
150                     path.append( startPath );
151                     String annotationPathValue = (String) annotationAttributes.get( "value" );
152                     if ( !annotationPathValue.startsWith( "/" ) )
153                     {
154                         path.append( '/' );
155                     }
156                     path.append( annotationPathValue );
157                     ServletDescriptor servletDescriptor = new ServletDescriptor( path.toString(), metadataReader
158                         .getClassMetadata().getClassName() );
159                     servlets.add( servletDescriptor );
160                 }
161                 else
162                 {
163                     StringBuilder path = new StringBuilder();
164                     String annotationPathValue = (String) annotationAttributes.get( "value" );
165                     if ( !annotationPathValue.startsWith( "/" ) )
166                     {
167                         path.append( '/' );
168                     }
169                     path.append( annotationPathValue );
170                     ServletDescriptor servletDescriptor = new ServletDescriptor( path.toString(), metadataReader
171                         .getClassMetadata().getClassName() );
172                     servlets.add( servletDescriptor );
173                 }
174             }
175         }
176         return servlets;
177     }
178 
179 }