diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java index c765958..0552f44 100644 --- a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java +++ b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/JasperReportsProcessor.java @@ -18,16 +18,20 @@ import org.apache.commons.lang3.StringUtils; -import io.quarkiverse.jasperreports.Constants; -import io.quarkiverse.jasperreports.deployment.config.ReportConfig; +import io.quarkiverse.jasperreports.JasperReportsBeanProducer; +import io.quarkiverse.jasperreports.JasperReportsRecorder; +import io.quarkiverse.jasperreports.config.Constants; +import io.quarkiverse.jasperreports.config.ReportBuildTimeConfig; import io.quarkiverse.jasperreports.deployment.item.CompiledReportFileBuildItem; import io.quarkiverse.jasperreports.deployment.item.ReportFileBuildItem; import io.quarkiverse.jasperreports.deployment.item.ReportRootBuildItem; -import io.quarkiverse.jasperreports.repository.ReadOnlyStreamingService; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; +import io.quarkus.arc.deployment.BeanContainerBuildItem; import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.CombinedIndexBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.GeneratedClassBuildItem; @@ -397,7 +401,7 @@ void registerFonts(BuildProducer nativeIma * Otherwise, it returns the default source path defined in ReportConfig. */ @BuildStep - ReportRootBuildItem defaultReportRoot(ReportConfig config) { + ReportRootBuildItem defaultReportRoot(ReportBuildTimeConfig config) { if (config.build().enable()) { return new ReportRootBuildItem(config.build().source().toString()); } @@ -495,7 +499,7 @@ void watchReportFiles(BuildProducer watchedPa * @param outputTarget The OutputTargetBuildItem containing information about the build output directory. */ @BuildStep - void compileReports(ReportConfig config, List reportFiles, + void compileReports(ReportBuildTimeConfig config, List reportFiles, BuildProducer compiledReportProducer, BuildProducer compiledReportFileProducer, OutputTargetBuildItem outputTarget) { @@ -548,9 +552,28 @@ void compileReports(ReportConfig config, List reportFiles, } } + /** + * Registers the JasperReportsBeanProducer as an unremovable bean. + * + * @return An AdditionalBeanBuildItem for the JasperReportsBeanProducer. + */ + @BuildStep + AdditionalBeanBuildItem registerBeanProducer() { + return AdditionalBeanBuildItem.unremovableOf(JasperReportsBeanProducer.class); + } + + /** + * Initializes the JasperReports producer at runtime. + * + * @param recorder The JasperReportsRecorder to use for initialization. + * @param beanContainer The BeanContainerBuildItem containing the bean container. + * @param config The ReportBuildTimeConfig to use for initialization. + */ @BuildStep - AdditionalBeanBuildItem additionalBeans() { - return AdditionalBeanBuildItem.unremovableOf(ReadOnlyStreamingService.class); + @Record(ExecutionTime.RUNTIME_INIT) + void initializeBeanProducer(JasperReportsRecorder recorder, BeanContainerBuildItem beanContainer, + ReportBuildTimeConfig config) { + recorder.initProducer(beanContainer.getValue(), config); } /** @@ -569,4 +592,4 @@ static Path findProjectRoot(Path outputDirectory, Path startDirectory) { return startDirectory; } } -} +} \ No newline at end of file diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/item/AbstractReportFileBuildItem.java b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/item/AbstractReportFileBuildItem.java index a4b3189..f01a508 100644 --- a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/item/AbstractReportFileBuildItem.java +++ b/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/item/AbstractReportFileBuildItem.java @@ -1,9 +1,9 @@ package io.quarkiverse.jasperreports.deployment.item; -import static io.quarkiverse.jasperreports.Constants.EXT_COMPILED; -import static io.quarkiverse.jasperreports.Constants.EXT_DATA_ADAPTER; -import static io.quarkiverse.jasperreports.Constants.EXT_REPORT; -import static io.quarkiverse.jasperreports.Constants.EXT_STYLE; +import static io.quarkiverse.jasperreports.config.Constants.EXT_COMPILED; +import static io.quarkiverse.jasperreports.config.Constants.EXT_DATA_ADAPTER; +import static io.quarkiverse.jasperreports.config.Constants.EXT_REPORT; +import static io.quarkiverse.jasperreports.config.Constants.EXT_STYLE; import java.nio.file.Path; import java.util.List; @@ -50,4 +50,4 @@ public String getType() { }; } -} +} \ No newline at end of file diff --git a/runtime/pom.xml b/runtime/pom.xml index ef10a72..e064abf 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -30,6 +30,14 @@ org.jboss.logging commons-logging-jboss-logging + + org.bouncycastle + bcprov-jdk18on + + + org.bouncycastle + bcpkix-jdk18on + @@ -107,14 +115,6 @@ fop 2.10 - - org.bouncycastle - bcprov-jdk18on - - - org.bouncycastle - bcpkix-jdk18on - net.sf.saxon Saxon-HE diff --git a/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsBeanProducer.java b/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsBeanProducer.java new file mode 100644 index 0000000..7fe20b0 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsBeanProducer.java @@ -0,0 +1,39 @@ +package io.quarkiverse.jasperreports; + +import java.nio.file.Path; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.context.Dependent; +import jakarta.enterprise.inject.Produces; + +import io.quarkiverse.jasperreports.repository.ReadOnlyStreamingService; + +/** + * A bean producer for JasperReports-related services. + * This class is responsible for initializing and producing the ReadOnlyStreamingService. + */ +@ApplicationScoped +public class JasperReportsBeanProducer { + + private volatile Path destinationPath; + + /** + * Initializes the bean producer with the destination path for JasperReports files. + * + * @param destinationPath The path where compiled JasperReports files are located. + */ + void initialize(Path destinationPath) { + this.destinationPath = destinationPath; + } + + /** + * Produces a ReadOnlyStreamingService instance. + * + * @return A new ReadOnlyStreamingService initialized with the destination path. + */ + @Dependent + @Produces + public ReadOnlyStreamingService readOnlyStreamingService() { + return new ReadOnlyStreamingService(this.destinationPath); + } +} diff --git a/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsRecorder.java b/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsRecorder.java new file mode 100644 index 0000000..d509099 --- /dev/null +++ b/runtime/src/main/java/io/quarkiverse/jasperreports/JasperReportsRecorder.java @@ -0,0 +1,24 @@ +package io.quarkiverse.jasperreports; + +import io.quarkiverse.jasperreports.config.ReportBuildTimeConfig; +import io.quarkus.arc.runtime.BeanContainer; +import io.quarkus.runtime.annotations.Recorder; + +/** + * Recorder for JasperReports initialization. + * This class is responsible for initializing the JasperReportsBeanProducer at runtime. + */ +@Recorder +public class JasperReportsRecorder { + + /** + * Initializes the JasperReportsBeanProducer with the configured destination path. + * + * @param container The BeanContainer used to retrieve the JasperReportsBeanProducer instance. + * @param config The ReportBuildTimeConfig containing the build configuration. + */ + public void initProducer(BeanContainer container, ReportBuildTimeConfig config) { + JasperReportsBeanProducer producer = container.beanInstance(JasperReportsBeanProducer.class); + producer.initialize(config.build().destination()); + } +} diff --git a/runtime/src/main/java/io/quarkiverse/jasperreports/Constants.java b/runtime/src/main/java/io/quarkiverse/jasperreports/config/Constants.java similarity index 88% rename from runtime/src/main/java/io/quarkiverse/jasperreports/Constants.java rename to runtime/src/main/java/io/quarkiverse/jasperreports/config/Constants.java index 40905ef..49afae6 100644 --- a/runtime/src/main/java/io/quarkiverse/jasperreports/Constants.java +++ b/runtime/src/main/java/io/quarkiverse/jasperreports/config/Constants.java @@ -1,4 +1,4 @@ -package io.quarkiverse.jasperreports; +package io.quarkiverse.jasperreports.config; public interface Constants { @@ -14,4 +14,4 @@ public interface Constants { static final String DEFAULT_DEST_PATH = "jasperreports"; -} +} \ No newline at end of file diff --git a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/config/ReportConfig.java b/runtime/src/main/java/io/quarkiverse/jasperreports/config/ReportBuildTimeConfig.java similarity index 87% rename from deployment/src/main/java/io/quarkiverse/jasperreports/deployment/config/ReportConfig.java rename to runtime/src/main/java/io/quarkiverse/jasperreports/config/ReportBuildTimeConfig.java index c9a44f8..973c9eb 100644 --- a/deployment/src/main/java/io/quarkiverse/jasperreports/deployment/config/ReportConfig.java +++ b/runtime/src/main/java/io/quarkiverse/jasperreports/config/ReportBuildTimeConfig.java @@ -1,4 +1,4 @@ -package io.quarkiverse.jasperreports.deployment.config; +package io.quarkiverse.jasperreports.config; import java.nio.file.Path; @@ -8,8 +8,8 @@ import io.smallrye.config.WithDefault; @ConfigMapping(prefix = "quarkus.jasperreports") -@ConfigRoot(phase = ConfigPhase.BUILD_TIME) -public interface ReportConfig { +@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED) +public interface ReportBuildTimeConfig { String DEFAULT_SOURCE_PATH = "src/main/jasperreports"; String DEFAULT_DEST_PATH = "jasperreports"; @@ -40,4 +40,4 @@ interface BuildConfig { Path destination(); } -} +} \ No newline at end of file diff --git a/runtime/src/main/java/io/quarkiverse/jasperreports/repository/ReadOnlyStreamingService.java b/runtime/src/main/java/io/quarkiverse/jasperreports/repository/ReadOnlyStreamingService.java index 44ab5e1..b66edb7 100644 --- a/runtime/src/main/java/io/quarkiverse/jasperreports/repository/ReadOnlyStreamingService.java +++ b/runtime/src/main/java/io/quarkiverse/jasperreports/repository/ReadOnlyStreamingService.java @@ -1,22 +1,16 @@ package io.quarkiverse.jasperreports.repository; -import static io.quarkiverse.jasperreports.Constants.EXT_COMPILED; -import static io.quarkiverse.jasperreports.Constants.EXT_DATA_ADAPTER; -import static io.quarkiverse.jasperreports.Constants.EXT_STYLE; +import static io.quarkiverse.jasperreports.config.Constants.EXT_COMPILED; +import static io.quarkiverse.jasperreports.config.Constants.EXT_DATA_ADAPTER; +import static io.quarkiverse.jasperreports.config.Constants.EXT_STYLE; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; import java.util.Collections; -import java.util.Optional; -import jakarta.annotation.PostConstruct; -import jakarta.enterprise.context.Dependent; - -import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.logging.Logger; -import io.quarkiverse.jasperreports.Constants; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JasperReportsContext; import net.sf.jasperreports.engine.SimpleJasperReportsContext; @@ -31,73 +25,116 @@ import net.sf.jasperreports.repo.SimpleRepositoryContext; import net.sf.jasperreports.repo.StreamRepositoryService; -@Dependent +/** + * A read-only implementation of StreamRepositoryService for JasperReports. + * This service provides access to compiled reports, styles, and data adapters + * from a specified destination path. + */ public class ReadOnlyStreamingService implements StreamRepositoryService { private static final Logger LOG = Logger.getLogger(ReadOnlyStreamingService.class); private final JasperReportsContext context = new SimpleJasperReportsContext(); - - // TODO - why is it not picking up the default value from ReportConfig??? - @ConfigProperty(name = "quarkus.jasperreports.build.destination", defaultValue = Constants.DEFAULT_DEST_PATH) - Optional reportPathConfig; - - @PostConstruct - public void onInit() { - ((SimpleJasperReportsContext) context).setExtensions(RepositoryService.class, Collections.singletonList(this)); - ((SimpleJasperReportsContext) context).setExtensions(PersistenceServiceFactory.class, + private final Path destinationPath; + + /** + * Constructs a new ReadOnlyStreamingService with the specified destination path. + * + * @param destinationPath The path where compiled reports and styles are located. + */ + public ReadOnlyStreamingService(Path destinationPath) { + this.destinationPath = destinationPath; + SimpleJasperReportsContext simpleContext = ((SimpleJasperReportsContext) context); + simpleContext.setExtensions(RepositoryService.class, Collections.singletonList(this)); + simpleContext.setExtensions(PersistenceServiceFactory.class, Collections.singletonList(FileRepositoryPersistenceServiceFactory.getInstance())); } + /** + * Returns the JasperReportsContext associated with this service. + * + * @return The JasperReportsContext instance. + */ public JasperReportsContext getContext() { return context; } + /** + * Retrieves an InputStream for the specified URI. + * This method handles compiled reports, styles, and data adapters. + * + * @param uri The URI of the resource to retrieve. + * @return An InputStream for the requested resource, or null if not found. + */ @Override public InputStream getInputStream(String uri) { - InputStream is = null; + String logType = null; + String filePath = uri; if (uri.endsWith(EXT_COMPILED) || uri.endsWith(EXT_STYLE)) { - final Path reportPath = Path.of(reportPathConfig.get().toString(), uri); - final String reportFile = reportPath.toString(); - - try { - LOG.debugf("Loading %s file %s", (uri.endsWith(EXT_COMPILED) ? "report" : "style"), reportFile); - - return JRLoader.getLocationInputStream(reportFile); - } catch (JRException ex) { - LOG.warnf("Failed to load %s - %s", (uri.endsWith(EXT_COMPILED) ? "report" : "style"), ex.getMessage()); - LOG.debug(ex); - } + logType = uri.endsWith(EXT_COMPILED) ? "report" : "style"; + filePath = Path.of(this.destinationPath.toString(), uri).toString(); } else if (uri.endsWith(EXT_DATA_ADAPTER)) { - try { - LOG.debugf("Loading data adapter file %s", uri); + logType = "data adapter"; + } - return JRLoader.getLocationInputStream(uri); + if (logType != null) { + try { + LOG.debugf("Loading %s file %s", logType, filePath); + return JRLoader.getLocationInputStream(filePath); } catch (JRException ex) { - LOG.warnf("Failed to load data adapter - %s", ex.getMessage()); + LOG.warnf("Failed to load %s - %s", logType, ex.getMessage()); LOG.debug(ex); } } - return is; + return null; } + /** + * This method is not supported in this read-only implementation. + * + * @param uri The URI of the resource. + * @return This method always throws an IllegalStateException. + * @throws IllegalStateException Always thrown as this repository is read-only. + */ @Override public OutputStream getOutputStream(String uri) { throw new IllegalStateException("This repository is read only"); } + /** + * This method is not supported in this implementation. + * + * @param uri The URI of the resource. + * @return This method always throws an IllegalStateException. + * @throws IllegalStateException Always thrown as this method is not supported. + */ @Override public Resource getResource(String uri) { throw new IllegalStateException("Can only return an InputStream"); } + /** + * This method is not supported in this read-only implementation. + * + * @param uri The URI of the resource. + * @param resource The resource to save. + * @throws IllegalStateException Always thrown as this repository is read-only. + */ @Override public void saveResource(String uri, Resource resource) { throw new IllegalStateException("This repository is read only"); } + /** + * Retrieves a resource of the specified type for the given URI. + * + * @param The type of resource to retrieve. + * @param uri The URI of the resource. + * @param resourceType The class of the resource type. + * @return The requested resource, or null if not found or if no appropriate PersistenceService is available. + */ @Override @SuppressWarnings("unchecked") public T getResource(String uri, Class resourceType) { @@ -112,4 +149,4 @@ public T getResource(String uri, Class resourceType) { return null; } -} +} \ No newline at end of file