/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.inject.lifecycle;
import org.eclipse.che.commons.schedule.Launcher;
import org.eclipse.che.commons.schedule.ScheduleCron;
import org.eclipse.che.commons.schedule.ScheduleDelay;
import org.eclipse.che.commons.schedule.ScheduleRate;
import org.eclipse.che.commons.schedule.executor.LoggedRunnable;
import com.google.inject.ConfigurationException;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.matcher.Matcher;
import com.google.inject.matcher.Matchers;
import com.google.inject.name.Names;
import com.google.inject.spi.InjectionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
/**
* Listen guice injections and launch method marked with schedule annotations.
*
* @author Sergii Kabashniuk
*/
public class ScheduleInjectionListener<T> extends LifecycleModule implements InjectionListener<T> {
private static final Logger LOG = LoggerFactory.getLogger(ScheduleInjectionListener.class);
private final Matcher<AnnotatedElement> javaxSingleton = Matchers.annotatedWith(javax.inject.Singleton.class);
private final Matcher<AnnotatedElement> googleSingleton = Matchers.annotatedWith(com.google.inject.Singleton.class);
private final Provider<Launcher> launcherProvider;
private final Provider<Injector> injectorProvider;
public ScheduleInjectionListener(Provider<Launcher> launcherProvider, Provider<Injector> injectorProvider) {
this.launcherProvider = launcherProvider;
this.injectorProvider = injectorProvider;
}
private <T> T getValue(Class<T> configurationType, String configurationKey) {
try {
return injectorProvider.get().getInstance(Key.get(configurationType, Names.named(configurationKey)));
} catch (ConfigurationException | ProvisionException e) {
return null;
}
}
private long getValue(String configurationKey) {
String stringValue = getValue(String.class, configurationKey);
if (stringValue != null) {
long result = Long.parseLong(stringValue);
if (result == 0) {
throw new RuntimeException("Invalid value 0 for parameter " + configurationKey);
}
return result;
}
Long longValue = getValue(Long.class, configurationKey);
if (longValue != null) {
long result = longValue.longValue();
if (result == 0) {
throw new RuntimeException("Invalid value 0 for parameter " + configurationKey);
}
return result;
}
Integer intValue = getValue(Integer.class, configurationKey);
if (intValue != null) {
long result = intValue.longValue();
if (result == 0) {
throw new RuntimeException("Invalid value 0 for parameter " + configurationKey);
}
return result;
}
throw new RuntimeException("Parameter " + configurationKey + " is not configured");
}
private void launch(Object object, Method method, ScheduleCron annotation) {
Launcher launcher = launcherProvider.get();
launcher.scheduleCron(new LoggedRunnable(object,
method), annotation.cronParameterName().isEmpty() ? annotation.cron()
: getValue(String.class,
annotation
.cronParameterName
()));
}
private void launch(Object object, Method method, ScheduleDelay annotation) {
if (annotation.delayParameterName().isEmpty() && annotation.delay() == 0) {
throw new RuntimeException("Delay parameter is not configured");
}
Launcher launcher = launcherProvider.get();
launcher.scheduleWithFixedDelay(new LoggedRunnable(object,
method),
annotation.initialDelayParameterName().isEmpty() ? annotation.initialDelay()
: getValue(
annotation
.initialDelayParameterName()),
annotation.delayParameterName().isEmpty() ? annotation.delay()
: getValue(
annotation.delayParameterName()),
annotation.unit());
}
private void launch(Object object, Method method, ScheduleRate annotation) {
if (annotation.periodParameterName().isEmpty() && annotation.period() == 0) {
throw new RuntimeException("Period parameter is not configured");
}
Launcher launcher = launcherProvider.get();
launcher.scheduleAtFixedRate(new LoggedRunnable(object,
method),
annotation.initialDelayParameterName().isEmpty() ? annotation.initialDelay()
: getValue(
annotation
.initialDelayParameterName()),
annotation.periodParameterName().isEmpty() ? annotation.period()
: getValue(
annotation.periodParameterName()),
annotation.unit());
}
private void launch(Object object, Class<? extends Annotation> annotationType) {
boolean isSingleton = javaxSingleton.matches(object.getClass()) ||
googleSingleton.matches(object.getClass());
for (Method method : get(object.getClass(), annotationType)) {
if (!isSingleton) {
throw new RuntimeException(
"Scheduled class " + object.getClass() + " should be marked as singleton");
}
if (annotationType.equals(ScheduleRate.class)) {
launch(object, method, method.getAnnotation(ScheduleRate.class));
} else if (annotationType.equals(ScheduleDelay.class)) {
launch(object, method, method.getAnnotation(ScheduleDelay.class));
} else if (annotationType.equals(ScheduleCron.class)) {
launch(object, method, method.getAnnotation(ScheduleCron.class));
}
}
}
@Override
public void afterInjection(T injectee) {
launch(injectee, ScheduleCron.class);
launch(injectee, ScheduleRate.class);
launch(injectee, ScheduleDelay.class);
}
@Override
protected void configure() {
}
}