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(); }
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 }
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; }
public static ServiceName transportServiceName(String name) { return ServiceName.of(TRANSPORT_BASE, name); }
public static ServiceName translatorServiceName(String name) { return ServiceName.of(TRANSLATOR_BASE, name); }
/** * 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); } } } } }