diff --git a/appserver/common/annotation-framework/osgi.bundle b/appserver/common/annotation-framework/osgi.bundle index 8b97d0499e3..96d1caa39c4 100644 --- a/appserver/common/annotation-framework/osgi.bundle +++ b/appserver/common/annotation-framework/osgi.bundle @@ -37,10 +37,12 @@ # only if the new code is made subject to such option by the copyright # holder. # +# Portions Copyright [2025] [Payara Foundation and/or its affiliates] -exportcontents: \ org.glassfish.apf; \ org.glassfish.apf.context; \ org.glassfish.apf.factory; \ + org.glassfish.apf.jandex; \ org.glassfish.apf.impl; version=${project.osgi.version} diff --git a/appserver/common/annotation-framework/pom.xml b/appserver/common/annotation-framework/pom.xml index a8d46a1137f..45e0000e8f6 100755 --- a/appserver/common/annotation-framework/pom.xml +++ b/appserver/common/annotation-framework/pom.xml @@ -106,6 +106,16 @@ common-util ${project.version} + + fish.payara.server.internal.deployment + deployment-common + ${project.version} + + + fish.payara.server.internal.core + kernel + ${project.version} + fish.payara.server.internal.common internal-api diff --git a/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/JavaEEScanner.java b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/JavaEEScanner.java index 79596d8c45f..ef7adebd517 100644 --- a/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/JavaEEScanner.java +++ b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/JavaEEScanner.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018] Payara Foundation and/or affiliates +// Portions Copyright [2018-2025] Payara Foundation and/or affiliates /* * JavaEEScanner.java @@ -47,8 +47,6 @@ package org.glassfish.apf.impl; import org.glassfish.apf.ComponentInfo; -import org.glassfish.hk2.classmodel.reflect.Parser; -import org.glassfish.hk2.classmodel.reflect.ParsingContext; import org.glassfish.hk2.classmodel.reflect.Types; import java.io.File; @@ -64,24 +62,14 @@ public abstract class JavaEEScanner { Types types; public ComponentInfo getComponentInfo(Class componentImpl) { - return new ComponentDefinition(componentImpl); + throw new UnsupportedOperationException("No longer supported"); } protected void initTypes(File file) throws IOException { - ParsingContext context = new ParsingContext.Builder().build(); - try (Parser cp = new Parser(context)) { - cp.parse(file, null); - try { - cp.awaitTermination(); - } catch (InterruptedException e) { - throw new IOException(e); - } - types = cp.getContext().getTypes(); - } + throw new UnsupportedOperationException("No longer supported"); } public Types getTypes() { - return types; + throw new UnsupportedOperationException("No longer supported"); } - } diff --git a/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/ProcessingContextImpl.java b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/ProcessingContextImpl.java index 40ec5fdb54c..37116e98c67 100644 --- a/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/ProcessingContextImpl.java +++ b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/impl/ProcessingContextImpl.java @@ -53,6 +53,7 @@ * * @author Jerome ochez */ +@Deprecated(forRemoval = true) class ProcessingContextImpl implements ProcessingContext { protected AnnotationProcessor processor; diff --git a/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/jandex/JandexIndexReader.java b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/jandex/JandexIndexReader.java new file mode 100644 index 00000000000..1deab4d6f60 --- /dev/null +++ b/appserver/common/annotation-framework/src/main/java/org/glassfish/apf/jandex/JandexIndexReader.java @@ -0,0 +1,440 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2025] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/main/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package org.glassfish.apf.jandex; + +import com.sun.enterprise.deploy.shared.ArchiveFactory; +import com.sun.enterprise.deployment.deploy.shared.JarArchive; +import fish.payara.nucleus.executorservice.PayaraExecutorService; +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; +import org.glassfish.apf.impl.AnnotationUtils; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.api.deployment.DeploymentContext; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.api.event.EventListener; +import org.glassfish.api.event.Events; +import org.glassfish.deployment.common.DeploymentProperties; +import org.glassfish.deployment.common.DeploymentUtils; +import org.glassfish.internal.deployment.DeploymentTracing; +import org.glassfish.internal.deployment.JandexIndexer; +import org.glassfish.internal.deployment.analysis.StructuredDeploymentTracing; +import org.jboss.jandex.IndexReader; +import org.jboss.jandex.IndexWriter; +import org.jboss.jandex.Indexer; +import org.jvnet.hk2.annotations.Service; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiPredicate; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import static org.glassfish.internal.deployment.Deployment.DEPLOYMENT_SUCCESS; + +@Service +public class JandexIndexReader implements JandexIndexer, EventListener { + private static final String JANDEX_INDEX_METADATA_KEY = JandexIndexer.class.getName() + ".index"; + private static final Pattern ARCHIVE_EXTENSION_PATTERN = Pattern.compile("\\.(?=\\war$)"); + + @Inject + ArchiveFactory archiveFactory; + @Inject + ServerEnvironment serverEnvironment; + @Inject + Events events; + @Inject + PayaraExecutorService payaraExecutorService; + + private static final Lock errorsLock = new ReentrantLock(); + private static final Queue delayedCacheAdditions = new ConcurrentLinkedQueue<>(); + + @PostConstruct + public void init() { + events.register(this); + } + + @Override + @SuppressWarnings("ResultOfMethodCallIgnored") + public void index(DeploymentContext deploymentContext) throws IOException { + StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(deploymentContext); + try (var span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, deploymentContext.getSource().getName())) { + getCachePath(deploymentContext.getSource().getName(), "none").getParent().toFile().mkdirs(); + + if (getIndexMap(deploymentContext) == null) { + Map indexMap = new ConcurrentHashMap<>(); + deploymentContext.addTransientAppMetaData(JANDEX_INDEX_METADATA_KEY, indexMap); + indexMap.put(deploymentContext.getSource().getURI().toString(), + indexRootArchive(deploymentContext, tracing)); + if (DeploymentUtils.useWarLibraries(deploymentContext)) { + DeploymentUtils.getWarLibraryCache().keySet() + .forEach(path -> getOrCreateIndex(deploymentContext, Path.of(path).toUri(), tracing)); + } + indexExternalLibraries(deploymentContext, tracing); + } + } + } + + @Override + public void reindex(DeploymentContext deploymentContext) throws IOException { + deploymentContext.removeTransientAppMetaData(JANDEX_INDEX_METADATA_KEY); + index(deploymentContext); + } + + @Override + public Index getRootIndex(DeploymentContext deploymentContext) { + return getIndexMap(deploymentContext).get(deploymentContext.getSource().getURI().toString()); + } + + @Override + public Map getAllIndexes(DeploymentContext deploymentContext) { + return getIndexMap(deploymentContext); + } + + @Override + public Map getIndexesByURI(DeploymentContext deploymentContext, Collection uris) { + Map result = new HashMap<>(); + uris.forEach(uri -> result.put(uri.toString(), getOrCreateIndex(deploymentContext, uri, + StructuredDeploymentTracing.createDisabled(uri.toString())))); + return result; + } + + @Override + public boolean isJakartaEEApplication(DeploymentContext deploymentContext) throws IOException { + // Check if the application contains any Jakarta EE specific annotations or classes + // TODO: doesn't work with EAR quite yet, root deployment for EARs is wrong + return getRootIndex(deploymentContext).getIndex().getKnownClasses().stream() + .flatMap(clazz -> clazz.annotations().stream()) + .anyMatch(annotation -> annotation.name().toString().startsWith("jakarta.")); + } + + @Override + public boolean hasAnyAnnotations(DeploymentContext deploymentContext, List uris, String... annotations) { + var indexMap = getIndexMap(deploymentContext); + if (indexMap == null) { + return false; + } + for (URI uri : uris) { + Index index = indexMap.get(uri.toString()); + if (index != null) { + for (String annotation : annotations) { + if (!index.getIndex().getAnnotations(annotation).isEmpty()) { + return true; + } + } + } + } + return false; + } + + @SuppressWarnings("unchecked") + private static Map getIndexMap(DeploymentContext deploymentContext) { + return deploymentContext.getTransientAppMetaData(JANDEX_INDEX_METADATA_KEY, Map.class); + } + + Index getIndexFromArchive(ReadableArchive archive) throws IOException { + Index index = readIndex(archive, "META-INF/jandex.idx"); + if (index == null) { + index = readIndex(archive, "WEB-INF/classes/META-INF/jandex.idx"); + } + return index; + } + + private Index getOrCreateIndex(DeploymentContext deploymentContext, URI uri, StructuredDeploymentTracing tracing) { + if (isEndsWithSlash(uri.toString())) { + return getRootIndex(deploymentContext); + } + Map indexMap = getIndexMap(deploymentContext); + return indexMap.computeIfAbsent(uri.toString(), key -> { + try { + DeploymentUtils.WarLibraryDescriptor descriptor = DeploymentUtils.getWarLibraryCache().get(uri.getPath()); + return descriptor != null ? descriptor.getIndex() : indexOrGetFromCacheWithSpan(archiveFactory.openArchive(uri), tracing); + } catch (IOException | ClassNotFoundException e) { + return null; + } + }); + } + + private Index indexOrGetFromCacheWithSpan(ReadableArchive archive, + StructuredDeploymentTracing tracing) throws IOException, ClassNotFoundException { + try (var span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, archive.getName())) { + return indexOrGetFromCache(archive); + } + } + + private static boolean isEndsWithSlash(String path) { + return path.endsWith(File.separator) || path.endsWith("/"); + } + + private Index indexRootArchive(DeploymentContext deploymentContext, StructuredDeploymentTracing tracing) throws IOException { + Index index = getIndexFromArchive(deploymentContext.getSource()); + ArrayList subArchives = new ArrayList<>(); + if (index == null) { + index = indexArchive(deploymentContext.getSource(), subArchives); + } else { + filterEntries(deploymentContext.getSource(), JandexIndexReader::checkIfSubArchive, subArchives); + } + indexSubArchives(deploymentContext, deploymentContext.getSource(), subArchives, tracing); + return index; + } + + private void indexSubArchives(DeploymentContext deploymentContext, ReadableArchive rootArchive, + List subArchives, StructuredDeploymentTracing tracing) throws IOException { + List> innerJarTasks = new ArrayList<>(); + StringBuilder errors = new StringBuilder(); + subArchives.forEach(subArchive -> innerJarTasks.add( + () -> indexSubArchive(deploymentContext, rootArchive, subArchive, errors, tracing))); + ForkJoinPool.commonPool().invokeAll(innerJarTasks); + if (errors.length() > 0) { + throw new IOException(errors.toString()); + } + } + + private Index indexArchive(ReadableArchive archive, List innerArchives) throws IOException { + Indexer indexer = new Indexer(); + StringBuilder errors = new StringBuilder(); + + filterEntries(archive, (entry, performIndex) -> { + try { + if (performIndex && entry.endsWith(".class")) { + try (InputStream stream = archive.getEntry(entry)) { + if (stream != null) { + indexer.index(stream); + } + } + } + } catch (IOException e) { + appendError(archive, entry, errors); + } + return checkIfSubArchive(entry, performIndex); + }, innerArchives); + + if (errors.length() > 0) { + throw new IOException(errors.toString()); + } + return new Index(indexer.complete()); + } + + private static void filterEntries(ReadableArchive archive, BiPredicate filter, + List entries) { + Set explodedEntries = new HashSet<>(); + archive.entries().asIterator().forEachRemaining(entry -> { + String explodedEntry = toExplodedName(entry); + if (explodedEntry != null && archive.isDirectory(explodedEntry)) { + explodedEntries.add(explodedEntry); + } + if (filter.test(entry, !startsWithAny(entry, explodedEntries))) { + entries.add(entry); + } + }); + } + + private static boolean startsWithAny(String entry, Set explodedEntries) { + return explodedEntries.stream().anyMatch(entry::startsWith); + } + + private static String toExplodedName(String entry) { + Matcher matcher = ARCHIVE_EXTENSION_PATTERN.matcher(entry); + return matcher.find() ? matcher.replaceAll("_") : null; + } + + private static boolean checkIfSubArchive(String entry, boolean doit) { + return ARCHIVE_EXTENSION_PATTERN.matcher(entry).find(); + } + + private Void indexSubArchive(DeploymentContext context, ReadableArchive archive, + String entry, StringBuilder errors, StructuredDeploymentTracing tracing) { + try (ReadableArchive subArchive = archive.getSubArchive(entry); + var span = subArchive != null + ? tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, subArchive.getName()) : null) { + if (subArchive != null) { + Index index = indexOrGetFromCache(subArchive); + getIndexMap(context).put(subArchive.getURI().toString(), index); + } + } catch (IOException | ClassNotFoundException e) { + appendError(archive, entry, errors); + } + return null; + } + + private Index indexOrGetFromCache(ReadableArchive subArchive) throws IOException, ClassNotFoundException { + String subArchivePath = subArchive.getURI().getPath(); + Index index = getIndexFromArchive(subArchive); + if (index == null) { + index = getCachedIndex(subArchive); + } + if (index == null) { + List innerArchives = new ArrayList<>(); + index = indexArchive(subArchive, innerArchives); + if (!subArchivePath.endsWith("-SNAPSHOT.jar") + && !subArchivePath.endsWith("-SNAPSHOT-tests.jar") + && !isEndsWithSlash(subArchivePath)) { + var finalIndex = index; + var archiveName = subArchive.getName(); + var archiveSize = subArchive.getArchiveSize(); + var archiveChecksum = getChecksum(subArchive); + delayedCacheAdditions.offer(() -> cacheIndex(archiveName, archiveSize, archiveChecksum, finalIndex)); + } + } + return index; + } + + private static void appendError(ReadableArchive archive, String entry, StringBuilder errors) { + errorsLock.lock(); + try { + if (errors.length() == 0) { + errors.append(String.format("Unable to index %s from archive %s ", entry, archive.getName())); + } + } finally { + errorsLock.unlock(); + } + } + + private Index getCachedIndex(ReadableArchive archive) throws IOException, ClassNotFoundException { + if (!getCachePath(archive.getName(), "idx").toFile().exists()) { + return null; + } + try (var stream = new GZIPInputStream(Files.newInputStream(getCachePath(archive.getName(),"idx")))) { + var objectInputStream = new ObjectInputStream(stream); + long archiveSize = objectInputStream.readLong(); + long archiveChecksum = objectInputStream.readLong(); + if (archiveSize != archive.getArchiveSize() || archiveChecksum != getChecksum(archive)) { + return null; + } + Index index = (Index) objectInputStream.readObject(); + index.setIndex(new IndexReader(stream).read()); + return index; + } + } + + private void cacheIndex(String archiveName, long archiveSize, long archiveChecksum, Index index) { + try (var stream = new GZIPOutputStream(Files.newOutputStream(getCachePath(archiveName, "idx")))) { + var objectOutputStream = new ObjectOutputStream(stream); + objectOutputStream.writeLong(archiveSize); + objectOutputStream.writeLong(archiveChecksum); + objectOutputStream.writeObject(index); + IndexWriter indexWriter = new IndexWriter(stream); + indexWriter.write(index.getIndex()); + } catch (IOException e) { + AnnotationUtils.getLogger().log(Level.WARNING, e, () -> "Failed to cache Jandex index for " + archiveName); + } + } + + private long getChecksum(ReadableArchive archive) { + long crc = 0; + if (archive instanceof JarArchive) { + var jarArchive = (JarArchive) archive; + crc = jarArchive.getArchiveCrc(); + } + return crc; + } + + private Path getCachePath(String archiveName, String suffix) { + return Path.of(serverEnvironment.getInstanceRoot() + "/jandex-cache/" + archiveName + "." + suffix); + } + + private Index readIndex(ReadableArchive archive, String path) throws IOException { + try (InputStream stream = archive.getEntry(path)) { + if (stream != null) { + return new Index(new IndexReader(stream).read()); + } + } + return null; + } + + private void indexExternalLibraries(DeploymentContext deploymentContext, + StructuredDeploymentTracing tracing) throws IOException { + boolean skipScanExternalLibProp = Boolean.valueOf(deploymentContext.getAppProps() + .getProperty(DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB)); + for (URI externalLib : getExternalLibraries(skipScanExternalLibProp, deploymentContext)) { + getOrCreateIndex(deploymentContext, externalLib, tracing); + } + } + + private List getExternalLibraries(boolean skipScanExternalLibProp, + DeploymentContext deploymentContext) { + if (skipScanExternalLibProp) { + // if we skip scanning external libraries, we should just + // return an empty list here + return Collections.emptyList(); + } + try { + return Stream.concat(DeploymentUtils.getExternalLibraries(deploymentContext.getSource()).stream(), + deploymentContext.getAppLibs().stream()).collect(Collectors.toList()); + } catch (URISyntaxException e) { + AnnotationUtils.getLogger().log(Level.WARNING, e, () -> "Failed to get external libraries"); + return Collections.emptyList(); + } + } + + @Override + public void event(Event event) { + if (event.is(DEPLOYMENT_SUCCESS)) { + // drain the queue of delayed cache additions + while (!delayedCacheAdditions.isEmpty()) { + payaraExecutorService.submit(delayedCacheAdditions.poll()); + } + } + } +} diff --git a/appserver/deployment/dol/pom.xml b/appserver/deployment/dol/pom.xml index 4a07d0e5488..cc009fae189 100755 --- a/appserver/deployment/dol/pom.xml +++ b/appserver/deployment/dol/pom.xml @@ -182,5 +182,10 @@ ${project.version} jar + + fish.payara.server.internal.common + internal-api + ${project.version} + diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/context/EjbBundleContext.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/context/EjbBundleContext.java index 98efead7a71..5a9c241a46c 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/context/EjbBundleContext.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/context/EjbBundleContext.java @@ -79,8 +79,11 @@ public EjbBundleDescriptor getDescriptor() { * Return null if corresponding descriptor is not found. */ public AnnotatedElementHandler createContextForEjb() { - Class ejbClass = (Class)this.getProcessingContext().getProcessor( - ).getLastAnnotatedElement(ElementType.TYPE); + Class ejbClass = null; + if (getProcessingContext().getProcessor() != null) { + ejbClass = (Class) this.getProcessingContext().getProcessor( + ).getLastAnnotatedElement(ElementType.TYPE); + } EjbDescriptor[] ejbDescs = null; String ejbClassName = null; if (ejbClass != null) { @@ -137,13 +140,16 @@ public ServiceReferenceContainer[] getServiceRefContainers() { * Return null if corresponding descriptor is not found. */ public AnnotatedElementHandler createContextForEjbInterceptor() { + EjbInterceptor ejbInterceptor = null; + if (getProcessingContext().getProcessor() != null) { Class interceptorClass = (Class)this.getProcessingContext().getProcessor( ).getLastAnnotatedElement(ElementType.TYPE); - EjbInterceptor ejbInterceptor = + ejbInterceptor = this.getDescriptor().getInterceptorByClassName( interceptorClass.getName()); - + } + AnnotatedElementHandler aeHandler = null; if (ejbInterceptor != null) { aeHandler = new EjbInterceptorContext(ejbInterceptor); diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/AnnotationProcessingContext.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/AnnotationProcessingContext.java new file mode 100644 index 00000000000..dd7bdb95697 --- /dev/null +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/AnnotationProcessingContext.java @@ -0,0 +1,76 @@ +package com.sun.enterprise.deployment.annotation.factory; + +import org.glassfish.apf.AnnotatedElementHandler; +import org.glassfish.apf.AnnotationProcessor; +import org.glassfish.apf.ErrorHandler; +import org.glassfish.apf.ProcessingContext; +import org.glassfish.apf.Scanner; +import org.glassfish.api.deployment.archive.ReadableArchive; + +class AnnotationProcessingContext implements ProcessingContext { + private final AnnotatedElementHandler handler; + private final ReadableArchive archive; + private final AnnotationProcessor processor = new JandexAnnotationProcessor(); + + AnnotationProcessingContext(AnnotatedElementHandler handler, ReadableArchive archive) { + this.handler = handler; + this.archive = archive; + } + + @Override + public AnnotationProcessor getProcessor() { + return processor; + } + + @Override + public Scanner getProcessingInput() { + return null; + } + + @Override + public ReadableArchive getArchive() { + return archive; + } + + @Override + public void setArchive(ReadableArchive archive) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void setProcessingInput(Scanner scanner) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + @Deprecated(forRemoval = true) + public void pushHandler(AnnotatedElementHandler handler) { + // no-op + } + + @Override + public AnnotatedElementHandler getHandler() { + return handler; + } + + @Override + @Deprecated(forRemoval = true) + public AnnotatedElementHandler popHandler() { + return handler; + } + + @Override + public U getHandler(Class handlerType) throws ClassCastException { + return handlerType.cast(handler); + } + + @Override + public void setErrorHandler(ErrorHandler errorHandler) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public ErrorHandler getErrorHandler() { + return null; + } +} diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/JandexAnnotationProcessor.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/JandexAnnotationProcessor.java new file mode 100644 index 00000000000..c1eecd8be4a --- /dev/null +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/JandexAnnotationProcessor.java @@ -0,0 +1,62 @@ +package com.sun.enterprise.deployment.annotation.factory; + +import org.glassfish.apf.AnnotationHandler; +import org.glassfish.apf.AnnotationInfo; +import org.glassfish.apf.AnnotationProcessorException; +import org.glassfish.apf.ProcessingContext; +import org.glassfish.apf.ProcessingResult; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.util.logging.Level; + +public class JandexAnnotationProcessor implements org.glassfish.apf.AnnotationProcessor { + private Class type; + + @Override + public ProcessingContext createContext() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public ProcessingResult process(ProcessingContext ctx) throws AnnotationProcessorException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public ProcessingResult process(ProcessingContext ctx, Class[] classes) throws AnnotationProcessorException { + if (classes.length != 1) { + throw new IllegalArgumentException("Only one class is supported."); + } + this.type = classes[0]; + return null; + } + + @Override + public void pushAnnotationHandler(AnnotationHandler handler) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public AnnotationHandler getAnnotationHandler(Class type) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void popAnnotationHandler(Class type) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public AnnotatedElement getLastAnnotatedElement(ElementType type) { + if (type != ElementType.TYPE) { + throw new IllegalArgumentException("Only ElementType.TYPE is supported."); + } + return this.type; + } + + @Override + public void log(Level level, AnnotationInfo locator, String localizedMessage) { + throw new UnsupportedOperationException("Not supported."); + } +} diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/SJSASFactory.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/SJSASFactory.java index 086dac290f2..e6a8e006f4f 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/SJSASFactory.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/factory/SJSASFactory.java @@ -37,6 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2025] [Payara Foundation and/or its affiliates] package com.sun.enterprise.deployment.annotation.factory; @@ -45,66 +46,214 @@ import org.glassfish.apf.AnnotationProcessor; import org.glassfish.apf.AnnotationProcessorException; import org.glassfish.apf.HandlerProcessingResult; +import org.glassfish.apf.context.AnnotationContext; import org.glassfish.apf.factory.Factory; -import org.glassfish.apf.impl.AnnotationProcessorImpl; +import org.glassfish.apf.impl.AnnotationUtils; +import org.glassfish.api.deployment.DeploymentContext; +import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.deployment.common.RootDeploymentDescriptor; import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.utilities.BuilderHelper; +import org.glassfish.internal.deployment.JandexIndexer; +import org.glassfish.internal.deployment.JandexIndexer.Index; +import org.jboss.jandex.AnnotationInstance; import org.jvnet.hk2.annotations.Service; import jakarta.annotation.PostConstruct; import jakarta.inject.Inject; import jakarta.inject.Singleton; +import java.io.File; +import java.io.IOException; import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.reflect.AnnotatedElement; +import java.net.URI; +import java.nio.file.Files; +import java.util.Collections; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; /** * This factory is responsible for initializing a ready to use - * AnnotationProcessor. + * JandexAnnotationProcessor. * * @author Shing Wai Chan */ @Service @Singleton public class SJSASFactory extends Factory { + private static final Logger logger = AnnotationUtils.getLogger(); @Inject private ServiceLocator locator; + @Inject + JandexIndexer jandexIndexer; - private final Set annotationClassNames = new HashSet<>(); - private final Set annotationClassNamesMetaDataComplete = new HashSet<>(); - - // we have two system processors to process annotations: - // one to process all JavaEE annotations when metadata-complete is false, - // another to process a subset of JavaEE annotations when - // metadata-complete is true - private AnnotationProcessorImpl systemProcessor=null; - private AnnotationProcessorImpl systemProcessorMetaDataComplete=null; + private final Map annotationHandlers = new ConcurrentHashMap<>(); + @Deprecated(forRemoval = true) public AnnotationProcessor getAnnotationProcessor(boolean isMetaDataComplete) { - AnnotationProcessorImpl processor = - Factory.getDefaultAnnotationProcessor(); - if (!isMetaDataComplete) { - processor.setDelegate(systemProcessor); - } else { - processor.setDelegate(systemProcessorMetaDataComplete); - } - return processor; + throw new UnsupportedOperationException("This method is deprecated and should not be used"); } - @SuppressWarnings("unchecked") + @Deprecated(forRemoval = true) public Set getAnnotations(boolean isMetaDataComplete) { - if (!isMetaDataComplete) { - return (Set)((HashSet)annotationClassNames).clone(); - } else { - return (Set)((HashSet)annotationClassNamesMetaDataComplete).clone(); + throw new UnsupportedOperationException("This method is deprecated and should not be used"); + } + + public void processAnnotations(DeploymentContext deploymentContext, RootDeploymentDescriptor bundleDesc, + ReadableArchive archive) throws IOException { + if (checkAlreadyProcessed(deploymentContext, bundleDesc)) { + return; + } + + String archiveURI = bundleDesc.getModuleDescriptor().getArchiveUri(); + if (archiveURI == null) { + archiveURI = bundleDesc.getName(); + } + Index index = jandexIndexer.getAllIndexes(deploymentContext) + .get(new File(archiveURI).toURI().toString()); + if (index == null) { + File file = new File(archiveURI); + URI uri = file.toURI(); + if (file.isDirectory()) { + // TODO: assuming there is only one file in the directory + // exploded WAR support for EAR + uri = Files.list(file.toPath()).filter(path -> path.toString().endsWith("ar")).findAny().get().toUri(); + } + index = jandexIndexer.getIndexesByURI(deploymentContext, Collections.singleton(uri)).values().stream().findAny().get(); + } + AnnotationProcessingContext processingContext = new AnnotationProcessingContext( + AnnotatedElementHandlerFactory.createAnnotatedElementHandler(bundleDesc), archive); + Set annotationInstances = new HashSet<>(); + for (Map.Entry entry : annotationHandlers.entrySet()) { + Class annotationClass = entry.getValue().getAnnotationType(); + index.getIndex().getAnnotations(entry.getKey()).forEach(annotationInstance -> { + if (annotationInstances.add(annotationInstance)) { + try { + Class cls = deploymentContext.getClassLoader().loadClass(mapAnnotationToClassName(annotationInstance)); + logger.fine("Processing annotation: " + annotationInstance + " on class: " + cls + + " bundleDesc: " + bundleDesc.getName() + " of type: " + bundleDesc.getClass() + + " with id: " + System.identityHashCode(bundleDesc)); + processingContext.getProcessor().process(processingContext, new Class[] { cls }); + ((AnnotationContext) processingContext.getHandler()).setProcessingContext(processingContext); + AnnotatedElement element = mapAnnotationToElement(cls, annotationInstance); + AnnotationInfo annotationInfo = new AnnotationInfo(processingContext, + element, element.getAnnotation(annotationClass), mapAnnotationToElementType(annotationInstance)); + entry.getValue().processAnnotation(annotationInfo); + } catch (AnnotationProcessorException | ReflectiveOperationException e) { + throw new IllegalStateException(e); + } finally { + try { + processingContext.getProcessor().process(processingContext, new Class[] { null }); + ((AnnotationContext) processingContext.getHandler()).setProcessingContext(null); + } catch (AnnotationProcessorException e) { + logger.log(Level.FINE, "Error processing annotation", e); + } + } + } + }); } } - + + private boolean checkAlreadyProcessed(DeploymentContext deploymentContext, RootDeploymentDescriptor bundleDescriptor) { + @SuppressWarnings("unchecked") + Set alreadyProcessed = + deploymentContext.getTransientAppMetaData("alreadyProcessedAnnotations", Set.class); + if (alreadyProcessed == null) { + alreadyProcessed = Collections.newSetFromMap(new IdentityHashMap<>()); + deploymentContext.addTransientAppMetaData("alreadyProcessedAnnotations", alreadyProcessed); + } + return !alreadyProcessed.add(bundleDescriptor); + } + + /** + * *** TODO: duplicate from weld-gf-connector + * @param annotationInstance + * @return + */ + private static String mapAnnotationToClassName(AnnotationInstance annotationInstance) { + String className = null; + switch (annotationInstance.target().kind()) { + case CLASS: + className = annotationInstance.target().asClass().name().toString(); + break; + case FIELD: + className = annotationInstance.target().asField().declaringClass().name().toString(); + break; + case METHOD: + className = annotationInstance.target().asMethod().receiverType().name().toString(); + break; + case METHOD_PARAMETER: + className = annotationInstance.target().asMethodParameter().method().receiverType().name().toString(); + break; + case TYPE: + className = annotationInstance.target().asType().asClass().toString(); + break; + case RECORD_COMPONENT: + className = annotationInstance.target().asRecordComponent().declaringClass().name().toString(); + break; + } + return className; + } + + private static AnnotatedElement mapAnnotationToElement(Class cls, AnnotationInstance annotationInstance) + throws ReflectiveOperationException { + AnnotatedElement element = null; + switch (annotationInstance.target().kind()) { + case CLASS: + case TYPE: + element = cls; + break; + case FIELD: + element = cls.getDeclaredField(annotationInstance.target().asField().name()); + break; + case METHOD: + int parametersCount = annotationInstance.target().asMethod().parametersCount(); + if (annotationInstance.target().asMethod().parametersCount() == 0) { + element = cls.getDeclaredMethod(annotationInstance.target().asMethod().name()); + } else { + var parameters = new Class[parametersCount]; + for (int count = 0; count < parametersCount; count++) { + parameters[count] = cls.getClassLoader().loadClass(annotationInstance.target() + .asMethod().parameterType(count).name().toString()); + } + element = cls.getDeclaredMethod(annotationInstance.target().asMethod().name(), parameters); + } + break; + case RECORD_COMPONENT: + element = cls.getDeclaredField(annotationInstance.target().asRecordComponent().name()); + break; + case METHOD_PARAMETER: + throw new UnsupportedOperationException("Method parameter not supported"); + } + return element; + } + + private static ElementType mapAnnotationToElementType(AnnotationInstance annotationInstance) { + switch (annotationInstance.target().kind()) { + case CLASS: + case TYPE: + return ElementType.TYPE; + case FIELD: + return ElementType.FIELD; + case METHOD: + return ElementType.METHOD; + case METHOD_PARAMETER: + return ElementType.PARAMETER; + default: + throw new IllegalArgumentException("Unsupported target kind: " + annotationInstance.target().kind()); + } + } + private static String getAnnotationHandlerForStringValue(ActiveDescriptor onMe) { Map> metadata = onMe.getMetadata(); List answers = metadata.get(AnnotationHandler.ANNOTATION_HANDLER_METADATA); @@ -116,31 +265,14 @@ private static String getAnnotationHandlerForStringValue(ActiveDescriptor i : locator.getDescriptors(BuilderHelper.createContractFilter( AnnotationHandler.class.getName()))) { ActiveDescriptor descriptor = (ActiveDescriptor) i; String annotationTypeName = getAnnotationHandlerForStringValue(descriptor); if (annotationTypeName == null) continue; - - systemProcessor.pushAnnotationHandler(annotationTypeName, new LazyAnnotationHandler(descriptor)); - annotationClassNames.add("L" + annotationTypeName.replace('.', '/') + ";"); - - // In the current set of the annotations processed by the - // deployment layer, the only annotation that should be - // processed even when metadata-complete atribute value is true - // is jakarta.annotation.ManagedBean. If there are more annotations - // falling in this category in the future, add them to this list - if (annotationTypeName.equals("jakarta.annotation.ManagedBean")) { - systemProcessorMetaDataComplete.pushAnnotationHandler(annotationTypeName, new LazyAnnotationHandler(descriptor)); - annotationClassNamesMetaDataComplete.add("L" + annotationTypeName.replace('.', '/') + ";"); - } + + annotationHandlers.put(annotationTypeName, new LazyAnnotationHandler(descriptor)); } } @@ -174,6 +306,5 @@ public HandlerProcessingResult processAnnotation( public Class[] getTypeDependencies() { return getHandler().getTypeDependencies(); } - } } diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/handlers/AbstractHandler.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/handlers/AbstractHandler.java index 54a948a91c6..f3a9edaa19d 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/handlers/AbstractHandler.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/handlers/AbstractHandler.java @@ -139,21 +139,7 @@ protected HandlerProcessingResult getInvalidAnnotatedElementHandlerResult( */ protected void log(Level level, AnnotationInfo ainfo, String localizedMessage) throws AnnotationProcessorException { - if (Level.SEVERE.equals(level)) { - ainfo.getProcessingContext().getErrorHandler().error( - new AnnotationProcessorException(localizedMessage, ainfo)); - } else if (Level.WARNING.equals(level)) { - ainfo.getProcessingContext().getErrorHandler().warning( - new AnnotationProcessorException(localizedMessage, ainfo)); - } else if (Level.FINE.equals(level)) { - ainfo.getProcessingContext().getErrorHandler().fine( - new AnnotationProcessorException(localizedMessage, ainfo)); - } else if (ainfo != null) { - ainfo.getProcessingContext().getProcessor().log( - level, ainfo, localizedMessage); - } else { - logger.log(level, localizedMessage); - } + logger.log(level, localizedMessage); } protected String getInjectionMethodPropertyName(Method method, diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/impl/ModuleScanner.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/impl/ModuleScanner.java index c7268b3be16..58cf41a1391 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/impl/ModuleScanner.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/annotation/impl/ModuleScanner.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2021] [Payara Foundation and/or its affiliates.] +// Portions Copyright [2016-2025] [Payara Foundation and/or its affiliates.] package com.sun.enterprise.deployment.annotation.impl; @@ -74,22 +74,10 @@ public abstract class ModuleScanner extends JavaEEScanner implements Scanner< private static final int DEFAULT_ENTRY_BUFFER_SIZE = 8192; - @Inject - DefaultAnnotationScanner defaultScanner; - protected File archiveFile = null; protected ClassLoader classLoader = null; protected Parser classParser = null; - private Set scannedURI = new HashSet<>(); - - private boolean needScanAnnotation = false; - - @Inject - PayaraExecutorService executorService; - - private Set entries = new HashSet<>(); - public static final Logger deplLogger = com.sun.enterprise.deployment.util.DOLUtils.deplLogger; @LogMessageInfo(message = "Exception caught during annotation scanning.", cause="An exception was caught that indicates that the annotation is incorrect.", action="Correct the annotation.", level="SEVERE") @@ -121,11 +109,7 @@ public abstract class ModuleScanner extends JavaEEScanner implements Scanner< public void process(ReadableArchive archiveFile, T bundleDesc, ClassLoader classLoader, Parser parser) throws IOException { - File file = new File(archiveFile.getURI()); - setParser(parser); - process(file, bundleDesc, classLoader); - completeProcess(bundleDesc, archiveFile); - calculateResults(bundleDesc); + throw new UnsupportedOperationException("No longer supported."); } /** @@ -144,79 +128,7 @@ protected void completeProcess(T bundleDescr, ReadableArchive archive) throws IO } protected void calculateResults(T bundleDesc) { - try { - classParser.awaitTermination(); - } catch (InterruptedException e) { - deplLogger.log(Level.SEVERE, - ANNOTATION_SCANNING_EXCEPTION, - e); - return; - } - Level logLevel = (System.getProperty("glassfish.deployment.dump.scanning")!=null?Level.INFO:Level.FINE); - boolean shouldLog = deplLogger.isLoggable(logLevel); - ParsingContext context = classParser.getContext(); - boolean isFullAttribute = false; - if (bundleDesc instanceof BundleDescriptor) { - isFullAttribute = ((BundleDescriptor)bundleDesc).isFullAttribute(); - } - Set annotationsToProcess = defaultScanner.getAnnotations(isFullAttribute); - for (String annotation: annotationsToProcess) { - Type type = context.getTypes().getBy(annotation); - - // we never found anyone using that type - if (type==null) continue; - - // is it an annotation - if (type instanceof AnnotationType) { - AnnotationType at = (AnnotationType) type; - for (AnnotatedElement ae : at.allAnnotatedTypes()) { - // if it is a member (field, method), let's retrieve the declaring type - // otherwise, use the annotated type directly. - Type t = (ae instanceof Member?((Member) ae).getDeclaringType():(Type) ae); - if (t.wasDefinedIn(scannedURI)) { - if (shouldLog) { - if (Level.INFO.equals(logLevel)) { - deplLogger.log(Level.INFO, - ANNOTATION_ADDED, - new Object[] { t.getName(), - ae.getName(), - at.getName() }); - } else { - deplLogger.log(Level.FINE, "Adding {0} since {1} is annotated with {2}", new Object[]{t.getName(), ae.getName(), at.getName()}); - } - } - entries.add(t.getName()); - } - } - - } else - // or is it an interface ? - if (type instanceof InterfaceModel) { - InterfaceModel im = (InterfaceModel) type; - for (ClassModel cm : im.allImplementations()) { - if (shouldLog) { - if (Level.INFO.equals(logLevel)) { - deplLogger.log(Level.INFO, - INTERFACE_ADDED, - new Object[] { cm.getName(), - im.getName() }); - } else { - deplLogger.log(Level.FINE, "Adding {0} since it is implementing {1}", new Object[]{cm.getName(), im.getName()}); - } - } - entries.add(cm.getName()); - } - } else { - deplLogger.log(Level.SEVERE, - INCORRECT_ANNOTATION, - annotation); - } - } - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, - "Done with results"); - } - + throw new UnsupportedOperationException("No longer supported."); } /** @@ -224,8 +136,7 @@ protected void calculateResults(T bundleDesc) { * @param className */ protected void addScanClassName(String className) { - if (className!=null && className.length()!=0) - entries.add(className); + throw new UnsupportedOperationException("No longer supported."); } /** @@ -233,24 +144,7 @@ protected void addScanClassName(String className) { * @param jarFile */ protected void addScanJar(File jarFile) throws IOException { - try { - /* - * An app might refer to a non-existent JAR in its Class-Path. Java - * SE accepts that silently, and so will GlassFish. - */ - if ( ! jarFile.exists()) { - return; - } - scannedURI.add(jarFile.toURI()); - if (needScanAnnotation) { - classParser.parse(jarFile, null); - } - } catch (ZipException ze) { - deplLogger.log(Level.WARNING, - JAR_EXCEPTION, - new Object[] { ze.getMessage(), - jarFile.getPath() }); - } + throw new UnsupportedOperationException("No longer supported."); } /** @@ -266,10 +160,7 @@ protected void addScanURI(final URI jarURI) throws IOException { * @param directory */ protected void addScanDirectory(File directory) throws IOException { - scannedURI.add(directory.toURI()); - if (needScanAnnotation) { - classParser.parse(directory, null); - } + throw new UnsupportedOperationException("No longer supported."); } @Override @@ -279,38 +170,12 @@ public ClassLoader getClassLoader() { @Override public Set getElements() { - return getElements(entries); + throw new UnsupportedOperationException("No longer supported."); } @Override public Set getElements(Set classNames) { - Set elements = new HashSet<>(); - if (getClassLoader() == null) { - deplLogger.log(Level.SEVERE, - NO_CLASSLOADER); - return elements; - } - - for (String className : classNames) { - if (deplLogger.isLoggable(Level.FINE)) { - deplLogger.log(Level.FINE, "Getting {0}", className); - } - try { - elements.add(classLoader.loadClass(className)); - } catch (NoClassDefFoundError err) { - deplLogger.log(Level.WARNING, - ANNOTATION_ERROR, - err); - } catch(ClassNotFoundException cnfe) { - LogRecord lr = new LogRecord(Level.WARNING, CLASSLOADING_ERROR); - Object args[] = { className, - cnfe.getMessage() }; - lr.setParameters(args); - lr.setThrown(cnfe); - deplLogger.log(lr); - } - } - return elements; + throw new UnsupportedOperationException("No longer supported."); } /** @@ -320,43 +185,15 @@ public Set getElements(Set classNames) { */ protected void addLibraryJars(T bundleDesc, ReadableArchive moduleArchive) { - List libraryURIs = new ArrayList<>(); - try { - if (bundleDesc instanceof BundleDescriptor) { - libraryURIs = DOLUtils.getLibraryJarURIs((BundleDescriptor)bundleDesc, moduleArchive); - } - - for (URI uri : libraryURIs) { - File libFile = new File(uri); - if (libFile.isFile()) { - addScanJar(libFile); - } else if (libFile.isDirectory()) { - addScanDirectory(libFile); - } - } - } catch (Exception ex) { - // we log a warning and proceed for any problems in - // adding library jars to the scan list - deplLogger.log(Level.WARNING, - LIBRARY_JAR_ERROR, - ex.getMessage()); - } + throw new UnsupportedOperationException("No longer supported."); } @Override public Types getTypes() { - return classParser.getContext().getTypes(); + throw new UnsupportedOperationException("No longer supported."); } protected void setParser(Parser parser) { - if (parser == null) { - // if the passed in parser is null, it means no annotation scanning - // has been done yet, we need to construct a new parser - // and do the annotation scanning here - ParsingContext pc = new ParsingContext.Builder().logger(deplLogger).executorService(executorService.getUnderlyingExecutorService()).build(); - parser = new Parser(pc); - needScanAnnotation = true; - } - classParser = parser; + throw new UnsupportedOperationException("No longer supported."); } } diff --git a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/archivist/Archivist.java b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/archivist/Archivist.java index e9d7b1c8d7a..fb2eaa17120 100644 --- a/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/archivist/Archivist.java +++ b/appserver/deployment/dol/src/main/java/com/sun/enterprise/deployment/archivist/Archivist.java @@ -37,13 +37,13 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2020-2024] [Payara Foundation and/or its affiliates.] +// Portions Copyright [2020-2025] [Payara Foundation and/or its affiliates.] package com.sun.enterprise.deployment.archivist; import com.sun.enterprise.deploy.shared.ArchiveFactory; -import com.sun.enterprise.deployment.*; -import com.sun.enterprise.deployment.annotation.factory.AnnotatedElementHandlerFactory; +import com.sun.enterprise.deployment.Application; +import com.sun.enterprise.deployment.BundleDescriptor; import com.sun.enterprise.deployment.annotation.factory.SJSASFactory; import com.sun.enterprise.deployment.annotation.impl.ModuleScanner; import com.sun.enterprise.deployment.io.DeploymentDescriptorFile; @@ -51,28 +51,50 @@ import static com.sun.enterprise.deployment.io.DescriptorConstants.PERSISTENCE_DD_ENTRY; import static com.sun.enterprise.deployment.io.DescriptorConstants.WEB_WEBSERVICES_JAR_ENTRY; import static com.sun.enterprise.deployment.io.DescriptorConstants.EJB_WEBSERVICES_JAR_ENTRY; -import com.sun.enterprise.deployment.util.*; +import com.sun.enterprise.deployment.util.ComponentPostVisitor; +import com.sun.enterprise.deployment.util.DOLUtils; +import com.sun.enterprise.deployment.util.TracerVisitor; import com.sun.enterprise.util.LocalStringManagerImpl; import com.sun.enterprise.util.io.FileUtils; import com.sun.enterprise.util.shared.ArchivistUtils; import fish.payara.nucleus.hotdeploy.ApplicationState; -import org.glassfish.apf.*; +import org.glassfish.apf.AnnotationProcessorException; +import org.glassfish.apf.ErrorHandler; +import org.glassfish.apf.ProcessingResult; +import org.glassfish.apf.ResultType; import org.glassfish.apf.Scanner; -import org.glassfish.apf.impl.DefaultErrorHandler; +import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ArchiveType; import org.glassfish.api.deployment.archive.Archive; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.api.deployment.archive.WritableArchive; -import org.glassfish.deployment.common.*; +import org.glassfish.deployment.common.DeploymentProperties; +import org.glassfish.deployment.common.Descriptor; +import org.glassfish.deployment.common.DescriptorVisitor; +import org.glassfish.deployment.common.InstalledLibrariesResolver; +import org.glassfish.deployment.common.ModuleDescriptor; +import org.glassfish.deployment.common.RootDeploymentDescriptor; import org.glassfish.hk2.api.MultiException; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.*; import jakarta.inject.Inject; +import org.glassfish.internal.deployment.Deployment; import org.jvnet.hk2.annotations.Contract; import org.xml.sax.SAXParseException; -import java.io.*; -import java.util.*; +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.JarInputStream; @@ -138,9 +160,6 @@ public abstract class Archivist { // runtime xml validation error level reporting/recovering private String runtimeValidationLevel = "parsing"; - // error handler for annotation processing - private ErrorHandler annotationErrorHandler = null; - private static final String WSDL = ".wsdl"; private static final String XML = ".xml"; private static final String XSD = ".xsd"; @@ -166,23 +185,19 @@ public abstract class Archivist { protected ServiceLocator habitat; @Inject - protected ServiceLocator locator; + SJSASFactory annotationFactory; @Inject - SJSASFactory annotationFactory; + Deployment deployment; + + @Deprecated(forRemoval = true) + protected ServiceLocator locator = null; @Inject ArchiveFactory archiveFactory; protected List extensionsArchivists; - /** - * Creates new Archivist - */ - public Archivist() { - annotationErrorHandler = new DefaultErrorHandler(); - } - /** * initializes this instance from another archivist, this is used to * transfer contextual information between archivists, for example whether @@ -194,7 +209,6 @@ protected void initializeContext(Archivist other) { isValidatingXML = other.isValidatingXML; validationLevel = other.validationLevel; classLoader = other.classLoader; - annotationErrorHandler = other.annotationErrorHandler; } /** @@ -590,24 +604,8 @@ protected ProcessingResult processAnnotations(RootDeploymentDescriptor bundleDes return null; } - AnnotatedElementHandler aeHandler = - AnnotatedElementHandlerFactory.createAnnotatedElementHandler( - bundleDesc); - - if (aeHandler == null) { - return null; - } - - Parser parser = null; - if (archive.getParentArchive() != null) { - parser = archive.getParentArchive().getExtraData(Parser.class); - } else { - parser = archive.getExtraData(Parser.class); - } - - scanner.process(archive, bundleDesc, classLoader, parser); - - if (!scanner.getElements().isEmpty()) { +// if (!scanner.getElements().isEmpty()) { + if (true) { if (((BundleDescriptor) bundleDesc).isDDWithNoAnnotationAllowed()) { // if we come into this block, it means an old version // of deployment descriptor has annotation which is not correct @@ -624,64 +622,18 @@ protected ProcessingResult processAnnotations(RootDeploymentDescriptor bundleDes "{0} in archive {1} is of version {2}, which cannot support annotations in an application. Please upgrade the deployment descriptor to be a version supported by Java EE 5.0 (or later).", new Object[]{ddName, archiveName, bundleDesc.getSpecVersion()})); } - boolean isFullAttribute = false; - if (bundleDesc instanceof BundleDescriptor) { - isFullAttribute = ((BundleDescriptor) bundleDesc).isFullAttribute(); - } - - AnnotationProcessor ap = annotationFactory.getAnnotationProcessor(isFullAttribute); - ProcessingContext ctx = getProcessingContext(bundleDesc, archive, ap); - ctx.setArchive(archive); - if (annotationErrorHandler != null) { - ctx.setErrorHandler(annotationErrorHandler); - } - ctx.setProcessingInput(scanner); - ctx.pushHandler(aeHandler); - - // Make sure there is a classloader available on the descriptor - // during annotation processing. - ClassLoader originalBundleClassLoader = null; - try { - originalBundleClassLoader = bundleDesc.getClassLoader(); - } catch (Exception e) { - // getClassLoader can throw exception if not available - } - - // Only set classloader if it's not already set. - if (originalBundleClassLoader == null) { - bundleDesc.setClassLoader(classLoader); - } - - try { - return ap.process(ctx); - } finally { - if (originalBundleClassLoader == null) { - bundleDesc.setClassLoader(null); - } - } +// boolean isFullAttribute = false; +// if (bundleDesc instanceof BundleDescriptor) { +// isFullAttribute = ((BundleDescriptor) bundleDesc).isFullAttribute(); +// } + + DeploymentContext deploymentContext = deployment.getCurrentDeploymentContext(); + annotationFactory.processAnnotations(deploymentContext, bundleDesc, archive); +// ProcessingContext ctx = getProcessingContext(bundleDesc, archive, ap); } return null; } - private ProcessingContext getProcessingContext( - RootDeploymentDescriptor bundleDesc, - ReadableArchive archive, - AnnotationProcessor ap) { - - ProcessingContext ctx = null; - ApplicationState state = archive.getExtraData(ApplicationState.class); - if (state != null) { - ctx = state.getProcessingContext(bundleDesc.getClass(), ProcessingContext.class); - } - if (ctx == null) { - ctx = ap.createContext(); - if (state != null) { - state.addProcessingContext(bundleDesc.getClass(), ctx); - } - } - return ctx; - } - /** * Read the standard deployment descriptors (can contained in one or many * file) and return the corresponding initialized descriptor instance. By @@ -1222,14 +1174,14 @@ public boolean isAnnotationProcessingRequested() { * @param annotationErrorHandler */ public void setAnnotationErrorHandler(ErrorHandler annotationErrorHandler) { - this.annotationErrorHandler = annotationErrorHandler; + throw new UnsupportedOperationException("No longer supported."); } /** * @return annotation ErrorHandler of this archivist */ public ErrorHandler getAnnotationErrorHandler() { - return annotationErrorHandler; + throw new UnsupportedOperationException("No longer supported."); } /** 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 67cdc4fbd78..9ed067ffe46 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 @@ -75,10 +75,10 @@ import org.glassfish.hk2.api.ActiveDescriptor; import org.glassfish.hk2.api.ServiceHandle; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.Types; import org.glassfish.internal.api.Globals; import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.internal.data.ApplicationRegistry; +import org.glassfish.internal.deployment.Deployment; import org.glassfish.internal.deployment.ExtendedDeploymentContext; import org.glassfish.internal.deployment.SnifferManager; import org.glassfish.loader.util.ASClassLoaderUtil; @@ -648,16 +648,18 @@ private static Collection getSniffersForModule(ServiceLocator habitat, SnifferManager snifferManager = habitat.getService(SnifferManager.class); List classPathURIs = handler.getClassPathURIs(archive); classPathURIs.addAll(getLibraryJarURIs(app, archive)); - Types types = archive.getParentArchive().getExtraData(Types.class); DeployCommandParameters parameters = archive.getParentArchive().getArchiveMetaData(DeploymentProperties.COMMAND_PARAMS, DeployCommandParameters.class); Properties appProps = archive.getParentArchive().getArchiveMetaData(DeploymentProperties.APP_PROPS, Properties.class); ExtendedDeploymentContext context = new DeploymentContextImpl(null, archive, parameters, habitat.getService(ServerEnvironment.class)); + context.setParentContext(habitat.getService(Deployment.class).getCurrentDeploymentContext()); + for (var entry : habitat.getService(Deployment.class).getCurrentDeploymentContext().getTransientAppMetadata().entrySet()) { + context.addTransientAppMetaData(entry.getKey(), entry.getValue()); + } if (appProps != null) { context.getAppProps().putAll(appProps); } context.setArchiveHandler(handler); - context.addTransientAppMetaData(Types.class.getName(), types); - Collection sniffers = snifferManager.getSniffers(context, classPathURIs, types); + Collection sniffers = snifferManager.getSniffers(context, classPathURIs, null); context.postDeployClean(true); String type = getTypeFromModuleType(md.getModuleType()); Sniffer mainSniffer = null; diff --git a/appserver/deployment/javaee-core/src/main/java/org/glassfish/javaee/core/deployment/DolProvider.java b/appserver/deployment/javaee-core/src/main/java/org/glassfish/javaee/core/deployment/DolProvider.java index fb0088874e2..9348e65db30 100644 --- a/appserver/deployment/javaee-core/src/main/java/org/glassfish/javaee/core/deployment/DolProvider.java +++ b/appserver/deployment/javaee-core/src/main/java/org/glassfish/javaee/core/deployment/DolProvider.java @@ -145,9 +145,6 @@ public MetaData getMetaData() { private Application processDOL(DeploymentContext dc) throws IOException { ReadableArchive sourceArchive = dc.getSource(); - sourceArchive.setExtraData(Types.class, dc.getTransientAppMetaData(Types.class.getName(), Types.class)); - sourceArchive.setExtraData(Parser.class, dc.getTransientAppMetaData(Parser.class.getName(), Parser.class)); - Optional appState = hotDeployService.getApplicationState(dc); appState.ifPresent(state -> sourceArchive.setExtraData(ApplicationState.class, state)); diff --git a/appserver/packager/appserver-core/pom.xml b/appserver/packager/appserver-core/pom.xml index 0245fc21cd3..518d4fce7f4 100644 --- a/appserver/packager/appserver-core/pom.xml +++ b/appserver/packager/appserver-core/pom.xml @@ -294,5 +294,10 @@ com.fasterxml.jackson.dataformat jackson-dataformat-toml + + io.smallrye + jandex + ${jandex.version} + diff --git a/appserver/payara-appserver-modules/microprofile/config/pom.xml b/appserver/payara-appserver-modules/microprofile/config/pom.xml index a5dff27d266..a1101154381 100644 --- a/appserver/payara-appserver-modules/microprofile/config/pom.xml +++ b/appserver/payara-appserver-modules/microprofile/config/pom.xml @@ -83,6 +83,11 @@ weld-integration ${project.version} + + io.smallrye + jandex + 3.2.3 + jakarta.annotation jakarta.annotation-api diff --git a/appserver/payara-appserver-modules/microprofile/config/src/main/java/fish/payara/microprofile/config/activation/ConfigDeployer.java b/appserver/payara-appserver-modules/microprofile/config/src/main/java/fish/payara/microprofile/config/activation/ConfigDeployer.java index eee474b1efd..9c615dcb787 100644 --- a/appserver/payara-appserver-modules/microprofile/config/src/main/java/fish/payara/microprofile/config/activation/ConfigDeployer.java +++ b/appserver/payara-appserver-modules/microprofile/config/src/main/java/fish/payara/microprofile/config/activation/ConfigDeployer.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) [2020-2021] Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) [2020-2025] Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -44,13 +44,14 @@ import jakarta.enterprise.inject.spi.Extension; +import jakarta.inject.Inject; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.inject.ConfigProperties; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.classmodel.reflect.Type; -import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.deployment.JandexIndexer; +import org.glassfish.internal.deployment.JandexIndexer.Index; import org.glassfish.weld.WeldDeployer; import org.jvnet.hk2.annotations.Service; @@ -60,6 +61,8 @@ @Service @PerLookup public class ConfigDeployer extends MicroProfileDeployer { + @Inject + JandexIndexer jandexIndexer; @Override @SuppressWarnings("unchecked") @@ -68,19 +71,13 @@ public ConfigApplicationContainer load(ConfigContainer container, // Perform annotation scanning to see if CDI extension is required here // This is performed here so that the ApplicationContainer executes regardless of CDI extension state - final Types types = deploymentContext.getTransientAppMetaData(Types.class.getName(), Types.class); - - - if (types != null) { - // The annotations that denote a Config API enabled application - final Type annotationType = types.getBy(ConfigProperty.class.getName()); - final Type annotation2Type = types.getBy(ConfigProperties.class.getName()); - final Type classType = types.getBy(Config.class.getName()); - final boolean annotationFound = annotationType != null; - final boolean annotation2Found = annotation2Type != null; - final boolean classFound = classType != null; - - if (annotationFound || annotation2Found || classFound) { + Index index = jandexIndexer.getRootIndex(deploymentContext); + if (index != null) { + boolean found = false; + found |= !index.getIndex().getAnnotations(ConfigProperty.class).isEmpty(); + found |= !index.getIndex().getAnnotations(ConfigProperties.class).isEmpty(); + found |= !index.getIndex().getAnnotations(Config.class).isEmpty(); + if (found) { // Register the CDI extension final Collection> snifferExtensions = deploymentContext.getTransientAppMetaData(WeldDeployer.SNIFFER_EXTENSIONS, Collection.class); if (snifferExtensions != null) { diff --git a/appserver/payara-appserver-modules/microprofile/metrics/pom.xml b/appserver/payara-appserver-modules/microprofile/metrics/pom.xml index a6354c4f94f..f2a0025a1bb 100644 --- a/appserver/payara-appserver-modules/microprofile/metrics/pom.xml +++ b/appserver/payara-appserver-modules/microprofile/metrics/pom.xml @@ -127,6 +127,11 @@ fish.payara.monitoring-console monitoring-console-api + + io.smallrye + jandex + 3.2.3 + org.mockito mockito-core diff --git a/appserver/payara-appserver-modules/microprofile/metrics/src/main/java/fish/payara/microprofile/metrics/activation/MetricsSniffer.java b/appserver/payara-appserver-modules/microprofile/metrics/src/main/java/fish/payara/microprofile/metrics/activation/MetricsSniffer.java index dfd43e02085..0cdc8a21f43 100644 --- a/appserver/payara-appserver-modules/microprofile/metrics/src/main/java/fish/payara/microprofile/metrics/activation/MetricsSniffer.java +++ b/appserver/payara-appserver-modules/microprofile/metrics/src/main/java/fish/payara/microprofile/metrics/activation/MetricsSniffer.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) [2020-2023] Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) [2020-2025] Payara Foundation and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -53,7 +53,8 @@ import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.hk2.api.PerLookup; -import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.deployment.JandexIndexer; +import org.glassfish.internal.deployment.JandexIndexer.Index; import org.jvnet.hk2.annotations.Service; import fish.payara.microprofile.connector.MicroProfileSniffer; @@ -66,6 +67,8 @@ public class MetricsSniffer extends MicroProfileSniffer { @Inject private ServerEnvironment serverEnv; + @Inject + JandexIndexer jandexIndexer; @Override @SuppressWarnings("unchecked") @@ -85,14 +88,12 @@ public Class[] getAnnotationTypes() { @Override public boolean handles(DeploymentContext context) { - final Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class); - - if (types != null) { - if (types.getBy(MetricRegistry.class.getName()) != null) { + Index index = jandexIndexer.getRootIndex(context); + if (index != null) { + if (!index.getIndex().getAnnotations(MetricRegistry.class).isEmpty()) { return true; } - - if (types.getBy(Metric.class.getName()) != null) { + if (!index.getIndex().getAnnotations(Metric.class).isEmpty()) { return true; } } diff --git a/appserver/web/gf-weld-connector/pom.xml b/appserver/web/gf-weld-connector/pom.xml index 5f2ec667e65..aa9648f04b4 100644 --- a/appserver/web/gf-weld-connector/pom.xml +++ b/appserver/web/gf-weld-connector/pom.xml @@ -80,5 +80,10 @@ jakarta.faces true + + io.smallrye + jandex + ${jandex.version} + diff --git a/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldSniffer.java b/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldSniffer.java index 273eaf77e97..a09e9a656ae 100644 --- a/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldSniffer.java +++ b/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldSniffer.java @@ -245,7 +245,7 @@ public String[] getAnnotationNames(DeploymentContext context) { } // make sure it's not an extension - if ( ! WeldUtils.isValidBdaBasedOnExtensionAndBeansXml( context.getSource() )) { + if ( ! WeldUtils.isValidBdaBasedOnExtensionAndBeansXml(context, context.getSource() )) { return null; } diff --git a/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldUtils.java b/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldUtils.java index f5f8050012c..de6e9134148 100644 --- a/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldUtils.java +++ b/appserver/web/gf-weld-connector/src/main/java/org/glassfish/weld/connector/WeldUtils.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2025] [Payara Foundation and/or its affiliates] package org.glassfish.weld.connector; @@ -48,12 +48,10 @@ import java.io.InputStream; import java.lang.annotation.Annotation; import java.net.URI; -import java.nio.file.Path; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -65,6 +63,7 @@ import jakarta.enterprise.inject.Model; import jakarta.enterprise.inject.Stereotype; import jakarta.faces.flow.FlowScoped; +import jakarta.faces.view.ViewScoped; import jakarta.inject.Inject; import jakarta.inject.Scope; import jakarta.inject.Singleton; @@ -73,17 +72,11 @@ import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.deployment.common.DeploymentUtils; -import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.AnnotationModel; -import org.glassfish.hk2.classmodel.reflect.AnnotationType; -import org.glassfish.hk2.classmodel.reflect.ClassModel; -import org.glassfish.hk2.classmodel.reflect.FieldModel; -import org.glassfish.hk2.classmodel.reflect.MethodModel; -import org.glassfish.hk2.classmodel.reflect.Type; -import org.glassfish.hk2.classmodel.reflect.Types; import org.glassfish.internal.api.Globals; -import org.glassfish.internal.deployment.ExtendedDeploymentContext; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.deployment.JandexIndexer; +import org.glassfish.internal.deployment.JandexIndexer.Index; +import org.jboss.jandex.AnnotationInstance; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; @@ -113,6 +106,9 @@ public class WeldUtils { // which does not have CDI implementation. So, we use the class name as a string. private static final String SERVICES_CLASSNAME = "jakarta.enterprise.inject.spi.Extension"; private static final String BCE_SERVICES_CLASSNAME = "jakarta.enterprise.inject.build.compatible.spi.BuildCompatibleExtension"; + private static final String CDI_ENABLING_ANNOTATIONS_CACHE_METADATA = "fish.payara.cdi.enabling.annotations.cache.metadata"; + private static final String CDI_ANNOTATED_CLASS_NAMES_METADATA = "fish.payara.cdi.annotated.class.names.metadata"; + public static final String META_INF_SERVICES_EXTENSION = "META-INF" + SEPARATOR_CHAR + SERVICES_DIR + SEPARATOR_CHAR + SERVICES_CLASSNAME; public static final String META_INF_BCE_SERVICES_EXTENSION = "META-INF" + SEPARATOR_CHAR + SERVICES_DIR + @@ -134,42 +130,45 @@ public class WeldUtils { */ public enum BDAType { WAR, JAR, RAR, UNKNOWN }; + static final Set> cdiScopeAnnotationClasses; protected static final Set cdiScopeAnnotations; static { - final HashSet cdi = new HashSet<>(); - cdi.add(Scope.class.getName()); - cdi.add(NormalScope.class.getName()); - cdi.add("jakarta.faces.view.ViewScoped"); - cdi.add("jakarta.faces.flow.FlowScoped"); - cdi.add(ConversationScoped.class.getName()); - cdi.add(FlowScoped.class.getName()); - cdi.add(ApplicationScoped.class.getName()); - cdi.add(SessionScoped.class.getName()); - cdi.add(RequestScoped.class.getName()); - cdi.add(Dependent.class.getName()); - cdi.add(Singleton.class.getName()); - cdi.add(Model.class.getName()); - - cdiScopeAnnotations = Collections.unmodifiableSet(cdi); - } - - protected static final Set cdiEnablingAnnotations; + final HashSet> cdi = new HashSet<>(); + cdi.add(Scope.class); + cdi.add(NormalScope.class); + cdi.add(ConversationScoped.class); + cdi.add(ViewScoped.class); + cdi.add(FlowScoped.class); + cdi.add(ApplicationScoped.class); + cdi.add(SessionScoped.class); + cdi.add(RequestScoped.class); + cdi.add(Dependent.class); + cdi.add(Singleton.class); + cdi.add(Model.class); + + cdiScopeAnnotationClasses = Collections.unmodifiableSet(cdi); + cdiScopeAnnotations = cdiScopeAnnotationClasses.stream().map(Class::getName).collect(Collectors.toSet()); + } + + static final Set cdiEnablingAnnotations; + static final Set> cdiEnablingAnnotationClasses; static { // CDI scopes - final HashSet cdi = new HashSet<>(cdiScopeAnnotations); + final HashSet> cdi = new HashSet<>(cdiScopeAnnotationClasses); // 1.2 updates - cdi.add(Decorator.class.getName()); - cdi.add(Interceptor.class.getName()); - cdi.add(Stereotype.class.getName()); + cdi.add(Decorator.class); + cdi.add(Interceptor.class); + cdi.add(Stereotype.class); // EJB annotations - cdi.add(MessageDriven.class.getName()); - cdi.add(Stateful.class.getName()); - cdi.add(Stateless.class.getName()); - cdi.add(jakarta.ejb.Singleton.class.getName()); + cdi.add(MessageDriven.class); + cdi.add(Stateful.class); + cdi.add(Stateless.class); + cdi.add(jakarta.ejb.Singleton.class); - cdiEnablingAnnotations = Collections.unmodifiableSet(cdi); + cdiEnablingAnnotationClasses = Collections.unmodifiableSet(cdi); + cdiEnablingAnnotations = cdiEnablingAnnotationClasses.stream().map(Class::getName).collect(Collectors.toSet()); } @@ -183,10 +182,15 @@ public enum BDAType { WAR, JAR, RAR, UNKNOWN }; */ public static boolean isImplicitBeanArchive(DeploymentContext context, ReadableArchive archive) throws IOException { - if(!isValidBdaBasedOnExtensionAndBeansXml(archive)) { - return false; - } - return isImplicitBeanArchive(context, archive.getURI()); + var index = Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, Collections.singleton(archive.getURI())) + .values().stream().findAny().get(); + return index.implicitBeanArchive(() -> { + if(!isValidBdaBasedOnExtensionAndBeansXml(context, archive)) { + return false; + } + return isImplicitBeanArchive(context, archive.getURI()); + }); } /** @@ -198,10 +202,12 @@ public static boolean isImplicitBeanArchive(DeploymentContext context, ReadableA * @return true, if it is an implicit bean deployment archive; otherwise, false. */ public static boolean isImplicitBeanArchive(DeploymentContext context, URI archivePath) { - return (isImplicitBeanDiscoveryEnabled(context) && hasCDIEnablingAnnotations(context, archivePath)); + var index = Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, Collections.singleton(archivePath)) + .values().stream().findAny().get(); + return index.implicitBeanArchive(() -> isImplicitBeanDiscoveryEnabled(context) && hasCDIEnablingAnnotations(context, archivePath)); } - /** * Determine whether there are any beans annotated with annotations that should enable CDI * processing even in the absence of a beans.xml descriptor. @@ -212,7 +218,10 @@ public static boolean isImplicitBeanArchive(DeploymentContext context, URI archi * @return true, if there is at least one bean annotated with a qualified annotation in the specified path */ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, URI path) { - return hasCDIEnablingAnnotations(context, Collections.singleton(path)); + var index = Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, Collections.singleton(path)) + .values().stream().findAny().get(); + return index.hasCDIEnablingAnnotations(() -> hasCDIEnablingAnnotations(context, Collections.singleton(path))); } @@ -226,19 +235,12 @@ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, URI p * @return true, if there is at least one bean annotated with a qualified annotation in the specified paths */ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, Collection paths) { - final Set exclusions = new HashSet<>(); - for (final Type type : getAllTypes(context, paths)) { - if (!(type instanceof AnnotationType) && type.wasDefinedIn(paths)) { - for (final AnnotationModel am : type.getAnnotations()) { - final AnnotationType at = am.getType(); - if (isCDIEnablingAnnotation(at, exclusions)) { - return true; - } - } - } - } - - return false; + Map indexes = Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, paths); + boolean result = Arrays.stream(getCDIEnablingAnnotations(context)) + .anyMatch(annotation -> indexes.values().stream() + .anyMatch(index -> !index.getIndex().getAnnotations(annotation).isEmpty())); + return result; } /** @@ -250,24 +252,42 @@ public static boolean hasCDIEnablingAnnotations(DeploymentContext context, Colle * @return An array of annotation type names; The array could be empty if none are found. */ public static String[] getCDIEnablingAnnotations(DeploymentContext context) { - final Set result = new HashSet<>(); - - final Set exclusions = new HashSet<>(); - for (final Type type : getAllTypes(context, List.of())) { - if (!(type instanceof AnnotationType)) { - for (final AnnotationModel am : type.getAnnotations()) { - final AnnotationType at = am.getType(); - if (isCDIEnablingAnnotation(at, exclusions)) { - result.add(at.getName()); + String[] annotations = context.getTransientAppMetaData(CDI_ENABLING_ANNOTATIONS_CACHE_METADATA, String[].class); + if (annotations != null) { + return annotations; + } + var indexes = Globals.getDefaultHabitat().getService(JandexIndexer.class).getAllIndexes(context); + Set appCdiEnablingAnnotations = indexes.values().stream() + .flatMap(index -> index.getIndex().getKnownClasses().stream()) + .flatMap(classInfo -> classInfo.annotations().stream()) + .map(annotationClass -> annotationClass.name().toString()) + .collect(Collectors.toSet()); + + Set additionalAnnotations = new HashSet<>(); + appCdiEnablingAnnotations.stream() + .filter(annotation -> !cdiEnablingAnnotations.contains(annotation)) + .forEach(annotation -> { + try { + @SuppressWarnings("unchecked") + Class cls = (Class) context.getClassLoader() + .loadClass(annotation); + for (var annotationClass : cdiEnablingAnnotationClasses) { + if (cls.isAnnotationPresent(annotationClass)) { + additionalAnnotations.add(annotation); + break; } } + } catch (ClassNotFoundException | NullPointerException e) { } - } - - return result.toArray(new String[0]); + }); + annotations = appCdiEnablingAnnotations.stream() + .filter(annotation -> cdiEnablingAnnotations.contains(annotation) + || additionalAnnotations.contains(annotation)) + .toArray(String[]::new); + context.addTransientAppMetaData(CDI_ENABLING_ANNOTATIONS_CACHE_METADATA, annotations); + return annotations; } - /** * Get the names of any classes that are annotated with bean-defining annotations, which should * enable CDI processing even in the absence of a beans.xml descriptor. @@ -277,22 +297,23 @@ public static String[] getCDIEnablingAnnotations(DeploymentContext context) { * @return A collection of class names; The collection could be empty if none are found. */ public static Collection getCDIAnnotatedClassNames(DeploymentContext context) { - final Set result = new HashSet<>(); - final Set cdiEnablingAnnotations = new HashSet<>(); - Collections.addAll(cdiEnablingAnnotations, getCDIEnablingAnnotations(context)); - - for (final Type type : getAllTypes(context, List.of())) { - if (!(type instanceof AnnotationType)) { - for (final AnnotationModel am : type.getAnnotations()) { - final AnnotationType at = am.getType(); - if (cdiEnablingAnnotations.contains(at.getName())) { - result.add(type.getName()); - break; - } - } - } + @SuppressWarnings("unchecked") + Set result = context.getTransientAppMetaData(CDI_ANNOTATED_CLASS_NAMES_METADATA, Set.class); + if (result != null) { + return result; } + final Set cdiEnablingAnnotations = new HashSet<>(); + Collections.addAll(cdiEnablingAnnotations, getCDIEnablingAnnotations(context)); + var indexes = Globals.getDefaultHabitat().getService(JandexIndexer.class).getAllIndexes(context); + result = new HashSet<>(); + var finalResult = result; + indexes.values().forEach(index -> cdiEnablingAnnotations + .forEach(annotation -> finalResult.addAll(index.getIndex().getAnnotations(annotation).stream() + .map(WeldUtils::mapAnnotationToClassName) + .filter(Objects::nonNull) + .collect(Collectors.toSet())))); + context.addTransientAppMetaData(CDI_ANNOTATED_CLASS_NAMES_METADATA, result); return result; } @@ -300,61 +321,25 @@ public static Collection getCDIAnnotatedClassNames(DeploymentContext con * Searches through the known class names of a {@link BeanDeploymentArchive} to determine which have fields or * methods with the {@link Inject} annotation. * - * @param types The Types obtained from a {@link DeploymentContext}'s transient metadata + * @param deploymentContext The deployment context * @param knownClassNames The known class names of a {@link BeanDeploymentArchive} * @return The class names from the given list which have fields or methods annotated with {@link Inject} */ - public static Collection getInjectionTargetClassNames(Types types, Collection knownClassNames) { - final Set result = new HashSet<>(); - - if (types != null) { - for (String knownClassName : knownClassNames) { - Type type = types.getBy(knownClassName); - - if (type != null && type instanceof ClassModel) { - boolean injectionTarget = false; - - Collection fieldModels = ((ClassModel) type).getFields(); - for (FieldModel fieldModel : fieldModels) { - injectionTarget = annotatedWithInject(fieldModel.getAnnotations()); - if (injectionTarget) { - break; - } - } - - if (!injectionTarget) { - Collection methodModels = type.getMethods(); - for (MethodModel methodModel : methodModels) { - injectionTarget = annotatedWithInject(methodModel.getAnnotations()); - if (injectionTarget) { - break; - } - } - } - - if (injectionTarget) { - result.add(type.getName()); - } + public static Collection getInjectionTargetClassNames(DeploymentContext deploymentContext, + Collection knownClassNames) { + var indexes = Globals.getDefaultHabitat().getService(JandexIndexer.class).getAllIndexes(deploymentContext); + Set result = new HashSet<>(); + indexes.values().forEach(index -> { + for (AnnotationInstance annotationInstance : index.getIndex().getAnnotations(Inject.class)) { + String className = mapAnnotationToClassName(annotationInstance); + if (className != null && knownClassNames.contains(className)) { + result.add(className); } } - } - + }); return result; } - private static boolean annotatedWithInject(Collection annotationModels) { - boolean injectionTarget = false; - for (AnnotationModel annotationModel : annotationModels) { - if (annotationModel.getType().getName().equals(Inject.class.getName())) { - injectionTarget = true; - break; - } - } - - return injectionTarget; - } - - /** * Determine whether the specified class is annotated with a CDI scope annotation. * @@ -378,47 +363,6 @@ public static boolean hasCDIEnablingAnnotation(Class clazz) { return hasValidAnnotation(clazz, cdiEnablingAnnotations, null); } - - /** - * Determine if the specified annotation type is a CDI-enabling annotation - * - * @param annotationType The annotation type to check - * - * @return true, if the specified annotation type qualifies as a CDI enabler; Otherwise, false - */ - private static boolean isCDIEnablingAnnotation(AnnotationType annotationType) { - return isCDIEnablingAnnotation(annotationType, new HashSet<>()); - } - - - /** - * Determine if the specified annotation type is a CDI-enabling annotation - * - * @param annotationType The annotation type to check - * @param exclusions The Set of annotation type names that should be excluded from the analysis - * - * @return true, if the specified annotation type qualifies as a CDI enabler; Otherwise, false - */ - private static boolean isCDIEnablingAnnotation(AnnotationType annotationType, - Set exclusions) { - - final String annotationTypeName = annotationType.getName(); - if (cdiEnablingAnnotations.contains(annotationTypeName)) { - return true; - } else if (exclusions.add(annotationTypeName)) { - // If the annotation type itself is not an excluded type, then check its annotation - // types, exclude itself to avoid infinite recursion - for (AnnotationModel parent : annotationType.getAnnotations()) { - if (isCDIEnablingAnnotation(parent.getType(), exclusions)) { - return true; - } - } - } - - return false; - } - - /** * Determine whether the specified class is annotated with one of the annotations in the specified * validScopes collection, but not with any of the annotations in the specified exclusion set. @@ -481,7 +425,7 @@ private static boolean isValidAnnotation(Class annotationT final String annotationTypeName = annotationType.getName(); if (validTypeNames.contains(annotationTypeName) && !excludedTypeNames.contains(annotationTypeName)) { return true; - } else if (excludedTypeNames.add(annotationTypeName)){ + } else if (excludedTypeNames.add(annotationTypeName)) { // If the annotation type itself is not an excluded type, then check its annotation // types, exclude itself (to avoid infinite recursion) for (Annotation parent : annotationType.getAnnotations()) { @@ -494,23 +438,6 @@ private static boolean isValidAnnotation(Class annotationT return false; } - - private static Types getTypes(DeploymentContext context) { - String metadataKey = Types.class.getName(); - - Types types = (Types) context.getTransientAppMetadata().get(metadataKey); - while (types == null) { - context = ((ExtendedDeploymentContext) context).getParentContext(); - if (context != null) { - types = (Types) context.getTransientAppMetadata().get(metadataKey); - } else { - break; - } - } - - return types; - } - public static int getPreLoaderThreads() { int result = 0; // Check the "global" configuration @@ -606,15 +533,20 @@ public static InputStream getBeansXmlInputStream(DeploymentContext context) { * @return false if there is an extension and no beans.xml * true otherwise */ - public static boolean isValidBdaBasedOnExtensionAndBeansXml(ReadableArchive archive) { - try { - if (hasExtension(archive) && !hasBeansXML(archive)) { - // Extensions and no beans.xml: not a bda - return false; + public static boolean isValidBdaBasedOnExtensionAndBeansXml(DeploymentContext context, ReadableArchive archive) { + var index = Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, Collections.singleton(archive.getURI())) + .values().stream().findAny().get(); + return index.isValidBdaBasedOnExtensionAndBeansXml(() -> { + try { + if (hasExtension(archive) && !hasBeansXML(archive)) { + // Extensions and no beans.xml: not a bda + return false; + } + } catch (IOException ignore) { } - } catch (IOException ignore) { - } - return true; + return true; + }); } public static boolean hasExtension(ReadableArchive archive) { @@ -702,24 +634,6 @@ public static String getBeanDiscoveryMode(InputStream beansXmlInputStream) { return beanDiscoveryMode; } - private static List getAllTypes(DeploymentContext context, Collection paths) { - final Types types = getTypes(context); - if (types == null) { - return List.of(); - } - - List allTypes = new ArrayList<>(types.getAllTypes()); - Map cache = DeploymentUtils.getWarLibraryCache(); - for (URI path : paths.isEmpty() ? cache.keySet().stream().map(Path::of).map(Path::toUri) - .collect(Collectors.toList()) : paths) { - var descriptor = cache.get(path.getRawPath()); - if (descriptor != null) { - allTypes.addAll(descriptor.getTypes()); - } - } - return allTypes; - } - private static class LocalDefaultHandler extends DefaultHandler { String beanDiscoveryMode = null; @@ -741,4 +655,29 @@ private SAXStoppedIntentionallyException() { super(); } } + + private static String mapAnnotationToClassName(AnnotationInstance annotationInstance) { + String className = null; + switch (annotationInstance.target().kind()) { + case CLASS: + className = annotationInstance.target().asClass().name().toString(); + break; + case FIELD: + className = annotationInstance.target().asField().declaringClass().name().toString(); + break; + case METHOD: + className = annotationInstance.target().asMethod().receiverType().name().toString(); + break; + case METHOD_PARAMETER: + className = annotationInstance.target().asMethodParameter().method().receiverType().name().toString(); + break; + case TYPE: + className = annotationInstance.target().asType().asClass().toString(); + break; + case RECORD_COMPONENT: + className = annotationInstance.target().asRecordComponent().declaringClass().name().toString(); + break; + } + return className; + } } diff --git a/appserver/web/jsf-connector/src/main/java/fish/payara/faces/integration/MojarraSniffer.java b/appserver/web/jsf-connector/src/main/java/fish/payara/faces/integration/MojarraSniffer.java index d6fa83f9725..8f93e6477d1 100644 --- a/appserver/web/jsf-connector/src/main/java/fish/payara/faces/integration/MojarraSniffer.java +++ b/appserver/web/jsf-connector/src/main/java/fish/payara/faces/integration/MojarraSniffer.java @@ -42,14 +42,14 @@ import com.sun.enterprise.util.Utility; import com.sun.faces.config.FacesInitializer; import com.sun.faces.config.FacesInitializer2; +import jakarta.inject.Inject; import jakarta.inject.Singleton; import jakarta.servlet.ServletContainerInitializer; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ArchiveType; import org.glassfish.api.deployment.archive.ReadableArchive; -import org.glassfish.hk2.classmodel.reflect.Types; -import org.glassfish.internal.deployment.ExtendedDeploymentContext; import org.glassfish.internal.deployment.GenericSniffer; +import org.glassfish.internal.deployment.JandexIndexer; import org.glassfish.web.loader.ServletContainerInitializerUtil; import org.jvnet.hk2.annotations.Service; @@ -75,6 +75,9 @@ public class MojarraSniffer extends GenericSniffer { private static final String[] containers = { "org.glassfish.weld.WeldContainer" }; private static final Logger logger = Logger.getLogger(MojarraSniffer.class.getName()); + @Inject + JandexIndexer jandexIndexer; + public MojarraSniffer() { super("cdi", null, null); } @@ -166,14 +169,14 @@ private boolean hasFacesEnablingClass(DeploymentContext context) { Map, Set>> initialiserList = ServletContainerInitializerUtil.getInitializerList( facesInitialisers, interestList, - getTypes(context), + jandexIndexer.getAllIndexes(context), Utility.getClassLoader(), false); for (Map.Entry, Set>> initialiserEntry : initialiserList.entrySet()) { if (initialiserEntry.getValue() != null && !initialiserEntry.getValue().isEmpty()) { if (logger.isLoggable(Level.FINE)) { List classNames = new ArrayList<>(); - initialiserEntry.getValue().stream().forEach(clazz -> classNames.add(clazz.getName())); + initialiserEntry.getValue().forEach(clazz -> classNames.add(clazz.getName())); logger.fine(initialiserEntry.getKey().getName() + " container initialiser has an interest in the following classes detected within the application: " + Arrays.toString(classNames.toArray())); @@ -200,26 +203,4 @@ private List getMojarraServletContextInitialisers(D return facesInitialisers; } - - private Types getTypes(DeploymentContext context) { - String metadataKey = Types.class.getName(); - - Types types = (Types) context.getTransientAppMetadata().get(metadataKey); - while (types == null) { - context = ((ExtendedDeploymentContext) context).getParentContext(); - if (context != null) { - types = (Types) context.getTransientAppMetadata().get(metadataKey); - } else { - break; - } - } - - if (types == null) { - logger.fine("No types found!"); - } - - return types; - } - - } diff --git a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/ServletContainerInitializerUtil.java b/appserver/web/war-util/src/main/java/org/glassfish/web/loader/ServletContainerInitializerUtil.java index 1a7be433272..4b9b15ec62b 100644 --- a/appserver/web/war-util/src/main/java/org/glassfish/web/loader/ServletContainerInitializerUtil.java +++ b/appserver/web/war-util/src/main/java/org/glassfish/web/loader/ServletContainerInitializerUtil.java @@ -43,10 +43,13 @@ import fish.payara.web.loader.ServletContainerInitializerBlacklist; import org.glassfish.deployment.common.ClassDependencyBuilder; -import org.glassfish.hk2.classmodel.reflect.*; import jakarta.servlet.ServletContainerInitializer; import jakarta.servlet.annotation.HandlesTypes; +import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.deployment.JandexIndexer.Index; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.ClassInfo; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -230,6 +233,15 @@ public static Map, List>> return interestList; } + @Deprecated + public static Map, Set>> getInitializerList( + Iterable initializers, + Map, List>> interestList, + Types types, + ClassLoader cl, boolean isStandalone) { + throw new IllegalStateException("Method is deprecated"); + } + /** * Given an interestlist that was built above, and a class loader, scan the entire web app's classes and libraries * looking for classes that extend/implement/use the annotations of a class present in the interest list @@ -245,7 +257,7 @@ public static Map, List>> public static Map, Set>> getInitializerList( Iterable initializers, Map, List>> interestList, - Types types, + Map indexMap, ClassLoader cl, boolean isStandalone) { if (interestList == null) { @@ -281,7 +293,7 @@ public static Map, Set>> * the information for every class in this app * */ - if (types==null || Boolean.getBoolean("org.glassfish.web.parsing")) { + if (indexMap==null || Boolean.getBoolean("org.glassfish.web.parsing")) { ClassDependencyBuilder classInfo = new ClassDependencyBuilder(); if (cl instanceof URLClassLoader) { URLClassLoader ucl = (URLClassLoader) cl; @@ -350,7 +362,7 @@ public static Map, Set>> initializerList = checkAgainstInterestList(classInfo, interestList, initializerList, cl, isStandalone); } else { - initializerList = checkAgainstInterestList(types, interestList, initializerList, cl, isStandalone); + initializerList = checkAgainstInterestList(indexMap, interestList, initializerList, cl, isStandalone); } } @@ -440,66 +452,32 @@ private static void scanDirectory(File dir, ClassDependencyBuilder classInfo) { * */ private static Map, Set>> checkAgainstInterestList( - Types classInfo, + Map indexMap, Map, List>> interestList, Map, Set>> initializerList, ClassLoader cl, boolean isStandalone) { - if (classInfo==null) { + if (indexMap==null) { return initializerList; } for (Map.Entry, List>> e: interestList.entrySet()) { - Class c = e.getKey(); - Type type = classInfo.getBy(c.getName()); - if (type==null) - continue; - Set> resultSet = new HashSet>(); - if (type instanceof AnnotationType) { - for (AnnotatedElement ae : ((AnnotationType) type).allAnnotatedTypes()) { - if (ae instanceof Member) { - ae = ((Member) ae).getDeclaringType(); - } else if (ae instanceof Parameter) { - ae = ((Parameter) ae).getMethod().getDeclaringType(); - } - if (ae instanceof Type) { - try { - resultSet.add(cl.loadClass(ae.getName())); - } catch (Throwable t) { - if (log.isLoggable(getStandaloneWarningLevel(isStandalone))) { - log.log(getStandaloneWarningLevel(isStandalone), - LogFacade.CLASS_LOADING_ERROR, - new Object[] {ae.getName(), t.toString()}); - } - } - } - } - } else { - Collection classes; - if (type instanceof InterfaceModel) { - classes = ((InterfaceModel) type).allImplementations(); - } else { - classes = ((ClassModel) type).allSubTypes(); - } - for (ClassModel classModel : classes) { - try { - resultSet.add(cl.loadClass(classModel.getName())); - } catch (Throwable t) { - if (log.isLoggable(getStandaloneWarningLevel(isStandalone))) { - log.log(getStandaloneWarningLevel(isStandalone), - LogFacade.CLASS_LOADING_ERROR, - new Object[] {classModel.getName(), t.toString()}); - } - } - } + for (Index index : indexMap.values()) { + index.getIndex().getAllKnownImplementors(e.getKey()) + .forEach(classInfo -> addClassToResult(classInfo, cl, isStandalone, resultSet)); + index.getIndex().getAllKnownSubclasses(e.getKey()) + .forEach(classInfo -> addClassToResult(classInfo, cl, isStandalone, resultSet)); + index.getIndex().getAnnotations(e.getKey()).forEach(annotation -> + addClassToResult(mapAnnotationToClassName(annotation), cl, isStandalone, resultSet)); } + List> containerInitializers = e.getValue(); for(Class initializer : containerInitializers) { Set> classSet = initializerList.get(initializer); if(classSet == null) { - classSet = new HashSet>(); + classSet = new HashSet<>(); } classSet.addAll(resultSet); initializerList.put(initializer, classSet); @@ -509,6 +487,55 @@ private static Map, Set>> return initializerList; } + + private static void addClassToResult(ClassInfo classInfo, ClassLoader cl, + boolean isStandalone, Set> resultSet) { + addClassToResult(classInfo.name().toString(), cl, isStandalone, resultSet); + } + + private static void addClassToResult(String className, ClassLoader cl, + boolean isStandalone, Set> resultSet) { + try { + resultSet.add(cl.loadClass(className)); + } catch (Exception t) { + if (log.isLoggable(getStandaloneWarningLevel(isStandalone))) { + log.log(getStandaloneWarningLevel(isStandalone), + LogFacade.CLASS_LOADING_ERROR, + new Object[]{className, t.toString()}); + } + } + } + + /** + * *** TODO: duplicate from weld-gf-connector + * @param annotationInstance + * @return + */ + private static String mapAnnotationToClassName(AnnotationInstance annotationInstance) { + String className = null; + switch (annotationInstance.target().kind()) { + case CLASS: + className = annotationInstance.target().asClass().name().toString(); + break; + case FIELD: + className = annotationInstance.target().asField().declaringClass().name().toString(); + break; + case METHOD: + className = annotationInstance.target().asMethod().receiverType().name().toString(); + break; + case METHOD_PARAMETER: + className = annotationInstance.target().asMethodParameter().method().receiverType().name().toString(); + break; + case TYPE: + className = annotationInstance.target().asType().asClass().toString(); + break; + case RECORD_COMPONENT: + className = annotationInstance.target().asRecordComponent().declaringClass().name().toString(); + break; + } + return className; + } + /** * Given the interestList, checks if a given class uses any of the * annotations; If so, builds the initializer list diff --git a/appserver/web/web-core/src/main/java/org/apache/catalina/core/StandardContext.java b/appserver/web/web-core/src/main/java/org/apache/catalina/core/StandardContext.java index 42758ba328c..c1a167b8c45 100644 --- a/appserver/web/web-core/src/main/java/org/apache/catalina/core/StandardContext.java +++ b/appserver/web/web-core/src/main/java/org/apache/catalina/core/StandardContext.java @@ -193,7 +193,11 @@ import org.glassfish.grizzly.http.server.util.MappingData; import org.glassfish.grizzly.http.util.CharChunk; import org.glassfish.grizzly.http.util.MessageBytes; +import org.glassfish.hk2.api.ServiceLocator; import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.deployment.Deployment; +import org.glassfish.internal.deployment.ExtendedDeploymentContext; +import org.glassfish.internal.deployment.JandexIndexer; import org.glassfish.web.loader.ServletContainerInitializerUtil; import org.glassfish.web.loader.WebappClassLoader; import org.glassfish.web.valve.GlassFishValve; @@ -5816,20 +5820,23 @@ protected boolean isStandalone() { protected void callServletContainerInitializers() throws LifecycleException { - // Get the list of ServletContainerInitializers and the classes - // they are interested in - Map, List>> interestList = - ServletContainerInitializerUtil.getInterestList( - servletContainerInitializers); - Map, Set>> initializerList = - ServletContainerInitializerUtil.getInitializerList( - servletContainerInitializers, interestList, - getTypes(), - getClassLoader(), isStandalone()); + ServiceLocator locator = org.glassfish.internal.api.Globals.getDefaultHabitat(); + var deploymentContext = locator.getService(Deployment.class).getCurrentDeploymentContext(); + + Map, Set>> initializerList = null; + if (deploymentContext != null && deploymentContext.getPhase() != ExtendedDeploymentContext.Phase.PREPARE) { + // Get the list of ServletContainerInitializers and the classes + // they are interested in + Map, List>> interestList = + ServletContainerInitializerUtil.getInterestList( + servletContainerInitializers); + initializerList = ServletContainerInitializerUtil.getInitializerList(servletContainerInitializers, interestList, + locator.getService(JandexIndexer.class).getAllIndexes(deploymentContext), getClassLoader(), isStandalone()); + } + if (initializerList == null) { return; } - // Allow programmatic registration of ServletContextListeners, but // only within the scope of ServletContainerInitializer#onStartup isProgrammaticServletContextListenerRegistrationAllowed = true; diff --git a/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebModule.java b/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebModule.java index 7e11a781b85..ad8af5fc444 100644 --- a/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebModule.java +++ b/appserver/web/web-glue/src/main/java/com/sun/enterprise/web/WebModule.java @@ -721,7 +721,7 @@ private JaccConfigurationFactory getJaccConfigurationFactory() { @Override protected Types getTypes() { if (wmInfo.getDeploymentContext()!=null) { - return wmInfo.getDeploymentContext().getTransientAppMetaData(Types.class.getName(), Types.class); + throw new IllegalStateException("getTypes() should not be called on a WebModule"); } else { return null; } diff --git a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/annotation/impl/WarScanner.java b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/annotation/impl/WarScanner.java index fb8e0536f3b..d5801541ca4 100644 --- a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/annotation/impl/WarScanner.java +++ b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/annotation/impl/WarScanner.java @@ -37,30 +37,21 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2016-2024] [Payara Foundation and/or its affiliates] +// Portions Copyright [2016-2025] [Payara Foundation and/or its affiliates] package org.glassfish.web.deployment.annotation.impl; import com.sun.enterprise.deployment.WebBundleDescriptor; -import com.sun.enterprise.deployment.WebComponentDescriptor; import com.sun.enterprise.deployment.annotation.impl.ModuleScanner; -import com.sun.enterprise.deployment.web.AppListenerDescriptor; -import com.sun.enterprise.deployment.web.ServletFilter; -import org.glassfish.apf.impl.AnnotationUtils; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.hk2.api.PerLookup; import org.glassfish.hk2.classmodel.reflect.Parser; import org.glassfish.internal.api.ClassLoaderHierarchy; -import org.glassfish.web.deployment.descriptor.*; import jakarta.inject.Inject; import org.jvnet.hk2.annotations.Service; import java.io.File; import java.io.IOException; -import java.util.Iterator; -import java.util.Vector; -import java.util.logging.Level; - /** * Implementation of the Scanner interface for war. @@ -85,7 +76,7 @@ public boolean isScanOtherLibraries() { @Override public void process(File archiveFile, WebBundleDescriptor webBundleDesc, ClassLoader classLoader) throws IOException { - throw new UnsupportedOperationException("Not supported."); + throw new UnsupportedOperationException("No longer supported."); } /** @@ -97,116 +88,6 @@ public void process(File archiveFile, WebBundleDescriptor webBundleDesc, @Override public void process(ReadableArchive readableArchive, WebBundleDescriptor webBundleDesc, ClassLoader classLoader, Parser parser) throws IOException { - - WebFragmentDescriptor webFragmentDesc = new WebFragmentDescriptor(); - if (webBundleDesc instanceof WebFragmentDescriptor) { - webFragmentDesc = (WebFragmentDescriptor) webBundleDesc; - } - if (webFragmentDesc.isWarLibrary()) { - this.archiveFile = new File(webFragmentDesc.getWarLibraryPath()); - } else { - this.archiveFile = new File(readableArchive.getURI()); - } - this.classLoader = classLoader; - setParser(parser); - - if (AnnotationUtils.getLogger().isLoggable(Level.FINE)) { - AnnotationUtils.getLogger().log(Level.FINE, "archiveFile is {0}", archiveFile); - AnnotationUtils.getLogger().log(Level.FINE, "webBundle is {0}", webBundleDesc); - AnnotationUtils.getLogger().log(Level.FINE, "classLoader is {0}", classLoader); - } - - if (!webFragmentDesc.isWarLibrary() && !archiveFile.isDirectory()) { - // on client side - return; - } - - if (isScanOtherLibraries()) { - addLibraryJars(webBundleDesc, readableArchive); - calculateResults(webBundleDesc); - return; - } - - File webinf = new File(archiveFile, "WEB-INF"); - - if (webBundleDesc instanceof WebFragmentDescriptor) { - if (webFragmentDesc.isWarLibrary()) { - addScanJar(archiveFile); - } else { - File lib = new File(webinf, "lib"); - if (lib.exists()) { - File jarFile = new File(lib, webFragmentDesc.getJarName()); - if (jarFile.exists()) { - // support exploded jar file - if (jarFile.isDirectory()) { - addScanDirectory(jarFile); - } else { - addScanJar(jarFile); - } - } - } - } - } else { - File classes = new File(webinf, "classes"); - if (classes.exists()) { - addScanDirectory(classes); - } - } - scanXmlDefinedClassesIfNecessary(webBundleDesc); - calculateResults(webBundleDesc); - } - - // This is not mandated by the spec. It is for WSIT. - // We will also scan any servlets/filters/listeners classes specified - // in web.xml additionally if those classes are not resided in the wars. - private void scanXmlDefinedClassesIfNecessary( - WebBundleDescriptor webBundleDesc) - throws IOException { - - ClassLoader commonCL = clh.getCommonClassLoader(); - - for (Iterator webComponents = - webBundleDesc.getWebComponentDescriptors().iterator(); - webComponents.hasNext();) { - WebComponentDescriptor webCompDesc = - (WebComponentDescriptor)webComponents.next(); - if (webCompDesc.isServlet()) { - String servletName = webCompDesc.getWebComponentImplementation(); - if (isScan(servletName, commonCL)) { - addScanClassName(servletName); - } - } - } - - Vector servletFilters = webBundleDesc.getServletFilters(); - for (int i = 0; i < servletFilters.size(); i++) { - ServletFilter filter = (ServletFilter)servletFilters.elementAt(i); - String filterName = filter.getClassName(); - if (isScan(filterName, commonCL)) { - addScanClassName(filter.getClassName()); - } - } - - Vector listeners = webBundleDesc.getAppListenerDescriptors(); - for (int j = 0; j < listeners.size(); j++) { - AppListenerDescriptor listenerDesc = - (AppListenerDescriptor) listeners.elementAt(j); - String listenerName = listenerDesc.getListener(); - if (isScan(listenerName, commonCL)) { - addScanClassName(listenerDesc.getListener()); - } - } - } - - /** - * Returns true if the class is accessible from the classloader - * @param className - * @param commonCL - * @return - * @throws IOException - */ - private boolean isScan(String className, ClassLoader commonCL) throws IOException { - return commonCL.getResource(className.replace(".", "/") + ".class") != null; + throw new UnsupportedOperationException("No longer supported."); } } - diff --git a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java index eca18f0b6f6..49e7df3ddac 100644 --- a/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java +++ b/appserver/web/web-glue/src/main/java/org/glassfish/web/deployment/archivist/WebArchivist.java @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2014-2024] [Payara Foundation and/or its affiliates] +// Portions Copyright [2014-2025] [Payara Foundation and/or its affiliates] package org.glassfish.web.deployment.archivist; @@ -50,10 +50,8 @@ import com.sun.enterprise.deployment.EjbDescriptor; import com.sun.enterprise.deployment.WebComponentDescriptor; import com.sun.enterprise.deployment.annotation.impl.ModuleScanner; -import org.glassfish.hk2.classmodel.reflect.Parser; -import org.glassfish.hk2.classmodel.reflect.Type; -import org.glassfish.hk2.classmodel.reflect.Types; import org.glassfish.internal.deployment.Deployment; +import org.glassfish.internal.deployment.JandexIndexer; import org.glassfish.web.deployment.annotation.impl.WarScanner; import com.sun.enterprise.deployment.archivist.Archivist; import com.sun.enterprise.deployment.archivist.ArchivistFor; @@ -81,6 +79,7 @@ import java.io.File; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedHashSet; @@ -90,7 +89,6 @@ import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; /** @@ -117,6 +115,8 @@ public class WebArchivist extends Archivist { private ArchiveFactory archiveFactory; @Inject private Deployment deployment; + @Inject + JandexIndexer jandexIndexer; /** * @return the module type handled by this archivist @@ -368,7 +368,6 @@ protected void postAnnotationProcess(WebBundleDescriptorImpl descriptor, ReadableArchive warArchive = null; try { warArchive = archiveFactory.openArchive(new File(wfDesc.getWarLibraryPath())); - warArchive.setExtraData(Parser.class, archive.getExtraData(Parser.class)); super.readAnnotations(warArchive, wfDesc, localExtensions); } finally { if (warArchive != null) { @@ -376,7 +375,10 @@ protected void postAnnotationProcess(WebBundleDescriptorImpl descriptor, } } DeploymentUtils.getWarLibraryCache().putIfAbsent(wfDesc.getWarLibraryPath(), - new DeploymentUtils.WarLibraryDescriptor(wfDesc, filterTypesByWarLibrary(wfDesc))); + new DeploymentUtils.WarLibraryDescriptor(wfDesc, + jandexIndexer.getIndexesByURI(deployment.getCurrentDeploymentContext(), + Collections.singleton(Path.of(wfDesc.getWarLibraryPath()).toUri())) + .values().stream().findAny().orElse(null))); } } else { super.readAnnotations(archive, wfDesc, localExtensions); @@ -418,15 +420,6 @@ protected void postAnnotationProcess(WebBundleDescriptorImpl descriptor, descriptor.addDefaultWebBundleDescriptor(defaultWebBundleDescriptor); } - private List filterTypesByWarLibrary(WebFragmentDescriptor wfDesc) { - Types types = deployment.getCurrentDeploymentContext().getTransientAppMetaData(Types.class.getName(), Types.class); - if (types == null) { - return List.of(); - } - return types.getAllTypes().stream().filter(key -> key.wasDefinedIn( - List.of(Path.of(wfDesc.getWarLibraryPath()).toUri()))).collect(Collectors.toList()); - } - /** * This method will return the list of web fragment in the desired order. */ @@ -475,6 +468,9 @@ private List readStandardFragments(WebBundleDescriptorImp } } wfDesc.setJarName(lib.substring(lib.lastIndexOf('/') + 1)); + if (embeddedArchive != null) { + wfDesc.setName(embeddedArchive.getURI().getPath()); + } if (isWarLibrary) { if (wfDesc.getClassLoader() != null) { wfDesc.setClassLoader(wfDesc.getClassLoader().getParent()); diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java index 235ed40151a..0f1431fc7eb 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/BeanDeploymentArchiveImpl.java @@ -47,6 +47,8 @@ import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.cdi.CDILoggerInfo; +import org.glassfish.internal.api.Globals; +import org.glassfish.internal.deployment.JandexIndexer; import org.glassfish.weld.connector.WeldUtils; import org.glassfish.weld.ejb.EjbDescriptorImpl; import org.jboss.weld.bootstrap.WeldBootstrap; @@ -66,19 +68,15 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable; -import java.net.MalformedURLException; import java.net.URI; import java.net.URL; -import java.net.URLClassLoader; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Level; import java.util.logging.Logger; import static java.util.logging.Level.FINE; import static java.util.logging.Level.FINER; import static java.util.logging.Level.SEVERE; -import static org.glassfish.web.loader.NonCachedJarStreamHandler.forceNonCachedJarURL; import static org.glassfish.weld.WeldDeployer.WELD_BOOTSTRAP; import static org.glassfish.weld.connector.WeldUtils.*; @@ -502,33 +500,7 @@ private void populate(Collection ej if (webinfbda) { bdaType = BDAType.WAR; - Enumeration entries = archive.entries(); - while (entries.hasMoreElements()) { - String entry = entries.nextElement(); - if (legalClassName(entry)) { - if (entry.contains(WEB_INF_CLASSES)) { - //Workaround for incorrect WARs that bundle classes above WEB-INF/classes - //[See. GLASSFISH-16706] - entry = entry.substring(WEB_INF_CLASSES.length() + 1); - } - String className = filenameToClassname(entry); - try { - if (hasBeansXml || isCDIAnnotatedClass(className)) { - beanClassNames.add(className); - beanClasses.add(getClassLoader().loadClass(className)); - } - moduleClassNames.add(className); - } catch (Throwable t) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, CDILoggerInfo.ERROR_LOADING_BEAN_CLASS, - new Object[]{className, t.toString()}); - } - } - } else if (entry.endsWith(BEANS_XML_FILENAME)) { - addBeansXMLURL(archive, entry); - } - } - archive.close(); + addClassNamesFromIndex(archive, hasBeansXml); } // If this archive has WEB-INF/lib entry.. @@ -699,94 +671,42 @@ private void ensureWebLibJarVisibility(List webLibBDA private void collectJarInfo(ReadableArchive archive, boolean isBeanArchive, boolean hasBeansXml) throws IOException, ClassNotFoundException { - if (archive != null) { + if (archive != null && isBeanArchive) { if (logger.isLoggable(FINE)) { logger.log(FINE, CDILoggerInfo.COLLECTING_JAR_INFO, new Object[]{archive.getURI()}); } - Enumeration entries = archive.entries(); - while (entries.hasMoreElements()) { - String entry = entries.nextElement(); - handleEntry(archive, entry, isBeanArchive, hasBeansXml); - } + addClassNamesFromIndex(archive, hasBeansXml); } } - private void handleEntry(ReadableArchive archive, - String entry, - boolean isBeanArchive, - boolean hasBeansXml) throws ClassNotFoundException { - if (legalClassName(entry)) { - String className = filenameToClassname(entry); - try { - if (isBeanArchive) { - // If the jar is a bean archive, or the individual class should be managed, - // based on its annotation(s) + private void addClassNamesFromIndex(ReadableArchive archive, boolean hasBeansXml) { + Globals.getDefaultHabitat().getService(JandexIndexer.class) + .getIndexesByURI(context, Collections.singleton(archive.getURI())) + .values().stream().findAny().get().getIndex() + .getKnownClasses().forEach(classInfo -> { + String className = classInfo.name().toString(); if (hasBeansXml || isCDIAnnotatedClass(className)) { - beanClasses.add(getClassLoader().loadClass(className)); beanClassNames.add(className); } - } - // Add the class as a module class - moduleClassNames.add(className); - } catch (Throwable t) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, - CDILoggerInfo.ERROR_LOADING_BEAN_CLASS, - new Object[]{className, t.toString()}); - } - } - } else if (entry.endsWith("/beans.xml")) { - try { - // use a throwaway classloader to load the application's beans.xml - ClassLoader throwAwayClassLoader = - new URLClassLoader(new URL[]{archive.getURI().toURL()}, null); - URL beansXmlUrl = forceNonCachedJarURL(throwAwayClassLoader.getResource(entry)); - if (beansXmlUrl != null && !beansXmlURLs.contains(beansXmlUrl)) { // http://java.net/jira/browse/GLASSFISH-17157 - beansXmlURLs.add(beansXmlUrl); - } - } catch (MalformedURLException e) { - if (logger.isLoggable(Level.SEVERE)) { - logger.log(Level.SEVERE, - CDILoggerInfo.SEVERE_ERROR_READING_ARCHIVE, - new Object[]{e.getMessage()}); - } - } - } - } - - - private boolean legalClassName(String className) { - return className.endsWith(CLASS_SUFFIX) && !className.startsWith(WEB_INF_LIB); + moduleClassNames.add(className); + }); } - private void collectRarInfo(ReadableArchive archive) throws IOException, ClassNotFoundException { if (logger.isLoggable(FINE)) { logger.log(FINE, CDILoggerInfo.COLLECTING_RAR_INFO, new Object[]{archive.getURI()}); } Enumeration entries = archive.entries(); + addClassNamesFromIndex(archive, false); while (entries.hasMoreElements()) { String entry = entries.nextElement(); if (entry.endsWith(JAR_SUFFIX)) { ReadableArchive jarArchive = archive.getSubArchive(entry); collectJarInfo(jarArchive, true, true); - } else { - handleEntry(archive, entry, true, true); } } } - private static String filenameToClassname(String filename) { - String className = null; - if (filename.indexOf(File.separatorChar) >= 0) { - className = filename.replace(File.separatorChar, '.'); - } else { - className = filename.replace(SEPARATOR_CHAR, '.'); - } - className = className.substring(0, className.length() - 6); - return className; - } - private ClassLoader getClassLoader() { ClassLoader cl; if (this.context.getClassLoader() != null) { diff --git a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java index 2bae45ddd6a..557eec86d44 100644 --- a/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java +++ b/appserver/web/weld-integration/src/main/java/org/glassfish/weld/WeldDeployer.java @@ -888,7 +888,7 @@ private void fireProcessInjectionTargetEvents(WeldBootstrap bootstrap, Applicati // From the spec: "The container must also fire an event for every Jakarta EE component class supporting // injection that may be instantiated by the container at runtime". Stress on the "may". Collection injectionTargetClassNames = WeldUtils.getInjectionTargetClassNames( - deploymentImpl.getTypes(), beanDeploymentArchive.getKnownClasses()); + deploymentImpl.context, beanDeploymentArchive.getKnownClasses()); for (String injectionTargetClassName : injectionTargetClassNames) { // Don't fire twice if (beanDeploymentArchive.getBeanClasses().contains(injectionTargetClassName)) { diff --git a/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/deployment/archive/Archive.java b/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/deployment/archive/Archive.java index 26b0007ad74..22d78c659ce 100644 --- a/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/deployment/archive/Archive.java +++ b/nucleus/common/glassfish-api/src/main/java/org/glassfish/api/deployment/archive/Archive.java @@ -55,7 +55,7 @@ * * @author Jerome Dochez */ -public interface Archive { +public interface Archive extends AutoCloseable { /** * closes this archive and releases all resources diff --git a/nucleus/common/internal-api/pom.xml b/nucleus/common/internal-api/pom.xml index 60536d64bd4..dc418615f55 100644 --- a/nucleus/common/internal-api/pom.xml +++ b/nucleus/common/internal-api/pom.xml @@ -140,6 +140,11 @@ + + io.smallrye + jandex + ${jandex.version} + org.glassfish.annotations logging-annotation-processor diff --git a/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/Deployment.java b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/Deployment.java index 5d29afd4fd9..e49c05ae459 100644 --- a/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/Deployment.java +++ b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/Deployment.java @@ -316,7 +316,9 @@ DeploymentContext enable(String target, Application app, ApplicationRef appRef, * @param context deployment context * @return the types information from the deployment artifacts * @throws IOException if the scanning fails due to an I/O exception + * @deprecated replaced with Jandex indexer */ + @Deprecated(forRemoval = true, since = "7.0.0") Types getDeployableTypes(DeploymentContext context) throws IOException; List getSniffersFromApp(Application app); diff --git a/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/JandexIndexer.java b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/JandexIndexer.java new file mode 100644 index 00000000000..101c2d520ed --- /dev/null +++ b/nucleus/common/internal-api/src/main/java/org/glassfish/internal/deployment/JandexIndexer.java @@ -0,0 +1,122 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2025] Payara Foundation and/or its affiliates. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common Development + * and Distribution License("CDDL") (collectively, the "License"). You + * may not use this file except in compliance with the License. You can + * obtain a copy of the License at + * https://github.com/payara/Payara/blob/main/LICENSE.txt + * See the License for the specific + * language governing permissions and limitations under the License. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation in the GPL Version 2 section of the License + * file that accompanied this code. + * + * Modifications: + * If applicable, add the following below the License Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyright [year] [name of copyright owner]" + * + * Contributor(s): + * If you wish your version of this file to be governed by only the CDDL or + * only the GPL Version 2, indicate your decision by adding "[Contributor] + * elects to include this software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice of license, a + * recipient has the option to distribute your version of this file under + * either the CDDL, the GPL Version 2 or to extend the choice of license to + * its licensees as provided above. However, if you add GPL Version 2 code + * and therefore, elected the GPL Version 2 license, then the option applies + * only if the new code is made subject to such option by the copyright + * holder. + */ +package org.glassfish.internal.deployment; + +import org.glassfish.api.deployment.DeploymentContext; +import org.jvnet.hk2.annotations.Contract; +import java.io.IOException; +import java.io.Serializable; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.BooleanSupplier; + +@Contract +public interface JandexIndexer { + enum SettingType { + UNSET, + TRUE, + FALSE, + ; + + public boolean isSet() { + return this != UNSET; + } + + public boolean isTrue() { + return this == TRUE; + } + + static SettingType of(BooleanSupplier supplier) { + return supplier.getAsBoolean() ? TRUE : FALSE; + } + } + + class Index implements Serializable { + private static final long serialVersionUID = 1L; + + private transient org.jboss.jandex.Index jandexIndex; + private SettingType implicitBeanArchive = SettingType.UNSET; + private SettingType hasCDIEnablingAnnotations = SettingType.UNSET; + private SettingType isValidBdaBasedOnExtensionAndBeansXml = SettingType.UNSET; + + public Index(org.jboss.jandex.Index index) { + this.jandexIndex = index; + } + + public org.jboss.jandex.Index getIndex() { + return jandexIndex; + } + + public void setIndex(org.jboss.jandex.Index index) { + this.jandexIndex = index; + } + + public boolean implicitBeanArchive(BooleanSupplier settingTypeSupplier) { + if (!implicitBeanArchive.isSet()) { + implicitBeanArchive = SettingType.of(settingTypeSupplier); + } + return implicitBeanArchive.isTrue(); + } + + public boolean hasCDIEnablingAnnotations(BooleanSupplier settingTypeSupplier) { + if (!hasCDIEnablingAnnotations.isSet()) { + hasCDIEnablingAnnotations = SettingType.of(settingTypeSupplier); + } + return hasCDIEnablingAnnotations.isTrue(); + } + + public boolean isValidBdaBasedOnExtensionAndBeansXml(BooleanSupplier settingTypeSupplier) { + if (!isValidBdaBasedOnExtensionAndBeansXml.isSet()) { + isValidBdaBasedOnExtensionAndBeansXml = SettingType.of(settingTypeSupplier); + } + return isValidBdaBasedOnExtensionAndBeansXml.isTrue(); + } + } + + void index(DeploymentContext deploymentContext) throws IOException; + void reindex(DeploymentContext deploymentContext) throws IOException; + boolean isJakartaEEApplication(DeploymentContext deploymentContext) throws IOException; + Index getRootIndex(DeploymentContext deploymentContext); + Map getAllIndexes(DeploymentContext deploymentContext); + Map getIndexesByURI(DeploymentContext deploymentContext, Collection uris); + boolean hasAnyAnnotations(DeploymentContext deploymentContext, List uris, String... annotations); +} diff --git a/nucleus/core/kernel/pom.xml b/nucleus/core/kernel/pom.xml index bc64e629576..0bd905ad787 100755 --- a/nucleus/core/kernel/pom.xml +++ b/nucleus/core/kernel/pom.xml @@ -272,6 +272,11 @@ fish.payara.deployment.transformer deployment-transformer-api + + io.smallrye + jandex + ${jandex.version} + 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 c5894174385..ee6704a111b 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 @@ -38,7 +38,7 @@ * holder. */ -// Portions Copyright 2016-2023 Payara Foundation and/or its affiliates. +// Portions Copyright 2016-2025 Payara Foundation and/or its affiliates. package com.sun.enterprise.v3.server; @@ -51,7 +51,6 @@ import com.sun.enterprise.util.LocalStringManagerImpl; import com.sun.enterprise.util.io.FileUtils; import fish.payara.enterprise.config.serverbeans.DeploymentGroup; -import fish.payara.nucleus.executorservice.PayaraExecutorService; import org.glassfish.api.ActionReport; import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.admin.ServerEnvironment; @@ -90,8 +89,7 @@ import org.glassfish.hk2.classmodel.reflect.Parser; import org.glassfish.hk2.classmodel.reflect.ParsingContext; import org.glassfish.hk2.classmodel.reflect.Types; -import org.glassfish.hk2.classmodel.reflect.util.CommonModelRegistry; -import org.glassfish.hk2.classmodel.reflect.util.ResourceLocator; +import org.glassfish.hk2.utilities.BuilderHelper; import org.glassfish.internal.api.ClassLoaderHierarchy; import org.glassfish.internal.data.ApplicationInfo; import org.glassfish.internal.data.ApplicationRegistry; @@ -104,6 +102,7 @@ import org.glassfish.internal.deployment.Deployment; import org.glassfish.internal.deployment.DeploymentTracing; import org.glassfish.internal.deployment.ExtendedDeploymentContext; +import org.glassfish.internal.deployment.JandexIndexer; import org.glassfish.internal.deployment.analysis.DeploymentSpan; import org.glassfish.internal.deployment.analysis.SpanSequence; import org.glassfish.internal.deployment.analysis.StructuredDeploymentTracing; @@ -149,9 +148,6 @@ import static java.util.stream.Collectors.toMap; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import java.net.URISyntaxException; -import org.glassfish.hk2.classmodel.reflect.util.ParsingConfig; -import org.glassfish.hk2.utilities.BuilderHelper; /** * Application Loader is providing useful methods to load applications @@ -198,16 +194,10 @@ public class ApplicationLifecycle implements Deployment, PostConstruct { Events events; @Inject - ConfigSupport configSupport; - - @Inject - CommonClassLoaderServiceImpl commonClassLoaderService; + private HotDeployService hotDeployService; @Inject - PayaraExecutorService executorService; - - @Inject - private HotDeployService hotDeployService; + JandexIndexer jandexIndexer; protected Logger logger = KernelLoggerInfo.getLogger(); final private static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ApplicationLifecycle.class); @@ -397,14 +387,13 @@ public void actOn(Logger logger) { span.start(DeploymentTracing.AppStage.CLASS_SCANNING); - Types types = null; if (handler.requiresAnnotationScanning(context.getSource())) { - types = getDeployableTypes(context); + jandexIndexer.index(context); } span.finish(); - transformApplication(context, types, tracing, span); + transformApplication(context, tracing, span); // containers that are started are not stopped even if // the deployment fail, the main reason @@ -663,132 +652,13 @@ public ApplicationInfo deploy(Collection sniffers, final Exte } @Override + @Deprecated(forRemoval = true) @SuppressWarnings("squid:S2095") public Types getDeployableTypes(DeploymentContext context) throws IOException { - synchronized (context) { - Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class); - if (types != null) { - return types; - } - StructuredDeploymentTracing tracing = StructuredDeploymentTracing.load(context); - Boolean skipScanExternalLibProp = Boolean.valueOf(context.getAppProps().getProperty(DeploymentProperties.SKIP_SCAN_EXTERNAL_LIB)); - - Parser parser = getDeployableParser(context.getSource(), skipScanExternalLibProp, false, tracing, - context.getLogger(), context); - ParsingContext parsingContext = parser.getContext(); - context.addTransientAppMetaData(Types.class.getName(), parsingContext.getTypes()); - context.addTransientAppMetaData(Parser.class.getName(), parser); - return parsingContext.getTypes(); - } - } - - public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp, - boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing, - Logger logger, DeploymentContext deploymentContext) throws IOException { - Parser parser = new Parser(createBuilder(modelUnAnnotatedMembers, logger).build()); - try(ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, source)) { - DeploymentSpan mainScanSpan = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, source.getName()); - return processParsing(skipScanExternalLibProp, tracing, parser, scannerAdapter, mainScanSpan, deploymentContext); - } + throw new IllegalStateException("This method is not supported anymore"); } - public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp, - boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing, Logger logger) - throws java.io.IOException { - Parser parser = new Parser(createBuilder(modelUnAnnotatedMembers, logger).build()); - ReadableArchiveScannerAdapter scannerAdapter = new ReadableArchiveScannerAdapter(parser, source); - DeploymentSpan mainScanSpan = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, source.getName()); - return processParsing(source, skipScanExternalLibProp, tracing, parser, scannerAdapter, mainScanSpan); - } - - public Parser processParsing(ReadableArchive source, boolean skipScanExternalLibProp, - StructuredDeploymentTracing tracing, Parser parser, - ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan) - throws IOException { - try { - parser.parse(scannerAdapter, () -> mainScanSpan.close()); - for (ReadableArchive externalLibArchive : getExternalLibraries(source, skipScanExternalLibProp)) { - ReadableArchiveScannerAdapter libAdapter = null; - try { - DeploymentSpan span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, externalLibArchive.getName()); - libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive); - parser.parse(libAdapter, () -> span.close()); - } finally { - if (libAdapter != null) { - libAdapter.close(); - } - } - } - parser.awaitTermination(); - scannerAdapter.close(); - return parser; - } catch (InterruptedException e) { - throw new IOException(e); - } - } - - public Parser processParsing(boolean skipScanExternalLibProp, - StructuredDeploymentTracing tracing, Parser parser, - ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan, - DeploymentContext deploymentContext) - throws IOException { - try { - parser.parse(scannerAdapter, () -> mainScanSpan.close()); - List externalLibraries = getExternalLibraries(skipScanExternalLibProp, deploymentContext); - for (ReadableArchive externalLibArchive : externalLibraries) { - DeploymentSpan span = tracing.startSpan(DeploymentTracing.AppStage.CLASS_SCANNING, externalLibArchive.getName()); - try (ReadableArchiveScannerAdapter libAdapter = new ReadableArchiveScannerAdapter(parser, externalLibArchive)) { - parser.parse(libAdapter, () -> span.close()); - } - } - parser.awaitTermination(); - for(ReadableArchive externalLibArchive: externalLibraries) { - externalLibArchive.close(); - } - return parser; - } catch (InterruptedException | java.net.URISyntaxException e) { - throw new IOException(e); - } - } - - public ParsingContext.Builder createBuilder(boolean modelUnAnnotatedMembers, Logger logger) { - ResourceLocator locator = determineLocator(); - // scan the jar and store the result in the deployment context. - ParsingContext.Builder parsingContextBuilder = new ParsingContext.Builder() - .logger(logger) - .executorService(executorService.getUnderlyingExecutorService()) - .config(new ParsingConfig() { - @Override - public Set getAnnotationsOfInterest() { - return Collections.emptySet(); - } - - @Override - public Set getTypesOfInterest() { - return Collections.emptySet(); - } - - @Override - public boolean modelUnAnnotatedMembers() { - return modelUnAnnotatedMembers; - } - }); - // workaround bug in Builder - parsingContextBuilder.locator(locator); - return parsingContextBuilder; - } - - - - private ResourceLocator determineLocator() { - if (CommonModelRegistry.getInstance().canLoadResources()) { - // common model registry will handle our external class dependencies - return null; - } - return new ClassloaderResourceLocatorAdapter(commonClassLoaderService.getCommonClassLoader()); - } - - private void transformApplication(ExtendedDeploymentContext context, Types types, + private void transformApplication(ExtendedDeploymentContext context, StructuredDeploymentTracing tracing, SpanSequence span) throws IOException { String transformNS = System.getProperty("fish.payara.deployment.transform.namespace"); @@ -817,11 +687,9 @@ private void transformApplication(ExtendedDeploymentContext context, Types types JakartaNamespaceDeploymentTransformer jakartaNamespaceDeploymentTransformerService = jakartaNamespaceDeploymentTransformerOptional.get(); - if (types == null) { - types = getDeployableTypes(context); - } + jandexIndexer.index(context); - if (!jakartaNamespaceDeploymentTransformerService.isJakartaEEApplication(types)) { + if (!jandexIndexer.isJakartaEEApplication(context)) { context.getSource().close(); // DeploymentException will be thrown here if this fails @@ -830,14 +698,10 @@ private void transformApplication(ExtendedDeploymentContext context, Types types context.getAppProps().setProperty(ServerTags.EMPTY_BEANS_XML_MODE_ALL_PROP, Boolean.TRUE.toString()); context.setSource((FileArchive) archiveFactory.createArchive(output)); - // reset transient and module data of original deployed archive - context.removeTransientAppMetaData(Types.class.getName()); - context.removeTransientAppMetaData(Parser.class.getName()); context.resetModuleMetaData(); tracing.register(context); - // Rescan for the data we just removed - getDeployableTypes(context); + jandexIndexer.reindex(context); } span.finish(); } @@ -857,45 +721,6 @@ private void notifyLifecycleInterceptorsAfter(final ExtendedDeploymentContext.Ph } } - private List getExternalLibraries(ReadableArchive source, Boolean skipScanExternalLibProp) throws IOException { - List externalLibArchives = new ArrayList<>(); - - if (skipScanExternalLibProp) { - // if we skip scanning external libraries, we should just - // return an empty list here - return Collections.emptyList(); - } - - List externalLibs = DeploymentUtils.getExternalLibraries(source); - for (URI externalLib : externalLibs) { - externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); - } - - return externalLibArchives; - } - - private List getExternalLibraries(Boolean skipScanExternalLibProp, - DeploymentContext deploymentContext) - throws IOException, URISyntaxException { - List externalLibArchives = new ArrayList<>(); - - if (skipScanExternalLibProp) { - // if we skip scanning external libraries, we should just - // return an empty list here - return Collections.emptyList(); - } - - for(URI externalLib : DeploymentUtils.getExternalLibraries(deploymentContext.getSource())) { - externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); - } - - for (URI externalLib : deploymentContext.getAppLibs()) { - externalLibArchives.add(archiveFactory.openArchive(new File(externalLib.getPath()))); - } - - return externalLibArchives; - } - /** * Suspends this application. * @@ -2712,4 +2537,40 @@ public Thread newThread(Runnable r) { public ExtendedDeploymentContext getCurrentDeploymentContext() { return DeploymentUtils.getCurrentDeploymentContext(); } + + @Deprecated(forRemoval = true) + public ParsingContext.Builder createBuilder(boolean modelUnAnnotatedMembers, Logger logger) { + throw new UnsupportedOperationException("Deprecated"); + } + + @Deprecated(forRemoval = true) + public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp, + boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing, + Logger logger, DeploymentContext deploymentContext) throws IOException { + throw new UnsupportedOperationException("Deprecated"); + } + + @Deprecated(forRemoval = true) + public Parser getDeployableParser(ReadableArchive source, boolean skipScanExternalLibProp, + boolean modelUnAnnotatedMembers, StructuredDeploymentTracing tracing, Logger logger) + throws IOException { + throw new UnsupportedOperationException("Deprecated"); + } + + @Deprecated(forRemoval = true) + public Parser processParsing(ReadableArchive source, boolean skipScanExternalLibProp, + StructuredDeploymentTracing tracing, Parser parser, + ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan) + throws IOException { + throw new UnsupportedOperationException("Deprecated"); + } + + @Deprecated(forRemoval = true) + public Parser processParsing(boolean skipScanExternalLibProp, + StructuredDeploymentTracing tracing, Parser parser, + ReadableArchiveScannerAdapter scannerAdapter, DeploymentSpan mainScanSpan, + DeploymentContext deploymentContext) + throws IOException { + throw new UnsupportedOperationException("Deprecated"); + } } diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassloaderResourceLocatorAdapter.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassloaderResourceLocatorAdapter.java deleted file mode 100644 index 1c268f32125..00000000000 --- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/ClassloaderResourceLocatorAdapter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright (c) [2019] Payara Foundation and/or its affiliates. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://github.com/payara/Payara/blob/main/LICENSE.txt - * See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at glassfish/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * The Payara Foundation designates this particular file as subject to the "Classpath" - * exception as provided by the Payara Foundation in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. - */ - -package com.sun.enterprise.v3.server; - -import org.glassfish.hk2.classmodel.reflect.util.ResourceLocator; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.stream.Stream; - -class ClassloaderResourceLocatorAdapter implements ResourceLocator { - private static String[] BLACKLIST = {"java/","com/sun"}; - - private ClassLoader delegate; - - ClassloaderResourceLocatorAdapter(ClassLoader delegate) { - this.delegate = delegate; - } - - @Override - public InputStream openResourceStream(String name) throws IOException { - return isAllowed(name) ? delegate.getResourceAsStream(name) : null; - } - - @Override - public URL getResource(String name) { - return isAllowed(name) ? delegate.getResource(name) : null; - } - - private static boolean isAllowed(String name) { - return Stream.of(BLACKLIST).noneMatch(p -> name.startsWith(p)); - } -} diff --git a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java index 1889421068f..4449b2e2688 100644 --- a/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java +++ b/nucleus/core/kernel/src/main/java/com/sun/enterprise/v3/server/SnifferManagerImpl.java @@ -42,8 +42,9 @@ package com.sun.enterprise.v3.server; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.*; import jakarta.inject.Inject; +import org.glassfish.hk2.classmodel.reflect.Types; +import org.glassfish.internal.deployment.JandexIndexer; import org.jvnet.hk2.annotations.Service; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.container.Sniffer; @@ -75,6 +76,8 @@ public class SnifferManagerImpl implements SnifferManager { @Inject protected ServiceLocator habitat; + @Inject + JandexIndexer jandexIndexer; /** * Returns all the presently registered sniffers @@ -132,17 +135,16 @@ public Collection getSniffers(DeploymentContext context) { ReadableArchive archive = context.getSource(); ArchiveHandler handler = context.getArchiveHandler(); List uris = handler.getClassPathURIs(archive); - Types types = context.getTransientAppMetaData(Types.class.getName(), Types.class); - return getSniffers(context, uris, types); + return getSniffers(context, uris, null); } - public Collection getSniffers(DeploymentContext context, List uris, Types types) { + public Collection getSniffers(DeploymentContext context, List uris, @Deprecated Types types) { // it is important to keep an ordered sequence here to keep sniffers Collection regularSniffers = getSniffers(); // in their natural order. // scan for registered annotations and retrieve applicable sniffers - List appSniffers = this.getApplicableSniffers(context, uris, types, regularSniffers, true); + List appSniffers = this.getApplicableSniffers(context, uris, regularSniffers); // call handles method of the sniffers for (Sniffer sniffer : regularSniffers) { @@ -153,7 +155,7 @@ public Collection getSniffers(DeploymentContext context, List uris return appSniffers; } - private List getApplicableSniffers(DeploymentContext context, List uris, Types types, Collection sniffers, boolean checkPath) { + private List getApplicableSniffers(DeploymentContext context, List uris, Collection sniffers) { ArchiveType archiveType = habitat.getService(ArchiveType.class, context.getArchiveHandler().getArchiveType()); if (sniffers == null || sniffers.isEmpty()) { @@ -166,37 +168,8 @@ private List getApplicableSniffers(DeploymentContext cont continue; } String[] annotationNames = sniffer.getAnnotationNames(context); - if (annotationNames == null || types == null) { - continue; - } - for (String annotationName : annotationNames) { - types.getAllTypes().stream() - .filter(type -> type instanceof AnnotationType && type.getName().equals(annotationName)) - .findFirst().ifPresent(type -> { - Collection elements = ((AnnotationType) type).allAnnotatedTypes(); - for (AnnotatedElement element : elements) { - if (checkPath) { - Type t; - if (element instanceof Member) { - t = ((Member) element).getDeclaringType(); - } else if (element instanceof Type) { - t = (Type) element; - } else if (element instanceof ParameterizedType) { - t = ((ParameterizedType) element).getType(); - } else { - LOGGER.log(Level.WARNING, "Unrecognised type: {0}.", element); - continue; - } - if (t.wasDefinedIn(uris)) { - result.add(sniffer); - break; - } - } else { - result.add(sniffer); - break; - } - } - }); + if (annotationNames != null && jandexIndexer.hasAnyAnnotations(context, uris, annotationNames)) { + result.add(sniffer); } } return result; 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 dde28643747..e4e628490d0 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 @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2022] Payara Foundation and/or affiliates +// Portions Copyright [2022-2025] Payara Foundation and/or affiliates package com.sun.enterprise.deployment.deploy.shared; @@ -51,6 +51,7 @@ import java.io.*; import org.glassfish.hk2.utilities.CleanerFactory; import java.util.*; +import java.util.concurrent.atomic.LongAccumulator; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarInputStream; @@ -780,5 +781,11 @@ private void populateEntries() { e = null; } } -} + @Override + public long getArchiveCrc() { + LongAccumulator checksum = new LongAccumulator(Long::sum, 0); + jarFile.entries().asIterator().forEachRemaining(entry -> checksum.accumulate(entry.getCrc())); + return checksum.get(); + } +} 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 a7635c71f2d..483b6609e50 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 @@ -37,6 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ +// Portions Copyright [2025] Payara Foundation and/or affiliates package com.sun.enterprise.deployment.deploy.shared; @@ -44,11 +45,12 @@ import java.net.URI; import org.glassfish.api.deployment.archive.Archive; import org.glassfish.api.deployment.archive.ReadableArchive; +import org.glassfish.hk2.classmodel.reflect.Parser; +import org.glassfish.hk2.classmodel.reflect.Types; import java.util.Enumeration; import java.util.Vector; import java.util.Map; import java.util.HashMap; -import java.util.zip.ZipEntry; import java.util.jar.JarEntry; import java.io.IOException; @@ -166,14 +168,23 @@ public ReadableArchive getParentArchive() { * type dataType registered. */ public synchronized U getExtraData(Class dataType) { + if (dataType == Types.class || dataType == Parser.class) { + throw new IllegalArgumentException("Cannot set Types or Parser as extra data - Deprecated"); + } return dataType.cast(extraData.get(dataType)); } public synchronized void setExtraData(Class dataType, U instance) { + if (dataType == Types.class || dataType == Parser.class) { + throw new IllegalArgumentException("Cannot set Types or Parser as extra data - Deprecated"); + } extraData.put(dataType, instance); } public synchronized void removeExtraData(Class dataType) { + if (dataType == Types.class || dataType == Parser.class) { + throw new IllegalArgumentException("Cannot set Types or Parser as extra data - Deprecated"); + } extraData.remove(dataType); } @@ -194,4 +205,8 @@ public T getArchiveMetaData(String metaDataKey, Class metadataType) { public void removeArchiveMetaData(String metaDataKey) { archiveMetaData.remove(metaDataKey); } + + public long getArchiveCrc() { + throw new UnsupportedOperationException("Not Supported"); + } } 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 573f185fa7a..8b6b4e8cda6 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 @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2019-2024] Payara Foundation and/or affiliates +// Portions Copyright [2019-2025] Payara Foundation and/or affiliates package org.glassfish.deployment.common; @@ -51,12 +51,16 @@ import org.glassfish.api.deployment.archive.ReadableArchive; import org.glassfish.api.deployment.archive.ArchiveHandler; import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.hk2.classmodel.reflect.Parser; +import org.glassfish.hk2.classmodel.reflect.Types; import org.glassfish.internal.api.ClassLoaderHierarchy; import org.glassfish.internal.deployment.*; import org.glassfish.loader.util.ASClassLoaderUtil; import java.lang.ref.WeakReference; import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.logging.Logger; import java.io.File; import java.io.IOException; @@ -76,8 +80,6 @@ import static java.util.logging.Level.FINEST; import org.glassfish.api.deployment.DeployCommandParameters; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.Parser; -import org.glassfish.hk2.classmodel.reflect.Types; import org.glassfish.internal.api.Globals; import org.glassfish.logging.annotation.LoggerInfo; @@ -118,7 +120,49 @@ public class DeploymentContextImpl implements ExtendedDeploymentContext, PreDest Phase phase = Phase.UNKNOWN; WeakReference sharableTemp = null; Map modulePropsMap = new HashMap(); - Map transientAppMetaData = new HashMap(); + Map transientAppMetaData = new HashMap<>() { + @Override + public Object get(Object key) { + check(key); + return super.get(key); + } + + @Override + public Object put(String key, Object value) { + check(key); + return super.put(key, value); + } + + @Override + public Object putIfAbsent(String key, Object value) { + check(key); + return super.putIfAbsent(key, value); + } + + @Override + public Object compute(String key, BiFunction remappingFunction) { + check(key); + return super.compute(key, remappingFunction); + } + + @Override + public Object computeIfAbsent(String key, Function mappingFunction) { + check(key); + return super.computeIfAbsent(key, mappingFunction); + } + + @Override + public Object computeIfPresent(String key, BiFunction remappingFunction) { + check(key); + return super.computeIfPresent(key, remappingFunction); + } + + private void check(Object key) { + if (key.equals(Types.class.getName()) || key.equals(Parser.class.getName())) { + throw new IllegalArgumentException("Cannot access " + key + " in transient metadata"); + } + } + }; Map moduleArchiveHandlers = new HashMap(); Map moduleDeploymentContexts = new HashMap(); ExtendedDeploymentContext parentContext = null; @@ -724,11 +768,6 @@ public void postDeployClean(boolean isFinalClean) { if (isFinalClean) { transientAppMetaData.clear(); } else { - final String [] classNamesToClean = {Types.class.getName(), Parser.class.getName()}; - - for (String className : classNamesToClean) { - transientAppMetaData.remove(className); - } com.sun.enterprise.deploy.shared.FileArchive.clearCache(); } } 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 ae86f5d23fd..c510ad228d6 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 @@ -37,7 +37,7 @@ * only if the new code is made subject to such option by the copyright * holder. */ -// Portions Copyright [2018-2024] Payara Foundation and/or affiliates +// Portions Copyright [2018-2025] Payara Foundation and/or affiliates package org.glassfish.deployment.common; @@ -54,7 +54,6 @@ import fish.payara.enterprise.config.serverbeans.DeploymentGroup; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.hk2.api.ServiceLocator; -import org.glassfish.hk2.classmodel.reflect.Type; import org.glassfish.internal.deployment.ExtendedDeploymentContext; import org.glassfish.loader.util.ASClassLoaderUtil; @@ -85,6 +84,7 @@ import org.glassfish.logging.annotation.LogMessageInfo; +import static org.glassfish.internal.deployment.JandexIndexer.Index; /** * Utility methods for deployment. @@ -117,19 +117,19 @@ public class DeploymentUtils { public static class WarLibraryDescriptor { private final Descriptor descriptor; - private final List types; + private final Index index; - public WarLibraryDescriptor(Descriptor descriptor, List types) { + public WarLibraryDescriptor(Descriptor descriptor, Index index) { this.descriptor = descriptor; - this.types = types; + this.index = index; } public Descriptor getDescriptor() { return descriptor; } - public List getTypes() { - return types; + public Index getIndex() { + return index; } } diff --git a/pom.xml b/pom.xml index 8e543487d17..ed4b5b6a1bc 100644 --- a/pom.xml +++ b/pom.xml @@ -287,6 +287,7 @@ 2.19.0 3.1.10.payara-p1 3.0.2 + 3.3.1 8.0.1.Final.payara-p1 8.0.1.Final 4.0.2