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 033/** 034 * @since 2.12 035 */ 036public class ComponentContainer implements BatchComponent, ServerComponent { 037 038 ComponentContainer parent, child; // no need for multiple children 039 MutablePicoContainer pico; 040 PropertyDefinitions propertyDefinitions; 041 042 /** 043 * Create root container 044 */ 045 public ComponentContainer() { 046 this.parent = null; 047 this.child = null; 048 this.pico = createPicoContainer(); 049 propertyDefinitions = new PropertyDefinitions(); 050 addSingleton(propertyDefinitions); 051 addSingleton(this); 052 } 053 054 /** 055 * Create child container 056 */ 057 private ComponentContainer(ComponentContainer parent) { 058 this.parent = parent; 059 this.pico = parent.pico.makeChildContainer(); 060 this.parent.child = this; 061 this.propertyDefinitions = parent.propertyDefinitions; 062 addSingleton(this); 063 } 064 065 /** 066 * This method MUST NOT be renamed start() because the container is registered itself in picocontainer. Starting 067 * a component twice is not authorized. 068 */ 069 public final ComponentContainer startComponents() { 070 pico.start(); 071 return this; 072 } 073 074 /** 075 * This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting 076 * a component twice is not authorized. 077 */ 078 public final ComponentContainer stopComponents() { 079 pico.stop(); 080 return this; 081 } 082 083 public final ComponentContainer addSingleton(Object component) { 084 return addComponent(component, true); 085 } 086 087 /** 088 * @param singleton return always the same instance if true, else a new instance 089 * is returned each time the component is requested 090 */ 091 public final ComponentContainer addComponent(Object component, boolean singleton) { 092 pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(getComponentKey(component), component); 093 propertyDefinitions.addComponent(component); 094 return this; 095 } 096 097 public final ComponentContainer addExtension(PluginMetadata plugin, Object extension) { 098 pico.as(Characteristics.CACHE).addComponent(getComponentKey(extension), extension); 099 declareExtension(plugin, extension); 100 return this; 101 } 102 103 public final void declareExtension(PluginMetadata plugin, Object extension) { 104 propertyDefinitions.addComponent(extension, plugin.getName()); 105 } 106 107 public final ComponentContainer addPicoAdapter(ComponentAdapter adapter) { 108 pico.addAdapter(adapter); 109 return this; 110 } 111 112 public final <T> T getComponentByType(Class<T> tClass) { 113 return pico.getComponent(tClass); 114 } 115 116 public final Object getComponentByKey(Object key) { 117 return pico.getComponent(key); 118 } 119 120 public final <T> java.util.List<T> getComponentsByType(java.lang.Class<T> tClass) { 121 return pico.getComponents(tClass); 122 } 123 124 public final ComponentContainer removeChild() { 125 if (child != null) { 126 pico.removeChildContainer(child.pico); 127 child = null; 128 } 129 return this; 130 } 131 132 public final ComponentContainer createChild() { 133 return new ComponentContainer(this); 134 } 135 136 static MutablePicoContainer createPicoContainer() { 137 ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "dispose"); 138 return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, null); 139 } 140 141 static Object getComponentKey(Object component) { 142 if (component instanceof Class) { 143 return component; 144 } 145 return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(component.toString()).toString(); 146 } 147 148 public ComponentContainer getParent() { 149 return parent; 150 } 151 152 public ComponentContainer getChild() { 153 return child; 154 } 155 156 /** 157 * Warning - do not use. This method exists only for the backward-compatibility due to the suppression 158 * of {@link org.sonar.api.utils.IocContainer} 159 * @return 160 */ 161 public MutablePicoContainer getPicoContainer() { 162 return pico; 163 } 164}