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