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.Collection;
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.Orderable;
026    import org.apache.hivemind.ShutdownCoordinator;
027    import org.apache.hivemind.definition.ImplementationConstructor;
028    import org.apache.hivemind.definition.ImplementationDefinition;
029    import org.apache.hivemind.definition.InterceptorDefinition;
030    import org.apache.hivemind.definition.ServicePointDefinition;
031    import org.apache.hivemind.events.RegistryShutdownListener;
032    import org.apache.hivemind.internal.Module;
033    import org.apache.hivemind.internal.ServiceModel;
034    import org.apache.hivemind.internal.ServiceModelFactory;
035    import org.apache.hivemind.order.Orderer;
036    import org.apache.hivemind.service.InterfaceSynthesizer;
037    import org.apache.hivemind.util.ToStringBuilder;
038    
039    /**
040     * Abstract implementation of {@link org.apache.hivemind.internal.ServicePoint}. Provides some of
041     * the machinery for creating new service instances, delegating most of it to the
042     * {@link org.apache.hivemind.internal.ServiceModel} instace for the service.
043     * 
044     * @author Howard Lewis Ship
045     */
046    public final class ServicePointImpl extends AbstractExtensionPoint implements
047            ConstructableServicePoint
048    {
049        private Object _service;
050    
051        private boolean _building;
052    
053        private Class _serviceInterface;
054    
055        private Class _declaredInterface;
056    
057        private List _orderedInterceptorDefinitions;
058    
059        private boolean _interceptorsOrdered;
060    
061        private ShutdownCoordinator _shutdownCoordinator;
062    
063        private ServiceModel _serviceModelObject;
064        
065        public ServicePointImpl(Module module, ServicePointDefinition definition)
066        {
067            super(module, definition);
068        }
069    
070        protected void extendDescription(ToStringBuilder builder)
071        {
072            if (_service != null)
073                builder.append("service", _service);
074    
075            builder.append("serviceInterfaceName", getServiceInterfaceClassName());
076            builder.append("serviceModel", getServiceModel());
077            builder.append("interceptorDefinitions", getInterceptorDefinitions());
078    
079            if (_building)
080                builder.append("building", _building);
081        }
082    
083        public synchronized Class getServiceInterface()
084        {
085            if (_serviceInterface == null)
086                _serviceInterface = lookupServiceInterface();
087    
088            return _serviceInterface;
089        }
090    
091        public synchronized Class getDeclaredInterface()
092        {
093            if (_declaredInterface == null)
094                _declaredInterface = lookupDeclaredInterface();
095    
096            return _declaredInterface;
097        }
098    
099        public String getServiceInterfaceClassName()
100        {
101            return getServicePointDefinition().getInterfaceClassName();
102        }
103    
104        private Object getInterceptorDefinitions()
105        {
106            return getServicePointDefinition().getInterceptors();
107        }
108    
109        private Class lookupDeclaredInterface()
110        {
111            Class result = null;
112    
113            try
114            {
115                result = getModule().resolveType(getServiceInterfaceClassName());
116            }
117            catch (Exception ex)
118            {
119                throw new ApplicationRuntimeException(ImplMessages.badInterface(
120                        getServiceInterfaceClassName(),
121                        getExtensionPointId()), getLocation(), ex);
122            }
123    
124            return result;
125        }
126    
127        private Class lookupServiceInterface()
128        {
129            Class declaredInterface = getDeclaredInterface();
130    
131            if (declaredInterface.isInterface())
132                return declaredInterface;
133    
134            // Not an interface ... a class. Synthesize an interface from the class itself.
135    
136            InterfaceSynthesizer is = (InterfaceSynthesizer) getModule().getService(
137                    HiveMind.INTERFACE_SYNTHESIZER_SERVICE,
138                    InterfaceSynthesizer.class);
139    
140            return is.synthesizeInterface(declaredInterface);
141        }
142    
143        /**
144         * Invoked by {@link #getService(Class)} to get a service implementation from the
145         * {@link ServiceModel}.
146         * <p>
147         * TODO: I'm concerned that this synchronized method could cause a deadlock. It would take a LOT
148         * (mutually dependent services in multiple threads being realized at the same time).
149         */
150        private synchronized Object getService()
151        {
152            if (_service == null)
153            {
154    
155                if (_building)
156                    throw new ApplicationRuntimeException(ImplMessages.recursiveServiceBuild(this));
157    
158                _building = true;
159    
160                try
161                {
162    
163                    ServiceModelFactory factory = getModule().getServiceModelFactory(getServiceModel());
164    
165                    _serviceModelObject = factory.createServiceModelForService(this);
166    
167                    _service = _serviceModelObject.getService();
168                }
169                finally
170                {
171                    _building = false;
172                }
173            }
174    
175            return _service;
176        }
177    
178        public Object getService(Class serviceInterface)
179        {
180            Object result = getService();
181    
182            if (!serviceInterface.isAssignableFrom(result.getClass()))
183            {
184                throw new ApplicationRuntimeException(ImplMessages.serviceWrongInterface(
185                        this,
186                        serviceInterface), getLocation(), null);
187            }
188    
189            return result;
190        }
191    
192        public String getServiceModel()
193        {
194            if (getServicePointDefinition() == null)
195                return null;
196    
197            return getImplementationDefinition().getServiceModel();
198        }
199    
200        public void clearConstructorInformation()
201        {
202            _orderedInterceptorDefinitions = null;
203        }
204    
205        // Hm. Does this need to be synchronized?
206    
207        /**
208         * @return  Ordered list of {@link InterceptorDefinition}s 
209         */
210       public List getOrderedInterceptorContributions()
211        {
212            if (!_interceptorsOrdered)
213            {
214                _orderedInterceptorDefinitions = orderInterceptors();
215                _interceptorsOrdered = true;
216            }
217    
218            return _orderedInterceptorDefinitions;
219        }
220    
221        /**
222         * @return  Ordered list of {@link InterceptorDefinition}s 
223         */
224        private List orderInterceptors()
225        {
226            Collection interceptorDefinitions = getServicePointDefinition().getInterceptors();
227            if (HiveMind.isEmpty(interceptorDefinitions))
228                return null;
229    
230            // Any error logging should go to the extension point
231            // we're constructing.
232    
233            Log log = LogFactory.getLog(getExtensionPointId());
234    
235            Orderer orderer = new Orderer(log, getModule().getErrorHandler(), ImplMessages
236                    .interceptorContribution());
237    
238            Iterator i = interceptorDefinitions.iterator();
239            while (i.hasNext())
240            {
241                InterceptorDefinition sid = (InterceptorDefinition) i.next();
242    
243                // Sort them into runtime excecution order. When we build
244                // the interceptor stack we'll apply them in reverse order,
245                // building outward from the core service implementation.
246    
247                String precedingNames = null;
248                String followingNames = null;
249                // Check if info about ordering is available
250                if (sid instanceof Orderable) {
251                    Orderable orderable = (Orderable) sid;
252                    precedingNames = orderable.getPrecedingNames();
253                    followingNames = orderable.getFollowingNames();
254                }
255                
256                orderer.add(sid, sid.getName(), precedingNames, followingNames);
257            }
258    
259            return orderer.getOrderedObjects();
260        }
261    
262        public void setShutdownCoordinator(ShutdownCoordinator coordinator)
263        {
264            _shutdownCoordinator = coordinator;
265        }
266    
267        public void addRegistryShutdownListener(RegistryShutdownListener listener)
268        {
269            _shutdownCoordinator.addRegistryShutdownListener(listener);
270        }
271    
272        /**
273         * Forces the service into existence.
274         */
275        public void forceServiceInstantiation()
276        {
277            getService();
278    
279            _serviceModelObject.instantiateService();
280        }
281    
282        /**
283         * Returns the service constructor.
284         */
285    
286        public ImplementationConstructor getServiceConstructor()
287        {
288            return getImplementationDefinition().getServiceConstructor();
289        }
290    
291        public ImplementationDefinition getImplementationDefinition()
292        {
293            if (getServicePointDefinition().getDefaultImplementation() == null)
294                throw new ApplicationRuntimeException(ImplMessages.servicePointDefinitionWithoutImplementation(getServicePointDefinition()));
295            return getServicePointDefinition().getDefaultImplementation();
296        }
297        
298        /**
299         * @return  the service point definition that describes this service point
300         */
301        public ServicePointDefinition getServicePointDefinition()
302        {
303            return (ServicePointDefinition) super.getDefinition();
304        }
305    
306    
307    }