/*
* JBoss, Home of Professional Open Source.
* Copyright 2009, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.bootstrap.impl.mc.server;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
import org.jboss.bootstrap.api.config.InvalidConfigurationException;
import org.jboss.bootstrap.api.config.ServerConfig;
import org.jboss.bootstrap.api.lifecycle.LifecycleEventException;
import org.jboss.bootstrap.api.server.Server;
import org.jboss.bootstrap.impl.base.config.InvalidBootstrapURLException;
import org.jboss.bootstrap.impl.base.server.AbstractServer;
import org.jboss.bootstrap.impl.base.xml.BootstrapParser;
import org.jboss.bootstrap.impl.mc.deployer.TempBasicXMLDeployer;
import org.jboss.bootstrap.spi.mc.server.MCBasedServerProvider;
import org.jboss.bootstrap.spi.metadata.BootstrapMetaData;
import org.jboss.kernel.Kernel;
import org.jboss.kernel.plugins.bootstrap.basic.BasicBootstrap;
import org.jboss.kernel.spi.dependency.KernelController;
import org.jboss.kernel.spi.deployment.KernelDeployment;
import org.jboss.logging.Logger;
import org.jboss.managed.api.annotation.ManagementProperty;
/**
* AbstractMCServerBase
*
* Microcontainer implementation of a Server.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @author <a href="ales.justin@jboss.com">Ales Justin</a>
* @author Scott.Stark@jboss.org
* @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a>
* @version $Revision: $
*/
public abstract class AbstractMCServerBase<K extends Server<K, T>, T extends ServerConfig<T>>
extends
AbstractServer<K, T> implements MCBasedServerProvider<K, T>
{
//-------------------------------------------------------------------------------------||
// Class Members ----------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
private static final Logger log = Logger.getLogger(AbstractMCServerBase.class);
/**
* Represents a slash
*/
private static final String SLASH = "/";
//-------------------------------------------------------------------------------------||
// Instance Members -------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* The MC Bootstrap
*/
private BasicBootstrap bootstrap;
/**
* The XML Deployer
*/
private TempBasicXMLDeployer kernelDeployer;
/**
* Container for version information.
*/
private final MCVersion version = MCVersion.getInstance();
//-------------------------------------------------------------------------------------||
// Constructors -----------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Constructor
*
* Creates the server with no default configuration
*/
protected AbstractMCServerBase(final Class<K> actualClass)
{
this(actualClass, null);
}
/**
* Constructor
*
* Creates the server from the specified configuration
*
* @param config
*/
protected AbstractMCServerBase(final Class<K> actualClass, final T config)
{
// Invoke super
super(actualClass, config);
}
//-------------------------------------------------------------------------------------||
// Overridden Implementations ---------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/* (non-Javadoc)
* @see org.jboss.bootstrap.impl.base.server.AbstractServer#getConfiguration()
*/
// Overridden just so that we can define the @ManagementProperty annotation
@ManagementProperty(name = "config")
@Override
public final T getConfiguration()
{
return super.getConfiguration();
}
//-------------------------------------------------------------------------------------||
// Required Implementations -----------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/* (non-Javadoc)
* @see org.jboss.bootstrap.spi.mc.server.MCServer#getKernel()
*/
@ManagementProperty(ignored = true)
public Kernel getKernel()
{
return this.getBootstrap().getKernel();
}
/*
* (non-Javadoc)
* @see org.jboss.bootstrap.spi.mc.server.MCBasedServer#getDeployments()
*/
@ManagementProperty(ignored = true)
public Map<String, KernelDeployment> getDeployments()
{
Map<String, KernelDeployment> deployments = null;
if (kernelDeployer != null)
deployments = kernelDeployer.getDeployments();
return deployments;
}
/* (non-Javadoc)
* @see org.jboss.bootstrap.spi.server.AbstractServer#doShutdown()
*/
@Override
protected void doShutdown() throws Exception
{
// Shutdown the deployer
try
{
if (kernelDeployer != null)
{
kernelDeployer.shutdown();
kernelDeployer = null;
}
}
catch (Throwable t)
{
log.warn("Error stopping xml deployer", t);
}
// Shutdown the controller
try
{
// Get a reference to the underlying kernel
Kernel tempKernelReference = null;
if (bootstrap != null)
{
tempKernelReference = bootstrap.getKernel();
}
// Null out the Bootstrap
bootstrap = null;
// If we had a kernel
if (tempKernelReference != null)
{
// Shut it down
KernelController controller = tempKernelReference.getController();
controller.shutdown();
}
}
catch (final Exception e)
{
log.warn("Error stopping " + KernelController.class.getName(), e);
}
}
/*
* (non-Javadoc)
* @see org.jboss.bootstrap.impl.base.server.AbstractServer#initialize()
*/
@Override
protected void doInitialize() throws IllegalStateException, InvalidConfigurationException, LifecycleEventException
{
/*
* We need to start the bootstrap here so we can set the kernel
* before we fire start kernel events
*/
this.initializeBootstrap();
// Call Super implementation
super.doInitialize();
}
/* (non-Javadoc)
* @see org.jboss.bootstrap.impl.base.server.AbstractServer#start()
*/
@Override
public void start() throws IllegalStateException, Exception
{
/*
* In the case that we're re-started, we need to reconstruct
* and set a new bootstrap/kernel, because initialize will
* is only called once.
*/
final BasicBootstrap bootstrap = this.getBootstrap();
if (bootstrap == null)
{
if (log.isTraceEnabled())
{
log.trace("Re-initializing the underlying bootstrap...");
}
this.initializeBootstrap();
log.debug("Underlying MC Bootstrap re-initialized.");
}
// Call Super implementation
super.start();
}
/* (non-Javadoc)
* @see org.jboss.bootstrap.spi.server.AbstractServer#doStart()
*/
@Override
protected void doStart() throws Exception
{
// Register the server implementation
final String mcServerBindName = "JBossServer";
final Kernel kernel = this.getKernel();
if (kernel == null)
{
throw new IllegalStateException("Server cannot be started without the presence of an underlying "
+ Kernel.class.getName());
}
final KernelController controller = kernel.getController();
final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(mcServerBindName, getClass().getName());
builder.addMethodInstallCallback("addBootstrap");
builder.addMethodUninstallCallback("removeBootstrap");
builder.ignoreStart(); // We invoke start manually, don't let MC do it
builder.ignoreStop(); // Stop on the server is called by the client, don't double-stop
try
{
log.debug("Installing " + this + " into MC under key: " + mcServerBindName);
controller.install(builder.getBeanMetaData(), this);
}
catch (Throwable t)
{
throw new Exception("Error in installing " + mcServerBindName + " during startup", t);
}
// Determine the url for the bootstrap
final T config = this.getConfiguration();
final URL homeUrl = config.getBootstrapHome();
final URL bootstrapUrl = config.getBootstrapUrl();
log.info("Starting Microcontainer, Main bootstrapURL=" + bootstrapUrl);
// Parse the bootstrap metadata
final BootstrapMetaData bootstrapMetaData = BootstrapParser.parse(bootstrapUrl);
List<String> bootstrapURLs = bootstrapMetaData.getBootstrapURLs();
if (bootstrapURLs == null)
{
bootstrapURLs = Collections.emptyList();
}
if (bootstrapURLs.isEmpty())
{
log.warn("No bootstrap urls in " + bootstrapUrl);
}
log.debug("BootstrapURLs=" + bootstrapURLs);
log.debug("Bootstrap URLs are relative to: " + homeUrl);
// Create an xml deployer
kernelDeployer = new TempBasicXMLDeployer(kernel);
try
{
// Deploy the bootstrap urls
for (String childBootstrapURL : bootstrapURLs)
{
// Check if child bootstrap URL is valid
if (childBootstrapURL.startsWith(SLASH))
{
throw new InvalidBootstrapURLException("Invlaid bootstrap URL: " + childBootstrapURL
+ ". Bootstrap URLs can not start with a '" + SLASH + "'");
}
final URL suburl = new URL(bootstrapUrl, childBootstrapURL);
log.debug("Deploying bootstrap xml: " + suburl);
kernelDeployer.deploy(suburl);
}
// Check it is complete
kernelDeployer.validate();
}
catch (Throwable t)
{
try
{
kernelDeployer.shutdown();
}
catch (Throwable ignored)
{
}
throw new Exception("Encountered exception in server startup", t);
}
}
//-------------------------------------------------------------------------------------||
// Functional Methods -----------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* @return the bootstrap
*/
protected final BasicBootstrap getBootstrap()
{
return bootstrap;
}
//-------------------------------------------------------------------------------------||
// Internal Helper Methods ------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Creates and runs the bootstrap, setting it upon completion
*/
private void initializeBootstrap()
{
// Run Bootstrap and set it
final BasicBootstrap bootstrap = new BasicBootstrap();
bootstrap.run();
this.bootstrap = bootstrap;
if (log.isTraceEnabled())
{
log.trace("Created and run: " + bootstrap);
}
}
@Override
public String toString()
{
return new StringBuilder().append("MCServer [").append(this.version.toString()).append("]").toString();
}
}