From dbd83d688403f4c1aa9e277b64ba8714a2c2146d Mon Sep 17 00:00:00 2001 From: Arjan Tijms Date: Tue, 31 May 2022 15:58:07 +0200 Subject: [PATCH 1/2] Support scanning applibs Refactoring first: * Renaming variables * Formatting * Simplifying logic * Etc Signed-off-by: Arjan Tijms --- .../enterprise/deployment/util/DOLUtils.java | 40 +- .../org/glassfish/weld/DeploymentImpl.java | 25 +- .../v3/server/ApplicationLifecycle.java | 199 +++--- .../server/ReadableArchiveScannerAdapter.java | 104 ++- .../deploy/shared/ArchiveFactory.java | 148 ++-- .../enterprise/deploy/shared/FileArchive.java | 671 +++++++++--------- .../deploy/shared/InputJarArchive.java | 593 ++++++++-------- .../deployment/deploy/shared/JarArchive.java | 56 +- .../common/DeploymentContextImpl.java | 513 ++++++------- .../deployment/common/DeploymentUtils.java | 301 ++++---- .../common/InstalledLibrariesResolver.java | 342 ++++----- .../loader/util/ASClassLoaderUtil.java | 426 +++++------ 12 files changed, 1676 insertions(+), 1742 deletions(-) diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/util/DOLUtils.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/util/DOLUtils.java index 8d153edefc5..3748f94c037 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/util/DOLUtils.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/util/DOLUtils.java @@ -17,6 +17,11 @@ package com.sun.enterprise.deployment.util; +import static com.sun.enterprise.deployment.deploy.shared.Util.toURI; +import static java.util.Collections.emptyList; +import static org.glassfish.deployment.common.DeploymentUtils.getManifestLibraries; +import static org.glassfish.loader.util.ASClassLoaderUtil.getAppLibDirLibrariesAsList; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -25,7 +30,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Hashtable; import java.util.List; import java.util.Properties; @@ -42,7 +46,6 @@ import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.deployment.common.DeploymentContextImpl; import org.glassfish.deployment.common.DeploymentProperties; -import org.glassfish.deployment.common.DeploymentUtils; import org.glassfish.deployment.common.Descriptor; import org.glassfish.deployment.common.ModuleDescriptor; import org.glassfish.deployment.common.RootDeploymentDescriptor; @@ -55,7 +58,9 @@ import org.glassfish.internal.data.ApplicationRegistry; import org.glassfish.internal.deployment.ExtendedDeploymentContext; import org.glassfish.internal.deployment.SnifferManager; -import org.glassfish.loader.util.ASClassLoaderUtil; +import org.glassfish.logging.annotation.LogMessageInfo; +import org.glassfish.logging.annotation.LogMessagesResourceBundle; +import org.glassfish.logging.annotation.LoggerInfo; import org.xml.sax.SAXException; import com.sun.enterprise.config.serverbeans.Applications; @@ -70,7 +75,6 @@ import com.sun.enterprise.deployment.WebBundleDescriptor; import com.sun.enterprise.deployment.archivist.Archivist; import com.sun.enterprise.deployment.archivist.ArchivistFactory; -import com.sun.enterprise.deployment.deploy.shared.Util; import com.sun.enterprise.deployment.io.ConfigurationDeploymentDescriptorFile; import com.sun.enterprise.deployment.io.ConfigurationDeploymentDescriptorFileFor; import com.sun.enterprise.deployment.io.DescriptorConstants; @@ -78,10 +82,6 @@ import com.sun.enterprise.deployment.xml.TagNames; import com.sun.enterprise.util.LocalStringManagerImpl; -import org.glassfish.logging.annotation.LogMessageInfo; -import org.glassfish.logging.annotation.LoggerInfo; -import org.glassfish.logging.annotation.LogMessagesResourceBundle; - /** * Utility class for convenience methods * @@ -151,36 +151,36 @@ public static synchronized Logger getDefaultLogger() { } public static boolean equals(Object a, Object b) { - return ((a == null && b == null) || - (a != null && a.equals(b))); + return ((a == null && b == null) || (a != null && a.equals(b))); } public static List getLibraryJarURIs(BundleDescriptor bundleDesc, ReadableArchive archive) throws Exception { if (bundleDesc == null) { - return Collections.emptyList(); + return emptyList(); } + ModuleDescriptor moduleDesc = bundleDesc.getModuleDescriptor(); Application app = ((BundleDescriptor)moduleDesc.getDescriptor()).getApplication(); return getLibraryJarURIs(app, archive); } public static List getLibraryJarURIs(Application app, ReadableArchive archive) throws Exception { - List libraryURLs = new ArrayList<>(); List libraryURIs = new ArrayList<>(); - // add libraries referenced through manifest - libraryURLs.addAll(DeploymentUtils.getManifestLibraries(archive)); + // Add libraries referenced through manifest + List libraryURLs = new ArrayList<>(getManifestLibraries(archive)); ReadableArchive parentArchive = archive.getParentArchive(); if (parentArchive == null) { - return Collections.emptyList(); + return emptyList(); } File appRoot = new File(parentArchive.getURI()); - // add libraries jars inside application lib directory - libraryURLs.addAll(ASClassLoaderUtil.getAppLibDirLibrariesAsList(appRoot, app.getLibraryDirectory(), null)); + // Add libraries jars inside application lib directory + libraryURLs.addAll(getAppLibDirLibrariesAsList(appRoot, app.getLibraryDirectory(), null)); for (URL url : libraryURLs) { - libraryURIs.add(Util.toURI(url)); + libraryURIs.add(toURI(url)); } + return libraryURIs; } @@ -188,9 +188,10 @@ public static BundleDescriptor getCurrentBundleForContext(DeploymentContext cont ExtendedDeploymentContext ctx = (ExtendedDeploymentContext)context; Application application = context.getModuleMetaData(Application.class); if (application == null) { - // this can happen for non-JavaEE type deployment. e.g., issue 15869 + // This can happen for non-JavaEE type deployment. e.g., issue 15869 return null; } + if (ctx.getParentContext() == null) { if (application.isVirtual()) { // standalone module @@ -199,6 +200,7 @@ public static BundleDescriptor getCurrentBundleForContext(DeploymentContext cont // top level return application; } + // a sub module of ear return application.getModuleByUri(ctx.getModuleUri()); } diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java index 42a509b2a96..00505106581 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/DeploymentImpl.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2009, 2020 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -748,16 +749,24 @@ private void processBdasForAppLibs(ReadableArchive archive, DeploymentContext co try { // Each appLib in context.getAppLibs is a URI of the form // "file:/glassfish/runtime/trunk/glassfish7/glassfish/domains/domain1/lib/applibs/mylib.jar" - List appLibs = context.getAppLibs(); - Set installedLibraries = getInstalledLibraries(archive); - - if (!isAnyEmpty(appLibs, installedLibraries)) { - for (URI appLib : appLibs) { - for (String installedLibrary : installedLibraries) { - if (appLib.getPath().endsWith(installedLibrary)) { + // parentArchiveAppLibs are the app libs in the manifest of the root archive and any embedded + // archives. + List rootArchiveAppLibs = context.getAppLibs(); + + // Each appLib in getInstalledLibraries(archive) is a String of the form + // "mylib.jar" + // currentArchiveAppLibNames are the app libs from the manifest of only the current archive. + // This may therefor be a subset of the rootArchiveAppLibs when the root archive has multiple + // embedded libs with their own app lib references in their manifest. + Set currentArchiveAppLibNames = getInstalledLibraries(archive); + + if (!isAnyEmpty(rootArchiveAppLibs, currentArchiveAppLibNames)) { + for (URI rootArchiveAppLib : rootArchiveAppLibs) { + for (String currentArchiveAppLibName : currentArchiveAppLibNames) { + if (rootArchiveAppLib.getPath().endsWith(currentArchiveAppLibName)) { ReadableArchive libArchive = null; try { - libArchive = archiveFactory.openArchive(appLib); + libArchive = archiveFactory.openArchive(rootArchiveAppLib); if (libArchive.exists(META_INF_BEANS_XML)) { libBdas.add(new RootBeanDeploymentArchive( libArchive, diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java index dc954c4d018..587f674b589 100644 --- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java +++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java @@ -18,10 +18,17 @@ package com.sun.enterprise.v3.server; import static com.sun.enterprise.config.serverbeans.ServerTags.IS_COMPOSITE; +import static com.sun.enterprise.util.Utility.isEmpty; import static java.util.Collections.emptyList; import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Level.SEVERE; +import static java.util.logging.Level.WARNING; +import static org.glassfish.api.admin.ServerEnvironment.DEFAULT_INSTANCE_NAME; +import static org.glassfish.deployment.common.DeploymentProperties.ALT_DD; +import static org.glassfish.deployment.common.DeploymentProperties.RUNTIME_ALT_DD; +import static org.glassfish.deployment.common.DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB; +import static org.glassfish.deployment.common.DeploymentUtils.getVirtualServers; import static org.glassfish.kernel.KernelLoggerInfo.inconsistentLifecycleState; import java.beans.PropertyVetoException; @@ -33,6 +40,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; @@ -49,14 +57,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.glassfish.api.ActionReport; import org.glassfish.api.admin.ParameterMap; -import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.api.admin.config.ApplicationName; import org.glassfish.api.container.Container; import org.glassfish.api.container.Sniffer; @@ -147,12 +153,14 @@ public class ApplicationLifecycle implements Deployment, PostConstruct { private static final String[] UPLOADED_GENERATED_DIRS = new String[] { "policy", "xml", "ejb", "jsp" }; + private static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationLifecycle.class); + protected Logger logger = KernelLoggerInfo.getLogger(); @Inject protected SnifferManagerImpl snifferManager; @Inject - ServiceLocator habitat; + ServiceLocator serviceLocator; @Inject ArchiveFactory archiveFactory; @@ -167,7 +175,7 @@ public class ApplicationLifecycle implements Deployment, PostConstruct { protected Applications applications; @Inject - @Named(ServerEnvironment.DEFAULT_INSTANCE_NAME) + @Named(DEFAULT_INSTANCE_NAME) Server server; @Inject @@ -186,24 +194,19 @@ public class ApplicationLifecycle implements Deployment, PostConstruct { @Inject ConfigSupport configSupport; - protected Logger logger = KernelLoggerInfo.getLogger(); - final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationLifecycle.class); + protected DeploymentLifecycleProbeProvider deploymentLifecycleProbeProvider; + private ExecutorService executorService; + private Collection alcInterceptors = emptyList(); protected Deployer getDeployer(EngineInfo engineInfo) { return engineInfo.getDeployer(); } - protected DeploymentLifecycleProbeProvider deploymentLifecycleProbeProvider = null; - - private ExecutorService executorService = null; - - private Collection alcInterceptors = Collections.EMPTY_LIST; - @Override public void postConstruct() { executorService = createExecutorService(); deploymentLifecycleProbeProvider = new DeploymentLifecycleProbeProvider(); - alcInterceptors = habitat.getAllServices(ApplicationLifecycleInterceptor.class); + alcInterceptors = serviceLocator.getAllServices(ApplicationLifecycleInterceptor.class); } /** @@ -229,9 +232,10 @@ public ArchiveHandler getArchiveHandler(ReadableArchive archive) throws IOExcept @Override public ArchiveHandler getArchiveHandler(ReadableArchive archive, String type) throws IOException { if (type != null) { - return habitat.getService(ArchiveDetector.class, type).getArchiveHandler(); + return serviceLocator.getService(ArchiveDetector.class, type).getArchiveHandler(); } - List detectors = new ArrayList(habitat.getAllServices(ArchiveDetector.class)); + + List detectors = new ArrayList(serviceLocator.getAllServices(ArchiveDetector.class)); Collections.sort(detectors, new Comparator() { // rank 2 is considered lower than rank 1, let's sort them in inceasing order @Override @@ -239,11 +243,13 @@ public int compare(ArchiveDetector o1, ArchiveDetector o2) { return o1.rank() - o2.rank(); } }); - for (ArchiveDetector ad : detectors) { - if (ad.handles(archive)) { - return ad.getArchiveHandler(); + + for (ArchiveDetector detector : detectors) { + if (detector.handles(archive)) { + return detector.getArchiveHandler(); } } + return null; } @@ -254,7 +260,6 @@ public ApplicationInfo deploy(final ExtendedDeploymentContext context) { @Override public ApplicationInfo deploy(Collection sniffers, final ExtendedDeploymentContext context) { - long operationStartTime = Calendar.getInstance().getTimeInMillis(); events.send(new Event(Deployment.DEPLOYMENT_START, context), false); @@ -270,22 +275,22 @@ public ApplicationInfo deploy(Collection sniffers, final Exte return null; } - // if the virtualservers param is not defined, set it to all + // If the virtualservers param is not defined, set it to all // defined virtual servers minus __asadmin on that target if (commandParams.virtualservers == null) { - commandParams.virtualservers = DeploymentUtils.getVirtualServers(commandParams.target, env, domain); + commandParams.virtualservers = getVirtualServers(commandParams.target, env, domain); } if (commandParams.enabled == null) { - commandParams.enabled = Boolean.TRUE; + commandParams.enabled = true; } if (commandParams.altdd != null) { - context.getSource().addArchiveMetaData(DeploymentProperties.ALT_DD, commandParams.altdd); + context.getSource().addArchiveMetaData(ALT_DD, commandParams.altdd); } if (commandParams.runtimealtdd != null) { - context.getSource().addArchiveMetaData(DeploymentProperties.RUNTIME_ALT_DD, commandParams.runtimealtdd); + context.getSource().addArchiveMetaData(RUNTIME_ALT_DD, commandParams.runtimealtdd); } ProgressTracker tracker = new ProgressTracker() { @@ -331,9 +336,6 @@ public void actOn(Logger logger) { // ignore } } - // comment this out for now as the interceptor seems to use - // a different hook to roll back failure - // notifyLifecycleInterceptorsAfter(ExtendedDeploymentContext.Phase.REPLICATION, context); if (!commandParams.keepfailedstubs) { try { @@ -342,6 +344,7 @@ public void actOn(Logger logger) { // ignore } } + appRegistry.remove(appName); } @@ -350,6 +353,7 @@ public void actOn(Logger logger) { context.addTransientAppMetaData(ExtendedDeploymentContext.TRACKER, tracker); context.setPhase(DeploymentContextImpl.Phase.PREPARE); ApplicationInfo appInfo = null; + try { ArchiveHandler handler = context.getArchiveHandler(); if (handler == null) { @@ -389,13 +393,13 @@ public void actOn(Logger logger) { sniffers = getSniffers(handler, sniffers, context); - ClassLoaderHierarchy clh = habitat.getService(ClassLoaderHierarchy.class); + ClassLoaderHierarchy classLoaderHierarchy = serviceLocator.getService(ClassLoaderHierarchy.class); if (tracing != null) { tracing.addMark(DeploymentTracing.Mark.CLASS_LOADER_HIERARCHY); } - context.createDeploymentClassLoader(clh, handler); - events.send(new Event(Deployment.AFTER_DEPLOYMENT_CLASSLOADER_CREATION, context), false); + context.createDeploymentClassLoader(classLoaderHierarchy, handler); + events.send(new Event(AFTER_DEPLOYMENT_CLASSLOADER_CREATION, context), false); if (tracing != null) { tracing.addMark(DeploymentTracing.Mark.CLASS_LOADER_CREATED); @@ -416,6 +420,7 @@ public void actOn(Logger logger) { logger.fine("After Sorting " + info.getSniffer().getModuleType()); } } + if (sortedEngineInfos == null || sortedEngineInfos.isEmpty()) { report.failure(logger, localStrings.getLocalString("unknowncontainertype", "There is no installed container capable of handling this application {0}", context.getSource().getName())); @@ -430,6 +435,7 @@ public void actOn(Logger logger) { for (Object m : context.getModuleMetadata()) { tempAppInfo.addMetaData(m); } + tempAppInfo.setIsJavaEEApp(sortedEngineInfos); // set the flag on the archive to indicate whether it's // a JavaEE archive or not @@ -448,7 +454,7 @@ public void actOn(Logger logger) { events.send(new Event(Deployment.DEPLOYMENT_BEFORE_CLASSLOADER_CREATION, context), false); - context.createApplicationClassLoader(clh, handler); + context.createApplicationClassLoader(classLoaderHierarchy, handler); events.send(new Event(Deployment.AFTER_APPLICATION_CLASSLOADER_CREATION, context), false); @@ -537,6 +543,7 @@ public void actOn(Logger logger) { return null; } } + return appInfo; } finally { context.postDeployClean(false /* not final clean-up yet */); @@ -566,39 +573,43 @@ public void actOn(Logger logger) { @Override public Types getDeployableTypes(DeploymentContext context) throws IOException { - synchronized (context) { Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class); if (types != null) { return types; - } else { + } - try { - // scan the jar and store the result in the deployment context. - ParsingContext parsingContext = new ParsingContext.Builder().logger(context.getLogger()) - .executorService(executorService).locator(getResourceLocator()).build(); - Parser parser = new Parser(parsingContext); - ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, context.getSource()); + try { + // Scan the jar and store the result in the deployment context. + Parser parser = new Parser( + new ParsingContext.Builder() + .logger(context.getLogger()) + .executorService(executorService) + .locator(getResourceLocator()) + .build()); + + try (ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, context.getSource())) { parser.parse(scannerAdapter, null); - for (ReadableArchive externalLibArchive : getExternalLibraries(context)) { - ReadableArchiveScannerAdapter libAdapter = null; - try { - libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive); - parser.parse(libAdapter, null); - } finally { - if (libAdapter != null) { - libAdapter.close(); - } - } + + List externalLibraries = getExternalLibraries(context); + + for (ReadableArchive externalLibrary : externalLibraries) { + parser.parse(new ReadableArchiveScannerAdapter(parser, externalLibrary), null); } + parser.awaitTermination(); - scannerAdapter.close(); - context.addTransientAppMetaData(Types.class.getName(), parsingContext.getTypes()); - context.addTransientAppMetaData(Parser.class.getName(), parser); - return parsingContext.getTypes(); - } catch (InterruptedException e) { - throw new IOException(e); + + for (ReadableArchive externalLibrary : externalLibraries) { + externalLibrary.close(); + } } + + context.addTransientAppMetaData(Types.class.getName(), parser.getContext().getTypes()); + context.addTransientAppMetaData(Parser.class.getName(), parser); + + return parser.getContext().getTypes(); + } catch (InterruptedException | URISyntaxException e) { + throw new IOException(e); } } } @@ -607,8 +618,9 @@ private ResourceLocator getResourceLocator() { if (CommonModelRegistry.getInstance().canLoadResources()) { return null; } - ClassLoaderHierarchy clh = habitat.getService(ClassLoaderHierarchy.class); - ClassLoader cl = clh.getCommonClassLoader(); + + ClassLoader classLoader = serviceLocator.getService(ClassLoaderHierarchy.class).getCommonClassLoader(); + return new ResourceLocator() { private boolean excluded(String name) { return name.startsWith("java/") || name.startsWith("sun/") || name.startsWith("com/sun/"); @@ -616,41 +628,41 @@ private boolean excluded(String name) { @Override public InputStream openResourceStream(String name) throws IOException { - return excluded(name) ? null : cl.getResourceAsStream(name); + return excluded(name) ? null : classLoader.getResourceAsStream(name); } @Override public URL getResource(String name) { - return excluded(name) ? null : cl.getResource(name); + return excluded(name) ? null : classLoader.getResource(name); } }; } private void notifyLifecycleInterceptorsBefore(final ExtendedDeploymentContext.Phase phase, final ExtendedDeploymentContext dc) { - for (ApplicationLifecycleInterceptor i : alcInterceptors) { - i.before(phase, dc); + for (ApplicationLifecycleInterceptor interceptor : alcInterceptors) { + interceptor.before(phase, dc); } } private void notifyLifecycleInterceptorsAfter(final ExtendedDeploymentContext.Phase phase, final ExtendedDeploymentContext dc) { - for (ApplicationLifecycleInterceptor i : alcInterceptors) { - i.after(phase, dc); + for (ApplicationLifecycleInterceptor interceptor : alcInterceptors) { + interceptor.after(phase, dc); } } - private List getExternalLibraries(DeploymentContext context) throws IOException { + private List getExternalLibraries(DeploymentContext context) throws IOException, URISyntaxException { List externalLibArchives = new ArrayList(); - String skipScanExternalLibProp = context.getAppProps().getProperty(DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB); + String skipScanExternalLibProp = context.getAppProps().getProperty(SKIP_SCAN_EXTERNAL_LIB); if (Boolean.valueOf(skipScanExternalLibProp)) { - // if we skip scanning external libraries, we should just + // If we skip scanning external libraries, we should just // return an empty list here - return Collections.EMPTY_LIST; + return emptyList(); } - List externalLibs = DeploymentUtils.getExternalLibraries(context.getSource()); - for (URI externalLib : externalLibs) { + // Get the libraries referenced in the manifest class-path + for (URI externalLib : DeploymentUtils.getExternalLibraries(context.getSource())) { externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); } @@ -692,7 +704,7 @@ public boolean resume(String appName) { } @Override - public List> setupContainerInfos(DeploymentContext context) throws Exception { + public List> setupContainerInfos(DeploymentContext context) throws Exception { return setupContainerInfos(context.getArchiveHandler(), getSniffers(context.getArchiveHandler(), null, context), context); } @@ -737,10 +749,10 @@ public Collection getSniffers(final ArchiveHandler handler, C tracing.addContainerMark(DeploymentTracing.ContainerMark.SNIFFER_DONE, containerName); } - // start all the containers associated with sniffers. + // Start all the containers associated with sniffers. EngineInfo engineInfo = containerRegistry.getContainer(containerName); if (engineInfo == null) { - // need to synchronize on the registry to not end up starting the same container from + // Need to synchronize on the registry to not end up starting the same container from // different threads. Collection> containersInfo = null; synchronized (containerRegistry) { @@ -754,7 +766,7 @@ public Collection getSniffers(final ArchiveHandler handler, C tracing.addContainerMark(DeploymentTracing.ContainerMark.AFTER_CONTAINER_SETUP, containerName); } - if (containersInfo == null || containersInfo.size() == 0) { + if (isEmpty(containersInfo)) { String msg = "Cannot start container(s) associated to application of type : " + sniffer.getModuleType(); report.failure(logger, msg, null); throw new Exception(msg); @@ -762,7 +774,7 @@ public Collection getSniffers(final ArchiveHandler handler, C } } - // now start all containers, by now, they should be all setup... + // Now start all containers, by now, they should be all setup... if (containersInfo != null && !startContainers(containersInfo, logger, context)) { final String msg = "Aborting, Failed to start container " + containerName; report.failure(logger, msg, null); @@ -779,6 +791,7 @@ public Collection getSniffers(final ArchiveHandler handler, C report.failure(logger, msg, null); throw new Exception(msg); } + Deployer deployer = getDeployer(engineInfo); if (deployer == null) { if (!startContainers(Collections.singleton(engineInfo), logger, context)) { @@ -801,13 +814,13 @@ public Collection getSniffers(final ArchiveHandler handler, C containerInfosByDeployers.put(deployer, engineInfo); } - // all containers that have recognized parts of the application being deployed + // All containers that have recognized parts of the application being deployed // have now been successfully started. Start the deployment process. List> sortedEngineInfos = new ArrayList<>(); Map typeByProvider = new HashMap<>(); - for (ApplicationMetaDataProvider provider : habitat.getAllServices(ApplicationMetaDataProvider.class)) { + for (ApplicationMetaDataProvider provider : serviceLocator.getAllServices(ApplicationMetaDataProvider.class)) { if (provider.getMetaData() != null) { for (Class provided : provider.getMetaData().provides()) { typeByProvider.put(provided, provider); @@ -815,14 +828,14 @@ public Collection getSniffers(final ArchiveHandler handler, C } } - // check if everything is provided. - for (ApplicationMetaDataProvider provider : habitat.getAllServices(ApplicationMetaDataProvider.class)) { + // Check if everything is provided. + for (ApplicationMetaDataProvider provider : serviceLocator.getAllServices(ApplicationMetaDataProvider.class)) { if (provider.getMetaData() != null) { for (Class dependency : provider.getMetaData().requires()) { if (!typeByProvider.containsKey(dependency)) { - // at this point, I only log problems, because it maybe that what I am deploying now + // at this point, we only log problems, because it maybe that what I am deploying now // will not require this application metadata. - logger.log(Level.WARNING, KernelLoggerInfo.applicationMetaDataProvider, new Object[] { provider, dependency }); + logger.log(WARNING, KernelLoggerInfo.applicationMetaDataProvider, new Object[] { provider, dependency }); } } } @@ -850,9 +863,8 @@ public Collection getSniffers(final ArchiveHandler handler, C serviceName = deployer.getClass().getSimpleName(); } - report.failure(logger, - serviceName + " deployer requires " + dependency + " but no other deployer provides it", - null); + report.failure(logger, serviceName + " deployer requires " + dependency + " but no other deployer provides it", + null); return null; } @@ -866,12 +878,10 @@ public Collection getSniffers(final ArchiveHandler handler, C if (logger.isLoggable(FINE)) { logger.fine("Keyed Deployer " + deployer.getClass()); } - loadDeployer( - orderedDeployers, - deployer, typeByDeployer, (Map) typeByProvider, context); + loadDeployer(orderedDeployers, deployer, typeByDeployer, (Map) typeByProvider, context); } - // now load metadata from deployers. + // Now load metadata from deployers. for (Deployer deployer : orderedDeployers) { if (logger.isLoggable(FINE)) { logger.fine("Ordered Deployer " + deployer.getClass()); @@ -937,14 +947,13 @@ private void loadDeployer(List results, Deployer deployer, Map results, Map, ApplicationMetaDataProvider> providers, ApplicationMetaDataProvider provider) { - results.addFirst(provider); + for (Class type : provider.getMetaData().requires()) { if (providers.containsKey(type)) { addRecursively(results, providers, providers.get(type)); } } - } @Override @@ -1030,7 +1039,7 @@ public ModuleInfo prepareModule(List> sortedEngineInfos, String protected Collection> setupContainer(Sniffer sniffer, Logger logger, DeploymentContext context) { ActionReport report = context.getActionReport(); - ContainerStarter starter = habitat.getService(ContainerStarter.class); + ContainerStarter starter = serviceLocator.getService(ContainerStarter.class); Collection> containersInfo = starter.startContainer(sniffer); if (containersInfo == null || containersInfo.size() == 0) { report.failure(logger, "Cannot start container(s) associated to application of type : " + sniffer.getModuleType(), null); @@ -1057,7 +1066,7 @@ protected boolean startContainers(Collection> containersInfo, L @SuppressWarnings("rawtypes") Deployer deployer; try { - deployer = habitat.getService(deployerClass); + deployer = serviceLocator.getService(deployerClass); engineInfo.setDeployer(deployer); } catch (MultiException e) { report.failure(logger, "Cannot instantiate or inject " + deployerClass, e); @@ -1065,7 +1074,8 @@ protected boolean startContainers(Collection> containersInfo, L return false; } catch (ClassCastException e) { engineInfo.stop(logger); - report.failure(logger, deployerClass + " does not implement " + " the org.jvnet.glassfish.api.deployment.Deployer interface", e); + report.failure(logger, + deployerClass + " does not implement " + " the org.jvnet.glassfish.api.deployment.Deployer interface", e); return false; } } @@ -1759,7 +1769,7 @@ private ReadableArchive getArchive(DeploymentContextBuilder builder) throws IOEx throw new IOException("Source archive or file not provided to builder"); } if (archive == null && builder.sourceAsFile() != null) { - archive = habitat.getService(ArchiveFactory.class).openArchive(builder.sourceAsFile()); + archive = serviceLocator.getService(ArchiveFactory.class).openArchive(builder.sourceAsFile()); if (archive == null) { throw new IOException("Invalid archive type : " + builder.sourceAsFile().getAbsolutePath()); } @@ -1830,8 +1840,7 @@ private ExtendedDeploymentContext getContext(ExtendedDeploymentContext initial, try { archive.close(); } catch (IOException e) { - logger.log(SEVERE, KernelLoggerInfo.errorClosingArtifact, - new Object[] { archive.getURI().getSchemeSpecificPart(), e }); + logger.log(SEVERE, KernelLoggerInfo.errorClosingArtifact, new Object[] { archive.getURI().getSchemeSpecificPart(), e }); throw e; } archive = (FileArchive) expandedArchive; diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java index c70becbac78..5899b17898c 100644 --- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java +++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ReadableArchiveScannerAdapter.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,6 +17,10 @@ package com.sun.enterprise.v3.server; +import static java.util.logging.Level.SEVERE; +import static org.glassfish.kernel.KernelLoggerInfo.exceptionWhileParsing; +import static org.glassfish.kernel.KernelLoggerInfo.invalidInputStream; + import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -25,9 +30,11 @@ import java.util.jar.Manifest; import java.util.logging.Level; import java.util.logging.Logger; + import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.hk2.classmodel.reflect.ArchiveAdapter; import org.glassfish.hk2.classmodel.reflect.Parser; +import org.glassfish.hk2.classmodel.reflect.Parser.Result; import org.glassfish.hk2.classmodel.reflect.util.AbstractAdapter; import org.glassfish.kernel.KernelLoggerInfo; @@ -36,38 +43,29 @@ * * @author Jerome Dochez */ -public class ReadableArchiveScannerAdapter extends AbstractAdapter { +public class ReadableArchiveScannerAdapter extends AbstractAdapter implements AutoCloseable { final ReadableArchive archive; final Parser parser; final URI uri; /** - * Can be null or can be pointing to the archive adapter in which - * we are embedded. + * Can be null or can be pointing to the archive adapter in which we are embedded. */ final ReadableArchiveScannerAdapter parent; /** - * We need to maintain a count of the sub archives we have asked - * the class-model to parse so we can close our archive once all - * the sub-archives have been closed themselves. + * We need to maintain a count of the sub archives we have asked the class-model to parse so we can close our archive + * once all the sub-archives have been closed themselves. * - * Obviously, we start with a count of 1 since we need to account - * for our own closure. + * Obviously, we start with a count of 1 since we need to account for our own closure. * */ final AtomicInteger releaseCount = new AtomicInteger(1); - /** - * Default timeout value for parsing a single jar (plus all internal jars it may contains) - */ - private final int DEFAULT_TIMEOUT = Integer.getInteger(Parser.DEFAULT_WAIT_SYSPROP, 600); - private final static Level level = Level.FINE; final private static Logger alogger = KernelLoggerInfo.getLogger(); - public ReadableArchiveScannerAdapter(Parser parser, ReadableArchive archive) { this.archive = archive; this.parser = parser; @@ -79,12 +77,12 @@ private ReadableArchiveScannerAdapter(ReadableArchiveScannerAdapter parent, Read this.parent = parent; this.archive = archive; this.parser = parent.parser; - this.uri = uri==null?archive.getURI():uri; + this.uri = uri == null ? archive.getURI() : uri; } @Override public URI getURI() { - return uri; + return uri; } @Override @@ -93,8 +91,7 @@ public Manifest getManifest() throws IOException { } @Override - public void onSelectedEntries(ArchiveAdapter.Selector selector, EntryTask entryTask, final Logger logger ) throws IOException { - + public void onSelectedEntries(ArchiveAdapter.Selector selector, EntryTask entryTask, final Logger logger) throws IOException { Enumeration entries = archive.entries(); while (entries.hasMoreElements()) { final String name = entries.nextElement(); @@ -102,14 +99,14 @@ public void onSelectedEntries(ArchiveAdapter.Selector selector, EntryTask entryT if (selector.isSelected(entry)) { handleEntry(name, entry, logger, entryTask); } - // check for non exploded jars. + + // Check for non exploded jars. if (name.endsWith(".jar")) { handleJar(name, logger); } } - if (logger.isLoggable(level)) { - logger.log(level, "Finished parsing " + this.uri); - } + + logger.log(level, () -> "Finished parsing " + uri); } @Override @@ -119,77 +116,66 @@ public void close() throws IOException { private void releaseCount() throws IOException { int release = releaseCount.decrementAndGet(); - if (release==0) { + if (release == 0) { archive.close(); - if (parent!=null) { + if (parent != null) { parent.releaseCount(); } } } - protected void handleEntry(String name, Entry entry, Logger logger /*ignored*/, EntryTask entryTask) - throws IOException { - - InputStream is = null; - try { - try { - is = archive.getEntry(name); - if (is==null) { - alogger.log(Level.SEVERE, KernelLoggerInfo.invalidInputStream, name); - return; - } - entryTask.on(entry, is); - } catch (Exception e) { - alogger.log(Level.SEVERE, KernelLoggerInfo.exceptionWhileParsing, - new Object[] { entry.name, archive.getURI(), entry.size, e}); + protected void handleEntry(String name, Entry entry, Logger logger /* ignored */, EntryTask entryTask) throws IOException { + try (InputStream is = archive.getEntry(name)) { + if (is == null) { + alogger.log(SEVERE, invalidInputStream, name); + return; } - } finally { - if (is!=null) - is.close(); + + entryTask.on(entry, is); + } catch (Exception e) { + alogger.log(SEVERE, exceptionWhileParsing, new Object[] { entry.name, archive.getURI(), entry.size, e }); } } - protected Future handleJar(final String name, final Logger logger) - throws IOException { + protected Future handleJar(final String name, final Logger logger) throws IOException { - // we need to check that there is no exploded directory by this name. + // We need to check that there is no exploded directory by this name. String explodedName = name.replaceAll("[/ ]", "__").replace(".jar", "_jar"); if (!archive.exists(explodedName)) { final ReadableArchive subArchive = archive.getSubArchive(name); - if (subArchive==null) { - logger.log(Level.SEVERE, KernelLoggerInfo.cantOpenSubArchive, - new Object[] {name, archive.getURI()}); + if (subArchive == null) { + logger.log(SEVERE, KernelLoggerInfo.cantOpenSubArchive, new Object[] { name, archive.getURI() }); return null; } - if (logger.isLoggable(level)) { - logger.log(level, "Spawning sub parsing " + subArchive.getURI()); - } + logger.log(level, () -> "Spawning sub parsing " + subArchive.getURI()); + final ReadableArchiveScannerAdapter adapter = new InternalJarAdapter(this, subArchive, subArchive.getURI()); - // we increment our release count, this tells us when we can safely close the parent + + // We increment our release count, this tells us when we can safely close the parent // archive. releaseCount.incrementAndGet(); + return parser.parse(adapter, new Runnable() { @Override public void run() { try { - if (logger.isLoggable(level)) - logger.log(level, "Closing sub archive " + subArchive.getURI()); + logger.log(level, () -> "Closing sub archive " + subArchive.getURI()); adapter.close(); } catch (IOException e) { - logger.log(Level.SEVERE, KernelLoggerInfo.exceptionWhileClosing, - new Object[] { name, e }); + logger.log(SEVERE, KernelLoggerInfo.exceptionWhileClosing, new Object[] { name, e }); } } }); } + return null; } /** - * Adapter for internal jar files. we don't process further down any more internal - * jar files. In other words, no jars inside jars inside jars can be deployed... + * Adapter for internal jar files. we don't process further down any more internal jar files. In other words, no jars + * inside jars inside jars can be deployed... */ private static class InternalJarAdapter extends ReadableArchiveScannerAdapter { public InternalJarAdapter(ReadableArchiveScannerAdapter parent, ReadableArchive archive, URI uri) { @@ -197,7 +183,7 @@ public InternalJarAdapter(ReadableArchiveScannerAdapter parent, ReadableArchive } @Override - protected Future handleJar(String name, Logger logger) throws IOException { + protected Future handleJar(String name, Logger logger) throws IOException { // we don't process second level internal jars return null; } diff --git a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/ArchiveFactory.java b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/ArchiveFactory.java index b9cea87892d..dcceff69889 100644 --- a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/ArchiveFactory.java +++ b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/ArchiveFactory.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,36 +17,32 @@ package com.sun.enterprise.deploy.shared; -import org.glassfish.api.deployment.DeployCommandParameters; -import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.api.deployment.archive.ReadableArchiveFactory; -import org.glassfish.api.deployment.archive.WritableArchive; -import org.glassfish.deployment.common.DeploymentUtils; -import org.glassfish.hk2.api.MultiException; -import org.glassfish.hk2.api.ServiceLocator; - -import jakarta.inject.Inject; - -import org.jvnet.hk2.annotations.Service; -import jakarta.inject.Singleton; +import static java.util.logging.Level.SEVERE; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.glassfish.api.deployment.DeployCommandParameters; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.api.deployment.archive.ReadableArchiveFactory; +import org.glassfish.api.deployment.archive.WritableArchive; +import org.glassfish.hk2.api.MultiException; +import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.logging.annotation.LogMessageInfo; -import org.glassfish.logging.annotation.LoggerInfo; -import org.glassfish.logging.annotation.LogMessagesResourceBundle; +import org.jvnet.hk2.annotations.Service; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; /** - * This implementation of the ArchiveFactory interface - * is capable of creating the right abstraction of the Archive + * This implementation of the ArchiveFactory interface is capable of creating the right abstraction of the Archive * interface depending on the protocol used in the URL. * * @author Jerome Dochez @@ -54,34 +51,29 @@ @Singleton public class ArchiveFactory { - @Inject - ServiceLocator habitat; - public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; - @LogMessageInfo(message = "Cannot find an archive implementation for {0}", cause="The type of archive being created is not supported.", action="Determine the type of archive requested to see whether another type can be used.", level="SEVERE") + @LogMessageInfo(message = "Cannot find an archive implementation for {0}", cause = "The type of archive being created is not supported.", action = "Determine the type of archive requested to see whether another type can be used.", level = "SEVERE") private static final String IMPLEMENTATION_NOT_FOUND = "NCLS-DEPLOYMENT-00021"; + + @Inject + ServiceLocator serviceLocator; + public WritableArchive createArchive(File path) throws java.io.IOException { try { - /* - *Use the expanded constructor so illegal characters (such as embedded blanks) in the path - *will be encoded. - */ + // Use the expanded constructor so illegal characters (such as embedded blanks) in the path will be encoded. return createArchive(prepareArchiveURI(path)); - } catch(java.net.URISyntaxException e) { + } catch (URISyntaxException e) { return null; } } public WritableArchive createArchive(String protocol, File path) throws java.io.IOException { try { - /* - *Use the expanded constructor so illegal characters (such as embedded blanks) in the path - *will be encoded. - */ + // Use the expanded constructor so illegal characters (such as embedded blanks) in the path will be encoded. return createArchive(protocol, prepareArchiveURI(path)); - } catch(java.net.URISyntaxException e) { + } catch (URISyntaxException e) { return null; } } @@ -89,37 +81,34 @@ public WritableArchive createArchive(String protocol, File path) throws java.io. public ReadableArchive openArchive(File path) throws java.io.IOException { try { return openArchive(prepareArchiveURI(path)); - } catch(java.net.URISyntaxException e) { + } catch (URISyntaxException e) { return null; } } /** - * Creates a new archivist using the URL as the path. The URL - * protocol will define the type of desired archive (jar, file, etc) + * Creates a new archivist using the URL as the path. The URL protocol will define the type of desired archive (jar, + * file, etc) + * * @param path to the archive * @return the apropriate archive */ public WritableArchive createArchive(URI path) throws IOException { - - String protocol = path.getScheme(); - return createArchive(protocol, path); + return createArchive(path.getScheme(), path); } public WritableArchive createArchive(String protocol, URI path) throws IOException { try { - WritableArchive archive = habitat.getService(WritableArchive.class, protocol); - if (archive==null) { - deplLogger.log(Level.SEVERE, - IMPLEMENTATION_NOT_FOUND, - protocol); + WritableArchive archive = serviceLocator.getService(WritableArchive.class, protocol); + if (archive == null) { + deplLogger.log(SEVERE, IMPLEMENTATION_NOT_FOUND, protocol); throw new MalformedURLException("Protocol not supported : " + protocol); } archive.create(path); return archive; } catch (MultiException e) { - LogRecord lr = new LogRecord(Level.SEVERE, IMPLEMENTATION_NOT_FOUND); + LogRecord lr = new LogRecord(SEVERE, IMPLEMENTATION_NOT_FOUND); lr.setParameters(new Object[] { protocol }); lr.setThrown(e); deplLogger.log(lr); @@ -130,6 +119,7 @@ public WritableArchive createArchive(String protocol, URI path) throws IOExcepti /** * It first consults {@link ReadableArchiveFactory} to get an archive, if it does not get then delegates to * {@link #openArchive(java.net.URI)}. + * * @param path Application archive, never null * @param properties property bag, can contain for example deploy time properties. Never null * @return Gives {@link ReadableArchive}. @@ -142,51 +132,53 @@ public ReadableArchive openArchive(File path, DeployCommandParameters properties } catch (URISyntaxException e) { return null; } - for (ReadableArchiveFactory fac : habitat.getAllServices(ReadableArchiveFactory.class)) { - //get the first ReadableArchive and move - ReadableArchive archive=null; - try{ - archive = fac.open(uri, properties); - }catch(Exception e){ - //ignore? + + for (ReadableArchiveFactory archiveFactory : serviceLocator.getAllServices(ReadableArchiveFactory.class)) { + // Get the first ReadableArchive and move + try { + ReadableArchive archive = archiveFactory.open(uri, properties); + if (archive != null) { + return archive; + } + } catch (Exception e) { + // ignore? } - if(archive == null) - continue; - return archive; } + return openArchive(path); } /** - * Opens an existing archivist using the URL as the path. - * The URL protocol will defines the type of desired archive + * Opens an existing archivist using the URL as the path. The URL protocol will defines the type of desired archive * (jar, file, memory, etc...) + * * @param path url to the existing archive * @return the appropriate archive */ public ReadableArchive openArchive(URI path) throws IOException { - String provider = path.getScheme(); if (provider.equals("file")) { - // this could be a jar file or a directory - File f = new File(path); - if (!f.exists()) throw new FileNotFoundException(f.getPath()); - if (f.isFile()) { + // This could be a jar file or a directory + File file = new File(path); + if (!file.exists()) { + throw new FileNotFoundException(file.getPath()); + } + if (file.isFile()) { provider = "jar"; } } + try { - ReadableArchive archive = habitat.getService(ReadableArchive.class, provider); - if (archive==null) { - deplLogger.log(Level.SEVERE, - IMPLEMENTATION_NOT_FOUND, - provider); + ReadableArchive archive = serviceLocator.getService(ReadableArchive.class, provider); + if (archive == null) { + deplLogger.log(SEVERE, IMPLEMENTATION_NOT_FOUND, provider); throw new MalformedURLException("Protocol not supported : " + provider); } + archive.open(path); return archive; } catch (MultiException e) { - LogRecord lr = new LogRecord(Level.SEVERE, IMPLEMENTATION_NOT_FOUND); + LogRecord lr = new LogRecord(SEVERE, IMPLEMENTATION_NOT_FOUND); lr.setParameters(new Object[] { provider }); lr.setThrown(e); deplLogger.log(lr); @@ -195,18 +187,18 @@ public ReadableArchive openArchive(URI path) throws IOException { } /** - *Create a URI for the jar specified by the path string. - *

- *The steps used here correctly encode "illegal" characters - such as embedded blanks - in - *the path string that otherwise would render the URI unusable. The URI constructor that - *accepts just the path string does not perform this encoding. - *@param path string for the archive - *@return URI with any necessary encoding of special characters + * Create a URI for the jar specified by the path string. + *

+ * The steps used here correctly encode "illegal" characters - such as embedded blanks - in the path string that + * otherwise would render the URI unusable. The URI constructor that accepts just the path string does not perform this + * encoding. + * + * @param path string for the archive + * @return URI with any necessary encoding of special characters */ - static java.net.URI prepareArchiveURI(File path) throws java.net.URISyntaxException, java.io.UnsupportedEncodingException, java.io.IOException { - + static java.net.URI prepareArchiveURI(File path) throws URISyntaxException, UnsupportedEncodingException, IOException { URI archiveURI = path.toURI(); - URI answer = new URI(archiveURI.getScheme(), null /* authority */, archiveURI.getPath(), null /* query */, null /* fragment */); - return answer; + + return new URI(archiveURI.getScheme(), null /* authority */, archiveURI.getPath(), null /* query */, null /* fragment */); } } diff --git a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/FileArchive.java b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/FileArchive.java index 05f60bbe34c..d2c1ca22520 100644 --- a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/FileArchive.java +++ b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deploy/shared/FileArchive.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. All rights reserved. * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,107 +17,110 @@ package com.sun.enterprise.deploy.shared; -import com.sun.enterprise.deployment.deploy.shared.Util; -import com.sun.enterprise.util.io.FileUtils; - +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.LineNumberReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.net.URI; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.logging.Level; import java.util.logging.Logger; import org.glassfish.api.deployment.archive.Archive; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.api.deployment.archive.WritableArchive; - -import jakarta.inject.Inject; - -import org.jvnet.hk2.annotations.Service; import org.glassfish.hk2.api.PerLookup; +import org.glassfish.logging.annotation.LogMessageInfo; +import org.jvnet.hk2.annotations.Service; -import java.io.*; -import java.util.*; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.net.URI; -import java.nio.file.Files; +import com.sun.enterprise.deployment.deploy.shared.Util; +import com.sun.enterprise.util.io.FileUtils; -import org.glassfish.logging.annotation.LogMessageInfo; -import org.glassfish.logging.annotation.LoggerInfo; -import org.glassfish.logging.annotation.LogMessagesResourceBundle; +import jakarta.inject.Inject; /** - * This implementation of the Archive interface maps to a directory/file - * structure. + * This implementation of the Archive interface maps to a directory/file structure. *

- * If the directory underlying the FileArchive is created by GlassFish - * then FileArchive filters its contents so only - * those files more recent than the creation of the archive itself are visible to - * consumers. + * If the directory underlying the FileArchive is created by GlassFish then FileArchive filters its contents so only + * those files more recent than the creation of the archive itself are visible to consumers. *

- * The main motivation is to hide unwanted "left-over" files - * from previous deployments that might linger, especially on Windows, - * after the previous app had been undeployed. (Deployment uses a FileArchive - * to extract the user's JAR-based archive into the applications directory.) - * Historically such left-over files arise after GlassFish expands an archive - * into its exploded form but then some - * code opens but does not close a file in that exploded directory tree. + * The main motivation is to hide unwanted "left-over" files from previous deployments that might linger, especially on + * Windows, after the previous app had been undeployed. (Deployment uses a FileArchive to extract the user's JAR-based + * archive into the applications directory.) Historically such left-over files arise after GlassFish expands an archive + * into its exploded form but then some code opens but does not close a file in that exploded directory tree. *

- * An open left-over file can be overwritten-in-place on Windows, and - * this happens when a caller invokes {@link #putNextEntry(java.lang.String) } - * to create a new entry (file) inside the archive. But a - * left-over file that is not in the new app but is - * still open by GlassFish cannot be deleted or renamed on Windows and so it will - * remain in the expansion directory. Such left-over files, if not filtered out, - * can confuse GlassFish and the application. By "stamping" the archive - * creation date we can filter out such old, left-over files. + * An open left-over file can be overwritten-in-place on Windows, and this happens when a caller invokes + * {@link #putNextEntry(java.lang.String) } to create a new entry (file) inside the archive. But a left-over file that + * is not in the new app but is still open by GlassFish cannot be deleted or renamed on Windows and so it will remain in + * the expansion directory. Such left-over files, if not filtered out, can confuse GlassFish and the application. By + * "stamping" the archive creation date we can filter out such old, left-over files. *

- * To support this feature, when FileArchive creates a directory it stores a - * marker file there, the contents of which records the creation date/time of - * the archive. We cannot just use the lastModified value for the top-level - * directory. Users might legitimately use "touch .reload" in the applications/appName - * directory to trigger a dynamic reload of the app. If .reload does not already - * exist then touch creates it, and this would update the lastModified of the - * directory file. + * To support this feature, when FileArchive creates a directory it stores a marker file there, the contents of which + * records the creation date/time of the archive. We cannot just use the lastModified value for the top-level directory. + * Users might legitimately use "touch .reload" in the applications/appName directory to trigger a dynamic reload of the + * app. If .reload does not already exist then touch creates it, and this would update the lastModified of the directory + * file. * * @author Jerome Dochez * @author Tim Quinn */ -@Service(name="file") +@Service(name = "file") @PerLookup public class FileArchive extends AbstractReadableArchive implements WritableArchive { + public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; + + @LogMessageInfo(message = "Attempt to list files in {0} failed, perhaps because that is not a valid directory or because file permissions do not allow GlassFish to access it", level = "WARNING") + private static final String FILE_LIST_FAILURE = "NCLS-DEPLOYMENT-00022"; + + @LogMessageInfo(message = "Ignoring {0} because the containing archive {1} recorded it as a pre-existing stale file", level = "WARNING") + private static final String STALE_FILES_SKIPPED = "NCLS-DEPLOYMENT-00023"; + private final static Level DEBUG_LEVEL = Level.FINE; @Inject ArchiveFactory archiveFactory; // the archive abstraction directory. - File archive = null; - URI uri = null; + File archive; + URI uri; // the currently opened entry - OutputStream os=null; - - public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; - - @LogMessageInfo(message = "Attempt to list files in {0} failed, perhaps because that is not a valid directory or because file permissions do not allow GlassFish to access it", level="WARNING") - private static final String FILE_LIST_FAILURE = "NCLS-DEPLOYMENT-00022"; - - @LogMessageInfo(message = "Ignoring {0} because the containing archive {1} recorded it as a pre-existing stale file", level="WARNING") - private static final String STALE_FILES_SKIPPED = "NCLS-DEPLOYMENT-00023"; + OutputStream os; /* - * tracks stale files in the archive and filters the archive's contents to - * exclude stale entries + * tracks stale files in the archive and filters the archive's contents to exclude stale entries */ private StaleFileManager staleFileManager; /* - * Records whether open or create has been invoked. Otherwise we can't - * be sure that the staleFileManager field has been set. + * Records whether open or create has been invoked. Otherwise we can't be sure that the staleFileManager field has been + * set. */ - private boolean isOpenedOrCreated = false; + private boolean isOpenedOrCreated; /** * Open an abstract archive + * * @param uri path to the archive */ @Override @@ -124,6 +128,7 @@ public void open(URI uri) throws IOException { if (!uri.getScheme().equals("file")) { throw new IOException("Wrong scheme for FileArchive : " + uri.getScheme()); } + this.uri = uri; archive = new File(uri); if (!archive.exists()) { @@ -137,42 +142,41 @@ public void open(URI uri) throws IOException { * @see #open(URI) * @param uri a string representing URI */ - public void open(String uri) throws IOException - { + public void open(String uri) throws IOException { open(URI.create(uri)); } /** * Get the size of the archive + * * @return tje the size of this archive or -1 on error */ @Override public long getArchiveSize() throws NullPointerException, SecurityException { - if(uri == null) { + if (uri == null) { return -1; } - File tmpFile = new File(uri); - return(tmpFile.length()); + + return new File(uri).length(); } /** * creates a new abstract archive with the given path + * * @param uri path to create the archive */ @Override public void create(URI uri) throws IOException { - - this.uri = uri; archive = new File(uri); /* - * Get the stale file manager before creating the directories; it's - * slightly faster that way. + * Get the stale file manager before creating the directories; it's slightly faster that way. */ staleFileManager = StaleFileManager.Util.getInstance(archive); if (!archive.exists() && !archive.mkdirs()) { - throw new IOException("Unable to create directory for " + archive.getAbsolutePath()); + throw new IOException("Unable to create directory for " + archive.getAbsolutePath()); } + isOpenedOrCreated = true; } @@ -220,55 +224,53 @@ public boolean isDirectory(String name) { } /** - * @return an @see java.util.Enumeration of entries in this abstract - * archive + * @return an @see java.util.Enumeration of entries in this abstract archive */ @Override public Enumeration entries() { final List namesList = new ArrayList(); getListOfFiles(archive, namesList, null); + return Collections.enumeration(namesList); } /** - * Returns the enumeration of first level directories in this - * archive + * Returns the enumeration of first level directories in this archive + * * @return enumeration of directories under the root of this archive */ @Override public Collection getDirectories() throws IOException { List results = new ArrayList(); - if (archive != null) { - for (File f : archive.listFiles()) { - if (f.isDirectory() && isEntryValid(f)) { - results.add(f.getName()); + if (archive != null) { + for (File file : archive.listFiles()) { + if (file.isDirectory() && isEntryValid(file)) { + results.add(file.getName()); } } } + return results; } /** - * @return an @see java.util.Enumeration of entries in this abstract - * archive, providing the list of embedded archive to not count their - * entries as part of this archive + * @return an @see java.util.Enumeration of entries in this abstract archive, providing the list of embedded archive to + * not count their entries as part of this archive */ - public Enumeration entries(Enumeration embeddedArchives) { - List nameList = new ArrayList(); + public Enumeration entries(Enumeration embeddedArchives) { + List nameList = new ArrayList(); List massagedNames = new ArrayList(); while (embeddedArchives.hasMoreElements()) { - String subArchiveName = (String) embeddedArchives.nextElement(); - massagedNames.add(FileUtils.makeFriendlyFilenameExtension(subArchiveName)); + String subArchiveName = (String) embeddedArchives.nextElement(); + massagedNames.add(FileUtils.makeFriendlyFilenameExtension(subArchiveName)); } - getListOfFiles(archive, nameList, massagedNames); - return Collections.enumeration(nameList); - } + getListOfFiles(archive, nameList, massagedNames); + return Collections.enumeration(nameList); + } /** - * Returns an enumeration of the module file entries with the - * specified prefix. All elements in the enumeration are of - * type String. Each String represents a file name relative - * to the root of the module. + * Returns an enumeration of the module file entries with the specified prefix. All elements in the enumeration are of + * type String. Each String represents a file name relative to the root of the module. * * @param prefix the prefix of entries to be included * @return an enumeration of the archive file entries. @@ -287,10 +289,11 @@ public Enumeration entries(String prefix) { */ @Override public boolean exists() { - if (archive != null) { - return archive.exists(); + if (archive == null) { + return false; } - return false; + + return archive.exists(); } /** @@ -301,22 +304,29 @@ public boolean exists() { */ @Override public ReadableArchive getSubArchive(String name) throws IOException { - String subEntryName = getFileSubArchivePath(name); - File subEntry = new File(subEntryName); - if (subEntry.exists() && isEntryValid(subEntry)) { - deplLogger.log(DEBUG_LEVEL, "FileArchive.getSubArchive for {0} found that it is valid", - subEntry.getAbsolutePath()); - ReadableArchive result = archiveFactory.openArchive(subEntry); - if (result instanceof AbstractReadableArchive) { - ((AbstractReadableArchive) result).setParentArchive(this); - } - return result; - } else if (subEntry.exists()) { + File subEntry = new File(getFileSubArchivePath(name)); + + if (!subEntry.exists()) { + return null; + } + + if (!isEntryValid(subEntry)) { deplLogger.log(DEBUG_LEVEL, "FileArchive.getSubArchive for {0} found that it is not a valid entry; it is stale", subEntry.getAbsolutePath()); + + return null; } - return null; + + deplLogger.log(DEBUG_LEVEL, "FileArchive.getSubArchive for {0} found that it is valid", subEntry.getAbsolutePath()); + + ReadableArchive result = archiveFactory.openArchive(subEntry); + if (result instanceof AbstractReadableArchive) { + ((AbstractReadableArchive) result).setParentArchive(this); + } + + return result; } + /** * create or obtain an embedded archive within this abstraction. * @@ -329,17 +339,14 @@ public WritableArchive createSubArchive(String name) throws IOException { if (!subEntry.exists()) { // time to create a new sub directory if (!subEntry.exists() && !subEntry.mkdirs()) { - throw new IOException("Unable to create directory for " + subEntry.getAbsolutePath()); + throw new IOException("Unable to create directory for " + subEntry.getAbsolutePath()); } - deplLogger.log(DEBUG_LEVEL, "FileArchive.createSubArchive created dirs for {0}", - subEntry.getAbsolutePath()); + deplLogger.log(DEBUG_LEVEL, "FileArchive.createSubArchive created dirs for {0}", subEntry.getAbsolutePath()); } else { - deplLogger.log(DEBUG_LEVEL, "FileArchive.createSubArchive found existing dir for {0}", - subEntry.getAbsolutePath()); + deplLogger.log(DEBUG_LEVEL, "FileArchive.createSubArchive found existing dir for {0}", subEntry.getAbsolutePath()); /* - * This subdirectory already exists, so it might be marked as - * stale. Because this invocation is creating the subarchive in - * the current archive, the subdirectory is no longer stale. + * This subdirectory already exists, so it might be marked as stale. Because this invocation is creating the subarchive + * in the current archive, the subdirectory is no longer stale. */ staleFileManager().recordValidEntry(subEntry); } @@ -351,38 +358,7 @@ public WritableArchive createSubArchive(String name) throws IOException { } /** - * - * create or obtain an embedded archive within this abstraction. - * - * @param name name of the embedded archive. - */ - private String getFileSubArchivePath(String name) throws IOException { - // Convert name to native form. See bug #6345029 for more details. - name = name.replace('/', File.separatorChar); - File file = new File(name); - File subDir; - if (file.isAbsolute()) { - subDir = file; - } else { - // first we try to see if a sub directory with the right file - // name exist - subDir = new File(archive, FileUtils.makeFriendlyFilenameExtension(name)); - if (!subDir.exists()) { - // now we try to open a sub jar file... - subDir = new File(archive, name); - if (!subDir.exists()) { - // ok, nothing worked, reassing the name to the - // sub directory one - subDir = new File(archive, FileUtils.makeFriendlyFilenameExtension(name)); - } - } - } - return subDir.getPath(); - } - - /** - * Returns the existence of the given entry name - * The file name must be relative to the root of the module. + * Returns the existence of the given entry name The file name must be relative to the root of the module. * * @param name the file name relative to the root of the module. * @return the existence the given entry name. @@ -395,16 +371,15 @@ public boolean exists(String name) throws IOException { } /** - * @return a @see java.io.InputStream for an existing entry in - * the current abstract archive + * @return a @see java.io.InputStream for an existing entry in the current abstract archive * @param name the entry name */ @Override public InputStream getEntry(String name) throws IOException { File input = getEntryFile(name); - if (!input.exists() || input.isDirectory() - || ! isEntryValid(input)) { // If name corresponds to directory, return null as it can not be opened + if (!input.exists() || input.isDirectory() || !isEntryValid(input)) { // If name corresponds to directory, return null as it can not + // be opened return null; } FileInputStream fis = new FileInputStream(input); @@ -423,11 +398,6 @@ public InputStream getEntry(String name) throws IOException { } } - private File getEntryFile(String name) { - name = name.replace('/', File.separatorChar); - return new File(archive, name); - } - /** * Returns the entry size for a given entry name or 0 if not known * @@ -438,7 +408,7 @@ private File getEntryFile(String name) { public long getEntrySize(String name) { name = name.replace('/', File.separatorChar); File input = new File(archive, name); - if (!input.exists() || ! isEntryValid(input)) { + if (!input.exists() || !isEntryValid(input)) { return 0; } return input.length(); @@ -452,7 +422,7 @@ public Manifest getManifest() throws IOException { InputStream is = null; try { is = getEntry(JarFile.MANIFEST_NAME); - if (is!=null) { + if (is != null) { Manifest m = new Manifest(is); return m; } @@ -485,16 +455,136 @@ public boolean renameTo(String name) { } /** - * Reports whether the entry is valid, in the sense that if this - * archive has been created during this execution then the entry - * requested was created later than the archive itself. + * Closes the current entry + */ + @Override + public void closeEntry() throws IOException { + if (os != null) { + os.flush(); + os.close(); + os = null; + } + } + + /** + * @returns an @see java.io.OutputStream for a new entry in this current abstract archive. + * @param name the entry name + */ + @Override + public OutputStream putNextEntry(String name) throws java.io.IOException { + name = name.replace('/', File.separatorChar); + + File newFile = new File(archive, name); + if (newFile.exists()) { + if (!deleteEntry(name, false /* isLogging */) && uri != null) { + deplLogger.log(Level.FINE, "Could not delete file {0} in FileArchive {1} during putNextEntry; continuing", + new Object[] { name, uri.toASCIIString() }); + } + } + // if the entry name contains directory structure, we need + // to create those directories first. + if (name.lastIndexOf(File.separatorChar) != -1) { + String dirs = name.substring(0, name.lastIndexOf(File.separatorChar)); + File dirsFile = new File(archive, dirs); + if (!dirsFile.exists() && !dirsFile.mkdirs()) { + throw new IOException("Unable to create directory for " + dirsFile.getAbsolutePath()); + } + } + staleFileManager().recordValidEntry(newFile); + os = new BufferedOutputStream(new FileOutputStream(newFile)); + return os; + } + + /** + * Returns the name portion of the archive's URI. + *

+ * For FileArhive the name is all of the path that follows the last slash (ignoring a slash at the end of the path). + *

+ * Here are some example archive names for the specified FileArchive paths: + *

    + *
  • /a/b/c/d/ -> d + *
  • /a/b/c/d -> d + *
  • /a/b/c.jar -> c.jar + *
+ * + * @return the name of the archive + * + */ + @Override + public String getName() { + return Util.getURIName(getURI()); + } + + @Override + public String toString() { + return getName(); + } + + /** + * @return true if this archive abstraction supports overwriting of elements + * + */ + public boolean supportsElementsOverwriting() { + return true; + } + + /** + * delete an entry in the archive + * + * @param name the entry name + * @return true if the entry was successfully deleted + * + */ + public boolean deleteEntry(String name) { + return deleteEntry(name, true); + } + + + // ## Private methods + + /** + * + * create or obtain an embedded archive within this abstraction. + * + * @param name name of the embedded archive. + */ + private String getFileSubArchivePath(String name) throws IOException { + // Convert name to native form. See bug #6345029 for more details. + name = name.replace('/', File.separatorChar); + File file = new File(name); + File subDir; + if (file.isAbsolute()) { + subDir = file; + } else { + // first we try to see if a sub directory with the right file + // name exist + subDir = new File(archive, FileUtils.makeFriendlyFilenameExtension(name)); + if (!subDir.exists()) { + // now we try to open a sub jar file... + subDir = new File(archive, name); + if (!subDir.exists()) { + // ok, nothing worked, reassing the name to the + // sub directory one + subDir = new File(archive, FileUtils.makeFriendlyFilenameExtension(name)); + } + } + } + return subDir.getPath(); + } + + private File getEntryFile(String name) { + name = name.replace('/', File.separatorChar); + return new File(archive, name); + } + + /** + * Reports whether the entry is valid, in the sense that if this archive has been created during this execution then the + * entry requested was created later than the archive itself. *

- * It is possible (for example, on Windows) for GlassFish to want to create - * a new archive in a directory that already exists and contains stale - * "left-over" files from a previous deployment, for example. This method - * causes the FileArchive implementation to hide any files that - * reside in the directory for an archive that was created during this VM - * execution but were not explicitly added to the archive using putNextEntry. + * It is possible (for example, on Windows) for GlassFish to want to create a new archive in a directory that already + * exists and contains stale "left-over" files from a previous deployment, for example. This method causes the + * FileArchive implementation to hide any files that reside in the directory for an archive that was created during this + * VM execution but were not explicitly added to the archive using putNextEntry. * * @param entry file to check * @return @@ -512,14 +602,13 @@ private boolean isEntryValid(final File entry, final boolean isLogging, final Lo } private StaleFileManager myStaleFileManager() { - /* - * If the FileArchive has been opened or created then its - * staleFileManager has been set. - */ - if ( ! isOpenedOrCreated) { - throw new IllegalStateException(); - } - return staleFileManager; + /* + * If the FileArchive has been opened or created then its staleFileManager has been set. + */ + if (!isOpenedOrCreated) { + throw new IllegalStateException(); + } + return staleFileManager; } private StaleFileManager staleFileManager() { @@ -535,8 +624,8 @@ private StaleFileManager staleFileManager() { } /** - * Reports whether the entry is valid, in the sense that the entry is - * more recent than the archive itself. + * Reports whether the entry is valid, in the sense that the entry is more recent than the archive itself. + * * @param entryName name of the entry to check * @return */ @@ -556,9 +645,8 @@ private boolean deleteDir(File directory) throws IOException { // delete contents /* - *Do not recursively delete the contents if the current directory - *is a symbolic link. - */ + * Do not recursively delete the contents if the current directory is a symbolic link. + */ /* * Fix for bug Glassfish-21261 , method safeIsRealDirectory(File) might return false in case if the currently directory @@ -566,11 +654,11 @@ private boolean deleteDir(File directory) throws IOException { */ if (!Files.isSymbolicLink(directory.toPath())) { File[] entries = directory.listFiles(); - for (int i=0;i files, List embeddedArchives) { @@ -594,23 +681,21 @@ private void getListOfFiles(File directory, List files, List embeddedArc } /** - * Adds the files in the specified directory to the collection of files - * already assembled. Excludes the contents of embedded archives in the current archive which - * appear in the file tree anchored at the given directory. + * Adds the files in the specified directory to the collection of files already assembled. Excludes the contents of + * embedded archives in the current archive which appear in the file tree anchored at the given directory. + * * @param directory the directory to scan for files * @param files collection of files already assembled to which this directory's files are to be added * @param embeddedArchives collection of embedded archives in the current archive * @param logger logger to which to report inability to get the list of files from the directory */ void getListOfFiles(File directory, List files, List embeddedArchives, final Logger logger) { - if(archive == null || directory == null || !directory.isDirectory()) + if (archive == null || directory == null || !directory.isDirectory()) return; final File[] fileList = directory.listFiles(); if (fileList == null) { - deplLogger.log(Level.WARNING, - FILE_LIST_FAILURE, - directory.getAbsolutePath()); - return; + deplLogger.log(Level.WARNING, FILE_LIST_FAILURE, directory.getAbsolutePath()); + return; } for (File aList : fileList) { String fileName = aList.getAbsolutePath().substring(archive.getAbsolutePath().length() + 1); @@ -632,26 +717,10 @@ void getListOfFiles(File directory, List files, List embeddedArchives, f } } - /** @return true if this archive abstraction supports overwriting of elements - * - */ - public boolean supportsElementsOverwriting() { - return true; - } - - /** delete an entry in the archive - * @param name the entry name - * @return true if the entry was successfully deleted - * - */ - public boolean deleteEntry(String name) { - return deleteEntry(name, true); - } - private boolean deleteEntry(String name, final boolean isLogging) { name = name.replace('/', File.separatorChar); File input = new File(archive, name); - if (!input.exists() || ! isEntryValid(input, isLogging)) { + if (!input.exists() || !isEntryValid(input, isLogging)) { return false; } final boolean result = input.delete(); @@ -659,78 +728,16 @@ private boolean deleteEntry(String name, final boolean isLogging) { return result; } - /** - * Closes the current entry - */ - @Override - public void closeEntry() throws IOException { - if (os!=null) { - os.flush(); - os.close(); - os = null; - } - } - /** - * @returns an @see java.io.OutputStream for a new entry in this - * current abstract archive. - * @param name the entry name - */ - @Override - public OutputStream putNextEntry(String name) throws java.io.IOException { - name = name.replace('/', File.separatorChar); - - File newFile = new File(archive, name); - if (newFile.exists()) { - if (!deleteEntry(name, false /* isLogging */) && uri != null) { - deplLogger.log(Level.FINE, - "Could not delete file {0} in FileArchive {1} during putNextEntry; continuing", - new Object[]{name, uri.toASCIIString()}); - } - } - // if the entry name contains directory structure, we need - // to create those directories first. - if (name.lastIndexOf(File.separatorChar)!=-1) { - String dirs = name.substring(0, name.lastIndexOf(File.separatorChar)); - File dirsFile = new File(archive, dirs); - if (!dirsFile.exists() && !dirsFile.mkdirs()) { - throw new IOException("Unable to create directory for " + dirsFile.getAbsolutePath()); - } - } - staleFileManager().recordValidEntry(newFile); - os = new BufferedOutputStream(new FileOutputStream(newFile)); - return os; - } - - /** - * Returns the name portion of the archive's URI. - *

- * For FileArhive the name is all of the path that follows - * the last slash (ignoring a slash at the end of the path). - *

- * Here are some example archive names for the specified FileArchive paths: - *

    - *
  • /a/b/c/d/ -> d - *
  • /a/b/c/d -> d - *
  • /a/b/c.jar -> c.jar - *
- * @return the name of the archive - * - */ - @Override - public String getName() { - return Util.getURIName(getURI()); - } /** - * API which FileArchive methods should use for dealing with the StaleFileManager - * implementation. + * API which FileArchive methods should use for dealing with the StaleFileManager implementation. */ public static interface StaleFileManager { /** - * Returns whether the specified file is valid - that is, is dated - * after the archive was created. + * Returns whether the specified file is valid - that is, is dated after the archive was created. + * * @param f the file to check * @param isLogging whether to log a warning about the check of the entry * @return true if the file is valid; false otherwise @@ -740,8 +747,8 @@ public static interface StaleFileManager { boolean isEntryValid(File f, boolean isLogging, Logger logger); /** - * Returns whether the specified file is for the hidden timestamp file - * which FileArchive uses internally. + * Returns whether the specified file is for the hidden timestamp file which FileArchive uses internally. + * * @param f the file to check * @return true if the File is the hidden timestamp file; false otherwise */ @@ -762,12 +769,12 @@ private static File markerFile(final File archive) { } /** - * Creates a marker file in the archive directory - if it still - * exists and contains any stale files. + * Creates a marker file in the archive directory - if it still exists and contains any stale files. + * * @param archive the File for the archive to mark */ public static void markDeletedArchive(final Archive archive) { - if ( ! (archive instanceof FileArchive)) { + if (!(archive instanceof FileArchive)) { return; } @@ -776,17 +783,17 @@ public static void markDeletedArchive(final Archive archive) { } /** - * Creates a marker file in the archive directory - if it still - * exists and contains any stale files. + * Creates a marker file in the archive directory - if it still exists and contains any stale files. + * * @param archive the File for the archive to mark */ public static void markDeletedArchive(final File archiveFile) { - if ( ! archiveFile.exists()) { + if (!archiveFile.exists()) { return; } - final IteratorstaleFileIt = findFiles(archiveFile); - if ( ! staleFileIt.hasNext()) { + final Iterator staleFileIt = findFiles(archiveFile); + if (!staleFileIt.hasNext()) { return; } @@ -797,7 +804,7 @@ public static void markDeletedArchive(final File archiveFile) { } catch (FileNotFoundException ex) { throw new RuntimeException(ex); } - for ( ; staleFileIt.hasNext(); ) { + for (; staleFileIt.hasNext();) { final URI relativeURI = archiveURI.relativize(staleFileIt.next().toURI()); ps.println(relativeURI); deplLogger.log(DEBUG_LEVEL, "FileArchive.StaleFileManager recording left-over file {0}", relativeURI); @@ -806,13 +813,12 @@ public static void markDeletedArchive(final File archiveFile) { } /** - * Returns an Iterator over the files contained in the directory tree - * anchored at the given directory, excluding any stale file - * marker file. + * Returns an Iterator over the files contained in the directory tree anchored at the given directory, excluding any + * stale file marker file. *

- * For efficiency, this implementation avoids creating a list of - * all the files in the directory tree all at once. It traverses - * each directory as it encounters it. + * For efficiency, this implementation avoids creating a list of all the files in the directory tree all at once. It + * traverses each directory as it encounters it. + * * @param dir root of the directory tree to be traversed * @return Iterator over the contained files */ @@ -823,12 +829,10 @@ private static Iterator findFiles(final File dir) { private final ListIterator fileListIt; { - fileList = new ArrayList(Arrays.asList(dir.listFiles( - new MarkerExcluderFileFilter()))); + fileList = new ArrayList(Arrays.asList(dir.listFiles(new MarkerExcluderFileFilter()))); fileListIt = fileList.listIterator(); } - @Override public boolean hasNext() { return fileListIt.hasNext(); @@ -839,12 +843,10 @@ public File next() { final File result = fileListIt.next(); if (result.isDirectory()) { - for (File f : result.listFiles( - new MarkerExcluderFileFilter())) { + for (File f : result.listFiles(new MarkerExcluderFileFilter())) { fileListIt.add(f); /* - * Back up so the next invocation of this method - * will return the just-added entry. + * Back up so the next invocation of this method will return the just-added entry. */ fileListIt.previous(); } @@ -864,19 +866,18 @@ private static final class MarkerExcluderFileFilter implements FileFilter { @Override public boolean accept(File pathname) { - return ! pathname.getName().equals(MARKER_FILE_PATH); + return !pathname.getName().equals(MARKER_FILE_PATH); } } /** * Factory method for a StaleFileManager. *

- * Callers should invoke this method only after they have finished with - * the FileArchive and have tried to delete it. If the directory - * for the archive remains then it contains one or more stale files - * that could not be deleted, and the factory method returns a - * instance that tracks the stale files. If the directory no longer - * exists then the delete succeeded, there are + * Callers should invoke this method only after they have finished with the FileArchive and have tried to delete it. If + * the directory for the archive remains then it contains one or more stale files that could not be deleted, and the + * factory method returns a instance that tracks the stale files. If the directory no longer exists then the delete + * succeeded, there are + * * @param archive the directory to contain the archive * @return StaleFileManager for the FileArchive to use */ @@ -893,8 +894,7 @@ public static StaleFileManager getInstance(final File archive) throws IOExceptio /** * Acts as a stale file manager but does no real work. *

- * Used as a stale file manager for an archive that was successfully - * deleted and therefore contains no stale files. + * Used as a stale file manager for an archive that was successfully deleted and therefore contains no stale files. */ private static class StaleFileManagerImplNoop implements StaleFileManager { @@ -946,6 +946,7 @@ private StaleFileManagerImpl(final File archive) throws FileNotFoundException, I /** * Reads entry names of stale files from the marker file, if it exists. + * * @param markerFile the marker file to be read * @return Collection of stale entry names. * @throws FileNotFoundException if the marker file existed initially but vanished before it could be opened @@ -953,7 +954,7 @@ private StaleFileManagerImpl(final File archive) throws FileNotFoundException, I */ private static Collection readStaleEntryNames(final File markerFile) throws FileNotFoundException, IOException { final Collection result = new ArrayList(); - if ( ! markerFile.exists()) { + if (!markerFile.exists()) { return result; } LineNumberReader reader = null; @@ -972,7 +973,7 @@ private static Collection readStaleEntryNames(final File markerFile) thr } if (isShowEntriesToBeSkipped) { deplLogger.log(DEBUG_LEVEL, "FileArchive.StaleFileManager will skip following file(s): {0}{1}", - new Object[] {LINE_SEP, entriesToSkip.toString()}); + new Object[] { LINE_SEP, entriesToSkip.toString() }); } return result; } finally { @@ -987,15 +988,12 @@ public boolean isEntryValid(final File f, final boolean isLogging) { return isEntryValid(f, isLogging, deplLogger); } - @Override public boolean isEntryValid(final File f, final boolean isLogging, final Logger logger) { - final boolean result = ( ! isEntryMarkerFile(f)) && - ( ! staleEntryNames.contains(archiveURI.relativize(f.toURI()).getPath())); - if ( ! result && ! isEntryMarkerFile(f) && isLogging) { - deplLogger.log(Level.WARNING, - STALE_FILES_SKIPPED, - new Object[] {archiveURI.relativize(f.toURI()).toASCIIString(), archiveFile.getAbsolutePath()}); + final boolean result = (!isEntryMarkerFile(f)) && (!staleEntryNames.contains(archiveURI.relativize(f.toURI()).getPath())); + if (!result && !isEntryMarkerFile(f) && isLogging) { + deplLogger.log(Level.WARNING, STALE_FILES_SKIPPED, + new Object[] { archiveURI.relativize(f.toURI()).toASCIIString(), archiveFile.getAbsolutePath() }); } return result; } @@ -1008,22 +1006,21 @@ public boolean isEntryMarkerFile(File f) { /** * Records that the specified file is valid. *

- * If the file had previously been marked as stale, it will no longer be - * considered stale. + * If the file had previously been marked as stale, it will no longer be considered stale. + * * @param f the File which is now valid */ @Override public void recordValidEntry(File f) { if (updateStaleEntry(f, "FileArchive.StaleFileManager marking formerly stale entry {0} as active")) { /* - * Process not only the file itself but the directories from the - * file to the owning archive, since the directories are now - * implicitly valid as well. + * Process not only the file itself but the directories from the file to the owning archive, since the directories are + * now implicitly valid as well. */ do { f = f.getParentFile(); updateStaleEntry(f, "FileArchive.StaleFileManager marking formerly stale ancestor {0} as active"); - } while ( ! f.equals(archiveFile)); + } while (!f.equals(archiveFile)); flush(); } } @@ -1032,9 +1029,8 @@ public void recordValidEntry(File f) { public void recordDeletedEntry(File f) { if (updateStaleEntry(f, "FileArchive.StaleFileManager recording deletion of entry {0}")) { /* - * If there are no other stale files in the same directory as - * the file just deleted, then remove the directory from - * the stale files collection and check its ancestors. + * If there are no other stale files in the same directory as the file just deleted, then remove the directory from the + * stale files collection and check its ancestors. */ do { if (isStaleEntryInDir(f.getParentFile())) { @@ -1042,7 +1038,7 @@ public void recordDeletedEntry(File f) { } updateStaleEntry(f, "FileArchive.StaleFileManager recording that formerly stale directory {0} is no longer stale"); f = f.getParentFile(); - } while ( ! f.equals(archiveFile)); + } while (!f.equals(archiveFile)); flush(); } @@ -1051,9 +1047,9 @@ public void recordDeletedEntry(File f) { private boolean isStaleEntryInDir(final File dir) { final String dirURIPath = archiveURI.relativize(dir.toURI()).getPath(); for (String staleEntryName : staleEntryNames) { - if (staleEntryName.startsWith(dirURIPath) && ! staleEntryName.equals(dirURIPath)) { + if (staleEntryName.startsWith(dirURIPath) && !staleEntryName.equals(dirURIPath)) { deplLogger.log(DEBUG_LEVEL, "FileArchive.StaleFileManager.isStaleEntryInDir found remaining stale entry {0} in {1}", - new Object[] {staleEntryName, dir.getAbsolutePath()}); + new Object[] { staleEntryName, dir.getAbsolutePath() }); return true; } } @@ -1069,11 +1065,10 @@ private boolean updateStaleEntry(File f, final String msg) { final String entryName = archiveURI.relativize(f.toURI()).toASCIIString(); final boolean wasStale = staleEntryNames.remove(entryName); if (wasStale) { - deplLogger.log(DEBUG_LEVEL, msg, - entryName); + deplLogger.log(DEBUG_LEVEL, msg, entryName); } else { deplLogger.log(DEBUG_LEVEL, "updateStaleEntry did not find {0} in the stale entries {1}", - new Object[] {entryName, staleEntryNames.toString()}); + new Object[] { entryName, staleEntryNames.toString() }); } return wasStale; } @@ -1083,14 +1078,15 @@ public void flush() { if (staleEntryNames.isEmpty()) { deplLogger.log(DEBUG_LEVEL, "FileArchive.StaleFileManager.flush deleting marker file; no more stale entries"); final File marker = Util.markerFile(archiveFile); - if ( ! marker.exists() || marker.delete()) { + if (!marker.exists() || marker.delete()) { return; } /* - * Couldn't delete the marker file, so try to write out an empty one - * so its old contents will not confuse the stale file manager. + * Couldn't delete the marker file, so try to write out an empty one so its old contents will not confuse the stale file + * manager. */ - deplLogger.log(Level.FINE, "FileArchive.StatleFileManager.flush could not delete marker file {0}; continuing by writing out an empty marker file", + deplLogger.log(Level.FINE, + "FileArchive.StatleFileManager.flush could not delete marker file {0}; continuing by writing out an empty marker file", marker.getAbsolutePath()); } PrintStream ps = null; @@ -1104,9 +1100,8 @@ public void flush() { } ps.close(); deplLogger.log(DEBUG_LEVEL, "FileArchive.StaleFileManager.flush rewrote on-disk file {0} containing {1}", - new Object[] {markerFile.getAbsolutePath(), staleEntryNames.toString()}); + new Object[] { markerFile.getAbsolutePath(), staleEntryNames.toString() }); } - } } diff --git a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/InputJarArchive.java b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/InputJarArchive.java index b229a327c53..f05fa30cf07 100644 --- a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/InputJarArchive.java +++ b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/InputJarArchive.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,126 +17,112 @@ package com.sun.enterprise.deployment.deploy.shared; -import com.sun.enterprise.util.i18n.StringManager; -import com.sun.enterprise.util.io.FileUtils; -import java.net.MalformedURLException; -import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.deployment.common.DeploymentUtils; -import org.jvnet.hk2.annotations.Service; - -import org.glassfish.hk2.api.PerLookup; - -import java.io.*; -import java.util.*; +import static com.sun.enterprise.util.io.FileUtils.deleteFile; +import static com.sun.enterprise.util.io.FileUtils.renameFile; +import static java.util.jar.JarFile.MANIFEST_NAME; +import static java.util.logging.Level.WARNING; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.AbstractCollection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.WeakHashMap; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; -import java.net.URI; -import java.net.URISyntaxException; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.hk2.api.PerLookup; import org.glassfish.logging.annotation.LogMessageInfo; +import org.jvnet.hk2.annotations.Service; + +import com.sun.enterprise.util.i18n.StringManager; /** - * This implementation of the Archive deal with reading - * jar files either from a JarFile or from a JarInputStream + * This implementation of the Archive deal with reading jar files either from a JarFile or from a JarInputStream * * @author Jerome Dochez */ -@Service(name="jar") +@Service(name = "jar") @PerLookup public class InputJarArchive extends JarArchive implements ReadableArchive { public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; + private static StringManager localStrings = StringManager.getManager(InputJarArchive.class); - @LogMessageInfo(message = " file open failure; file = {0}", level="WARNING") + @LogMessageInfo(message = " file open failure; file = {0}", level = "WARNING") private static final String FILE_OPEN_FAILURE = "NCLS-DEPLOYMENT-00019"; - @LogMessageInfo(message = "exception message: {0} -- invalid zip file: {1}", level="WARNING") + @LogMessageInfo(message = "exception message: {0} -- invalid zip file: {1}", level = "WARNING") private static final String INVALID_ZIP_FILE = "NCLS-DEPLOYMENT-00020"; // the file we are currently mapped to - volatile protected JarFile jarFile=null; + volatile protected JarFile jarFile; // in case this abstraction is dealing with a jar file // within a jar file, the jarFile will be null and this // JarInputStream will contain the - volatile protected JarInputStream jarIS=null; + volatile protected JarInputStream jarIS; // the archive Uri volatile private URI uri; // parent jar file for embedded jar - private InputJarArchive parentArchive=null; - - private static StringManager localStrings = StringManager.getManager(InputJarArchive.class); + private InputJarArchive parentArchive; // track entry enumerations to close them if needed when the archive is closed - private final WeakHashMap entryEnumerations = - new WeakHashMap(); + private final WeakHashMap entryEnumerations = new WeakHashMap(); /** - * Get the size of the archive - * @return tje the size of this archive or -1 on error - */ - public long getArchiveSize() throws NullPointerException, SecurityException { - if(uri == null) { - return -1; - } - File tmpFile = new File(uri); - return(tmpFile.length()); - } - - /** @return an @see java.io.OutputStream for a new entry in this - * current abstract archive. - * @param name the entry name + * Open an abstract archive + * + * @param uri the path to the archive */ - public OutputStream addEntry(String name) throws IOException { - throw new UnsupportedOperationException("Cannot write to an JAR archive open for reading"); + @Override + public void open(URI uri) throws IOException { + this.uri = uri; + jarFile = getJarFile(uri); } /** - * close the abstract archive + * Get the size of the archive + * + * @return tje the size of this archive or -1 on error */ - public synchronized void close() throws IOException { - for (EntryEnumeration e : entryEnumerations.keySet()) { - e.closeNoRemove(); - } - entryEnumerations.clear(); - if (jarFile!=null) { - jarFile.close(); - jarFile=null; - } - if (jarIS!=null) { - jarIS.close(); - jarIS=null; + @Override + public long getArchiveSize() throws NullPointerException, SecurityException { + if (uri == null) { + return -1; } - } - private synchronized EntryEnumeration recordEntryEnumeration(final EntryEnumeration e) { - entryEnumerations.put(e, null); - return e; + return new File(uri).length(); } /** - * Returns the collection of first level directories in this - * archive. + * Returns the collection of first level directories in this archive. *

- * Avoid having to fetch all the entries if we can avoid it. The only time - * we must do that is if size() is invoked on the collection. Use - * the CollectionWrappedEnumeration for this optimization which will - * create a full in-memory list of the entries only if and when needed - * to satisfy the size() method. + * Avoid having to fetch all the entries if we can avoid it. The only time we must do that is if size() is invoked on + * the collection. Use the CollectionWrappedEnumeration for this optimization which will create a full in-memory list of + * the entries only if and when needed to satisfy the size() method. * * @return collection of directories under the root of this archive */ @Override public Collection getDirectories() throws IOException { - return new CollectionWrappedEnumeration( - new CollectionWrappedEnumeration.EnumerationFactory() { + return new CollectionWrappedEnumeration(new CollectionWrappedEnumeration.EnumerationFactory() { @Override public Enumeration enumeration() { @@ -144,116 +131,84 @@ public Enumeration enumeration() { }); } - /** - * creates a new abstract archive with the given path - * - * @param uri the path to create the archive - */ - public void create(URI uri) throws IOException { - throw new UnsupportedOperationException("Cannot write to an JAR archive open for reading"); - } - @Override public Enumeration entries() { return entries(false); } - /** - * Returns an enumeration of the entry names in the archive. - * - * @param topLevelDirectoriesOnly whether to report directories only or non-directories only - * @return enumeration of the matching entry names, excluding the manifest - */ - private Enumeration entries(final boolean topLevelDirectoriesOnly) { - try { - /* - * We have two decisions to make: - * - * 1. whether the caller wants top-level directory entries or all - * non-directory entries enumerated, and - * - * 2. how to obtain the sequence of JarEntry objects which we filter - * before returning their names. - * - */ - return recordEntryEnumeration(createEntryEnumeration(topLevelDirectoriesOnly)); - } catch (IOException ex) { - throw new RuntimeException(ex); + @Override + public JarEntry getJarEntry(String name) { + if (jarFile == null) { + return null; } + + return jarFile.getJarEntry(name); } /** - * @return an @see java.util.Enumeration of entries in this abstract - * archive, providing the list of embedded archive to not count their - * entries as part of this archive + * @return true if this abstract archive maps to an existing jar file */ - public Enumeration entries(Enumeration embeddedArchives) { - // jar file are not recursive - return entries(); - } - - public JarEntry getJarEntry(String name) { - if (jarFile!=null) { - return jarFile.getJarEntry(name); - } - return null; + @Override + public boolean exists() { + return jarFile != null; } /** - * Returns the existence of the given entry name - * The file name must be relative to the root of the module. + * Returns the existence of the given entry name The file name must be relative to the root of the module. * - * @param name the file name relative to the root of the module. * @return the existence the given entry name. + * @param name the file name relative to the root of the module. * @return the existence the given entry name. */ + @Override public boolean exists(String name) throws IOException { - if (jarFile!=null) { - ZipEntry ze = jarFile.getEntry(name); - if (ze!=null) { - return true; - } + if (jarFile == null) { + return false; } - return false; + + return jarFile.getEntry(name) != null; } /** - * @return a @see java.io.InputStream for an existing entry in - * the current abstract archive + * @return a @see java.io.InputStream for an existing entry in the current abstract archive * @param entryName entry name */ + @Override public InputStream getEntry(String entryName) throws IOException { - if (jarFile!=null) { - ZipEntry ze = jarFile.getEntry(entryName); - if (ze!=null) { - return new BufferedInputStream(jarFile.getInputStream(ze)); - } else { + if (jarFile != null) { + ZipEntry zipEntry = jarFile.getEntry(entryName); + if (zipEntry == null) { return null; } - } else - if ((parentArchive != null) && (parentArchive.jarFile != null)) { - JarEntry je; - // close the current input stream - if (jarIS!=null) { - jarIS.close(); - } - // reopen the embedded archive and position the input stream - // at the beginning of the desired element - JarEntry archiveJarEntry = (uri != null)? parentArchive.jarFile.getJarEntry(uri.getSchemeSpecificPart()) : null; - if (archiveJarEntry == null) { - return null; - } - jarIS = new JarInputStream(parentArchive.jarFile.getInputStream(archiveJarEntry)); - do { - je = jarIS.getNextJarEntry(); - } while (je!=null && !je.getName().equals(entryName)); - if (je!=null) { - return new BufferedInputStream(jarIS); - } else { - return null; - } - } else { + return new BufferedInputStream(jarFile.getInputStream(zipEntry)); + } + + if (parentArchive == null || parentArchive.jarFile == null) { + return null; + } + + // Close the current input stream + if (jarIS != null) { + jarIS.close(); + } + + // Reopen the embedded archive and position the input stream + // at the beginning of the desired element + JarEntry archiveJarEntry = (uri != null) ? parentArchive.jarFile.getJarEntry(uri.getSchemeSpecificPart()) : null; + if (archiveJarEntry == null) { return null; } + + JarEntry jarEntry; + jarIS = new JarInputStream(parentArchive.jarFile.getInputStream(archiveJarEntry)); + do { + jarEntry = jarIS.getNextJarEntry(); + } while (jarEntry != null && !jarEntry.getName().equals(entryName)); + + if (jarEntry == null) { + return null; + } + + return new BufferedInputStream(jarIS); } /** @@ -262,79 +217,57 @@ public InputStream getEntry(String entryName) throws IOException { * @param name the entry name * @return the entry size */ + @Override public long getEntrySize(String name) { - if (jarFile!=null) { - ZipEntry ze = jarFile.getEntry(name); - if (ze!=null) { - return ze.getSize(); - } + if (jarFile == null) { + return 0; } - return 0; - } - /** Open an abstract archive - * @param uri the path to the archive - */ - public void open(URI uri) throws IOException { - this.uri = uri; - jarFile = getJarFile(uri); - } - - /** - * @return a JarFile instance for a file path - */ - protected static JarFile getJarFile(URI uri) throws IOException { - JarFile jf = null; - try { - File file = new File(uri); - if (file.exists()) { - jf = new JarFile(file); - } - } catch(IOException e) { - deplLogger.log(Level.WARNING, - FILE_OPEN_FAILURE, - new Object[]{uri}); - // add the additional information about the path - // since the IOException from jdk doesn't include that info - String additionalInfo = localStrings.getString( - "enterprise.deployment.invalid_zip_file", uri); - deplLogger.log(Level.WARNING, - INVALID_ZIP_FILE, - new Object[] { e.getLocalizedMessage(), additionalInfo } ); + ZipEntry zipEntry = jarFile.getEntry(name); + if (zipEntry == null) { + return 0; } - return jf; - } + return zipEntry.getSize(); + } /** * @return the manifest information for this abstract archive */ + @Override public Manifest getManifest() throws IOException { - if (jarFile!=null) { + if (jarFile != null) { return jarFile.getManifest(); } - if (parentArchive!=null) { - // close the current input stream - if (jarIS!=null) { - jarIS.close(); - } - // reopen the embedded archive and position the input stream - // at the beginning of the desired element - if (jarIS==null) { - jarIS = new JarInputStream(parentArchive.jarFile.getInputStream(parentArchive.jarFile.getJarEntry(uri.getSchemeSpecificPart()))); - } - Manifest m = jarIS.getManifest(); - if (m==null) { - java.io.InputStream is = getEntry(java.util.jar.JarFile.MANIFEST_NAME); - if (is!=null) { - m = new Manifest(); - m.read(is); - is.close(); - } + + if (parentArchive == null) { + return null; + } + + // Close the current input stream + if (jarIS != null) { + jarIS.close(); + } + + // Reopen the embedded archive and position the input stream + // at the beginning of the desired element + if (jarIS == null) { + jarIS = new JarInputStream( + parentArchive.jarFile.getInputStream( + parentArchive.jarFile.getJarEntry(uri.getSchemeSpecificPart()))); + } + + Manifest manifest = jarIS.getManifest(); + if (manifest == null) { + InputStream is = getEntry(MANIFEST_NAME); + if (is != null) { + manifest = new Manifest(); + manifest.read(is); + is.close(); } - return m; } - return null; + + return manifest; } /** @@ -342,64 +275,63 @@ public Manifest getManifest() throws IOException { * * @return the path for this archive. */ + @Override public URI getURI() { return uri; } - /** - * @return true if this abstract archive maps to an existing - * jar file - */ - public boolean exists() { - return jarFile!=null; - } - /** * deletes the underlying jar file */ + @Override public boolean delete() { - if (jarFile==null) { + if (jarFile == null) { return false; } + try { jarFile.close(); jarFile = null; } catch (IOException ioe) { return false; } - return FileUtils.deleteFile(new File(uri)); + + return deleteFile(new File(uri)); } /** * rename the underlying jar file */ + @Override public boolean renameTo(String name) { - if (jarFile==null) { + if (jarFile == null) { return false; } + try { jarFile.close(); jarFile = null; } catch (IOException ioe) { return false; } - return FileUtils.renameFile(new File(uri), new File(name)); + + return renameFile(new File(uri), new File(name)); } /** - * @return an Archive for an embedded archive indentified with - * the name parameter + * @return an Archive for an embedded archive indentified with the name parameter */ + @Override public ReadableArchive getSubArchive(String name) throws IOException { - if (jarFile!=null) { + if (jarFile != null) { // for now, I only support one level down embedded archives InputJarArchive ija = new InputJarArchive(); JarEntry je = jarFile.getJarEntry(name); - if (je!=null) { + if (je != null) { JarInputStream jis = new JarInputStream(new BufferedInputStream(jarFile.getInputStream(je))); try { - ija.uri = new URI("jar",name, null); - } catch(URISyntaxException e) { + ija.uri = new URI("jar", name, null); + } catch (URISyntaxException e) { // do nothing } ija.jarIS = jis; @@ -407,14 +339,109 @@ public ReadableArchive getSubArchive(String name) throws IOException { return ija; } } + return null; } /** - * Creates the correct type of entry enumeration, depending on whether the - * current archive is nested or not and depending on whether the caller - * requested top-level directory entries or all non-directory entries be returned - * in the enumeration. + * close the abstract archive + */ + @Override + public synchronized void close() throws IOException { + for (EntryEnumeration e : entryEnumerations.keySet()) { + e.closeNoRemove(); + } + + entryEnumerations.clear(); + if (jarFile != null) { + jarFile.close(); + jarFile = null; + } + + if (jarIS != null) { + jarIS.close(); + jarIS = null; + } + } + + /** + * @return an @see java.util.Enumeration of entries in this abstract archive, providing the list of embedded archive to + * not count their entries as part of this archive + */ + public Enumeration entries(Enumeration embeddedArchives) { + // jar file are not recursive + return entries(); + } + + /** + * @return an @see java.io.OutputStream for a new entry in this current abstract archive. + * @param name the entry name + */ + public OutputStream addEntry(String name) throws IOException { + throw new UnsupportedOperationException("Cannot write to an JAR archive open for reading"); + } + + /** + * creates a new abstract archive with the given path + * + * @param uri the path to create the archive + */ + public void create(URI uri) throws IOException { + throw new UnsupportedOperationException("Cannot write to an JAR archive open for reading"); + } + + private synchronized EntryEnumeration recordEntryEnumeration(final EntryEnumeration e) { + entryEnumerations.put(e, null); + return e; + } + + /** + * Returns an enumeration of the entry names in the archive. + * + * @param topLevelDirectoriesOnly whether to report directories only or non-directories only + * @return enumeration of the matching entry names, excluding the manifest + */ + private Enumeration entries(final boolean topLevelDirectoriesOnly) { + try { + /* + * We have two decisions to make: + * + * 1. whether the caller wants top-level directory entries or all non-directory entries enumerated, and + * + * 2. how to obtain the sequence of JarEntry objects which we filter before returning their names. + * + */ + return recordEntryEnumeration(createEntryEnumeration(topLevelDirectoriesOnly)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** + * @return a JarFile instance for a file path + */ + protected static JarFile getJarFile(URI uri) throws IOException { + JarFile jarFile = null; + try { + File file = new File(uri); + if (file.exists()) { + jarFile = new JarFile(file); + } + } catch (IOException e) { + deplLogger.log(WARNING, FILE_OPEN_FAILURE, new Object[] { uri }); + // add the additional information about the path + // since the IOException from jdk doesn't include that info + String additionalInfo = localStrings.getString("enterprise.deployment.invalid_zip_file", uri); + deplLogger.log(WARNING, INVALID_ZIP_FILE, new Object[] { e.getLocalizedMessage(), additionalInfo }); + } + + return jarFile; + } + + /** + * Creates the correct type of entry enumeration, depending on whether the current archive is nested or not and + * depending on whether the caller requested top-level directory entries or all non-directory entries be returned in the + * enumeration. * * @param uriToReadForEntries * @param topLevelDirectoriesOnly @@ -422,32 +449,27 @@ public ReadableArchive getSubArchive(String name) throws IOException { * @throws FileNotFoundException * @throws IOException */ - private EntryEnumeration createEntryEnumeration( - final boolean topLevelDirectoriesOnly) throws FileNotFoundException, IOException { - final JarEntrySource source = (parentArchive == null ? - new ArchiveJarEntrySource(uri) : - new SubarchiveJarEntrySource(parentArchive.jarFile, uri)); + private EntryEnumeration createEntryEnumeration(final boolean topLevelDirectoriesOnly) throws FileNotFoundException, IOException { + final JarEntrySource source = (parentArchive == null ? new ArchiveJarEntrySource(uri) + : new SubarchiveJarEntrySource(parentArchive.jarFile, uri)); + if (topLevelDirectoriesOnly) { return new TopLevelDirectoryEntryEnumeration(source); - } else { - return new NonDirectoryEntryEnumeration(source); } + + return new NonDirectoryEntryEnumeration(source); } /** - * Logic for enumerations of the entry names that is common between the - * top-level directory entry enumeration and the full non-directory - * enumeration. + * Logic for enumerations of the entry names that is common between the top-level directory entry enumeration and the + * full non-directory enumeration. *

- * The goal is to wrap an Enumeration around the underlying entries - * available in the archive. This avoids collecting all - * the entry names first and then returning an enumeration of the collection; - * that can be very costly for large JARs. + * The goal is to wrap an Enumeration around the underlying entries available in the archive. This avoids collecting all + * the entry names first and then returning an enumeration of the collection; that can be very costly for large JARs. *

- * But, the trade-off is that we need to be careful because we leave a stream - * opened to the JAR. So, even though the finalizer is not guaranteed to be - * invoked, we still provide one to close up the JarFile. This should help - * reduce the chance for locked JARs on Windows due to open streams. + * But, the trade-off is that we need to be careful because we leave a stream opened to the JAR. So, even though the + * finalizer is not guaranteed to be invoked, we still provide one to close up the JarFile. This should help reduce the + * chance for locked JARs on Windows due to open streams. */ private abstract class EntryEnumeration implements Enumeration { @@ -462,8 +484,7 @@ private EntryEnumeration(final JarEntrySource jarEntrySource) { } /** - * Finishes the initialization for the enumeration; MUST be invoked - * from the subclass constructor after super(...). + * Finishes the initialization for the enumeration; MUST be invoked from the subclass constructor after super(...). */ protected void completeInit() { nextMatchingEntry = skipToNextMatchingEntry(); @@ -491,8 +512,7 @@ protected JarEntry getNextJarEntry() throws IOException { /** * Returns the next JarEntry available from the archive. *

- * Different concrete subclasses implement this differently so as to - * enumerate the correct sequence of entry names. + * Different concrete subclasses implement this differently so as to enumerate the correct sequence of entry names. * * @return the next available JarEntry; null if no more are available */ @@ -519,17 +539,15 @@ protected void finalize() throws Throwable { } /** - * Defines behavior for sources of JarEntry objects for EntryEnumeration - * implementations. + * Defines behavior for sources of JarEntry objects for EntryEnumeration implementations. *

- * The implementation must be different for top-level archives vs. - * subarchives. + * The implementation must be different for top-level archives vs. subarchives. */ private interface JarEntrySource { /** - * Returns the next JarEntry from the raw entries() enumeration - * of the archive or subarchive. + * Returns the next JarEntry from the raw entries() enumeration of the archive or subarchive. + * * @return JarEntry for the next entry in the JarArchive * @throws IOException */ @@ -537,14 +555,14 @@ private interface JarEntrySource { /** * Closes the source of the JarEntry objects. + * * @throws IOException */ void close() throws IOException; } /** - * Source of JarEntry objects for a top-level archive (as opposed to a - * subarchive). + * Source of JarEntry objects for a top-level archive (as opposed to a subarchive). */ private static class ArchiveJarEntrySource implements JarEntrySource { @@ -554,9 +572,8 @@ private static class ArchiveJarEntrySource implements JarEntrySource { private ArchiveJarEntrySource(final URI archiveURI) throws IOException { sourceJarFile = getJarFile(archiveURI); - if (sourceJarFile == null){ - throw new IOException(localStrings.getString( - "enterprise.deployment.invalid_zip_file", archiveURI)); + if (sourceJarFile == null) { + throw new IOException(localStrings.getString("enterprise.deployment.invalid_zip_file", archiveURI)); } jarEntries = sourceJarFile.entries(); } @@ -599,8 +616,7 @@ public void close() throws IOException { /** * Enumerates the top-level directory entries. *

- * This implementation uses the enumeration of JarEntry objects from the - * JarFile itself. + * This implementation uses the enumeration of JarEntry objects from the JarFile itself. */ private class TopLevelDirectoryEntryEnumeration extends EntryEnumeration { @@ -615,18 +631,13 @@ protected JarEntry skipToNextMatchingEntry() { try { /* - * The next entry should be returned (and not skipped) if the entry is a - * directory entry and it contains only a single slash at the - * end of the entry name. + * The next entry should be returned (and not skipped) if the entry is a directory entry and it contains only a single + * slash at the end of the entry name. */ while ((candidateNextEntry = getNextJarEntry()) != null) { final String candidateNextEntryName = candidateNextEntry.getName(); - if ( candidateNextEntry.isDirectory() && - (candidateNextEntryName.indexOf('/') == - candidateNextEntryName.lastIndexOf('/')) && - (candidateNextEntryName.indexOf('/') == - candidateNextEntryName.length() - 1) - ) { + if (candidateNextEntry.isDirectory() && (candidateNextEntryName.indexOf('/') == candidateNextEntryName.lastIndexOf('/')) + && (candidateNextEntryName.indexOf('/') == candidateNextEntryName.length() - 1)) { break; } } @@ -652,14 +663,12 @@ protected JarEntry skipToNextMatchingEntry() { JarEntry candidateNextEntry; try { /* - * The next entry should be returned (and not skipped) if the entry is - * not a directory entry and if it also not the manifest. + * The next entry should be returned (and not skipped) if the entry is not a directory entry and if it also not the + * manifest. */ while ((candidateNextEntry = getNextJarEntry()) != null) { final String candidateNextEntryName = candidateNextEntry.getName(); - if ( ! candidateNextEntry.isDirectory() && - ! candidateNextEntryName.equals(JarFile.MANIFEST_NAME) - ) { + if (!candidateNextEntry.isDirectory() && !candidateNextEntryName.equals(JarFile.MANIFEST_NAME)) { break; } } @@ -673,13 +682,10 @@ protected JarEntry skipToNextMatchingEntry() { /** * A Collection which wraps an Enumeration. *

- * Note that the nextSlot field is always updated, even if we are using - * the original enumeration to return the next value from the iterator. This - * is so that, if the caller invokes size() which causes us to build the - * ArrayList containing all the elements -- even if that invocation comes while - * the iterator is being used to return values -- the subsequent invocations - * of hasNext and next will use the correct place in the newly-constructed - * ArrayList of values. + * Note that the nextSlot field is always updated, even if we are using the original enumeration to return the next + * value from the iterator. This is so that, if the caller invokes size() which causes us to build the ArrayList + * containing all the elements -- even if that invocation comes while the iterator is being used to return values -- the + * subsequent invocations of hasNext and next will use the correct place in the newly-constructed ArrayList of values. * * @param */ @@ -710,9 +716,7 @@ public Iterator iterator() { @Override public boolean hasNext() { - return (entries != null) ? - nextSlot < entries.size() : - e.hasMoreElements(); + return (entries != null) ? nextSlot < entries.size() : e.hasMoreElements(); } @Override @@ -741,21 +745,20 @@ public void remove() { public int size() { if (entries == null) { populateEntries(); - }; + } + ; return entries.size(); } private void populateEntries() { entries = new ArrayList(); /* - * Fill up the with data from - * a new enumeration. + * Fill up the with data from a new enumeration. */ - for (Enumeration newE = factory.enumeration(); newE.hasMoreElements(); ) { + for (Enumeration newE = factory.enumeration(); newE.hasMoreElements();) { entries.add(newE.nextElement()); } e = null; } } } - diff --git a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/JarArchive.java b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/JarArchive.java index f186fe6b121..16ee38e71ff 100644 --- a/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/JarArchive.java +++ b/nucleus/deployment/common/src/main/java/com/sun/enterprise/deployment/deploy/shared/JarArchive.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,21 +17,19 @@ package com.sun.enterprise.deployment.deploy.shared; - +import java.io.IOException; import java.net.URI; -import org.glassfish.api.deployment.archive.Archive; -import org.glassfish.api.deployment.archive.ReadableArchive; import java.util.Enumeration; -import java.util.Vector; -import java.util.Map; import java.util.HashMap; -import java.util.zip.ZipEntry; +import java.util.Map; +import java.util.Vector; import java.util.jar.JarEntry; -import java.io.IOException; + +import org.glassfish.api.deployment.archive.Archive; +import org.glassfish.api.deployment.archive.ReadableArchive; /** - * This abstract class contains all common implementation of the - * Archive/WritableArchive interfaces for Jar files + * This abstract class contains all common implementation of the Archive/WritableArchive interfaces for Jar files * * @author Jerome Dochez */ @@ -38,19 +37,18 @@ public abstract class JarArchive implements Archive { protected ReadableArchive parentArchive; - protected Map, Object> extraData=new HashMap, Object>(); + protected Map, Object> extraData = new HashMap, Object>(); protected Map archiveMetaData = new HashMap(); /** - * Returns an enumeration of the module file entries with the - * specified prefix. All elements in the enumeration are of - * type String. Each String represents a file name relative - * to the root of the module. + * Returns an enumeration of the module file entries with the specified prefix. All elements in the enumeration are of + * type String. Each String represents a file name relative to the root of the module. * * @param prefix the prefix of entries to be included * @return an enumeration of the archive file entries. */ + @Override public Enumeration entries(String prefix) { Enumeration allEntries = entries(); Vector entries = new Vector(); @@ -63,45 +61,47 @@ public Enumeration entries(String prefix) { return entries.elements(); } - /** + /** * Returns the name portion of the archive's URI. *

- * For JarArhive the name is all of the path that follows - * the last slash up to but not including the last dot. + * For JarArhive the name is all of the path that follows the last slash up to but not including the last dot. *

* Here are some example archive names for the specified JarArchive paths: *

    *
  • /a/b/c/d.jar -> d - *
  • /a/b/c/d -> d + *
  • /a/b/c/d -> d *
  • /x/y/z.html -> z *
+ * * @return the name of the archive * */ + @Override public String getName() { - return JarArchive.getName(getURI()); + return JarArchive.getName(getURI()); } abstract protected JarEntry getJarEntry(String entryName); /** - * Returns the existence of the given entry name - * The file name must be relative to the root of the module. + * Returns the existence of the given entry name The file name must be relative to the root of the module. * - * @param name the file name relative to the root of the module. * @return the existence the given entry name. + * @param name the file name relative to the root of the module. * @return the existence the given entry name. */ public boolean exists(String name) throws IOException { - return getJarEntry(name)!=null; + return getJarEntry(name) != null; } /** * Returns true if the entry is a directory or a plain file + * * @param name name is one of the entries returned by {@link #entries()} * @return true if the entry denoted by the passed name is a directory */ + @Override public boolean isDirectory(String name) { JarEntry entry = getJarEntry(name); - if (entry==null) { + if (entry == null) { throw new IllegalArgumentException(name); } return entry.isDirectory(); @@ -134,12 +134,10 @@ public ReadableArchive getParentArchive() { } /** - * Returns any data that could have been calculated as part of - * the descriptor loading. + * Returns any data that could have been calculated as part of the descriptor loading. * * @param dataType the type of the extra data - * @return the extra data or null if there are not an instance of - * type dataType registered. + * @return the extra data or null if there are not an instance of type dataType registered. */ public synchronized U getExtraData(Class dataType) { return dataType.cast(extraData.get(dataType)); @@ -154,7 +152,7 @@ public synchronized void removeExtraData(Class dataType) { } public void addArchiveMetaData(String metaDataKey, Object metaData) { - if (metaData!=null) { + if (metaData != null) { archiveMetaData.put(metaDataKey, metaData); } } diff --git a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java index b49986caae1..ea56baf37ae 100644 --- a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java +++ b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentContextImpl.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,41 +17,48 @@ package org.glassfish.deployment.common; -import com.sun.enterprise.config.serverbeans.ServerTags; -import org.glassfish.deployment.versioning.VersioningUtils; -import java.lang.instrument.ClassFileTransformer; -import org.glassfish.api.ActionReport; -import org.glassfish.api.deployment.InstrumentableClassLoader; -import org.glassfish.api.deployment.OpsParams; - -import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.api.deployment.archive.ArchiveHandler; -import org.glassfish.api.admin.ServerEnvironment; -import org.glassfish.internal.api.ClassLoaderHierarchy; -import org.glassfish.internal.deployment.*; -import org.glassfish.loader.util.ASClassLoaderUtil; +import static com.sun.enterprise.config.serverbeans.ServerTags.IS_COMPOSITE; +import static com.sun.enterprise.util.io.FileUtils.whack; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.FINEST; -import java.util.*; -import java.util.logging.Logger; -import java.util.logging.Level; import java.io.File; import java.io.IOException; +import java.lang.instrument.ClassFileTransformer; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.MalformedURLException; import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.logging.Logger; +import org.glassfish.api.ActionReport; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.deployment.InstrumentableClassLoader; +import org.glassfish.api.deployment.OpsParams; +import org.glassfish.api.deployment.archive.ArchiveHandler; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.deployment.versioning.VersioningUtils; import org.glassfish.hk2.api.PreDestroy; - -import com.sun.enterprise.util.LocalStringManagerImpl; -import com.sun.enterprise.util.io.FileUtils; import org.glassfish.hk2.classmodel.reflect.Parser; import org.glassfish.hk2.classmodel.reflect.Types; - -import org.glassfish.logging.annotation.LogMessageInfo; -import org.glassfish.logging.annotation.LoggerInfo; +import org.glassfish.internal.api.ClassLoaderHierarchy; +import org.glassfish.internal.deployment.Deployment; +import org.glassfish.internal.deployment.ExtendedDeploymentContext; +import org.glassfish.loader.util.ASClassLoaderUtil; import org.glassfish.logging.annotation.LogMessagesResourceBundle; +import org.glassfish.logging.annotation.LoggerInfo; + +import com.sun.enterprise.util.LocalStringManagerImpl; /** * @@ -63,14 +71,12 @@ public class DeploymentContextImpl implements ExtendedDeploymentContext, PreDest // Reserve this range [NCLS-DEPLOYMENT-00001, NCLS-DEPLOYMENT-02000] // for message ids used in this deployment common module - @LoggerInfo(subsystem = "DEPLOYMENT", description="Deployment logger for common module", publish=true) + @LoggerInfo(subsystem = "DEPLOYMENT", description = "Deployment logger for common module", publish = true) private static final String DEPLOYMENT_LOGGER = "jakarta.enterprise.system.tools.deployment.common"; - public static final Logger deplLogger = - Logger.getLogger(DEPLOYMENT_LOGGER, SHARED_LOGMESSAGE_RESOURCE); - - final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(DeploymentContextImpl.class); + public static final Logger deplLogger = Logger.getLogger(DEPLOYMENT_LOGGER, SHARED_LOGMESSAGE_RESOURCE); + private static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(DeploymentContextImpl.class); private static final String INTERNAL_DIR_NAME = "__internal"; private static final String APP_TENANTS_SUBDIR_NAME = "__app-tenants"; @@ -85,27 +91,28 @@ public class DeploymentContextImpl implements ExtendedDeploymentContext, PreDest Map modulesMetaData = new HashMap(); List transformers = new ArrayList(); Phase phase = Phase.UNKNOWN; - ClassLoader sharableTemp = null; + ClassLoader sharableTemp; Map modulePropsMap = new HashMap(); Map transientAppMetaData = new HashMap(); Map moduleArchiveHandlers = new HashMap(); Map moduleDeploymentContexts = new HashMap(); - ExtendedDeploymentContext parentContext = null; - String moduleUri = null; - private String tenant = null; - private String originalAppName = null; - private File tenantDir = null; + ExtendedDeploymentContext parentContext; + String moduleUri; + private String tenant; + private String originalAppName; + private File tenantDir; /** Creates a new instance of DeploymentContext */ public DeploymentContextImpl(Deployment.DeploymentContextBuilder builder, ServerEnvironment env) { - this(builder.report(), builder.sourceAsArchive(), builder.params(), env); + this(builder.report(), builder.sourceAsArchive(), builder.params(), env); } - public DeploymentContextImpl(ActionReport actionReport, Logger logger, - ReadableArchive source, OpsParams params, ServerEnvironment env) { - this(actionReport, source, params, env); + + public DeploymentContextImpl(ActionReport actionReport, Logger logger, ReadableArchive source, OpsParams params, + ServerEnvironment env) { + this(actionReport, source, params, env); } - public DeploymentContextImpl(ActionReport actionReport, - ReadableArchive source, OpsParams params, ServerEnvironment env) { + + public DeploymentContextImpl(ActionReport actionReport, ReadableArchive source, OpsParams params, ServerEnvironment env) { this.originalSource = source; this.source = source; this.actionReport = actionReport; @@ -113,23 +120,27 @@ public DeploymentContextImpl(ActionReport actionReport, this.env = env; } - public Phase getPhase() - { + @Override + public Phase getPhase() { return phase; } + @Override public void setPhase(Phase newPhase) { this.phase = newPhase; } + @Override public ReadableArchive getSource() { return source; } + @Override public void setSource(ReadableArchive source) { this.source = source; } + @Override public U getCommandParameters(Class commandParametersType) { try { return commandParametersType.cast(parameters); @@ -138,275 +149,272 @@ public U getCommandParameters(Class commandParametersTy } } + @Override public Logger getLogger() { return deplLogger; } + @Override public synchronized void preDestroy() { try { PreDestroy.class.cast(sharableTemp).preDestroy(); } catch (Exception e) { - // ignore, the classloader does not need to be destroyed + // ignore, the classloader does not need to be destroyed } try { PreDestroy.class.cast(cloader).preDestroy(); } catch (Exception e) { - // ignore, the classloader does not need to be destroyed + // ignore, the classloader does not need to be destroyed } } /** - * Returns the class loader associated to this deployment request. - * ClassLoader instances are usually obtained by the getClassLoader API on - * the associated ArchiveHandler for the archive type being deployed. + * Returns the class loader associated to this deployment request. ClassLoader instances are usually obtained by the + * getClassLoader API on the associated ArchiveHandler for the archive type being deployed. *

- * This can return null and the container should allocate a ClassLoader - * while loading the application. + * This can return null and the container should allocate a ClassLoader while loading the application. * - * @return a class loader capable of loading classes and resources from the - * source + * @return a class loader capable of loading classes and resources from the source * @link {org.jvnet.glassfish.apu.deployment.archive.ArchiveHandler.getClassLoader()} */ + @Override public ClassLoader getFinalClassLoader() { return cloader; } /** - * Returns the class loader associated to this deployment request. - * ClassLoader instances are usually obtained by the getClassLoader API on - * the associated ArchiveHandler for the archive type being deployed. + * Returns the class loader associated to this deployment request. ClassLoader instances are usually obtained by the + * getClassLoader API on the associated ArchiveHandler for the archive type being deployed. *

- * This can return null and the container should allocate a ClassLoader - * while loading the application. + * This can return null and the container should allocate a ClassLoader while loading the application. * - * @return a class loader capable of loading classes and resources from the - * source + * @return a class loader capable of loading classes and resources from the source * @link {org.jvnet.glassfish.apu.deployment.archive.ArchiveHandler.getClassLoader()} */ + @Override public ClassLoader getClassLoader() { - /* TODO -- Replace this method with another that does not imply it is - * an accessor and conveys that the result may change depending on the - * current lifecycle. For instance contemporaryClassLoader() - * Problem was reported by findbug - */ - return getClassLoader(true); + /* + * TODO -- Replace this method with another that does not imply it is an accessor and conveys that the result may change + * depending on the current lifecycle. For instance contemporaryClassLoader() Problem was reported by findbug + */ + return getClassLoader(true); } + @Override public synchronized void setClassLoader(ClassLoader cloader) { this.cloader = cloader; } - - // this classloader will be used for sniffer retrieval, metadata parsing + // This classloader will be used for sniffer retrieval, metadata parsing // and the prepare - public synchronized void createDeploymentClassLoader(ClassLoaderHierarchy clh, ArchiveHandler handler) - throws URISyntaxException, MalformedURLException { - this.addTransientAppMetaData(ExtendedDeploymentContext.IS_TEMP_CLASSLOADER, Boolean.TRUE); + @Override + public synchronized void createDeploymentClassLoader(ClassLoaderHierarchy clh, ArchiveHandler handler) throws URISyntaxException, MalformedURLException { + this.addTransientAppMetaData(IS_TEMP_CLASSLOADER, TRUE); this.sharableTemp = createClassLoader(clh, handler, null); } - // this classloader will used to load and start the application - public void createApplicationClassLoader(ClassLoaderHierarchy clh, ArchiveHandler handler) - throws URISyntaxException, MalformedURLException { - this.addTransientAppMetaData(ExtendedDeploymentContext.IS_TEMP_CLASSLOADER, Boolean.FALSE); - if (this.cloader == null) { - this.cloader = createClassLoader(clh, handler, parameters.name()); + // This classloader will used to load and start the application + @Override + public void createApplicationClassLoader(ClassLoaderHierarchy classLoaderHierarchy, ArchiveHandler handler) throws URISyntaxException, MalformedURLException { + addTransientAppMetaData(IS_TEMP_CLASSLOADER, FALSE); + + if (cloader == null) { + cloader = createClassLoader(classLoaderHierarchy, handler, parameters.name()); } } - private ClassLoader createClassLoader(ClassLoaderHierarchy clh, ArchiveHandler handler, String appName) - throws URISyntaxException, MalformedURLException { + private ClassLoader createClassLoader(ClassLoaderHierarchy classLoaderHierarchy, ArchiveHandler handler, String appName) throws URISyntaxException, MalformedURLException { // first we create the appLib class loader, this is non shared libraries class loader - ClassLoader applibCL = clh.getAppLibClassLoader(appName, getAppLibs()); - - ClassLoader parentCL = clh.createApplicationParentCL(applibCL, this); + ClassLoader applibCL = classLoaderHierarchy.getAppLibClassLoader(appName, getAppLibs()); + ClassLoader parentCL = classLoaderHierarchy.createApplicationParentCL(applibCL, this); return handler.getClassLoader(parentCL, this); } public synchronized ClassLoader getClassLoader(boolean sharable) { - // if we are in prepare phase, we need to return our sharable temporary class loader + // If we are in prepare phase, we need to return our sharable temporary class loader // otherwise, we return the final one. - if (phase==Phase.PREPARE) { + if (phase == Phase.PREPARE) { if (sharable) { return sharableTemp; - } else { - InstrumentableClassLoader cl = InstrumentableClassLoader.class.cast(sharableTemp); - return cl.copy(); } - } else { - // we are out of the prepare phase, destroy the shareableTemp and - // return the final classloader - if (sharableTemp!=null) { - try { - PreDestroy.class.cast(sharableTemp).preDestroy(); - } catch (Exception e) { - // ignore, the classloader does not need to be destroyed - } - sharableTemp=null; + + return InstrumentableClassLoader.class.cast(sharableTemp).copy(); + } + + // we are out of the prepare phase, destroy the shareableTemp and + // return the final classloader + if (sharableTemp != null) { + try { + PreDestroy.class.cast(sharableTemp).preDestroy(); + } catch (Exception e) { + // ignore, the classloader does not need to be destroyed } - return cloader; + sharableTemp = null; } + + return cloader; } /** - * Returns a scratch directory that can be used to store things in. - * The scratch directory will be persisted accross server restart but - * not accross redeployment of the same application + * Returns a scratch directory that can be used to store things in. The scratch directory will be persisted accross + * server restart but not accross redeployment of the same application * * @param subDirName the sub directory name of the scratch dir - * @return the scratch directory for this application based on - * passed in subDirName. Returns the root scratch dir if the - * passed in value is null. + * @return the scratch directory for this application based on passed in subDirName. Returns the root scratch dir if the + * passed in value is null. */ + @Override public File getScratchDir(String subDirName) { File rootScratchDir = env.getApplicationStubPath(); + if (tenant != null && originalAppName != null) { - // multi-tenant case + // Multi-tenant case rootScratchDir = getRootScratchTenantDirForApp(originalAppName); rootScratchDir = new File(rootScratchDir, tenant); - if (subDirName != null ) { + if (subDirName != null) { rootScratchDir = new File(rootScratchDir, subDirName); } + return rootScratchDir; - } else { - // regular case - if (subDirName != null ) { - rootScratchDir = new File(rootScratchDir, subDirName); - } - String appDirName = VersioningUtils.getRepositoryName(parameters.name()); - return new File(rootScratchDir, appDirName); } + + // Regular case + if (subDirName != null) { + rootScratchDir = new File(rootScratchDir, subDirName); + } + + return new File(rootScratchDir, VersioningUtils.getRepositoryName(parameters.name())); } /** * {@inheritDoc} */ + @Override public File getSourceDir() { - return new File(getSource().getURI()); } + @Override public void addModuleMetaData(Object metaData) { - if (metaData!=null) { + if (metaData != null) { modulesMetaData.put(metaData.getClass().getName(), metaData); } } + @Override public T getModuleMetaData(Class metadataType) { Object moduleMetaData = modulesMetaData.get(metadataType.getName()); if (moduleMetaData != null) { return metadataType.cast(moduleMetaData); - } else { - for (Object metadata : modulesMetaData.values()) { - try { - return metadataType.cast(metadata); - } catch (ClassCastException e) { - } + } + + for (Object metadata : modulesMetaData.values()) { + try { + return metadataType.cast(metadata); + } catch (ClassCastException e) { } - return null; } + + return null; } + @Override public Collection getModuleMetadata() { - List copy = new ArrayList(); - copy.addAll(modulesMetaData.values()); - return copy; + return new ArrayList<>(modulesMetaData.values()); } + @Override public Map getTransientAppMetadata() { - HashMap copy = new HashMap(); - copy.putAll(transientAppMetaData); - return copy; + return new HashMap(transientAppMetaData); } + @Override public void addTransientAppMetaData(String metaDataKey, Object metaData) { - if (metaData!=null) { + if (metaData != null) { transientAppMetaData.put(metaDataKey, metaData); } } + @Override public T getTransientAppMetaData(String key, Class metadataType) { Object metaData = transientAppMetaData.get(key); - if (metaData != null) { - return metadataType.cast(metaData); + if (metaData == null) { + return null; } - return null; + + return metadataType.cast(metaData); } /** - * Returns the application level properties that will be persisted as a - * key value pair at then end of deployment. That allows individual - * Deployers implementation to store some information at the - * application level that should be available upon server restart. - * Application level propertries are shared by all the modules. + * Returns the application level properties that will be persisted as a key value pair at then end of deployment. That + * allows individual Deployers implementation to store some information at the application level that should be + * available upon server restart. Application level propertries are shared by all the modules. * * @return the application's properties. */ + @Override public Properties getAppProps() { - if (props==null) { + if (props == null) { props = new Properties(); } + return props; } /** - * Returns the module level properties that will be persisted as a - * key value pair at then end of deployment. That allows individual - * Deployers implementation to store some information at the module - * level that should be available upon server restart. - * Module level properties are only visible to the current module. + * Returns the module level properties that will be persisted as a key value pair at then end of deployment. That allows + * individual Deployers implementation to store some information at the module level that should be available upon + * server restart. Module level properties are only visible to the current module. + * * @return the module's properties. */ + @Override public Properties getModuleProps() { - // for standalone case, it would return the same as application level - // properties - // for composite case, the composite deployer will return proper - // module level properties - if (props==null) { + // For standalone case, it would return the same as application level properties + // For composite case, the composite deployer will return proper module level properties + if (props == null) { props = new Properties(); } + return props; } /** * Add a new ClassFileTransformer to the context * - * @param transformer the new class file transformer to register to the new application - * class loader - * @throws UnsupportedOperationException if the class loader we use does not support the - * registration of a ClassFileTransformer. In such case, the deployer should either fail - * deployment or revert to a mode without the byteocode enhancement feature. + * @param transformer the new class file transformer to register to the new application class loader + * @throws UnsupportedOperationException if the class loader we use does not support the registration of a + * ClassFileTransformer. In such case, the deployer should either fail deployment or revert to a mode without the + * byteocode enhancement feature. */ + @Override public void addTransformer(ClassFileTransformer transformer) { + InstrumentableClassLoader instrumentableClassLoader = InstrumentableClassLoader.class.cast(getFinalClassLoader()); + String isComposite = getAppProps().getProperty(IS_COMPOSITE); - InstrumentableClassLoader icl = InstrumentableClassLoader.class.cast(getFinalClassLoader()); - String isComposite = getAppProps().getProperty(ServerTags.IS_COMPOSITE); - - if (Boolean.valueOf(isComposite) && icl instanceof URLClassLoader) { - URLClassLoader urlCl = (URLClassLoader)icl; + if (Boolean.valueOf(isComposite) && instrumentableClassLoader instanceof URLClassLoader) { + URLClassLoader urlClassLoader = (URLClassLoader) instrumentableClassLoader; boolean isAppLevel = (getParentContext() == null); if (isAppLevel) { - // for ear lib PUs, let's install the - // tranformers with the EarLibClassLoader - icl = InstrumentableClassLoader.class.cast(urlCl.getParent().getParent()); + // For ear lib PUs, let's install the tranformers with the EarLibClassLoader + instrumentableClassLoader = InstrumentableClassLoader.class.cast(urlClassLoader.getParent().getParent()); } else { - // for modules inside the ear, let's install the - // transformers with the EarLibClassLoader in + // For modules inside the ear, let's install the transformers with the EarLibClassLoader in // addition to installing them to module classloader - ClassLoader libCl = urlCl.getParent().getParent(); - if (!(libCl instanceof URLClassLoader)) { - // web module - libCl = libCl.getParent(); + ClassLoader libClassLoader = urlClassLoader.getParent().getParent(); + if (!(libClassLoader instanceof URLClassLoader)) { + // Web module + libClassLoader = libClassLoader.getParent(); } - if (libCl instanceof URLClassLoader) { - InstrumentableClassLoader libIcl = InstrumentableClassLoader.class.cast(libCl); - libIcl.addTransformer(transformer); + if (libClassLoader instanceof URLClassLoader) { + InstrumentableClassLoader.class.cast(libClassLoader).addTransformer(transformer); } } } - icl.addTransformer(transformer); + + instrumentableClassLoader.addTransformer(transformer); } /** @@ -414,97 +422,92 @@ public void addTransformer(ClassFileTransformer transformer) { * * @return the transformers list */ + @Override public List getTransformers() { return transformers; } - public List getAppLibs() - throws URISyntaxException { + @Override + public List getAppLibs() throws URISyntaxException { List libURIs = new ArrayList(); if (parameters.libraries() != null) { - URL[] urls = - ASClassLoaderUtil.getDeployParamLibrariesAsURLs( - parameters.libraries(), env); + URL[] urls = ASClassLoaderUtil.getDeployParamLibrariesAsURLs(parameters.libraries(), env); for (URL url : urls) { File file = new File(url.getFile()); - deplLogger.log(Level.FINE, "Specified library jar: "+file.getAbsolutePath()); - if (file.exists()){ + deplLogger.log(FINE, "Specified library jar: " + file.getAbsolutePath()); + if (file.exists()) { libURIs.add(url.toURI()); } else { - throw new IllegalArgumentException(localStrings.getLocalString("enterprise.deployment.nonexist.libraries", "Specified library jar {0} does not exist: {1}", file.getName(), file.getAbsolutePath())); + throw new IllegalArgumentException(localStrings.getLocalString("enterprise.deployment.nonexist.libraries", + "Specified library jar {0} does not exist: {1}", file.getName(), file.getAbsolutePath())); } } } Set extensionList = null; - try{ + try { extensionList = InstalledLibrariesResolver.getInstalledLibraries(source); - }catch(IOException ioe){ + } catch (IOException ioe) { throw new RuntimeException(ioe); } + URL[] extensionListLibraries = ASClassLoaderUtil.getLibrariesAsURLs(extensionList, env); for (URL url : extensionListLibraries) { libURIs.add(url.toURI()); - if (deplLogger.isLoggable(Level.FINEST)) { - deplLogger.log(Level.FINEST, "Detected [EXTENSION_LIST]" + - " installed-library [ " + url + " ] for archive [ "+source.getName()+ "]"); + if (deplLogger.isLoggable(FINEST)) { + deplLogger.log(FINEST, + "Detected [EXTENSION_LIST]" + " installed-library [ " + url + " ] for archive [ " + source.getName() + "]"); } } return libURIs; } + @Override public void clean() { - if (parameters.origin == OpsParams.Origin.undeploy || - parameters.origin == OpsParams.Origin.deploy ) { - // for undeploy or deploy failure roll back - - // need to remove the generated directories... - // need to remove generated/xml, generated/ejb, generated/jsp, + if (parameters.origin == OpsParams.Origin.undeploy || parameters.origin == OpsParams.Origin.deploy) { + // For undeploy or deploy failure roll back we need to remove generated/xml, generated/ejb, generated/jsp, - // remove generated/xml - File generatedXmlRoot = getScratchDir("xml"); - FileUtils.whack(generatedXmlRoot); + // Remove generated/xml + whack(getScratchDir("xml")); - // remove generated/ejb - File generatedEjbRoot = getScratchDir("ejb"); - // recursively delete... - FileUtils.whack(generatedEjbRoot); + // Remove generated/ejb + whack(getScratchDir("ejb")); - // remove generated/jsp - File generatedJspRoot = getScratchDir("jsp"); - // recursively delete... - FileUtils.whack(generatedJspRoot); + // Remove generated/jsp + whack(getScratchDir("jsp")); - // remove the internal archive directory which holds the original + // Remove the internal archive directory which holds the original // archive (and possibly deployment plan) that cluster sync can use - FileUtils.whack(getAppInternalDir()); + whack(getAppInternalDir()); - FileUtils.whack(getAppAltDDDir()); + whack(getAppAltDDDir()); - // remove the root tenant dir for this application - FileUtils.whack(getRootTenantDirForApp(parameters.name())); + // Remove the root tenant dir for this application + whack(getRootTenantDirForApp(parameters.name())); - // remove the root tenant generated dir root for this application - FileUtils.whack(getRootScratchTenantDirForApp(parameters.name())); + // Remove the root tenant generated dir root for this application + whack(getRootScratchTenantDirForApp(parameters.name())); } else if (parameters.origin == OpsParams.Origin.mt_unprovision) { // for unprovision application, remove the tenant dir - FileUtils.whack(tenantDir); + whack(tenantDir); - // and remove the generated dir - File generatedRoot = getScratchDir(null); - FileUtils.whack(generatedRoot); + // And remove the generated dir + whack(getScratchDir(null)); } } + @Override public ArchiveHandler getArchiveHandler() { return archiveHandler; } + @Override public void setArchiveHandler(ArchiveHandler archiveHandler) { this.archiveHandler = archiveHandler; } + @Override public ReadableArchive getOriginalSource() { return originalSource; } @@ -514,6 +517,7 @@ public ReadableArchive getOriginalSource() { * * @return a map containing module properties */ + @Override public Map getModulePropsMap() { return modulePropsMap; } @@ -523,6 +527,7 @@ public Map getModulePropsMap() { * * @param modulePropsMap */ + @Override public void setModulePropsMap(Map modulePropsMap) { this.modulePropsMap = modulePropsMap; } @@ -532,6 +537,7 @@ public void setModulePropsMap(Map modulePropsMap) { * * @param parentContext */ + @Override public void setParentContext(ExtendedDeploymentContext parentContext) { this.parentContext = parentContext; } @@ -542,6 +548,7 @@ public void setParentContext(ExtendedDeploymentContext parentContext) { * * @return the parent context */ + @Override public ExtendedDeploymentContext getParentContext() { return parentContext; } @@ -551,25 +558,27 @@ public ExtendedDeploymentContext getParentContext() { * * @return the module uri */ + @Override public String getModuleUri() { return moduleUri; } - /** + /** * Sets the module uri for this module context * * @param moduleUri */ + @Override public void setModuleUri(String moduleUri) { this.moduleUri = moduleUri; } - /** * Gets the archive handlers for modules * * @return a map containing module archive handlers */ + @Override public Map getModuleArchiveHandlers() { return moduleArchiveHandlers; } @@ -579,6 +588,7 @@ public Map getModuleArchiveHandlers() { * * @return a map containing module deployment contexts */ + @Override public Map getModuleDeploymentContexts() { return moduleDeploymentContexts; } @@ -588,57 +598,36 @@ public Map getModuleDeploymentContexts() { * * @return an action report */ + @Override public ActionReport getActionReport() { return actionReport; } + @Override public File getAppInternalDir() { final File internalDir = new File(env.getApplicationRepositoryPath(), INTERNAL_DIR_NAME); return new File(internalDir, VersioningUtils.getRepositoryName(parameters.name())); } + @Override public File getAppAltDDDir() { final File altDDDir = env.getApplicationAltDDPath(); return new File(altDDDir, VersioningUtils.getRepositoryName(parameters.name())); } + @Override public void setTenant(final String tenant, final String appName) { this.tenant = tenant; this.originalAppName = appName; tenantDir = initTenantDir(); } - private File initTenantDir() { - if (tenant == null || originalAppName == null) { - return null; - } - File f = getRootTenantDirForApp(originalAppName); - f = new File(f, tenant); - if (!f.exists() && !f.mkdirs()) { - if (deplLogger.isLoggable(Level.FINEST)) { - deplLogger.log(Level.FINEST, "Unable to create directory " + f.getAbsolutePath()); - } - - } - return f; - } - - private File getRootTenantDirForApp(String appName) { - File rootTenantDir = new File(env.getApplicationRepositoryPath(), APP_TENANTS_SUBDIR_NAME); - File rootTenantDirForApp = new File(rootTenantDir, appName); - return rootTenantDirForApp; - } - - private File getRootScratchTenantDirForApp(String appName) { - File rootScratchTenantDir = new File(env.getApplicationStubPath(), APP_TENANTS_SUBDIR_NAME); - File rootScratchTenantDirForApp = new File(rootScratchTenantDir, appName); - return rootScratchTenantDirForApp; - } - + @Override public String getTenant() { return tenant; } + @Override public File getTenantDir() { return tenantDir; } @@ -649,28 +638,62 @@ public void postDeployClean(boolean isFinalClean) { if (isFinalClean) { transientAppMetaData.clear(); } else { - final String [] classNamesToClean = {Types.class.getName(), Parser.class.getName()}; + final String[] classNamesToClean = { Types.class.getName(), Parser.class.getName() }; for (String className : classNamesToClean) { transientAppMetaData.remove(className); } } } + actionReport = null; } + @Override + public String toString() { + return (source == null ? "" : source.toString()) + " " + (originalSource == null ? "" : originalSource.getURI()); + } + /** - * Prepare the scratch directories, creating the directories - * if they do not exist + * Prepare the scratch directories, creating the directories if they do not exist */ + @Override public void prepareScratchDirs() throws IOException { prepareScratchDir(getScratchDir("ejb")); prepareScratchDir(getScratchDir("xml")); prepareScratchDir(getScratchDir("jsp")); } - private void prepareScratchDir(File f) throws IOException { - if (!f.isDirectory() && !f.mkdirs()) - throw new IOException("Cannot create scratch directory : " + f.getAbsolutePath()); + + // ### Private methods + + private File initTenantDir() { + if (tenant == null || originalAppName == null) { + return null; + } + + File tenantDir = new File(getRootTenantDirForApp(originalAppName), tenant); + if (!tenantDir.exists() && !tenantDir.mkdirs()) { + if (deplLogger.isLoggable(FINEST)) { + deplLogger.log(FINEST, "Unable to create directory " + tenantDir.getAbsolutePath()); + } + + } + + return tenantDir; + } + + private File getRootTenantDirForApp(String appName) { + return new File(new File(env.getApplicationRepositoryPath(), APP_TENANTS_SUBDIR_NAME), appName); + } + + private File getRootScratchTenantDirForApp(String appName) { + return new File(new File(env.getApplicationStubPath(), APP_TENANTS_SUBDIR_NAME), appName); + } + + private void prepareScratchDir(File scratchDir) throws IOException { + if (!scratchDir.isDirectory() && !scratchDir.mkdirs()) { + throw new IOException("Cannot create scratch directory : " + scratchDir.getAbsolutePath()); + } } } diff --git a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentUtils.java b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentUtils.java index 5e82fd324e8..d7551e79de0 100644 --- a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentUtils.java +++ b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/DeploymentUtils.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,47 +17,52 @@ package org.glassfish.deployment.common; -import com.sun.enterprise.config.serverbeans.*; -import com.sun.enterprise.deploy.shared.ArchiveFactory; -import com.sun.enterprise.deploy.shared.FileArchive; -import com.sun.enterprise.util.io.FileUtils; -import org.glassfish.api.deployment.archive.ArchiveType; -import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.api.deployment.archive.WritableArchive; -import org.glassfish.api.deployment.archive.ArchiveHandler; -import org.glassfish.api.deployment.archive.ArchiveDetector; -import org.glassfish.api.container.Sniffer; -import org.glassfish.api.admin.ServerEnvironment; -import com.sun.enterprise.util.LocalStringManagerImpl; -import org.glassfish.api.deployment.DeploymentContext; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.loader.util.ASClassLoaderUtil; - +import static com.sun.enterprise.util.Utility.isAnyNull; +import static com.sun.enterprise.util.io.FileUtils.makeFriendlyFilenameExtension; +import static com.sun.enterprise.util.io.FileUtils.makeLegalNoBlankFileName; +import static com.sun.enterprise.util.io.FileUtils.safeIsDirectory; +import static java.util.jar.JarFile.MANIFEST_NAME; +import static java.util.logging.Level.WARNING; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.BufferedInputStream; -import java.util.Enumeration; -import java.util.Properties; import java.net.URI; -import java.net.URL; import java.net.URISyntaxException; +import java.net.URL; import java.util.ArrayList; import java.util.Collections; +import java.util.Enumeration; import java.util.List; -import java.util.zip.Adler32; +import java.util.Properties; import java.util.jar.Manifest; -import java.util.jar.JarFile; -import java.util.logging.Logger; import java.util.logging.LogRecord; -import java.util.logging.Level; - +import java.util.logging.Logger; +import java.util.zip.Adler32; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.deployment.DeploymentContext; +import org.glassfish.api.deployment.archive.ArchiveDetector; +import org.glassfish.api.deployment.archive.ArchiveType; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.api.deployment.archive.WritableArchive; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.loader.util.ASClassLoaderUtil; import org.glassfish.logging.annotation.LogMessageInfo; -import org.glassfish.logging.annotation.LoggerInfo; -import org.glassfish.logging.annotation.LogMessagesResourceBundle; + +import com.sun.enterprise.config.serverbeans.Application; +import com.sun.enterprise.config.serverbeans.Cluster; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.HttpService; +import com.sun.enterprise.config.serverbeans.Server; +import com.sun.enterprise.config.serverbeans.VirtualServer; +import com.sun.enterprise.deploy.shared.ArchiveFactory; +import com.sun.enterprise.deploy.shared.FileArchive; +import com.sun.enterprise.util.LocalStringManagerImpl; +import com.sun.enterprise.util.io.FileUtils; /** * Utility methods for deployment. @@ -64,9 +70,9 @@ public class DeploymentUtils { - public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; + public static final Logger deplLogger = DeploymentContextImpl.deplLogger; - @LogMessageInfo(message = "Exception caught {0}", level="WARNING") + @LogMessageInfo(message = "Exception caught {0}", level = "WARNING") private static final String EXCEPTION_CAUGHT = "NCLS-DEPLOYMENT-00010"; public static final String DEPLOYMENT_PROPERTY_JAVA_WEB_START_ENABLED = "java-web-start-enabled"; @@ -98,19 +104,18 @@ public static boolean isDomainTarget(final String targetName) { * @return checksum calculated from URIs of files in the directory */ public static long checksum(final File directory) { - if ( ! directory.isDirectory()) { - final String msg = localStrings.getLocalString( - "enterprise.deployment.remoteDirPathUnusable", - "The directory deployment path {0} is not a directory or is inaccessible", - directory.getAbsolutePath()); + if (!directory.isDirectory()) { + final String msg = localStrings.getLocalString("enterprise.deployment.remoteDirPathUnusable", + "The directory deployment path {0} is not a directory or is inaccessible", directory.getAbsolutePath()); throw new IllegalArgumentException(msg); } + final List uris = new ArrayList(); scanDirectory(directory.toURI(), directory, uris); + /* - * Sort the URIs. File.listFiles does not guarantee any particular - * ordering of the visited files, and for two checksums to match we - * need to process the URIs in the same order. + * Sort the URIs. File.listFiles does not guarantee any particular ordering of the visited files, and for two checksums + * to match we need to process the URIs in the same order. */ Collections.sort(uris); @@ -118,22 +123,24 @@ public static long checksum(final File directory) { for (URI uri : uris) { checksum.update(uri.toASCIIString().getBytes()); } + return checksum.getValue(); } /** - * Returns the downloadable artifacts object from the specified deployment - * context, creating it there if it does not already exist. - * @param dc the deployment context from which to fetch the downloadable Artifacts object + * Returns the downloadable artifacts object from the specified deployment context, creating it there if it does not + * already exist. + * + * @param deploymentContext the deployment context from which to fetch the downloadable Artifacts object * @return */ - public static Artifacts downloadableArtifacts(final DeploymentContext dc) { - return Artifacts.get(dc, DOWNLOADABLE_ARTIFACTS_KEY_PREFIX); + public static Artifacts downloadableArtifacts(final DeploymentContext deploymentContext) { + return Artifacts.get(deploymentContext, DOWNLOADABLE_ARTIFACTS_KEY_PREFIX); } /** - * Returns the downloadable artifacts object derived from the properties - * saved with the specified Application + * Returns the downloadable artifacts object derived from the properties saved with the specified Application + * * @param app the Application config object with (possibly) properties describing downloadable artifacts * @return */ @@ -142,18 +149,19 @@ public static Artifacts downloadableArtifacts(final Application app) { } /** - * Returns the generated artifacts object from the specified deployment - * context, creating it there if it does not already exist. + * Returns the generated artifacts object from the specified deployment context, creating it there if it does not + * already exist. + * * @param app * @return */ - public static Artifacts generatedArtifacts(final DeploymentContext dc) { - return Artifacts.get(dc, GENERATED_ARTIFACTS_KEY_PREFIX); + public static Artifacts generatedArtifacts(final DeploymentContext deploymentContext) { + return Artifacts.get(deploymentContext, GENERATED_ARTIFACTS_KEY_PREFIX); } /** - * Returns the generated artifacts object derived from the properties - * saved with the specified Application + * Returns the generated artifacts object derived from the properties saved with the specified Application + * * @param app the Application config object with (possibly) properties describing generated artifacts * @return */ @@ -161,38 +169,41 @@ public static Artifacts generatedArtifacts(final Application app) { return Artifacts.get(app.getDeployProperties(), GENERATED_ARTIFACTS_KEY_PREFIX); } - private static void scanDirectory(final URI anchorDirURI, - final File directory, final List uris) { - for (File f : directory.listFiles()) { - uris.add(anchorDirURI.relativize(f.toURI())); - if (f.isDirectory()) { - scanDirectory(anchorDirURI, f, uris); + private static void scanDirectory(final URI anchorDirURI, final File directory, final List uris) { + for (File file : directory.listFiles()) { + uris.add(anchorDirURI.relativize(file.toURI())); + if (file.isDirectory()) { + scanDirectory(anchorDirURI, file, uris); } } } - // check if the archive matches the specified archive type + // Check if the archive matches the specified archive type public static boolean isArchiveOfType(ReadableArchive archive, ArchiveType archiveType, DeploymentContext context, ServiceLocator locator) { - if (archive == null || archiveType == null) { + if (isAnyNull(archive, archiveType)) { return false; } + String type = archiveType.toString(); if (context != null && context.getArchiveHandler() != null) { - // first check the current context for the current archive type + // First check the current context for the current archive type return type.equals(context.getArchiveHandler().getArchiveType()); } + try { ArchiveDetector detector = locator.getService(ArchiveDetector.class, type); if (detector == null) { return false; } + return detector.handles(archive); } catch (IOException ioe) { - LogRecord lr = new LogRecord(Level.WARNING, EXCEPTION_CAUGHT); + LogRecord lr = new LogRecord(WARNING, EXCEPTION_CAUGHT); Object args[] = { ioe.getMessage() }; lr.setParameters(args); lr.setThrown(ioe); deplLogger.log(lr); + return false; } } @@ -201,11 +212,10 @@ public static boolean isArchiveOfType(ReadableArchive archive, ArchiveType archi return isArchiveOfType(archive, archiveType, null, locator); } - /** + /** * @param pathName - * @return the default value of the EE name. - * The default name is the pathname with any filename extension - * (.jar, .war, .rar) removed, but with any directory names included. + * @return the default value of the EE name. The default name is the pathname with any filename extension (.jar, .war, + * .rar) removed, but with any directory names included. */ public static String getDefaultEEName(String pathName) { if (pathName == null) { @@ -218,82 +228,74 @@ public static String getDefaultEEName(String pathName) { pathName = pathName.substring(0, pathName.length() - 1); } if (pathName.lastIndexOf("/") != -1) { - pathName = pathName.substring(pathName.lastIndexOf( - "/") + 1); + pathName = pathName.substring(pathName.lastIndexOf("/") + 1); } - if (pathName.endsWith(".jar") || pathName.endsWith(".war") - || pathName.endsWith(".rar") || pathName.endsWith(".ear")) { + + if (pathName.endsWith(".jar") || pathName.endsWith(".war") || pathName.endsWith(".rar") || pathName.endsWith(".ear")) { return pathName.substring(0, pathName.length() - 4); - } else { - return pathName; } + + return pathName; } /** - * This method returns the relative file path of an embedded module to - * the application root. - * For example, if the module is expanded/located at - * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar, - * this method will return fooEJB_jar + * This method returns the relative file path of an embedded module to the application root. For example, if the module + * is expanded/located at $domain_dir/applications/ee-apps/foo/fooEJB_jar, this method will return fooEJB_jar * - *@param appRootPath The path of the application root which - * contains the module - * e.g. $domain_dir/applications/j2ee-apps/foo - *@param moduleUri The module uri - * e.g. fooEJB.jar - *@return The relative file path of the module to the application root + * @param appRootPath The path of the application root which contains the module e.g. + * $domain_dir/applications/ee-apps/foo + * @param moduleUri The module uri e.g. fooEJB.jar + * @return The relative file path of the module to the application root */ - public static String getRelativeEmbeddedModulePath(String appRootPath, - String moduleUri) { - moduleUri = FileUtils.makeLegalNoBlankFileName(moduleUri); - if (FileUtils.safeIsDirectory(new File(appRootPath, moduleUri))) { + public static String getRelativeEmbeddedModulePath(String appRootPath, String moduleUri) { + moduleUri = makeLegalNoBlankFileName(moduleUri); + if (safeIsDirectory(new File(appRootPath, moduleUri))) { return moduleUri; - } else { - return FileUtils.makeFriendlyFilenameExtension(moduleUri); } + + return makeFriendlyFilenameExtension(moduleUri); } /** - * This method returns the file path of an embedded module. - * For example, if the module is expanded/located at - * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar, - * this method will return - * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar + * This method returns the file path of an embedded module. For example, if the module is expanded/located at + * $domain_dir/applications/ee-apps/foo/fooEJB_jar, this method will return + * $domain_dir/applications/ee-apps/foo/fooEJB_jar * - *@param appRootPath The path of the application root which - * contains the module - * e.g. $domain_dir/applications/j2ee-apps/foo - *@param moduleUri The module uri - * e.g. fooEJB.jar - *@return The file path of the module + * @param appRootPath The path of the application root which contains the module e.g. + * $domain_dir/applications/ee-apps/foo + * @param moduleUri The module uri e.g. fooEJB.jar + * @return The file path of the module */ - public static String getEmbeddedModulePath(String appRootPath, - String moduleUri) { - return appRootPath + File.separator + getRelativeEmbeddedModulePath(appRootPath, moduleUri) ; + public static String getEmbeddedModulePath(String appRootPath, String moduleUri) { + return appRootPath + File.separator + getRelativeEmbeddedModulePath(appRootPath, moduleUri); } public static boolean useV2Compatibility(DeploymentContext context) { return V2_COMPATIBILITY.equals(context.getAppProps().getProperty(DeploymentProperties.COMPATIBILITY)); } - public static String relativizeWithinDomainIfPossible( - final URI absURI) throws URISyntaxException { - URI instanceRootURI = new URI(System.getProperty(INSTANCE_ROOT_URI_PROPERTY_NAME)); - URI appURI = instanceRootURI.relativize(absURI); - String appLocation = (appURI.isAbsolute()) ? - appURI.toString() : - "${" + INSTANCE_ROOT_URI_PROPERTY_NAME + "}/" + appURI.toString(); - return appLocation; + public static String relativizeWithinDomainIfPossible(final URI absURI) throws URISyntaxException { + URI appURI = new URI(System.getProperty(INSTANCE_ROOT_URI_PROPERTY_NAME)).relativize(absURI); + + return (appURI.isAbsolute()) ? appURI.toString() : "${" + INSTANCE_ROOT_URI_PROPERTY_NAME + "}/" + appURI.toString(); } public static void validateApplicationName(String name) { if (name.indexOf('/') != -1) { - throw new IllegalArgumentException(localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", "/", name)); - } else if (name.indexOf('#') != -1) { - throw new IllegalArgumentException(localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", "#", name)); - } else if (name.indexOf(';') != -1) { - throw new IllegalArgumentException(localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", ";", name)); + throw new IllegalArgumentException( + localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", "/", name)); + } + + if (name.indexOf('#') != -1) { + throw new IllegalArgumentException( + localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", "#", name)); + } + + if (name.indexOf(';') != -1) { + throw new IllegalArgumentException( + localStrings.getLocalString("illegal_char_in_name", "Illegal character [{0}] in the name [{1}].", ";", name)); } + return; } @@ -304,9 +306,7 @@ public static void validateApplicationName(String name) { * @param target of the expanding * @throws IOException when the archive is corrupted */ - public static void expand(ReadableArchive source, WritableArchive target) - throws IOException { - + public static void expand(ReadableArchive source, WritableArchive target) throws IOException { Enumeration e = source.entries(); while (e.hasMoreElements()) { String entryName = e.nextElement(); @@ -316,46 +316,48 @@ public static void expand(ReadableArchive source, WritableArchive target) os = target.putNextEntry(entryName); FileUtils.copy(is, os, source.getEntrySize(entryName)); } finally { - if (os!=null) { + if (os != null) { target.closeEntry(); } is.close(); } } - // last is manifest is existing. - Manifest m = source.getManifest(); - if (m!=null) { - OutputStream os = target.putNextEntry(JarFile.MANIFEST_NAME); - m.write(os); + // Last is manifest if exists + Manifest manifest = source.getManifest(); + if (manifest != null) { + manifest.write(target.putNextEntry(MANIFEST_NAME)); target.closeEntry(); } } - public static String getInternalNameForTenant(String appname, - String tenantname) { + public static String getInternalNameForTenant(String appname, String tenantname) { return appname + "___" + tenantname; } public static String propertiesValue(final Properties props, final char sep) { final StringBuilder sb = new StringBuilder(); + String currentSep = ""; - for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { - final Object key = en.nextElement(); - final Object v = props.get(key); - sb.append(currentSep).append(key.toString()).append("=").append(v.toString()); + for (Enumeration propertyNames = props.propertyNames(); propertyNames.hasMoreElements();) { + final Object key = propertyNames.nextElement(); + final Object value = props.get(key); + sb.append(currentSep) + .append(key.toString()) + .append("=") + .append(value.toString()); + currentSep = String.valueOf(sep); } + return sb.toString(); } - public static List getManifestLibraries(DeploymentContext context) - throws IOException { + public static List getManifestLibraries(DeploymentContext context) throws IOException { return getManifestLibraries(context.getSource()); } - public static List getManifestLibraries(DeploymentContext context, - Manifest manifest) throws IOException { + public static List getManifestLibraries(DeploymentContext context, Manifest manifest) throws IOException { return getManifestLibraries(context.getSource(), manifest); } @@ -377,9 +379,8 @@ private static List getManifestLibraries(ReadableArchive archive, Manifest } } - // add libraries referenced through manifest - return ASClassLoaderUtil.getManifestClassPathAsURLs( - manifest, appRootPath); + // Add libraries referenced through manifest + return ASClassLoaderUtil.getManifestClassPathAsURLs(manifest, appRootPath); } public static List getExternalLibraries(ReadableArchive archive) { @@ -390,6 +391,7 @@ public static List getExternalLibraries(ReadableArchive archive) { if (archive.getParentArchive() != null) { archiveURI = archive.getParentArchive().getURI(); } + for (URL manifestURL : manifestURLs) { URI manifestLibURI = archiveURI.relativize(manifestURL.toURI()); if (manifestLibURI.isAbsolute()) { @@ -400,13 +402,15 @@ public static List getExternalLibraries(ReadableArchive archive) { } } } catch (Exception e) { - Logger.getAnonymousLogger().log(Level.WARNING, e.getMessage(), e); + Logger.getAnonymousLogger().log(WARNING, e.getMessage(), e); } + return externalLibURIs; } /** * Opens the specified file as an archive, using the provided archive factory. + * * @param dir directory to be opened as an archive * @param archiveFactory ArchiveFactory to use to create the archive object * @return FileArchive opened for the directory @@ -417,8 +421,7 @@ public static FileArchive openAsFileArchive(final File dir, final ArchiveFactory } /* - * @return comma-separated list of all defined virtual servers (exclusive - * of __asadmin) on the specified target + * @return comma-separated list of all defined virtual servers (exclusive of __asadmin) on the specified target */ public static String getVirtualServers(String target, ServerEnvironment env, Domain domain) { if (target == null) { @@ -431,21 +434,21 @@ public static String getVirtualServers(String target, ServerEnvironment env, Dom if (env.isDas() && DeploymentUtils.isDomainTarget(target)) { target = "server"; } - StringBuilder sb = new StringBuilder(); + + boolean first = true; Server server = domain.getServerNamed(target); Config config = null; if (server != null) { - config = domain.getConfigs().getConfigByName( - server.getConfigRef()); + config = domain.getConfigs().getConfigByName(server.getConfigRef()); } else { Cluster cluster = domain.getClusterNamed(target); if (cluster != null) { - config = domain.getConfigs().getConfigByName( - cluster.getConfigRef()); + config = domain.getConfigs().getConfigByName(cluster.getConfigRef()); } } + StringBuilder virtualServers = new StringBuilder(); if (config != null) { HttpService httpService = config.getHttpService(); if (httpService != null) { @@ -456,18 +459,18 @@ public static String getVirtualServers(String target, ServerEnvironment env, Dom continue; } if (first) { - sb.append(host.getId()); + virtualServers.append(host.getId()); first = false; } else { - sb.append(","); - sb.append(host.getId()); + virtualServers.append(","); + virtualServers.append(host.getId()); } } } } } - return sb.toString(); + return virtualServers.toString(); } public static void copyStream(InputStream in, OutputStream out) throws IOException { @@ -475,6 +478,6 @@ public static void copyStream(InputStream in, OutputStream out) throws IOExcepti int len; while ((len = in.read(buf)) >= 0) { out.write(buf, 0, len); -} + } } } diff --git a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/InstalledLibrariesResolver.java b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/InstalledLibrariesResolver.java index fa8125957a5..9dba0e94130 100644 --- a/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/InstalledLibrariesResolver.java +++ b/nucleus/deployment/common/src/main/java/org/glassfish/deployment/common/InstalledLibrariesResolver.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,272 +17,252 @@ package org.glassfish.deployment.common; -import java.io.*; +import static java.util.Collections.emptyList; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.FINEST; +import static java.util.logging.Level.INFO; +import static java.util.logging.Level.WARNING; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.text.MessageFormat; -import java.util.jar.JarFile; -import java.util.jar.Manifest; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.Set; +import java.util.StringTokenizer; import java.util.jar.Attributes; +import java.util.jar.JarFile; import java.util.jar.JarInputStream; -import java.util.logging.*; -import java.util.*; +import java.util.jar.Manifest; +import java.util.logging.LogRecord; +import java.util.logging.Logger; import org.glassfish.api.deployment.archive.ReadableArchive; - import org.glassfish.logging.annotation.LogMessageInfo; /** * This class resolves the dependencies between optional packages (installed libraries) and also between * apps/stand-alone modules that depend on optional packages (installed libraries) + * * @author Sheetal Vartak */ public class InstalledLibrariesResolver { - /** Installed libraries list (accounts only for "domainRoot/lib/applibs" and not any - *of "java.ext.dirs" entries) + /** + * Installed libraries list (accounts only for "domainRoot/lib/applibs" and not any of "java.ext.dirs" entries) */ private static Map appLibsDirLibsStore = new HashMap(); public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; - @LogMessageInfo(message = "Optional package {0} does not exist or its Specification-Version does not match. Unable to satisfy dependency for {1}", level="WARNING") + @LogMessageInfo(message = "Optional package {0} does not exist or its Specification-Version does not match. Unable to satisfy dependency for {1}", level = "WARNING") private static final String PACKAGE_NOT_FOUND = "NCLS-DEPLOYMENT-00011"; - @LogMessageInfo(message = "Optional package dependency satisfied for {0}", level="INFO") + @LogMessageInfo(message = "Optional package dependency satisfied for {0}", level = "INFO") private static final String PACKAGE_SATISFIED = "NCLS-DEPLOYMENT-00012"; - @LogMessageInfo(message = "Error in opening optional package file {0} due to exception: {1}.", level="WARNING") + @LogMessageInfo(message = "Error in opening optional package file {0} due to exception: {1}.", level = "WARNING") private static final String INVALID_ZIP = "NCLS-DEPLOYMENT-00013"; - @LogMessageInfo(message = "Exception occurred : {0}.", level="WARNING") + @LogMessageInfo(message = "Exception occurred : {0}.", level = "WARNING") private static final String EXCEPTION_OCCURRED = "NCLS-DEPLOYMENT-00014"; - @LogMessageInfo(message = "Specification-Version for the optional package [ {0} ] in the jarfile [ {1} ] is not specified. Please provide a valid specification version for this optional package", level="WARNING") + @LogMessageInfo(message = "Specification-Version for the optional package [ {0} ] in the jarfile [ {1} ] is not specified. Please provide a valid specification version for this optional package", level = "WARNING") private static final String NULL_SPEC_VERS = "NCLS-DEPLOYMENT-00015"; - @LogMessageInfo(message = "Skipping extension processing for {0} due to error: {1}", level="INFO") + @LogMessageInfo(message = "Skipping extension processing for {0} due to error: {1}", level = "INFO") private static final String SKIPPING_PROCESSING_INFO = "NCLS-DEPLOYMENT-00016"; /** * resolves installed library dependencies + * * @param manifest Manifest File * @param archiveUri archive * @return status indicating whether all dependencies (transitive) is resolved or not */ public static boolean resolveDependencies(Manifest manifest, String archiveUri) { - - //let us try app-libs directory + // let us try app-libs directory try { getInstalledLibraries(archiveUri, manifest, true, appLibsDirLibsStore); } catch (MissingResourceException e1) { - deplLogger.log(Level.WARNING, PACKAGE_NOT_FOUND, new Object[] { e1.getClass(), archiveUri}); + deplLogger.log(WARNING, PACKAGE_NOT_FOUND, new Object[] { e1.getClass(), archiveUri }); return false; } - deplLogger.log(Level.INFO, PACKAGE_SATISFIED, new Object[]{archiveUri}); + deplLogger.log(INFO, PACKAGE_SATISFIED, new Object[] { archiveUri }); return true; } /** - * check whether the optional packages have all their - * internal dependencies resolved + * Check whether the optional packages have all their internal dependencies resolved + * * @param libDir libraryDirectory */ - public static void initializeInstalledLibRegistry(String libDir ) { + public static void initializeInstalledLibRegistry(String libDir) { initializeInstalledLibRegistryForApplibs(libDir); } - /** - * Adds all the jar files in all of the ext dirs into a single string - * in classpath format. Returns the empty string if there are no - * jar files in any ext dirs. - * @return an empty string - * @deprecated This will always return an empty string for JDK9+ - */ - @Deprecated - public static String getExtDirFilesAsClasspath() { - return ""; - } - public static Set getInstalledLibraries(ReadableArchive archive) throws IOException { Set libraries = new HashSet(); - if (archive != null) { - Manifest manifest = archive.getManifest(); - - //we are looking for libraries only in "applibs" directory, hence strict=false - Set installedLibraries = - getInstalledLibraries(archive.getURI().toString(), manifest, false, appLibsDirLibsStore); - libraries.addAll(installedLibraries); - - // now check my libraries. - Vector libs = getArchiveLibraries(archive); - if (libs != null) { - for (String libUri : libs) { - JarInputStream jis = null; - try { - InputStream libIs = archive.getEntry(libUri); - if(libIs == null) { - //libIs can be null if reading an exploded archive where directories are also exploded. See FileArchive.getEntry() - continue; - } - jis = new JarInputStream(libIs); - manifest = jis.getManifest(); - if (manifest != null) { - //we are looking for libraries only in "applibs" directory, hence strict=false - Set jarLibraries = - getInstalledLibraries(archive.getURI().toString(), manifest, false, - appLibsDirLibsStore); - libraries.addAll(jarLibraries); - } - } finally { - if (jis != null) - jis.close(); - } + if (archive == null) { + return libraries; + } + + Manifest manifest = archive.getManifest(); + + // We are looking for libraries only in "applibs" directory, hence strict=false + Set installedLibraries = getInstalledLibraries(archive.getURI().toString(), manifest, false, appLibsDirLibsStore); + libraries.addAll(installedLibraries); + + // Now check any embedded libraries. + for (String libUri : getEmbeddedLibraries(archive)) { + try (InputStream embeddedLibInputStream = archive.getEntry(libUri)) { + if (embeddedLibInputStream == null) { + // embeddedLibInputStream can be null if reading an exploded archive where directories are also exploded. See + // FileArchive.getEntry() + continue; + } + + manifest = new JarInputStream(embeddedLibInputStream).getManifest(); + if (manifest != null) { + // We are looking for libraries only in "applibs" directory, hence strict=false + libraries.addAll(getInstalledLibraries(archive.getURI().toString(), manifest, false, appLibsDirLibsStore)); } } } + return libraries; } - private static Set getInstalledLibraries(String archiveURI, Manifest manifest, boolean strict, - Map libraryStore) { + private static Set getInstalledLibraries(String archiveURI, Manifest manifest, boolean strict, Map libraryStore) { Set libraries = new HashSet(); String extensionList = null; + try { - extensionList = manifest.getMainAttributes(). - getValue(Attributes.Name.EXTENSION_LIST); - if(deplLogger.isLoggable(Level.FINE)){ + extensionList = manifest.getMainAttributes().getValue(Attributes.Name.EXTENSION_LIST); + if (deplLogger.isLoggable(FINE)) { deplLogger.fine("Extension-List for archive [" + archiveURI + "] : " + extensionList); } } catch (Exception e) { - //ignore this exception - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, - "InstalledLibrariesResolver : exception occurred : " + e.toString()); - } + // Ignore this exception + deplLogger.log(FINE, () -> "InstalledLibrariesResolver : exception occurred : " + e.toString()); } if (extensionList != null) { - StringTokenizer st = - new StringTokenizer(extensionList, " "); - while (st.hasMoreTokens()) { - - String token = st.nextToken().trim(); - String extName = manifest.getMainAttributes(). - getValue(token + "-" + Attributes.Name.EXTENSION_NAME); - if (extName != null) { - extName = extName.trim(); + StringTokenizer extensionListTokenizer = new StringTokenizer(extensionList, " "); + while (extensionListTokenizer.hasMoreTokens()) { + + String token = extensionListTokenizer.nextToken().trim(); + String extensionName = manifest.getMainAttributes().getValue(token + "-" + Attributes.Name.EXTENSION_NAME); + if (extensionName != null) { + extensionName = extensionName.trim(); } - String specVersion = manifest.getMainAttributes(). - getValue(token + "-" + Attributes.Name.SPECIFICATION_VERSION); + String specVersion = manifest.getMainAttributes().getValue(token + "-" + Attributes.Name.SPECIFICATION_VERSION); - Extension extension = new Extension(extName); + Extension extension = new Extension(extensionName); if (specVersion != null) { extension.setSpecVersion(specVersion); } - //TODO possible NPE when extension is unspecified + + // TODO possible NPE when extension is unspecified boolean isLibraryInstalled = libraryStore.containsKey(extension); if (isLibraryInstalled) { - String libraryName = libraryStore.get(extension); - libraries.add(libraryName); - } else { - if(strict){ - throw new MissingResourceException(extName + " not found", extName, null); - }else{ - // no action needed - } + libraries.add(libraryStore.get(extension)); + } else if (strict) { + throw new MissingResourceException(extensionName + " not found", extensionName, null); } - if (deplLogger.isLoggable(Level.FINEST)) { - deplLogger.log(Level.FINEST, " is library installed [" + extName + "] " + - "for archive [" + archiveURI + "]: " + isLibraryInstalled); + + if (deplLogger.isLoggable(FINEST)) { + deplLogger.log(FINEST, + " is library installed [" + extensionName + "] " + "for archive [" + archiveURI + "]: " + isLibraryInstalled); } } } + return libraries; } - /** - * @return a list of libraries included in the archivist + * @return a list of libraries included in the archive */ - private static Vector getArchiveLibraries(ReadableArchive archive) { - + private static List getEmbeddedLibraries(ReadableArchive archive) { Enumeration entries = archive.entries(); - if (entries == null) - return null; + if (entries == null) { + emptyList(); + } - Vector libs = new Vector(); + List libs = new ArrayList<>(); 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; } - /** - * initialize the "applibs" part of installed libraries ie., - * any library within "applibs" which represents an extension (EXTENSION_NAME in MANIFEST.MF) - * that can be used by applications (as EXTENSION_LIST in their MANIFEST.MF) + * Initialize the "applibs" part of installed libraries ie., any library within "applibs" which represents an extension + * (EXTENSION_NAME in MANIFEST.MF) that can be used by applications (as EXTENSION_LIST in their MANIFEST.MF) + * * @param domainLibDir library directory (of a domain) */ private static void initializeInstalledLibRegistryForApplibs(String domainLibDir) { - String applibsDirString = domainLibDir + File.separator + "applibs"; - deplLogger.fine("applib-Dir-String..." + applibsDirString); - ArrayList validApplibsDirLibFiles = new ArrayList(); + + List validApplibsDirLibFiles = new ArrayList<>(); Map installedLibraries = getInstalledLibraries(applibsDirString, null, validApplibsDirLibFiles); appLibsDirLibsStore.putAll(installedLibraries); - for (File file : validApplibsDirLibFiles) { JarFile jarFile = null; try { jarFile = new JarFile(file); - Manifest m = jarFile.getManifest(); - if (m!=null) { - try{ - getInstalledLibraries(file.getAbsolutePath(), m, true, appLibsDirLibsStore); - }catch(MissingResourceException mre ){ - deplLogger.log(Level.WARNING, PACKAGE_NOT_FOUND, new Object[] {mre.getClass(), file.getAbsolutePath()}); + Manifest manifest = jarFile.getManifest(); + if (manifest != null) { + try { + getInstalledLibraries(file.getAbsolutePath(), manifest, true, appLibsDirLibsStore); + } catch (MissingResourceException mre) { + deplLogger.log(WARNING, PACKAGE_NOT_FOUND, new Object[] { mre.getClass(), file.getAbsolutePath() }); } - } } catch (IOException ioe) { - deplLogger.log(Level.WARNING, - INVALID_ZIP, - new Object[] {file.getAbsolutePath(), ioe.getMessage()}); - }finally { - if (jarFile!=null) + deplLogger.log(WARNING, INVALID_ZIP, new Object[] { file.getAbsolutePath(), ioe.getMessage() }); + } finally { + if (jarFile != null) { try { jarFile.close(); } catch (IOException e) { - deplLogger.log(Level.WARNING, - EXCEPTION_OCCURRED, - new Object[] {e.getMessage()}); + deplLogger.log(WARNING, EXCEPTION_OCCURRED, new Object[] { e.getMessage() }); } + } } } - } - private static Map getInstalledLibraries(String libraryDirectoryName, Set processedLibraryNames, - List processedLibraries) { + private static Map getInstalledLibraries(String libraryDirectoryName, Set processedLibraryNames, List processedLibraries) { Map installedLibraries = new HashMap(); File dir = new File(libraryDirectoryName); - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, "installed library directory : " + dir); + if (deplLogger.isLoggable(FINE)) { + deplLogger.log(FINE, "installed library directory : " + dir); } File[] libraries = dir.listFiles(); @@ -289,52 +270,45 @@ private static Map getInstalledLibraries(String libraryDirect try { for (int i = 0; i < libraries.length; i++) { - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, "installed library : " + libraries[i]); + if (deplLogger.isLoggable(FINE)) { + deplLogger.log(FINE, "installed library : " + libraries[i]); } + /* - *Skip any candidate that does not end with .jar or is a - *directory. + * Skip any candidate that does not end with .jar or is a directory. */ if (libraries[i].isDirectory()) { - deplLogger.log(Level.FINE, - "Skipping installed library processing on " + - libraries[i].getAbsolutePath() + - "; it is a directory"); + deplLogger.log(FINE, "Skipping installed library processing on " + libraries[i].getAbsolutePath() + "; it is a directory"); continue; - } else if (!libraries[i].getName().toLowerCase(Locale.getDefault()).endsWith(".jar")) { - deplLogger.log(Level.FINE, - "Skipping installed library processing on " + - libraries[i].getAbsolutePath() + - "; it does not appear to be a JAR file based on its file type"); + } + + if (!libraries[i].getName().toLowerCase(Locale.getDefault()).endsWith(".jar")) { + deplLogger.log(FINE, "Skipping installed library processing on " + libraries[i].getAbsolutePath() + + "; it does not appear to be a JAR file based on its file type"); continue; } + JarFile jarFile = null; try { jarFile = new JarFile(libraries[i]); Manifest manifest = jarFile.getManifest(); - if(processedLibraryNames != null){ + if (processedLibraryNames != null) { processedLibraryNames.add(libraries[i].toString()); } - if(processedLibraries != null){ + if (processedLibraries != null) { processedLibraries.add(libraries[i]); } - //Extension-Name of optional package + // Extension-Name of optional package if (manifest != null) { - String extName = manifest.getMainAttributes(). - getValue(Attributes.Name.EXTENSION_NAME); - String specVersion = manifest.getMainAttributes(). - getValue(Attributes.Name.SPECIFICATION_VERSION); - deplLogger.fine("Extension " + libraries[i].getAbsolutePath() + - ", extNameOfOPtionalPkg..." + extName + - ", specVersion..." + specVersion); + String extName = manifest.getMainAttributes().getValue(Attributes.Name.EXTENSION_NAME); + String specVersion = manifest.getMainAttributes().getValue(Attributes.Name.SPECIFICATION_VERSION); + deplLogger.fine("Extension " + libraries[i].getAbsolutePath() + ", extNameOfOPtionalPkg..." + extName + + ", specVersion..." + specVersion); if (extName != null) { if (specVersion == null) { - deplLogger.log(Level.WARNING, - NULL_SPEC_VERS, - new Object[]{extName, jarFile.getName()}); + deplLogger.log(WARNING, NULL_SPEC_VERS, new Object[] { extName, jarFile.getName() }); specVersion = ""; } @@ -345,15 +319,12 @@ private static Map getInstalledLibraries(String libraryDirect } } } catch (Throwable thr) { - String msg = deplLogger.getResourceBundle().getString( - "enterprise.deployment.backend.optionalpkg.dependency.error"); - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, MessageFormat.format( - msg, libraries[i].getAbsolutePath(), thr.getMessage()), thr); + String msg = deplLogger.getResourceBundle().getString("enterprise.deployment.backend.optionalpkg.dependency.error"); + if (deplLogger.isLoggable(FINE)) { + deplLogger.log(FINE, MessageFormat.format(msg, libraries[i].getAbsolutePath(), thr.getMessage()), thr); } else { - LogRecord lr = new LogRecord(Level.INFO, - SKIPPING_PROCESSING_INFO); - lr.setParameters(new Object[] { libraries[i].getAbsolutePath(), thr.getMessage() } ); + LogRecord lr = new LogRecord(INFO, SKIPPING_PROCESSING_INFO); + lr.setParameters(new Object[] { libraries[i].getAbsolutePath(), thr.getMessage() }); deplLogger.log(lr); } } finally { @@ -363,10 +334,11 @@ private static Map getInstalledLibraries(String libraryDirect } } } catch (IOException e) { - deplLogger.log(Level.WARNING, - "enterprise.deployment.backend.optionalpkg.dependency.exception", new Object[]{e.getMessage()}); + deplLogger.log(WARNING, "enterprise.deployment.backend.optionalpkg.dependency.exception", + new Object[] { e.getMessage() }); } } + return installedLibraries; } @@ -377,7 +349,7 @@ static class Extension { private String implVersion = ""; private String implVendor = ""; - public Extension(String name){ + public Extension(String name) { this.extensionName = name; } @@ -421,28 +393,28 @@ public void setImplVendor(String implVendor) { this.implVendor = implVendor; } - public boolean equals(Object o){ - if(o != null && o instanceof Extension){ - Extension e = (Extension)o; - if((o == this) || - (e.getExtensionName().equals(extensionName) && - (e.getImplVendor().equals(implVendor) || (e.getImplVendor().equals("")) ) && - (e.getImplVersion().equals(implVersion) || (e.getImplVersion().equals("")) ) && - (e.getSpecVendor().equals(specVendor) || (e.getSpecVendor().equals("")) ) && - (e.getSpecVersion().equals(specVersion) || (e.getSpecVersion().equals("")) ) - )){ + @Override + public boolean equals(Object o) { + if (o != null && o instanceof Extension) { + Extension e = (Extension) o; + if ((o == this) || (e.getExtensionName().equals(extensionName) + && (e.getImplVendor().equals(implVendor) || (e.getImplVendor().equals(""))) + && (e.getImplVersion().equals(implVersion) || (e.getImplVersion().equals(""))) + && (e.getSpecVendor().equals(specVendor) || (e.getSpecVendor().equals(""))) + && (e.getSpecVersion().equals(specVersion) || (e.getSpecVersion().equals(""))))) { return true; - }else{ + } else { return false; } - }else { + } else { return false; } } + @Override public int hashCode() { int result = 17; - result = 37*result + extensionName.hashCode(); + result = 37 * result + extensionName.hashCode(); return result; } } diff --git a/nucleus/deployment/common/src/main/java/org/glassfish/loader/util/ASClassLoaderUtil.java b/nucleus/deployment/common/src/main/java/org/glassfish/loader/util/ASClassLoaderUtil.java index 6b3a083dd84..fbfed741371 100644 --- a/nucleus/deployment/common/src/main/java/org/glassfish/loader/util/ASClassLoaderUtil.java +++ b/nucleus/deployment/common/src/main/java/org/glassfish/loader/util/ASClassLoaderUtil.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2022, 2022 Contributors to the Eclipse Foundation. * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the @@ -16,221 +17,207 @@ package org.glassfish.loader.util; -import com.sun.enterprise.module.HK2Module; -import com.sun.enterprise.module.ModulesRegistry; -import com.sun.enterprise.util.io.FileUtils; -import org.glassfish.api.deployment.DeployCommandParameters; -import org.glassfish.api.deployment.DeploymentContext; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.internal.api.ClassLoaderHierarchy; -import org.glassfish.internal.data.ApplicationRegistry; -import org.glassfish.internal.data.ApplicationInfo; -import org.glassfish.api.admin.ServerEnvironment; -import com.sun.enterprise.deployment.deploy.shared.Util; +import static com.sun.enterprise.util.Utility.isEmpty; +import static com.sun.enterprise.util.io.FileUtils.isJar; +import static com.sun.enterprise.util.io.FileUtils.isZip; +import static java.io.File.pathSeparator; +import static java.io.File.separator; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.WARNING; + import java.io.File; -import java.io.FileFilter; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.FileInputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; -import java.net.URISyntaxException; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.LogRecord; -import java.util.jar.JarFile; -import java.util.jar.Manifest; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.StringTokenizer; import java.util.jar.Attributes; -import java.util.*; +import java.util.jar.Attributes.Name; +import java.util.jar.Manifest; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.deployment.DeployCommandParameters; +import org.glassfish.api.deployment.DeploymentContext; +import org.glassfish.deployment.common.DeploymentContextImpl; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.api.ClassLoaderHierarchy; +import org.glassfish.internal.data.ApplicationInfo; +import org.glassfish.internal.data.ApplicationRegistry; import org.glassfish.logging.annotation.LogMessageInfo; +import com.sun.enterprise.deployment.deploy.shared.Util; +import com.sun.enterprise.module.HK2Module; +import com.sun.enterprise.module.ModulesRegistry; + public class ASClassLoaderUtil { - public static final Logger deplLogger = org.glassfish.deployment.common.DeploymentContextImpl.deplLogger; + public static final Logger deplLogger = DeploymentContextImpl.deplLogger; - @LogMessageInfo(message = "Cannot convert classpath to URL {0}", level="WARNING") + @LogMessageInfo(message = "Cannot convert classpath to URL {0}", level = "WARNING") private static final String CLASSPATH_ERROR = "NCLS-DEPLOYMENT-00045"; - @LogMessageInfo(message = "Exception: {0}", level="WARNING") + @LogMessageInfo(message = "Exception: {0}", level = "WARNING") private static final String EXCEPTION = "NCLS-DEPLOYMENT-00017"; - @LogMessageInfo(message = "unexpected error in getting urls", level="WARNING") + @LogMessageInfo(message = "unexpected error in getting urls", level = "WARNING") private static final String UNEXPECTED_EXCEPTION = "NCLS-DEPLOYMENT-00018"; - private static String modulesClassPath = null; + private static String modulesClassPath; /** The manifest file name from an archive. */ - private static final String MANIFEST_ENTRY = - "META-INF" + File.separator + "MANIFEST.MF"; + private static final String MANIFEST_ENTRY = "META-INF" + separator + "MANIFEST.MF"; /** - * Gets the classpath associated with a module, suffixing libraries - * defined [if any] for the application + * Gets the classpath associated with a module, suffixing libraries defined [if any] for the application * - * @param habitat the habitat the application resides in. + * @param serviceLocator the habitat the application resides in. * @param moduleId HK2Module id of the module * @param deploymentLibs libraries option passed through deployment - * @return A File.pathSeparator separated list of classpaths - * for the passed in module, including the module specified - * "libraries" defined for the module. + * @return A File.pathSeparator separated list of classpaths for the passed in module, including the module + * specified "libraries" defined for the module. */ - public static String getModuleClassPath - (ServiceLocator habitat, String moduleId, String deploymentLibs) { + public static String getModuleClassPath(ServiceLocator serviceLocator, String moduleId, String deploymentLibs) { + deplLogger.log(FINE, () -> "ASClassLoaderUtil.getModuleClassPath " + "for module Id : " + moduleId); - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, - "ASClassLoaderUtil.getModuleClassPath " + "for module Id : " + moduleId); - } + StringBuilder classpath = new StringBuilder(getModulesClasspath(serviceLocator)); - StringBuilder classpath = new StringBuilder(getModulesClasspath(habitat)); - ClassLoaderHierarchy clh = - habitat.getService(ClassLoaderHierarchy.class); - final String commonClassPath = clh.getCommonClassPath(); - if (commonClassPath != null && commonClassPath.length() > 0) { - classpath.append(commonClassPath).append(File.pathSeparator); + String commonClassPath = serviceLocator.getService(ClassLoaderHierarchy.class).getCommonClassPath(); + if (!isEmpty(commonClassPath)) { + classpath.append(commonClassPath).append(pathSeparator); } - addDeployParamLibrariesForModule(classpath, moduleId, deploymentLibs, habitat); - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, - "Final classpath: " + classpath.toString()); - } - return classpath.toString(); + addDeployParamLibrariesForModule(classpath, moduleId, deploymentLibs, serviceLocator); + deplLogger.log(FINE, () -> "Final classpath: " + classpath.toString()); + + return classpath.toString(); } - public static String getModuleClassPath (ServiceLocator habitat, - DeploymentContext context) { - DeployCommandParameters params = - context.getCommandParameters(DeployCommandParameters.class); + public static String getModuleClassPath(ServiceLocator habitat, DeploymentContext context) { + DeployCommandParameters params = context.getCommandParameters(DeployCommandParameters.class); + return getModuleClassPath(habitat, params.name(), params.libraries()); } - - private static void addDeployParamLibrariesForModule(StringBuilder sb, - String moduleId, String deploymentLibs, ServiceLocator habitat) { + private static void addDeployParamLibrariesForModule(StringBuilder sb, String moduleId, String deploymentLibs, ServiceLocator serviceLocator) { if (moduleId.indexOf("#") != -1) { moduleId = moduleId.substring(0, moduleId.indexOf("#")); } if (deploymentLibs == null) { - ApplicationInfo appInfo = - habitat.getService(ApplicationRegistry.class).get(moduleId); + ApplicationInfo appInfo = serviceLocator.getService(ApplicationRegistry.class).get(moduleId); if (appInfo == null) { - // this might be an internal container app, - // like _default_web_app, ignore. + // This might be an internal container app, like _default_web_app, ignore. return; } deploymentLibs = appInfo.getLibraries(); } - final URL[] libs = - getDeployParamLibrariesAsURLs(deploymentLibs, habitat); + + final URL[] libs = getDeployParamLibrariesAsURLs(deploymentLibs, serviceLocator); if (libs != null) { - for (final URL u : libs) { - sb.append(u.getPath()); - sb.append(File.pathSeparator); + for (URL libUrl : libs) { + sb.append(libUrl.getPath()); + sb.append(pathSeparator); } } } - private static URL[] getDeployParamLibrariesAsURLs(String librariesStr, - ServiceLocator habitat) { - return getDeployParamLibrariesAsURLs(librariesStr, - habitat.getService(ServerEnvironment.class)); + private static URL[] getDeployParamLibrariesAsURLs(String librariesStr, ServiceLocator serviceLocator) { + return getDeployParamLibrariesAsURLs(librariesStr, serviceLocator.getService(ServerEnvironment.class)); } - /** - * converts libraries specified via EXTENSION_LIST entry in MANIFEST.MF of - * all of the libraries of the deployed archive to - * The libraries are made available to - * the application in the order specified. + * converts libraries specified via EXTENSION_LIST entry in MANIFEST.MF of all of the libraries of the deployed archive + * to The libraries are made available to the application in the order specified. * - * @param librariesStr is a comma-separated list of library JAR files + * @param libraries is a comma-separated list of library JAR files * @param env the server environment * @return array of URL */ - public static URL[] getLibrariesAsURLs(Set librariesStr, - ServerEnvironment env) { - if(librariesStr == null) + public static URL[] getLibrariesAsURLs(Set libraries, ServerEnvironment env) { + if (libraries == null) { return null; - final URL [] urls = new URL[librariesStr.size()]; - String [] librariesStrArray = new String[librariesStr.size()]; - librariesStrArray = librariesStr.toArray(librariesStrArray); - return getDeployParamLibrariesAsURLs(env, librariesStrArray, urls); + } + + return getDeployParamLibrariesAsURLs(env, libraries.toArray(new String[libraries.size()]), new URL[libraries.size()]); } /** - * converts libraries specified via the --libraries deployment option to - * URL[]. The library JAR files are specified by either relative or - * absolute paths. The relative path is relative to - * instance-root/lib/applibs. The libraries are made available to - * the application in the order specified. + * converts libraries specified via the --libraries deployment option to URL[]. The library JAR files are specified by + * either relative or absolute paths. The relative path is relative to instance-root/lib/applibs. The libraries are made + * available to the application in the order specified. * * @param librariesStr is a comma-separated list of library JAR files * @param env the server environment * @return array of URL */ - public static URL[] getDeployParamLibrariesAsURLs(String librariesStr, - ServerEnvironment env) { - if(librariesStr == null) + public static URL[] getDeployParamLibrariesAsURLs(String librariesStr, ServerEnvironment env) { + if (librariesStr == null) { return null; - String [] librariesStrArray = librariesStr.split(","); - final URL [] urls = new URL[librariesStrArray.length]; - return getDeployParamLibrariesAsURLs(env, librariesStrArray, urls); + } + + String[] librariesStrArray = librariesStr.split(","); + return getDeployParamLibrariesAsURLs(env, librariesStrArray, new URL[librariesStrArray.length]); } - private static URL[] getDeployParamLibrariesAsURLs(ServerEnvironment env, String[] librariesStrArray, - URL[] urls) { - final String appLibsDir = env.getLibPath() - + File.separator + "applibs"; + private static URL[] getDeployParamLibrariesAsURLs(ServerEnvironment env, String[] libraries, URL[] urls) { + final String appLibsDir = env.getLibPath() + File.separator + "applibs"; - int i=0; - for(final String libraryStr:librariesStrArray){ + int i = 0; + for (final String libraryStr : libraries) { try { - File f = new File(libraryStr); - if(!f.isAbsolute()) - f = new File(appLibsDir, libraryStr); - URL url =f.toURI().toURL(); + File libraryFile = new File(libraryStr); + if (!libraryFile.isAbsolute()) { + libraryFile = new File(appLibsDir, libraryStr); + } + + URL url = libraryFile.toURI().toURL(); urls[i++] = url; } catch (MalformedURLException malEx) { - deplLogger.log(Level.WARNING, - CLASSPATH_ERROR, - libraryStr); - LogRecord lr = new LogRecord(Level.WARNING, EXCEPTION); + deplLogger.log(WARNING, CLASSPATH_ERROR, libraryStr); + LogRecord lr = new LogRecord(WARNING, EXCEPTION); lr.setParameters(new Object[] { malEx.getMessage() }); lr.setThrown(malEx); deplLogger.log(lr); } } + return urls; } - private static synchronized String getModulesClasspath(ServiceLocator habitat) { + private static synchronized String getModulesClasspath(ServiceLocator serviceLocator) { synchronized (ASClassLoaderUtil.class) { if (modulesClassPath == null) { - final StringBuilder tmpString = new StringBuilder(); - ModulesRegistry mr = habitat.getService(ModulesRegistry.class); - if (mr != null) { - for (HK2Module module : mr.getModules()) { + final StringBuilder modulesClassPathBuilder = new StringBuilder(); + ModulesRegistry modulesRegistry = serviceLocator.getService(ModulesRegistry.class); + if (modulesRegistry != null) { + for (HK2Module module : modulesRegistry.getModules()) { for (URI uri : module.getModuleDefinition().getLocations()) { - tmpString.append(uri.getPath()); - tmpString.append(File.pathSeparator); + modulesClassPathBuilder.append(uri.getPath()); + modulesClassPathBuilder.append(pathSeparator); } } } - //set shared classpath for module so that it doesn't need to be - //recomputed for every other invocation - modulesClassPath = tmpString.toString(); + // Set shared classpath for module so that it doesn't need to be + // recomputed for every other invocation + modulesClassPath = modulesClassPathBuilder.toString(); } } + return modulesClassPath; } /** * Returns an array of urls that contains .. + * *
      *    i.   all the valid directories from the given directory (dirs) array
      *    ii.  all jar files from the given directory (jarDirs) array
@@ -238,22 +225,20 @@ private static synchronized String getModulesClasspath(ServiceLocator habitat) {
      *         not ignoring zip file (ignoreZip is false).
      * 
* - * @param dirs array of directory path names - * @param jarDirs array of path name to directories that contains - * JAR & ZIP files. - * @param ignoreZip whether to ignore zip files - * @return an array of urls that contains all the valid dirs, - * *.jar & *.zip + * @param dirs array of directory path names + * @param jarDirs array of path name to directories that contains JAR & ZIP files. + * @param ignoreZip whether to ignore zip files + * @return an array of urls that contains all the valid dirs, *.jar & *.zip * - * @throws IOException if an i/o error while constructing the urls + * @throws IOException if an i/o error while constructing the urls */ - public static URL[] getURLs(File[] dirs, File[] jarDirs, - boolean ignoreZip) throws IOException { + public static URL[] getURLs(File[] dirs, File[] jarDirs, boolean ignoreZip) throws IOException { return convertURLListToArray(getURLsAsList(dirs, jarDirs, ignoreZip)); } /** * Returns a list of urls that contains .. + * *
      *    i.   all the valid directories from the given directory (dirs) array
      *    ii.  all jar files from the given directory (jarDirs) array
@@ -261,59 +246,54 @@ public static URL[] getURLs(File[] dirs, File[] jarDirs,
      *         not ignoring zip file (ignoreZip is false).
      * 
* - * @param dirs array of directory path names - * @param jarDirs array of path name to directories that contains - * JAR & ZIP files. - * @param ignoreZip whether to ignore zip files - * @return an array of urls that contains all the valid dirs, - * *.jar & *.zip + * @param dirs array of directory path names + * @param jarDirs array of path name to directories that contains JAR & ZIP files. + * @param ignoreZip whether to ignore zip files + * @return an array of urls that contains all the valid dirs, *.jar & *.zip * - * @throws IOException if an i/o error while constructing the urls + * @throws IOException if an i/o error while constructing the urls */ - public static List getURLsAsList(File[] dirs, File[] jarDirs, - boolean ignoreZip) throws IOException { + public static List getURLsAsList(File[] dirs, File[] jarDirs, boolean ignoreZip) throws IOException { List list = new ArrayList(); - // adds all directories + // Adds all directories if (dirs != null) { - for (int i=0; i list) { URL[] urls = new URL[0]; if (list != null && list.size() > 0) { urls = new URL[list.size()]; - urls = (URL[]) list.toArray(urls); + urls = list.toArray(urls); } return urls; } /** * get URL list from classpath + * * @param classpath classpath string containing the classpaths - * @param delimiter delimiter to separate the classpath components - * in the classpath string + * @param delimiter delimiter to separate the classpath components in the classpath string * @param rootPath root path of the classpath if the paths are relative - + * * @return urlList URL list from the given classpath */ - public static List getURLsFromClasspath(String classpath, - String delimiter, String rootPath) { - final List urls = new ArrayList(); + public static List getURLsFromClasspath(String classpath, String delimiter, String rootPath) { + final List urls = new ArrayList(); - if (classpath == null || classpath.length() == 0) { + if (isEmpty(classpath)) { return urls; } - // tokenize classpath - final StringTokenizer st = new StringTokenizer(classpath, delimiter); - while (st.hasMoreTokens()) { + // Tokenize classpath + final StringTokenizer classpathTokenizer = new StringTokenizer(classpath, delimiter); + while (classpathTokenizer.hasMoreTokens()) { try { - String path = st.nextToken(); + String path = classpathTokenizer.nextToken(); try { - // try to see if the path is absolute - URL url = new URL(path); - URI uri = url.toURI(); + // Try to see if the path is absolute + URI uri = new URL(path).toURI(); if (uri.isAbsolute()) { urls.add(uri.toURL()); continue; @@ -364,89 +342,62 @@ public static List getURLsFromClasspath(String classpath, if (rootPath != null && rootPath.length() != 0) { path = rootPath + File.separator + path; } - File f = new File(path); - urls.add(f.toURI().toURL()); - } catch(Exception e) { - deplLogger.log(Level.WARNING, - UNEXPECTED_EXCEPTION, - e); + + urls.add(new File(path).toURI().toURL()); + } catch (Exception e) { + deplLogger.log(WARNING, UNEXPECTED_EXCEPTION, e); } } + return urls; } - /** + /** * Returns the manifest file for the given root path. * - * - * Example: - * |--repository/ - * | |--applications/ - * | |--converter/ - * | |--ejb-jar-ic_jar/ <---- rootPath - * | |--META-INF/ - * | |--MANIFEST.MF - * + * Example: |--repository/ | |--applications/ | |--converter/ | |--ejb-jar-ic_jar/ <---- rootPath | |--META-INF/ | + * |--MANIFEST.MF * - * @param rootPath absolute path to the module + * @param rootPath absolute path to the module * - * @return the manifest file for the given module + * @return the manifest file for the given module */ public static Manifest getManifest(String rootPath) { - - InputStream in = null; - Manifest mf = null; - - // gets the input stream to the MANIFEST.MF file - try { - in = new FileInputStream(rootPath+File.separator+MANIFEST_ENTRY); - - if (in != null) { - mf = new Manifest(in); - } + // Gets the input stream to the MANIFEST.MF file + try (InputStream in = new FileInputStream(rootPath + separator + MANIFEST_ENTRY)) { + return new Manifest(in); } catch (IOException ioe) { // ignore - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ioe) { - // Ignore - } - } + return null; } - return mf; } - /** - * Returns the class path (if any) from the given manifest file as an - * URL list. + * Returns the class path (if any) from the given manifest file as an URL list. * - * @param manifest manifest file of an archive - * @param rootPath root path to the module + * @param manifest manifest file of an archive + * @param rootPath root path to the module * - * @return a list of URLs - * an empty list if given manifest is null + * @return a list of URLs an empty list if given manifest is null */ - public static List getManifestClassPathAsURLs(Manifest manifest, - String rootPath) { - List urlList = new ArrayList(); - if (manifest != null) { - Attributes mainAttributes = manifest.getMainAttributes(); + public static List getManifestClassPathAsURLs(Manifest manifest, String rootPath) { + List urls = new ArrayList<>(); + if (manifest == null) { + return urls; + } - for (Map.Entry entry : mainAttributes.entrySet()) { + Attributes mainAttributes = manifest.getMainAttributes(); - Attributes.Name next = (Attributes.Name) entry.getKey(); + for (Entry entry : mainAttributes.entrySet()) { + Name next = (Name) entry.getKey(); - if (next.equals(Attributes.Name.CLASS_PATH)) { - String classpathString = (String) entry.getValue(); - urlList = getURLsFromClasspath(classpathString, " ", - rootPath); - } + if (next.equals(Name.CLASS_PATH)) { + String classpathString = (String) entry.getValue(); + urls = getURLsFromClasspath(classpathString, " ", rootPath); } } - return urlList; + + return urls; } /** @@ -454,25 +405,19 @@ public static List getManifestClassPathAsURLs(Manifest manifest, * * @param appRoot the application root * @param appLibDir the Application library directory - * @param compatibilityProp the version of the release that we need to - * maintain backward compatibility + * @param compatibilityProp the version of the release that we need to maintain backward compatibility * @return an array of URL */ - public static URL[] getAppLibDirLibraries(File appRoot, String appLibDir, - String compatibilityProp) - throws IOException { - return convertURLListToArray( - getAppLibDirLibrariesAsList(appRoot, appLibDir, compatibilityProp)); + public static URL[] getAppLibDirLibraries(File appRoot, String appLibDir, String compatibilityProp) throws IOException { + return convertURLListToArray(getAppLibDirLibrariesAsList(appRoot, appLibDir, compatibilityProp)); } - public static List getAppLibDirLibrariesAsList(File appRoot, String appLibDir, String compatibilityProp) - throws IOException { + public static List getAppLibDirLibrariesAsList(File appRoot, String appLibDir, String compatibilityProp) throws IOException { URL[] libDirLibraries = new URL[0]; // get all the app lib dir libraries if (appLibDir != null) { String libPath = appLibDir.replace('/', File.separatorChar); - libDirLibraries = getURLs(null, - new File[] {new File(appRoot, libPath)}, true); + libDirLibraries = getURLs(null, new File[] { new File(appRoot, libPath) }, true); } List allLibDirLibraries = new ArrayList(); @@ -480,23 +425,20 @@ public static List getAppLibDirLibrariesAsList(File appRoot, String appLibD allLibDirLibraries.add(url); } - // if the compatibility property is set to "v2", we should add all the + // If the compatibility property is set to "v2", we should add all the // jars under the application root to maintain backward compatibility // of v2 jar visibility if (compatibilityProp != null && compatibilityProp.equals("v2")) { - List appRootLibraries = getURLsAsList(null, new File[] {appRoot}, true); + List appRootLibraries = getURLsAsList(null, new File[] { appRoot }, true); allLibDirLibraries.addAll(appRootLibraries); } + return allLibDirLibraries; } public static List getLibDirectoryJarURIs(File moduleLibDirectory) throws Exception { List libLibraryURIs = new ArrayList(); - File[] jarFiles = moduleLibDirectory.listFiles(new FileFilter() { - public boolean accept(File pathname) { - return (pathname.getAbsolutePath().endsWith(".jar")); - } - }); + File[] jarFiles = moduleLibDirectory.listFiles(pathname -> pathname.getAbsolutePath().endsWith(".jar")); if (jarFiles != null && jarFiles.length > 0) { for (File jarFile : jarFiles) { From c889fe7b36ca1d5d534c4abaa890b8b4802f7beb Mon Sep 17 00:00:00 2001 From: Arjan Tijms Date: Tue, 31 May 2022 17:43:57 +0200 Subject: [PATCH 2/2] Add scanning of extension-list jars Signed-off-by: Arjan Tijms --- .../com/sun/enterprise/v3/server/ApplicationLifecycle.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java index 587f674b589..f16d4c3370f 100644 --- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java +++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ApplicationLifecycle.java @@ -666,6 +666,11 @@ private List getExternalLibraries(DeploymentContext context) th externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); } + // Get the libraries referenced in the manifest extension-list + for (URI externalLib : context.getAppLibs()) { + externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); + } + return externalLibArchives; }