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.parser;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.concurrent.CopyOnWriteArrayList;
  
  import org.apache.aries.blueprint.ComponentDefinitionRegistry;
  import org.apache.aries.blueprint.ComponentNameAlreadyInUseException;
  import org.apache.aries.blueprint.Interceptor;
  import org.apache.aries.blueprint.reflect.PassThroughMetadataImpl;
  import org.osgi.service.blueprint.reflect.ComponentMetadata;
  import org.osgi.service.blueprint.reflect.Target;
  
  /**
   * ComponentDefinitionRegistry implementation.
   *
   * This implementation uses concurrent lists and maps to store components and converters metadata
   * to allow its use by concurrent threads. 
   *
   * @version $Rev$, $Date$
   */
  public class ComponentDefinitionRegistryImpl implements ComponentDefinitionRegistry {
  
      private final Map<String, ComponentMetadata> components;
      private final List<Target> typeConverters;
      private final Map<ComponentMetadata, List<Interceptor>> interceptors;
  
      public ComponentDefinitionRegistryImpl() {
          // Use a linked hash map to keep the declaration order 
          components = Collections.synchronizedMap(new LinkedHashMap<String, ComponentMetadata>());
          typeConverters = new CopyOnWriteArrayList<Target>();
          interceptors = Collections.synchronizedMap(new HashMap<ComponentMetadata, List<Interceptor>>());
      }
  
      public void reset() {
          components.clear();
          typeConverters.clear();
          interceptors.clear();
      }
  
      public boolean containsComponentDefinition(String name) {
          return components.containsKey(name);
      }
  
      public ComponentMetadata getComponentDefinition(String name) {
          return components.get(name);
      }
  
      public Set<String> getComponentDefinitionNames() {
          return Collections.unmodifiableSet(components.keySet());
      }
  
      public void registerComponentDefinition(ComponentMetadata component) {
          String id = component.getId();
          if (id == null) {
              // TODO: should we generate a unique name?
              throw new IllegalArgumentException("Component must have a valid id");
          }
          if (id.startsWith("blueprint") && !(component instanceof PassThroughMetadataImpl)) {
              // TODO: log a warning
          }
          // TODO: perform other validation: scope, class/runtimeClass/factoryMethod, etc...
          if (components.containsKey(id)) {
              throw new ComponentNameAlreadyInUseException(id);
          }
          components.put(id, component);
      }
  
      public void removeComponentDefinition(String name) {
          ComponentMetadata removed = components.remove(name);
          if(removed!=null){
              interceptors.remove(removed);
          }
      }
  
      public void registerTypeConverter(Target component) {
          typeConverters.add(component);
          if (component instanceof ComponentMetadata) {
              registerComponentDefinition((ComponentMetadata) component);
          }
      }
  
      public List<Target> getTypeConverters() {
          return typeConverters;
      }
  
      public void registerInterceptorWithComponent(ComponentMetadata component, Interceptor interceptor) {
          if(interceptor!=null){
              List<Interceptor> componentInterceptorList = interceptors.get(component);
              if(componentInterceptorList==null){
                  componentInterceptorList = new ArrayList<Interceptor>();
                  interceptors.put(component, componentInterceptorList);
              }
              if(!componentInterceptorList.contains(interceptor)){
                  componentInterceptorList.add(interceptor);
                  Collections.sort(componentInterceptorList, new Comparator<Interceptor>(){
                      public int compare(Interceptor object1, Interceptor object2) {
                          //invert the order so higher ranks are sorted 1st
                          return object2.getRank() - object1.getRank();
                      }
                  });
              }
          }
      }
  
      public List<Interceptor> getInterceptors(ComponentMetadata component) {
          List<Interceptor> result = interceptors.get(component);
          return (result == null) ? Collections.<Interceptor>emptyList() : result;
      }
      
  }
  