/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.deployment.archivist;
import javax.xml.parsers.SAXParser;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.ZipEntry;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.enterprise.deploy.shared.ModuleType;
import com.sun.enterprise.deployment.archivist.ExtensionModuleArchivist;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchive;
import com.sun.enterprise.deployment.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.deploy.shared.InputJarArchive;
import com.sun.enterprise.deployment.deploy.shared.Archive;
import com.sun.enterprise.deployment.io.*;
import com.sun.enterprise.deployment.io.runtime.ApplicationRuntimeDDFile;
import com.sun.enterprise.deployment.interfaces.pluggable.ArchiveDescriptor;
import com.sun.enterprise.deployment.node.ApplicationNode;
import com.sun.enterprise.deployment.util.ApplicationValidator;
import com.sun.enterprise.deployment.util.ApplicationVisitor;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.deployment.util.ModuleDescriptor;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.xml.ConnectorTagNames;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.enterprise.util.shared.ArchivistUtils;
/**
* This class is responsible for handling application archive files
*
* @author Jerome Dochez
* @version
*/
public class ApplicationArchivist extends Archivist {
/**
* The application archivist handles J2EE Application archive file
*/
Application application = null;
/**
* The DeploymentDescriptorFile handlers we are delegating for XML i/o
*/
DeploymentDescriptorFile standardDD = new ApplicationDeploymentDescriptorFile();
/** resources... */
private static LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(ApplicationArchivist.class);
/** Creates new ApplicationArchivist */
public ApplicationArchivist() {
handleRuntimeInfo = true;
}
/**
* @return the module type handled by this archivist
* as defined in the application DTD
*
*/
public ModuleType getModuleType() {
return ModuleType.EAR;
}
/**
* Set the DOL descriptor for this Archivist, used by super classes
*/
public void setDescriptor(Descriptor descriptor) {
if (descriptor instanceof Application) {
application = (Application) descriptor;
} else {
throw new RuntimeException("Error setting descriptor in " + this);
}
}
/**
* writes the content of an archive to a JarFile
*
* @param the descriptors to use for writing
* @param the output stream to write to
*/
protected void writeContents(AbstractArchive in, AbstractArchive out) throws IOException {
Vector filesToSkip = new Vector();
if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
DOLUtils.getDefaultLogger().fine("Write " + out.getArchiveUri() + " with " + this);
}
// any files already written to the output should never be rewritten
for (Enumeration alreadyWritten = out.entries(); alreadyWritten.hasMoreElements();) {
String elementName = (String) alreadyWritten.nextElement();
filesToSkip.add(elementName);
}
// write this application .ear file contents...
for (Iterator modules = application.getModules();modules.hasNext();) {
ModuleDescriptor aModule = (ModuleDescriptor) modules.next();
Archivist subArchivist = getPluggableArchivists().getArchivistForType(aModule.getModuleType());
subArchivist.initializeContext(this);
subArchivist.setModuleDescriptor(aModule);
if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
DOLUtils.getDefaultLogger().info("Write " + aModule.getArchiveUri() + " with " + subArchivist);
}
if (aModule.getAlternateDescriptor()!=null) {
// no need to rewrite the original bundle since
// the deployment descriptors are saved at the application level
// so I don't put it in the list of files to be skipped and it will
// be copied as a library.
// but I need to save the deployment descriptor for this bundle
OutputStream os = out.putNextEntry(aModule.getAlternateDescriptor());
subArchivist.writeStandardDeploymentDescriptors(os);
out.closeEntry();
// now write runtime descriptors
if (isHandlingRuntimeInfo()) {
os = out.putNextEntry("sun-" + aModule.getAlternateDescriptor());
subArchivist.writeRuntimeDeploymentDescriptors(os);
out.closeEntry();
}
} else {
// Create a new jar file inside the application .ear
AbstractArchive internalJar = out.getEmbeddedArchive(aModule.getArchiveUri());
// we need to copy the old archive to a temp file so
// the save method can copy its original contents from
InputStream is = in.getEntry(aModule.getArchiveUri());
File tmpFile=null;
try {
if (in.supportsElementsOverwriting()) {
subArchivist.setArchiveUri(internalJar.getArchiveUri());
} else {
tmpFile = getTempFile(path);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmpFile));
ArchivistUtils.copy(is, bos);
// configure archivist
subArchivist.setArchiveUri(tmpFile.getAbsolutePath());
}
subArchivist.writeContents(internalJar);
out.closeEntry(internalJar);
} catch(IOException ioe) {
throw ioe;
} finally {
if (tmpFile!=null)
tmpFile.delete();
}
// no need to copy the bundle from the original jar file
filesToSkip.add(aModule.getArchiveUri());
}
}
// now write the old contents and new descriptors
super.writeContents(in, out, filesToSkip);
}
/**
* @return the descriptor associated with the archivist
*/
public Descriptor getDescriptor() {
return application;
}
/**
* @return a default BundleDescriptor for this archivist
*/
public Descriptor getDefaultBundleDescriptor() {
Application appDesc = new Application();
return appDesc;
}
/**
* open a new application archive file, read all the deployment descriptors
*
* @param path the file path for the J2EE Application archive
*/
public RootDeploymentDescriptor open(AbstractArchive appArchive)
throws IOException, SAXParseException {
setManifest(appArchive.getManifest());
// read the standard deployment descriptors
Descriptor appDesc = readStandardDeploymentDescriptor(appArchive);
setDescriptor(appDesc);
// Now that we have parsed the standard DD, let's read all the
// PersistenceUnits defined in the ear level.
readPersistenceDeploymentDescriptors(appArchive, getDescriptor());
// read the modules deployment descriptors
if (!readModulesDescriptors((Application) appDesc, appArchive))
return null;
// now read the runtime deployment descriptors
super.readRuntimeDeploymentDescriptor(appArchive, appDesc);
// validate...
if (classLoader!=null && isHandlingRuntimeInfo()) {
validate(null);
}
return (RootDeploymentDescriptor) appDesc;
}
/**
* read the modules deployment descriptor from this application object using
* the passed archive
* @param application containing the list of modules.
* @param appArchive containing the sub modules files.
* @return true if everything went fine
*/
public boolean readModulesDescriptors(Application app, AbstractArchive appArchive)
throws IOException, SAXParseException {
for (Iterator modules = app.getModules();modules.hasNext();) {
ModuleDescriptor aModule = (ModuleDescriptor) modules.next();
if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
DOLUtils.getDefaultLogger().fine("Opening sub-module " + aModule);
}
Descriptor descriptor = null;
ArchiveDescriptor archiveDesc = null;
Archivist newArchivist = null;
AbstractArchive embeddedArchive =
appArchive.getEmbeddedArchive(aModule.getArchiveUri());
if(ModuleType.WAR.equals(aModule.getModuleType())){
// Check if this is an extension module.If there is an IOException
// thrown then this means that we cannot determine the archivist
// using the archive, and also that this is not an extension
// module.
try {
newArchivist =
getPluggableArchivists().getArchivistForArchive(
embeddedArchive);
} catch (IOException ioe) {
// This has to be a Web Module now.
newArchivist = getPluggableArchivists().getArchivistForType(
aModule.getModuleType());
}
} else {
newArchivist = getPluggableArchivists().getArchivistForType(
aModule.getModuleType());
}
newArchivist.initializeContext(this);
newArchivist.setRuntimeXMLValidation(this.getRuntimeXMLValidation());
newArchivist.setRuntimeXMLValidationLevel(
this.getRuntimeXMLValidationLevel());
//AbstractArchive embeddedArchive = appArchive.getEmbeddedArchive(aModule.getArchiveUri());
if (aModule.getAlternateDescriptor()!=null) {
// the module use alternate deployement descriptor, ignore the
// DDs in the archive.
InputStream is = appArchive.getEntry(aModule.getAlternateDescriptor());
DeploymentDescriptorFile ddFile = newArchivist.getStandardDDFile();
ddFile.setXMLValidation(newArchivist.getXMLValidation());
ddFile.setXMLValidationLevel(newArchivist.getXMLValidationLevel());
if (appArchive.getArchiveUri()!=null) {
ddFile.setErrorReportingString(appArchive.getArchiveUri());
}
descriptor = ddFile.read(is);
is.close();
newArchivist.readWebServicesDescriptor(embeddedArchive, descriptor);
newArchivist.readPersistenceDeploymentDescriptors(embeddedArchive, descriptor);
newArchivist.postStandardDDsRead((RootDeploymentDescriptor) descriptor, embeddedArchive);
newArchivist.readAnnotations(embeddedArchive, (BundleDescriptor)descriptor);
newArchivist.postAnnotationProcess((BundleDescriptor)descriptor, embeddedArchive);
newArchivist.postOpen((RootDeploymentDescriptor) descriptor, embeddedArchive);
// now reads the runtime deployment descriptor...
if (isHandlingRuntimeInfo()) {
is = appArchive.getEntry("sun-" + aModule.getAlternateDescriptor());
if (is!=null) {
DeploymentDescriptorFile confDD =
newArchivist.getConfigurationDDFile();
confDD.setXMLValidation(
newArchivist.getRuntimeXMLValidation());
confDD.setXMLValidationLevel(
newArchivist.getRuntimeXMLValidationLevel());
if (appArchive.getArchiveUri()!=null) {
confDD.setErrorReportingString(
appArchive.getArchiveUri());
}
confDD.read(descriptor, is);
is.close();
newArchivist.postRuntimeDDsRead((RootDeploymentDescriptor)descriptor, embeddedArchive);
} else {
if (embeddedArchive!=null) {
newArchivist.readRuntimeDeploymentDescriptor(embeddedArchive,descriptor);
}
}
}
} else {
// open the subarchive to get the deployment descriptor...
if (embeddedArchive!=null) {
if(newArchivist instanceof ExtensionModuleArchivist) {
try{
((ExtensionModuleArchivist)newArchivist).
setJ2eeApplication(true);
archiveDesc =
((ExtensionModuleArchivist)newArchivist).openArchive(
embeddedArchive.getArchiveUri(),
null,
this.classLoader,
false);
} catch (Exception ex) {
//log this message
DOLUtils.getDefaultLogger().severe(
"Exception thrown while processing module "
+ aModule.getDescriptor().getModuleID()
+ ex.getMessage());
ex.printStackTrace();
}
} else {
descriptor = newArchivist.open(embeddedArchive);
}
} else {
DOLUtils.getDefaultLogger().info(localStrings.getLocalString(
"enterprise.deployment.cannotfindmodule",
"Cannot find module {0} in application bundle",
new Object[] {aModule.getArchiveUri()}));
return false;
}
}
if (embeddedArchive!=null) {
embeddedArchive.close();
}
if (descriptor != null && descriptor instanceof BundleDescriptor) {
aModule.setDescriptor((BundleDescriptor) descriptor);
((BundleDescriptor) descriptor).setApplication(app);
aModule.setManifest(newArchivist.getManifest());
} else if(archiveDesc != null &&
archiveDesc instanceof BundleDescriptor) {
aModule.setDescriptor((BundleDescriptor) archiveDesc);
((BundleDescriptor) archiveDesc).setApplication(app);
aModule.setManifest(newArchivist.getManifest());
} else {
// display a message only if we had a handle on the sub archive
if (embeddedArchive!=null) {
DOLUtils.getDefaultLogger().info(localStrings.getLocalString(
"enterprise.deployment.cannotreadDDs",
"Cannot read the Deployment Descriptors for module {0}",
new Object[] {aModule.getArchiveUri()}));
}
return false;
}
}
return true;
}
/**
* Read the runtime deployment descriptors (can contained in one or
* many file) set the corresponding information in the passed descriptor.
* By default, the runtime deployment descriptors are all contained in
* the xml file characterized with the path returned by
* @see getRuntimeDeploymentDescriptorPath
*
* @param the initialized deployment descriptor
*/
public void readRuntimeDeploymentDescriptor(AbstractArchive archive, Descriptor descriptor)
throws IOException, SAXParseException {
if (descriptor instanceof Application) {
Application application = (Application) descriptor;
// each modules first...
for (Iterator itr=application.getModules();itr.hasNext();) {
ModuleDescriptor md = (ModuleDescriptor) itr.next();
Archivist archivist = getPluggableArchivists().getArchivistForType(md.getModuleType());
archivist.initializeContext(this);
archivist.setRuntimeXMLValidation(
this.getRuntimeXMLValidation());
archivist.setRuntimeXMLValidationLevel(
this.getRuntimeXMLValidationLevel());
InputStream is = null;
if (md.getAlternateDescriptor()!=null) {
// we are using alternate deployment descriptors
is = archive.getEntry("sun-" + md.getAlternateDescriptor());
if (is!=null) {
DeploymentDescriptorFile confDD =
archivist.getConfigurationDDFile();
confDD.setXMLValidation(
archivist.getRuntimeXMLValidation());
confDD.setXMLValidationLevel(
archivist.getRuntimeXMLValidationLevel());
if (archive.getArchiveUri()!=null) {
confDD.setErrorReportingString(
archive.getArchiveUri());
}
confDD.read(md.getDescriptor(), is);
is.close();
}
}
// if is variable is null, it means that we are either
// not using alternate deployment descriptors or we could
// not find the appropriate sun-???.xml alternate DD.
if (is==null) {
AbstractArchive subArchive = archive.getEmbeddedArchive(md.getArchiveUri());
archivist.readRuntimeDeploymentDescriptor(subArchive, md.getDescriptor());
}
}
}
// for the application
super.readRuntimeDeploymentDescriptor(archive, descriptor);
}
/**
* Read the runtime deployment descriptors (can contained in one or
* many file) from a deployment plan archive, set the corresponding
* information in the passed descriptor.
*/
public void readRuntimeDDFromDeploymentPlan(
AbstractArchive planArchive, Descriptor descriptor)
throws IOException, SAXParseException {
if (planArchive == null) {
return;
}
// list of entries in the deployment plan
Vector dpEntries = new Vector();
for (Enumeration e = planArchive.entries(); e.hasMoreElements();) {
dpEntries.add(e.nextElement());
}
if (descriptor instanceof Application) {
Application application = (Application) descriptor;
//runtime deployment descriptor for the sub modules
for (Iterator itr = application.getModules(); itr.hasNext();) {
ModuleDescriptor moduleDesc = (ModuleDescriptor) itr.next();
Archivist subArchivist = ArchivistFactory.getArchivistForType(moduleDesc.getModuleType());
String archiveUri = moduleDesc.getArchiveUri();
String runtimeDDPath = subArchivist.getRuntimeDeploymentDescriptorPath();
if (runtimeDDPath!=null) {
String mangledName;
// the runtime deployment descriptor from the deployment file
mangledName = archiveUri + "."
+ runtimeDDPath.substring(runtimeDDPath.lastIndexOf('/')+1);
DOLUtils.getDefaultLogger().fine("mangledName is " + mangledName);
if (dpEntries.contains(mangledName)) {
subArchivist.readRuntimeDDFromDeploymentPlan(
mangledName, planArchive, moduleDesc.getDescriptor());
}
}
}
}
//for sun-application.xml
super.readRuntimeDDFromDeploymentPlan(planArchive, descriptor);
}
/**
* validates the DOL Objects associated with this archivist, usually
* it requires that a class loader being set on this archivist or passed
* as a parameter
*/
public void validate(ClassLoader aClassLoader) {
ClassLoader cl = aClassLoader;
if (cl==null) {
cl = classLoader;
}
if (cl==null) {
return;
}
application.setClassLoader(cl);
application.visit((ApplicationVisitor) new ApplicationValidator());
}
/**
* add a new module to this archivist
*
* @param path for the new module to be added
* @param set of library jars for this module
* @param external deployment descriptor to use instead of the
* the ones in the jar file.
*/
public ModuleDescriptor addArchive(String archivePath, Set libraryJars, String externalDD)
throws SAXParseException, IOException {
AbstractArchive newArchive = abstractArchiveFactory.openArchive(archivePath);
return addArchive(newArchive, libraryJars, externalDD);
}
/**
* add a new module to this archivist
*
* @param AbstractArchive for the new module to be added
* @param set of library jars for this module
* @param external deployment descriptor to use instead of the
* the ones in the jar file.
*/
public ModuleDescriptor addArchive(AbstractArchive newArchive, Set libraryJars, String externalDD)
throws SAXParseException, IOException {
// let's create a tmp file to store the new application .ear
File outputFile=null;
ModuleDescriptor newModule = null;
try {
outputFile = getTempFile(path);
AbstractArchive out = abstractArchiveFactory.createArchive(outputFile.getAbsolutePath());
// let's create a new module descriptor for this module
newModule = getModuleFor(out, newArchive, libraryJars, externalDD);
application.addModule(newModule);
// this should take care of writing the sub modules with the right
// manifests and deployment descriptors settings...
AbstractArchive in = abstractArchiveFactory.openArchive(path);
Vector filesToSkip = new Vector();
filesToSkip.add(newModule.getArchiveUri());
writeContents(in, out, filesToSkip);
in.close();
out.close();
// rename the tmp file
renameTmp(outputFile.getAbsolutePath(), path);
} finally {
if (outputFile!=null)
outputFile.delete();
}
return newModule;
}
/**
* creates a new module descriptor for a J2EE Archive to be added to the current
* application archive.
*
* @param abstract archive for the application archive file
* @param the archive file path to be added
* @param set of library jars to add to the classpath of this module
* @param optional external deployment descriptors
*
* @return an initialized ModuleDescriptor for the new module
*/
private ModuleDescriptor getModuleFor(AbstractArchive out, AbstractArchive newArchive, Set libraryJars, String externalDD)
throws SAXParseException, IOException {
// Let's get an archivist for the new archive to be added and delegate
Archivist newArchivist = getPluggableArchivists().getArchivistForArchive(newArchive);
newArchivist.initializeContext(this);
newArchivist.setArchiveUri(newArchive.getArchiveUri());
ModuleDescriptor newModule = newArchivist.addToArchive(this, externalDD);
newArchivist.prepareForInclusion(out);
// now update the manifest for this archivist... and writes the libray jars
// to our application archive...
if (libraryJars!=null && !libraryJars.isEmpty()) {
StringBuffer classPath = new StringBuffer();
for (Iterator e = libraryJars.iterator(); e.hasNext();) {
String libUri = (String) e.next();
File libFile = new File(libUri);
if (libFile.exists()) {
classPath.append(libUri);
classPath.append(' ');
addFileToArchive(out, libFile.getAbsolutePath(), libUri);
} else {
throw new FileNotFoundException("Library file " + libFile.getAbsolutePath() + " not found");
}
}
Manifest manifest = newArchivist.getManifest();
if (manifest==null) {
manifest = new Manifest();
newArchivist.setManifest(manifest);
}
Attributes atts = manifest.getMainAttributes();
atts.putValue(Attributes.Name.CLASS_PATH.toString(), classPath.toString());
}
// now include the new module in the output archive
AbstractArchive newModuleJar = out.getEmbeddedArchive(newModule.getArchiveUri());
// write and close
newArchivist.writeContents(newModuleJar);
out.closeEntry(newModuleJar);
return newModule;
}
/**
* @return the DeploymentDescriptorFile responsible for handling
* standard deployment descriptor
*/
public DeploymentDescriptorFile getStandardDDFile() {
return standardDD;
}
/**
* @return if exists the DeploymentDescriptorFile responsible for
* handling the configuration deployment descriptors
*/
public DeploymentDescriptorFile getConfigurationDDFile() {
return new ApplicationRuntimeDDFile();
}
/**
* Perform Optional packages dependencies checking on an archive
*/
public boolean performOptionalPkgDependenciesCheck(AbstractArchive archive) throws IOException {
if (!super.performOptionalPkgDependenciesCheck(archive))
return false;
// now check sub modules
if (application==null) {
throw new IOException("Application object not set on archivist");
}
Iterator<ModuleDescriptor> modulesItr = application.getModules();
boolean returnValue = true;
while(modulesItr.hasNext()) {
ModuleDescriptor md = modulesItr.next();
AbstractArchive sub = archive.getEmbeddedArchive(md.getArchiveUri());
if (sub!=null) {
Archivist subArchivist = getPluggableArchivists().getArchivistForType(md.getModuleType());
if (!subArchivist.performOptionalPkgDependenciesCheck(sub))
returnValue = false;
}
}
return returnValue;
}
/**
* Copy this archivist to a new abstract archive
* @param out the new archive to use to copy our contents into
*/
public void copyInto(AbstractArchive source, AbstractArchive target) throws IOException {
try {
Application a = (Application) readStandardDeploymentDescriptor(source);
} catch(SAXParseException spe) {
spe.printStackTrace();
DOLUtils.getDefaultLogger().log(Level.SEVERE, "enterprise.deployment.backend.fileCopyFailure");
}
}
/**
* Copy this archivist to a new abstract archive
* @param a the deployment descriptor for an application
* @param source the source archive
* @param target the target archive
*/
public void copyInto(Application a, AbstractArchive source, AbstractArchive target) throws IOException {
copyInto(a, source, target, true);
}
/**
* Copy this archivist to a new abstract archive
* @param a the deployment descriptor for an application
* @param source the source archive
* @param target the target archive
* @param overwriteManifest if true, the manifest in source archive overwrites the one in target
*/
public void copyInto(Application a, AbstractArchive source,
AbstractArchive target, boolean overwriteManifest)
throws IOException {
Vector entriesAdded = new Vector();
for (Iterator modules = a.getModules();modules.hasNext();) {
ModuleDescriptor aModule = (ModuleDescriptor) modules.next();
entriesAdded.add(aModule.getArchiveUri());
AbstractArchive subSource = source.getEmbeddedArchive(aModule.getArchiveUri());
AbstractArchive subTarget = target.getEmbeddedArchive(aModule.getArchiveUri());
Archivist newArchivist = getPluggableArchivists().getArchivistForType(aModule.getModuleType());
newArchivist.copyInto(subSource, subTarget, overwriteManifest);
target.closeEntry(subTarget);
String subModulePath = subSource.getArchiveUri();
if (subModulePath.startsWith(source.getArchiveUri())) {
subModulePath = subModulePath.substring(source.getArchiveUri().length()+File.separator.length());
for (Enumeration subEntries = subSource.entries();subEntries.hasMoreElements();) {
String anEntry = (String) subEntries.nextElement();
entriesAdded.add(subModulePath + "/" + anEntry);
}
}
subSource.close();
}
super.copyInto(source, target, entriesAdded, overwriteManifest);
}
/**
* Open a jar file and return an application object for the modules contained
* in the archive. If the archive is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param the archive file
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(File jarFile)
throws IOException, SAXParseException {
return openArchive(jarFile, false);
}
/**
* Open a jar file and return an application object for the modules contained
* in the archive/directory. If the archive/directory is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param archivist to use to open the archive file
* @param the archive file
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(Archivist archivist, File jarFile, boolean handleRuntimeInfo)
throws IOException, SAXParseException{
// never read the runtime deployment descriptor before the
// module type is found and the application object created
AbstractArchive originalArchive = null;
if(jarFile.isDirectory())
{
originalArchive = new FileArchive();
((FileArchive)originalArchive).open(jarFile.getAbsolutePath());
}
else
{
originalArchive = new InputJarArchive();
((InputJarArchive)originalArchive).open(jarFile.getAbsolutePath());
}
Application application = openArchive(archivist, originalArchive, handleRuntimeInfo);
originalArchive.close();
return application;
}
/**
* Open a jar file and return an application object for the modules contained
* in the archive. If the archive is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param archivist to use to open the archive file
* @param the archive abstraction
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(Archivist archivist, AbstractArchive in, boolean handleRuntimeInfo)
throws IOException, SAXParseException {
return openArchive(in.getArchiveUri(), archivist, in, handleRuntimeInfo);
}
/**
* Open a jar file and return an application object for the modules contained
* in the archive. If the archive is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param the application moduleID
* @param archivist to use to open the archive file
* @param the archive abstraction
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(String appName, Archivist archivist, AbstractArchive in, boolean handleRuntimeInfo)
throws IOException, SAXParseException {
// we are not reading the runtime deployment descriptor now...
archivist.setHandleRuntimeInfo(false);
Descriptor descriptor = archivist.open(in);
Application application;
if (descriptor instanceof Application) {
application = (Application) descriptor;
application.setRegistrationName(appName);
} else {
BundleDescriptor aBundle = (BundleDescriptor) descriptor;
if (aBundle==null) {
logger.log(Level.SEVERE, localStrings.getLocalString(
"enterprise.deployment.cannotreadDDs",
"Cannot read the Deployment Descriptors for module {0}",
new Object[] { in.getArchiveUri() }));
return null;
}
ModuleDescriptor newModule = archivist.createModuleDescriptor(aBundle);
newModule.setArchiveUri(in.getArchiveUri());
application = Application.createApplication(appName, newModule);
}
// now read the runtime deployment descriptor
if (handleRuntimeInfo) {
// now read the runtime deployment descriptors from the original jar file
archivist.setHandleRuntimeInfo(true);
archivist.readRuntimeDeploymentDescriptor(in, descriptor);
}
// validate
archivist.validate(null);
return application;
}
/**
* Open a jar file with the Archivists define by the
* pluggable archivists instance and return an application
* object for the modules contained in the archive.
* If the archive is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param the archive file
* @param the instance of PluggableArchivists responsible for
* instanciating the archivists.
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(File jarFile,
PluggableArchivists pa, boolean handleRuntimeInfo)
throws IOException, SAXParseException {
Archivist archivist = pa.getArchivistForArchive(jarFile);
return openArchive(archivist, jarFile, handleRuntimeInfo);
}
/**
* Open a jar file with the default Archivists and return an application
* object for the modules contained in the archive.
* If the archive is a standalone module, this API will
* create an empty application and add the standalone module to it
*
* @param the archive file
* @param true to read configuration deployment descriptors
* @return the application object
*/
public static Application openArchive(File jarFile, boolean handleRuntimeInfo)
throws IOException, SAXParseException {
Archivist archivist = ArchivistFactory.getArchivistForArchive(jarFile);
return openArchive(archivist, jarFile, handleRuntimeInfo);
}
/**
* @return the application name from an application .ear file
* @param the .ear file
*/
static public String getApplicationName(File jarFile) throws IOException {
if (!jarFile.exists()) {
throw new IOException(localStrings.getLocalString(
"enterprise.deployment.exceptionjarfiledoesn'texist",
"{0} does not exist", new Object[] {jarFile}));
}
/*
*Add finally clause containing explicit close of jar file.
*/
JarFile jar = null;
try {
jar = new JarFile(jarFile);
ApplicationDeploymentDescriptorFile node = new ApplicationDeploymentDescriptorFile();
node.setXMLValidation(false);
ZipEntry deploymentEntry = jar.getEntry(node.getDeploymentDescriptorPath());
if (deploymentEntry != null) {
try {
Application application = (Application) node.read(jar.getInputStream(deploymentEntry));
return application.getDisplayName();
} catch (Exception pe) {
pe.printStackTrace();
}
}
} finally {
if (jar != null) {
jar.close();
}
}
return null;
}
/**
* This method will be invoked if and only if the following is true:
* 1. directory deployment with neither standard nor runtime DD
* 2. JSR88 DeploymentManager.distribute using InputStream with neither
* standard nor runtime DD
* <p>
* Note that we will only venture a guess for case 1. JSR88 deployment
* of an application (ear) using InputStream without any deployment
* descriptor will NOT be supported at this time.
*/
protected boolean postHandles(AbstractArchive abstractArchive)
throws IOException {
// Only try to make a guess if the archive is a directory
// We will try to conclude if a directory represents an application
// by looking at if it contains any Java EE modules.
// We are supporting directory names with both "_suffix" and ".suffix".
File file = new File(abstractArchive.getArchiveUri());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File content : files) {
if (content.isDirectory()) {
String dirPath = content.getPath();
if (dirPath.endsWith("_war")
|| dirPath.endsWith(".war")
|| dirPath.endsWith("_jar")
|| dirPath.endsWith(".jar")
|| dirPath.endsWith("_rar")
|| dirPath.endsWith(".rar")) {
return true;
}
}
}
}
return false;
}
protected String getArchiveExtension() {
return APPLICATION_EXTENSION;
}
@Override public void readPersistenceDeploymentDescriptors(
AbstractArchive appArchive, Descriptor descriptor) throws IOException, SAXParseException {
if(logger.isLoggable(Level.FINE)) {
logger.logp(Level.FINE, "ApplicationArchivist",
"readPersistenceDeploymentDescriptors", "archive = {0}",
appArchive.getURI());
}
Application application = Application.class.cast(descriptor);
Map<String, Archive> subArchives = new HashMap<String, Archive>();
try{
Enumeration entries = appArchive.entries();
while(entries.hasMoreElements()){
String entry = String.class.cast(entries.nextElement());
// at ear level only jar files can be root of PU.
if (entry.endsWith(".jar")) {
Iterator modules = application.getModules();
boolean belongsToSomeModule = false;
while(modules.hasNext()){
// We need to do the following check because we don't want
// to process files like foo_war/WEB-INF/lib/a.jar.
// So the following check ensures that
// we have found a .jar embedded in ear file which is
// neither an appclient jar nor an ejb jar and nor is it
// part of a rar or war.
String explodedModuleURI = FileUtils.makeFriendlyFileName(
ModuleDescriptor.class.cast(modules.next()).
getArchiveUri()) + "/"; // add '/' to indicate its a directory
if(entry.startsWith(explodedModuleURI)){
belongsToSomeModule = true;
break; // no need to see if it belongs to some other module
}
}
if(!belongsToSomeModule) {
subArchives.put(entry, appArchive.getSubArchive(entry));
}
}
}
for(Map.Entry<String, Archive> pathToArchiveEntry : subArchives.entrySet()) {
readPersistenceDeploymentDescriptor(pathToArchiveEntry.getValue(), pathToArchiveEntry.getKey(), descriptor);
}
}finally{
for(Archive subArchive : subArchives.values()) {
subArchive.close();
}
}
}
/**
* This is a helper method.
* This method is needed because we sometimes have to read PU descriptors
* from the original app exploded dir as opposed to generated dir
* because generated XML do not contain any information about PUs.
* This method also handles the case where application object is virtual,
* (a virtual application represents a standalone module deployment object).
* @param archive from where persistence descriptors will be read from.
* @param application the application object whose persistence units
* will be read. This method will read all the persistence units
* recurssively and register at appropriate level.
* @throws IOException
* @throws SAXParseException
*/
public static void readPersistenceDeploymentDescriptorsRecursively(
AbstractArchive archive, Application application) throws IOException,
SAXParseException {
if(!application.isVirtual()) {
ApplicationArchivist appArchivist = new ApplicationArchivist();
appArchivist.readPersistenceDeploymentDescriptors(archive, application);
for(Iterator modules = application.getModules(); modules.hasNext();) {
final ModuleDescriptor moduleDescriptor =
ModuleDescriptor.class.cast(modules.next());
Archivist moduleArchivist = ArchivistFactory.
getArchivistForType(moduleDescriptor.getModuleType());
AbstractArchive moduleArchive = archive.getEmbeddedArchive(
moduleDescriptor.getArchiveUri());
try{
moduleArchivist.readPersistenceDeploymentDescriptors(
moduleArchive, moduleDescriptor.getDescriptor());
} finally {
moduleArchive.close();
}
}
} else {
// it's a standalone war/jar/rar etc.
final ModuleDescriptor module =
ModuleDescriptor.class.cast(application.getModules().next());
Archivist archivist =
ArchivistFactory.getArchivistForType(module.getModuleType());
archivist.readPersistenceDeploymentDescriptors(
archive, module.getDescriptor());
}
}
public boolean hasDescriptors(AbstractArchive embeddedArchive) {
File webInfEntry = new File(embeddedArchive.getArchiveUri(), "WEB-INF");
File[] fileList = webInfEntry.listFiles();
if(fileList != null) {
for(int i=0; i < fileList.length; i++) {
if(fileList[i].getName().endsWith(".xml")) {
return true;
}
}
return false;
}
return false;
}
// for test purposes
public static void main(String args[]) {
if (args.length==0) {
return;
} else {
String fileName = args[0];
try {
Archivist archivist = ArchivistFactory.getArchivistForArchive(fileName);
archivist.setHandleRuntimeInfo(true);
archivist.setArchiveUri(fileName);
archivist.setXMLValidation(true);
archivist.setXMLValidationLevel("full");
Descriptor descriptor = ApplicationArchivist.openArchive(archivist, new File(fileName), true);
if (args.length >1 && args[1]!=null) {
archivist.write(args[1]);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
}