(no commit message)
[utils] / system / general / src / main / java / org / wamblee / system / core / AbstractComponent.java
1 /*
2  * Copyright 2005-2010 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 java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.logging.Logger;
23
24 /**
25  * Abstract subsystem class making it easy to implement new subsystems.
26  * 
27  */
28 public abstract class AbstractComponent<Type> implements Component<Type> {
29     private static final Logger LOG = Logger.getLogger(AbstractComponent.class
30         .getName());
31
32     private ThreadLocal<List<ProvidedInterface>> remaining;
33
34     private String context;
35
36     private String name;
37
38     private List<ProvidedInterface> provided;
39
40     private List<RequiredInterface> required;
41
42     /**
43      * Constructs the subsystem.
44      * 
45      * @param aName
46      *            Name of the system.
47      * @param aProvided
48      *            Provided services.
49      * @param aRequired
50      *            Required services.
51      */
52     protected AbstractComponent(String aName,
53         List<ProvidedInterface> aProvided, List<RequiredInterface> aRequired) {
54         remaining = new ThreadLocal<List<ProvidedInterface>>();
55         context = null;
56         name = aName;
57         provided = new ArrayList<ProvidedInterface>(aProvided);
58         required = new ArrayList<RequiredInterface>(aRequired);
59     }
60
61     /**
62      * Constructs the subsystem.
63      * 
64      * @param aName
65      *            Name of the system.
66      * @param aProvided
67      *            Provided services.
68      * @param aRequired
69      *            Required services.
70      */
71     protected AbstractComponent(String aName, ProvidedInterface[] aProvided,
72         RequiredInterface[] aRequired) {
73         this(aName, Arrays.asList(aProvided), Arrays.asList(aRequired));
74     }
75
76     /**
77      * Creates a new AbstractComponent object.
78      * 
79      */
80     protected AbstractComponent(String aName) {
81         this(aName, new ProvidedInterface[0], new RequiredInterface[0]);
82     }
83
84     public AbstractComponent<Type> addProvidedInterface(
85         ProvidedInterface aProvided) {
86         provided.add(aProvided);
87
88         return this;
89     }
90
91     public AbstractComponent<Type> addRequiredInterface(
92         RequiredInterface aRequired) {
93         required.add(aRequired);
94
95         return this;
96     }
97
98     @Override
99     public final String getName() {
100         return name;
101     }
102
103     @Override
104     public void addContext(String aContext) {
105         if (context == null) {
106             context = aContext;
107         } else {
108             context = aContext + "." + context;
109         }
110     }
111
112     @Override
113     public String getContext() {
114         return context;
115     }
116
117     @Override
118     public String getQualifiedName() {
119         if (context == null) {
120             return getName();
121         }
122
123         return context + "." + getName();
124     }
125
126     @Override
127     public final List<ProvidedInterface> getProvidedInterfaces() {
128         return Collections.unmodifiableList(provided);
129     }
130
131     @Override
132     public final List<RequiredInterface> getRequiredInterfaces() {
133         return Collections.unmodifiableList(required);
134     }
135
136     @Override
137     public final Type start(Scope aScope) {
138         LOG.info("Initialization starting '" + getQualifiedName() + "'");
139
140         List<ProvidedInterface> oldRemaining = remaining.get();
141         remaining
142             .set(new ArrayList<ProvidedInterface>(getProvidedInterfaces()));
143
144         try {
145             Type runtime = doStart(aScope);
146             checkNotStartedInterfaces();
147             LOG.info("Initialization finished '" + getQualifiedName() + "'");
148
149             return runtime;
150         } finally {
151             remaining.set(oldRemaining);
152         }
153     }
154
155     private void checkNotStartedInterfaces() {
156         if (remaining.get().size() > 0) {
157             StringBuffer notProvided = new StringBuffer();
158
159             for (ProvidedInterface providedIntf : remaining.get()) {
160                 notProvided.append("\nComponent " + getQualifiedName() +
161                     " did not start interface " + providedIntf);
162             }
163
164             throw new SystemAssemblyException(notProvided.toString());
165         }
166     }
167
168     /**
169      * Must be implemented for initializing the subsystem. The implementation
170      * must call {@link #addInterface(ProvidedInterface, Object, Scope)} for
171      * each service that is started.
172      * 
173      * 
174      * @return Returns the runtime of the component.
175      */
176     protected abstract Type doStart(Scope aScope);
177
178     /**
179      * Implementations must call this method to indicate that a new service has
180      * been started.
181      * 
182      * @param aDescriptor
183      *            Provided interface.
184      * @param aService
185      *            Implementation of the interface.
186      * @param aScope
187      *            scope in which to publish the implementation.
188      * 
189      */
190     protected final void addInterface(ProvidedInterface aDescriptor,
191         Object aService, Scope aScope) {
192         LOG.info("Interface '" + getQualifiedName() + "." +
193             aDescriptor.getName() + "' started.");
194
195         if (!remaining.get().remove(aDescriptor)) {
196             throw new SystemAssemblyException("Component '" +
197                 getQualifiedName() + "' started an unexpected interface '" +
198                 aDescriptor +
199                 "' that was not registerd as a provided interface before");
200         }
201
202         aScope.publishInterface(aDescriptor, aService);
203     }
204
205     @Override
206     public void stop(Type aRuntime) {
207         LOG.info("Stopping initiated '" + getQualifiedName() + "'");
208         doStop(aRuntime);
209         LOG.info("Stopping completed '" + getQualifiedName() + "'");
210     }
211
212     protected abstract void doStop(Type aRuntime);
213
214     @Override
215     public String toString() {
216         return getQualifiedName();
217     }
218
219     public ProvidedInterface findProvidedInterface(String aName) {
220         for (ProvidedInterface providedIntf : getProvidedInterfaces()) {
221             if (providedIntf.getName().equals(aName)) {
222                 return providedIntf;
223             }
224         }
225
226         return null;
227     }
228
229     public RequiredInterface findRequiredInterface(String aName) {
230         for (RequiredInterface requiredIntf : getRequiredInterfaces()) {
231             if (requiredIntf.getName().equals(aName)) {
232                 return requiredIntf;
233             }
234         }
235
236         return null;
237     }
238 }