/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.hadoop.store.support;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.hadoop.store.event.StoreEventPublisher;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
/**
* Convenient base class for object which needs spring task scheduler, task executor and life cycle handling.
*
* @author Janne Valkealahti
*
*/
public abstract class LifecycleObjectSupport implements InitializingBean, SmartLifecycle, BeanFactoryAware {
private static final Log log = LogFactory.getLog(LifecycleObjectSupport.class);
// fields for lifecycle
private volatile boolean autoStartup = true;
private volatile int phase = 0;
private volatile boolean running;
// lock to protect lifycycle methods
private final ReentrantLock lifecycleLock = new ReentrantLock();
// common task handling
private TaskScheduler taskScheduler;
private TaskExecutor taskExecutor;
// to access bean factory
private volatile BeanFactory beanFactory;
/** Context application event publisher if exist */
private volatile StoreEventPublisher storeEventPublisher;
@Override
public final void afterPropertiesSet() {
try {
this.onInit();
}
catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new BeanInitializationException("failed to initialize", e);
}
}
@Override
public final void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.notNull(beanFactory, "beanFactory must not be null");
if (log.isDebugEnabled()) {
log.debug("Setting bean factory: " + beanFactory + " for " + this);
}
this.beanFactory = beanFactory;
}
@Override
public final boolean isAutoStartup() {
return this.autoStartup;
}
@Override
public final int getPhase() {
return this.phase;
}
@Override
public final boolean isRunning() {
this.lifecycleLock.lock();
try {
return this.running;
}
finally {
this.lifecycleLock.unlock();
}
}
@Override
public final void start() {
this.lifecycleLock.lock();
try {
if (!this.running) {
this.doStart();
this.running = true;
if (log.isInfoEnabled()) {
log.info("started " + this);
}
else {
if (log.isDebugEnabled()) {
log.debug("already started " + this);
}
}
}
}
finally {
this.lifecycleLock.unlock();
}
}
@Override
public final void stop() {
this.lifecycleLock.lock();
try {
if (this.running) {
this.doStop();
this.running = false;
if (log.isInfoEnabled()) {
log.info("stopped " + this);
}
}
else {
if (log.isDebugEnabled()) {
log.debug("already stopped " + this);
}
}
}
finally {
this.lifecycleLock.unlock();
}
}
@Override
public final void stop(Runnable callback) {
this.lifecycleLock.lock();
try {
this.stop();
callback.run();
}
finally {
this.lifecycleLock.unlock();
}
}
/**
* Sets the auto startup.
*
* @param autoStartup the new auto startup
* @see SmartLifecycle
*/
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
/**
* Sets the phase.
*
* @param phase the new phase
* @see SmartLifecycle
*/
public void setPhase(int phase) {
this.phase = phase;
}
/**
* Gets the {@link BeanFactory} for this instance.
*
* @return the bean factory.
*/
protected final BeanFactory getBeanFactory() {
return beanFactory;
}
/**
* Sets the used {@link TaskScheduler}.
*
* @param taskScheduler the task scheduler
*/
public void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "taskScheduler must not be null");
this.taskScheduler = taskScheduler;
}
/**
* Gets the defined {@link TaskScheduler}.
*
* @return the defined task scheduler
*/
protected TaskScheduler getTaskScheduler() {
if (taskScheduler == null && getBeanFactory() != null) {
if (log.isDebugEnabled()) {
log.debug("getting taskScheduler service from bean factory " + getBeanFactory());
}
taskScheduler = StoreContextUtils.getTaskScheduler(getBeanFactory());
}
return taskScheduler;
}
/**
* Sets the used {@link TaskExecutor}.
*
* @param taskExecutor the task executor
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
Assert.notNull(taskExecutor, "taskExecutor must not be null");
this.taskExecutor = taskExecutor;
}
/**
* Gets the store event publisher.
*
* @return the store event publisher
*/
public StoreEventPublisher getStoreEventPublisher() {
if (storeEventPublisher == null && getBeanFactory() != null) {
if (log.isDebugEnabled()) {
log.debug("getting yarnEventPublisher service from bean factory " + getBeanFactory());
}
storeEventPublisher = StoreContextUtils.getEventPublisher(getBeanFactory());
}
return storeEventPublisher;
}
/**
* Sets the store event publisher.
*
* @param storeEventPublisher the new store event publisher
*/
public void setStoreEventPublisher(StoreEventPublisher storeEventPublisher) {
Assert.notNull(storeEventPublisher, "StoreEventPublisher cannot be null");
this.storeEventPublisher = storeEventPublisher;
}
/**
* Gets the defined {@link TaskExecutor}.
*
* @return the defined task executor
*/
protected TaskExecutor getTaskExecutor() {
if (taskExecutor == null && getBeanFactory() != null) {
if (log.isDebugEnabled()) {
log.debug("getting taskExecutor service from bean factory " + getBeanFactory());
}
taskExecutor = StoreContextUtils.getTaskExecutor(getBeanFactory());
}
return taskExecutor;
}
/**
* Subclasses may implement this for initialization logic. Called during the {@link InitializingBean} phase.
* Implementor should always call super method not to break initialization chain.
*
* @throws Exception if error occurred during init
*/
protected void onInit() throws Exception {
}
/**
* Subclasses may implement this method with the start behaviour. This method will be invoked while holding the
* {@link #lifecycleLock}.
*/
protected void doStart() {
};
/**
* Subclasses may implement this method with the stop behaviour. This method will be invoked while holding the
* {@link #lifecycleLock}.
*/
protected void doStop() {
};
}