001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2013 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube 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 * SonarQube 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 License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 package org.sonar.api.platform; 021 022 import com.google.common.collect.Iterables; 023 import org.picocontainer.Characteristics; 024 import org.picocontainer.ComponentAdapter; 025 import org.picocontainer.DefaultPicoContainer; 026 import org.picocontainer.MutablePicoContainer; 027 import org.picocontainer.behaviors.OptInCaching; 028 import org.picocontainer.lifecycle.ReflectionLifecycleStrategy; 029 import org.picocontainer.monitors.NullComponentMonitor; 030 import org.sonar.api.BatchComponent; 031 import org.sonar.api.ServerComponent; 032 import org.sonar.api.config.PropertyDefinitions; 033 034 import javax.annotation.Nullable; 035 036 import java.util.List; 037 038 /** 039 * @since 2.12 040 */ 041 public class ComponentContainer implements BatchComponent, ServerComponent { 042 043 // no need for multiple children 044 ComponentContainer parent, child; 045 MutablePicoContainer pico; 046 PropertyDefinitions propertyDefinitions; 047 ComponentKeys componentKeys; 048 049 /** 050 * Create root container 051 */ 052 public ComponentContainer() { 053 this.parent = null; 054 this.child = null; 055 this.pico = createPicoContainer(); 056 this.componentKeys = new ComponentKeys(); 057 propertyDefinitions = new PropertyDefinitions(); 058 addSingleton(propertyDefinitions); 059 addSingleton(this); 060 } 061 062 /** 063 * Create child container 064 */ 065 protected ComponentContainer(ComponentContainer parent) { 066 this.parent = parent; 067 this.pico = parent.pico.makeChildContainer(); 068 this.parent.child = this; 069 this.propertyDefinitions = parent.propertyDefinitions; 070 this.componentKeys = new ComponentKeys(); 071 addSingleton(this); 072 } 073 074 public void execute() { 075 boolean threw = true; 076 try { 077 startComponents(); 078 threw = false; 079 } finally { 080 stopComponents(threw); 081 } 082 } 083 084 /** 085 * This method MUST NOT be renamed start() because the container is registered itself in picocontainer. Starting 086 * a component twice is not authorized. 087 */ 088 public ComponentContainer startComponents() { 089 try { 090 doBeforeStart(); 091 pico.start(); 092 doAfterStart(); 093 return this; 094 } catch (Exception e) { 095 throw PicoUtils.propagate(e); 096 } 097 } 098 099 /** 100 * This method aims to be overridden 101 */ 102 103 protected void doBeforeStart() { 104 105 } 106 107 /** 108 * This method aims to be overridden 109 */ 110 protected void doAfterStart() { 111 112 } 113 114 /** 115 * This method MUST NOT be renamed stop() because the container is registered itself in picocontainer. Starting 116 * a component twice is not authorized. 117 */ 118 public ComponentContainer stopComponents() { 119 return stopComponents(false); 120 } 121 122 public ComponentContainer stopComponents(boolean swallowException) { 123 try { 124 pico.stop(); 125 126 127 } catch (RuntimeException e) { 128 if (!swallowException) { 129 throw PicoUtils.propagate(e); 130 } 131 } finally { 132 removeChild(); 133 if (parent != null) { 134 parent.removeChild(); 135 } 136 } 137 return this; 138 } 139 140 /** 141 * @since 3.5 142 */ 143 public ComponentContainer add(Object... objects) { 144 for (Object object : objects) { 145 if (object instanceof ComponentAdapter) { 146 addPicoAdapter((ComponentAdapter) object); 147 } else if (object instanceof Iterable) { 148 add(Iterables.toArray((Iterable) object, Object.class)); 149 } else { 150 addSingleton(object); 151 } 152 } 153 return this; 154 } 155 156 public ComponentContainer addSingleton(Object component) { 157 return addComponent(component, true); 158 } 159 160 /** 161 * @param singleton return always the same instance if true, else a new instance 162 * is returned each time the component is requested 163 */ 164 public ComponentContainer addComponent(Object component, boolean singleton) { 165 Object key = componentKeys.of(component); 166 pico.as(singleton ? Characteristics.CACHE : Characteristics.NO_CACHE).addComponent(key, component); 167 declareExtension(null, component); 168 return this; 169 } 170 171 public ComponentContainer addExtension(@Nullable PluginMetadata plugin, Object extension) { 172 Object key = componentKeys.of(extension); 173 pico.as(Characteristics.CACHE).addComponent(key, extension); 174 declareExtension(plugin, extension); 175 return this; 176 } 177 178 public void declareExtension(@Nullable PluginMetadata plugin, Object extension) { 179 propertyDefinitions.addComponent(extension, plugin != null ? plugin.getName() : ""); 180 } 181 182 public ComponentContainer addPicoAdapter(ComponentAdapter adapter) { 183 pico.addAdapter(adapter); 184 return this; 185 } 186 187 public <T> T getComponentByType(Class<T> tClass) { 188 return pico.getComponent(tClass); 189 } 190 191 public Object getComponentByKey(Object key) { 192 return pico.getComponent(key); 193 } 194 195 public <T> List<T> getComponentsByType(Class<T> tClass) { 196 return pico.getComponents(tClass); 197 } 198 199 public ComponentContainer removeChild() { 200 if (child != null) { 201 pico.removeChildContainer(child.pico); 202 child = null; 203 } 204 return this; 205 } 206 207 public ComponentContainer createChild() { 208 return new ComponentContainer(this); 209 } 210 211 static MutablePicoContainer createPicoContainer() { 212 ReflectionLifecycleStrategy lifecycleStrategy = new ReflectionLifecycleStrategy(new NullComponentMonitor(), "start", "stop", "dispose"); 213 return new DefaultPicoContainer(new OptInCaching(), lifecycleStrategy, null); 214 } 215 216 public ComponentContainer getParent() { 217 return parent; 218 } 219 220 public ComponentContainer getChild() { 221 return child; 222 } 223 224 public MutablePicoContainer getPicoContainer() { 225 return pico; 226 } 227 }