org.jboss.as.ee.structure.EarStructureProcessor Maven / Gradle / Ivy
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.jboss.as.ee.structure;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.jboss.as.ee.logging.EeLogger;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.MountedDeploymentOverlay;
import org.jboss.as.server.deployment.SubDeploymentMarker;
import org.jboss.as.server.deployment.SubExplodedDeploymentMarker;
import org.jboss.as.server.deployment.module.ModuleRootMarker;
import org.jboss.as.server.deployment.module.MountHandle;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.as.server.deployment.module.TempFileProviderService;
import org.jboss.metadata.ear.spec.EarMetaData;
import org.jboss.metadata.ear.spec.ModuleMetaData;
import org.jboss.metadata.ear.spec.ModuleMetaData.ModuleType;
import org.jboss.vfs.VFS;
import org.jboss.vfs.VFSUtils;
import org.jboss.vfs.VirtualFile;
import org.jboss.vfs.VisitorAttributes;
import org.jboss.vfs.util.SuffixMatchFilter;
/**
* Deployment processor responsible for detecting EAR deployments and putting setting up the basic structure.
*
* @author John Bailey
* @author Stuart Douglas
*/
public class EarStructureProcessor implements DeploymentUnitProcessor {
private static final String JAR_EXTENSION = ".jar";
private static final String WAR_EXTENSION = ".war";
private static final String SAR_EXTENSION = ".sar";
private static final String RAR_EXTENSION = ".rar";
private static final List CHILD_ARCHIVE_EXTENSIONS = new ArrayList();
static {
CHILD_ARCHIVE_EXTENSIONS.add(JAR_EXTENSION);
CHILD_ARCHIVE_EXTENSIONS.add(WAR_EXTENSION);
CHILD_ARCHIVE_EXTENSIONS.add(SAR_EXTENSION);
CHILD_ARCHIVE_EXTENSIONS.add(RAR_EXTENSION);
}
private static final SuffixMatchFilter CHILD_ARCHIVE_FILTER = new SuffixMatchFilter(CHILD_ARCHIVE_EXTENSIONS, new VisitorAttributes() {
public boolean isLeavesOnly() {
return false;
}
});
private static final String DEFAULT_LIB_DIR = "lib";
public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
if (!DeploymentTypeMarker.isType(DeploymentType.EAR, deploymentUnit)) {
return;
}
final ResourceRoot deploymentRoot = phaseContext.getDeploymentUnit().getAttachment(Attachments.DEPLOYMENT_ROOT);
final VirtualFile virtualFile = deploymentRoot.getRoot();
// Make sure we don't index or add this as a module root
deploymentRoot.putAttachment(Attachments.INDEX_RESOURCE_ROOT, false);
ModuleRootMarker.mark(deploymentRoot, false);
String libDirName = DEFAULT_LIB_DIR;
//its possible that the ear metadata could come for jboss-app.xml
final boolean appXmlPresent = deploymentRoot.getRoot().getChild("META-INF/application.xml").exists();
final EarMetaData earMetaData = deploymentUnit.getAttachment(org.jboss.as.ee.structure.Attachments.EAR_METADATA);
if (earMetaData != null) {
final String xmlLibDirName = earMetaData.getLibraryDirectory();
if (xmlLibDirName != null) {
if (xmlLibDirName.length() == 1 && xmlLibDirName.charAt(0) == '/') {
throw EeLogger.ROOT_LOGGER.rootAsLibraryDirectory();
}
libDirName = xmlLibDirName;
}
}
// Process all the children
Map overlays = deploymentUnit.getAttachment(Attachments.DEPLOYMENT_OVERLAY_LOCATIONS);
try {
final VirtualFile libDir;
// process the lib directory
if (!libDirName.isEmpty()) {
libDir = virtualFile.getChild(libDirName);
if (libDir.exists()) {
List libArchives = libDir.getChildren(CHILD_ARCHIVE_FILTER);
for (final VirtualFile child : libArchives) {
String relativeName = child.getPathNameRelativeTo(deploymentRoot.getRoot());
MountedDeploymentOverlay overlay = overlays.get(relativeName);
final MountHandle mountHandle;
if (overlay != null) {
overlay.remountAsZip(false);
mountHandle = MountHandle.create(null);
} else {
final Closeable closable = child.isFile() ? mount(child, false) : null;
mountHandle = MountHandle.create(closable);
}
final ResourceRoot childResource = new ResourceRoot(child, mountHandle);
if (child.getName().toLowerCase(Locale.ENGLISH).endsWith(JAR_EXTENSION)) {
ModuleRootMarker.mark(childResource);
deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, childResource);
}
}
}
} else {
libDir = null;
}
// scan the ear looking for wars and jars
final List childArchives = new ArrayList(virtualFile.getChildren(new SuffixMatchFilter(
CHILD_ARCHIVE_EXTENSIONS, new VisitorAttributes() {
@Override
public boolean isLeavesOnly() {
return false;
}
@Override
public boolean isRecurse(VirtualFile file) {
// don't recurse into /lib
if (file.equals(libDir)) {
return false;
}
for (String suffix : CHILD_ARCHIVE_EXTENSIONS) {
if (file.getName().endsWith(suffix)) {
// don't recurse into sub deployments
return false;
}
}
return true;
}
})));
// if there is no application.xml then look in the ear root for modules
if (!appXmlPresent) {
for (final VirtualFile child : childArchives) {
final boolean isWarFile = child.getName().toLowerCase(Locale.ENGLISH).endsWith(WAR_EXTENSION);
final boolean isRarFile = child.getName().toLowerCase(Locale.ENGLISH).endsWith(RAR_EXTENSION);
this.createResourceRoot(deploymentUnit, child, isWarFile || isRarFile, isWarFile);
}
} else {
final Set subDeploymentFiles = new HashSet();
// otherwise read from application.xml
for (final ModuleMetaData module : earMetaData.getModules()) {
if(module.getFileName().endsWith(".xml")) {
throw EeLogger.ROOT_LOGGER.unsupportedModuleType(module.getFileName());
}
final VirtualFile moduleFile = virtualFile.getChild(module.getFileName());
if (!moduleFile.exists()) {
throw EeLogger.ROOT_LOGGER.cannotProcessEarModule(virtualFile, module.getFileName());
}
if (libDir != null) {
VirtualFile moduleParentFile = moduleFile.getParent();
if (moduleParentFile != null && libDir.equals(moduleParentFile)) {
throw EeLogger.ROOT_LOGGER.earModuleChildOfLibraryDirectory(libDirName, module.getFileName());
}
}
// maintain this in a collection of subdeployment virtual files, to be used later
subDeploymentFiles.add(moduleFile);
final boolean webArchive = module.getType() == ModuleType.Web;
final ResourceRoot childResource = this.createResourceRoot(deploymentUnit, moduleFile, true, webArchive);
childResource.putAttachment(org.jboss.as.ee.structure.Attachments.MODULE_META_DATA, module);
if (!webArchive) {
ModuleRootMarker.mark(childResource);
}
final String alternativeDD = module.getAlternativeDD();
if (alternativeDD != null && alternativeDD.trim().length() > 0) {
final VirtualFile alternateDeploymentDescriptor = deploymentRoot.getRoot().getChild(alternativeDD);
if (!alternateDeploymentDescriptor.exists()) {
throw EeLogger.ROOT_LOGGER.alternateDeploymentDescriptor(alternateDeploymentDescriptor, moduleFile);
}
switch (module.getType()) {
case Client:
childResource.putAttachment(org.jboss.as.ee.structure.Attachments.ALTERNATE_CLIENT_DEPLOYMENT_DESCRIPTOR, alternateDeploymentDescriptor);
break;
case Connector:
childResource.putAttachment(org.jboss.as.ee.structure.Attachments.ALTERNATE_CONNECTOR_DEPLOYMENT_DESCRIPTOR, alternateDeploymentDescriptor);
break;
case Ejb:
childResource.putAttachment(org.jboss.as.ee.structure.Attachments.ALTERNATE_EJB_DEPLOYMENT_DESCRIPTOR, alternateDeploymentDescriptor);
break;
case Web:
childResource.putAttachment(org.jboss.as.ee.structure.Attachments.ALTERNATE_WEB_DEPLOYMENT_DESCRIPTOR, alternateDeploymentDescriptor);
break;
case Service:
throw EeLogger.ROOT_LOGGER.unsupportedModuleType(module.getFileName());
}
}
}
// now check the rest of the archive for any other jar/sar files
for (final VirtualFile child : childArchives) {
if (subDeploymentFiles.contains(child)) {
continue;
}
final String fileName = child.getName().toLowerCase(Locale.ENGLISH);
if (fileName.endsWith(SAR_EXTENSION) || fileName.endsWith(JAR_EXTENSION)) {
this.createResourceRoot(deploymentUnit, child, false, false);
}
}
}
} catch (IOException e) {
throw EeLogger.ROOT_LOGGER.failedToProcessChild(e, virtualFile);
}
}
private static Closeable mount(VirtualFile moduleFile, boolean explode) throws IOException {
return explode ? VFS.mountZipExpanded(moduleFile, moduleFile, TempFileProviderService.provider())
: VFS.mountZip(moduleFile.getPhysicalFile(), moduleFile, TempFileProviderService.provider());
}
/**
* Creates a {@link ResourceRoot} for the passed {@link VirtualFile file} and adds it to the list of {@link ResourceRoot}s
* in the {@link DeploymentUnit deploymentUnit}
*
* @param deploymentUnit The deployment unit
* @param file The file for which the resource root will be created
* @param markAsSubDeployment If this is true, then the {@link ResourceRoot} that is created will be marked as a subdeployment
* through a call to {@link SubDeploymentMarker#mark(org.jboss.as.server.deployment.module.ResourceRoot)}
* @param explodeDuringMount If this is true then the {@link VirtualFile file} will be exploded during mount,
* while creating the {@link ResourceRoot}
* @return Returns the created {@link ResourceRoot}
* @throws IOException
*/
private ResourceRoot createResourceRoot(final DeploymentUnit deploymentUnit, final VirtualFile file, final boolean markAsSubDeployment, final boolean explodeDuringMount) throws IOException {
final boolean war = file.getName().toLowerCase(Locale.ENGLISH).endsWith(WAR_EXTENSION);
final Closeable closable = file.isFile() ? mount(file, explodeDuringMount) : exportExplodedWar(war, file, deploymentUnit);
final MountHandle mountHandle = MountHandle.create(closable);
final ResourceRoot resourceRoot = new ResourceRoot(file, mountHandle);
deploymentUnit.addToAttachmentList(Attachments.RESOURCE_ROOTS, resourceRoot);
if (markAsSubDeployment) {
SubDeploymentMarker.mark(resourceRoot);
}
if (war) {
resourceRoot.putAttachment(Attachments.INDEX_RESOURCE_ROOT, false);
SubExplodedDeploymentMarker.mark(resourceRoot);
}
return resourceRoot;
}
private Closeable exportExplodedWar(final boolean war, final VirtualFile file, final DeploymentUnit deploymentUnit) throws IOException {
if (isExplodedWarInArchiveEar(war, file, deploymentUnit)) {
File warContent = file.getPhysicalFile();
VFSUtils.recursiveCopy(file, warContent.getParentFile());
return VFS.mountReal(warContent, file);
}
return null;
}
private boolean isExplodedWarInArchiveEar(final boolean war, final VirtualFile file, final DeploymentUnit deploymentUnit) {
return war && !file.isFile() && deploymentUnit.hasAttachment(Attachments.DEPLOYMENT_CONTENTS) && deploymentUnit.getAttachment(Attachments.DEPLOYMENT_CONTENTS).isFile();
}
public void undeploy(DeploymentUnit context) {
final List children = context.removeAttachment(Attachments.RESOURCE_ROOTS);
if (children != null) {
for (ResourceRoot childRoot : children) {
VFSUtils.safeClose(childRoot.getMountHandle());
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy