001: // Copyright 2004, 2005 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.hivemind.impl;
016:
017: import java.util.ArrayList;
018: import java.util.Iterator;
019: import java.util.List;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.apache.hivemind.ApplicationRuntimeException;
024: import org.apache.hivemind.HiveMind;
025: import org.apache.hivemind.Occurances;
026: import org.apache.hivemind.ShutdownCoordinator;
027: import org.apache.hivemind.events.RegistryShutdownListener;
028: import org.apache.hivemind.internal.ServiceImplementationConstructor;
029: import org.apache.hivemind.internal.ServiceInterceptorContribution;
030: import org.apache.hivemind.internal.ServiceModel;
031: import org.apache.hivemind.internal.ServiceModelFactory;
032: import org.apache.hivemind.order.Orderer;
033: import org.apache.hivemind.schema.Schema;
034: import org.apache.hivemind.service.InterfaceSynthesizer;
035: import org.apache.hivemind.util.ToStringBuilder;
036:
037: /**
038: * Abstract implementation of {@link org.apache.hivemind.internal.ServicePoint}. Provides some of
039: * the machinery for creating new service instances, delegating most of it to the
040: * {@link org.apache.hivemind.internal.ServiceModel} instace for the service.
041: *
042: * @author Howard Lewis Ship
043: */
044: public final class ServicePointImpl extends AbstractExtensionPoint
045: implements ConstructableServicePoint {
046: private Object _service;
047:
048: private boolean _building;
049:
050: private String _serviceInterfaceName;
051:
052: private Class _serviceInterface;
053:
054: private Class _declaredInterface;
055:
056: private ServiceImplementationConstructor _defaultServiceConstructor;
057:
058: private ServiceImplementationConstructor _serviceConstructor;
059:
060: private List _interceptorContributions;
061:
062: private boolean _interceptorsOrdered;
063:
064: private Schema _parametersSchema;
065:
066: private Occurances _parametersCount;
067:
068: private String _serviceModel;
069:
070: private ShutdownCoordinator _shutdownCoordinator;
071:
072: private ServiceModel _serviceModelObject;
073:
074: protected void extendDescription(ToStringBuilder builder) {
075: if (_service != null)
076: builder.append("service", _service);
077:
078: builder.append("serviceInterfaceName", _serviceInterfaceName);
079: builder.append("defaultServiceConstructor",
080: _defaultServiceConstructor);
081: builder.append("serviceConstructor", _serviceConstructor);
082: builder.append("interceptorContributions",
083: _interceptorContributions);
084: builder.append("parametersSchema", _parametersSchema);
085: builder.append("parametersCount", _parametersCount);
086: builder.append("serviceModel", _serviceModel);
087:
088: if (_building)
089: builder.append("building", _building);
090: }
091:
092: public void addInterceptorContribution(
093: ServiceInterceptorContribution contribution) {
094: if (_interceptorContributions == null)
095: _interceptorContributions = new ArrayList();
096:
097: _interceptorContributions.add(contribution);
098: }
099:
100: public synchronized Class getServiceInterface() {
101: if (_serviceInterface == null)
102: _serviceInterface = lookupServiceInterface();
103:
104: return _serviceInterface;
105: }
106:
107: public synchronized Class getDeclaredInterface() {
108: if (_declaredInterface == null)
109: _declaredInterface = lookupDeclaredInterface();
110:
111: return _declaredInterface;
112: }
113:
114: /** @since 1.1 */
115:
116: public String getServiceInterfaceClassName() {
117: return _serviceInterfaceName;
118: }
119:
120: private Class lookupDeclaredInterface() {
121: Class result = null;
122:
123: try {
124: result = getModule().resolveType(_serviceInterfaceName);
125: } catch (Exception ex) {
126: throw new ApplicationRuntimeException(ImplMessages
127: .badInterface(_serviceInterfaceName,
128: getExtensionPointId()), getLocation(), ex);
129: }
130:
131: return result;
132: }
133:
134: private Class lookupServiceInterface() {
135: Class declaredInterface = getDeclaredInterface();
136:
137: if (declaredInterface.isInterface())
138: return declaredInterface;
139:
140: // Not an interface ... a class. Synthesize an interface from the class itself.
141:
142: InterfaceSynthesizer is = (InterfaceSynthesizer) getModule()
143: .getService(HiveMind.INTERFACE_SYNTHESIZER_SERVICE,
144: InterfaceSynthesizer.class);
145:
146: return is.synthesizeInterface(declaredInterface);
147: }
148:
149: public void setServiceConstructor(
150: ServiceImplementationConstructor contribution,
151: boolean defaultConstructor) {
152: if (defaultConstructor)
153: _defaultServiceConstructor = contribution;
154: else
155: _serviceConstructor = contribution;
156: }
157:
158: public void setServiceInterfaceName(String string) {
159: _serviceInterfaceName = string;
160: }
161:
162: public void setParametersSchema(Schema schema) {
163: _parametersSchema = schema;
164: }
165:
166: public Schema getParametersSchema() {
167: return _parametersSchema;
168: }
169:
170: public ServiceImplementationConstructor getServiceConstructor(
171: boolean defaultConstructor) {
172: return defaultConstructor ? _defaultServiceConstructor
173: : _serviceConstructor;
174: }
175:
176: /**
177: * Invoked by {@link #getService(Class)} to get a service implementation from the
178: * {@link ServiceModel}.
179: * <p>
180: * TODO: I'm concerned that this synchronized method could cause a deadlock. It would take a LOT
181: * (mutually dependent services in multiple threads being realized at the same time).
182: */
183: private synchronized Object getService() {
184: if (_service == null) {
185:
186: if (_building)
187: throw new ApplicationRuntimeException(ImplMessages
188: .recursiveServiceBuild(this ));
189:
190: _building = true;
191:
192: try {
193:
194: ServiceModelFactory factory = getModule()
195: .getServiceModelFactory(getServiceModel());
196:
197: _serviceModelObject = factory
198: .createServiceModelForService(this );
199:
200: _service = _serviceModelObject.getService();
201: } finally {
202: _building = false;
203: }
204: }
205:
206: return _service;
207: }
208:
209: public Object getService(Class serviceInterface) {
210: Object result = getService();
211:
212: if (!serviceInterface.isAssignableFrom(result.getClass())) {
213: throw new ApplicationRuntimeException(ImplMessages
214: .serviceWrongInterface(this , serviceInterface),
215: getLocation(), null);
216: }
217:
218: return result;
219: }
220:
221: public String getServiceModel() {
222: return _serviceModel;
223: }
224:
225: public void setServiceModel(String model) {
226: _serviceModel = model;
227: }
228:
229: public void clearConstructorInformation() {
230: _serviceConstructor = null;
231: _interceptorContributions = null;
232: }
233:
234: // Hm. Does this need to be synchronized?
235:
236: public List getOrderedInterceptorContributions() {
237: if (!_interceptorsOrdered) {
238: _interceptorContributions = orderInterceptors();
239: _interceptorsOrdered = true;
240: }
241:
242: return _interceptorContributions;
243: }
244:
245: private List orderInterceptors() {
246: if (HiveMind.isEmpty(_interceptorContributions))
247: return null;
248:
249: // Any error logging should go to the extension point
250: // we're constructing.
251:
252: Log log = LogFactory.getLog(getExtensionPointId());
253:
254: Orderer orderer = new Orderer(log, getModule()
255: .getErrorHandler(), ImplMessages
256: .interceptorContribution());
257:
258: Iterator i = _interceptorContributions.iterator();
259: while (i.hasNext()) {
260: ServiceInterceptorContribution sic = (ServiceInterceptorContribution) i
261: .next();
262:
263: // Sort them into runtime excecution order. When we build
264: // the interceptor stack we'll apply them in reverse order,
265: // building outward from the core service implementation.
266:
267: orderer.add(sic, sic.getName(), sic
268: .getPrecedingInterceptorIds(), sic
269: .getFollowingInterceptorIds());
270: }
271:
272: return orderer.getOrderedObjects();
273: }
274:
275: public void setShutdownCoordinator(ShutdownCoordinator coordinator) {
276: _shutdownCoordinator = coordinator;
277: }
278:
279: public void addRegistryShutdownListener(
280: RegistryShutdownListener listener) {
281: _shutdownCoordinator.addRegistryShutdownListener(listener);
282: }
283:
284: /**
285: * Forces the service into existence.
286: */
287: public void forceServiceInstantiation() {
288: getService();
289:
290: _serviceModelObject.instantiateService();
291: }
292:
293: public Occurances getParametersCount() {
294: return _parametersCount;
295: }
296:
297: public void setParametersCount(Occurances occurances) {
298: _parametersCount = occurances;
299: }
300:
301: /**
302: * Returns the service constructor, if defined, or the default service constructor. The default
303: * service constructor comes from the <service-point> itself; other modules can override
304: * this default using an <implementation> element.
305: */
306:
307: public ServiceImplementationConstructor getServiceConstructor() {
308: return _serviceConstructor == null ? _defaultServiceConstructor
309: : _serviceConstructor;
310: }
311: }
|