public ModelController createController(final ModelNode model, final Setup registration)
      throws InterruptedException {
    final ServiceController<?> existingController =
        serviceContainer.getService(ServiceName.of("ModelController"));
    if (existingController != null) {
      final CountDownLatch latch = new CountDownLatch(1);
      existingController.addListener(
          new AbstractServiceListener<Object>() {
            public void listenerAdded(ServiceController<?> serviceController) {
              serviceController.setMode(ServiceController.Mode.REMOVE);
            }

            public void transition(
                ServiceController<?> serviceController, ServiceController.Transition transition) {
              if (transition.equals(ServiceController.Transition.REMOVING_to_REMOVED)) {
                latch.countDown();
              }
            }
          });
      latch.await();
    }

    ServiceTarget target = serviceContainer.subTarget();
    ControlledProcessState processState = new ControlledProcessState(true);
    ModelControllerService svc = new ModelControllerService(processState, registration, model);
    ServiceBuilder<ModelController> builder =
        target.addService(ServiceName.of("ModelController"), svc);
    builder.install();
    svc.latch.await();
    ModelController controller = svc.getValue();
    ModelNode setup = Util.getEmptyOperation("setup", new ModelNode());
    controller.execute(setup, null, null, null);
    processState.setRunning();
    return controller;
  }
  /*
   * In order to test this specific scenario, we use Byteman to insert a monitor in the specific moment
   *  where the transition from STOP_REQUESTED to the next state is going to occur.
   *  This monitor will force the thread to wait until upperCount is incremented to 1.
   */
  @Test
  public void test() throws Exception {
    ServiceName serviceName = ServiceName.of("service");
    TestServiceListener serviceListener = new TestServiceListener();

    // install service as usual
    Future<ServiceController<?>> serviceStart = serviceListener.expectServiceStart(serviceName);
    serviceContainer.addService(serviceName, Service.NULL).addListener(serviceListener).install();
    ServiceController<?> serviceController = assertController(serviceName, serviceStart);

    Future<ServiceController<?>> serviceStopping =
        serviceListener.expectNoServiceStopping(serviceName);
    Future<ServiceController<?>> serviceStop = serviceListener.expectNoServiceStop(serviceName);
    serviceStart = serviceListener.expectNoServiceStart(serviceName);
    // set the mode to NEVER, so that serviceController enters STOP_REQUESTED state
    serviceController.setMode(ServiceController.Mode.NEVER);
    // set the mode to ACTIVE, so that serviceController transitions to UP state
    serviceController.setMode(ServiceController.Mode.ACTIVE);
    // no notifications are expected
    assertNull(serviceStop.get());
    assertNull(serviceStopping.get());
    assertNull(serviceStart.get());
    // service should still be in the up state
    assertSame(ServiceController.State.UP, serviceController.getState());
  }
  public static void main(String[] args) throws Exception {
    final int totalServiceDefinitions = Integer.parseInt(args[0]);
    final int threadPoolSize = Integer.parseInt(args[1]);

    final ServiceContainer container = ServiceContainer.Factory.create();
    final ThreadPoolExecutor executor =
        new ThreadPoolExecutor(
            threadPoolSize,
            threadPoolSize,
            1000,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());
    container.setExecutor(executor);

    BatchBuilder batch = container.batchBuilder();

    final LatchedFinishListener listener = new LatchedFinishListener();

    final Value<Field> testFieldValue =
        new CachedValue<Field>(
            new LookupFieldValue(new ImmediateValue<Class<?>>(TestObject.class), "test"));

    final List<Value<Class<?>>> params =
        Collections.singletonList((Value<Class<?>>) new ImmediateValue<Class<?>>(TestObject.class));
    final List<Value<Method>> setterMethodValues = new ArrayList<Value<Method>>(5);
    for (int i = 0; i < 5; i++)
      setterMethodValues.add(
          new CachedValue<Method>(
              new LookupMethodValue(
                  new ImmediateValue<Class<?>>(TestObject.class), "setOther" + (i), params)));

    for (int i = 0; i < totalServiceDefinitions; i++) {
      final TestObject testObject = new TestObject("test" + i);
      final TestObjectService service = new TestObjectService(testObject);
      final ServiceBuilder<TestObject> builder =
          batch.addService(ServiceName.of(("test" + i).intern()), service).addListener(listener);

      final Object injectedValue = new Object();
      //            builder.addInjection(injectedValue).toFieldValue(testFieldValue);

      int nextDivByFive = (5 - (i % 5)) + i;
      int numDeps = Math.min(nextDivByFive - i, totalServiceDefinitions - i - 1);
      for (int j = 0; j < numDeps; j++) {
        int depId = i + j + 1;
        if (depId % 5 == 0) continue;

        //                builder.addDependency(ServiceName.of(("test" +
        // depId).intern())).toMethodValue(setterMethodValues.get(j),
        // Collections.singletonList(Values.injectedValue()));
      }
    }

    batch.install();
    listener.await();
    System.out.println(totalServiceDefinitions + " : " + listener.getElapsedTime() / 1000.0);
    container.shutdown();
    executor.shutdown();
  }
示例#4
0
 public static ServiceName dsListenerServiceName(String vdbName, int version, String name)
     throws InvalidServiceNameException {
   try {
     return ServiceName.of(
         DS_LISTENER_BASE, vdbName, String.valueOf(version), VDBStatusChecker.stripContext(name));
   } catch (RuntimeException e) {
     throw new InvalidServiceNameException(
         IntegrationPlugin.Event.TEIID50099,
         e,
         IntegrationPlugin.Util.gs(IntegrationPlugin.Event.TEIID50099, name, vdbName, version));
   }
 }
  /**
   * Create a new controller with the passed in operations.
   *
   * @param additionalInit Additional initialization that should be done to the parsers, controller
   *     and service container before initializing our extension
   * @param bootOperations the operations
   */
  protected KernelServices installInController(
      AdditionalInitialization additionalInit, List<ModelNode> bootOperations) throws Exception {
    if (additionalInit == null) {
      additionalInit = new AdditionalInitialization();
    }
    ControllerInitializer controllerInitializer = additionalInit.createControllerInitializer();
    additionalInit.setupController(controllerInitializer);

    // Initialize the controller
    ServiceContainer container =
        ServiceContainer.Factory.create("test" + counter.incrementAndGet());
    ServiceTarget target = container.subTarget();
    ControlledProcessState processState = new ControlledProcessState(true);
    List<ModelNode> extraOps = controllerInitializer.initializeBootOperations();
    List<ModelNode> allOps = new ArrayList<ModelNode>();
    if (extraOps != null) {
      allOps.addAll(extraOps);
    }
    allOps.addAll(bootOperations);
    StringConfigurationPersister persister = new StringConfigurationPersister(allOps, testParser);
    ModelControllerService svc =
        new ModelControllerService(
            additionalInit.getType(),
            mainExtension,
            controllerInitializer,
            additionalInit,
            processState,
            persister,
            additionalInit.isValidateOperations());
    ServiceBuilder<ModelController> builder =
        target.addService(ServiceName.of("ModelController"), svc);
    builder.install();

    additionalInit.addExtraServices(target);

    // sharedState = svc.state;
    svc.latch.await();
    ModelController controller = svc.getValue();
    ModelNode setup = Util.getEmptyOperation("setup", new ModelNode());
    controller.execute(setup, null, null, null);
    processState.setRunning();

    KernelServices kernelServices =
        new KernelServices(
            container, controller, persister, new OperationValidator(svc.rootRegistration));
    this.kernelServices.add(kernelServices);
    if (svc.error != null) {
      throw svc.error;
    }

    return kernelServices;
  }
 @Override
 public ServiceName getServiceName(Deployment dep, int state) {
   // Currently the bundleId is needed for uniqueness because of
   // [MSC-97] Cannot re-install service with same name
   Long bundleId = dep.getAttachment(Long.class);
   ServiceName serviceName =
       ServiceName.of(
           BUNDLE_BASE_NAME, "" + bundleId, "" + dep.getSymbolicName(), "" + dep.getVersion());
   if (state == Bundle.INSTALLED || state == Bundle.RESOLVED || state == Bundle.ACTIVE) {
     serviceName = serviceName.append(ConstantsHelper.bundleState(state));
   }
   return serviceName;
 }
/** @author <a href="*****@*****.**">Kabir Khan</a> */
public class SocketBindingUserService implements Service<SocketBindingUserService> {

  public static final ServiceName NAME = ServiceName.of("test", "binding", "user");
  public final InjectedValue<SocketBinding> socketBindingValue = new InjectedValue<SocketBinding>();

  @Override
  public SocketBindingUserService getValue()
      throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  @Override
  public void start(StartContext arg0) throws StartException {}

  @Override
  public void stop(StopContext arg0) {}
}
  private ServiceName getInjectorServiceName(
      final DeploymentUnit deploymentUnit,
      final AnnotationInstance annotation,
      final AbstractComponentDescription componentDescription,
      final DeploymentPhaseContext phaseContext,
      final String targetName,
      String injectionTypeName)
      throws DeploymentUnitProcessingException {

    String scopedPuName = getScopedPuName(deploymentUnit, annotation);
    ServiceName puServiceName = getPuServiceName(scopedPuName);
    ServiceName injectorName =
        ServiceName.of(
            componentDescription.getModuleName(),
            componentDescription.getComponentClassName(),
            targetName);
    if (isPersistenceContext(annotation)) {
      phaseContext
          .getServiceTarget()
          .addService(
              injectorName,
              new PersistenceContextInjectorService(
                  annotation, puServiceName, deploymentUnit, scopedPuName, injectionTypeName))
          .addDependency(puServiceName)
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
    } else {
      phaseContext
          .getServiceTarget()
          .addService(
              injectorName,
              new PersistenceUnitInjectorService(
                  annotation, puServiceName, deploymentUnit, scopedPuName, injectionTypeName))
          .addDependency(puServiceName)
          .setInitialMode(ServiceController.Mode.ACTIVE)
          .install();
    }
    return injectorName;
  }
 @SuppressWarnings({"unchecked"})
 private void addBean(
     final ServiceTarget serviceTarget,
     BeanMetaDataConfig beanConfig,
     Value<ClassLoader> classLoaderValue) {
   final String className = beanConfig.getBeanClass();
   final Value<Class<?>> classValue = cached(new LookupClassValue(className, classLoaderValue));
   final List<? extends Value<Class<?>>> types = Collections.emptyList();
   final Value<Constructor<?>> constructorValue =
       cached(new LookupConstructorValue(classValue, types));
   final List<? extends Value<?>> args = Collections.emptyList();
   final Value<Object> constructedValue = cached(new ConstructedValue(constructorValue, args));
   serviceTarget.addService(
       ServiceName.of(beanConfig.getName()),
       new AbstractService<Object>() {
         @Override
         public Object getValue() throws IllegalStateException {
           return constructedValue.getValue();
         }
       });
   // TODO -- missing a bunch of stuff
 }
示例#10
0
public class ServicesServices {

  private ServicesServices() {}

  public static final ServiceName TORQUEBOX = ServiceName.of("torquebox");
  public static final ServiceName SERVICES = TORQUEBOX.append("services");

  public static ServiceName serviceComponentResolver(DeploymentUnit unit, String serviceName) {
    return unit.getServiceName().append("component_resolver").append(serviceName);
  }

  public static ServiceName serviceCreateRubyService(DeploymentUnit unit, String serviceName) {
    return unit.getServiceName().append("service").append(serviceName).append("create");
  }

  public static ServiceName serviceStartRubyService(DeploymentUnit unit, String serviceName) {
    return unit.getServiceName().append("service").append(serviceName);
  }

  public static ServiceName serviceInjectableService(DeploymentUnit unit, String serviceName) {
    return serviceStartRubyService(unit, serviceName).append("injectable");
  }
}
  public List<ServiceState> getServiceReferencesInternal(
      AbstractBundle bundleState, String clazz, Filter filter, boolean checkAssignable) {
    if (bundleState == null) throw new IllegalArgumentException("Null bundleState");

    List<ServiceName> serviceNames;
    if (clazz != null) {
      serviceNames = serviceNameMap.get(clazz);
      if (serviceNames == null) serviceNames = new ArrayList<ServiceName>();

      // Add potentially registered xservcie
      ServiceName xserviceName = ServiceName.of(ModuleContext.XSERVICE_PREFIX, clazz);
      ServiceController<?> xservice = serviceContainer.getService(xserviceName);
      if (xservice != null) serviceNames.add(xserviceName);
    } else {
      // [MSC-9] Add ability to query the ServiceContainer
      Set<ServiceName> allServiceNames = new HashSet<ServiceName>();
      for (List<ServiceName> auxList : serviceNameMap.values()) allServiceNames.addAll(auxList);

      serviceNames = new ArrayList<ServiceName>(allServiceNames);
    }

    if (serviceNames.isEmpty()) return Collections.emptyList();

    if (filter == null) filter = NoFilter.INSTANCE;

    List<ServiceState> result = new ArrayList<ServiceState>();
    for (ServiceName serviceName : serviceNames) {
      ServiceController<?> controller = serviceContainer.getService(serviceName);
      if (controller == null)
        throw new IllegalStateException("Cannot obtain service for: " + serviceName);

      Object value = controller.getValue();

      // Create the ServiceState on demand for an XService instance
      // [TODO] This should be done eagerly to keep the serviceId constant
      // [TODO] service events for XService lifecycle changes
      // [MSC-17] Canonical ServiceName string representation
      if (value instanceof ServiceState == false
          && serviceName.toString().contains(ModuleContext.XSERVICE_PREFIX)) {
        long serviceId = getNextServiceId();
        Bundle bundle = packageAdmin.getBundle(value.getClass());
        AbstractBundle owner = AbstractBundle.assertBundleState(bundle);
        value =
            new ServiceState(
                owner,
                serviceId,
                new ServiceName[] {serviceName},
                new String[] {clazz},
                value,
                null);
      }

      ServiceState serviceState = (ServiceState) value;
      if (filter.match(serviceState) == false) continue;

      Object rawValue = serviceState.getRawValue();

      checkAssignable &= (clazz != null);
      checkAssignable &= (bundleState.getBundleId() != 0);
      checkAssignable &= !(rawValue instanceof ServiceFactory);
      if (checkAssignable == false || serviceState.isAssignableTo(bundleState, clazz)) {
        result.add(serviceState);
      }
    }

    // Sort the result
    Collections.sort(result, ServiceReferenceComparator.getInstance());
    Collections.reverse(result);

    return Collections.unmodifiableList(result);
  }
  @Override
  @SuppressWarnings({"rawtypes", "unchecked"})
  public ServiceState registerService(
      AbstractBundle bundleState, String[] clazzes, Object serviceValue, Dictionary properties) {
    if (clazzes == null || clazzes.length == 0)
      throw new IllegalArgumentException("Null service classes");

    // Immediately after registration of a {@link ListenerHook}, the ListenerHook.added() method
    // will be called
    // to provide the current collection of service listeners which had been added prior to the hook
    // being registered.
    Collection<ListenerInfo> listenerInfos = null;
    if (serviceValue instanceof ListenerHook)
      listenerInfos = eventsPlugin.getServiceListenerInfos(null);

    // A temporary association of the clazz and name
    Map<ServiceName, String> associations = new HashMap<ServiceName, String>();

    // Generate the service names
    long serviceId = getNextServiceId();
    ServiceName[] serviceNames = new ServiceName[clazzes.length];
    for (int i = 0; i < clazzes.length; i++) {
      if (clazzes[i] == null)
        throw new IllegalArgumentException("Null service class at index: " + i);

      String shortName = clazzes[i].substring(clazzes[i].lastIndexOf(".") + 1);
      serviceNames[i] =
          ServiceName.of(
              "jbosgi", bundleState.getSymbolicName(), shortName, new Long(serviceId).toString());
    }

    final ServiceState serviceState =
        new ServiceState(bundleState, serviceId, serviceNames, clazzes, serviceValue, properties);
    BatchBuilder batchBuilder = serviceContainer.batchBuilder();
    Service service =
        new Service() {
          @Override
          public Object getValue() throws IllegalStateException {
            // [TODO] for injection to work this needs to be the Object value
            return serviceState;
          }

          @Override
          public void start(StartContext context) throws StartException {}

          @Override
          public void stop(StopContext context) {}
        };

    log.debug("Register service: " + Arrays.asList(serviceNames));

    ServiceName rootServiceName = serviceNames[0];
    BatchServiceBuilder serviceBuilder = batchBuilder.addService(rootServiceName, service);
    associations.put(rootServiceName, clazzes[0]);

    // Set the startup mode
    serviceBuilder.setInitialMode(Mode.AUTOMATIC);

    // Add the service aliases
    for (int i = 1; i < serviceNames.length; i++) {
      ServiceName alias = serviceNames[i];
      associations.put(alias, clazzes[1]);
      serviceBuilder.addAliases(alias);
    }

    try {
      batchBuilder.install();

      // Register the name association. We do this here
      // in case anything went wrong during the install
      for (Entry<ServiceName, String> aux : associations.entrySet()) {
        bundleState.addRegisteredService(serviceState);
        registerNameAssociation(aux.getValue(), aux.getKey());
      }
    } catch (ServiceRegistryException ex) {
      log.error("Cannot register services: " + serviceNames, ex);
    }

    // Call the newly added ListenerHook.added() method
    if (serviceValue instanceof ListenerHook) {
      ListenerHook listenerHook = (ListenerHook) serviceValue;
      listenerHook.added(listenerInfos);
    }

    // This event is synchronously delivered after the service has been registered with the
    // Framework.
    eventsPlugin.fireServiceEvent(bundleState, ServiceEvent.REGISTERED, serviceState);

    return serviceState;
  }
示例#13
0
 public static ServiceName transportServiceName(String name) {
   return ServiceName.of(TRANSPORT_BASE, name);
 }
示例#14
0
 public static ServiceName translatorServiceName(String name) {
   return ServiceName.of(TRANSLATOR_BASE, name);
 }
示例#15
0
/**
 * MK2 implementation of EJB3.1 {@link TimerService}
 *
 * @author <a href="mailto:[email protected]">Carlo de Wolf</a>
 * @version $Revision: $
 */
public class TimerServiceImpl implements TimerService, Service<TimerService> {

  /** inactive timer states */
  private static final Set<TimerState> ineligibleTimerStates;

  /** Logger */
  private static final Logger logger = Logger.getLogger(TimerServiceImpl.class);

  public static final ServiceName SERVICE_NAME = ServiceName.of("ejb3", "timerService");

  /** The service name this timer service is registered under */
  private final ServiceName serviceName;

  private final InjectedValue<EJBComponent> ejbComponentInjectedValue =
      new InjectedValue<EJBComponent>();

  private final InjectedValue<ExecutorService> executorServiceInjectedValue =
      new InjectedValue<ExecutorService>();

  private final InjectedValue<java.util.Timer> timerInjectedValue =
      new InjectedValue<java.util.Timer>();

  private final InjectedValue<TimedObjectInvoker> timedObjectInvoker =
      new InjectedValue<TimedObjectInvoker>();

  /** Auto timers that should be added on startup */
  private final Map<Method, List<AutoTimer>> autoTimers;

  /** Used for persistent timers */
  private final InjectedValue<TimerPersistence> timerPersistence =
      new InjectedValue<TimerPersistence>();

  /** All timers which were created by this {@link TimerService} */
  private final Map<String, TimerImpl> timers =
      Collections.synchronizedMap(new HashMap<String, TimerImpl>());

  /**
   * Holds the {@link java.util.concurrent.Future} of each of the timer tasks that have been
   * scheduled
   */
  private final Map<String, java.util.TimerTask> scheduledTimerFutures =
      new HashMap<String, java.util.TimerTask>();

  /**
   * Key that is used to store timers that are waiting on transaction completion in the transaction
   * local
   */
  private static final Object waitingOnTxCompletionKey = new Object();

  private TransactionManager transactionManager;
  private TransactionSynchronizationRegistry tsr;
  private final TimerServiceRegistry timerServiceRegistry;

  /** Dynamic resource. Exposed under service=timer-service. */
  private TimerServiceResource resource = new TimerServiceResource();

  private Closeable listenerHandle;

  private volatile boolean started = false;

  static {
    final Set<TimerState> states = new HashSet<TimerState>();
    states.add(TimerState.CANCELED);
    states.add(TimerState.EXPIRED);
    ineligibleTimerStates = Collections.unmodifiableSet(states);
  }

  /**
   * Creates a {@link TimerServiceImpl}
   *
   * @param autoTimers
   * @param serviceName
   * @throws IllegalArgumentException If either of the passed param is null
   * @deprecated Use {@link #TimerServiceImpl(java.util.Map, org.jboss.msc.service.ServiceName,
   *     org.jboss.as.ejb3.component.TimerServiceRegistry)} instead
   */
  @Deprecated
  public TimerServiceImpl(
      final Map<Method, List<AutoTimer>> autoTimers, final ServiceName serviceName) {
    this(autoTimers, serviceName, null);
  }

  /**
   * Creates a {@link TimerServiceImpl}
   *
   * @param autoTimers The auto timers associated with this timer service
   * @param serviceName The service name of this timer service
   * @param registry The {@link TimerServiceRegistry} which has the knowledge of other timer
   *     services belonging to the EJB module to which this timer service belongs.
   */
  public TimerServiceImpl(
      final Map<Method, List<AutoTimer>> autoTimers,
      final ServiceName serviceName,
      final TimerServiceRegistry registry) {
    this.autoTimers = autoTimers;
    this.serviceName = serviceName;
    this.timerServiceRegistry = registry;
  }

  @Override
  public synchronized void start(final StartContext context) throws StartException {

    if (logger.isDebugEnabled()) {
      logger.debug("Starting timerservice for timedObjectId: " + getInvoker().getTimedObjectId());
    }
    final EJBComponent component = ejbComponentInjectedValue.getValue();
    this.transactionManager = component.getTransactionManager();
    this.tsr = component.getTransactionSynchronizationRegistry();
    final TimedObjectInvoker invoker = timedObjectInvoker.getValue();
    if (invoker == null) {
      throw EjbLogger.ROOT_LOGGER.invokerIsNull();
    }

    started = true;
    // register ourselves to the TimerServiceRegistry (if any)
    if (timerServiceRegistry != null) {
      timerServiceRegistry.registerTimerService(this);
    }
    listenerHandle =
        timerPersistence
            .getValue()
            .registerChangeListener(getInvoker().getTimedObjectId(), new TimerRefreshListener());
  }

  @Override
  public synchronized void stop(final StopContext context) {
    // un-register ourselves to the TimerServiceRegistry (if any)
    if (timerServiceRegistry != null) {
      timerServiceRegistry.unRegisterTimerService(this);
    }

    timerPersistence.getValue().timerUndeployed(timedObjectInvoker.getValue().getTimedObjectId());
    started = false;
    this.transactionManager = null;
    IoUtils.safeClose(listenerHandle);
    listenerHandle = null;
    timerInjectedValue.getValue().purge(); // WFLY-3823
  }

  public synchronized void activate() {
    final List<ScheduleTimer> timers = new ArrayList<ScheduleTimer>();
    for (Map.Entry<Method, List<AutoTimer>> entry : autoTimers.entrySet()) {
      for (AutoTimer timer : entry.getValue()) {
        timers.add(
            new ScheduleTimer(
                entry.getKey(), timer.getScheduleExpression(), timer.getTimerConfig()));
      }
    }
    // restore the timers
    restoreTimers(timers);
  }

  public synchronized void deactivate() {
    suspendTimers();
  }

  @Override
  public synchronized TimerService getValue()
      throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public Timer createCalendarTimer(ScheduleExpression schedule)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    return this.createCalendarTimer(schedule, null);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createCalendarTimer(ScheduleExpression schedule, TimerConfig timerConfig)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    Serializable info = timerConfig == null ? null : timerConfig.getInfo();
    boolean persistent = timerConfig == null || timerConfig.isPersistent();
    return this.createCalendarTimer(schedule, info, persistent, null);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createIntervalTimer(
      Date initialExpiration, long intervalDuration, TimerConfig timerConfig)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (initialExpiration == null) {
      throw EjbLogger.ROOT_LOGGER.initialExpirationIsNullCreatingTimer();
    }
    if (initialExpiration.getTime() < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidInitialExpiration("initialExpiration.getTime()");
    }
    if (intervalDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidInitialExpiration("intervalDuration");
    }
    return this.createTimer(
        initialExpiration, intervalDuration, timerConfig.getInfo(), timerConfig.isPersistent());
  }

  /** {@inheritDoc} */
  @Override
  public Timer createIntervalTimer(
      long initialDuration, long intervalDuration, TimerConfig timerConfig)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (initialDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidInitialExpiration("intervalDuration");
    }
    if (intervalDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidInitialExpiration("intervalDuration");
    }

    return this.createIntervalTimer(
        new Date(System.currentTimeMillis() + initialDuration), intervalDuration, timerConfig);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createSingleActionTimer(Date expiration, TimerConfig timerConfig)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (expiration == null) {
      throw EjbLogger.ROOT_LOGGER.expirationIsNull();
    }
    if (expiration.getTime() < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidExpirationActionTimer();
    }
    return this.createTimer(expiration, 0, timerConfig.getInfo(), timerConfig.isPersistent());
  }

  /** {@inheritDoc} */
  @Override
  public Timer createSingleActionTimer(long duration, TimerConfig timerConfig)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (duration < 0) throw EjbLogger.ROOT_LOGGER.invalidDurationActionTimer();

    return createTimer(
        new Date(System.currentTimeMillis() + duration),
        0,
        timerConfig.getInfo(),
        timerConfig.isPersistent());
  }

  /** {@inheritDoc} */
  @Override
  public Timer createTimer(long duration, Serializable info)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (duration < 0) throw EjbLogger.ROOT_LOGGER.invalidDurationTimer();
    return createTimer(new Date(System.currentTimeMillis() + duration), 0, info, true);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createTimer(Date expiration, Serializable info)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (expiration == null) {
      throw EjbLogger.ROOT_LOGGER.expirationDateIsNull();
    }
    if (expiration.getTime() < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidExpirationTimer();
    }
    return this.createTimer(expiration, 0, info, true);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createTimer(long initialDuration, long intervalDuration, Serializable info)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (initialDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidInitialDurationTimer();
    }
    if (intervalDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidIntervalTimer();
    }
    return this.createTimer(
        new Date(System.currentTimeMillis() + initialDuration), intervalDuration, info, true);
  }

  /** {@inheritDoc} */
  @Override
  public Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info)
      throws IllegalArgumentException, IllegalStateException, EJBException {
    assertTimerServiceState();
    if (initialExpiration == null) {
      throw EjbLogger.ROOT_LOGGER.initialExpirationDateIsNull();
    }
    if (initialExpiration.getTime() < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidExpirationTimer();
    }
    if (intervalDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidIntervalDurationTimer();
    }
    return this.createTimer(initialExpiration, intervalDuration, info, true);
  }

  public TimerImpl loadAutoTimer(
      ScheduleExpression schedule, TimerConfig timerConfig, Method timeoutMethod) {
    return this.createCalendarTimer(
        schedule, timerConfig.getInfo(), timerConfig.isPersistent(), timeoutMethod);
  }

  /** {@inheritDoc} */
  @Override
  public Collection<Timer> getTimers() throws IllegalStateException, EJBException {
    assertTimerServiceState();
    Object pk = currentPrimaryKey();
    final Set<Timer> activeTimers = new HashSet<Timer>();
    // get all active timers for this timerservice
    synchronized (this.timers) {
      for (final TimerImpl timer : this.timers.values()) {
        if (timer.isActive()) {
          if (timer.getPrimaryKey() == null || timer.getPrimaryKey().equals(pk)) {
            activeTimers.add(timer);
          }
        }
      }
    }
    // get all active timers which are persistent, but haven't yet been
    // persisted (waiting for tx to complete) that are in the current transaction
    for (final TimerImpl timer : getWaitingOnTxCompletionTimers().values()) {
      if (timer.isActive()) {
        if (timer.getPrimaryKey() == null || timer.getPrimaryKey().equals(pk)) {
          activeTimers.add(timer);
        }
      }
    }
    return activeTimers;
  }

  /** {@inheritDoc} */
  @Override
  public Collection<Timer> getAllTimers() throws IllegalStateException, EJBException {
    // query the registry
    if (this.timerServiceRegistry != null) {
      return this.timerServiceRegistry.getAllActiveTimers();
    }
    // if we don't have the registry (shouldn't really happen) which stores the timer services
    // applicable for the EJB module to which
    // this timer service belongs, then let's at least return the active timers that are applicable
    // only for this timer service
    return this.getTimers();
  }

  /**
   * Create a {@link javax.ejb.Timer}
   *
   * @param initialExpiration The {@link java.util.Date} at which the first timeout should occur.
   *     <p>If the date is in the past, then the timeout is triggered immediately when the timer
   *     moves to {@link TimerState#ACTIVE}
   * @param intervalDuration The interval (in milliseconds) between consecutive timeouts for the
   *     newly created timer.
   *     <p>Cannot be a negative value. A value of 0 indicates a single timeout action
   * @param info {@link java.io.Serializable} info that will be made available through the newly
   *     created timer's {@link javax.ejb.Timer#getInfo()} method
   * @param persistent True if the newly created timer has to be persistent
   * @return Returns the newly created timer
   * @throws IllegalArgumentException If <code>initialExpiration</code> is null or <code>
   *     intervalDuration</code> is negative
   * @throws IllegalStateException If this method was invoked during a lifecycle callback on the EJB
   */
  private Timer createTimer(
      Date initialExpiration, long intervalDuration, Serializable info, boolean persistent) {
    if (this.isLifecycleCallbackInvocation() && !this.isSingletonBeanInvocation()) {
      throw EjbLogger.ROOT_LOGGER.failToCreateTimerDoLifecycle();
    }
    if (initialExpiration == null) {
      throw EjbLogger.ROOT_LOGGER.initialExpirationIsNull();
    }
    if (intervalDuration < 0) {
      throw EjbLogger.ROOT_LOGGER.invalidIntervalDuration();
    }

    // create an id for the new timer instance
    UUID uuid = UUID.randomUUID();
    // create the timer

    TimerImpl timer =
        TimerImpl.builder()
            .setNewTimer(true)
            .setId(uuid.toString())
            .setInitialDate(initialExpiration)
            .setRepeatInterval(intervalDuration)
            .setInfo(info)
            .setPersistent(persistent)
            .setPrimaryKey(currentPrimaryKey())
            .setTimerState(TimerState.CREATED)
            .setTimedObjectId(getInvoker().getTimedObjectId())
            .build(this);

    // now "start" the timer. This involves, moving the timer to an ACTIVE state
    // and scheduling the timer task

    this.persistTimer(timer, true);
    this.startTimer(timer);
    // return the newly created timer
    return timer;
  }

  /** @return The primary key of the current EJB, or null if not applicable */
  private Object currentPrimaryKey() {

    final InterceptorContext context = CurrentInvocationContext.get();

    if (context == null) {
      return null;
    }
    return context.getPrivateData(EntityBeanComponent.PRIMARY_KEY_CONTEXT_KEY);
  }

  /**
   * Creates a calendar based {@link javax.ejb.Timer}
   *
   * @param schedule The {@link javax.ejb.ScheduleExpression} which will be used for creating
   *     scheduled timer tasks for a calendar based timer
   * @param info {@link java.io.Serializable} info that will be made available through the newly
   *     created timer's {@link javax.ejb.Timer#getInfo()} method
   * @param persistent True if the newly created timer has to be persistent
   * @return Returns the newly created timer
   * @throws IllegalArgumentException If the passed <code>schedule</code> is null
   * @throws IllegalStateException If this method was invoked during a lifecycle callback on the EJB
   */
  private TimerImpl createCalendarTimer(
      ScheduleExpression schedule, Serializable info, boolean persistent, Method timeoutMethod) {
    if (this.isLifecycleCallbackInvocation() && !this.isSingletonBeanInvocation()) {
      throw EjbLogger.ROOT_LOGGER.failToCreateTimerDoLifecycle();
    }
    if (schedule == null) {
      throw EjbLogger.ROOT_LOGGER.scheduleIsNull();
    }
    // generate an id for the timer
    UUID uuid = UUID.randomUUID();
    // create the timer
    TimerImpl timer =
        CalendarTimer.builder()
            .setAutoTimer(timeoutMethod != null)
            .setScheduleExprSecond(schedule.getSecond())
            .setScheduleExprMinute(schedule.getMinute())
            .setScheduleExprHour(schedule.getHour())
            .setScheduleExprDayOfWeek(schedule.getDayOfWeek())
            .setScheduleExprDayOfMonth(schedule.getDayOfMonth())
            .setScheduleExprMonth(schedule.getMonth())
            .setScheduleExprYear(schedule.getYear())
            .setScheduleExprStartDate(schedule.getStart())
            .setScheduleExprEndDate(schedule.getEnd())
            .setScheduleExprTimezone(schedule.getTimezone())
            .setTimeoutMethod(timeoutMethod)
            .setTimerState(TimerState.CREATED)
            .setId(uuid.toString())
            .setPersistent(persistent)
            .setPrimaryKey(currentPrimaryKey())
            .setTimedObjectId(getInvoker().getTimedObjectId())
            .setInfo(info)
            .setNewTimer(true)
            .build(this);

    this.persistTimer(timer, true);
    // now "start" the timer. This involves, moving the timer to an ACTIVE state
    // and scheduling the timer task
    this.startTimer(timer);
    // return the timer
    return timer;
  }

  public TimerImpl getTimer(final String timerId) {
    return timers.get(timerId);
  }

  /**
   * Returns the {@link TimedObjectInvoker} to which this timer service belongs
   *
   * @return
   */
  public TimedObjectInvoker getInvoker() {
    return timedObjectInvoker.getValue();
  }

  /**
   * Returns the {@link javax.ejb.Timer} corresponding to the passed {@link javax.ejb.TimerHandle}
   *
   * @param handle The {@link javax.ejb.TimerHandle} for which the {@link javax.ejb.Timer} is being
   *     looked for
   */
  public TimerImpl getTimer(TimerHandle handle) {
    TimerHandleImpl timerHandle = (TimerHandleImpl) handle;
    TimerImpl timer = timers.get(timerHandle.getId());
    if (timer != null) {
      return timer;
    }
    return getWaitingOnTxCompletionTimers().get(timerHandle.getId());
  }

  /**
   * @return Returns the current transaction, if any. Else returns null.
   * @throws javax.ejb.EJBException If there is any system level exception
   */
  protected Transaction getTransaction() {
    try {
      return transactionManager.getTransaction();
    } catch (SystemException e) {
      throw new EJBException(e);
    }
  }

  /**
   * Persists the passed <code>timer</code>.
   *
   * <p>
   *
   * <p>If the passed timer is null or is non-persistent (i.e. {@link
   * javax.ejb.Timer#isPersistent()} returns false), then this method acts as a no-op
   *
   * @param timer
   */
  public void persistTimer(final TimerImpl timer, boolean newTimer) {
    if (timer == null) {
      return;
    }
    if (timer.isTimerPersistent()) {
      try {
        if (timerPersistence.getOptionalValue() == null) {
          ROOT_LOGGER.timerPersistenceNotEnable();
          return;
        }
        if (newTimer) {
          timerPersistence.getValue().addTimer(timer);
        } else {
          timerPersistence.getValue().persistTimer(timer);
        }

      } catch (Throwable t) {
        this.setRollbackOnly();
        throw new RuntimeException(t);
      }
    }
  }

  public void cancelTimer(final TimerImpl timer) {
    timer.lock();
    boolean release = true;
    try {
      // first check whether the timer has expired or has been cancelled
      timer.assertTimerState();
      boolean startedInTx = getWaitingOnTxCompletionTimers().containsKey(timer.getId());
      if (timer.getState() != TimerState.EXPIRED) {
        timer.setTimerState(TimerState.CANCELED);
      }
      if (transactionActive() && !startedInTx) {
        registerSynchronization(new TimerRemoveSynchronization(timer));
        release = false;
      } else {
        // cancel any scheduled Future for this timer
        this.cancelTimeout(timer);
        this.unregisterTimerResource(timer.getId());
        this.timers.remove(timer.getId());
      }
      // persist changes
      persistTimer(timer, false);
    } finally {
      if (release) {
        timer.unlock();
      }
    }
  }

  public void expireTimer(final TimerImpl timer) {
    this.cancelTimeout(timer);
    timer.setTimerState(TimerState.EXPIRED);
    this.unregisterTimerResource(timer.getId());
    this.timers.remove(timer.getId());
  }

  /**
   * Suspends any currently scheduled tasks for {@link javax.ejb.Timer}s
   *
   * <p>Note that, suspend does <b>not</b> cancel the {@link javax.ejb.Timer}. Instead, it just
   * cancels the <b>next scheduled timeout</b>. So once the {@link javax.ejb.Timer} is restored
   * (whenever that happens), the {@link javax.ejb.Timer} will continue to timeout at appropriate
   * times.
   */
  public void suspendTimers() {
    // get all active timers (persistent/non-persistent inclusive)
    Collection<Timer> timers = this.getTimers();
    for (Timer timer : timers) {
      if (!(timer instanceof TimerImpl)) {
        continue;
      }
      // suspend the timer
      ((TimerImpl) timer).suspend();
    }
  }

  /**
   * Restores persisted timers, corresponding to this timerservice, which are eligible for any new
   * timeouts.
   *
   * <p>This includes timers whose {@link TimerState} is <b>neither</b> of the following:
   *
   * <ul>
   *   <li>{@link TimerState#CANCELED}
   *   <li>{@link TimerState#EXPIRED}
   * </ul>
   *
   * <p>All such restored timers will be schedule for their next timeouts.
   *
   * @param autoTimers
   */
  public void restoreTimers(final List<ScheduleTimer> autoTimers) {
    // get the persisted timers which are considered active
    List<TimerImpl> restorableTimers = this.getActivePersistentTimers();

    // timers are removed from the list as they are loaded
    final List<ScheduleTimer> newAutoTimers = new LinkedList<ScheduleTimer>(autoTimers);

    if (ROOT_LOGGER.isDebugEnabled()) {
      ROOT_LOGGER.debug(
          "Found "
              + restorableTimers.size()
              + " active persistentTimers for timedObjectId: "
              + getInvoker().getTimedObjectId());
    }
    // now "start" each of the restorable timer. This involves, moving the timer to an ACTIVE state
    // and scheduling the timer task
    for (final TimerImpl activeTimer : restorableTimers) {

      if (activeTimer.isAutoTimer()) {
        CalendarTimer calendarTimer = (CalendarTimer) activeTimer;
        boolean found = false;
        // so we know we have an auto timer. We need to try and match it up with the auto timers.
        ListIterator<ScheduleTimer> it = newAutoTimers.listIterator();
        while (it.hasNext()) {
          ScheduleTimer timer = it.next();
          final String methodName = timer.getMethod().getName();
          final String[] params = new String[timer.getMethod().getParameterTypes().length];
          for (int i = 0; i < timer.getMethod().getParameterTypes().length; ++i) {
            params[i] = timer.getMethod().getParameterTypes()[i].getName();
          }
          if (doesTimeoutMethodMatch(calendarTimer.getTimeoutMethod(), methodName, params)) {

            // the timers have the same method.
            // now lets make sure the schedule is the same
            // and the timer does not change the persistence
            if (this.doesScheduleMatch(
                    calendarTimer.getScheduleExpression(), timer.getScheduleExpression())
                && timer.getTimerConfig().isPersistent()) {
              it.remove();
              found = true;
              break;
            }
          }
        }
        if (!found) {
          activeTimer.setTimerState(TimerState.CANCELED);
        } else {
          // ensure state switch to active if was TIMEOUT in the DB
          // if the persistence is shared it must be ensured to not update
          // timers of other nodes in the cluster
          activeTimer.setTimerState(TimerState.ACTIVE);
        }
        this.persistTimer(activeTimer, false);
        if (found) {
          startTimer(activeTimer);
          ROOT_LOGGER.debugv("Started timer: {0}", activeTimer);
        }
      } else if (!ineligibleTimerStates.contains(activeTimer.getState())) {
        startTimer(activeTimer);
      }
      ROOT_LOGGER.debugv("Started timer: {0}", activeTimer);
    }

    for (ScheduleTimer timer : newAutoTimers) {
      this.loadAutoTimer(timer.getScheduleExpression(), timer.getTimerConfig(), timer.getMethod());
    }
  }

  /**
   * Registers a timer with a transaction (if any in progress) and then moves the timer to an active
   * state, so that it becomes eligible for timeouts
   */
  protected void startTimer(TimerImpl timer) {
    // if there's no transaction, then trigger a schedule immediately.
    // Else, the timer will be scheduled on tx synchronization callback
    if (!transactionActive()) {
      this.timers.put(timer.getId(), timer);
      // set active if the timer is started if it was read
      // from persistence as current running to ensure correct schedule here
      timer.setTimerState(TimerState.ACTIVE);
      // create and schedule a timer task
      this.registerTimerResource(timer.getId());
      timer.scheduleTimeout(true);
    } else {
      addWaitingOnTxCompletionTimer(timer);
      registerSynchronization(new TimerCreationTransactionSynchronization(timer));
    }
  }

  private void registerSynchronization(Synchronization synchronization) {
    try {
      final Transaction tx = this.getTransaction();
      // register for lifecycle events of transaction
      tx.registerSynchronization(synchronization);
    } catch (RollbackException e) {
      throw new EJBException(e);
    } catch (SystemException e) {
      throw new EJBException(e);
    }
  }

  /** @return true if the transaction is in a state where synchronizations can be registered */
  boolean transactionActive() {
    final Transaction currentTx = getTransaction();
    if (currentTx != null) {
      try {
        int status = currentTx.getStatus();
        if (status == Status.STATUS_MARKED_ROLLBACK
            || status == Status.STATUS_ROLLEDBACK
            || status == Status.STATUS_ROLLING_BACK
            || status == Status.STATUS_NO_TRANSACTION
            || status == Status.STATUS_UNKNOWN
            || status == Status.STATUS_COMMITTED
            || isBeforeCompletion()) {
          return false;
        } else {
          return true;
        }
      } catch (SystemException e) {
        throw new RuntimeException(e);
      }
    } else {
      return false;
    }
  }

  private boolean isBeforeCompletion() {
    final CurrentSynchronizationCallback.CallbackType type = CurrentSynchronizationCallback.get();
    if (type != null) {
      return type == CurrentSynchronizationCallback.CallbackType.BEFORE_COMPLETION;
    }
    return false;
  }

  /**
   * Returns true if the {@link CurrentInvocationContext} represents a lifecycle callback
   * invocation. Else returns false.
   *
   * <p>This method internally relies on {@link CurrentInvocationContext#get()} to obtain the
   * current invocation context.
   *
   * <ul>
   *   <li>If the context is available then it looks for the method that was invoked. The absence of
   *       a method indicates a lifecycle callback.
   *   <li>If the context is <i>not</i> available, then this method returns false (i.e. it doesn't
   *       consider the current invocation as a lifecycle callback). This is for convenience, to
   *       allow the invocation of {@link javax.ejb.TimerService} methods in the absence of {@link
   *       CurrentInvocationContext}
   * </ul>
   *
   * <p>
   *
   * @return
   */
  protected boolean isLifecycleCallbackInvocation() {
    final InterceptorContext currentInvocationContext = CurrentInvocationContext.get();
    if (currentInvocationContext == null) {
      return false;
    }
    // If the method in current invocation context is null,
    // then it represents a lifecycle callback invocation
    Method invokedMethod = currentInvocationContext.getMethod();
    if (invokedMethod == null) {
      // it's a lifecycle callback
      return true;
    }
    // not a lifecycle callback
    return false;
  }

  /**
   * Creates and schedules a {@link org.jboss.as.ejb3.timerservice.task.TimerTask} for the next
   * timeout of the passed <code>timer</code>
   */
  protected void scheduleTimeout(TimerImpl timer, boolean newTimer) {
    synchronized (scheduledTimerFutures) {
      if (!newTimer && !scheduledTimerFutures.containsKey(timer.getId())) {
        // this timer has been cancelled by another thread. We just return
        return;
      }

      Date nextExpiration = timer.getNextExpiration();
      if (nextExpiration == null) {
        ROOT_LOGGER.nextExpirationIsNull(timer);
        return;
      }
      // create the timer task
      final TimerTask<?> timerTask = timer.getTimerTask();
      // find out how long is it away from now
      long delay = nextExpiration.getTime() - System.currentTimeMillis();
      // if in past, then trigger immediately
      if (delay < 0) {
        delay = 0;
      }
      long intervalDuration = timer.getInterval();
      final Task task = new Task(timerTask, ejbComponentInjectedValue.getValue().getControlPoint());
      if (intervalDuration > 0) {
        ROOT_LOGGER.debugv(
            "Scheduling timer {0} at fixed rate, starting at {1} milliseconds from now with repeated interval={2}",
            timer, delay, intervalDuration);
        // schedule the task
        this.timerInjectedValue.getValue().scheduleAtFixedRate(task, delay, intervalDuration);
        // maintain it in timerservice for future use (like cancellation)
        this.scheduledTimerFutures.put(timer.getId(), task);
      } else {
        ROOT_LOGGER.debugv(
            "Scheduling a single action timer {0} starting at {1} milliseconds from now",
            timer, delay);
        // schedule the task
        this.timerInjectedValue.getValue().schedule(task, delay);
        // maintain it in timerservice for future use (like cancellation)
        this.scheduledTimerFutures.put(timer.getId(), task);
      }
    }
  }

  /**
   * Cancels any scheduled {@link java.util.concurrent.Future} corresponding to the passed <code>
   * timer</code>
   *
   * @param timer
   */
  protected void cancelTimeout(final TimerImpl timer) {
    synchronized (this.scheduledTimerFutures) {
      java.util.TimerTask timerTask = this.scheduledTimerFutures.remove(timer.getId());
      if (timerTask != null) {
        timerTask.cancel();
      }
    }
  }

  public void invokeTimeout(final TimerImpl timer) {
    synchronized (this.scheduledTimerFutures) {
      if (this.scheduledTimerFutures.containsKey(timer.getId())) {
        timer.getTimerTask().run();
      }
    }
  }

  public boolean isScheduled(final String tid) {
    synchronized (this.scheduledTimerFutures) {
      return this.scheduledTimerFutures.containsKey(tid);
    }
  }

  /**
   * Returns an unmodifiable view of timers in the current transaction that are waiting for the
   * transaction to finish
   */
  private Map<String, TimerImpl> getWaitingOnTxCompletionTimers() {
    Map<String, TimerImpl> timers = null;
    if (getTransaction() != null) {
      timers = (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey);
    }
    return timers == null ? Collections.<String, TimerImpl>emptyMap() : timers;
  }

  private void addWaitingOnTxCompletionTimer(final TimerImpl timer) {
    Map<String, TimerImpl> timers =
        (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey);
    if (timers == null) {
      tsr.putResource(waitingOnTxCompletionKey, timers = new HashMap<String, TimerImpl>());
    }
    timers.put(timer.getId(), timer);
  }

  private boolean isSingletonBeanInvocation() {
    return ejbComponentInjectedValue.getValue() instanceof SingletonComponent;
  }

  private List<TimerImpl> getActivePersistentTimers() {
    // we need only those timers which correspond to the
    // timed object invoker to which this timer service belongs. So
    // first get hold of the timed object id
    final String timedObjectId = this.getInvoker().getTimedObjectId();
    // timer states which do *not* represent an active timer
    if (timerPersistence.getOptionalValue() == null) {
      // if the persistence setting is null then there are no persistent timers
      return Collections.emptyList();
    }

    final List<TimerImpl> persistedTimers =
        timerPersistence.getValue().loadActiveTimers(timedObjectId, this);
    final List<TimerImpl> activeTimers = new ArrayList<TimerImpl>();
    for (final TimerImpl persistedTimer : persistedTimers) {
      if (ineligibleTimerStates.contains(persistedTimer.getState())) {
        continue;
      }
      // add it to the list of timers which will be restored
      activeTimers.add(persistedTimer);
    }

    return activeTimers;
  }

  private boolean doesTimeoutMethodMatch(
      final Method timeoutMethod, final String timeoutMethodName, final String[] methodParams) {
    if (timeoutMethod.getName().equals(timeoutMethodName) == false) {
      return false;
    }
    final Class<?>[] timeoutMethodParams = timeoutMethod.getParameterTypes();
    return this.methodParamsMatch(timeoutMethodParams, methodParams);
  }

  private boolean doesScheduleMatch(
      final ScheduleExpression expression1, final ScheduleExpression expression2) {
    if (!same(expression1.getDayOfMonth(), expression2.getDayOfMonth())) {
      return false;
    }
    if (!same(expression1.getDayOfWeek(), expression2.getDayOfWeek())) {
      return false;
    }
    if (!same(expression1.getEnd(), expression2.getEnd())) {
      return false;
    }
    if (!same(expression1.getHour(), expression2.getHour())) {
      return false;
    }
    if (!same(expression1.getMinute(), expression2.getMinute())) {
      return false;
    }
    if (!same(expression1.getMonth(), expression2.getMonth())) {
      return false;
    }
    if (!same(expression1.getSecond(), expression2.getSecond())) {
      return false;
    }
    if (!same(expression1.getStart(), expression2.getStart())) {
      return false;
    }
    if (!same(expression1.getTimezone(), expression2.getTimezone())) {
      return false;
    }
    if (!same(expression1.getYear(), expression2.getYear())) {
      return false;
    }
    return true;
  }

  private boolean same(Object i1, Object i2) {
    if (i1 == null && i2 != null) {
      return false;
    }
    if (i2 == null && i1 != null) {
      return false;
    }
    if (i1 == null && i2 == null) {
      return true;
    }
    return i1.equals(i2);
  }

  private boolean methodParamsMatch(Class<?>[] methodParams, String[] otherMethodParams) {
    if (otherMethodParams == null) {
      otherMethodParams = new String[0];
    }
    if (methodParams.length != otherMethodParams.length) {
      return false;
    }
    for (int i = 0; i < methodParams.length; i++) {
      if (!methodParams[i].getName().equals(otherMethodParams[i])) {
        return false;
      }
    }
    return true;
  }

  /**
   * Marks the transaction for rollback NOTE: This method will soon be removed, once this timer
   * service implementation becomes "managed"
   */
  private void setRollbackOnly() {
    try {
      Transaction tx = this.transactionManager.getTransaction();
      if (tx != null) {
        tx.setRollbackOnly();
      }
    } catch (IllegalStateException ise) {
      ROOT_LOGGER.ignoringException(ise);
    } catch (SystemException se) {
      ROOT_LOGGER.ignoringException(se);
    }
  }

  private void assertTimerServiceState() {
    AllowedMethodsInformation.checkAllowed(MethodType.TIMER_SERVICE_METHOD);
    if (isLifecycleCallbackInvocation() && !this.isSingletonBeanInvocation()) {
      throw EjbLogger.ROOT_LOGGER.failToInvokeTimerServiceDoLifecycle();
    }
  }

  public InjectedValue<EJBComponent> getEjbComponentInjectedValue() {
    return ejbComponentInjectedValue;
  }

  public InjectedValue<ExecutorService> getExecutorServiceInjectedValue() {
    return executorServiceInjectedValue;
  }

  public InjectedValue<java.util.Timer> getTimerInjectedValue() {
    return timerInjectedValue;
  }

  public InjectedValue<TimerPersistence> getTimerPersistence() {
    return timerPersistence;
  }

  public ServiceName getServiceName() {
    return serviceName;
  }

  public boolean isStarted() {
    return started;
  }

  public InjectedValue<TimedObjectInvoker> getTimedObjectInvoker() {
    return timedObjectInvoker;
  }

  public TimerServiceResource getResource() {
    return resource;
  }

  private void registerTimerResource(final String timerId) {
    this.resource.timerCreated(timerId);
  }

  private void unregisterTimerResource(final String timerId) {
    this.resource.timerRemoved(timerId);
  }

  /**
   * Check if a persistent timer is already executed from a different instance or should be
   * executed. For non-persistent timer it always return <code>true</code>.
   *
   * @param timer the timer which should be checked
   * @return <code>true</code> if the timer is not persistent or the persistent timer should start
   */
  public boolean shouldRun(TimerImpl timer) {
    return !timer.isPersistent()
        || timerPersistence.getValue().shouldRun(timer, this.transactionManager);
  }

  private class TimerCreationTransactionSynchronization implements Synchronization {
    /** The timer being managed in the transaction */
    private final TimerImpl timer;

    public TimerCreationTransactionSynchronization(TimerImpl timer) {
      if (timer == null) {
        throw EjbLogger.ROOT_LOGGER.timerIsNull();
      }
      this.timer = timer;
    }

    @Override
    public void beforeCompletion() {}

    /** {@inheritDoc} */
    @Override
    public void afterCompletion(int status) {
      if (status == Status.STATUS_COMMITTED) {
        ROOT_LOGGER.debugv("commit timer creation: {0}", this.timer);
        timers.put(timer.getId(), timer);

        registerTimerResource(timer.getId());
        TimerState timerState = this.timer.getState();
        switch (timerState) {
          case CREATED:
            this.timer.setTimerState(TimerState.ACTIVE);
            this.timer.scheduleTimeout(true);
            break;
          case ACTIVE:
            this.timer.scheduleTimeout(true);
            break;
        }
      } else if (status == Status.STATUS_ROLLEDBACK) {
        ROOT_LOGGER.debugv("Rolling back timer creation: {0}", this.timer);
        this.timer.setTimerState(TimerState.CANCELED);
      }
    }
  }

  private class TimerRemoveSynchronization implements Synchronization {

    private final TimerImpl timer;

    private TimerRemoveSynchronization(final TimerImpl timer) {
      this.timer = timer;
    }

    @Override
    public void beforeCompletion() {}

    @Override
    public void afterCompletion(final int status) {
      try {
        if (status == Status.STATUS_COMMITTED) {
          cancelTimeout(timer);
          unregisterTimerResource(timer.getId());
          timers.remove(timer.getId());
        } else {
          timer.setTimerState(TimerState.ACTIVE);
        }
      } finally {
        timer.unlock();
      }
    }
  }

  private class Task extends java.util.TimerTask {

    private final TimerTask<?> delegate;
    private final ControlPoint controlPoint;
    /**
     * This is true if a task is queued up to be run by the request controller, used to stop timer
     * tasks banking up when the container is suspended.
     */
    private volatile boolean queued = false;

    public Task(final TimerTask<?> delegate, ControlPoint controlPoint) {
      this.delegate = delegate;
      this.controlPoint = controlPoint;
    }

    @Override
    public void run() {
      final ExecutorService executor = executorServiceInjectedValue.getOptionalValue();
      if (executor != null) {
        if (controlPoint == null) {
          executor.submit(delegate);
        } else if (!queued) {
          queued = true;
          controlPoint.queueTask(
              new Runnable() {
                @Override
                public void run() {
                  queued = false;
                  delegate.run();
                }
              },
              executor,
              -1,
              null,
              false);
        } else {
          EjbLogger.EJB3_INVOCATION_LOGGER.debug(
              "Skipping timer invocation as existing request is already queued.");
        }
      }
    }

    @Override
    public boolean cancel() {
      delegate.cancel();
      return super.cancel();
    }
  }

  private final class TimerRefreshListener implements TimerPersistence.TimerChangeListener {

    @Override
    public void timerAdded(TimerImpl timer) {
      TimerServiceImpl.this.startTimer(timer);
    }

    @Override
    public void timerRemoved(String timerId) {
      TimerImpl timer = TimerServiceImpl.this.getTimer(timerId);
      if (timer != null) {
        TimerServiceImpl.this.cancelTimeout(timer);
      }
    }

    @Override
    public TimerServiceImpl getTimerService() {
      return TimerServiceImpl.this;
    }
  }
}
/**
 * Service that is responsible for running an application clients main method, and shutting down the
 * server once it completes
 *
 * @author Stuart Douglas
 */
public class ApplicationClientStartService implements Service<ApplicationClientStartService> {

  public static final ServiceName SERVICE_NAME = ServiceName.of("appClientStart");

  private final InjectedValue<ApplicationClientDeploymentService>
      applicationClientDeploymentServiceInjectedValue =
          new InjectedValue<ApplicationClientDeploymentService>();
  private final InjectedValue<Component> applicationClientComponent =
      new InjectedValue<Component>();
  private final InjectedEENamespaceContextSelector namespaceContextSelectorInjectedValue;
  private final List<SetupAction> setupActions;
  private final Method mainMethod;
  private final String[] parameters;
  private final ClassLoader classLoader;
  private final ContextSelector<EJBClientContext> contextSelector;

  private Thread thread;
  private ComponentInstance instance;

  public ApplicationClientStartService(
      final Method mainMethod,
      final String[] parameters,
      final InjectedEENamespaceContextSelector namespaceContextSelectorInjectedValue,
      final ClassLoader classLoader,
      final List<SetupAction> setupActions,
      final String hostUrl,
      final CallbackHandler callbackHandler) {
    this.mainMethod = mainMethod;
    this.parameters = parameters;
    this.namespaceContextSelectorInjectedValue = namespaceContextSelectorInjectedValue;
    this.classLoader = classLoader;
    this.setupActions = setupActions;
    this.contextSelector = new LazyConnectionContextSelector(hostUrl, callbackHandler);
  }

  public ApplicationClientStartService(
      final Method mainMethod,
      final String[] parameters,
      final InjectedEENamespaceContextSelector namespaceContextSelectorInjectedValue,
      final ClassLoader classLoader,
      final List<SetupAction> setupActions,
      final EJBClientConfiguration configuration) {
    this.mainMethod = mainMethod;
    this.parameters = parameters;
    this.namespaceContextSelectorInjectedValue = namespaceContextSelectorInjectedValue;
    this.classLoader = classLoader;
    this.setupActions = setupActions;
    this.contextSelector = new ConfigBasedEJBClientContextSelector(configuration);
  }

  @Override
  public synchronized void start(final StartContext context) throws StartException {
    final ServiceContainer serviceContainer = context.getController().getServiceContainer();

    thread =
        new Thread(
            new Runnable() {

              @Override
              public void run() {
                final ClassLoader oldTccl =
                    WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
                try {
                  try {
                    try {
                      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(classLoader);
                      AccessController.doPrivileged(new SetSelectorAction(contextSelector));
                      applicationClientDeploymentServiceInjectedValue
                          .getValue()
                          .getDeploymentCompleteLatch()
                          .await();
                      NamespaceContextSelector.setDefault(namespaceContextSelectorInjectedValue);

                      try {
                        // perform any additional setup that may be needed
                        for (SetupAction action : setupActions) {
                          action.setup(Collections.<String, Object>emptyMap());
                        }

                        // do static injection etc
                        instance = applicationClientComponent.getValue().createInstance();

                        mainMethod.invoke(null, new Object[] {parameters});
                      } finally {
                        final ListIterator<SetupAction> iterator =
                            setupActions.listIterator(setupActions.size());
                        Throwable error = null;
                        while (iterator.hasPrevious()) {
                          SetupAction action = iterator.previous();
                          try {
                            action.teardown(Collections.<String, Object>emptyMap());
                          } catch (Throwable e) {
                            error = e;
                          }
                        }
                        if (error != null) {
                          throw new RuntimeException(error);
                        }
                      }
                    } catch (Exception e) {
                      ROOT_LOGGER.exceptionRunningAppClient(e, e.getClass().getSimpleName());
                    } finally {
                      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldTccl);
                    }
                  } finally {
                    if (contextSelector instanceof LazyConnectionContextSelector) {
                      ((LazyConnectionContextSelector) contextSelector).close();
                    }
                  }
                } finally {
                  serviceContainer.shutdown();
                }
              }
            });
    thread.start();
    Runtime.getRuntime()
        .addShutdownHook(
            new Thread(
                new Runnable() {
                  @Override
                  public void run() {
                    if (serviceContainer != null) {
                      serviceContainer.shutdown();
                    }
                  }
                }));
  }

  @Override
  public synchronized void stop(final StopContext context) {
    if (instance != null) {
      instance.destroy();
    }
    thread.interrupt();
    thread = null;
  }

  @Override
  public ApplicationClientStartService getValue()
      throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  public InjectedValue<ApplicationClientDeploymentService>
      getApplicationClientDeploymentServiceInjectedValue() {
    return applicationClientDeploymentServiceInjectedValue;
  }

  public InjectedValue<Component> getApplicationClientComponent() {
    return applicationClientComponent;
  }

  private static final class SetSelectorAction
      implements PrivilegedAction<ContextSelector<EJBClientContext>> {

    private final ContextSelector<EJBClientContext> selector;

    private SetSelectorAction(final ContextSelector<EJBClientContext> selector) {
      this.selector = selector;
    }

    @Override
    public ContextSelector<EJBClientContext> run() {
      return EJBClientContext.setSelector(selector);
    }
  }
}
/**
 * Provides the initial bootstrap of the Weld container. This does not actually finish starting the
 * container, merely gets it to the point that the bean manager is available.
 *
 * @author Stuart Douglas
 */
public class WeldBootstrapService implements Service<WeldBootstrapService> {

  public static final ServiceName SERVICE_NAME = ServiceName.of("WeldBootstrapService");

  private final WeldBootstrap bootstrap;
  private final WeldDeployment deployment;
  private final Environment environment;
  private final Map<String, BeanDeploymentArchive> beanDeploymentArchives;
  private final BeanDeploymentArchiveImpl rootBeanDeploymentArchive;

  private final String deploymentName;

  private final InjectedValue<WeldSecurityServices> securityServices =
      new InjectedValue<WeldSecurityServices>();
  private final InjectedValue<WeldTransactionServices> weldTransactionServices =
      new InjectedValue<WeldTransactionServices>();
  private final InjectedValue<ExecutorServices> executorServices =
      new InjectedValue<ExecutorServices>();

  private volatile boolean started;

  public WeldBootstrapService(
      WeldDeployment deployment, Environment environment, final String deploymentName) {
    this.deployment = deployment;
    this.environment = environment;
    this.deploymentName = deploymentName;
    this.bootstrap = new WeldBootstrap();
    Map<String, BeanDeploymentArchive> bdas = new HashMap<String, BeanDeploymentArchive>();
    BeanDeploymentArchiveImpl rootBeanDeploymentArchive = null;
    for (BeanDeploymentArchive archive : deployment.getBeanDeploymentArchives()) {
      bdas.put(archive.getId(), archive);
      if (archive instanceof BeanDeploymentArchiveImpl) {
        BeanDeploymentArchiveImpl bda = (BeanDeploymentArchiveImpl) archive;
        if (bda.isRoot()) {
          rootBeanDeploymentArchive = bda;
        }
      }
    }
    this.rootBeanDeploymentArchive = rootBeanDeploymentArchive;
    this.beanDeploymentArchives = Collections.unmodifiableMap(bdas);
  }

  /**
   * Starts the weld container
   *
   * @throws IllegalStateException if the container is already running
   */
  public synchronized void start(final StartContext context) {
    if (started) {
      throw WeldLogger.ROOT_LOGGER.alreadyRunning("WeldContainer");
    }
    started = true;

    WeldLogger.DEPLOYMENT_LOGGER.startingWeldService(deploymentName);
    // set up injected services
    addWeldService(SecurityServices.class, securityServices.getValue());
    addWeldService(TransactionServices.class, weldTransactionServices.getValue());

    if (!deployment.getServices().contains(ExecutorServices.class)) {
      addWeldService(ExecutorServices.class, executorServices.getValue());
    }

    ModuleGroupSingletonProvider.addClassLoaders(
        deployment.getModule().getClassLoader(), deployment.getSubDeploymentClassLoaders());

    ClassLoader oldTccl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
    try {
      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(
          deployment.getModule().getClassLoader());
      bootstrap.startContainer(deploymentName, environment, deployment);
      WeldProvider.containerInitialized(
          Container.instance(deploymentName), getBeanManager(), deployment);
    } finally {
      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldTccl);
    }
  }

  /**
   * Stops the container
   *
   * @throws IllegalStateException if the container is not running
   */
  public synchronized void stop(final StopContext context) {
    if (!started) {
      throw WeldLogger.ROOT_LOGGER.notStarted("WeldContainer");
    }
    WeldLogger.DEPLOYMENT_LOGGER.stoppingWeldService(deploymentName);
    ClassLoader oldTccl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
    try {
      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(
          deployment.getModule().getClassLoader());
      WeldProvider.containerShutDown(Container.instance(deploymentName));
      bootstrap.shutdown();
    } finally {
      WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(oldTccl);
      ModuleGroupSingletonProvider.removeClassLoader(deployment.getModule().getClassLoader());
    }
    started = false;
  }

  /**
   * Gets the {@link BeanManager} for a given bean deployment archive id.
   *
   * @throws IllegalStateException if the container is not running
   * @throws IllegalArgumentException if the bean deployment archive id is not found
   */
  public BeanManagerImpl getBeanManager(String beanArchiveId) {
    if (!started) {
      throw WeldLogger.ROOT_LOGGER.notStarted("WeldContainer");
    }
    BeanDeploymentArchive beanDeploymentArchive = beanDeploymentArchives.get(beanArchiveId);
    if (beanDeploymentArchive == null) {
      throw WeldLogger.ROOT_LOGGER.beanDeploymentNotFound(beanArchiveId);
    }
    return bootstrap.getManager(beanDeploymentArchive);
  }

  /**
   * Adds a {@link Service} to the deployment. This method must not be called after the container
   * has started
   */
  public <T extends org.jboss.weld.bootstrap.api.Service> void addWeldService(
      Class<T> type, T service) {
    deployment.addWeldService(type, service);
  }

  /**
   * Gets the {@link BeanManager} linked to the root bean deployment archive. This BeanManager has
   * access to all beans in a deployment
   *
   * @throws IllegalStateException if the container is not running
   */
  public BeanManagerImpl getBeanManager() {
    if (!started) {
      throw WeldLogger.ROOT_LOGGER.notStarted("WeldContainer");
    }
    return bootstrap.getManager(rootBeanDeploymentArchive);
  }

  /** get all beans deployment archives in the deployment */
  public Set<BeanDeploymentArchive> getBeanDeploymentArchives() {
    return new HashSet<BeanDeploymentArchive>(beanDeploymentArchives.values());
  }

  public boolean isStarted() {
    return started;
  }

  WeldBootstrap getBootstrap() {
    return bootstrap;
  }

  @Override
  public WeldBootstrapService getValue() throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  public InjectedValue<WeldSecurityServices> getSecurityServices() {
    return securityServices;
  }

  public InjectedValue<WeldTransactionServices> getWeldTransactionServices() {
    return weldTransactionServices;
  }

  public InjectedValue<ExecutorServices> getExecutorServices() {
    return executorServices;
  }
}
/**
 * @author Heiko Braun
 * @since 19/02/16
 */
@Vetoed
public class MonitorService implements Monitor, Service<MonitorService> {

  public static final ServiceName SERVICE_NAME = ServiceName.of("swarm", "monitor");

  public MonitorService(Optional<String> securityRealm) {
    this.securityRealm = securityRealm;
  }

  @Override
  public long getProbeTimeoutSeconds() {
    return DEFAULT_PROBE_TIMEOUT_SECONDS;
  }

  @Override
  public void start(StartContext startContext) throws StartException {
    executorService = Executors.newSingleThreadExecutor();
    serverEnvironment = serverEnvironmentValue.getValue();
    controllerClient = modelControllerValue.getValue().createClient(executorService);

    if (!securityRealm.isPresent()) {
      System.out.println(
          "WARN: You are running the monitoring endpoints without any security realm configuration!");
    }
  }

  @Override
  public void stop(StopContext stopContext) {
    if (executorService != null) {
      executorService.shutdownNow();
    }
  }

  @Override
  public MonitorService getValue() throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  @Override
  public ModelNode getNodeInfo() {
    ModelNode payload = new ModelNode();

    ModelNode op = new ModelNode();
    op.get(ADDRESS).setEmptyList();
    op.get(OP).set("query");
    op.get("select").add("name");
    op.get("select").add("server-state");
    op.get("select").add("suspend-state");
    op.get("select").add("running-mode");
    op.get("select").add("uuid");

    try {
      ModelNode response = controllerClient.execute(op);
      ModelNode unwrapped = unwrap(response);
      // need a way to figure out *which* version we really mean here...
      unwrapped.get("wfs-version").set("fixme");
      return unwrapped;
    } catch (IOException e) {
      return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage());
    }
  }

  @Override
  public ModelNode heap() {

    // /core-service=platform-mbean/type=memory:read-resource(include-runtime=true)

    ModelNode op = new ModelNode();
    op.get(ADDRESS).add("core-service", "platform-mbean");
    op.get(ADDRESS).add("type", "memory");
    op.get(OP).set("query");
    op.get("select").add("heap-memory-usage");
    op.get("select").add("non-heap-memory-usage");

    try {
      ModelNode response = controllerClient.execute(op);
      return unwrap(response);
    } catch (IOException e) {
      return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage());
    }
  }

  @Override
  public ModelNode threads() {

    // /core-service=platform-mbean/type=threading:read-resource(include-runtime=true)

    ModelNode op = new ModelNode();
    op.get(ADDRESS).add("core-service", "platform-mbean");
    op.get(ADDRESS).add("type", "threading");
    op.get(OP).set("query");
    op.get("select").add("thread-count");
    op.get("select").add("peak-thread-count");
    op.get("select").add("total-started-thread-count");
    op.get("select").add("current-thread-cpu-time");
    op.get("select").add("current-thread-user-time");

    try {
      ModelNode response = controllerClient.execute(op);
      return unwrap(response);
    } catch (IOException e) {
      return new ModelNode().get(FAILURE_DESCRIPTION).set(e.getMessage());
    }
  }

  @Override
  public void registerHealth(HealthMetaData metaData) {
    System.out.println("Adding /health endpoint delegate: " + metaData.getWebContext());
    this.endpoints.add(metaData);
  }

  @Override
  public List<HealthMetaData> getHealthURIs() {
    return Collections.unmodifiableList(this.endpoints);
  }

  @Override
  public Optional<SecurityRealm> getSecurityRealm() {

    if (securityRealm.isPresent() && null == securityRealmServiceValue.getOptionalValue()) {
      throw new RuntimeException(
          "A security realm has been specified, but has not been configured: "
              + securityRealm.get());
    }

    return securityRealmServiceValue.getOptionalValue() != null
        ? Optional.of(securityRealmServiceValue.getValue())
        : Optional.empty();
  }

  private static ModelNode unwrap(ModelNode response) {
    if (response.get(OUTCOME).asString().equals(SUCCESS)) return response.get(RESULT);
    else return response;
  }

  public Injector<ServerEnvironment> getServerEnvironmentInjector() {
    return this.serverEnvironmentValue;
  }

  public Injector<ModelController> getModelControllerInjector() {
    return this.modelControllerValue;
  }

  public Injector<SecurityRealm> getSecurityRealmInjector() {
    return this.securityRealmServiceValue;
  }

  private static final long DEFAULT_PROBE_TIMEOUT_SECONDS = 2;

  private final InjectedValue<ServerEnvironment> serverEnvironmentValue =
      new InjectedValue<ServerEnvironment>();

  private final InjectedValue<ModelController> modelControllerValue =
      new InjectedValue<ModelController>();

  private final InjectedValue<SecurityRealm> securityRealmServiceValue =
      new InjectedValue<SecurityRealm>();

  private final Optional<String> securityRealm;

  private ExecutorService executorService;

  private ServerEnvironment serverEnvironment;

  private ModelControllerClient controllerClient;

  private CopyOnWriteArrayList<HealthMetaData> endpoints =
      new CopyOnWriteArrayList<HealthMetaData>();
}
/**
 * Timed object invoker for an EJB. This is analogous to a view service for timer invocations
 *
 * @author Stuart Douglas
 */
public class TimedObjectInvokerImpl
    implements TimedObjectInvoker, Serializable, Service<TimedObjectInvoker> {

  public static final ServiceName SERVICE_NAME = ServiceName.of("TimedObjectInvoker");

  private final InjectedValue<EJBComponent> ejbComponent = new InjectedValue<EJBComponent>();
  private final Module module;
  private boolean started = false;

  /** String that uniquely identifies a deployment */
  private final String deploymentString;

  private Map<Method, Interceptor> timeoutInterceptors;

  public TimedObjectInvokerImpl(final String deploymentString, final Module module) {
    this.deploymentString = deploymentString;
    this.module = module;
  }

  @Override
  public void callTimeout(final TimerImpl timer, final Method timeoutMethod) throws Exception {
    final Interceptor interceptor;
    synchronized (this) {
      if (!started) {
        // this can happen if an invocation has been triggered as the deployment is shutting down
        throw EjbLogger.ROOT_LOGGER.timerInvocationFailedDueToInvokerNotBeingStarted();
      }
      interceptor = timeoutInterceptors.get(timeoutMethod);
    }
    if (interceptor == null) {
      throw EjbLogger.ROOT_LOGGER.failToInvokeTimeout(timeoutMethod);
    }
    final InterceptorContext context = new InterceptorContext();
    context.setContextData(new HashMap<String, Object>());
    context.setMethod(timeoutMethod);
    if (timeoutMethod.getParameterTypes().length == 0) {
      context.setParameters(new Object[0]);
    } else {
      final Object[] params = new Object[1];
      params[0] = timer;
      context.setParameters(params);
    }
    context.setTimer(timer);

    if (timer.getPrimaryKey() != null) {
      context.putPrivateData(EntityBeanComponent.PRIMARY_KEY_CONTEXT_KEY, timer.getPrimaryKey());
    }
    context.putPrivateData(Component.class, ejbComponent.getValue());
    context.putPrivateData(MethodIntf.class, MethodIntf.TIMER);
    context.putPrivateData(InvocationType.class, InvocationType.TIMER);
    interceptor.processInvocation(context);
  }

  @Override
  public String getTimedObjectId() {
    return deploymentString + "." + ejbComponent.getValue().getComponentName();
  }

  @Override
  public void callTimeout(final TimerImpl timer) throws Exception {
    callTimeout(timer, ejbComponent.getValue().getTimeoutMethod());
  }

  @Override
  public ClassLoader getClassLoader() {
    return module.getClassLoader();
  }

  @Override
  public synchronized void start(final StartContext context) throws StartException {
    SimpleInterceptorFactoryContext factoryContext = new SimpleInterceptorFactoryContext();
    factoryContext.getContextData().put(Component.class, ejbComponent.getValue());
    Map<Method, Interceptor> interceptors = new HashMap<Method, Interceptor>();
    for (Map.Entry<Method, InterceptorFactory> entry :
        ejbComponent.getValue().getTimeoutInterceptors().entrySet()) {
      interceptors.put(entry.getKey(), entry.getValue().create(factoryContext));
    }
    this.timeoutInterceptors = interceptors;
    started = true;
  }

  @Override
  public synchronized void stop(final StopContext context) {
    started = false;
    this.timeoutInterceptors = null;
  }

  @Override
  public synchronized TimedObjectInvoker getValue()
      throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  public InjectedValue<EJBComponent> getEjbComponent() {
    return ejbComponent;
  }
}
/**
 * Service that is responsible for running an application clients main method, and shutting down the
 * server once it completes
 *
 * @author Stuart Douglas
 */
public class ApplicationClientStartService implements Service<ApplicationClientStartService> {

  public static final ServiceName SERVICE_NAME = ServiceName.of("appClientStart");

  private final InjectedValue<ApplicationClientDeploymentService>
      applicationClientDeploymentServiceInjectedValue =
          new InjectedValue<ApplicationClientDeploymentService>();
  private final InjectedValue<Component> applicationClientComponent =
      new InjectedValue<Component>();
  private final InjectedEENamespaceContextSelector namespaceContextSelectorInjectedValue;
  private final Method mainMethod;
  private final String[] parameters;
  private final ClassLoader classLoader;
  final String hostUrl;

  private Thread thread;
  private ComponentInstance instance;

  public ApplicationClientStartService(
      final Method mainMethod,
      final String[] parameters,
      final String hostUrl,
      final InjectedEENamespaceContextSelector namespaceContextSelectorInjectedValue,
      final ClassLoader classLoader) {
    this.mainMethod = mainMethod;
    this.parameters = parameters;
    this.namespaceContextSelectorInjectedValue = namespaceContextSelectorInjectedValue;
    this.classLoader = classLoader;
    this.hostUrl = hostUrl;
  }

  @Override
  public synchronized void start(final StartContext context) throws StartException {

    thread =
        new Thread(
            new Runnable() {

              @Override
              public void run() {
                try {
                  final Endpoint endpoint = Remoting.createEndpoint("endpoint", OptionMap.EMPTY);
                  endpoint.addConnectionProvider(
                      "remote",
                      new RemoteConnectionProviderFactory(),
                      OptionMap.create(Options.SSL_ENABLED, Boolean.FALSE));

                  // open a connection
                  final IoFuture<Connection> futureConnection =
                      endpoint.connect(
                          new URI(hostUrl),
                          OptionMap.create(Options.SASL_POLICY_NOANONYMOUS, Boolean.FALSE),
                          new AnonymousCallbackHandler());
                  final Connection connection =
                      IoFutureHelper.get(futureConnection, 5L, TimeUnit.SECONDS);
                  try {
                    try {

                      final ClassLoader oldTccl = SecurityActions.getContextClassLoader();
                      try {
                        try {
                          SecurityActions.setContextClassLoader(classLoader);

                          final EJBClientContext ejbClientContext = EJBClientContext.create();
                          ejbClientContext.registerConnection(connection);
                          final ContextSelector<EJBClientContext> previousSelector =
                              EJBClientContext.setConstantContext(ejbClientContext);
                          applicationClientDeploymentServiceInjectedValue
                              .getValue()
                              .getDeploymentCompleteLatch()
                              .await();

                          try {
                            NamespaceContextSelector.setDefault(
                                namespaceContextSelectorInjectedValue);
                            // do static injection etc
                            // TODO: this should be better
                            instance = applicationClientComponent.getValue().createInstance();
                            mainMethod.invoke(null, new Object[] {parameters});
                          } finally {
                            if (previousSelector != null) {
                              EJBClientContext.setSelector(previousSelector);
                            }
                          }
                        } catch (Exception e) {
                          ROOT_LOGGER.exceptionRunningAppClient(e, e.getClass().getSimpleName());
                        } finally {
                          SecurityActions.setContextClassLoader(oldTccl);
                        }
                      } finally {
                        CurrentServiceContainer.getServiceContainer().shutdown();
                      }
                    } finally {
                      try {
                        connection.close();
                      } catch (Throwable e) {
                        ROOT_LOGGER.exceptionClosingConnection(e);
                      }
                    }
                  } finally {
                    try {
                      endpoint.close();
                    } catch (Throwable e) {
                      ROOT_LOGGER.exceptionClosingConnection(e);
                    }
                  }
                } catch (IOException e) {
                  throw new RuntimeException(e);
                } catch (URISyntaxException e) {
                  throw new RuntimeException(e);
                }
              }
            });
    thread.start();
  }

  @Override
  public synchronized void stop(final StopContext context) {
    if (instance != null) {
      instance.destroy();
    }
    thread.interrupt();
    thread = null;
  }

  @Override
  public ApplicationClientStartService getValue()
      throws IllegalStateException, IllegalArgumentException {
    return this;
  }

  public InjectedValue<ApplicationClientDeploymentService>
      getApplicationClientDeploymentServiceInjectedValue() {
    return applicationClientDeploymentServiceInjectedValue;
  }

  public InjectedValue<Component> getApplicationClientComponent() {
    return applicationClientComponent;
  }

  /** User: jpai */
  public class AnonymousCallbackHandler implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
      for (Callback current : callbacks) {
        if (current instanceof NameCallback) {
          NameCallback ncb = (NameCallback) current;
          ncb.setName("anonymous");
        } else {
          throw new UnsupportedCallbackException(current);
        }
      }
    }
  }
}