| // |
| // ======================================================================== |
| // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.plus.annotation; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.TimeUnit; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import javax.servlet.ServletContainerInitializer; |
| |
| import org.eclipse.jetty.util.ConcurrentHashSet; |
| import org.eclipse.jetty.util.Loader; |
| import org.eclipse.jetty.util.StringUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.eclipse.jetty.webapp.WebAppContext; |
| |
| public class ContainerInitializer |
| { |
| private static final Logger LOG = Log.getLogger(ContainerInitializer.class); |
| |
| final protected ServletContainerInitializer _target; |
| final protected Class<?>[] _interestedTypes; |
| final protected Set<String> _applicableTypeNames = new ConcurrentHashSet<String>(); |
| final protected Set<String> _annotatedTypeNames = new ConcurrentHashSet<String>(); |
| |
| |
| public ContainerInitializer (ServletContainerInitializer target, Class<?>[] classes) |
| { |
| _target = target; |
| _interestedTypes = classes; |
| } |
| |
| public ContainerInitializer (ClassLoader loader, String toString) |
| { |
| Matcher m = Pattern.compile("ContainerInitializer\\{(.*),interested=(.*),applicable=(.*),annotated=(.*)\\}").matcher(toString); |
| if (!m.matches()) |
| throw new IllegalArgumentException(toString); |
| |
| try |
| { |
| _target = (ServletContainerInitializer)loader.loadClass(m.group(1)).newInstance(); |
| String[] interested = StringUtil.arrayFromString(m.group(2)); |
| _interestedTypes = new Class<?>[interested.length]; |
| for (int i=0;i<interested.length;i++) |
| _interestedTypes[i]=loader.loadClass(interested[i]); |
| for (String s:StringUtil.arrayFromString(m.group(3))) |
| _applicableTypeNames.add(s); |
| for (String s:StringUtil.arrayFromString(m.group(4))) |
| _annotatedTypeNames.add(s); |
| } |
| catch(Exception e) |
| { |
| throw new IllegalArgumentException(toString, e); |
| } |
| } |
| |
| public ServletContainerInitializer getTarget () |
| { |
| return _target; |
| } |
| |
| public Class[] getInterestedTypes () |
| { |
| return _interestedTypes; |
| } |
| |
| |
| /** |
| * A class has been found that has an annotation of interest |
| * to this initializer. |
| * @param className the class name to add |
| */ |
| public void addAnnotatedTypeName (String className) |
| { |
| _annotatedTypeNames.add(className); |
| } |
| |
| public Set<String> getAnnotatedTypeNames () |
| { |
| return Collections.unmodifiableSet(_annotatedTypeNames); |
| } |
| |
| public void addApplicableTypeName (String className) |
| { |
| _applicableTypeNames.add(className); |
| } |
| |
| public Set<String> getApplicableTypeNames () |
| { |
| return Collections.unmodifiableSet(_applicableTypeNames); |
| } |
| |
| |
| public void callStartup(WebAppContext context) |
| throws Exception |
| { |
| if (_target != null) |
| { |
| Set<Class<?>> classes = new HashSet<Class<?>>(); |
| |
| ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); |
| Thread.currentThread().setContextClassLoader(context.getClassLoader()); |
| |
| try |
| { |
| for (String s : _applicableTypeNames) |
| classes.add(Loader.loadClass(context.getClass(), s)); |
| |
| context.getServletContext().setExtendedListenerTypes(true); |
| if (LOG.isDebugEnabled()) |
| { |
| long start = System.nanoTime(); |
| _target.onStartup(classes, context.getServletContext()); |
| LOG.debug("ContainerInitializer {} called in {}ms", _target.getClass().getName(), TimeUnit.MILLISECONDS.convert(System.nanoTime()-start, TimeUnit.NANOSECONDS)); |
| } |
| else |
| _target.onStartup(classes, context.getServletContext()); |
| } |
| finally |
| { |
| context.getServletContext().setExtendedListenerTypes(false); |
| Thread.currentThread().setContextClassLoader(oldLoader); |
| } |
| } |
| } |
| |
| public String toString() |
| { |
| List<String> interested = Collections.emptyList(); |
| if (_interestedTypes != null) |
| { |
| interested = new ArrayList<>(_interestedTypes.length); |
| for (Class<?> c : _interestedTypes) |
| interested.add(c.getName()); |
| } |
| |
| return String.format("ContainerInitializer{%s,interested=%s,applicable=%s,annotated=%s}",_target.getClass().getName(),interested,_applicableTypeNames,_annotatedTypeNames); |
| } |
| |
| public void resolveClasses(WebAppContext context, Map<String, Set<String>> classMap) |
| { |
| //We have already found the classes that directly have an annotation that was in the HandlesTypes |
| //annotation of the ServletContainerInitializer. For each of those classes, walk the inheritance |
| //hierarchy to find classes that extend or implement them. |
| Set<String> annotatedClassNames = getAnnotatedTypeNames(); |
| if (annotatedClassNames != null && !annotatedClassNames.isEmpty()) |
| { |
| for (String name : annotatedClassNames) |
| { |
| //add the class that has the annotation |
| addApplicableTypeName(name); |
| |
| //find and add the classes that inherit the annotation |
| addInheritedTypes(classMap, (Set<String>)classMap.get(name)); |
| } |
| } |
| |
| |
| //Now we need to look at the HandlesTypes classes that were not annotations. We need to |
| //find all classes that extend or implement them. |
| if (getInterestedTypes() != null) |
| { |
| for (Class<?> c : getInterestedTypes()) |
| { |
| if (!c.isAnnotation()) |
| { |
| //find and add the classes that implement or extend the class. |
| //but not including the class itself |
| addInheritedTypes(classMap, (Set<String>)classMap.get(c.getName())); |
| } |
| } |
| } |
| } |
| |
| private void addInheritedTypes(Map<String, Set<String>> classMap,Set<String> names) |
| { |
| if (names == null || names.isEmpty()) |
| return; |
| |
| for (String s : names) |
| { |
| //add the name of the class |
| addApplicableTypeName(s); |
| |
| //walk the hierarchy and find all types that extend or implement the class |
| addInheritedTypes(classMap, (Set<String>)classMap.get(s)); |
| } |
| } |
| } |