001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020package org.sonar.api.platform; 021 022import org.picocontainer.Characteristics; 023import org.picocontainer.ComponentAdapter; 024import org.picocontainer.DefaultPicoContainer; 025import org.picocontainer.MutablePicoContainer; 026import org.picocontainer.behaviors.OptInCaching; 027import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; 028import org.picocontainer.monitors.NullComponentMonitor; 029import org.sonar.api.BatchComponent; 030import org.sonar.api.ServerComponent; 031import org.sonar.api.config.PropertyDefinitions; 032 033import javax.annotation.Nullable; 034 035/** 036 * @since 2.12 037 */ 038public class ComponentContainer implements BatchComponent, ServerComponent { 039 040 ComponentContainer parent, child; // no need for multiple children 041 MutablePicoContainer pico; 042 PropertyDefinitions propertyDefinitions; 043 044 /** 045 * Create root container 046 */ 047 public ComponentContainer() { 048 this.parent = null; 049 this.child = null; 050 this.pico = createPicoContainer(); 051 propertyDefinitions = new PropertyDefinitions(); 052 addSingleton(propertyDefinitions); 053 addSingleton(this); 054 } 055 056 /** 057 * Create child container 058 */ 059 private ComponentContainer(ComponentContainer parent) { 060 this.parent = parent; 061 this.pico = parent.pico.makeChildContainer(); 062 this.parent.child = this; 063 this.propertyDefinitions = parent.propertyDefinitions; 064 addSingleton(this); 065 } 066 067 /** 068 * This method MUST NOT be renamed start() because the container is registered itself in picocontainer. Starting 069 * a component twice is not authorized. 070 */ 071 public final ComponentContainer startComponents() { 072 pico.start(); 073 return this; 074 } 075 076 /** 077 * This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting 078 * a component twice is not authorized. 079 */ 080 public final ComponentContainer stopComponents() { 081 pico.stop(); 082 return this; 083 } 084 085 public final ComponentContainer addSingleton(Object component) { 086 return addComponent(component, true); 087 } 088 089 /** 090 * @param singleton return always the same instance if true, else a new instance 091 * is returned each time the component is requested 092 */ 093 public final ComponentContainer addComponent(Object component, boolean singleton) { 094 pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(getComponentKey(component), component); 095 declareExtension(null, component); 096 return this; 097 } 098 099 public final ComponentContainer addExtension(@Nullable PluginMetadata plugin, Object extension) { 100 pico.as(Characteristics.CACHE).addComponent(getComponentKey(extension), extension); 101 declareExtension(plugin, extension); 102 return this; 103 } 104 105 public final void declareExtension(@Nullable PluginMetadata plugin, Object extension) { 106 propertyDefinitions.addComponent(extension, plugin!=null ? plugin.getName() : ""); 107 } 108 109 public final ComponentContainer addPicoAdapter(ComponentAdapter adapter) { 110 pico.addAdapter(adapter); 111 return this; 112 } 113 114 public final <T> T getComponentByType(Class<T> tClass) { 115 return pico.getComponent(tClass); 116 } 117 118 public final Object getComponentByKey(Object key) { 119 return pico.getComponent(key); 120 } 121 122 public final <T> java.util.List<T> getComponentsByType(java.lang.Class<T> tClass) { 123 return pico.getComponents(tClass); 124 } 125 126 public final ComponentContainer removeChild() { 127 if (child != null) { 128 pico.removeChildContainer(child.pico); 129 child = null; 130 } 131 return this; 132 } 133 134 public final ComponentContainer createChild() { 135 return new ComponentContainer(this); 136 } 137 138 static MutablePicoContainer createPicoContainer() { 139 ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "dispose"); 140 return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, null); 141 } 142 143 static Object getComponentKey(Object component) { 144 if (component instanceof Class) { 145 return component; 146 } 147 return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(component.toString()).toString(); 148 } 149 150 public ComponentContainer getParent() { 151 return parent; 152 } 153 154 public ComponentContainer getChild() { 155 return child; 156 } 157 158 public MutablePicoContainer getPicoContainer() { 159 return pico; 160 } 161}