source code formatting.
[utils] / system / general / src / main / java / org / wamblee / system / core / AbstractComponent.java
1 /*
2  * Copyright 2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.wamblee.system.core;
17
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25
26
27 /**
28  * Abstract subsystem class making it easy to implement new subsystems.
29  *
30  * @param <Type> DOCUMENT ME!
31  */
32 public abstract class AbstractComponent<Type> implements Component<Type> {
33     /**
34      * DOCUMENT ME!
35      */
36     private static final Log LOG = LogFactory.getLog(AbstractComponent.class);
37
38     /**
39      * DOCUMENT ME!
40      */
41     private ThreadLocal<List<ProvidedInterface>> remaining;
42
43     /**
44      * DOCUMENT ME!
45      */
46     private String context;
47
48     /**
49      * DOCUMENT ME!
50      */
51     private String name;
52
53     /**
54      * DOCUMENT ME!
55      */
56     private List<ProvidedInterface> provided;
57
58     /**
59      * DOCUMENT ME!
60      */
61     private List<RequiredInterface> required;
62
63 /**
64          * Constructs the subsystem.
65          * 
66          * @param aName
67          *            Name of the system.
68          * @param aProvided
69          *            Provided services.
70          * @param aRequired
71          *            Required services.
72          */
73     protected AbstractComponent(String aName,
74         List<ProvidedInterface> aProvided, List<RequiredInterface> aRequired) {
75         remaining     = new ThreadLocal<List<ProvidedInterface>>();
76         context       = null;
77         name          = aName;
78         provided      = new ArrayList<ProvidedInterface>(aProvided);
79         required      = new ArrayList<RequiredInterface>(aRequired);
80     }
81
82 /**
83      * Constructs the subsystem.
84      * 
85      * @param aName
86      *            Name of the system.
87      * @param aProvided
88      *            Provided services.
89      * @param aRequired
90      *            Required services.
91      */
92     protected AbstractComponent(String aName, ProvidedInterface[] aProvided,
93         RequiredInterface[] aRequired) {
94         this(aName, Arrays.asList(aProvided), Arrays.asList(aRequired));
95     }
96
97     /**
98      * Creates a new AbstractComponent object.
99      *
100      * @param aName DOCUMENT ME!
101      */
102     protected AbstractComponent(String aName) {
103         this(aName, new ProvidedInterface[0], new RequiredInterface[0]);
104     }
105
106     /**
107      * DOCUMENT ME!
108      *
109      * @param aProvided DOCUMENT ME!
110      *
111      * @return DOCUMENT ME!
112      */
113     public AbstractComponent<Type> addProvidedInterface(
114         ProvidedInterface aProvided) {
115         provided.add(aProvided);
116
117         return this;
118     }
119
120     /**
121      * DOCUMENT ME!
122      *
123      * @param aRequired DOCUMENT ME!
124      *
125      * @return DOCUMENT ME!
126      */
127     public AbstractComponent<Type> addRequiredInterface(
128         RequiredInterface aRequired) {
129         required.add(aRequired);
130
131         return this;
132     }
133
134     /**
135      * DOCUMENT ME!
136      *
137      * @return DOCUMENT ME!
138      */
139     @Override
140     public final String getName() {
141         return name;
142     }
143
144     /**
145      * DOCUMENT ME!
146      *
147      * @param aContext DOCUMENT ME!
148      */
149     @Override
150     public void addContext(String aContext) {
151         if (context == null) {
152             context = aContext;
153         } else {
154             context = aContext + "." + context;
155         }
156     }
157
158     /**
159      * DOCUMENT ME!
160      *
161      * @return DOCUMENT ME!
162      */
163     @Override
164     public String getContext() {
165         return context;
166     }
167
168     /**
169      * DOCUMENT ME!
170      *
171      * @return DOCUMENT ME!
172      */
173     @Override
174     public String getQualifiedName() {
175         if (context == null) {
176             return getName();
177         }
178
179         return context + "." + getName();
180     }
181
182     /**
183      * DOCUMENT ME!
184      *
185      * @return DOCUMENT ME!
186      */
187     @Override
188     public final List<ProvidedInterface> getProvidedInterfaces() {
189         return Collections.unmodifiableList(provided);
190     }
191
192     /**
193      * DOCUMENT ME!
194      *
195      * @return DOCUMENT ME!
196      */
197     @Override
198     public final List<RequiredInterface> getRequiredInterfaces() {
199         return Collections.unmodifiableList(required);
200     }
201
202     /**
203      * DOCUMENT ME!
204      *
205      * @param aScope DOCUMENT ME!
206      *
207      * @return DOCUMENT ME!
208      */
209     @Override
210     public final Type start(Scope aScope) {
211         LOG.info("Initialization starting '" + getQualifiedName() + "'");
212
213         List<ProvidedInterface> oldRemaining = remaining.get();
214         remaining.set(new ArrayList<ProvidedInterface>(getProvidedInterfaces()));
215
216         try {
217             Type runtime = doStart(aScope);
218             checkNotStartedInterfaces();
219             LOG.info("Initialization finished '" + getQualifiedName() + "'");
220
221             return runtime;
222         } finally {
223             remaining.set(oldRemaining);
224         }
225     }
226
227     /**
228      * DOCUMENT ME!
229      */
230     private void checkNotStartedInterfaces() {
231         if (remaining.get().size() > 0) {
232             String notProvided = "";
233
234             for (ProvidedInterface provided : remaining.get()) {
235                 notProvided += ("\nComponent " + getQualifiedName()
236                 + " did not start interface " + provided);
237             }
238
239             throw new SystemAssemblyException(notProvided);
240         }
241     }
242
243     /**
244      * Must be implemented for initializing the subsystem. The
245      * implementation must call {@link #addInterface(ProvidedInterface,
246      * Object, Scope)} for each service that is started.
247      *
248      * @param aScope DOCUMENT ME!
249      *
250      * @return Returns the runtime of the component.
251      */
252     protected abstract Type doStart(Scope aScope);
253
254     /**
255      * Implementations must call this method to indicate that a new
256      * service has been started.
257      *
258      * @param aDescriptor Provided interface.
259      * @param aService Implementation of the interface.
260      * @param aScope scope in which to publish the implementation.
261      *
262      * @throws SystemAssemblyException DOCUMENT ME!
263      */
264     protected final void addInterface(ProvidedInterface aDescriptor,
265         Object aService, Scope aScope) {
266         LOG.info("Interface '" + getQualifiedName() + "."
267             + aDescriptor.getName() + "' started.");
268
269         if (!remaining.get().remove(aDescriptor)) {
270             throw new SystemAssemblyException("Component '"
271                 + getQualifiedName() + "' started an unexpected interface '"
272                 + aDescriptor
273                 + "' that was not registerd as a provided interface before");
274         }
275
276         aScope.publishInterface(aDescriptor, aService);
277     }
278
279     /**
280      * DOCUMENT ME!
281      *
282      * @param aRuntime DOCUMENT ME!
283      */
284     @Override
285     public void stop(Type aRuntime) {
286         LOG.info("Stopping initiated '" + getQualifiedName() + "'");
287         doStop(aRuntime);
288         LOG.info("Stopping completed '" + getQualifiedName() + "'");
289     }
290
291     /**
292      * DOCUMENT ME!
293      *
294      * @param aRuntime DOCUMENT ME!
295      */
296     protected abstract void doStop(Type aRuntime);
297
298     /**
299      * DOCUMENT ME!
300      *
301      * @return DOCUMENT ME!
302      */
303     @Override
304     public String toString() {
305         return getQualifiedName();
306     }
307
308     /**
309      * DOCUMENT ME!
310      *
311      * @param aName DOCUMENT ME!
312      *
313      * @return DOCUMENT ME!
314      */
315     public ProvidedInterface findProvidedInterface(String aName) {
316         for (ProvidedInterface provided : getProvidedInterfaces()) {
317             if (provided.getName().equals(aName)) {
318                 return provided;
319             }
320         }
321
322         return null;
323     }
324
325     /**
326      * DOCUMENT ME!
327      *
328      * @param aName DOCUMENT ME!
329      *
330      * @return DOCUMENT ME!
331      */
332     public RequiredInterface findRequiredInterface(String aName) {
333         for (RequiredInterface required : getRequiredInterfaces()) {
334             if (required.getName().equals(aName)) {
335                 return required;
336             }
337         }
338
339         return null;
340     }
341 }