package org.mobicents.slee.container.component.deployment;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import javax.slee.SLEEException;
import javax.slee.management.DeploymentException;
import org.apache.log4j.Logger;
import org.mobicents.slee.container.component.EventTypeComponent;
import org.mobicents.slee.container.component.LibraryComponent;
import org.mobicents.slee.container.component.ProfileSpecificationComponent;
import org.mobicents.slee.container.component.ResourceAdaptorComponent;
import org.mobicents.slee.container.component.ResourceAdaptorTypeComponent;
import org.mobicents.slee.container.component.SbbComponent;
import org.mobicents.slee.container.component.SleeComponent;
import org.mobicents.slee.container.component.deployment.classloading.URLClassLoaderDomain;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.EventTypeDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.EventTypeDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.LibraryDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.LibraryDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ProfileSpecificationDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ProfileSpecificationDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ResourceAdaptorDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ResourceAdaptorDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ResourceAdaptorTypeDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.ResourceAdaptorTypeDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.SbbDescriptorFactory;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.SbbDescriptorImpl;
import org.mobicents.slee.container.component.deployment.jaxb.descriptors.library.MJar;
/**
* DU Component jar builder
*
* @author martins
*
*/
public class DeployableUnitJarComponentBuilder {
private static final Logger logger = Logger
.getLogger(DeployableUnitJarComponentBuilder.class);
/**
* Builds the DU component from a jar with the specified file name,
* contained in the specified DU jar file. The component is built in the
* specified deployment dir.
*
* @param componentJarFileName
* @param deployableUnitJar
* @param deploymentDir
* @param documentBuilder
* @return
* @throws DeploymentException
*/
public List<SleeComponent> buildComponents(String componentJarFileName,
JarFile deployableUnitJar, File deploymentDir) throws DeploymentException {
// extract the component jar from the DU jar, to the temp du dir
File extractedFile = extractFile(componentJarFileName,
deployableUnitJar, deploymentDir);
JarFile componentJarFile = null;
try {
componentJarFile = new JarFile(extractedFile);
} catch (IOException e) {
throw new DeploymentException(
"failed to create jar file for extracted file "
+ extractedFile);
}
InputStream componentDescriptorInputStream = null;
List<SleeComponent> components = new ArrayList<SleeComponent>();
try {
// now extract the jar file to a new dir
File componentJarDeploymentDir = new File(deploymentDir,
componentJarFileName+"-contents");
if (!componentJarDeploymentDir.exists()) {
if (!componentJarDeploymentDir.mkdir()) {
throw new SLEEException("dir for jar " + componentJarFileName
+ " not created in " + deploymentDir);
}
} else {
throw new SLEEException("dir for jar " + componentJarFileName
+ " already exists in " + deploymentDir);
}
extractJar(componentJarFile, componentJarDeploymentDir);
// create components from descriptor
JarEntry componentDescriptor = null;
if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/sbb-jar.xml")) != null) {
// create class loader domain shared by all components
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(
new URL[] { componentJarDeploymentDir.toURL() }, Thread.currentThread()
.getContextClassLoader());
// parse descriptor
componentDescriptorInputStream = componentJarFile
.getInputStream(componentDescriptor);
SbbDescriptorFactory descriptorFactory = new SbbDescriptorFactory();
List<SbbDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (SbbDescriptorImpl descriptor : descriptors) {
SbbComponent component = new SbbComponent(descriptor);
component.setDeploymentDir(componentJarDeploymentDir);
component.setClassLoaderDomain(classLoaderDomain);
components.add(component);
}
} else if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/profile-spec-jar.xml")) != null) {
// create class loader domain shared by all components
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(
new URL[] { componentJarDeploymentDir.toURL() }, Thread.currentThread()
.getContextClassLoader());
// parse descriptor
componentDescriptorInputStream = componentJarFile
.getInputStream(componentDescriptor);
ProfileSpecificationDescriptorFactory descriptorFactory = new ProfileSpecificationDescriptorFactory();
List<ProfileSpecificationDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (ProfileSpecificationDescriptorImpl descriptor : descriptors) {
ProfileSpecificationComponent component = new ProfileSpecificationComponent(descriptor);
component.setDeploymentDir(componentJarDeploymentDir);
component.setClassLoaderDomain(classLoaderDomain);
components.add(component);
}
} else if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/library-jar.xml")) != null) {
Set<LibraryComponent> libraryComponents = new HashSet<LibraryComponent>();
// we need to gather all URLs for the shared class loader domain to watch
Set<URL> classLoaderDomainURLs = new HashSet<URL>();
classLoaderDomainURLs.add(componentJarDeploymentDir.toURL());
// parse the descriptor
componentDescriptorInputStream = componentJarFile
.getInputStream(componentDescriptor);
LibraryDescriptorFactory descriptorFactory = new LibraryDescriptorFactory();
List<LibraryDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (LibraryDescriptorImpl descriptor : descriptors) {
LibraryComponent component = new LibraryComponent(descriptor);
for (MJar mJar : descriptor.getJars()) {
classLoaderDomainURLs.add(new File(componentJarDeploymentDir,mJar.getJarName()).toURL());
}
// set deploy dir and cl domain
component.setDeploymentDir(componentJarDeploymentDir);
components.add(component);
libraryComponents.add(component);
}
// create shared url domain
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(classLoaderDomainURLs.toArray(new URL[classLoaderDomainURLs.size()]),Thread.currentThread().getContextClassLoader());
// add it to each component
for (LibraryComponent component : libraryComponents) {
component.setClassLoaderDomain(classLoaderDomain);
}
} else if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/event-jar.xml")) != null) {
// create class loader domain shared by all components
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(
new URL[] { componentJarDeploymentDir.toURL() }, Thread.currentThread()
.getContextClassLoader());
// parse descriptor
componentDescriptorInputStream = componentJarFile.getInputStream(componentDescriptor);
EventTypeDescriptorFactory descriptorFactory = new EventTypeDescriptorFactory();
List<EventTypeDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (EventTypeDescriptorImpl descriptor : descriptors) {
EventTypeComponent component = new EventTypeComponent(descriptor);
component.setDeploymentDir(componentJarDeploymentDir);
component.setClassLoaderDomain(classLoaderDomain);
components.add(component);
}
} else if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/resource-adaptor-type-jar.xml")) != null) {
// create class loader domain shared by all components
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(
new URL[] { componentJarDeploymentDir.toURL() }, Thread.currentThread()
.getContextClassLoader());
// parse descriptor
componentDescriptorInputStream = componentJarFile
.getInputStream(componentDescriptor);
ResourceAdaptorTypeDescriptorFactory descriptorFactory = new ResourceAdaptorTypeDescriptorFactory();
List<ResourceAdaptorTypeDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (ResourceAdaptorTypeDescriptorImpl descriptor : descriptors) {
ResourceAdaptorTypeComponent component = new ResourceAdaptorTypeComponent(descriptor);
component.setDeploymentDir(componentJarDeploymentDir);
component.setClassLoaderDomain(classLoaderDomain);
components.add(component);
}
} else if ((componentDescriptor = componentJarFile
.getJarEntry("META-INF/resource-adaptor-jar.xml")) != null) {
// create class loader domain shared by all components
URLClassLoaderDomain classLoaderDomain = new URLClassLoaderDomain(
new URL[] { componentJarDeploymentDir.toURL() }, Thread.currentThread()
.getContextClassLoader());
// parse descriptor
componentDescriptorInputStream = componentJarFile
.getInputStream(componentDescriptor);
ResourceAdaptorDescriptorFactory descriptorFactory = new ResourceAdaptorDescriptorFactory();
List<ResourceAdaptorDescriptorImpl> descriptors = descriptorFactory.parse(componentDescriptorInputStream);
// create components
for (ResourceAdaptorDescriptorImpl descriptor : descriptors) {
ResourceAdaptorComponent component = new ResourceAdaptorComponent(descriptor);
component.setDeploymentDir(componentJarDeploymentDir);
component.setClassLoaderDomain(classLoaderDomain);
components.add(component);
}
} else {
throw new DeploymentException(
"No Deployment Descriptor found in the "
+ componentJarFile.getName()
+ " entry of a deployable unit.");
}
} catch (IOException e) {
throw new DeploymentException(
"failed to parse jar descriptor from "
+ componentJarFile.getName(), e);
} finally {
if (componentDescriptorInputStream != null) {
try {
componentDescriptorInputStream.close();
} catch (IOException e) {
logger
.error("failed to close inputstream of descriptor for jar "
+ componentJarFile);
}
}
}
// close component jar file
try {
componentJarFile.close();
} catch (IOException e) {
logger.error("failed to close component jar file", e);
}
// and delete the extracted jar file, we don't need it anymore
if (!extractedFile.delete()) {
logger.warn("failed to delete " + extractedFile);
}
return components;
}
/**
* Extracts the file with name <code>fileName</code> out of the
* <code>containingJar</code> archive and stores it in <code>dstDir</code>.
*
* @param fileName
* the name of the file to extract.
* @param containingJar
* the archive where to extract it from.
* @param dstDir
* the location where the extracted file should be stored.
* @return a <code>java.io.File</code> reference to the extracted file.
* @throws DeploymentException
*/
private File extractFile(String fileName, JarFile containingJar,
File dstDir) throws DeploymentException {
ZipEntry zipFileEntry = containingJar.getEntry(fileName);
logger.debug("Extracting file " + fileName + " from "
+ containingJar.getName());
if (zipFileEntry == null) {
throw new DeploymentException("Error extracting jar file "
+ fileName + " from " + containingJar.getName());
}
File extractedFile = new File(dstDir, new File(zipFileEntry.getName())
.getName());
try {
pipeStream(containingJar.getInputStream(zipFileEntry),
new FileOutputStream(extractedFile));
} catch (FileNotFoundException e) {
throw new DeploymentException("file " + fileName + " not found in "
+ containingJar.getName(), e);
} catch (IOException e) {
throw new DeploymentException("erro extracting file " + fileName
+ " from " + containingJar.getName(), e);
}
logger.debug("Extracted file " + extractedFile.getName());
return extractedFile;
}
/**
* This method will extract all the files in the jar file
*
* @param jarFile
* the jar file
* @param dstDir
* the destination where files in the jar file be extracted
* @param deployableUnitID
* @return
* @throws DeploymentException
* failed to extract files
*/
private void extractJar(JarFile jarFile, File dstDir)
throws DeploymentException {
// Extract jar contents to a classpath location
JarInputStream jarIs = null;
try {
jarIs = new JarInputStream(new BufferedInputStream(
new FileInputStream(jarFile.getName())));
for (JarEntry entry = jarIs.getNextJarEntry(); jarIs.available() > 0
&& entry != null; entry = jarIs.getNextJarEntry()) {
logger.debug("jar entry = " + entry.getName());
if (entry.isDirectory()) {
// Create jar directories.
File dir = new File(dstDir, entry.getName());
if (!dir.exists()) {
if (!dir.mkdirs()) {
logger.debug("Failed to create directory "
+ dir.getAbsolutePath());
throw new IOException("Failed to create directory "
+ dir.getAbsolutePath());
}
} else
logger.debug("Created directory"
+ dir.getAbsolutePath());
} else // unzip files
{
File file = new File(dstDir, entry.getName());
File dir = file.getParentFile();
if (!dir.exists()) {
if (!dir.mkdirs()) {
logger.debug("Failed to create directory "
+ dir.getAbsolutePath());
throw new IOException("Failed to create directory "
+ dir.getAbsolutePath());
} else
logger.debug("Created directory"
+ dir.getAbsolutePath());
}
pipeStream(jarFile.getInputStream(entry),
new FileOutputStream(file));
}
}
} catch (Exception e) {
throw new DeploymentException("failed to extract jar file "
+ jarFile.getName());
} finally {
if (jarIs != null) {
try {
jarIs.close();
} catch (IOException e) {
logger.error("failed to close jar input stream", e);
}
}
}
}
private static byte buffer[] = new byte[8192];
/**
* Pipes data from the input stream into the output stream.
*
* @param is
* The InputStream where the data is coming from.
* @param os
* The OutputStream where the data is going to.
* @throws IOException
* if reading or writing the data fails.
*/
private void pipeStream(InputStream is, OutputStream os)
throws IOException {
synchronized (buffer) {
try {
for (int bytesRead = is.read(buffer); bytesRead != -1; bytesRead = is
.read(buffer))
os.write(buffer, 0, bytesRead);
is.close();
os.close();
} catch (IOException ioe) {
try {
is.close();
} catch (Exception ioexc) {/* do sth? */
}
try {
os.close();
} catch (Exception ioexc) {/* do sth? */
}
throw ioe;
}
}
}
}