/*
* 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 static com.sun.enterprise.deployment.io.DescriptorConstants.PERSISTENCE_DD_ENTRY;
import java.io.*;
import java.util.jar.*;
import java.util.jar.Attributes.Name;
import java.util.zip.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.SAXParseException;
import org.xml.sax.InputSource;
import javax.enterprise.deploy.shared.ModuleType;
import com.sun.enterprise.deployment.annotation.AnnotatedElementHandler;
import com.sun.enterprise.deployment.annotation.AnnotationProcessor;
import com.sun.enterprise.deployment.annotation.AnnotationProcessorException;
import com.sun.enterprise.deployment.annotation.ErrorHandler;
import com.sun.enterprise.deployment.annotation.ResultType;
import com.sun.enterprise.deployment.annotation.factory.AnnotatedElementHandlerFactory;
import com.sun.enterprise.deployment.annotation.factory.ScannerFactory;
import com.sun.enterprise.deployment.annotation.factory.SJSASFactory;
import com.sun.enterprise.deployment.annotation.impl.AnnotationUtils;
import com.sun.enterprise.deployment.annotation.impl.DefaultErrorHandler;
import com.sun.enterprise.deployment.annotation.ProcessingContext;
import com.sun.enterprise.deployment.annotation.ProcessingResult;
import com.sun.enterprise.deployment.annotation.Scanner;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchive;
import com.sun.enterprise.deployment.deploy.shared.AbstractArchiveFactory;
import com.sun.enterprise.deployment.deploy.shared.JarArchiveFactory;
import com.sun.enterprise.deployment.deploy.shared.Archive;
import com.sun.enterprise.deployment.io.*;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.util.DescriptorVisitor;
import com.sun.enterprise.deployment.util.DOLUtils;
import com.sun.enterprise.deployment.backend.OptionalPkgDependency;
import com.sun.enterprise.deployment.backend.IASDeploymentException;
import com.sun.enterprise.deployment.util.ModuleDescriptor;
import com.sun.enterprise.deployment.util.TracerVisitor;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.util.shared.ArchivistUtils;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.logging.LogDomains;
/**
* This abstract class contains all common behaviour for Achivisits. Archivists
* classes are responsible for reading and writing correct J2EE Archives
*
* @author Jerome Dochez
* @version
*/
public abstract class Archivist {
protected static final Logger logger =
LogDomains.getLogger(LogDomains.DPL_LOGGER);
static {
AnnotationUtils.setLogger(logger);
AnnotationUtils.setLoggerTarget("*");
}
public static final String MANIFEST_VERSION_VALUE = "1.0";
// the path for the underlying archive file
protected String path;
// should we read or save the runtime info.
protected boolean handleRuntimeInfo = true;
// default should be false in production
protected boolean annotationProcessingRequested = false;
// attributes of this archive
protected Manifest manifest;
// the archive abstraction we use to access the physical storage
protected AbstractArchiveFactory abstractArchiveFactory= null;
/**
* plugable archivist factory for creating sub modules archivists
*/
protected PluggableArchivists pa = null;
// resources...
private static final LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(Archivist.class);
// class loader to use when validating the DOL
protected ClassLoader classLoader=null;
// boolean for XML validation
private boolean isValidatingXML = true;
// boolean for runtime XML validation
private boolean isValidatingRuntimeXML = false;
// xml validation error level reporting/recovering
private String validationLevel = "parsing";
// runtime xml validation error level reporting/recovering
private String runtimeValidationLevel = "parsing";
// error handler for annotation processing
private ErrorHandler annotationErrorHandler = null;
private static final String WSDL = ".wsdl";
private static final String XML = ".xml";
private static final String XSD = ".xsd";
protected static final String APPLICATION_EXTENSION = ".ear";
protected static final String APPCLIENT_EXTENSION = ".jar";
protected static final String WEB_EXTENSION = ".war";
protected static final String EJB_EXTENSION = ".jar";
protected static final String CONNECTOR_EXTENSION = ".rar";
//Used to detect the uploaded files which always end in ".tmp"
protected static final String UPLOAD_EXTENSION = ".tmp";
private static final String PROCESS_ANNOTATION_FOR_OLD_DD =
"process.annotation.for.old.dd";
private static final boolean processAnnotationForOldDD =
Boolean.getBoolean(PROCESS_ANNOTATION_FOR_OLD_DD);
/** Creates new Archivist */
public Archivist() {
// by default we are dealing with jar files, can be changed with
// setAbstractArchiveFactory
abstractArchiveFactory = new JarArchiveFactory();
annotationErrorHandler = new DefaultErrorHandler();
}
/**
* initializes this instance from another archivist, this is used
* to transfer contextual information between archivists, for
* example whether we should handle runtime information and such
*/
protected void initializeContext(Archivist other) {
handleRuntimeInfo = other.isHandlingRuntimeInfo();
annotationProcessingRequested = other.isAnnotationProcessingRequested();
isValidatingXML = other.isValidatingXML;
validationLevel = other.validationLevel;
abstractArchiveFactory = other.getAbstractArchiveFactory();
classLoader = other.classLoader;
annotationErrorHandler = other.annotationErrorHandler;
}
/**
* sets the abstract archive factory associated with this archivist.
* @param the new factory for creating abstract archives
*/
public void setAbstractArchiveFactory(AbstractArchiveFactory aa) {
abstractArchiveFactory = aa;
}
/**
* @return the currently associated abstract archive factory
*/
public AbstractArchiveFactory getAbstractArchiveFactory() {
return abstractArchiveFactory;
}
/**
* Open a new archive file, read the XML descriptor and set the constructed
* DOL descriptor instance
*
* @param path the archive file path
* @return the deployment descriptor for this archive
*/
public RootDeploymentDescriptor open(AbstractArchive archive)
throws IOException, SAXParseException {
setManifest(archive.getManifest());
RootDeploymentDescriptor descriptor = readDeploymentDescriptors(archive);
if (descriptor!=null){
postOpen(descriptor, archive);
}
return descriptor;
}
/**
* Open a new archive file, read the XML descriptor and set the constructed
* DOL descriptor instance
*
* @param path the archive file path
* @return the deployment descriptor for this archive
*/
public RootDeploymentDescriptor open(String path)
throws IOException, SAXParseException {
this.path = path;
File file = new File(path);
if (!file.exists()) {
throw new FileNotFoundException(path);
}
AbstractArchive abstractArchive = abstractArchiveFactory.openArchive(path);
RootDeploymentDescriptor descriptor = open(abstractArchive);
abstractArchive.close();
// attempt validation
validate(null);
return descriptor;
}
/**
* open a new archive file using a file descriptor
* @param the archive to open
*/
public RootDeploymentDescriptor open(File file) throws IOException, SAXParseException {
return open(file.getAbsolutePath());
}
/**
* perform any action after all standard DDs is read
* @param the deployment descriptor for the module
* @param the module archive
*/
protected void postStandardDDsRead(RootDeploymentDescriptor descriptor,
AbstractArchive archive) throws IOException {
}
/**
* perform any action after annotation processed
* @param the deployment descriptor for the module
* @param the module archive
*/
protected void postAnnotationProcess(RootDeploymentDescriptor descriptor,
AbstractArchive archive) throws IOException {
}
/**
* perform any action after all runtime DDs read
* @param the deployment descriptor for the module
* @param the module archive
*/
protected void postRuntimeDDsRead(RootDeploymentDescriptor descriptor,
AbstractArchive archive) throws IOException {
}
/**
* perform any post deployment descriptor reading action
*
* @param the deployment descriptor for the module
* @param the module archive
*/
protected void postOpen(RootDeploymentDescriptor descriptor, AbstractArchive archive)
throws IOException
{
}
/**
* Read the standard deployment descriptors (can contained in one or
* many file) and return the corresponding initialized descriptor instance.
* By default, the standard deployment descriptors are all contained in
* the xml file characterized with the path returned by
* @see getDeploymentDescriptorPath
*
* @return the initialized descriptor
*/
public RootDeploymentDescriptor readDeploymentDescriptors(AbstractArchive abstractArchive)
throws IOException, SAXParseException {
// read the standard deployment descriptors
BundleDescriptor descriptor = (BundleDescriptor)readStandardDeploymentDescriptor(abstractArchive);
ModuleDescriptor newModule = createModuleDescriptor(descriptor);
newModule.setArchiveUri(abstractArchive.getArchiveUri());
readWebServicesDescriptor(abstractArchive, descriptor);
// Now that we have parsed the standard DD, let's read all the
// PersistenceUnits defined in this archive as well.
readPersistenceDeploymentDescriptors(abstractArchive, getDescriptor());
postStandardDDsRead(descriptor, abstractArchive);
readAnnotations(abstractArchive, descriptor);
postAnnotationProcess(descriptor, abstractArchive);
// now read the runtime deployment descriptors
readRuntimeDeploymentDescriptor(abstractArchive, descriptor);
postRuntimeDDsRead(descriptor, abstractArchive);
return descriptor;
}
protected void readAnnotations(AbstractArchive abstractArchive, BundleDescriptor descriptor) throws IOException {
// if the system property is set to process annotation for pre-JavaEE5
// DD, the semantics of isFull flag is: full attribute is set to
// true in DD. Otherwise the semantics is full attribute set to
// true or it is pre-JavaEE5 DD.
boolean isFull = false;
if (processAnnotationForOldDD) {
isFull = descriptor.isFullAttribute();
} else {
isFull = descriptor.isFullFlag();
}
// only process annotation when these two requirements satisfied:
// 1. It is not a full deployment descriptor
// 2. It is called through dynamic deployment
if (!isFull && annotationProcessingRequested
&& classLoader != null) {
try {
ProcessingResult result = processAnnotations(descriptor, abstractArchive);
if (result != null &&
ResultType.FAILED.equals(result.getOverallResult())){
DOLUtils.getDefaultLogger().severe(localStrings.getLocalString(
"enterprise.deployment.archivist.annotationprocessingfailed",
"Annotations processing failed for {0}",
new Object[]{abstractArchive.getArchiveUri()}));
}
//XXX for backward compatible in case of having cci impl in EJB
} catch(NoClassDefFoundError err) {
if (DOLUtils.getDefaultLogger().isLoggable(Level.WARNING)) {
DOLUtils.getDefaultLogger().warning(
"Error in annotation processing: " + err);
}
} catch(AnnotationProcessorException ex) {
DOLUtils.getDefaultLogger().severe(ex.getMessage());
DOLUtils.getDefaultLogger().log(Level.FINE, ex.getMessage(), ex);
throw new IllegalStateException(ex);
}
} else if (DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
DOLUtils.getDefaultLogger().fine("Annotation is not processed for this archive.");
}
}
/**
* This method is responsible for reading of any persistence DD defined
* in the SCOPE of this descriptor. Note, it only reads persistence DD
* defined in the current SCOPE.
* @param archive is the archive that will be scanned for persistence DD
* @param descriptor which will be populated with information read from
* persistence DD.
* @throws IOException
* @throws SAXParseException
*/
public void readPersistenceDeploymentDescriptors(
AbstractArchive archive, Descriptor descriptor)
throws IOException, SAXParseException {
// This is a no-op implementation as opposed to an abstract method
// because it gets called from ConnectorArchivist.
}
/**
* Process annotations in a bundle descriptor, the annoation processing
* is dependent on the type of descriptor being passed.
*/
public ProcessingResult processAnnotations(BundleDescriptor bundleDesc,
AbstractArchive abstractArchive)
throws AnnotationProcessorException, IOException {
AnnotatedElementHandler aeHandler =
AnnotatedElementHandlerFactory.createAnnotatedElementHandler(
bundleDesc);
if (aeHandler == null) {
return null;
}
Scanner scanner = ScannerFactory.createScanner(
bundleDesc, this, abstractArchive, classLoader);
if (!scanner.getElements().isEmpty()) {
if (bundleDesc.isDDWithNoAnnotationAllowed()) {
// if we come into this block, it means an old version
// of deployment descriptor has annotation which is not correct
// throw exception in this case
String ddName =
getStandardDDFile().getDeploymentDescriptorPath();
String explodedArchiveName =
new File(abstractArchive.getArchiveUri()).getName();
String archiveName = FileUtils.revertFriendlyFilenameExtension(
explodedArchiveName);
throw new AnnotationProcessorException(
localStrings.getLocalString(
"enterprise.deployment.oldDDwithAnnotation",
"{0} in archive {1} is of version {2}, which cannot support annotations in an application. Please upgrade the deployment descriptor to be a version supported by Java EE 5.0 (or later).",
new Object[] {ddName, archiveName, bundleDesc.getSpecVersion()}));
}
AnnotationProcessor ap = SJSASFactory.getAnnotationProcessor();
ProcessingContext ctx = ap.createContext();
if (annotationErrorHandler != null) {
ctx.setErrorHandler(annotationErrorHandler);
}
ctx.setProcessingInput(scanner);
ctx.pushHandler(aeHandler);
// Make sure there is a classloader available on the descriptor
// during annotation processing.
ClassLoader originalBundleClassLoader = null;
try {
originalBundleClassLoader = bundleDesc.getClassLoader();
} catch(Exception e) {
// getClassLoader can throw exception if not available
}
// Only set classloader if it's not already set.
if( originalBundleClassLoader == null ) {
bundleDesc.setClassLoader(classLoader);
}
try {
return ap.process(ctx);
} finally {
if( originalBundleClassLoader == null ) {
bundleDesc.setClassLoader(null);
}
}
} else {
bundleDesc.setFullFlag(true);
}
return null;
}
/**
* Read the standard deployment descriptors (can contained in one or
* many file) and return the corresponding initialized descriptor instance.
* By default, the standard deployment descriptors are all contained in
* the xml file characterized with the path returned by
* @see getDeploymentDescriptorPath
*
* @return the initialized descriptor
*/
public Descriptor readStandardDeploymentDescriptor(AbstractArchive abstractArchive)
throws IOException, SAXParseException {
InputStream is = null;
try {
is = abstractArchive.getEntry(getStandardDDFile().getDeploymentDescriptorPath());
if (is!=null) {
DeploymentDescriptorFile ddFile = getStandardDDFile();
ddFile.setXMLValidation(getXMLValidation());
ddFile.setXMLValidationLevel(validationLevel);
if (abstractArchive.getArchiveUri()!=null) {
ddFile.setErrorReportingString(abstractArchive.getArchiveUri());
}
Descriptor result = ddFile.read(is);
return result;
} else {
/*
*Always return at least the default, because the info is needed
*when an app is loaded during a server restart and there might not
*be a physical descriptor file.
*/
return getDefaultBundleDescriptor();
}
} finally {
if (is != null) {
is.close();
}
}
}
/**
* 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 abstractArchive, Descriptor descriptor)
throws IOException, SAXParseException {
// if we are not supposed to handle runtime info, just pass
String ddFileEntryName = getRuntimeDeploymentDescriptorPath();
if (!isHandlingRuntimeInfo() || ddFileEntryName==null) {
return;
}
InputStream is = null;
try {
// apply the runtime settings if any
is = abstractArchive.getEntry(ddFileEntryName);
DeploymentDescriptorFile confDD = getConfigurationDDFile();
if (abstractArchive.getArchiveUri()!=null) {
confDD.setErrorReportingString(abstractArchive.getArchiveUri());
}
if (is!=null && confDD!=null) {
confDD.setXMLValidation(getRuntimeXMLValidation());
confDD.setXMLValidationLevel(runtimeValidationLevel);
confDD.read(descriptor, is);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) {
}
}
}
}
/**
* 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 we are not supposed to handle runtime info, just pass
String runtimeDDPath = getRuntimeDeploymentDescriptorPath();
if (runtimeDDPath==null || 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());
}
String entry = runtimeDDPath.substring(runtimeDDPath.lastIndexOf('/')+1);
if (dpEntries.contains(entry)) {
readRuntimeDDFromDeploymentPlan(entry, planArchive, 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.
*/
protected void readRuntimeDDFromDeploymentPlan(
String entry, AbstractArchive planArchive, Descriptor descriptor)
throws IOException, SAXParseException {
InputStream is = null;
try {
is = planArchive.getEntry(entry);
DeploymentDescriptorFile confDD = getConfigurationDDFile();
if (is!=null && confDD!=null) {
if (planArchive.getArchiveUri()!=null) {
confDD.setErrorReportingString(planArchive.getArchiveUri());
}
confDD.setXMLValidation(getXMLValidation());
confDD.read(descriptor, is);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ioe) { }
}
}
}
/**
* Read the (optional) webservices.xml descriptor in this module.
* Only applicable for web and ejb modules.
*/
protected void readWebServicesDescriptor(AbstractArchive abstractArchive,
Descriptor descriptor)
throws IOException, SAXParseException {
DeploymentDescriptorFile confDD = getWebServicesDDFile(descriptor);
if (abstractArchive.getArchiveUri()!=null) {
confDD.setErrorReportingString(abstractArchive.getArchiveUri());
}
InputStream is = null;
try {
is = abstractArchive.getEntry(confDD.getDeploymentDescriptorPath());
if (is != null) {
confDD.setXMLValidation(getXMLValidation());
confDD.setXMLValidationLevel(validationLevel);
confDD.read(descriptor, is);
}
} finally {
if (is != null) {
is.close();
}
}
}
/*
* write the J2EE module represented by this instance to a new
* J2EE archive file
*
*/
public void write() throws IOException {
write(path);
}
/**
* saves the archive
*
* @param outPath the file to use
*/
public void write(String outPath) throws IOException {
AbstractArchive in = abstractArchiveFactory.openArchive(path);
write(in, outPath);
in.close();
}
/**
* save the archive
*
* @param input abstract archive to copy old elements from
* @param outPath the file to use
*/
public void write(AbstractArchive in, String outPath) throws IOException {
AbstractArchive oldArchive=null;
try {
oldArchive = abstractArchiveFactory.openArchive(outPath);
} catch (IOException ioe) {
// there could be many reasons why we cannot open this archive,
// we should continue
}
AbstractArchive out = null;
BufferedOutputStream bos=null;
try {
String tmpName = null;
if (oldArchive!=null && oldArchive.exists() &&
!oldArchive.supportsElementsOverwriting()) {
// this is a rewrite, get a temp file name...
// I am creating a tmp file just to get a name
File outputFile = getTempFile(outPath);
tmpName = outputFile.getAbsolutePath();
outputFile.delete();
out = abstractArchiveFactory.createArchive(tmpName);
oldArchive.close();
} else {
out = abstractArchiveFactory.createArchive(outPath);
}
// write archivist content
writeContents(in, out);
out.close();
in.close();
// if we were using a temp file, time to rewrite the original
if (tmpName!=null) {
AbstractArchive finalArchive = abstractArchiveFactory.openArchive(outPath);
finalArchive.delete();
AbstractArchive tmpArchive = abstractArchiveFactory.openArchive(tmpName);
tmpArchive.renameTo(outPath);
}
} catch (IOException ioe) {
// cleanup
if (out!=null) {
try {
out.close();
//out.delete(); <-- OutputJarArchive.delete isn't supported.
} catch (IOException outIoe) {
// ignore exceptions here, otherwise this will end up masking the real
// IOException in 'ioe'.
}
}
// propagate exception
throw ioe;
}
}
public void write(AbstractArchive in, AbstractArchive out) throws IOException {
writeContents(in,out);
}
/**
* writes the content of an archive to a JarFile
*
* @param the jar output stream to write to
*/
protected void writeContents(AbstractArchive out) throws IOException {
AbstractArchive in = abstractArchiveFactory.openArchive(path);
writeContents(in, out);
in.close();
}
/**
* writes the content of an archive to a JarFile
*
* @param the jar output stream to write to
*/
protected void writeContents(AbstractArchive in, AbstractArchive out) throws IOException {
writeContents(in, out, null);
}
/**
* writes the content of an archive to a JarFile
*
* @param the input archive
* @param the archive output stream to write to
* @param the files to not write from the original archive
*/
protected void writeContents(AbstractArchive in, AbstractArchive out, Vector entriesToSkip)
throws IOException {
// Copy original jarFile elements
if (in!=null && in.exists()) {
if (entriesToSkip==null) {
entriesToSkip = getListOfFilesToSkip();
} else {
entriesToSkip.addAll(getListOfFilesToSkip());
}
copyJarElements(in, out, entriesToSkip);
}
// now the deployment descriptors
writeDeploymentDescriptors(out);
// manifest file
if (manifest!=null) {
OutputStream os = out.putNextEntry(JarFile.MANIFEST_NAME);
manifest.write(new DataOutputStream(os));
out.closeEntry();
}
}
/**
* writes the deployment descriptors (standard and runtime)
* to a JarFile using the right deployment descriptor path
*
* @out the abstract archive file to write to
*/
public void writeDeploymentDescriptors(AbstractArchive out) throws IOException {
// Standard DDs
writeStandardDeploymentDescriptors(out);
// the rest...
writeExtraDeploymentDescriptors(out);
}
/**
* writes the standard deployment descriptors to an abstract archive
*
* @param the abstract archive to write to
*/
public void writeStandardDeploymentDescriptors(AbstractArchive out) throws IOException {
OutputStream os = out.putNextEntry(getDeploymentDescriptorPath());
writeStandardDeploymentDescriptors(os);
out.closeEntry();
Descriptor desc = getDescriptor();
// only bundle descriptor can have web services
if (desc instanceof BundleDescriptor) {
writeWebServicesDescriptors((BundleDescriptor) desc, out);
}
}
/**
* writes the runtime deployment descriptors to an abstract archive
*
* @param the abstract archive
*/
public void writeRuntimeDeploymentDescriptors(AbstractArchive out) throws IOException {
Descriptor desc = getDescriptor();
// Runtime DDs
if (isHandlingRuntimeInfo()) {
DeploymentDescriptorFile confDD = getConfigurationDDFile();
if (confDD!=null) {
OutputStream os = out.putNextEntry(getRuntimeDeploymentDescriptorPath());
confDD.write(desc, os);
out.closeEntry();
}
}
}
/**
* write all extra deployment descriptors (like cmp related and runtime dds)
*
* @out the abstract archive file to write to
*/
protected void writeExtraDeploymentDescriptors(AbstractArchive out) throws IOException {
writeRuntimeDeploymentDescriptors(out);
}
/**
* writes the standard deployment descriptor to an output stream
*
* @param output stream to write out the descriptors
*/
public void writeStandardDeploymentDescriptors(OutputStream os) throws IOException {
getStandardDDFile().write(getDescriptor(), os);
}
/**
* writes de configuration deployment descriptor to a new XML file
*
* @param output stream to write the configuration deployment descriptors
*/
public void writeRuntimeDeploymentDescriptors(OutputStream os) throws IOException {
DeploymentDescriptorFile confDD = getConfigurationDDFile();
if (confDD!=null) {
confDD.write(getDescriptor(), os);
}
}
/**
* @return whether this archivist should write a web services
* deployment descriptor
*/
protected void writeWebServicesDescriptors(BundleDescriptor desc, AbstractArchive out)
throws IOException {
if (desc.hasWebServices()) {
DeploymentDescriptorFile webServicesDD = getWebServicesDDFile(desc);
OutputStream os = out.putNextEntry(webServicesDD.getDeploymentDescriptorPath());
webServicesDD.write(desc, os);
out.closeEntry();
}
}
/**
* @return the location of the DeploymentDescriptor file for a
* particular type of J2EE Archive
*/
public String getDeploymentDescriptorPath() {
return getStandardDDFile().getDeploymentDescriptorPath();
}
/**
* @return the location of the web services related deployment
* descriptor file inside this archive or null if this archive
* does not support webservices implementation.
*/
public String getWebServicesDeploymentDescriptorPath() {
return null;
}
/**
* @return the location of the runtime deployment descriptor file
* for a particular type of J2EE Archive
*/
public String getRuntimeDeploymentDescriptorPath() {
DeploymentDescriptorFile ddFile = getConfigurationDDFile();
if (ddFile!=null) {
return ddFile.getDeploymentDescriptorPath();
} else {
return null;
}
}
/**
* @return true if the passed AbstractArchive contains runtime
* deployment descriptors information
*/
public boolean containsRuntimeDeploymentDescriptors(AbstractArchive in) {
String ddFileName = getRuntimeDeploymentDescriptorPath();
if (ddFileName==null) {
return false;
}
for (Enumeration e = in.entries();e.hasMoreElements();) {
String entryName = (String) e.nextElement();
if (entryName.equals(ddFileName)) {
return true;
}
}
// we iterated all archive elements, could not find our
// runtime DD file, it's a pure j2ee archive
return false;
}
/**
* Archivists can be associated with a module descriptor once the
* XML deployment descriptors have been read and the DOL tree
* is initialized.
*/
public void setModuleDescriptor(ModuleDescriptor module) {
setDescriptor(module.getDescriptor());
setManifest(module.getManifest());
}
/**
* Perform Optional packages dependencies checking on an archive
*/
public boolean performOptionalPkgDependenciesCheck(AbstractArchive archive) throws IOException {
boolean dependenciesSatisfied = true;
Manifest m = archive.getManifest();
if (m!=null) {
dependenciesSatisfied=OptionalPkgDependency.optionalPkgDependencyLogic(m, archive.getArchiveUri());
}
// now check my libraries.
Vector<String> libs = getLibraries(archive);
if (libs!=null) {
for (String libUri : libs) {
JarInputStream jis=null;
try {
jis = new JarInputStream(archive.getEntry(libUri));
m = jis.getManifest();
if (m!=null) {
if (!OptionalPkgDependency.optionalPkgDependencyLogic(m, libUri)) {
dependenciesSatisfied=false;
}
}
} finally {
if (jis!=null)
jis.close();
}
}
}
return dependenciesSatisfied;
}
/**
* Archivist read XML deployment descriptors and keep the
* parsed result in the DOL descriptor instances. Sets the descriptor
* for a particular Archivist type
*/
public abstract void setDescriptor(Descriptor descriptor);
/**
* @return the Descriptor for this archvist
*/
public abstract Descriptor getDescriptor();
/**
* @return the module type handled by this archivist
* as defined in the application DTD
*
*/
public abstract ModuleType getModuleType();
/**
* @return the DeploymentDescriptorFile responsible for handling
* standard deployment descriptor
*/
public abstract DeploymentDescriptorFile getStandardDDFile();
/**
* @return if exists the DeploymentDescriptorFile responsible for
* handling the configuration deployment descriptors
*/
public abstract DeploymentDescriptorFile getConfigurationDDFile();
/**
* @return a default BundleDescriptor for this archivist
*/
public abstract Descriptor getDefaultBundleDescriptor();
/**
* @param arch archive for this module. can be null. only used for reading
* @return the DeploymentDescriptorFile responsible for
* handling the web services deployment descriptors
*/
public DeploymentDescriptorFile getWebServicesDDFile(Descriptor desc) {
return new WebServicesDeploymentDescriptorFile(desc);
}
/**
*@return The archive extension handled by a specific archivist
*/
protected abstract String getArchiveExtension();
/**
* @return true if the archivist is handling the provided archive
*/
protected abstract boolean postHandles(AbstractArchive abstractArchive) throws IOException;
public boolean hasStandardDeploymentDescriptor(AbstractArchive archive)
throws IOException {
if (getStandardDDFile() != null) {
InputStream stIs = archive.getEntry(getDeploymentDescriptorPath());
if (stIs != null) {
stIs.close();
return true;
}
}
return false;
}
public boolean hasRuntimeDeploymentDescriptor(AbstractArchive archive)
throws IOException {
//check null: since .par archive does not have runtime dds
if (getConfigurationDDFile() != null) {
InputStream runIs = archive.getEntry(
getConfigurationDDFile().getDeploymentDescriptorPath());
if (runIs != null) {
runIs.close();
return true;
}
}
return false;
}
/**
* creates a new module descriptor for this archivist
* @return the new module descriptor
*/
public ModuleDescriptor createModuleDescriptor(BundleDescriptor descriptor) {
ModuleDescriptor newModule = new ModuleDescriptor();
newModule.setModuleType(getModuleType());
newModule.setDescriptor(descriptor);
setDescriptor(descriptor);
return newModule;
}
/**
* print the current descriptor associated with this archivist
*/
public void printDescriptor() {
getDescriptor().visit((DescriptorVisitor) new TracerVisitor());
}
/**
* sets if this archivist saves the runtime info
*
* @param true to save the runtime info
*/
public void setHandleRuntimeInfo(boolean handleRuntimeInfo) {
this.handleRuntimeInfo = handleRuntimeInfo;
}
/**
* @return true if this archivist will save the runtime info
*/
public boolean isHandlingRuntimeInfo() {
return handleRuntimeInfo;
}
/**
* sets if this archivist process annotation
*
* @param true to process annotation
*/
public void setAnnotationProcessingRequested(
boolean annotationProcessingRequested) {
this.annotationProcessingRequested = annotationProcessingRequested;
}
/**
* @return true if this archivist will process annotation
*/
public boolean isAnnotationProcessingRequested() {
return annotationProcessingRequested;
}
/**
* sets annotation ErrorHandler for this archivist
*
* @param annotationErrorHandler
*/
public void setAnnotationErrorHandler(ErrorHandler annotationErrorHandler) {
this.annotationErrorHandler = annotationErrorHandler;
}
/**
* @return annotation ErrorHandler of this archivist
*/
public ErrorHandler getAnnotationErrorHandler() {
return annotationErrorHandler;
}
/**
* sets the manifest file for this archive
*
* @param manifest to use at saving time
*/
public void setManifest(Manifest m) {
manifest = m;
}
/**
* @return the manifest file for this archive
*/
public Manifest getManifest() {
return manifest;
}
/**
* Sets the class-path for this archive
*
* @param the new class-path
*/
public void setClassPath(String newClassPath) {
if (manifest==null) {
manifest = new Manifest();
}
Attributes atts = manifest.getMainAttributes();
atts.putValue(Attributes.Name.CLASS_PATH.toString(), newClassPath);
}
/**
* @return the class-path as set in the manifest associated
* with the archive
*/
public String getClassPath() {
if (manifest==null) {
return null;
}
Attributes atts = manifest.getMainAttributes();
return atts.getValue(Attributes.Name.CLASS_PATH);
}
/**
* @return a list of libraries included in the archivist
*/
public Vector getLibraries(AbstractArchive archive) {
Enumeration<String> entries = archive.entries();
if (entries==null)
return null;
Vector libs = new Vector();
while (entries.hasMoreElements()) {
String entryName = entries.nextElement();
if (entryName.indexOf('/')!=-1) {
continue; // not on the top level
}
if (entryName.endsWith(".jar")) {
libs.add(entryName);
}
}
return libs;
}
/**
* @returns an entry name unique amongst names in this archive based on the triel name.
*/
protected String getUniqueEntryFilenameFor(AbstractArchive archive, String trialName) throws IOException {
Vector entriesNames = new Vector();
Enumeration e = archive.entries();
while (e!=null && e.hasMoreElements()) {
entriesNames.add(e.nextElement());
}
return Descriptor.createUniqueFilenameAmongst(trialName, entriesNames);
}
/**
* Add this archive to an application archivist
*
* @param application archive to add itself to
* @param library jars for this archive
* @param external deployment descriptor path
*/
protected ModuleDescriptor addToArchive(ApplicationArchivist appArch, String externalDD)
throws IOException, SAXParseException {
AbstractArchive archiveToBeAdded = abstractArchiveFactory.openArchive(path);
File archiveFile = new File(path);
AbstractArchive appArchive = abstractArchiveFactory.openArchive(appArch.getArchiveUri());
String archiveName = getUniqueEntryFilenameFor(appArchive, archiveFile.getName());
appArchive.close();
Descriptor descriptor = null;
if (externalDD != null && !"".equals(externalDD)) {
File externalDescriptorFile = new File(externalDD);
if (externalDescriptorFile.exists()) {
FileInputStream fis = new FileInputStream(externalDescriptorFile);
try {
DeploymentDescriptorFile ddf = getStandardDDFile();
descriptor = ddf.read(fis);
} catch(SAXParseException pe) {
archiveToBeAdded.close();
pe.printStackTrace();
// propagate
throw pe;
}
}
}
if (descriptor==null) {
// We get the deployment descriptors, including maybe the
// runtime deployment descriptors
descriptor = open(archiveToBeAdded);
}
archiveToBeAdded.close();
// Create a new module descriptor for this new module
if (descriptor instanceof BundleDescriptor) {
ModuleDescriptor newModule = new ModuleDescriptor();
newModule.setArchiveUri(archiveName);
newModule.setModuleType(getModuleType());
newModule.setDescriptor((BundleDescriptor) descriptor);
newModule.setManifest(getManifest());
if (externalDD != null && !"".equals(externalDD)) {
newModule.setAlternateDescriptor(externalDD);
}
return newModule;
} else {
return null;
}
}
/**
* prepare an archivist for inclusion in a application archive.
*
* @param archive file where this archivist will be saved
*/
protected void prepareForInclusion(AbstractArchive out) throws IOException {
}
public void saveRuntimeInfo(File output) throws IOException {
// if output file is null, we overwrite the current archive...
File outputFile = output;
if (outputFile==null) {
outputFile = getTempFile(path);
}
// copy all entries from source to target except the
// runtime descriptor file
AbstractArchive out = abstractArchiveFactory.createArchive(outputFile.getAbsolutePath());
AbstractArchive in = abstractArchiveFactory.openArchive(path);
Vector skipFiles = new Vector();
skipFiles.add(getRuntimeDeploymentDescriptorPath());
copyInto(in, out, skipFiles);
in.close();
// now save the runtime deployment descriptor...
OutputStream os = out.putNextEntry(getRuntimeDeploymentDescriptorPath());
writeRuntimeDeploymentDescriptors(os);
out.closeEntry();
out.close();
// if we overwrote the old archive, need to rename the tmp now
if (output==null) {
AbstractArchive finalArchive = abstractArchiveFactory.openArchive(path);
finalArchive.delete();
AbstractArchive tmpArchive = abstractArchiveFactory.openArchive(outputFile.getAbsolutePath());
tmpArchive.renameTo(path);
}
}
/**
* apply runtimne info to this archive descriptors and saves it
*/
public void applyRuntimeInfo(File runtimeDD, File output) throws IOException, SAXParseException {
// update the runtime info
getConfigurationDDFile().read(getDescriptor(), new FileInputStream(runtimeDD));
// save the runtime info...
saveRuntimeInfo(output);
}
/**
* utility method to get a tmp file in the current user directory of the provided
* directory
*
* @param File file or directory to use as temp location (use parent directory
* if a file is provided)
*/
protected static File getTempFile(String fileOrDirPath) throws IOException {
if (fileOrDirPath!=null) {
return getTempFile(new File(fileOrDirPath));
} else {
return getTempFile((File) null);
}
}
/**
* @return the list of files that should not be copied from the old archive
* when a save is performed.
*/
public Vector getListOfFilesToSkip() {
Vector filesToSkip = new Vector();
filesToSkip.add(getDeploymentDescriptorPath());
if (manifest!=null) {
filesToSkip.add(JarFile.MANIFEST_NAME);
}
if (getRuntimeDeploymentDescriptorPath()!=null) {
filesToSkip.add(getRuntimeDeploymentDescriptorPath());
}
// Can't depend on having a descriptor, so skip all possible
// web service deployment descriptor paths.
filesToSkip.addAll(WebServicesDeploymentDescriptorFile.
getAllDescriptorPaths());
return filesToSkip;
}
/**
* utility method to get a tmp file in the current user directory of the provided
* directory
*
* @param File file or directory to use as temp location (use parent directory
* if a file is provided)
*/
protected static File getTempFile(File fileOrDir) throws IOException {
File dir = null;
if (fileOrDir==null) {
dir=new File(System.getProperty("user.dir"));
} else {
if (!fileOrDir.isDirectory()) {
dir = fileOrDir.getParentFile();
if (dir==null) {
dir=new File(System.getProperty("user.dir"));
}
} else {
dir = fileOrDir;
}
}
return File.createTempFile("tmp", ".jar", dir);
}
/**
* add a file to an output abstract archive
*
* @param archive abstraction to use when adding the file
* @param path to the file to add
* @param entryName the entry name in the archive
*/
protected static void addFileToArchive(AbstractArchive archive, String filePath, String entryName)
throws IOException {
FileInputStream is = new FileInputStream(new File(filePath));
OutputStream os = archive.putNextEntry(entryName);
ArchivistUtils.copyWithoutClose(is, os);
is.close();
archive.closeEntry();
}
/**
* copy all contents of a jar file to a new jar file except
* for all the deployment descriptors files
*
* @param input jar file
* @param output jar file
* @param vector of entry name to not copy from to source jar file
*/
protected void copyJarElements(AbstractArchive in, AbstractArchive out, Vector ignoreList)
throws IOException {
Enumeration entries = in.entries();
// we need to add the list of existing entries in the output
// archive to the list of files to ignore to avoid any collision
for (Enumeration outEntriesItr = out.entries();outEntriesItr.hasMoreElements();) {
if (ignoreList==null) {
ignoreList = new Vector();
}
ignoreList.add(outEntriesItr.nextElement());
}
if (entries!=null) {
for (;entries.hasMoreElements();) {
String anEntry = (String) entries.nextElement();
if (ignoreList==null || !ignoreList.contains(anEntry)) {
InputStream is = in.getEntry(anEntry);
OutputStream os = out.putNextEntry(anEntry);
ArchivistUtils.copyWithoutClose(is, os);
is.close();
out.closeEntry();
}
}
}
}
/**
* rename a tmp file
*
* @param old name
* @param new name
*/
protected boolean renameTmp(String from, String to) throws IOException {
AbstractArchive finalArchive = abstractArchiveFactory.openArchive(to);
finalArchive.delete();
AbstractArchive tmpArchive = abstractArchiveFactory.openArchive(from);
boolean success = tmpArchive.renameTo(to);
if (!success) {
throw new IOException("Error renaming JAR");
}
return success;
}
/**
* Sets the path for this archivist's archive file
*/
public void setArchiveUri(String path) {
this.path = path;
}
/**
* @return the path for this archivist's archive file
*/
public String getArchiveUri() {
return path;
}
/**
* Sets the classloader for this archivist
* @param class loader
*/
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
/**
* Turn on or off the XML Validation for all standard deployment
* descriptors loading
* @param true to turn on XML validation
*/
public void setXMLValidation(boolean validate) {
isValidatingXML=validate;
}
/**
* @return true if the Deployment Descriptors XML will be validated
* while reading.
*/
public boolean getXMLValidation() {
return isValidatingXML;
}
/**
* Turn on or off the XML Validation for runtime deployment
* descriptors loading
* @param true to turn on XML validation
*/
public void setRuntimeXMLValidation(boolean validate) {
isValidatingRuntimeXML = validate;
}
/**
* @return true if the runtime XML will be validated
* while reading.
*/
public boolean getRuntimeXMLValidation() {
return isValidatingRuntimeXML;
}
/**
* Sets the xml validation error reporting/recovering level.
* The reporting level is active only when xml validation is
* turned on @see setXMLValidation.
* so far, two values can be passed, medium which reports the
* xml validation and continue and full which reports the
* xml validation and stop the xml parsing.
*/
public void setXMLValidationLevel(String level) {
validationLevel = level;
}
/**
* @return the xml validation reporting level
*/
public String getXMLValidationLevel() {
return validationLevel;
}
/**
* Sets the runtime xml validation error reporting/recovering level.
* The reporting level is active only when xml validation is
* turned on @see setXMLValidation.
* so far, two values can be passed, medium which reports the
* xml validation and continue and full which reports the
* xml validation and stop the xml parsing.
*/
public void setRuntimeXMLValidationLevel(String level) {
runtimeValidationLevel = level;
}
/**
* @return the runtime xml validation reporting level
*/
public String getRuntimeXMLValidationLevel() {
return runtimeValidationLevel;
}
/**
* 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) {
}
/**
* Copy this archivist to a new abstract archive
* @param out the new archive to use to copy our contents into
*/
public void copyInto(AbstractArchive target) throws IOException {
AbstractArchive source = abstractArchiveFactory.openArchive(path);
copyInto(source, target);
}
/**
* Copy source archivist to a target abstract archive. By default,
* every entry in source archive will be copied to the target archive,
* including the manifest of the source archive.
* @param source the source archive to copy from
* @param target the target archive to copy to
* @param entriesToSkip the entries that will be skipped by target archive
*/
public void copyInto(AbstractArchive source, AbstractArchive target) throws IOException {
copyInto(source, target, null, true);
}
/**
* Copy source archivist to a target abstract archive. By default,
* every entry in source archive will be copied to the target archive.
* @param source the source archive to copy from
* @param target the target archive to copy to
* @param overwriteManifest if true, the manifest in source archive
* overwrites the one in target archive
*/
public void copyInto(AbstractArchive source, AbstractArchive target, boolean overwriteManifest) throws IOException {
copyInto(source, target, null, overwriteManifest);
}
/**
* Copy source archivist to a target abstract archive. By default, the manifest
* in source archive overwrites the one in target archive.
* @param source the source archive to copy from
* @param target the target archive to copy to
* @param entriesToSkip the entries that will be skipped by target archive
*/
public void copyInto(AbstractArchive source, AbstractArchive target, Vector entriesToSkip)
throws IOException {
copyInto(source, target, entriesToSkip, true);
}
/**
* Copy this archivist to a new abstract archive
* @param source the source archive to copy from
* @param target the target archive to copy to
* @param entriesToSkip the entries that will be skipped by target archive
* @param overwriteManifest if true, the manifest in source archive
* overwrites the one in target archive
*/
public void copyInto(AbstractArchive source, AbstractArchive target,
Vector entriesToSkip, boolean overwriteManifest)
throws IOException {
copyJarElements(source, target, entriesToSkip);
if (overwriteManifest) {
Manifest m = source.getManifest();
if (m != null) {
OutputStream os = target.putNextEntry(JarFile.MANIFEST_NAME);
m.write(os);
target.closeEntry();
}
}
}
/**
* extract a entry of this archive to a file
* @param the entry name
* @param the file to copy the entry into
*/
public void extractEntry(String entryName, File out) throws IOException {
AbstractArchive archive = abstractArchiveFactory.openArchive(path);
InputStream is = archive.getEntry(entryName);
OutputStream os = new BufferedOutputStream(new FileOutputStream(out));
ArchivistUtils.copy(new BufferedInputStream(is), os);
archive.close();
}
/**
* Sets the pluggable archivist factory for this instance
*/
public void setPluggableArchivists(PluggableArchivists pa) {
this.pa = pa;
}
/**
* @return the pluggable archivist factory
*/
public PluggableArchivists getPluggableArchivists() {
if (pa==null) {
return ArchivistFactory.getPluggableArchivists();
} else {
return pa;
}
}
public static void copyAnEntry(AbstractArchive in,
AbstractArchive out, String entryName) throws IOException {
InputStream is = null;
InputStream is2 = null;
try {
is = in.getEntry(entryName);
is2 = out.getEntry(entryName);
if (is != null && is2 == null) {
OutputStream os = out.putNextEntry(entryName);
ArchivistUtils.copyWithoutClose(is, os);
}
} finally {
/*
*Close any streams that were opened.
*/
if (is != null) {
is.close();
}
if (is2 != null) {
is2.close();
}
out.closeEntry();
}
}
public void copyStandardDeploymentDescriptors(AbstractArchive in,
AbstractArchive out) throws IOException {
String entryName = getDeploymentDescriptorPath();
copyAnEntry(in, out, entryName);
Descriptor desc = getDescriptor();
// only bundle descriptor can have web services
if (desc instanceof BundleDescriptor) {
BundleDescriptor desc2 = (BundleDescriptor)desc;
if (desc2.hasWebServices()) {
DeploymentDescriptorFile webServicesDD =
getWebServicesDDFile((BundleDescriptor)desc2);
String anEntry = webServicesDD.getDeploymentDescriptorPath();
copyAnEntry(in, out, anEntry);
}
}
}
// copy wsdl and mapping files etc
public static void copyExtraElements(AbstractArchive in,
AbstractArchive out) throws IOException {
Enumeration entries = in.entries();
if (entries!=null) {
for (;entries.hasMoreElements();) {
String anEntry = (String) entries.nextElement();
if(anEntry.endsWith(PERSISTENCE_DD_ENTRY)) {
// Don't copy persistence.xml file because they are some times
// bundled inside war/WEB-INF/lib/*.jar and hence we always
// read them from exploded directory.
// see Integration Notice #80587
continue;
}
if (anEntry.indexOf(WSDL) != -1 ||
anEntry.indexOf(XML) != -1 ||
anEntry.indexOf(XSD) != -1) {
copyAnEntry(in, out, anEntry);
}
}
}
}
protected void readPersistenceDeploymentDescriptor(
Archive subArchive, String puRoot, Descriptor descriptor)
throws IOException, SAXParseException {
final String subArchiveURI = AbstractArchive.class.cast(subArchive).getArchiveUri();
if (logger.isLoggable(Level.FINE)) {
logger.logp(Level.FINE, "Archivist",
"readPersistenceDeploymentDescriptor",
"PURoot = [{0}] subArchive = {1}",
new Object[]{puRoot, subArchiveURI});
}
final RootDeploymentDescriptor rootDD =
RootDeploymentDescriptor.class.cast(descriptor);
if (rootDD.getPersistenceUnitsDescriptor(puRoot) != null) {
if (logger.isLoggable(Level.FINE)) {
logger.logp(Level.FINE, "Archivist",
"readPersistenceDeploymentDescriptor",
"PU has been already read for = {0}",
subArchiveURI);
}
return;
}
PersistenceDeploymentDescriptorFile persistenceDeploymentDescriptorFile
= new PersistenceDeploymentDescriptorFile();
persistenceDeploymentDescriptorFile.setErrorReportingString(
subArchiveURI.toString());
persistenceDeploymentDescriptorFile.setXMLValidation(getXMLValidation());
persistenceDeploymentDescriptorFile.setXMLValidationLevel(
getXMLValidationLevel());
InputStream is = subArchive.getEntry(
persistenceDeploymentDescriptorFile.getDeploymentDescriptorPath());
if (is == null) {
if (logger.isLoggable(Level.FINE)) {
logger.logp(Level.FINE, "Archivist",
"readPersistenceDeploymentDescriptor",
"{0} does not contain {1}, so it is not a PU Root.",
new Object[]{subArchiveURI,
persistenceDeploymentDescriptorFile.getDeploymentDescriptorPath()});
}
return;
}
try {
PersistenceUnitsDescriptor persistenceUnitsDescriptor =
PersistenceUnitsDescriptor.class.cast(
persistenceDeploymentDescriptorFile.read(rootDD, is));
rootDD.addPersistenceUnitsDescriptor(puRoot,
persistenceUnitsDescriptor);
} finally {
is.close();
}
}
protected boolean handles(AbstractArchive archive) throws IOException {
return hasStandardDeploymentDescriptor(archive) ||
hasRuntimeDeploymentDescriptor(archive);
}
}