/*
* Copyright 2013, The Sporting Exchange Limited
*
* 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 com.betfair.cougar.core.impl;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import com.betfair.cougar.core.api.CougarSpringCtxFactory;
import com.betfair.cougar.core.api.exception.PanicInTheCougar;
import com.betfair.cougar.core.impl.logging.CougarLog4JBootstrap;
import com.betfair.cougar.core.impl.logging.LogBootstrap;
import com.betfair.cougar.core.impl.logging.NullLogBootstrap;
import com.betfair.cougar.logging.CougarLoggingUtils;
import com.betfair.cougar.util.configuration.PropertyLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* A factory that creates and starts cougar application server. Can be used to start cougar application server as a
* stand-alone java application or to start it as an embedded component, e.g. from a servlet-based web application.
* <p/>
* Examples:
* To start cougar as a standalone app just call:
* new CougarSpringCtxFactoryImpl().create(null);
* <p/>
* To integrate cougar with existing servlet-based web application, create custom ServletContextListener and call:
* WebApplicationContext parentCtx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
* new CougarSpringCtxFactoryImpl().create(parentCtx);
*/
public class CougarSpringCtxFactoryImpl implements CougarSpringCtxFactory {
public static final String LOGGING_BOOTSTRAP_CLASS_PROPERTY = "cougar.core.log.bootstrap.class";
public static final Class DEFAULT_COUGAR_LOG_INIT_CLASS = CougarLog4JBootstrap.class;
private String configDir = "conf";
public void setConfigDir(String configDir) {
this.configDir = configDir;
}
public ClassPathXmlApplicationContext create() {
return create(null);
}
@Override
public ClassPathXmlApplicationContext create(ApplicationContext parentCtx) {
logInitialisation(System.getProperty(LOGGING_BOOTSTRAP_CLASS_PROPERTY));
ClassPathXmlApplicationContext context=null;
try {
List<String> configs = getConfigs();
if(parentCtx==null){
context= new ClassPathXmlApplicationContext(configs.toArray(new String[configs.size()]));
}else{
context=new ClassPathXmlApplicationContext(configs.toArray(new String[configs.size()]), parentCtx);
}
} catch (Exception e) {
CougarLoggingUtils.getLogger(CougarSpringCtxFactoryImpl.class).log(e);
throw new PanicInTheCougar(e);
}
return context;
}
protected List<String> getConfigs() throws IOException {
List<String> configs = new ArrayList<String>();
Enumeration<URL> bootstraps = Main.class.getClassLoader().getResources(configDir + "/cougar-bootstrap-spring.xml");
while (bootstraps.hasMoreElements()) {
configs.add(bootstraps.nextElement().toExternalForm());
}
URL core = Main.class.getClassLoader().getResource(configDir + "/cougar-core-spring.xml");
if (core == null) {
throw new IllegalStateException("Cannot find Cougar Core definition");
}
configs.add(core.toExternalForm());
Enumeration<URL> modules = Main.class.getClassLoader().getResources(configDir + "/cougar-module-spring.xml");
while (modules.hasMoreElements()) {
configs.add(modules.nextElement().toExternalForm());
}
Enumeration<URL> applications = Main.class.getClassLoader().getResources(configDir + "/cougar-application-spring.xml");
while (applications.hasMoreElements()) {
configs.add(applications.nextElement().toExternalForm());
}
return configs;
}
public void logInitialisation(String loggingBootstrapClassName) {
Class logBootstrapClass = establishLogInitialisationClass(loggingBootstrapClassName);
runLogInitialisation(logBootstrapClass);
}
public void runLogInitialisation(Class logBootstrapClass) {
try {
//Construct a set of resources to attempt to load initial log config from
Resource defaultConfig = new ClassPathResource(configDir + "/cougar-core-defaults.properties");
PropertyLoader pl = new PropertyLoader(defaultConfig, "overrides.properties");
//Build a merged properties file that contains the above as well as System properties
Properties properties = pl.buildConsolidatedProperties();
LogBootstrap logBootstrap = (LogBootstrap)logBootstrapClass.newInstance();
//fire it up with the full set of merged properties
logBootstrap.init(properties);
} catch (Exception ex) {
System.err.println("An error occurred initialising the logger. Ensure the value of property [" +
LOGGING_BOOTSTRAP_CLASS_PROPERTY +
"] points to a class that the implements LogBootstrap interface or is set to \"none\"" + ex);
throw new PanicInTheCougar(ex);
}
}
public Class establishLogInitialisationClass(String loggingBootstrapClassName) {
Class logBootstrapClass;
//Decision tree about the log initialisation is as follows:
//1. If the log name is "none" then do no initialisation whatsoever
//2. If there is a specific class name then attempt to load that. If that fails, write something to STDERR
//3. Otherwise load the log4j log init
if (loggingBootstrapClassName != null) {
if (loggingBootstrapClassName.equals("none")) { //If this condition fails, consumer is indicating they'll use their own log impl
logBootstrapClass = NullLogBootstrap.class;
} else {
try {
logBootstrapClass = Class.forName(loggingBootstrapClassName);
} catch (ClassNotFoundException cnfe) {
System.err.println("Unable to resolve logging initialisation class: [" +
loggingBootstrapClassName + "] falling back to default log4j initialisation for logging");
logBootstrapClass = DEFAULT_COUGAR_LOG_INIT_CLASS;
}
}
} else {
logBootstrapClass = DEFAULT_COUGAR_LOG_INIT_CLASS;
}
return logBootstrapClass;
}
}