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 */
020 package org.sonar.api.platform;
021
022 import org.picocontainer.Characteristics;
023 import org.picocontainer.ComponentAdapter;
024 import org.picocontainer.DefaultPicoContainer;
025 import org.picocontainer.MutablePicoContainer;
026 import org.picocontainer.behaviors.OptInCaching;
027 import org.picocontainer.lifecycle.ReflectionLifecycleStrategy;
028 import org.picocontainer.monitors.NullComponentMonitor;
029 import org.sonar.api.BatchComponent;
030 import org.sonar.api.ServerComponent;
031 import org.sonar.api.config.PropertyDefinitions;
032
033 /**
034 * @since 2.12
035 */
036 public 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 }