/**
*
*/
package org.minnal.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ServiceLoader;
import org.minnal.core.config.ApplicationConfiguration;
import org.minnal.core.config.ConfigurationProvider;
import org.minnal.core.config.ContainerConfiguration;
import org.minnal.utils.reflection.Generics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Lists;
/**
* @author ganeshs
*
*/
public class Container implements Lifecycle {
private Router router;
private ApplicationMapping applicationMapping;
private ContainerConfiguration configuration;
private List<ContainerLifecycleListener> listeners = new ArrayList<ContainerLifecycleListener>();
private ContainerMessageObserver messageObserver = new ContainerMessageObserver();
private List<Bundle<BundleConfiguration>> bundles = new ArrayList<Bundle<BundleConfiguration>>();
private static ConfigurationProvider configurationProvider = ConfigurationProvider.getDefault();
private static final Logger logger = LoggerFactory.getLogger(Container.class);
public Container(String configPath) {
this(configurationProvider.provide(ContainerConfiguration.class, configPath));
}
public Container() {
this(configurationProvider.provide(ContainerConfiguration.class));
}
public Container(ContainerConfiguration configuration) {
this.configuration = configuration;
this.applicationMapping = new ApplicationMapping(configuration.getBasePath());
router = new Router(applicationMapping);
router.registerListener(messageObserver);
}
public void init() {
loadBundles();
loadApplications();
}
public Collection<Application<ApplicationConfiguration>> getApplications() {
return applicationMapping.getApplications();
}
protected void loadApplications() {
logger.info("Loading the applications");
for (Application<ApplicationConfiguration> application : ServiceLoader.load(Application.class)) {
String mountPath = configuration.getMounts().get(application.getClass().getName());
if (mountPath == null) {
mountPath = application.getConfiguration().getBasePath();
} else {
application.getConfiguration().setBasePath(mountPath);
}
mount(application);
}
}
/**
* Loads all the bundles using SPI.
*/
protected void loadBundles() {
logger.info("Loading the bundles from service loader");
ServiceLoader<Bundle> loader = ServiceLoader.load(Bundle.class);
List<Bundle> bundles = Lists.newArrayList(loader);
Collections.sort(bundles, new Comparator<Bundle>() {
@Override
public int compare(Bundle o1, Bundle o2) {
if (o1.getOrder() == o2.getOrder()) {
return 0;
}
return o1.getOrder() < o2.getOrder() ? -1 : 1;
}
});
for (Bundle<BundleConfiguration> bundle : bundles) {
Class<BundleConfiguration> configClass = Generics.getTypeParameter(bundle.getClass(), BundleConfiguration.class);
BundleConfiguration bundleConfig = configuration.getBundleOverrides().get(bundle.getClass().getCanonicalName());
if (bundleConfig == null) {
try {
bundleConfig = (BundleConfiguration) configClass.newInstance();
} catch (Exception e) {
throw new MinnalException(e);
}
}
bundle.init(this, bundleConfig);
this.bundles.add(bundle);
}
}
/**
* Mounts the application on the container
*
* @param application
*/
protected void mount(Application<ApplicationConfiguration> application) {
logger.info("Mounting the application {} on the mount path {}", application, application.getConfiguration().getBasePath());
application.getConfiguration().setParent(configuration);
for (ContainerLifecycleListener listener : listeners) {
listener.preMount(application);
}
application.init();
applicationMapping.addApplication(application);
for (ContainerLifecycleListener listener : listeners) {
listener.postMount(application);
}
}
/**
* Unmounts an application from the given mount url
*
* @param mountUrl
*/
protected void unMount(String mountUrl) {
logger.info("Unmounting the mount path {}", mountUrl);
Application<ApplicationConfiguration> application = applicationMapping.removeApplication(mountUrl);
for (ContainerLifecycleListener listener : listeners) {
listener.preUnMount(application);
}
application.stop();
for (ContainerLifecycleListener listener : listeners) {
listener.postUnMount(application);
}
}
public void start() {
logger.info("Starting the container");
for (ContainerLifecycleListener listener : listeners) {
listener.beforeStart(this);
}
for (Bundle<BundleConfiguration> bundle : bundles) {
bundle.start();
}
for (Application<ApplicationConfiguration> application : applicationMapping.getApplications()) {
application.start();
}
for (ContainerLifecycleListener listener : listeners) {
listener.afterStart(this);
}
}
public void stop() {
logger.info("Stopping the container");
for (ContainerLifecycleListener listener : listeners) {
listener.beforeStop(this);
}
for (Bundle<BundleConfiguration> bundle : bundles) {
bundle.stop();
}
// FIXME What will application do on stop?
for (Application<ApplicationConfiguration> application : applicationMapping.getApplications()) {
application.stop();
}
for (ContainerLifecycleListener listener : listeners) {
listener.afterStop(this);
}
}
public void registerListener(ContainerLifecycleListener listener) {
logger.trace("Registering the life cycle listener {}", listener.getClass());
listeners.add(listener);
}
public void registerListener(MessageListener listener) {
messageObserver.registerListener(listener);
}
/**
* @return the configuration
*/
public ContainerConfiguration getConfiguration() {
return configuration;
}
/**
* @return the router
*/
public Router getRouter() {
return router;
}
public ContainerMessageObserver getMessageObserver() {
return messageObserver;
}
}