001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.xbean.kernel.standard;
018    
019    import java.util.Iterator;
020    import java.util.List;
021    import java.util.Set;
022    import java.util.Arrays;
023    import java.util.LinkedHashSet;
024    import java.util.Collections;
025    
026    import java.util.concurrent.TimeUnit;
027    import java.util.concurrent.atomic.AtomicLong;
028    import java.util.concurrent.locks.ReentrantLock;
029    import org.apache.xbean.kernel.ForcedStopException;
030    import org.apache.xbean.kernel.IllegalServiceStateException;
031    import org.apache.xbean.kernel.Kernel;
032    import org.apache.xbean.kernel.KernelOperationInterruptedException;
033    import org.apache.xbean.kernel.KernelOperationTimoutException;
034    import org.apache.xbean.kernel.ServiceEvent;
035    import org.apache.xbean.kernel.ServiceFactory;
036    import org.apache.xbean.kernel.ServiceMonitor;
037    import org.apache.xbean.kernel.ServiceName;
038    import org.apache.xbean.kernel.ServiceNotFoundException;
039    import org.apache.xbean.kernel.ServiceState;
040    import org.apache.xbean.kernel.StartStrategies;
041    import org.apache.xbean.kernel.StartStrategy;
042    import org.apache.xbean.kernel.StopStrategy;
043    import org.apache.xbean.kernel.UnregisterServiceException;
044    import org.apache.xbean.kernel.UnsatisfiedConditionsException;
045    import org.apache.xbean.kernel.InvalidServiceTypeException;
046    
047    /**
048     * The ServiceManager handles the life cycle of a single service.   The manager is responsible for gaurenteeing that
049     * all start conditions have been satisfied before the service is constructed, and that all stop conditions have been
050     * satisfied before the service is destroyed.  The ServiceManager can be started and stopped several times, but once
051     * destroyed no methods may be called.
052     *
053     * @author Dain Sundstrom
054     * @version $Id$
055     * @since 2.0
056     */
057    public class ServiceManager implements Comparable {
058        /**
059         * The kernel in which this service is registered.
060         */
061        private final Kernel kernel;
062    
063        /**
064         * The unique id of this service in the kernel.
065         */
066        private final long serviceId;
067    
068        /**
069         * The unique name of this service in the kernel.
070         */
071        private final ServiceName serviceName;
072    
073        /**
074         * The factory used to create and destroy the service instance.
075         */
076        private final ServiceFactory serviceFactory;
077    
078        /**
079         * The type of service this service manager will create.  This value is cached from the serviceFactory.getT
080         */
081        private final Set serviceTypes;
082    
083        /**
084         * The monitor to which we fire service events.  The ServiceManager requires an asynchronous monitor becuse events are
085         * fired from within the lock.  This helps to reduce complexity but will cause more services to sit in the
086         * {@link ServiceState#STARTING} and {@link ServiceState#STOPPING} states since events are propagated in a separate
087         * thread.
088         */
089        private final ServiceMonitor serviceMonitor;
090    
091        /**
092         * The service context given to the service factory.  This contans a reference to the kernel, serviceName and
093         * classloader.
094         */
095        private final StandardServiceContext standardServiceContext;
096    
097        /**
098         * Current state of this service.
099         */
100        private volatile ServiceState state = ServiceState.STOPPED;
101    
102        /**
103         * The time the service was started or 0 if not started.
104         */
105        private volatile long startTime;
106    
107        /**
108         * The {@link ServiceCondition) objects required to be ready before this service can be completely started.
109         */
110        private AggregateCondition startCondition;
111    
112        /**
113         * The {@link ServiceCondition) objects required to be ready before this service can be completely stopped.
114         */
115        private AggregateCondition stopCondition;
116    
117        /**
118         * The service instance.
119         */
120        private volatile Object service;
121    
122        /**
123         * The single lock we use.
124         */
125        private final ReentrantLock lock = new ReentrantLock();
126    
127        /**
128         * The maximum duration to wait for the lock.
129         */
130        private final long timeoutDuration;
131    
132        /**
133         * The unit of measure for the {@link #timeoutDuration}.
134         */
135        private final TimeUnit timeoutUnits;
136    
137        /**
138         * The name of the operation for which the lock is held; this is used in the reentrant exception message.
139         */
140        private String currentLockHolderOperation = "NOT-HELD";
141    
142        /**
143         * Sequence number for service event objects.
144         */
145        private final AtomicLong eventId = new AtomicLong(0);
146    
147        /**
148         * If true, when start is successful we will startRecusrive all of the services owned by this service.
149         */
150        private boolean recursive = false;
151    
152        /**
153         * Creates a service manager for a single service.
154         *
155         * @param kernel the kernel in which this wraper will be registered
156         * @param serviceId the unique id of this service in the kernel
157         * @param serviceName the unique name of this service in the kernel
158         * @param serviceFactory the factory used to create and destroy the service instance
159         * @param serviceMonitor the monitor of service events
160         * @param timeoutDuration the maximum duration to wait for a lock
161         * @param timeoutUnits the unit of measure for the timeoutDuration
162         */
163        public ServiceManager(Kernel kernel,
164                long serviceId,
165                ServiceName serviceName,
166                ServiceFactory serviceFactory,
167                ServiceMonitor serviceMonitor,
168                long timeoutDuration,
169                TimeUnit timeoutUnits) {
170    
171            this.kernel = kernel;
172            this.serviceId = serviceId;
173            this.serviceName = serviceName;
174            this.serviceFactory = serviceFactory;
175            this.serviceMonitor = serviceMonitor;
176            this.timeoutDuration = timeoutDuration;
177            this.timeoutUnits = timeoutUnits;
178            standardServiceContext = new StandardServiceContext(kernel, serviceName, serviceFactory.getClassLoader());
179            serviceTypes = Collections.unmodifiableSet(new LinkedHashSet(Arrays.asList(serviceFactory.getTypes())));
180        }
181    
182        /**
183         * Initializes the service.
184         *
185         * @throws IllegalServiceStateException if the service is not restartable and is disabled
186         * @throws UnsatisfiedConditionsException if the service is not restartable and there were unsatisfied start conditions
187         * @throws Exception if the service is not restartable and service construction threw an exception
188         * @see Kernel#registerService(ServiceName, ServiceFactory, ClassLoader)
189         */
190        public void initialize() throws IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
191            if (!serviceFactory.isRestartable() && !serviceFactory.isEnabled()) {
192                throw new IllegalServiceStateException("A disabled non-restartable service factory can not be initalized", serviceName);
193            }
194    
195            serviceMonitor.serviceRegistered(createServiceEvent());
196    
197            // if we are not restartable, we need to start immediately, otherwise we are not going to register this service
198            if (!serviceFactory.isRestartable()) {
199                try {
200                    start(false, StartStrategies.UNREGISTER);
201                } catch (UnregisterServiceException e) {
202                    serviceMonitor.serviceUnregistered(createServiceEvent());
203                    Throwable cause = e.getCause();
204                    if (cause instanceof Exception) {
205                        throw (Exception) cause;
206                    } else if (cause instanceof Error) {
207                        throw (Error) cause;
208                    } else {
209                        throw new AssertionError(cause);
210                    }
211                }
212    
213                // a non restartable service uses a special stop conditions object that picks up stop conditions as they
214                // are added.  When the stop() method is called on a non-restartable service all of the stop conditions
215                // registered with the service factory are initialized (if not already initialized), and the isSatisfied
216                // method is called.  This should cause the stop logic of a stop condition to fire.
217                lock("initialize");
218                try {
219                    stopCondition = new NonRestartableStopCondition(kernel, serviceName, serviceFactory.getClassLoader(), lock, serviceFactory);
220                } finally {
221                    unlock();
222                }
223            }
224        }
225    
226        /**
227         * Attempts to stop and destroy the service.
228         *
229         * @param stopStrategy the strategy used to determine how to handle unsatisfied stop conditions
230         * @throws IllegalServiceStateException is the service did not stop
231         * @throws UnsatisfiedConditionsException if there were unsatisfied stop conditions
232         * @see Kernel#unregisterService(ServiceName, StopStrategy)
233         */
234        public void destroy(StopStrategy stopStrategy) throws IllegalServiceStateException, UnsatisfiedConditionsException {
235            // if we are not restartable, we need to stop
236            try {
237                if (!stop(stopStrategy)) {
238                    throw new IllegalServiceStateException("Service did not stop", serviceName);
239                }
240            } catch (UnsatisfiedConditionsException e) {
241                throw e;
242            }
243    
244            if (!serviceFactory.isRestartable()) {
245                lock("destroy");
246                try {
247                    if (state != ServiceState.STOPPED) {
248                        state = ServiceState.STARTING;
249                        serviceMonitor.serviceStopping(createServiceEvent());
250                        if (service != null) {
251                            try {
252                                // destroy the service
253                                serviceFactory.destroyService(standardServiceContext);
254                            } catch (Throwable e) {
255                                serviceMonitor.serviceStopError(createErrorServiceEvent(e));
256                            }
257                        }
258    
259                        destroyAllConditions(serviceMonitor);
260    
261                        service = null;
262                        startTime = 0;
263                        state = ServiceState.STOPPED;
264                        serviceMonitor.serviceStopped(createServiceEvent());
265                    }
266                } finally {
267                    unlock();
268                }
269            }
270    
271            // cool we can unregistered
272            serviceMonitor.serviceUnregistered(createServiceEvent());
273        }
274    
275        /**
276         * Gets the unique id of this service in the kernel.
277         *
278         * @return the unique id of this service in the kernel
279         */
280        public long getServiceId() {
281            return serviceId;
282        }
283    
284        /**
285         * Gets the unique name of this service in the kernel.
286         *
287         * @return the unique name of this servce in the kernel
288         */
289        public ServiceName getServiceName() {
290            return serviceName;
291        }
292    
293        /**
294         * Gets the types of the service that will be managed by this service manager.
295         * @return the types of the service
296         */
297        public Set getServiceTypes() {
298            return serviceTypes;
299        }
300    
301        /**
302         * Gets the factory used to create and destroy the service instance.
303         *
304         * @return the factory for the service instance
305         * @see Kernel#getServiceFactory(ServiceName)
306         */
307        public ServiceFactory getServiceFactory() {
308            return serviceFactory;
309        }
310    
311        /**
312         * Gets the class loader for this service.  This class loader is provided to the service factory in the
313         * ServiceContext object.
314         *
315         * @return the classloader for this service
316         * @see Kernel#getClassLoaderFor(ServiceName)
317         */
318        public ClassLoader getClassLoader() {
319            return serviceFactory.getClassLoader();
320        }
321    
322        /**
323         * Gets the service instance.
324         *
325         * @return the service instance
326         * @see Kernel#getService(ServiceName)
327         */
328        public Object getService() {
329            return service;
330        }
331    
332        /**
333         * Gets the current state of this service.
334         *
335         * @return the current state of this service
336         * @see Kernel#getServiceState(ServiceName)
337         */
338        public ServiceState getState() {
339            return state;
340        }
341    
342        /**
343         * Gets the time at which this service entered the STARTING state or 0 if the service is STOPPED.
344         *
345         * @return the start time or 0 if the service is stopped
346         * @see Kernel#getServiceStartTime(ServiceName)
347         */
348        public long getStartTime() {
349            return startTime;
350        }
351    
352        /**
353         * Attempts to starts the service.
354         *
355         * @param recursive if start is successful should we start recursive the services owned by this servic
356         * @param startStrategy the strategy used to determine how to handle unsatisfied start conditions and start errors
357         * @throws IllegalServiceStateException if the service is in a state in which it can not be started
358         * @throws UnregisterServiceException if the kernel should unregister this service
359         * @throws UnsatisfiedConditionsException if there were unsatisfied start conditions
360         * @throws Exception it service creation threw an exception
361         * @see Kernel#startService(ServiceName)
362         * @see Kernel#startServiceRecursive(ServiceName)
363         */
364        public void start(boolean recursive, StartStrategy startStrategy) throws IllegalServiceStateException, UnregisterServiceException, UnsatisfiedConditionsException, Exception {
365            // verify that it is possible to start this service in the current state before obtaining the lock
366            if (!verifyStartable(state)) {
367                if (recursive) {
368                    startOwnedServices(startStrategy);
369                }
370                return;
371            }
372    
373            boolean shouldStartRecursive = false;
374            lock("start");
375            try {
376                // update the recursive flag
377                this.recursive = this.recursive || recursive;
378    
379                Throwable startError = null;
380                try {
381                    //
382                    // Loop until all start conditions have been satified.  The start strategy can break this loop.
383                    //
384                    boolean satisfied = false;
385                    while (!satisfied) {
386                        // do we still want to start?
387                        if (!verifyStartable(state)) {
388                            // assume someone else called startOwnedServices
389                            return;
390                        }
391    
392                        // if we are in the STOPPED state, we need to move to the STARTING state
393                        if (state == ServiceState.STOPPED) {
394                            // we are now officially starting
395                            state = ServiceState.STARTING;
396                            serviceMonitor.serviceStarting(createServiceEvent());
397    
398                            // initialize the start conditions
399                            startCondition = new AggregateCondition(kernel, serviceName, serviceFactory.getClassLoader(), lock, serviceFactory.getStartConditions());
400                            startCondition.initialize();
401                        }
402    
403                        // are we satisfied?
404                        Set unsatisfiedConditions = startCondition.getUnsatisfied();
405                        satisfied = unsatisfiedConditions.isEmpty();
406                        if (!satisfied) {
407                            // if the stragegy wants us to wait for conditions to be satisfied, it will return true
408                            if (startStrategy.waitForUnsatisfiedConditions(serviceName, unsatisfiedConditions)) {
409                                // wait for satisfaction and loop
410                                startCondition.awaitSatisfaction();
411                            } else {
412                                // no wait, notify the monitor and exit
413                                serviceMonitor.serviceWaitingToStart(createWaitingServiceEvent(unsatisfiedConditions));
414                                return;
415                            }
416                        }
417                    }
418    
419                    // we are ready to create the service
420                    service = serviceFactory.createService(standardServiceContext);
421    
422                    // verify that the service implements all of the types
423                    if (service == null) {
424                        throw new NullPointerException("Service factory return null from createService for service " + serviceName);
425                    }
426                    for (Iterator iterator = serviceTypes.iterator(); iterator.hasNext();) {
427                        Class type = (Class) iterator.next();
428                        if (!type.isInstance(service)) {
429                            throw new InvalidServiceTypeException(serviceName, type, service.getClass());
430                        }
431                    }
432    
433                    // success transition to running
434                    startTime = System.currentTimeMillis();
435                    state = ServiceState.RUNNING;
436                    serviceMonitor.serviceRunning(createServiceEvent());
437    
438                    // should we recursively start our children
439                    shouldStartRecursive = this.recursive || recursive;
440                    this.recursive = false;
441                } catch (UnsatisfiedConditionsException e) {
442                    // thrown from waitForUnsatisfiedConditions
443                    throw e;
444                } catch (IllegalServiceStateException e) {
445                    // this can be thrown while awaiting satisfaction
446                    throw e;
447                } catch (Exception e) {
448                    startError = e;
449                } catch (Error e) {
450                    startError = e;
451                }
452    
453                if (startError != null) {
454                    try {
455                        if (startError instanceof UnregisterServiceException) {
456                            throw (UnregisterServiceException) startError;
457                        } else {
458                            // the strategy will normally rethrow the startError, but if it doesn't notify the service monitor
459                            startStrategy.startError(serviceName, startError);
460                            serviceMonitor.serviceStartError(createErrorServiceEvent(startError));
461                        }
462                    } finally {
463                        // we are now STOPPING
464                        state = ServiceState.STOPPING;
465                        serviceMonitor.serviceStopping(createServiceEvent());
466    
467                        // clean up the conditons
468                        destroyAllConditions(serviceMonitor);
469    
470                        // transition to the STOPPED state
471                        service = null;
472                        startTime = 0;
473                        state = ServiceState.STOPPED;
474                        serviceMonitor.serviceStopped(createServiceEvent());
475                    }
476                }
477            } finally {
478                unlock();
479            }
480    
481    
482            // startRecursive all of the owned services
483            if (shouldStartRecursive) {
484                startOwnedServices(startStrategy);
485            }
486        }
487    
488        private void startOwnedServices(StartStrategy startStrategy) throws IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
489            Set ownedServices = serviceFactory.getOwnedServices();
490            if (ownedServices == null) throw new NullPointerException("serviceFactory.getOwnedServices() returned null");
491            for (Iterator iterator = ownedServices.iterator(); iterator.hasNext();) {
492                ServiceName ownedService = (ServiceName) iterator.next();
493                try {
494                    kernel.startServiceRecursive(ownedService, startStrategy);
495                } catch (ServiceNotFoundException ignored) {
496                    // this is ok -- service unregistered
497                } catch (IllegalServiceStateException ignored) {
498                    // ownedService is disabled or stopping -- anyway we don't care
499                }
500            }
501        }
502    
503        /**
504         * Verifies that the service is startable.  This can be used out side a lock to avoid unecessary locking.
505         *
506         * @param state the state of the service
507         * @return true if it is possible to start a service in the specifiec state
508         * @throws IllegalServiceStateException if it is illegal to start a service in the specified state
509         */
510        private boolean verifyStartable(ServiceState state) throws IllegalServiceStateException {
511            // if we are alredy in the running state, there is nothing to do
512            if (state == ServiceState.RUNNING) {
513                return false;
514            }
515    
516            // if we are in the stopping states, that is an error
517            if (state == ServiceState.STOPPING) {
518                throw new IllegalServiceStateException("A stopping service can not be started", serviceName);
519            }
520    
521            // is this service enabled?
522            if (state == ServiceState.STOPPED && !serviceFactory.isEnabled()) {
523                throw new IllegalServiceStateException("Service is disabled", serviceName);
524            }
525    
526            return true;
527        }
528    
529        /**
530         * Attempts to stop the service.
531         *
532         * @param stopStrategy the strategy used to determine how to handle unsatisfied stop conditions
533         * @return true if the service was sucessfully stopped; false otherwise
534         * @throws UnsatisfiedConditionsException if there were unsatisfied stop conditions
535         * @see Kernel#stopService(ServiceName)
536         */
537        public boolean stop(StopStrategy stopStrategy) throws UnsatisfiedConditionsException {
538            // check that we aren't already stopped before attempting to acquire the lock
539            ServiceState initialState = state;
540            if (initialState == ServiceState.STOPPED) {
541                return true;
542            }
543    
544            lock("stop");
545            try {
546                try {
547                    //
548                    // Loop until all stop conditions have been satified.  The stop strategy can break this loop.
549                    //
550                    boolean satisfied = false;
551                    while (!satisfied) {
552                        // do we still want to stop?
553                        if (state == ServiceState.STOPPED) {
554                            return true;
555                        }
556    
557                        // if we are not the STOPPING state, transition to it
558                        // we check on the stopConditions variable because non-restartable services preset this in the
559                        // intialization method
560                        if (stopCondition == null) {
561                            // we are not officially stopping
562                            serviceMonitor.serviceStopping(createServiceEvent());
563                            state = ServiceState.STOPPING;
564    
565                            // initialize all of the stop conditions
566                            stopCondition = new AggregateCondition(kernel, serviceName, serviceFactory.getClassLoader(), lock, serviceFactory.getStopConditions());
567                            stopCondition.initialize();
568                        }
569    
570                        // are we satisfied?
571                        Set unsatisfiedConditions = stopCondition.getUnsatisfied();
572                        satisfied = unsatisfiedConditions.isEmpty();
573                        if (!satisfied) {
574                            // if the stragegy wants us to wait for conditions to be satisfied, it will return true
575                            if (stopStrategy.waitForUnsatisfiedConditions(serviceName, unsatisfiedConditions)) {
576                                // wait for satisfaction and loop
577                                stopCondition.awaitSatisfaction();
578                            } else {
579                                // no wait, notify the monitor and exit
580                                serviceMonitor.serviceWaitingToStop(createWaitingServiceEvent(unsatisfiedConditions));
581                                return false;
582                            }
583                        }
584                    }
585                } catch (UnsatisfiedConditionsException e) {
586                    throw e;
587                } catch (ForcedStopException e) {
588                    serviceMonitor.serviceStopError(createErrorServiceEvent(e));
589                } catch (Exception e) {
590                    serviceMonitor.serviceStopError(createErrorServiceEvent(e));
591                } catch (Error e) {
592                    serviceMonitor.serviceStopError(createErrorServiceEvent(e));
593                }
594    
595                if (serviceFactory.isRestartable()) {
596                    if (service != null) {
597                        try {
598                            // destroy the service
599                            serviceFactory.destroyService(standardServiceContext);
600                        } catch (Throwable e) {
601                            serviceMonitor.serviceStopError(createErrorServiceEvent(e));
602                        }
603                    }
604    
605                    destroyAllConditions(serviceMonitor);
606    
607                    service = null;
608                    startTime = 0;
609                    state = ServiceState.STOPPED;
610                    serviceMonitor.serviceStopped(createServiceEvent());
611                }
612                return true;
613            } finally {
614                unlock();
615            }
616        }
617    
618        private void destroyAllConditions(ServiceMonitor monitor) {
619            if (!lock.isHeldByCurrentThread()) {
620                throw new IllegalStateException("Current thread must hold lock before calling destroyAllConditions");
621            }
622    
623            if (startCondition != null) {
624                List errors = startCondition.destroy();
625                // errors from destroying the start conditions are stop errors because destroy is only called while
626                // stopping the service
627                for (Iterator iterator = errors.iterator(); iterator.hasNext();) {
628                    Throwable stopError = (Throwable) iterator.next();
629                    monitor.serviceStopError(createErrorServiceEvent(stopError));
630                }
631                startCondition = null;
632            }
633            if (stopCondition != null) {
634                List errors = stopCondition.destroy();
635                for (Iterator iterator = errors.iterator(); iterator.hasNext();) {
636                    Throwable stopError = (Throwable) iterator.next();
637                    monitor.serviceStopError(createErrorServiceEvent(stopError));
638                }
639                stopCondition = null;
640            }
641        }
642    
643        /**
644         * Obtain the lock for the specified operation.
645         *
646         * @param operationName name of the operation that lock will be used for - this is only used for exception messages
647         * @throws IllegalStateException if thread tries to reenter while holding the lock
648         * @throws KernelOperationTimoutException if lock could not be obtained in {@link #timeoutDuration} {@link #timeoutUnits}
649         * @throws KernelOperationInterruptedException if the thread was interrupted while waiting for the lock
650         */
651        private void lock(String operationName) throws IllegalStateException, KernelOperationTimoutException, KernelOperationInterruptedException {
652            if (lock.isHeldByCurrentThread()) {
653                throw new IllegalStateException("Current thread holds lock for " + currentLockHolderOperation +
654                        " and lock can not be reacquired for " + operationName + " on " + serviceName);
655            }
656    
657            try {
658                if (!lock.tryLock(timeoutDuration, timeoutUnits)) {
659                    throw new KernelOperationTimoutException("Could not obtain lock for " + operationName + " operation on " +
660                            serviceName + " within " + timeoutDuration + " " + timeoutUnits.toString().toLowerCase(),
661                            serviceName,
662                            operationName);
663                }
664                currentLockHolderOperation = operationName;
665            } catch (InterruptedException e) {
666                throw new KernelOperationInterruptedException("Interrupted while attempting to obtain lock for " + operationName +
667                        " operation on " + serviceName,
668                        e,
669                        serviceName,
670                        operationName);
671    
672            }
673        }
674    
675        /**
676         * Unlock the lock and clear the currentLockHolderOperation name.
677         */
678        private void unlock() {
679            if (!lock.isHeldByCurrentThread()) {
680                throw new IllegalMonitorStateException("Not owner");
681            }
682    
683            currentLockHolderOperation = "NOT-HELD";
684            lock.unlock();
685        }
686    
687        private ServiceEvent createServiceEvent() {
688            return new ServiceEvent(eventId.getAndIncrement(), kernel, serviceName, serviceFactory, serviceFactory.getClassLoader(), service, null, null);
689        }
690    
691        private ServiceEvent createWaitingServiceEvent(Set unsatisfiedConditions) {
692            return new ServiceEvent(eventId.getAndIncrement(), kernel, serviceName, serviceFactory, serviceFactory.getClassLoader(), service, null, unsatisfiedConditions);
693        }
694    
695        private ServiceEvent createErrorServiceEvent(Throwable cause) {
696            return new ServiceEvent(eventId.getAndIncrement(), kernel, serviceName, serviceFactory, serviceFactory.getClassLoader(), null, cause, null);
697        }
698    
699        public int hashCode() {
700            return (int) (serviceId ^ (serviceId >>> 32));
701        }
702    
703        public boolean equals(Object o) {
704            if (o instanceof ServiceManager) {
705                return serviceId == ((ServiceManager)o).serviceId;
706            }
707            return false;
708        }
709    
710        public int compareTo(Object o) {
711            ServiceManager serviceManager = (ServiceManager) o;
712    
713            if (serviceId < serviceManager.serviceId) {
714                return -1;
715            } else if (serviceId > serviceManager.serviceId) {
716                return 1;
717            } else {
718                return 0;
719            }
720        }
721    
722        public String toString() {
723            return "[ServiceManager: serviceId=" + serviceId + ", serviceName=" + serviceName + ", state=" + state + "]";
724        }
725    }