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 }