/*
* Copyright (c) 2014-2015 Janith Bandara, This source is a part of
* Audit4j - An open source auditing framework.
* http://audit4j.org
*
* 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.audit4j.core;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.audit4j.core.command.CommandProcessor;
import org.audit4j.core.command.impl.MetadataCommand;
import org.audit4j.core.command.impl.ObjectSerializerCommand;
import org.audit4j.core.dto.AuditEvent;
import org.audit4j.core.exception.ConfigurationException;
import org.audit4j.core.exception.InitializationException;
import org.audit4j.core.exception.ValidationException;
import org.audit4j.core.filter.AuditAnnotationFilter;
import org.audit4j.core.filter.AuditEventFilter;
import org.audit4j.core.handler.Handler;
import org.audit4j.core.io.AsyncAnnotationAuditOutputStream;
import org.audit4j.core.io.AsyncAuditOutputStream;
import org.audit4j.core.io.AuditEventOutputStream;
import org.audit4j.core.io.AuditOutputStream;
import org.audit4j.core.io.AuditProcessOutputStream;
import org.audit4j.core.io.MetadataLookupStream;
import org.audit4j.core.jmx.MBeanAgent;
import org.audit4j.core.schedule.Schedulers;
import org.audit4j.core.util.EnvUtil;
import org.audit4j.core.util.Log;
import org.audit4j.core.util.StopWatch;
/**
* The Audit4j Context. This will load and execute required resources in to the
* memory when initializing audit4j, Context makes sure necessary resources
* provide when running audit4j and it's plugins. Also this will ensure to
* release the memory allocated by audit4j when shutdown.
*
* <p>
* Available public methods:
* </p>
* <ul>
* <li>{@link #init()} Initialize the Audit4j context.</li>
* <li>{@link #initWithConfiguration(Configuration configuration)} Initialize
* the Audit4j context with external configurations.</li>
* <li>{@link #initWithConfiguration(String configFilePath)} Initialize the
* Audit4j context with external configuration file.</li>
* <li>{@link #stop()} Shutdown Audit4j. This will free memory allocated by the
* Audit4j</li>
* <li>{@link #enable()} Enable audit4j.</li>
* <li>{@link #disable()} Disable audit4j.</li>
* <li>{@link #terminate()} Terminate audit4j.</li>
* <li>{@link #getConfigContext()} get initialized configurations.</li>
* <li>{@link #setConfig(Configuration configuration)} set initial and external
* configurations in to context.</li>
* </ul>
*
* @author <a href="mailto:janith3000@gmail.com">Janith Bandara</a>
*
* @since 1.0.1
*/
public final class Context {
/** The Configuration instance. One time initialize. */
private static Configuration conf;
/** The config file path. */
private static String configFilePath;
/** The audit output stream. */
private static AuditOutputStream<AuditEvent> auditStream;
/** The config context. */
private static ConcurrentConfigurationContext configContext;
/** The Constant INIT_FAILED. */
private static final String INIT_FAILED = "initialization failed.!!";
private static final LifeCycleContext lifeCycle = LifeCycleContext.getInstance();
private static AnnotationTransformer annotationTransformer;
/**
* Private singalton.
*/
private Context() {
// Nothing here. Private Constructor
}
/**
* Initialize the Audit4j instance. This will ensure the single audit4j
* instance and single Configuration repository load in to the memory.
*/
final static void init() {
StopWatch stopWatch = new StopWatch();
stopWatch.start("Audit4jInit");
if (configContext == null) {
configContext = new ConcurrentConfigurationContext();
}
if (lifeCycle.getStatus().equals(RunStatus.READY) || lifeCycle.getStatus().equals(RunStatus.STOPPED)) {
Audit4jBanner banner = new Audit4jBanner();
banner.printBanner();
Log.info("Initializing Audit4j...");
// Check system environment;
checkEnvironment();
// Load configurations to Memory
Log.info("Loading Configurations...");
if (conf == null) {
loadConfig();
}
Log.info("Validating Configurations...");
if (conf == null) {
terminate();
throw new InitializationException(INIT_FAILED);
}
try {
ValidationManager.validateConfigurations(conf);
} catch (ValidationException e1) {
terminate();
throw new InitializationException(INIT_FAILED, e1);
}
// Execute commands.
CommandProcessor.getInstance().process(conf.getCommands());
// Load Registry configurations.
loadRegistry();
if (conf.getProperties() == null) {
conf.setProperties(new HashMap<String, String>());
} else {
for (Map.Entry<String, String> entry : conf.getProperties().entrySet()) {
if (System.getProperties().containsKey(entry.getValue())) {
conf.getProperties().put(entry.getKey(), System.getProperty(entry.getValue()));
}
}
}
configContext.getProperties().putAll(conf.getProperties());
// Initialize handlers.
initHandlers();
// Initialize layouts.
initLayout();
// Initialize annotation transformer.
if (conf.getAnnotationTransformer() == null) {
annotationTransformer = getDefaultAnnotationTransformer();
} else {
annotationTransformer = conf.getAnnotationTransformer();
}
// Initialize IO streams.
initStreams();
for (AuditEventFilter filter : conf.getFilters()) {
configContext.addFilter(filter);
}
configContext.setMetaData(conf.getMetaData());
// Execute Scheduler tasks.
Log.info("Executing Schedulers...");
Schedulers.taskRegistry().scheduleAll();
// Initialize monitoring support if available in the configurations.
if (conf.getJmx() != null) {
MBeanAgent agent = new MBeanAgent();
agent.setJmxConfig(conf.getJmx());
agent.init();
agent.registerMbeans();
}
lifeCycle.setStatus(RunStatus.RUNNING);
lifeCycle.setStartUpTime(new Date().getTime());
stopWatch.stop();
Long initializationTime = stopWatch.getLastTaskTimeMillis();
Log.info("Audit4j initialized. Total time: ", initializationTime, "ms");
}
}
/**
* Initialize audit4j with external configurations.
*
* This method allows to external plugins can inject the configurations.
* Since the security reasons, this allows to create one time configuration
* setting to Audit4j.
*
* @param configuration
* the configuration
*
* @since 2.3.1
*/
public static void initWithConfiguration(Configuration configuration) {
Context.setConfig(configuration);
init();
}
/**
* Initialize audit4j with external configuration file.
*
* This method allows to external plugins can inject the configurations.
* Since the security reasons, this allows to create one time configuration
* setting to Audit4j.
*
* @param configFilePath
* the config file path
* @since 2.3.1
*/
public static void initWithConfiguration(String configFilePath) {
Context.setConfigFilePath(configFilePath);
init();
}
/**
* The Audit4j context shutdown method. This will release the all allocated
* resources by the Audit4j Context initialization.
*
* @since 2.2.0
*/
final static void stop() {
if (lifeCycle.getStatus().equals(RunStatus.RUNNING) || lifeCycle.getStatus().equals(RunStatus.DISABLED)) {
lifeCycle.setStatus(RunStatus.STOPPED);
Log.info("Preparing to shutdown Audit4j...");
Log.info("Closing Streams...");
auditStream.close();
Log.info("Shutdown handlers...");
for (Handler handler : configContext.getHandlers()) {
handler.stop();
Log.info(handler.getClass().getName() + " shutdown.");
}
Log.info("Disposing configurations...");
configContext = null;
conf = null;
Log.info("Audit4j shutdown completed.");
} else {
Log.info("No active Audit4j instance. Cancelling shutdown request.");
}
}
/**
* Enable Audit4j core services.
*
* @since 2.2.0
*/
final static void enable() {
if (lifeCycle.getStatus().equals(RunStatus.READY) || lifeCycle.getStatus().equals(RunStatus.STOPPED)) {
init();
} else if (lifeCycle.getStatus().equals(RunStatus.DISABLED)) {
lifeCycle.setStatus(RunStatus.RUNNING);
}
}
/**
* Disable Audit4j core services.
*
* @since 2.2.0
*/
final static void disable() {
Log.warn("Audit4j Disabled.!!");
lifeCycle.setStatus(RunStatus.DISABLED);
}
/**
* Terminate Audit4j core services.
*
* @since 2.3.0
*/
final static void terminate() {
Log.warn("Audit4j Terminated due to critical error.");
lifeCycle.setStatus(RunStatus.TERMINATED);
}
/**
* Gets the config context.
*
* @return the config context
*/
static ConcurrentConfigurationContext getConfigContext() {
return configContext;
}
/**
* Check environment.
*
* @since 2.3.0
*/
private final static void checkEnvironment() {
// Check java support.!
boolean javaSupport = EnvUtil.isJDK7OrHigher();
if (!javaSupport) {
Log.error("Your Java version (", EnvUtil.getJavaersion(), ") is not supported for Audit4j. ",
ErrorGuide.getGuide(ErrorGuide.JAVA_VERSION_ERROR));
throw new InitializationException("Java version is not supported.");
}
}
/**
* Load configuration items.
*/
private final static void loadConfig() {
try {
conf = Configurations.loadConfig(configFilePath);
} catch (ConfigurationException e) {
terminate();
throw new InitializationException(INIT_FAILED, e);
}
}
/**
* Load initial configurations from Registry.
*
* @since 2.3.0
*/
private static void loadRegistry() {
// Load audit filters to runtime configurations.
for (AuditEventFilter filter : PreConfigurationContext.getPrefilters()) {
configContext.addFilter(filter);
}
// Load audit annotation filters to runtime configurations.
for (AuditAnnotationFilter annotationFilter : PreConfigurationContext.getPreannotationfilters()) {
configContext.addAnnotationFilter(annotationFilter);
}
}
/**
* Initialize handlers.
*/
private static void initHandlers() {
Log.info("Initializing Handlers...");
for (Handler handler : conf.getHandlers()) {
try {
if (!configContext.getHandlers().contains(handler)) {
Map<String, String> handlerproperties = new HashMap<>();
handlerproperties.putAll(configContext.getProperties());
handler.setProperties(handlerproperties);
handler.init();
configContext.addHandler(handler);
}
Log.info(handler.getClass().getName() + " Initialized.");
} catch (InitializationException e) {
Log.error("There is a problem in the hander: ", handler.getClass().getName(),
ErrorGuide.getGuide(ErrorGuide.HANDLER_ERROR));
terminate();
throw new InitializationException(INIT_FAILED, e);
}
}
}
/**
* Initialize layout.
*/
private static void initLayout() {
Log.info("Initializing Layout...");
try {
conf.getLayout().init();
configContext.setLayout(conf.getLayout());
Log.info(conf.getLayout().getClass().getName() + " Initialized.");
} catch (InitializationException e) {
Log.error("There is a problem in the layout: ", conf.getLayout().getClass().getName(), " you configured.",
ErrorGuide.getGuide(ErrorGuide.LAYOUT_ERROR));
terminate();
throw new InitializationException(INIT_FAILED);
}
}
/**
* Initialize streams.
*/
private static void initStreams() {
Log.info("Initializing Streams...");
MetadataCommand command = (MetadataCommand) PreConfigurationContext.getCommandByName("-metadata");
if (command.isAsync()) {
AsyncAnnotationAuditOutputStream asyncAnnotationStream = new AsyncAnnotationAuditOutputStream(
new AuditProcessOutputStream(Context.getConfigContext()), annotationTransformer);
MetadataLookupStream metadataStream = new MetadataLookupStream(
new AuditProcessOutputStream(Context.getConfigContext()));
AsyncAuditOutputStream asyncStream = new AsyncAuditOutputStream(metadataStream, asyncAnnotationStream);
auditStream = new AuditEventOutputStream(asyncStream);
} else {
AsyncAnnotationAuditOutputStream asyncAnnotationStream = new AsyncAnnotationAuditOutputStream(
new AuditProcessOutputStream(Context.getConfigContext()), annotationTransformer);
AsyncAuditOutputStream asyncStream = new AsyncAuditOutputStream(
new AuditProcessOutputStream(Context.getConfigContext()), asyncAnnotationStream);
MetadataLookupStream metadataStream = new MetadataLookupStream(asyncStream);
auditStream = new AuditEventOutputStream(metadataStream);
}
Log.info("Audit Streams Initialized.");
}
/**
* Initializes and returns the default annotation transformer.
*
* @return default annotation transformer
*/
private static AnnotationTransformer<AuditEvent> getDefaultAnnotationTransformer() {
DefaultAnnotationTransformer defaultAnnotationTransformer = new DefaultAnnotationTransformer();
ObjectSerializerCommand serializerCommand = (ObjectSerializerCommand) PreConfigurationContext
.getCommandByName("-objectSerializer");
if (serializerCommand.getSerializer() == null) {
defaultAnnotationTransformer.setSerializer(new ObjectToFieldsSerializer());
} else {
defaultAnnotationTransformer.setSerializer(serializerCommand.getSerializer());
}
return defaultAnnotationTransformer;
}
/**
* Sets the config.
*
* @param conf
* the new config
*/
final static void setConfig(Configuration conf) {
Context.conf = conf;
}
/**
* Gets the config.
*
* @return the config
* @deprecated
*
* Gets the config.
*/
@Deprecated
static Configuration getConfig() {
return conf;
}
/**
* Sets the config file path.
*
* @param configFilePath
* the new config file path
*/
public static void setConfigFilePath(String configFilePath) {
Context.configFilePath = configFilePath;
}
/**
* Gets the audit stream.
*
* @return the audit stream
*/
final static AuditOutputStream<AuditEvent> getAuditStream() {
return auditStream;
}
/**
* Gets the running status.
*
* @return the status
* @since 2.2.0
*/
public static RunStatus getStatus() {
return lifeCycle.getStatus();
}
}