Skip to content

Commit

Permalink
Integration for Quarkus 3.x. Fixes #564
Browse files Browse the repository at this point in the history
(cherry picked from commit 62a886a)
  • Loading branch information
Rudy De Busscher authored and zdenek-jonas committed May 19, 2023
1 parent 39e5440 commit 96391f4
Show file tree
Hide file tree
Showing 34 changed files with 2,086 additions and 0 deletions.
11 changes: 11 additions & 0 deletions docs/modules/misc/pages/integrations/quarkus.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ mvn quarkus:add-extension -Dextensions="one.microstream:microstream-quarkus-exte

The extension requires Quarkus 2.11.1 as a minimal version.

The integration requires Spring Boot 2.x (with version 2.1.0.RELEASE being the minimal supported one).

If you are running Quarkus 3, use the following dependency in your project:

[source, shell, title="Add Quarkus 3 extension", subs=attributes+]
----
mvn quarkus:add-extension -Dextensions="one.microstream:microstream-quarkus3-extension:09.00.00-MS-GA"
----

The migration from version 2 to 3 doesn't require any code changes related to the MicroStream integration classes.

== Configuration

The configuration of the _StorageManager_ can be done using key/value pairs that are provided by Quarkus configuration. The configuration keys must be prefixed by `one.microstream`
Expand Down
1 change: 1 addition & 0 deletions integrations/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<module>cdi3</module>
<module>spring-boot</module>
<module>quarkus</module>
<module>quarkus3</module>
</modules>

<profiles>
Expand Down
64 changes: 64 additions & 0 deletions integrations/quarkus3/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>one.microstream</groupId>
<artifactId>microstream-integrations-quarkus3-parent</artifactId>
<version>09.00.00-MS-GA-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>microstream-quarkus3-extension-deployment</artifactId>
<name>MicroStream Quarkus 3 Extension - Deployment</name>
<url>https://microstream.one</url>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>one.microstream</groupId>
<artifactId>microstream-quarkus3-extension</artifactId>
<version>09.00.00-MS-GA-SNAPSHOT</version>
</dependency>

<!-- test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package one.microstream.integrations.quarkus.deployment;

/*-
* #%L
* MicroStream Quarkus 3 Extension - Deployment
* %%
* Copyright (C) 2019 - 2023 MicroStream Software
* %%
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
* #L%
*/


import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import one.microstream.integrations.quarkus.types.Storage;
import one.microstream.integrations.quarkus.types.impl.BeanCreatorParameterNames;
import one.microstream.integrations.quarkus.types.impl.RootCreator;
import one.microstream.integrations.quarkus.types.impl.StorageBean;
import one.microstream.integrations.quarkus.types.impl.StorageBeanCreator;
import one.microstream.integrations.quarkus.types.impl.StorageClassInfo;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.IndexView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Quarkus extension processor to handle the {@link Storage} annotation.
*/
class MicrostreamExtensionProcessor
{

private static final Logger LOGGER = LoggerFactory.getLogger(MicrostreamExtensionProcessor.class);

private static final DotName STORAGE_ANNOTATION = DotName.createSimple(Storage.class.getName());

private static final DotName INJECT_ANNOTATION = DotName.createSimple(Inject.class.getName());

private static final String FEATURE = "microstream-extension";

@BuildStep
FeatureBuildItem feature()
{
return new FeatureBuildItem(FEATURE);
}

@BuildStep
StorageBeanBuildItem findStorageRoot(final BeanArchiveIndexBuildItem beanArchiveIndex)
{
LOGGER.debug("BuildStep for MicroStream: Find any class that is annotated with @Storage");
final Set<StorageClassInfo> rootClasses = findAnnotatedClasses(beanArchiveIndex);
if (rootClasses.size() > 1)
{
throw new IllegalStateException(
"In the application you must have only one class with the Storage annotation, classes: "
+ rootClasses);
}
return new StorageBeanBuildItem(rootClasses.stream()
.findAny()
.orElse(null));
}

@BuildStep
SyntheticBeanBuildItem rootBean(final StorageBeanBuildItem storageBeanBuildItem)
{

final Optional<Class<?>> rootClass = storageBeanBuildItem.getRootClass();

if (rootClass.isPresent())
{
LOGGER.debug("BuildStep for MicroStream: Configure a SyntheticBeanBuildItem for the @Storage bean");
LOGGER.info(String.format("Processing Extension: @Storage found at %s", rootClass));
return SyntheticBeanBuildItem.configure(rootClass.get())
.scope(Singleton.class)
.creator(RootCreator.class)
.done();

}
else
{
// Quarkus is fine with returning null for a BuildItem instance.
return null;

}

}

@BuildStep
SyntheticBeanBuildItem storageBean(final StorageBeanBuildItem storageBeanBuildItem)
{
LOGGER.debug("BuildStep for MicroStream: Configure a SyntheticBeanBuildItem for the bean keeping info about @Storage class");

final Optional<Class<?>> rootClass = storageBeanBuildItem.getRootClass();

final String fields = String.join(",", storageBeanBuildItem.getFieldsToInject());

// .orElse is needed due to https://github.com/quarkusio/quarkus/issues/27664
return SyntheticBeanBuildItem.configure(StorageBean.class)
.scope(Singleton.class)
.creator(StorageBeanCreator.class)
.param(BeanCreatorParameterNames.CLASS_NAME, rootClass.orElse(Object.class))
.param(BeanCreatorParameterNames.FIELDS, fields)
.done();

}



private Set<StorageClassInfo> findAnnotatedClasses(final BeanArchiveIndexBuildItem beanArchiveIndex)
{
final Set<StorageClassInfo> result = new HashSet<>();
final IndexView indexView = beanArchiveIndex.getIndex();
final Collection<AnnotationInstance> storageBeans = indexView.getAnnotations(STORAGE_ANNOTATION);

for (AnnotationInstance ann : storageBeans)
{
ClassInfo beanClassInfo = ann.target()
.asClass();

result.add(createStorageBeanClassInfo(beanClassInfo));

}
return result;
}

private StorageClassInfo createStorageBeanClassInfo(final ClassInfo beanClassInfo)
{
try
{
Class<?> classReference = Class.forName(beanClassInfo.name()
.toString(), false, Thread.currentThread()
.getContextClassLoader());

List<String> fieldsToInject = beanClassInfo.fields()
.stream()
.filter(fi -> fi.hasAnnotation(INJECT_ANNOTATION))
.map(FieldInfo::name)
.collect(Collectors.toList());

return new StorageClassInfo(classReference, fieldsToInject);

} catch (ClassNotFoundException e)
{
throw new RuntimeException("Unable to load Class ", e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package one.microstream.integrations.quarkus.deployment;

/*-
* #%L
* MicroStream Quarkus 3 Extension - Deployment
* %%
* Copyright (C) 2019 - 2023 MicroStream Software
* %%
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
* #L%
*/



import io.quarkus.builder.item.SimpleBuildItem;
import one.microstream.integrations.quarkus.types.impl.StorageClassInfo;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
* {@link io.quarkus.builder.item.BuildItem} that is derived from {@link io.quarkus.arc.deployment.BeanArchiveIndexBuildItem} that keep tracks
* of the class annotated with {@link one.microstream.integrations.quarkus.types.Storage}.
*/
public final class StorageBeanBuildItem extends SimpleBuildItem
{

private final StorageClassInfo rootClassInfo;

public StorageBeanBuildItem(final StorageClassInfo rootClassInfo)
{
this.rootClassInfo = rootClassInfo;
}

/**
* Return the class where {@link one.microstream.storage.types.Storage} is defined or empty optional if
* not defined by user.
* @return Class with @Storage or empty.
*/
public Optional<Class<?>> getRootClass()
{
return Optional.ofNullable(this.rootClassInfo).map(StorageClassInfo::getClassReference);
}


/**
* Returns the names of the fields that have {@link jakarta.inject.Inject} within class annotated with
* {@link one.microstream.integrations.quarkus.types.Storage}. Empty list when no annotated placed anywhere.
* @return names of the fields to Inject or empty list if nothing to inject manually.
*/
public List<String> getFieldsToInject()
{
if (this.rootClassInfo == null) {
return Collections.emptyList();
} else {
return this.rootClassInfo.getFieldsToInject();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package one.microstream.integrations.quarkus.deployment;

/*-
* #%L
* MicroStream Quarkus 3 Extension - Deployment
* %%
* Copyright (C) 2019 - 2023 MicroStream Software
* %%
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
* #L%
*/

import java.io.File;

public class CleanupUtil
{

public static boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
}
Loading

0 comments on commit 96391f4

Please sign in to comment.