/*
*
*/
package org.sf.bee.runtime;
import org.sf.bee.runtime.repository.BeeRuntimeRepositoryManager;
import java.util.Date;
import java.util.Iterator;
import org.sf.bee.app.Application;
import org.sf.bee.commons.logging.Level;
import org.sf.bee.app.IAppConstants;
import org.sf.bee.app.IRuntimeConstants;
import org.sf.bee.app.context.AppContext;
import org.sf.bee.commons.events.BeeEvent;
import org.sf.bee.commons.events.BeeEventNotifier;
import org.sf.bee.commons.events.BeeEvents;
import org.sf.bee.commons.exception.ExceptionList;
import org.sf.bee.commons.exception.IMultipartExceptionHandler;
import org.sf.bee.commons.logging.Logger;
import org.sf.bee.commons.util.ExceptionUtils;
import org.sf.bee.commons.util.StringUtils;
import org.sf.bee.commons.util.fs.PathUtils;
import org.sf.bee.commons.logging.util.LoggingUtils;
import org.sf.bee.commons.net.utils.NetUtils;
import org.sf.bee.commons.plugins.BeePluginManager;
import org.sf.bee.profiler.components.TimeWatcher;
import org.sf.bee.runtime.configuration.AbstractRuntimeConfiguration;
import org.sf.bee.runtime.configuration.RuntimeConfigFile;
import org.sf.bee.runtime.configuration.exceptions.MismatchConfigurationException;
import org.sf.bee.runtime.configuration.helpers.ConfigRpcService;
import org.sf.bee.runtime.configuration.helpers.ConfigTask;
/**
*
* @author angelo.geminiani
*/
public abstract class AbstractRuntime
implements IAppConstants, IRuntimeConstants, IMultipartExceptionHandler {
public static String APPLICATION_VERSION = "1.0.0.1";
private boolean _initialized = false;
private RuntimeStatus _status = RuntimeStatus.IDLE;
private ExceptionList _errors = new ExceptionList();
private BeeRuntimeRepositoryManager _repository = new BeeRuntimeRepositoryManager();
private AbstractRuntimeConfiguration _configuration;
private BeeEventNotifier _eventNotifier = new BeeEventNotifier();
private ConfigRpcService _rpc;
private ConfigTask _tasks;
private final Application _application;
private final BeePluginManager _plugins;
private final RuntimeLateActionList _lateActions;
public AbstractRuntime(final Application application) {
_application = application;
_plugins = new BeePluginManager();
_lateActions = new RuntimeLateActionList();
}
public final Application getApplication() {
return _application;
}
public final BeePluginManager getPluginManager() {
return _plugins;
}
public final BeeEventNotifier getEventManager() {
return _eventNotifier;
}
public final ClassLoader getClassLoader() {
return this.getClass().getClassLoader();
}
@Override
public final ExceptionList getErrors() {
return _errors;
}
public final void add(final Object owner,
final String context, final Throwable t) {
_errors.add(owner, context, t);
}
public final boolean open() {
if (_initialized) {
return true;
}
final TimeWatcher watch = new TimeWatcher();
watch.start();
boolean result = true;
// open runtime
try {
// ON BEFORE OPEN
final AbstractRuntimeConfiguration config = this.onBeforeOpen();
if (null != config) {
_configuration = config;
//-- open configuration --//
_configuration.open();
//-- initialize logging level --//
this.initLoggingLevel(_configuration.getFlagDebugMode());
//-- store configuration and initialize runtime --//
this.loadConfiguration(_configuration);
_initialized = true;
// ON OPEN
this.onOpen();
this.notifyListenersOnOpen();
//-- STATUS: READY --//
this.setStatus(RuntimeStatus.READY);
}
} catch (Throwable t) {
_errors.add(t);
}
// check initialization errors
final ExceptionList errors = this.getErrors();
if (errors.hasErrors()) {
this.getLogger().log(
Level.SEVERE,
"Problem initializing {0}: \n{1}",
new Object[]{this.getClass().getSimpleName(),
errors.toString(false)});
this.setStatus(RuntimeStatus.ERROR);
result = false;
} else {
result = true;
}
watch.stop();
this.logStarted(watch.toString());
return result;
}
public final void close() {
// ON_CLOSE event
this.notifyListenersOnClose();
try {
this.onClose();
} catch (Throwable t) {
this.getLogger().log(Level.SEVERE, null, t);
}
this.closeRuntime();
}
public final RuntimeStatus getStatus() {
return _status;
}
public final AbstractRuntimeConfiguration getConfiguration() {
return _configuration;
}
public final boolean isReady() {
return null != _configuration && _configuration.isReady();
}
public final BeeRuntimeRepositoryManager getRepository() {
return _repository;
}
public final ConfigRpcService getRpcManager() {
return _rpc;
}
public final RuntimeLateActionList getLateActions() {
return _lateActions;
}
public void executeLateActions() {
final Iterator<IRuntimeLateAction> iterator = _lateActions.iterator();
while (iterator.hasNext()) {
final IRuntimeLateAction action = iterator.next();
action.executeLateAction(this);
}
}
// ------------------------------------------------------------------------
// p r o t e c t e d
// ------------------------------------------------------------------------
protected abstract AbstractRuntimeConfiguration onBeforeOpen() throws Exception;
protected abstract void onOpen() throws Exception;
protected abstract void onClose() throws Exception;
protected final Logger getLogger() {
return LoggingUtils.getLogger(this);
}
protected final RuntimeConfigFile createConfigurationFile(final String path)
throws MismatchConfigurationException {
final String fileName = this.checkConfigurationFileName(path);
final RuntimeConfigFile result = new RuntimeConfigFile();
result.loadFromFile(this.getAbsoluteName(fileName));
return result;
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private void initLoggingLevel(final boolean debugMode) {
if (debugMode) {
LoggingUtils.setLevel(Level.FINER);
}
}
private void loadConfiguration(final AbstractRuntimeConfiguration configuration) {
//-- event notifier --//
if (null != configuration
&& configuration.isReady()) {
this.initEventNotifier(configuration.getListenersList());
}
//-- rpc --//
_rpc = new ConfigRpcService();
_rpc.run();
//-- tasks --//
_tasks = new ConfigTask(configuration.getTasks());
_tasks.run();
}
private String getAbsoluteName(final String fileName) {
final String appPath = AppContext.getPathApp();
final String root = PathUtils.convertAndReplaceDuplicates(appPath);
final String path = PathUtils.convertAndReplaceDuplicates(fileName);
if (PathUtils.isAbsolute(path)) {
return path;
} else {
return PathUtils.combine(root, path);
}
}
private String checkConfigurationFileName(final String confPathStr) {
final String fileName;
if (StringUtils.hasText(confPathStr)) {
fileName = StringUtils.trim(confPathStr);
// align context
AppContext.setPathConf(fileName);
} else {
fileName = AppContext.getPathConf();
}
this.getLogger().log(Level.FINE, "confPath set to {0}", fileName);
return fileName;
}
private void initEventNotifier(final String[] listeners) {
if (null != _eventNotifier) {
if (listeners.length > 0) {
for (final String listener : listeners) {
_eventNotifier.addEventListener(listener);
}
this.getLogger().info("Initialized EventNotifier");
} else {
this.getLogger().info("EventNotifier is disabled (No configuration file declared).");
}
}
}
private void closeRuntime() {
// reset status
this.setStatus(RuntimeStatus.IDLE);
final TimeWatcher mainProfiler = new TimeWatcher();
final TimeWatcher profiler = new TimeWatcher();
mainProfiler.start();
this.getLogger().info("Cleaning runtime ...");
// Clear resources cache
profiler.reset();
profiler.start();
this.getLogger().fine(
"\tStart Finalizing Resource Bundle Cache (i18n) ...");
try {
_repository.clear();
} catch (Exception e) {
this.getLogger().log(
Level.SEVERE, "ERROR ON REPOSITORY CLEARING: {0}", e.getMessage());
}
profiler.stop();
this.getLogger().log(
Level.FINE, "\tFinish Finalizing Repository: {0}", profiler.toString());
mainProfiler.stop();
this.getLogger().log(Level.INFO, "Finish clean Runtime: {0}", mainProfiler.toString());
}
private void notifyListenersOnOpen() {
//-- NOTIFY onOpen --//
if (null != _eventNotifier) {
BeeEvent event = new BeeEvent(this, BeeEvents.ON_OPEN);
_eventNotifier.doEvent(event);
}
}
private void notifyListenersOnClose() {
//-- NOTIFY onOpen --//
if (null != _eventNotifier) {
BeeEvent event = new BeeEvent(this, BeeEvents.ON_CLOSE);
_eventNotifier.doEvent(event);
}
}
private void logStarted(final String elapsedTime) {
final String hostId = NetUtils.getHostIdentifierEncoded();
// log runtime start up
final StringBuilder message = new StringBuilder();
message.append("\n");
message.append("---------------------------------------------------------------\n");
message.append("\t\tStarted Runtime\n");
message.append("\n");
message.append("\t\tHost Id: ".concat(hostId).concat("\n"));
message.append("\t\tRuntime Version: ".concat(RUNTIME_VERSION).concat("\n"));
message.append("\t\tApplication Version: ".concat(APPLICATION_VERSION).concat("\n"));
message.append("\t\tDate: ".concat((new Date()).toString()).concat("\n"));
message.append("\t\tTime elapsed: ".concat(elapsedTime).concat("\n"));
message.append("---------------------------------------------------------------\n");
this.getLogger().info(message.toString());
}
private void setStatus(RuntimeStatus status) {
this._status = status;
}
private void setStatus(final RuntimeStatus status,
final Throwable t) {
_status = status;
if (RuntimeStatus.READY.equals(status)) {
this.getLogger().info("RUNTIME READY: Runtime is ready.");
} else {
if (null != t) {
this.getLogger().log(Level.SEVERE,
StringUtils.format("RUNTIME NOT READY: ERROR [%s]",
ExceptionUtils.getRealMessage(t)),
t);
this.getErrors().add(t);
}
}
}
}