View Javadoc

1   // ========================================================================
2   // Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.annotations;
15  
16  import java.net.URI;
17  import java.net.URL;
18  import java.net.URLClassLoader;
19  import java.util.ArrayList;
20  import java.util.EventListener;
21  import java.util.List;
22  
23  import org.eclipse.jetty.plus.servlet.ServletHandler;
24  import org.eclipse.jetty.servlet.FilterHolder;
25  import org.eclipse.jetty.servlet.FilterMapping;
26  import org.eclipse.jetty.servlet.ServletHolder;
27  import org.eclipse.jetty.servlet.ServletMapping;
28  import org.eclipse.jetty.util.LazyList;
29  import org.eclipse.jetty.util.log.Log;
30  import org.eclipse.jetty.util.resource.Resource;
31  import org.eclipse.jetty.webapp.WebAppContext;
32  import org.eclipse.jetty.webapp.WebInfConfiguration;
33  
34  /**
35   * Configuration
36   *
37   *
38   */
39  public class AnnotationConfiguration extends org.eclipse.jetty.plus.webapp.Configuration
40  {
41      public static final String JAR_RESOURCES = WebInfConfiguration.JAR_RESOURCES;
42                                                        
43      
44      
45      /** 
46       * @see org.eclipse.jetty.plus.webapp.AbstractConfiguration#parseAnnotations()
47       */
48      public void parseAnnotations(final WebAppContext context) throws Exception
49      {
50          /*
51           * TODO Need to also take account of hidden classes on system classpath that should never
52           * contribute annotations to a webapp (system and server classes):
53           * 
54           * --- when scanning system classpath:
55           *   + system classes : should always be scanned (subject to pattern)
56           *   + server classes : always ignored
57           *   
58           * --- when scanning webapp classpath:
59           *   + system classes : always ignored
60           *   + server classes : always scanned
61           * 
62           * 
63           * If same class is found in both container and in context then need to use
64           * webappcontext parentloaderpriority to work out which one contributes the
65           * annotation.
66           */
67          AnnotationFinder finder = new AnnotationFinder();
68  
69          //TODO change for servlet spec 3
70          parseContainerPath (context, finder);
71          parseWebInfLib (context, finder);
72          parseWebInfClasses (context, finder);
73  
74          AnnotationProcessor processor = new AnnotationProcessor(context, finder);
75          processor.process();
76          
77          List servlets = processor.getServlets();
78          List filters = processor.getFilters();
79          List servletMappings = processor.getServletMappings();
80          List filterMappings = processor.getFilterMappings();
81          List listeners = processor.getListeners();
82          
83          ServletHandler servletHandler = (ServletHandler)context.getServletHandler();
84          servletHandler.setFilters((FilterHolder[])LazyList.toArray(filters,FilterHolder.class));
85          servletHandler.setFilterMappings((FilterMapping[])LazyList.toArray(filterMappings,FilterMapping.class));
86          servletHandler.setServlets((ServletHolder[])LazyList.toArray(servlets,ServletHolder.class));
87          servletHandler.setServletMappings((ServletMapping[])LazyList.toArray(servletMappings,ServletMapping.class));
88          context.setEventListeners((EventListener[])LazyList.toArray(listeners,EventListener.class));
89      }
90      
91      public void parseContainerPath (final WebAppContext context, final AnnotationFinder finder)
92      throws Exception
93      {
94          //if no pattern for the container path is defined, then by default scan NOTHING
95          Log.debug("Scanning container jars");
96          
97          //Get the container jar uris
98          
99          ArrayList<URI> containerCandidateUris = findJars (context.getClassLoader().getParent(), true);
100         
101         //Pick out the uris from JAR_RESOURCES that match those uris to be scanned
102         ArrayList<URI> containerUris = new ArrayList<URI>();
103         List<Resource> jarResources = (List<Resource>)context.getAttribute(JAR_RESOURCES);
104         for (Resource r : jarResources)
105         {
106             URI uri = r.getURI();
107             if (containerCandidateUris.contains(uri))
108             {
109                 containerUris.add(uri);
110             }
111                
112         }
113         
114         finder.find (containerUris.toArray(new URI[containerUris.size()]),
115                 new ClassNameResolver ()
116                 {
117                     public boolean isExcluded (String name)
118                     {
119                         if (context.isSystemClass(name)) return false;
120                         if (context.isServerClass(name)) return true;
121                         return false;
122                     }
123 
124                     public boolean shouldOverride (String name)
125                     { 
126                         //looking at system classpath
127                         if (context.isParentLoaderPriority())
128                             return true;
129                         return false;
130                     }
131                 });
132     }
133     
134     
135     public void parseWebInfLib (final WebAppContext context, final AnnotationFinder finder)
136     throws Exception
137     {
138         Log.debug("Scanning WEB-INF/lib jars");
139         //Get the uris of jars on the webapp classloader
140         ArrayList<URI> candidateUris = findJars(context.getClassLoader(), false);
141         
142         //Pick out the uris from JAR_RESOURCES that match those to be scanned
143         ArrayList<URI> webInfUris = new ArrayList<URI>();
144         List<Resource> jarResources = (List<Resource>)context.getAttribute(JAR_RESOURCES);
145         for (Resource r : jarResources)
146         {
147             URI uri = r.getURI();
148             if (candidateUris.contains(uri))
149             {
150                 webInfUris.add(uri);
151             }
152         }
153         
154         //if no pattern for web-inf/lib is defined, then by default scan everything in it
155        finder.find(webInfUris.toArray(new URI[webInfUris.size()]), 
156                 new ClassNameResolver()
157                 {
158                     public boolean isExcluded (String name)
159                     {    
160                         if (context.isSystemClass(name)) return true;
161                         if (context.isServerClass(name)) return false;
162                         return false;
163                     }
164 
165                     public boolean shouldOverride (String name)
166                     {
167                         //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
168                         if (context.isParentLoaderPriority())
169                             return false;
170                         return true;
171                     }
172                 });  
173                 
174     }
175      
176     public void parseWebInfClasses (final WebAppContext context, final AnnotationFinder finder)
177     throws Exception
178     {
179         Log.debug("Scanning classes in WEB-INF/classes");
180         finder.find(context.getWebInf().addPath("classes/"), 
181                     new ClassNameResolver()
182         {
183             public boolean isExcluded (String name)
184             {
185                 if (context.isSystemClass(name)) return true;
186                 if (context.isServerClass(name)) return false;
187                 return false;
188             }
189 
190             public boolean shouldOverride (String name)
191             {
192                 //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp?
193                 if (context.isParentLoaderPriority())
194                     return false;
195                 return true;
196             }
197         });
198     }
199 
200     
201 
202     public ArrayList<URI> findJars (ClassLoader loader, boolean visitParent)
203     {
204         ArrayList<URI> uris = new ArrayList<URI>();
205        
206         while (loader != null && (loader instanceof URLClassLoader))
207         {
208             URL[] urls = ((URLClassLoader)loader).getURLs();
209             if (urls != null)
210             {
211                 for (URL u : urls)
212                 {
213                     try
214                     {
215                         uris.add(u.toURI());
216                     }
217                     catch (Exception e)
218                     {
219                         Log.warn(e);
220                     }
221                 } 
222             }
223             if (visitParent)
224                 loader = loader.getParent();
225             else
226                 loader = null;
227         }
228         return uris;
229     }
230 }