content: /**
   *
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.aries.blueprint.web;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.net.URI;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Properties;
  import javax.servlet.ServletContext;
  import javax.servlet.ServletContextEvent;
  import javax.servlet.ServletContextListener;
  
  import org.apache.aries.blueprint.NamespaceHandler;
  import org.apache.aries.blueprint.Namespaces;
  import org.apache.aries.blueprint.container.BlueprintContainerImpl;
  import org.apache.aries.blueprint.container.SimpleNamespaceHandlerSet;
  import org.apache.aries.blueprint.parser.NamespaceHandlerSet;
  
  /**
   * Initialises all the blueprint XML files called <code>META-INF/blueprint.xml</code> on the classpath
   */
  public class BlueprintContextListener implements ServletContextListener {
  
      public static final String CONTAINER_ATTRIBUTE = "org.apache.aries.blueprint.container";
  
      public static final String CONTEXT_LOCATION = "blueprintLocation";
      public static final String DEFAULT_CONTEXT_LOCATION = "META-INF/blueprint.xml";
      
      public static final String NAMESPACE_HANDLERS_PARAMETER = "blueprintNamespaceHandlers";
      public static final String NAMESPACE_HANDLERS_LOCATION = "META-INF/blueprint.handlers";
      
      public static final String PROPERTIES = "blueprintProperties";
      
  
      public void contextInitialized(ServletContextEvent event) {
          ServletContext servletContext = event.getServletContext();
          String location = servletContext.getInitParameter(CONTEXT_LOCATION);
          if (location == null) {
              location = DEFAULT_CONTEXT_LOCATION;
          }
          List<URL> resourcePaths = new ArrayList<URL>();
          ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
          try {
              Enumeration<URL> resources = classLoader.getResources(location);
              while (resources.hasMoreElements()) {
                  resourcePaths.add(resources.nextElement());
              }
              servletContext.log("Loading Blueprint contexts " + resourcePaths);
  
              Map<String, String> properties = new HashMap<String, String>();
              String propLocations = servletContext.getInitParameter(PROPERTIES);
              if (propLocations != null) {
                  for (String propLoc : propLocations.split(",")) {
                      Enumeration<URL> propUrl = classLoader.getResources(propLoc);
                      while (propUrl.hasMoreElements()) {
                          URL url = propUrl.nextElement();
                          InputStream is = url.openStream();
                          try {
                              Properties props = new Properties();
                              props.load(is);
                              Enumeration names = props.propertyNames();
                              while (names.hasMoreElements()) {
                                  String key = names.nextElement().toString();
                                  properties.put(key, props.getProperty(key));
                              }
                          } finally {
                              is.close();
                          }
                      }
                  }
              }
  
              NamespaceHandlerSet nsHandlerSet = getNamespaceHandlerSet(servletContext, classLoader);
              BlueprintContainerImpl container = new BlueprintContainerImpl(classLoader, resourcePaths, properties, nsHandlerSet, true);
              servletContext.setAttribute(CONTAINER_ATTRIBUTE, container);
          } catch (Exception e) {
              servletContext.log("Failed to startup blueprint container. " + e, e);
          }
      }
      
      protected NamespaceHandlerSet getNamespaceHandlerSet(ServletContext servletContext, ClassLoader tccl) {
          NamespaceHandlerSet nsSet = getNamespaceHandlerSetFromParameter(servletContext, tccl);
          if (nsSet != null) {
              return nsSet;
          }
          return getNamespaceHandlerSetFromLocation(servletContext, tccl);
      }
  
      protected NamespaceHandlerSet getNamespaceHandlerSetFromParameter(ServletContext servletContext, ClassLoader tccl) {
          String handlersProp = servletContext.getInitParameter(NAMESPACE_HANDLERS_PARAMETER);
          if (handlersProp == null) {
              return null;
          }
          return getNamespaceHandlerSetFromClassNames(servletContext, tccl, Arrays.asList(handlersProp.split(",")));
      }
          
      protected NamespaceHandlerSet getNamespaceHandlerSetFromLocation(ServletContext servletContext, ClassLoader tccl) {
          List<String> handlerClassNames = new LinkedList<String>();
          try {
              Enumeration<URL> resources = tccl.getResources(NAMESPACE_HANDLERS_LOCATION);
              while (resources.hasMoreElements()) {
                  URL resource = resources.nextElement();
                  BufferedReader br = new BufferedReader(new InputStreamReader(resource.openStream()));
                  try {
                      for (String line = br.readLine(); line != null; line = br.readLine()) {
                          String trimmedLine = line.trim();
                          if (trimmedLine.isEmpty() || trimmedLine.startsWith("#")) {
                              continue;
                          }
                          handlerClassNames.add(trimmedLine);
                      }
                  } finally {
                      br.close();
                  }
              }
          } catch (IOException ex) {
              throw new RuntimeException("Failed to load namespace handler resources", ex);
          }
          if (!handlerClassNames.isEmpty()) {
              return getNamespaceHandlerSetFromClassNames(servletContext, tccl, handlerClassNames);
          } else {
              return null;
          }
          
      }
      
      protected NamespaceHandlerSet getNamespaceHandlerSetFromClassNames(ServletContext servletContext, ClassLoader tccl, 
          List<String> handlerClassNames) {
          SimpleNamespaceHandlerSet nsSet = new SimpleNamespaceHandlerSet();
          
          for (String name : handlerClassNames) {
              String trimmedName = name.trim();
              Object instance = null; 
              try {
                  instance = tccl.loadClass(trimmedName).newInstance();
              } catch (Exception ex) {
                  throw new RuntimeException("Failed to load NamespaceHandler: " + trimmedName, ex);
              }
              if (!(instance instanceof NamespaceHandler)) {
                  throw new RuntimeException("Invalid NamespaceHandler: " + trimmedName);
              }
              NamespaceHandler nsHandler = (NamespaceHandler)instance;
              Namespaces namespaces = nsHandler.getClass().getAnnotation(Namespaces.class);
              if (namespaces != null) {
                  for (String ns : namespaces.value()) {
                      nsSet.addNamespace(URI.create(ns), nsHandler.getSchemaLocation(ns), nsHandler);    
                  }
              }
          }
          
          return nsSet;
      }
      
      public void contextDestroyed(ServletContextEvent event) {
          ServletContext servletContext = event.getServletContext();
          Object container = servletContext.getAttribute(CONTAINER_ATTRIBUTE);
          if (container instanceof BlueprintContainerImpl) {
              BlueprintContainerImpl blueprint = (BlueprintContainerImpl) container;
              blueprint.destroy();
          }
      }
  }
  