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