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