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