/*
* IronJacamar, a Java EE Connector Architecture implementation
* Copyright 2015, Red Hat Inc, 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 Eclipse Public License 1.0 as
* published by the Free Software Foundation.
*
* 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 Eclipse
* Public License for more details.
*
* You should have received a copy of the Eclipse 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.ironjacamar.embedded;
import org.ironjacamar.embedded.dsl.InputStreamDescriptor;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.jboss.logging.Logger;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.ResourceAdapterArchive;
import org.jboss.shrinkwrap.descriptor.api.Descriptor;
import com.github.fungal.api.Kernel;
import com.github.fungal.api.KernelFactory;
import com.github.fungal.api.classloading.ClassLoaderFactory;
import com.github.fungal.api.configuration.DeploymentOrder;
import com.github.fungal.api.configuration.KernelConfiguration;
/**
* The embedded IronJacamar container
* @author <a href="mailto:jesper.pedersen@ironjacamar.org">Jesper Pedersen</a>
*/
class EmbeddedJCA implements Embedded
{
/** Buffer size */
private static final int BUFFER_SIZE = 4096;
/** The logger */
private static Logger log = Logger.getLogger(EmbeddedJCA.class);
/** Enable full profile */
private final boolean fullProfile;
/** Kernel */
private Kernel kernel;
/** ShrinkWrap deployments */
private List<File> shrinkwrapDeployments;
/** Started */
private boolean started;
/**
* Constructs an embedded JCA environment. If <code>fullProfile</code>
* is <code>true</code> then a full JCA 1.6 container is initialized -
* otherwise only the basic kernel is initialized and services has
* to be added as deployments
* @param fullProfile Should a full profile be initialized
*/
EmbeddedJCA(boolean fullProfile)
{
this.fullProfile = fullProfile;
this.shrinkwrapDeployments = null;
this.started = false;
}
/**
* Startup
* @exception Throwable If an error occurs
*/
public void startup() throws Throwable
{
if (started)
throw new IllegalStateException("Container already started");
List<String> order = new ArrayList<String>(3);
order.add(".xml");
order.add(".rar");
order.add("-ra.xml");
order.add("-ds.xml");
boolean management =
Boolean.valueOf(SecurityActions.getSystemProperty("ironjacamar.embedded.management", "false"));
KernelConfiguration kernelConfiguration = new KernelConfiguration();
kernelConfiguration = kernelConfiguration.name("ironjacamar");
kernelConfiguration = kernelConfiguration.home(null);
kernelConfiguration = kernelConfiguration.classLoader(ClassLoaderFactory.TYPE_PARENT_FIRST);
kernelConfiguration = kernelConfiguration.management(management);
if (management)
kernelConfiguration = kernelConfiguration.usePlatformMBeanServer(true);
kernelConfiguration = kernelConfiguration.parallelDeploy(false);
kernelConfiguration = kernelConfiguration.remoteAccess(false);
kernelConfiguration = kernelConfiguration.hotDeployment(false);
kernelConfiguration = kernelConfiguration.eventListener(new PreClassLoaderEventListener());
kernelConfiguration = kernelConfiguration.eventListener(new PostClassLoaderEventListener());
kernelConfiguration = kernelConfiguration.deploymentOrder(new DeploymentOrder(order));
kernel = KernelFactory.create(kernelConfiguration);
kernel.startup();
if (fullProfile)
{
deploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "naming.xml");
deploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "stdio.xml");
deploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "transaction.xml");
deploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "jca.xml");
deploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "ds.xml");
}
started = true;
}
/**
* Shutdown
* @exception Throwable If an error occurs
*/
public void shutdown() throws Throwable
{
if (!started)
throw new IllegalStateException("Container not started");
if (shrinkwrapDeployments != null && !shrinkwrapDeployments.isEmpty())
{
List<File> copy = new ArrayList<File>(shrinkwrapDeployments);
for (File f : copy)
{
removeDeployment(f);
}
}
if (fullProfile)
{
undeploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "ds.xml");
undeploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "jca.xml");
undeploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "transaction.xml");
undeploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "stdio.xml");
undeploy(SecurityActions.getClassLoader(EmbeddedJCA.class), "naming.xml");
}
kernel.shutdown();
started = false;
}
/**
* {@inheritDoc}
*/
public boolean isRunning()
{
return started;
}
/**
* Lookup a bean
* @param <T> the generic type
* @param name The bean name
* @param expectedType The expected type for the bean
* @return The bean instance
* @exception Throwable If an error occurs
*/
public <T> T lookup(String name, Class<T> expectedType) throws Throwable
{
if (name == null)
throw new IllegalArgumentException("Name is null");
if (expectedType == null)
throw new IllegalArgumentException("ExpectedType is null");
if (!started)
throw new IllegalStateException("Container not started");
return kernel.getBean(name, expectedType);
}
/**
* Deploy
* @param url The resource url
* @exception Throwable If an error occurs
*/
public void deploy(URL url) throws Throwable
{
if (url == null)
throw new IllegalArgumentException("Url is null");
if (!started)
throw new IllegalStateException("Container not started");
log.debugf("Deploying: %s", url);
kernel.getMainDeployer().deploy(url);
}
/**
* {@inheritDoc}
*/
public void deploy(Descriptor descriptor) throws Throwable
{
if (descriptor == null)
throw new IllegalArgumentException("Descriptor is null");
if (descriptor.getDescriptorName() == null)
throw new IllegalArgumentException("Descriptor name is null");
if (!(descriptor instanceof InputStreamDescriptor ||
descriptor instanceof org.ironjacamar.embedded.dsl.datasources20.api.DatasourcesDescriptor ||
descriptor instanceof org.ironjacamar.embedded.dsl.resourceadapters20.api.ResourceAdaptersDescriptor))
throw new IllegalArgumentException("Unsupported descriptor: " + descriptor.getClass().getName());
if (!started)
throw new IllegalStateException("Container not started");
File parentDirectory = new File(SecurityActions.getSystemProperty("java.io.tmpdir"));
File descriptorFile = new File(parentDirectory, descriptor.getDescriptorName());
if (descriptorFile.exists())
recursiveDelete(descriptorFile);
FileOutputStream os = new FileOutputStream(descriptorFile);
BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE);
try
{
descriptor.exportTo(bos);
bos.flush();
}
finally
{
try
{
bos.close();
}
catch (IOException ignore)
{
// Ignore
}
}
log.debugf("Deploying: %s", descriptorFile);
kernel.getMainDeployer().deploy(descriptorFile.toURI().toURL());
}
/**
* Deploy
* @param raa The resource adapter archive
* @exception Throwable If an error occurs
*/
public void deploy(ResourceAdapterArchive raa) throws Throwable
{
if (raa == null)
throw new IllegalArgumentException("Url is null");
if (!raa.getName().endsWith(".rar"))
throw new IllegalArgumentException(raa.getName() + " doesn't end with .rar");
if (!started)
throw new IllegalStateException("Container not started");
File parentDirectory = new File(SecurityActions.getSystemProperty("java.io.tmpdir"));
File raaFile = new File(parentDirectory, raa.getName());
if (shrinkwrapDeployments != null && shrinkwrapDeployments.contains(raaFile))
throw new IOException(raa.getName() + " already deployed");
if (raaFile.exists())
recursiveDelete(raaFile);
raa.as(ZipExporter.class).exportTo(raaFile, true);
if (shrinkwrapDeployments == null)
shrinkwrapDeployments = new ArrayList<File>(1);
shrinkwrapDeployments.add(raaFile);
log.debugf("Deploying: %s", raaFile);
kernel.getMainDeployer().deploy(raaFile.toURI().toURL());
}
/**
* Deploy
* @param cl The class loader
* @param name The resource name
* @exception Throwable If an error occurs
*/
private void deploy(ClassLoader cl, String name) throws Throwable
{
if (cl == null)
throw new IllegalArgumentException("ClassLoader is null");
if (name == null)
throw new IllegalArgumentException("Name is null");
URL url = cl.getResource(name);
if (url == null)
throw new IllegalArgumentException("Resource is null");
log.debugf("Deploying: %s", url);
kernel.getMainDeployer().deploy(url);
}
/**
* Undeploy
* @param url The resource url
* @exception Throwable If an error occurs
*/
public void undeploy(URL url) throws Throwable
{
if (url == null)
throw new IllegalArgumentException("Url is null");
if (!started)
throw new IllegalStateException("Container not started");
log.debugf("Undeploying: %s", url);
kernel.getMainDeployer().undeploy(url);
}
/**
* {@inheritDoc}
*/
public void undeploy(Descriptor descriptor) throws Throwable
{
if (descriptor == null)
throw new IllegalArgumentException("Descriptor is null");
if (descriptor.getDescriptorName() == null)
throw new IllegalArgumentException("Descriptor name is null");
if (!(descriptor instanceof InputStreamDescriptor ||
descriptor instanceof org.ironjacamar.embedded.dsl.datasources20.api.DatasourcesDescriptor ||
descriptor instanceof org.ironjacamar.embedded.dsl.resourceadapters20.api.ResourceAdaptersDescriptor))
throw new IllegalArgumentException("Unsupported descriptor: " + descriptor.getClass().getName());
if (!started)
throw new IllegalStateException("Container not started");
File parentDirectory = new File(SecurityActions.getSystemProperty("java.io.tmpdir"));
File descriptorFile = new File(parentDirectory, descriptor.getDescriptorName());
log.debugf("Undeploying: %s", descriptorFile);
kernel.getMainDeployer().undeploy(descriptorFile.toURI().toURL());
recursiveDelete(descriptorFile);
}
/**
* Undeploy
* @param raa The resource adapter archive
* @exception Throwable If an error occurs
*/
public void undeploy(ResourceAdapterArchive raa) throws Throwable
{
if (raa == null)
throw new IllegalArgumentException("Url is null");
if (!started)
throw new IllegalStateException("Container not started");
File parentDirectory = new File(SecurityActions.getSystemProperty("java.io.tmpdir"));
File raaFile = new File(parentDirectory, raa.getName());
log.debugf("Undeploying: %s", raaFile);
if (shrinkwrapDeployments == null || !shrinkwrapDeployments.contains(raaFile))
throw new IOException(raa.getName() + " not deployed");
kernel.getMainDeployer().undeploy(raaFile.toURI().toURL());
removeDeployment(raaFile);
}
/**
* Undeploy
* @param cl The class loader
* @param name The resource name
* @exception Throwable If an error occurs
*/
private void undeploy(ClassLoader cl, String name) throws Throwable
{
if (cl == null)
throw new IllegalArgumentException("ClassLoader is null");
if (name == null)
throw new IllegalArgumentException("Name is null");
URL url = cl.getResource(name);
log.debugf("Undeploying: %s", url);
kernel.getMainDeployer().undeploy(url);
}
/**
* Remove ShrinkWrap deployment
* @param deployment The deployment
* @exception IOException Thrown if the deployment cant be removed
*/
private void removeDeployment(File deployment) throws IOException
{
if (deployment == null)
throw new IllegalArgumentException("Deployment is null");
if (deployment.exists() || (shrinkwrapDeployments != null && shrinkwrapDeployments.contains(deployment)))
{
shrinkwrapDeployments.remove(deployment);
if (shrinkwrapDeployments.isEmpty())
shrinkwrapDeployments = null;
recursiveDelete(deployment);
}
}
/**
* Recursive delete
* @param f The file handler
* @exception IOException Thrown if a file could not be deleted
*/
private void recursiveDelete(File f) throws IOException
{
if (f != null && f.exists())
{
File[] files = f.listFiles();
if (files != null)
{
for (int i = 0; i < files.length; i++)
{
if (files[i].isDirectory())
{
recursiveDelete(files[i]);
}
else
{
if (!files[i].delete())
throw new IOException("Could not delete " + files[i]);
}
}
}
if (!f.delete())
throw new IOException("Could not delete " + f);
}
}
}