From d866838154a5a67f2606f3f22fb6146269a152ed Mon Sep 17 00:00:00 2001 From: Nathan Rauh Date: Wed, 26 Feb 2025 08:30:01 -0600 Subject: [PATCH] Issue #30638 include QueryInfo init failures in introspector output --- .../internal/persistence/DataProvider.java | 11 ++++++++-- .../data/internal/persistence/QueryInfo.java | 22 ++++++++++++++++++- .../internal/persistence/RepositoryImpl.java | 12 ++++++++++ .../persistence/cdi/RepositoryProducer.java | 20 ++++++++++++++--- .../data/errpaths/DataIntrospectorTest.java | 9 ++++++++ 5 files changed, 68 insertions(+), 6 deletions(-) diff --git a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/DataProvider.java b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/DataProvider.java index 2fae99d3f78b..b6a056a232ec 100644 --- a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/DataProvider.java +++ b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/DataProvider.java @@ -28,6 +28,7 @@ import java.util.Optional; import java.util.Queue; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -519,6 +520,7 @@ public void initialize(ComponentMetaData metadata) throws IllegalStateException */ @Override public void introspect(PrintWriter writer) { + List> repositoryImpls = new ArrayList<>(); Set queryInfos = new LinkedHashSet<>(); Set builders = new LinkedHashSet<>(); @@ -555,7 +557,7 @@ public void introspect(PrintWriter writer) { repositoryProducers.forEach((appName, producers) -> { writer.println(" for application " + appName); for (RepositoryProducer producer : producers) { - queryInfos.addAll(producer.introspect(writer, " ")); + queryInfos.addAll(producer.introspect(writer, " ", repositoryImpls)); writer.println(); } }); @@ -604,7 +606,12 @@ else if (entityInfoFuture.isDone()) writer.println("Query Information:"); for (List queryInfoList : queryInfoPerEntity.values()) for (QueryInfo queryInfo : queryInfoList) { - queryInfo.introspect(writer, " "); + CompletableFuture future = null; + for (RepositoryImpl r : repositoryImpls) + if ((future = r.getQueryFuture(queryInfo.method)) != null) + break; + + queryInfo.introspect(writer, " ", future); writer.println(); } } diff --git a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/QueryInfo.java b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/QueryInfo.java index 2cd9191cb30e..fbcfe5f66607 100644 --- a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/QueryInfo.java +++ b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/QueryInfo.java @@ -4648,9 +4648,13 @@ else if (Iterator.class.equals(multiType)) * * @param writer writes to the introspection file. * @param indent indentation for lines. + * @param future future for this QueryInfo. */ + @FFDCIgnore(Throwable.class) @Trivial - public void introspect(PrintWriter writer, String indent) { + public void introspect(PrintWriter writer, + String indent, + CompletableFuture future) { writer.println(indent + "QueryInfo@" + Integer.toHexString(hashCode())); indent = indent + " "; writer.println(indent + "entity: " + entityInfo); @@ -4722,6 +4726,22 @@ else if (sortPositions == NONE_STATIC_SORT_ONLY) writer.println(indent + "validate method parameters? " + validateParams); writer.println(indent + "validate method result? " + validateResult); + + if (future != null) { + writer.print(indent + "state: "); + if (future.isCancelled()) + writer.println("cancelled"); + else if (future.isDone()) + try { + future.join(); + writer.println("completed"); + } catch (Throwable x) { + writer.println("failed"); + Util.printStackTrace(x, writer, indent + " ", null); + } + else + writer.println("not completed"); + } } /** diff --git a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/RepositoryImpl.java b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/RepositoryImpl.java index dffeb692dc83..c75bb32b205c 100644 --- a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/RepositoryImpl.java +++ b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/RepositoryImpl.java @@ -350,6 +350,18 @@ private static final String getName(Parameter param, int index) { : ("(" + (index + 1) + ")"); } + /** + * Used during introspection to report errors that occurred when processing + * repository methods. + * + * @param method repository method. + * @return future for the QueryInfo. + */ + @Trivial + public final CompletableFuture getQueryFuture(Method method) { + return queries.get(method); + } + /** * Request an instance of a resource of the specified type. * diff --git a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/cdi/RepositoryProducer.java b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/cdi/RepositoryProducer.java index 5c903556905c..6234d4139826 100644 --- a/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/cdi/RepositoryProducer.java +++ b/dev/io.openliberty.data.internal.persistence/src/io/openliberty/data/internal/persistence/cdi/RepositoryProducer.java @@ -23,6 +23,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; import com.ibm.websphere.ras.Tr; import com.ibm.websphere.ras.TraceComponent; @@ -67,6 +68,8 @@ public class RepositoryProducer implements Producer, ProducerFactory, B private final Class primaryEntityClass; private final DataProvider provider; private final Map, List> queriesPerEntityClass; + private final AtomicReference> repositoryImplRef = // + new AtomicReference<>(); // most recently created instance private final Class repositoryInterface; RepositoryProducer(Class repositoryInterface, BeanManager beanMgr, DataProvider provider, DataExtension extension, @@ -96,6 +99,7 @@ public void dispose(R repository) { repository = r; RepositoryImpl handler = (RepositoryImpl) Proxy.getInvocationHandler(repository); + repositoryImplRef.compareAndSet(handler, null); handler.beanDisposed(); } @@ -139,12 +143,20 @@ public Set getTypes() { * Write information about this instance to the introspection file for * Jakarta Data. * - * @param writer writes to the introspection file. - * @param indent indentation for lines. + * @param writer writes to the introspection file. + * @param indent indentation for lines. + * @param repositoryImpls list to populate with a RepositoryImpl that is produced + * by this producer. * @return list of QueryInfo for the caller to log. */ @Trivial - public List introspect(PrintWriter writer, String indent) { + public List introspect(PrintWriter writer, + String indent, + List> repositoryImpls) { + RepositoryImpl repositoryImpl = repositoryImplRef.get(); + if (repositoryImpl != null) + repositoryImpls.add(repositoryImpl); + List queryInfos = new ArrayList<>(); writer.println(indent + "RepositoryProducer@" + Integer.toHexString(hashCode())); @@ -232,6 +244,8 @@ public R produce(CreationalContext cc) { instance = r; } + repositoryImplRef.set(handler); + if (trace && tc.isEntryEnabled()) Tr.exit(this, tc, "produce", instance.toString()); return instance; diff --git a/dev/io.openliberty.data.internal_fat_errorpaths/fat/src/test/jakarta/data/errpaths/DataIntrospectorTest.java b/dev/io.openliberty.data.internal_fat_errorpaths/fat/src/test/jakarta/data/errpaths/DataIntrospectorTest.java index af4a95cb9349..23ee304a648a 100644 --- a/dev/io.openliberty.data.internal_fat_errorpaths/fat/src/test/jakarta/data/errpaths/DataIntrospectorTest.java +++ b/dev/io.openliberty.data.internal_fat_errorpaths/fat/src/test/jakarta/data/errpaths/DataIntrospectorTest.java @@ -199,6 +199,15 @@ public void testOutputContainsPrimaryEntity() { assertLineFound(" primary entity: test.jakarta.data.errpaths.web.Voter"); } + /** + * Verify that introspector output contains the a failure that occurred when + * attempting to initialize query information for a repository method. + */ + @Test + public void testOutputContainsQueryInfoInitFailure() { + assertLineContains("java.lang.UnsupportedOperationException: CWWKD1003E:"); + } + /** * Verify that introspector output contains method signatures from an * application-supplied record entity.