diff --git a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java
index 77791e4c28e..1555cb85eb3 100644
--- a/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java
+++ b/controller/src/main/java/org/jboss/as/controller/descriptions/ModelDescriptionConstants.java
@@ -571,6 +571,7 @@ public class ModelDescriptionConstants {
public static final String TYPE = "type";
public static final String UDP = "udp";
public static final String UNDEFINE_ATTRIBUTE_OPERATION = "undefine-attribute";
+ public static final String UNSTABLE_API_ANNOTATIONS = "unstable-api-annotations";
public static final String UNDEPLOY = "undeploy";
public static final String UNREADABLE_CHILDREN = "unreadable-children";
public static final String UPLOAD_DEPLOYMENT_BYTES = "upload-deployment-bytes";
diff --git a/core-feature-pack/common/pom.xml b/core-feature-pack/common/pom.xml
index 321811326e3..e1a7cf374cc 100644
--- a/core-feature-pack/common/pom.xml
+++ b/core-feature-pack/common/pom.xml
@@ -526,6 +526,11 @@
org.wildfly.security
wildfly-elytron-x500-principal
+
+ org.wildfly.unstable.api.annotation
+ unstable-api-annotation-classpath-indexer
+
+
org.wildfly.core
diff --git a/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/content/index.txt b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/content/index.txt
new file mode 100644
index 00000000000..917e2043049
--- /dev/null
+++ b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/content/index.txt
@@ -0,0 +1 @@
+# Comment to include file
\ No newline at end of file
diff --git a/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/module.xml b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/module.xml
new file mode 100644
index 00000000000..299b9fcde68
--- /dev/null
+++ b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main/module.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/extension/core-management/main/module.xml b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/extension/core-management/main/module.xml
index 0b1774f32d1..8c993cf72ce 100644
--- a/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/extension/core-management/main/module.xml
+++ b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/extension/core-management/main/module.xml
@@ -17,14 +17,19 @@
+
+
+
+
+
diff --git a/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/unstable/annotation/api/indexer/main/module.xml b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/unstable/annotation/api/indexer/main/module.xml
new file mode 100644
index 00000000000..6b5dcff1cf6
--- /dev/null
+++ b/core-feature-pack/common/src/main/resources/modules/system/layers/base/org/wildfly/unstable/annotation/api/indexer/main/module.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core-management/core-management-subsystem/pom.xml b/core-management/core-management-subsystem/pom.xml
index f4b1c730dac..1d8b872538c 100644
--- a/core-management/core-management-subsystem/pom.xml
+++ b/core-management/core-management-subsystem/pom.xml
@@ -80,6 +80,11 @@
true
+
+ org.wildfly.unstable.api.annotation
+ unstable-api-annotation-classpath-indexer
+
+
org.jboss.logmanager
jboss-logmanager
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementExtension.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementExtension.java
index f378dbcef4d..7e851824c3c 100644
--- a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementExtension.java
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementExtension.java
@@ -11,6 +11,7 @@
import org.jboss.as.controller.ExtensionContext;
import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.PersistentResourceXMLDescriptionWriter;
import org.jboss.as.controller.SubsystemRegistration;
import org.jboss.as.controller.descriptions.ResourceDescriptionResolver;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
@@ -18,17 +19,21 @@
import org.jboss.as.controller.parsing.ExtensionParsingContext;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import java.util.EnumSet;
+
/**
* @author Jeff Mesnil (c) 2016 Red Hat inc.
*/
public class CoreManagementExtension implements Extension {
public static final String SUBSYSTEM_NAME = "core-management";
- static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
+ public static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
static final PathElement PROCESS_STATE_LISTENER_PATH = PathElement.pathElement("process-state-listener");
static final String RESOURCE_NAME = CoreManagementExtension.class.getPackage().getName() + ".LocalDescriptions";
- private static final ModelVersion CURRENT_VERSION = ModelVersion.create(1, 0, 0);
+ static final ModelVersion VERSION_1_0_0 = ModelVersion.create(1, 0, 0);
+
+ static final ModelVersion CURRENT_VERSION = VERSION_1_0_0;
public static ResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
StringBuilder prefix = new StringBuilder(SUBSYSTEM_NAME);
@@ -44,7 +49,7 @@ public static ResourceDescriptionResolver getResourceDescriptionResolver(final S
@Override
public void initialize(ExtensionContext context) {
final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, CURRENT_VERSION);
- subsystem.registerXMLElementWriter(CoreManagementSubsystemParser_1_0::new);
+ subsystem.registerXMLElementWriter(new PersistentResourceXMLDescriptionWriter(CoreManagementSubsystemSchema_1_0.ALL.get(context.getStability())));
//This subsystem should be runnable on a host
subsystem.setHostCapable();
ManagementResourceRegistration registration = subsystem.registerSubsystemModel(new CoreManagementRootResourceDefinition());
@@ -53,8 +58,6 @@ public void initialize(ExtensionContext context) {
@Override
public void initializeParsers(ExtensionParsingContext context) {
- // For the current version we don't use a Supplier as we want its description initialized
- // TODO if any new xsd versions are added, use a Supplier for the old version
- context.setSubsystemXmlMapping(SUBSYSTEM_NAME, CoreManagementSubsystemParser_1_0.NAMESPACE, new CoreManagementSubsystemParser_1_0());
+ context.setSubsystemXmlMappings(CoreManagementExtension.SUBSYSTEM_NAME, EnumSet.allOf(CoreManagementSubsystemSchema_1_0.class));
}
}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementRootResourceDefinition.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementRootResourceDefinition.java
index 2a101f83c23..643e09658b2 100644
--- a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementRootResourceDefinition.java
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementRootResourceDefinition.java
@@ -6,15 +6,31 @@
package org.wildfly.extension.core.management;
+import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PersistentResourceDefinition;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.registry.Resource;
+import org.jboss.as.server.AbstractDeploymentChainStep;
+import org.jboss.as.server.DeploymentProcessorTarget;
+import org.jboss.dmr.ModelNode;
+import org.jboss.msc.service.ServiceBuilder;
+import org.wildfly.extension.core.management.UnstableApiAnnotationResourceDefinition.UnstableApiAnnotationLevel;
+import org.wildfly.extension.core.management.deployment.ReportUnstableApiAnnotationsProcessor;
+import org.wildfly.extension.core.management.deployment.ScanUnstableApiAnnotationsProcessor;
+
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
-import org.jboss.as.controller.AttributeDefinition;
-import org.jboss.as.controller.ModelOnlyAddStepHandler;
-import org.jboss.as.controller.PersistentResourceDefinition;
-import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import static org.jboss.as.server.deployment.Phase.PARSE;
+import static org.jboss.as.server.deployment.Phase.PARSE_REPORT_EXPERIMENTAL_ANNOTATIONS;
+import static org.jboss.as.server.deployment.Phase.PARSE_SCAN_EXPERIMENTAL_ANNOTATIONS;
+import static org.wildfly.extension.core.management.CoreManagementExtension.SUBSYSTEM_NAME;
/**
* {@link org.jboss.as.controller.ResourceDefinition} for the core-management subsystem root resource.
@@ -26,7 +42,7 @@ class CoreManagementRootResourceDefinition extends PersistentResourceDefinition
CoreManagementRootResourceDefinition() {
super(CoreManagementExtension.SUBSYSTEM_PATH,
CoreManagementExtension.getResourceDescriptionResolver(),
- ModelOnlyAddStepHandler.INSTANCE,
+ new CoreManagementAddHandler(),
ReloadRequiredRemoveStepHandler.INSTANCE);
}
@@ -38,7 +54,40 @@ public Collection getAttributes() {
@Override
protected List extends PersistentResourceDefinition> getChildren() {
return Arrays.asList(ConfigurationChangeResourceDefinition.INSTANCE,
- new ProcessStateListenerResourceDefinition()
+ new ProcessStateListenerResourceDefinition(),
+ UnstableApiAnnotationResourceDefinition.INSTANCE
);
}
+
+ private static class CoreManagementAddHandler extends AbstractBoottimeAddStepHandler {
+
+ @Override
+ protected void performBoottime(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
+
+ if (context.isNormalServer()) {
+ context.addStep(new AbstractDeploymentChainStep() {
+ @Override
+ protected void execute(DeploymentProcessorTarget processorTarget) {
+ processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME, PARSE, PARSE_SCAN_EXPERIMENTAL_ANNOTATIONS,
+ new ScanUnstableApiAnnotationsProcessor(context.getRunningMode(), context.getStability(), UnstableApiAnnotationService.LEVEL_SUPPLIER));
+ processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME, PARSE, PARSE_REPORT_EXPERIMENTAL_ANNOTATIONS,
+ new ReportUnstableApiAnnotationsProcessor(UnstableApiAnnotationService.LEVEL_SUPPLIER));
+ }
+ }, OperationContext.Stage.RUNTIME);
+ }
+
+ Resource unstableApiResource = resource.getChild(UnstableApiAnnotationResourceDefinition.PATH);
+ UnstableApiAnnotationLevel level = null;
+ if (unstableApiResource != null) {
+ ModelNode model = unstableApiResource.getModel();
+ String levelValue = UnstableApiAnnotationResourceDefinition.LEVEL.resolveModelAttribute(context, model).asString();
+ level = UnstableApiAnnotationLevel.valueOf(levelValue);
+ }
+
+ ServiceBuilder> sb = context.getCapabilityServiceTarget().addService();
+ Consumer serviceConsumer = sb.provides(UnstableApiAnnotationService.SERVICE_NAME);
+ sb.setInstance(new UnstableApiAnnotationService(serviceConsumer, level));
+ sb.install();
+ }
+ }
}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemParser_1_0.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemParser_1_0.java
deleted file mode 100644
index 5754f314900..00000000000
--- a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemParser_1_0.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright The WildFly Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package org.wildfly.extension.core.management;
-
-import static org.jboss.as.controller.PersistentResourceXMLDescription.builder;
-
-import org.jboss.as.controller.PersistentResourceXMLDescription;
-import org.jboss.as.controller.PersistentResourceXMLParser;
-
-/**
- * Parser and Marshaller for core-management's {@link #NAMESPACE}.
- *
- * All resources and attributes must be listed explicitly and not through any collections.
- * This ensures that if the resource definitions change in later version (e.g. a new attribute is added),
- * this will have no impact on parsing this specific version of the subsystem.
- *
- * @author Jeff Mesnil (c) 2016 Red Hat inc.
- */
-class CoreManagementSubsystemParser_1_0 extends PersistentResourceXMLParser {
-
- static final String NAMESPACE = "urn:jboss:domain:core-management:1.0";
-
- @Override
- public PersistentResourceXMLDescription getParserDescription() {
- return builder(CoreManagementExtension.SUBSYSTEM_PATH, NAMESPACE)
- .addChild(builder(ConfigurationChangeResourceDefinition.PATH).addAttribute(ConfigurationChangeResourceDefinition.MAX_HISTORY))
- .addChild(builder(CoreManagementExtension.PROCESS_STATE_LISTENER_PATH)
- .addAttribute(ProcessStateListenerResourceDefinition.LISTENER_CLASS)
- .addAttribute(ProcessStateListenerResourceDefinition.LISTENER_MODULE)
- .addAttribute(ProcessStateListenerResourceDefinition.PROPERTIES)
- .addAttribute(ProcessStateListenerResourceDefinition.TIMEOUT))
- .build();
- }
-}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemSchema_1_0.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemSchema_1_0.java
new file mode 100644
index 00000000000..aad63bd00ce
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/CoreManagementSubsystemSchema_1_0.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management;
+
+import org.jboss.as.controller.Feature;
+import org.jboss.as.controller.PersistentResourceXMLDescription;
+import org.jboss.as.controller.PersistentSubsystemSchema;
+import org.jboss.as.controller.SubsystemSchema;
+import org.jboss.as.controller.xml.VersionedNamespace;
+import org.jboss.as.version.Stability;
+import org.jboss.staxmapper.IntVersion;
+
+import java.util.EnumSet;
+import java.util.Map;
+
+/**
+ * Parser and Marshaller for core-management subsystem.
+ *
+ * All resources and attributes must be listed explicitly and not through any collections.
+ * This ensures that if the resource definitions change in later version (e.g. a new attribute is added),
+ * this will have no impact on parsing this specific version of the subsystem.
+ *
+ * @author Jeff Mesnil (c) 2016 Red Hat inc.
+ */
+public enum CoreManagementSubsystemSchema_1_0 implements PersistentSubsystemSchema {
+
+ VERSION_1_0(1),
+ VERSION_1_0_PREVIEW(1, Stability.PREVIEW);
+ static final Map ALL = Feature.map(EnumSet.of(VERSION_1_0, VERSION_1_0_PREVIEW));
+
+ private final VersionedNamespace namespace;
+
+ CoreManagementSubsystemSchema_1_0(int major) {
+ this.namespace = SubsystemSchema.createLegacySubsystemURN(CoreManagementExtension.SUBSYSTEM_NAME, new IntVersion(major, 0));
+ }
+
+ CoreManagementSubsystemSchema_1_0(int major, Stability stability) {
+ this.namespace = SubsystemSchema.createLegacySubsystemURN(CoreManagementExtension.SUBSYSTEM_NAME, stability, new IntVersion(major, 0));
+ }
+
+ @Override
+ public VersionedNamespace getNamespace() {
+ return this.namespace;
+ }
+
+ @Override
+ public PersistentResourceXMLDescription getXMLDescription() {
+ PersistentResourceXMLDescription.Factory factory = PersistentResourceXMLDescription.factory(this);
+ PersistentResourceXMLDescription.Builder builder = factory.builder(CoreManagementExtension.SUBSYSTEM_PATH);
+ builder.addChild(
+ factory.builder(ConfigurationChangeResourceDefinition.PATH)
+ .addAttribute(ConfigurationChangeResourceDefinition.MAX_HISTORY)
+ .build());
+ builder.addChild(
+ factory.builder(UnstableApiAnnotationResourceDefinition.RESOURCE_REGISTRATION)
+ .addAttribute(UnstableApiAnnotationResourceDefinition.LEVEL)
+ .build());
+ builder.addChild(
+ factory.builder(CoreManagementExtension.PROCESS_STATE_LISTENER_PATH)
+
+ .addAttribute(ProcessStateListenerResourceDefinition.LISTENER_CLASS)
+ .addAttribute(ProcessStateListenerResourceDefinition.LISTENER_MODULE)
+ .addAttribute(ProcessStateListenerResourceDefinition.PROPERTIES)
+ .addAttribute(ProcessStateListenerResourceDefinition.TIMEOUT)
+ .build());
+ return builder.build();
+ }
+}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationResourceDefinition.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationResourceDefinition.java
new file mode 100644
index 00000000000..66c359c3e60
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationResourceDefinition.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+package org.wildfly.extension.core.management;
+
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.PersistentResourceDefinition;
+import org.jboss.as.controller.ReloadRequiredAddStepHandler;
+import org.jboss.as.controller.ReloadRequiredRemoveStepHandler;
+import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
+import org.jboss.as.controller.ResourceRegistration;
+import org.jboss.as.controller.SimpleAttributeDefinition;
+import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
+import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
+import org.jboss.as.controller.operations.validation.EnumValidator;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.as.version.Stability;
+import org.jboss.dmr.ModelNode;
+import org.jboss.dmr.ModelType;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVICE;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UNSTABLE_API_ANNOTATIONS;
+
+/**
+ * Resource to list all configuration changes.
+ *
+ * @author Emmanuel Hugonnet (c) 2015 Red Hat, inc.
+ */
+public class UnstableApiAnnotationResourceDefinition extends PersistentResourceDefinition {
+
+ public static final Stability STABILITY = Stability.PREVIEW;
+ public static final SimpleAttributeDefinition LEVEL = SimpleAttributeDefinitionBuilder.create(
+ ModelDescriptionConstants.LEVEL, ModelType.STRING, true)
+ .setValidator(EnumValidator.create(UnstableApiAnnotationLevel.class))
+ .setDefaultValue(new ModelNode(UnstableApiAnnotationLevel.LOG.name()))
+ .build();
+ public static final PathElement PATH = PathElement.pathElement(SERVICE, UNSTABLE_API_ANNOTATIONS);
+ static final ResourceRegistration RESOURCE_REGISTRATION = ResourceRegistration.of(PATH, STABILITY);
+ static final UnstableApiAnnotationResourceDefinition INSTANCE = new UnstableApiAnnotationResourceDefinition();
+
+ private UnstableApiAnnotationResourceDefinition() {
+ super(
+ new Parameters(
+ RESOURCE_REGISTRATION,
+ CoreManagementExtension.getResourceDescriptionResolver(UNSTABLE_API_ANNOTATIONS))
+ .setAddHandler(ReloadRequiredAddStepHandler.INSTANCE)
+ .setRemoveHandler(ReloadRequiredRemoveStepHandler.INSTANCE));
+ }
+
+
+ @Override
+ public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
+ super.registerAttributes(resourceRegistration);
+ resourceRegistration.registerReadWriteAttribute(LEVEL, null, ReloadRequiredWriteAttributeHandler.INSTANCE);
+ }
+
+ @Override
+ public Collection getAttributes() {
+ return Collections.emptyList();
+ }
+
+ public enum UnstableApiAnnotationLevel {
+ LOG,
+ ERROR
+ }
+
+}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationService.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationService.java
new file mode 100644
index 00000000000..3546f12fe6d
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/UnstableApiAnnotationService.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management;
+
+import org.jboss.msc.Service;
+import org.jboss.msc.service.ServiceName;
+import org.jboss.msc.service.StartContext;
+import org.jboss.msc.service.StartException;
+import org.jboss.msc.service.StopContext;
+import org.wildfly.extension.core.management.UnstableApiAnnotationResourceDefinition.UnstableApiAnnotationLevel;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class UnstableApiAnnotationService implements Service {
+
+ public static ServiceName SERVICE_NAME = ServiceName.JBOSS.append("core-management", "unstable-api-annotation", "level");
+ private final Consumer serviceConsumer;
+ private final UnstableApiAnnotationLevel level;
+ static final UnstableApiAnnotationLevelSupplier LEVEL_SUPPLIER = new UnstableApiAnnotationLevelSupplier();
+
+ public UnstableApiAnnotationService(Consumer serviceConsumer, UnstableApiAnnotationLevel level) {
+ this.serviceConsumer = serviceConsumer;
+ this.level = level;
+ }
+
+ public UnstableApiAnnotationLevel getLevel() {
+ return level;
+ }
+
+ @Override
+ public void start(StartContext context) throws StartException {
+ serviceConsumer.accept(this);
+ LEVEL_SUPPLIER.level = level;
+ }
+
+ @Override
+ public void stop(StopContext context) {
+ serviceConsumer.accept(null);
+ LEVEL_SUPPLIER.level = level;
+ }
+
+ private static class UnstableApiAnnotationLevelSupplier implements Supplier {
+ private volatile UnstableApiAnnotationLevel level;
+ @Override
+ public UnstableApiAnnotationLevel get() {
+ return level;
+ }
+ }
+
+
+}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ReportUnstableApiAnnotationsProcessor.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ReportUnstableApiAnnotationsProcessor.java
new file mode 100644
index 00000000000..77be273fc16
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ReportUnstableApiAnnotationsProcessor.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management.deployment;
+
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.annotation.CompositeIndex;
+import org.jboss.jandex.DotName;
+import org.jboss.logging.Logger;
+import org.wildfly.extension.core.management.UnstableApiAnnotationResourceDefinition.UnstableApiAnnotationLevel;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.AnnotatedAnnotationUsage;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.AnnotatedClassUsage;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.AnnotatedFieldReference;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.AnnotatedMethodReference;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.AnnotationUsage;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.ClassInfoScanner;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.ExtendsAnnotatedClass;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.ImplementsAnnotatedInterface;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import static org.wildfly.extension.core.management.logging.CoreManagementLogger.UNSUPPORTED_ANNOTATION_LOGGER;
+
+public class ReportUnstableApiAnnotationsProcessor implements DeploymentUnitProcessor {
+
+ private final Supplier levelSupplier;
+
+ public ReportUnstableApiAnnotationsProcessor(Supplier levelSupplier) {
+ this.levelSupplier = levelSupplier;
+ }
+
+ /**
+ * Process this deployment for annotations. This will use an annotation indexer to create an index of all annotations
+ * found in this deployment and attach it to the deployment unit context.
+ *
+ * @param phaseContext the deployment unit context
+ * @throws DeploymentUnitProcessingException
+ *
+ */
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ final DeploymentUnit du = phaseContext.getDeploymentUnit();
+ DeploymentUnit top = du.getParent() == null ? du : du.getParent();
+ ClassInfoScanner scanner = top.getAttachment(UnstableApiAnnotationAttachments.UNSTABLE_API_ANNOTATION_SCANNER);
+ if (scanner == null) {
+ return;
+ }
+
+ // ScanExperimentalAnnotationsProcessor has looked for class, interface, method and field usage where those
+ // parts have been annotated with an annotation flagged as experimental.
+ // The finale part is to check the annotations indexed by Jandex
+ CompositeIndex index = du.getAttachment(Attachments.COMPOSITE_ANNOTATION_INDEX);
+ scanner.checkAnnotationIndex(annotationName -> index.getAnnotations(DotName.createSimple(annotationName)));
+
+ Set usages = scanner.getUsages();
+
+ if (!usages.isEmpty()) {
+ AnnotationUsages annotationUsages = AnnotationUsages.parseAndGroup(scanner.getUsages());
+ AnnotationUsageReporter reporter = getAnnotationUsageReporter(phaseContext, top);
+ if (reporter.isEnabled()) {
+ reportAnnotationUsages(top, annotationUsages, reporter);
+ }
+ }
+ }
+
+ private void reportAnnotationUsages(DeploymentUnit top, AnnotationUsages annotationUsages, AnnotationUsageReporter reporter) throws DeploymentUnitProcessingException {
+ reporter.header(UNSUPPORTED_ANNOTATION_LOGGER.deploymentContainsUnstableApiAnnotations(top.getName()));
+ for (ExtendsAnnotatedClass ext : annotationUsages.extendsAnnotatedClasses) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classExtendsClassWithUnstableApiAnnotations(
+ ext.getSourceClass(),
+ ext.getSuperClass(),
+ ext.getAnnotations()));
+ }
+ for (ImplementsAnnotatedInterface imp : annotationUsages.implementsAnnotatedInterfaces) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classImplementsInterfaceWithUnstableApiAnnotations(
+ imp.getSourceClass(),
+ imp.getInterface(),
+ imp.getAnnotations()));
+ }
+ for (AnnotatedFieldReference ref : annotationUsages.annotatedFieldReferences) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classReferencesFieldWithUnstableApiAnnotations(
+ ref.getSourceClass(),
+ ref.getFieldClass(),
+ ref.getFieldName(),
+ ref.getAnnotations()));
+ }
+ for (AnnotatedMethodReference ref : annotationUsages.annotatedMethodReferences) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classReferencesMethodWithUnstableApiAnnotations(
+ ref.getSourceClass(),
+ ref.getMethodClass(),
+ ref.getMethodName(),
+ ref.getDescriptor(),
+ ref.getAnnotations()));
+ }
+ for (AnnotatedClassUsage ref : annotationUsages.annotatedClassUsages) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classReferencesClassWithUnstableApiAnnotations(
+ ref.getSourceClass(),
+ ref.getReferencedClass(),
+ ref.getAnnotations()));
+ }
+ for (AnnotatedAnnotationUsage ref : annotationUsages.annotatedAnnotationUsages) {
+ reporter.reportAnnotationUsage(
+ UNSUPPORTED_ANNOTATION_LOGGER.classUsesAnnotatedAnnotations(
+ ref.getClazz(), ref.getAnnotations()));
+ }
+
+ reporter.complete();
+ }
+
+ private AnnotationUsageReporter getAnnotationUsageReporter(DeploymentPhaseContext ctx, DeploymentUnit top) throws DeploymentUnitProcessingException {
+ UnstableApiAnnotationLevel level = levelSupplier.get();
+ if (level == UnstableApiAnnotationLevel.ERROR) {
+ return new ErrorAnnotationUsageReporter();
+ }
+ return new WarningAnnotationUsageReporter();
+ }
+
+
+ private static class AnnotationUsages {
+
+
+ private final List extendsAnnotatedClasses;
+ private final List implementsAnnotatedInterfaces;
+ private final List annotatedFieldReferences;
+ private final List annotatedMethodReferences;
+ private final List annotatedClassUsages;
+ private final List annotatedAnnotationUsages;
+ public AnnotationUsages(List extendsAnnotatedClasses,
+ List implementsAnnotatedInterfaces,
+ List annotatedFieldReferences,
+ List annotatedMethodReferences,
+ List annotatedClassUsages,
+ List annotatedAnnotationUsages) {
+
+ this.extendsAnnotatedClasses = extendsAnnotatedClasses;
+ this.implementsAnnotatedInterfaces = implementsAnnotatedInterfaces;
+ this.annotatedFieldReferences = annotatedFieldReferences;
+ this.annotatedMethodReferences = annotatedMethodReferences;
+ this.annotatedClassUsages = annotatedClassUsages;
+ this.annotatedAnnotationUsages = annotatedAnnotationUsages;
+ }
+
+ static AnnotationUsages parseAndGroup(Set usages) {
+ List extendsAnnotatedClasses = new ArrayList<>();
+ List implementsAnnotatedInterfaces = new ArrayList<>();
+ List annotatedFieldReferences = new ArrayList<>();
+ List annotatedMethodReferences = new ArrayList<>();
+ List annotatedClassUsages = new ArrayList<>();
+ List annotatedAnnotationUsages = new ArrayList<>();
+ for (AnnotationUsage usage : usages) {
+ switch (usage.getType()) {
+ case EXTENDS_CLASS: {
+ ExtendsAnnotatedClass ext = usage.asExtendsAnnotatedClass();
+ extendsAnnotatedClasses.add(ext);
+ }
+ break;
+ case IMPLEMENTS_INTERFACE: {
+ ImplementsAnnotatedInterface imp = usage.asImplementsAnnotatedInterface();
+ implementsAnnotatedInterfaces.add(imp);
+ }
+ break;
+ case FIELD_REFERENCE: {
+ AnnotatedFieldReference ref = usage.asAnnotatedFieldReference();
+ annotatedFieldReferences.add(ref);
+ }
+ break;
+ case METHOD_REFERENCE: {
+ AnnotatedMethodReference ref = usage.asAnnotatedMethodReference();
+ annotatedMethodReferences.add(ref);
+ }
+ break;
+ case CLASS_USAGE: {
+ AnnotatedClassUsage ref = usage.asAnnotatedClassUsage();
+ annotatedClassUsages.add(ref);
+ }
+ break;
+ case ANNOTATED_ANNOTATION_USAGE: {
+ AnnotatedAnnotationUsage ref = usage.asAnnotatedAnnotationUsage();
+ annotatedAnnotationUsages.add(ref);
+ }
+ break;
+ }
+ }
+ extendsAnnotatedClasses.sort(new Comparator<>() {
+ @Override
+ public int compare(ExtendsAnnotatedClass o1, ExtendsAnnotatedClass o2) {
+ int i = o1.getSourceClass().compareTo(o2.getSourceClass());
+ if (i == 0) {
+ i = o1.getSuperClass().compareTo(o2.getSuperClass());
+ }
+
+ return i;
+ }
+ });
+ implementsAnnotatedInterfaces.sort(new Comparator<>() {
+ @Override
+ public int compare(ImplementsAnnotatedInterface o1, ImplementsAnnotatedInterface o2) {
+ int i = o1.getSourceClass().compareTo(o2.getSourceClass());
+ if (i == 0) {
+ i = o1.getInterface().compareTo(o2.getInterface());
+ }
+
+ return i;
+ }
+ });
+ annotatedFieldReferences.sort(new Comparator<>() {
+ @Override
+ public int compare(AnnotatedFieldReference o1, AnnotatedFieldReference o2) {
+ int i = o1.getSourceClass().compareTo(o2.getSourceClass());
+ if (i == 0) {
+ i = o1.getFieldClass().compareTo(o2.getFieldClass());
+ if (i == 0) {
+ i = o1.getFieldName().compareTo(o2.getFieldName());
+ }
+ }
+ return i;
+ }
+ });
+ annotatedMethodReferences.sort(new Comparator<>() {
+ @Override
+ public int compare(AnnotatedMethodReference o1, AnnotatedMethodReference o2) {
+ int i = o1.getSourceClass().compareTo(o2.getSourceClass());
+ if (i == 0) {
+ i = o1.getMethodClass().compareTo(o2.getMethodClass());
+ if (i == 0) {
+ i = o1.getMethodName().compareTo(o2.getMethodName());
+ if (i == 0) {
+ i = o1.getDescriptor().compareTo(o2.getDescriptor());
+ }
+ }
+ }
+ return i;
+ }
+ });
+ annotatedClassUsages.sort(new Comparator<>() {
+ @Override
+ public int compare(AnnotatedClassUsage o1, AnnotatedClassUsage o2) {
+ int i = o1.getSourceClass().compareTo(o2.getSourceClass());
+ if (i == 0) {
+ i = o1.getReferencedClass().compareTo(o2.getReferencedClass());
+ }
+ return i;
+ }
+ });
+ annotatedAnnotationUsages.sort(new Comparator<>(){
+ @Override
+ public int compare(AnnotatedAnnotationUsage o1, AnnotatedAnnotationUsage o2) {
+ return o1.getClazz().compareTo(o2.getClazz());
+ }
+ });
+
+ return new AnnotationUsages(extendsAnnotatedClasses,
+ implementsAnnotatedInterfaces,
+ annotatedFieldReferences,
+ annotatedMethodReferences,
+ annotatedClassUsages,
+ annotatedAnnotationUsages);
+ }
+ }
+
+
+
+ private interface AnnotationUsageReporter {
+ void header(String message);
+
+ void reportAnnotationUsage(String message);
+
+ void complete() throws DeploymentUnitProcessingException;
+
+ boolean isEnabled();
+ }
+
+ private class WarningAnnotationUsageReporter implements AnnotationUsageReporter {
+ @Override
+ public void header(String message) {
+ UNSUPPORTED_ANNOTATION_LOGGER.warn(message);
+ }
+
+ @Override
+ public void reportAnnotationUsage(String message) {
+ UNSUPPORTED_ANNOTATION_LOGGER.warn(message);
+ }
+
+ @Override
+ public void complete() throws DeploymentUnitProcessingException {
+
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return UNSUPPORTED_ANNOTATION_LOGGER.isEnabled(Logger.Level.WARN);
+ }
+ }
+
+ private class ErrorAnnotationUsageReporter implements AnnotationUsageReporter {
+ private final StringBuilder sb = new StringBuilder();
+ @Override
+ public void header(String message) {
+ sb.append(message);
+ }
+
+ @Override
+ public void reportAnnotationUsage(String message) {
+ sb.append("\n");
+ sb.append("-");
+ sb.append(message);
+ }
+
+ @Override
+ public void complete() throws DeploymentUnitProcessingException {
+ throw new DeploymentUnitProcessingException(sb.toString());
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ScanUnstableApiAnnotationsProcessor.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ScanUnstableApiAnnotationsProcessor.java
new file mode 100644
index 00000000000..a8fe09622a6
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/ScanUnstableApiAnnotationsProcessor.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management.deployment;
+
+import org.jboss.as.controller.RunningMode;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.DeploymentUtils;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.as.server.logging.ServerLogger;
+import org.jboss.as.version.Stability;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleClassLoader;
+import org.jboss.modules.ModuleLoadException;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.VisitorAttributes;
+import org.jboss.vfs.util.SuffixMatchFilter;
+import org.wildfly.extension.core.management.UnstableApiAnnotationResourceDefinition;
+import org.wildfly.extension.core.management.logging.CoreManagementLogger;
+import org.wildfly.unstable.api.annotation.classpath.index.RuntimeIndex;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.ClassInfoScanner;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+public class ScanUnstableApiAnnotationsProcessor implements DeploymentUnitProcessor {
+
+ private final RuntimeIndex runtimeIndex;
+
+ // If set we will output some extra information to the logs during testing, so we can verify the number of classes scanned
+ // This is important for WildFly to make sure that the scanning of nested archives (especially wars and ears) is
+ // working as expected and to guard against scanning classes multiple times (which happened during the development of this feature)
+ private final String EXTRA_TEST_OUTPUT_PROPERTY = "org.wildfly.test.unstable-api-annotation.extra-output";
+
+ private static final String BASE_MODULE_NAME = "org.wildfly._internal.unstable-api-annotation-index";
+ private static final String INDEX_FILE = "index.txt";
+ private final Stability stability;
+ private final Supplier levelSupplier;
+
+ private boolean extraTestOutput;
+
+ public ScanUnstableApiAnnotationsProcessor(RunningMode runningMode, Stability stability, Supplier levelSupplier) {
+ this.stability = stability;
+ this.levelSupplier = levelSupplier;
+ extraTestOutput = System.getProperties().containsKey(EXTRA_TEST_OUTPUT_PROPERTY);
+
+ boolean enableScanning = true;
+ if (runningMode == RunningMode.ADMIN_ONLY) {
+ enableScanning = false;
+ } else if (stability.enables(Stability.EXPERIMENTAL) || !stability.enables(UnstableApiAnnotationResourceDefinition.STABILITY)) {
+ // We don't care about scanning at the experimental level.
+ // Also, we need to be at the level where the feature is enabled or lower
+ enableScanning = false;
+ }
+
+ RuntimeIndex runtimeIndex = null;
+ if (enableScanning) {
+ ModuleLoader moduleLoader = ((ModuleClassLoader) this.getClass().getClassLoader()).getModule().getModuleLoader();
+ Module module = null;
+ try {
+ module = moduleLoader.loadModule(BASE_MODULE_NAME);
+ } catch (ModuleLoadException e) {
+ // TODO make this module part of core so it is always there
+ }
+ if (module != null) {
+ URL url = module.getExportedResource(INDEX_FILE);
+ List urls = new ArrayList<>();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ String fileName = reader.readLine();
+ while (fileName != null) {
+ fileName = fileName.trim();
+ if (!fileName.isEmpty() && !fileName.startsWith("#")) {
+ urls.add(module.getExportedResource(fileName));
+ }
+ fileName = reader.readLine();
+ }
+
+ if (!urls.isEmpty()) {
+ runtimeIndex = RuntimeIndex.load(urls);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ this.runtimeIndex = runtimeIndex;
+ }
+
+ /**
+ * Process this deployment for annotations. This will use an annotation indexer to create an index of all annotations
+ * found in this deployment and attach it to the deployment unit context.
+ *
+ * @param phaseContext the deployment unit context
+ * @throws DeploymentUnitProcessingException
+ */
+ public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+ if (runtimeIndex == null) {
+ return;
+ }
+ if (levelSupplier.get() == null) {
+ return;
+ }
+ final DeploymentUnit du = phaseContext.getDeploymentUnit();
+ DeploymentUnit top = DeploymentUtils.getTopDeploymentUnit(du);
+
+ ClassInfoScanner scanner = top.getAttachment(UnstableApiAnnotationAttachments.UNSTABLE_API_ANNOTATION_SCANNER);
+ if (scanner == null) {
+ scanner = new ClassInfoScanner(runtimeIndex);
+ top.putAttachment(UnstableApiAnnotationAttachments.UNSTABLE_API_ANNOTATION_SCANNER, scanner);
+ }
+ ProcessedClassCounter counter = new ProcessedClassCounter();
+
+ ServerLogger.DEPLOYMENT_LOGGER.debug("Scanning deployment for unstable api annotations");
+ List resourceRoots = DeploymentUtils.allResourceRoots(du);
+ for (ResourceRoot root : resourceRoots) {
+
+ // The EarStructureProcessor and WarStructureProcessor in full will set this accordingly
+ Boolean shouldIndexResource = root.getAttachment(Attachments.INDEX_RESOURCE_ROOT);
+ if (shouldIndexResource != null && !shouldIndexResource) {
+ continue;
+ }
+
+ if (root.getAttachment(UnstableApiAnnotationAttachments.UNSTABLE_API_ANNOTATIONS_SCANNED) != null) {
+ continue;
+ }
+ final VisitorAttributes visitorAttributes = new VisitorAttributes();
+ visitorAttributes.setLeavesOnly(true);
+ visitorAttributes.setRecurseFilter(f-> true);
+
+ try {
+ final List classChildren = root.getRoot().getChildren(new SuffixMatchFilter(".class", visitorAttributes));
+ for (VirtualFile file : classChildren) {
+ if (file.isFile() && file.getName().endsWith(".class")) {
+ try (InputStream in = file.openStream()) {
+ scanner.scanClass(in);
+ counter.incrementClassesScannedCount();
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ root.putAttachment(UnstableApiAnnotationAttachments.UNSTABLE_API_ANNOTATIONS_SCANNED, true);
+ }
+
+ long time = (System.currentTimeMillis() - counter.startTime);
+ CoreManagementLogger.UNSUPPORTED_ANNOTATION_LOGGER.debugf("Unstable annotation api scan took %d ms to scan %d classes", time, counter.getClassesScannedCount());
+ if (extraTestOutput) {
+ CoreManagementLogger.UNSUPPORTED_ANNOTATION_LOGGER.testOutputNumberOfClassesScanned(counter.getClassesScannedCount());
+ }
+ }
+
+ public static class ProcessedClassCounter {
+ private final long startTime = System.currentTimeMillis();
+
+ private volatile int classesScannedCount = 0;
+
+ void incrementClassesScannedCount() {
+ classesScannedCount++;
+ }
+
+ public int getClassesScannedCount() {
+ return classesScannedCount;
+ }
+ }
+}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/UnstableApiAnnotationAttachments.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/UnstableApiAnnotationAttachments.java
new file mode 100644
index 00000000000..e3218dc28ba
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/deployment/UnstableApiAnnotationAttachments.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management.deployment;
+
+import org.jboss.as.server.deployment.AttachmentKey;
+import org.wildfly.unstable.api.annotation.classpath.runtime.bytecode.ClassInfoScanner;
+
+class UnstableApiAnnotationAttachments {
+ public static final AttachmentKey UNSTABLE_API_ANNOTATION_SCANNER = AttachmentKey.create(ClassInfoScanner.class);
+
+ public static final AttachmentKey UNSTABLE_API_ANNOTATIONS_SCANNED = AttachmentKey.create(Boolean.class);
+
+}
diff --git a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/logging/CoreManagementLogger.java b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/logging/CoreManagementLogger.java
index 7926bc676d3..63860b511f0 100644
--- a/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/logging/CoreManagementLogger.java
+++ b/core-management/core-management-subsystem/src/main/java/org/wildfly/extension/core/management/logging/CoreManagementLogger.java
@@ -6,6 +6,7 @@
package org.wildfly.extension.core.management.logging;
import static org.jboss.logging.Logger.Level.ERROR;
+import static org.jboss.logging.Logger.Level.INFO;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.logging.BasicLogger;
@@ -15,6 +16,8 @@
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;
+import java.util.Set;
+
/**
*
* @author Emmanuel Hugonnet (c) 2016 Red Hat, inc.
@@ -27,6 +30,8 @@ public interface CoreManagementLogger extends BasicLogger {
*/
CoreManagementLogger ROOT_LOGGER = Logger.getMessageLogger(CoreManagementLogger.class, "org.wildfly.extension.core.management");
+ CoreManagementLogger UNSUPPORTED_ANNOTATION_LOGGER = Logger.getMessageLogger(CoreManagementLogger.class, "org.wildfly.annotation.unsupported");
+
// @Message(id = 1, value = "The resource %s wasn't working properly and has been removed.")
// String removedOutOfOrderResource(final String address);
@@ -53,4 +58,31 @@ public interface CoreManagementLogger extends BasicLogger {
@Message(id = 8, value = "Error to instantiate instance of class %s from module %s")
OperationFailedException errorToInstantiateClassInstanceFromModule(String className, String moduleID);
+
+ @Message(id = 9, value = "%s contains usage of annotations which indicate unstable API.")
+ String deploymentContainsUnstableApiAnnotations(String deployment);
+
+ @Message(id = 10, value = "%s extends %s which has been annotated with %s")
+ String classExtendsClassWithUnstableApiAnnotations(String sourceClass, String superClass, Set annotations);
+
+ @Message(id = 11, value = "%s implements %s which has been annotated with %s")
+ String classImplementsInterfaceWithUnstableApiAnnotations(String sourceClass, String superClass, Set annotations);
+
+ @Message(id = 12, value = "%s references field %s.%s which has been annotated with %s")
+ String classReferencesFieldWithUnstableApiAnnotations(String sourceClass, String fieldClass, String fieldName, Set annotations);
+
+ @Message(id = 13, value = "%s references method %s.%s%s which has been annotated with %s")
+ String classReferencesMethodWithUnstableApiAnnotations(String sourceClass, String methodClass, String methodName, String methodSignature, Set annotations);
+
+ @Message(id = 14, value = "%s references class %s which has been annotated with %s")
+ String classReferencesClassWithUnstableApiAnnotations(String sourceClass, String referencedClass, Set annotations);
+
+ @Message(id = 15, value = "Class %s is annotated with one or more annotations which in turn have been annotated with annotations indicating unstable api: %s")
+ String classUsesAnnotatedAnnotations(String clazz, Set annotations);
+
+ // For testing only
+ @LogMessage(level = INFO)
+ @Message(id = 16, value = "%d")
+ void testOutputNumberOfClassesScanned(int number);
+
}
diff --git a/core-management/core-management-subsystem/src/main/resources/org/wildfly/extension/core/management/LocalDescriptions.properties b/core-management/core-management-subsystem/src/main/resources/org/wildfly/extension/core/management/LocalDescriptions.properties
index fa9f915c3a7..5ed40797c43 100644
--- a/core-management/core-management-subsystem/src/main/resources/org/wildfly/extension/core/management/LocalDescriptions.properties
+++ b/core-management/core-management-subsystem/src/main/resources/org/wildfly/extension/core/management/LocalDescriptions.properties
@@ -16,6 +16,11 @@ core-management.configuration-changes.remove=Remove the configuration changes an
core-management.configuration-changes.max-history=The maximum number of configuration changes stored in history.
core-management.configuration-changes.list-changes=List the last configuration changes.
+core-management.unstable-api-annotations=Service to configure how we deal with finding annotations indicating unstable API in user code.
+core-management.unstable-api-annotations.add=Add the history for configuration changes.
+core-management.unstable-api-annotations.remove=Remove the configuration changes and clear the history.
+core-management.unstable-api-annotations.level=Whether to throw an error or log a warning if annotations indicating unstable API.
+
core-management.process-state-listener=Process state listener.
core-management.process-state-listener.add=Add the process-state-listener service.
core-management.process-state-listener.add-index=Add the process-state-listener serviceat the specified index.
diff --git a/core-management/core-management-subsystem/src/main/resources/schema/wildfly-core-management_preview_1_0.xsd b/core-management/core-management-subsystem/src/main/resources/schema/wildfly-core-management_preview_1_0.xsd
new file mode 100644
index 00000000000..3ebcafe0048
--- /dev/null
+++ b/core-management/core-management-subsystem/src/main/resources/schema/wildfly-core-management_preview_1_0.xsd
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Configuration for the history of configuration changes.
+
+
+
+
+
+
+ Number of configuration changes that are available in history.
+
+
+
+
+
+
+
+
+ Configuration of the handling of finding unstable api annotations in the
+ user's code
+
+
+
+
+
+
+ Whether to log or throw an error if use of unstable api annotations are found
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Configuration for a process state listener.
+
+
+
+
+
+
+
+ Configuration properties for the process state listener.
+
+
+
+
+
+
+
+ Name of the process state listener.
+
+
+
+
+
+
+ ControlledProcessStateListener class implementation.
+
+
+
+
+
+
+ Module where the ControlledProcessStateListener implementation class may be found.
+
+
+
+
+
+
+ Timeout used in seconds, for listener operations.
+ If an individual listener operation takes longer than this timeout it will be canceled.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystemTestCase.java b/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystemTestCase.java
deleted file mode 100644
index f002ce0ed61..00000000000
--- a/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystemTestCase.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright The WildFly Authors
- * SPDX-License-Identifier: Apache-2.0
- */
-
-package org.wildfly.extension.core.management;
-
-import java.io.IOException;
-
-import org.jboss.as.controller.ProcessType;
-import org.jboss.as.controller.RunningMode;
-import org.jboss.as.subsystem.test.AbstractSubsystemBaseTest;
-import org.jboss.as.subsystem.test.AdditionalInitialization;
-
-/**
- * @author Jeff Mesnil (c) 2016 Red Hat Inc.
- */
-public class CoreManagementSubsystemTestCase extends AbstractSubsystemBaseTest {
-
- public CoreManagementSubsystemTestCase() {
- super(CoreManagementExtension.SUBSYSTEM_NAME, new CoreManagementExtension());
- }
-
- @Override
- protected String getSubsystemXml() throws IOException {
- return readResource("core-management-subsystem-1_0.xml");
- }
-
- @Override
- protected AdditionalInitialization createAdditionalInitialization() {
- return new AdditionalInitialization() {
-
- @Override
- protected ProcessType getProcessType() {
- return ProcessType.HOST_CONTROLLER;
- }
-
- @Override
- protected RunningMode getRunningMode() {
- return RunningMode.ADMIN_ONLY;
- }
- };
- }
-}
diff --git a/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystem_1_0_TestCase.java b/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystem_1_0_TestCase.java
new file mode 100644
index 00000000000..7392d29e230
--- /dev/null
+++ b/core-management/core-management-subsystem/src/test/java/org/wildfly/extension/core/management/CoreManagementSubsystem_1_0_TestCase.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.extension.core.management;
+
+import org.jboss.as.subsystem.test.AbstractSubsystemSchemaTest;
+import org.jboss.as.subsystem.test.AdditionalInitialization;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.EnumSet;
+
+/**
+ * @author Jeff Mesnil (c) 2016 Red Hat Inc.
+ */
+@RunWith(Parameterized.class)
+public class CoreManagementSubsystem_1_0_TestCase extends AbstractSubsystemSchemaTest {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable getParameters() {
+ return EnumSet.allOf(CoreManagementSubsystemSchema_1_0.class);
+ }
+
+ public CoreManagementSubsystem_1_0_TestCase(CoreManagementSubsystemSchema_1_0 schema) {
+ super(CoreManagementExtension.SUBSYSTEM_NAME, new CoreManagementExtension(), schema, CoreManagementSubsystemSchema_1_0.ALL.get(schema.getStability()));
+ }
+
+ @Override
+ protected AdditionalInitialization createAdditionalInitialization() {
+ return new AdditionalInitialization.AdminOnlyHostControllerAdditionalInitialization(getSubsystemSchema());
+ }
+
+}
diff --git a/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-subsystem-1_0.xml b/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-1.0.xml
similarity index 53%
rename from core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-subsystem-1_0.xml
rename to core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-1.0.xml
index 75badc23690..7ab654653a6 100644
--- a/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-subsystem-1_0.xml
+++ b/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-1.0.xml
@@ -3,4 +3,6 @@
~ SPDX-License-Identifier: Apache-2.0
-->
+
+
\ No newline at end of file
diff --git a/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-preview-1.0.xml b/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-preview-1.0.xml
new file mode 100644
index 00000000000..89d671fd23b
--- /dev/null
+++ b/core-management/core-management-subsystem/src/test/resources/org/wildfly/extension/core/management/core-management-preview-1.0.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 43efcddba94..2ad1ff143dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,6 +245,7 @@
2.4.2.Final
4.1.0.Final
3.0.3.Final
+ 1.0.0.Alpha3
2.2
@@ -2172,11 +2173,17 @@
+
+ org.wildfly.unstable.api.annotation
+ unstable-api-annotation-classpath-indexer
+ ${version.org.wildfly.unstable.api.annotation}
+
+
org.yaml
snakeyaml
${version.org.yaml.snakeyaml}
-
+
org.jboss.logging
jboss-logging-annotations
diff --git a/server/src/main/java/org/jboss/as/server/deployment/Phase.java b/server/src/main/java/org/jboss/as/server/deployment/Phase.java
index 3621ae8cf05..c8ed45ca3a4 100644
--- a/server/src/main/java/org/jboss/as/server/deployment/Phase.java
+++ b/server/src/main/java/org/jboss/as/server/deployment/Phase.java
@@ -248,6 +248,8 @@ public AttachmentKey> getPhaseKey() {
public static final int PARSE_COMPOSITE_ANNOTATION_INDEX = 0x0301;
public static final int PARSE_EXTENSION_LIST = 0x0700;
public static final int PARSE_EXTENSION_NAME = 0x0800;
+ public static final int PARSE_SCAN_EXPERIMENTAL_ANNOTATIONS = 0x0840;
+ public static final int PARSE_REPORT_EXPERIMENTAL_ANNOTATIONS = 0x0850;
public static final int PARSE_WEB_DEPLOYMENT = 0x0B00;
public static final int PARSE_WEB_DEPLOYMENT_FRAGMENT = 0x0C00;
diff --git a/subsystem-test/framework/src/main/java/org/jboss/as/subsystem/test/AdditionalInitialization.java b/subsystem-test/framework/src/main/java/org/jboss/as/subsystem/test/AdditionalInitialization.java
index fea289c8788..023d8a3fbfd 100644
--- a/subsystem-test/framework/src/main/java/org/jboss/as/subsystem/test/AdditionalInitialization.java
+++ b/subsystem-test/framework/src/main/java/org/jboss/as/subsystem/test/AdditionalInitialization.java
@@ -5,10 +5,6 @@
package org.jboss.as.subsystem.test;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-
import org.jboss.as.controller.FeatureRegistry;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.ProcessType;
@@ -29,6 +25,10 @@
import org.jboss.dmr.ModelType;
import org.jboss.msc.service.ServiceTarget;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
/**
* Allows you to additionally initialize the service container and the model controller
* beyond the subsystem being tested. Override this class to add behaviour.
@@ -38,12 +38,7 @@
public class AdditionalInitialization extends AdditionalParsers implements FeatureRegistry {
public static final AdditionalInitialization MANAGEMENT = new ManagementAdditionalInitialization();
- public static final AdditionalInitialization ADMIN_ONLY_HC = new ManagementAdditionalInitialization() {
- @Override
- protected ProcessType getProcessType() {
- return ProcessType.HOST_CONTROLLER;
- }
- };
+ public static final AdditionalInitialization ADMIN_ONLY_HC = new AdminOnlyHostControllerAdditionalInitialization();
public static class HostControllerAdditionalInitialization extends AdditionalInitialization implements Serializable {
private static final long serialVersionUID = -509444465514822866L;
@@ -96,6 +91,26 @@ protected RunningMode getRunningMode() {
}
}
+ public static class AdminOnlyHostControllerAdditionalInitialization extends ManagementAdditionalInitialization implements Serializable {
+ public AdminOnlyHostControllerAdditionalInitialization() {
+ super();
+ }
+
+ public > AdminOnlyHostControllerAdditionalInitialization(S schema) {
+ super(schema);
+ }
+
+ public AdminOnlyHostControllerAdditionalInitialization(Stability stability) {
+ super(stability);
+ }
+
+ @Override
+ protected ProcessType getProcessType() {
+ return ProcessType.HOST_CONTROLLER;
+ }
+ }
+
+
/**
* Creates a {@link org.jboss.as.subsystem.test.AdditionalInitialization.ManagementAdditionalInitialization} with
* the given {@link org.jboss.as.controller.capability.RuntimeCapability capabilities} registered, making it
diff --git a/testsuite/pom.xml b/testsuite/pom.xml
index 0d64f23a552..4af49877963 100644
--- a/testsuite/pom.xml
+++ b/testsuite/pom.xml
@@ -53,6 +53,7 @@
elytron
embedded
scripts
+ unstable-api-annotation
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/pom.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/pom.xml
new file mode 100644
index 00000000000..06f63daafc7
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/pom.xml
@@ -0,0 +1,152 @@
+
+
+
+ 4.0.0
+
+
+ org.wildfly.core
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-parent
+ 25.0.0.Beta5-SNAPSHOT
+
+
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ pom
+
+ WildFly Core Test Suite: Unstable API Annotation Feature Pack
+
+
+
+
+
+ ${artifactId}-${project.version}
+
+
+
+ maven-clean-plugin
+
+
+ auto-clean
+ initialize
+
+ clean
+
+
+
+
+
+ org.wildfly.unstable.api.annotation
+ unstable-api-annotation-classpath-indexer-plugin
+ ${version.org.wildfly.unstable.api.annotation}
+
+
+ scan-experimental-annotations
+ compile
+
+ index-unstable-api-annotations
+
+
+ ${project.build.directory}/index/wildfly-core-testsuite-unstable-api-annotation-feature-pack.txt
+
+
+ org.wildfly.core.test.unstable.api.annotation.classes.api.Unstable
+
+ ${project.groupId}
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ copy-resources
+ process-resources
+
+ copy-resources
+
+
+ ${basedir}/target/resources
+
+
+ ${basedir}/src/main/resources
+
+
+
+
+
+
+
+ org.wildfly.galleon-plugins
+ wildfly-galleon-maven-plugin
+ ${version.org.wildfly.galleon-plugins}
+
+
+ wildfly-template-feature-pack-build
+
+ build-feature-pack
+
+ prepare-package
+
+ ${galleon.fork.embedded}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ copy-annotation-index
+ prepare-package
+
+ copy-resources
+
+
+ ${basedir}/target/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/content/
+
+
+ ${basedir}/target/index/
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.wildfly.core
+ wildfly-core-galleon-pack
+ zip
+
+
+
+ org.wildfly.galleon-plugins
+ wildfly-galleon-plugins
+ provided
+
+
+
+ ${project.groupId}
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-subsystem
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/domain/model.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/domain/model.xml
new file mode 100644
index 00000000000..0c9a627fa34
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/domain/model.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/host/model.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/host/model.xml
new file mode 100644
index 00000000000..3699b92e608
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/host/model.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/standalone/model.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/standalone/model.xml
new file mode 100644
index 00000000000..dfe41dab468
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/configs/standalone/model.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/feature_groups/unstable-api-annotation-test-subsystem.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/feature_groups/unstable-api-annotation-test-subsystem.xml
new file mode 100644
index 00000000000..99420a52fa4
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/feature_groups/unstable-api-annotation-test-subsystem.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/layers/standalone/unstable-api-annotation-test/layer-spec.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/layers/standalone/unstable-api-annotation-test/layer-spec.xml
new file mode 100644
index 00000000000..412abd2d258
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/layers/standalone/unstable-api-annotation-test/layer-spec.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/modules/system/layers/base/org/wildfly/core/test/extension/unstable-api-annotation-test-subsystem/main/module.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/modules/system/layers/base/org/wildfly/core/test/extension/unstable-api-annotation-test-subsystem/main/module.xml
new file mode 100644
index 00000000000..43c3c4d077f
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/modules/system/layers/base/org/wildfly/core/test/extension/unstable-api-annotation-test-subsystem/main/module.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/package.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/package.xml
new file mode 100644
index 00000000000..1afad183b75
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/package.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/pm/wildfly/tasks.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/pm/wildfly/tasks.xml
new file mode 100644
index 00000000000..f396d92504b
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/src/main/resources/packages/unstable-api-annotation-index.wildfly-core-testsuite-unstable-api-annotation-feature-pack/pm/wildfly/tasks.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack.txt
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/feature-pack/wildfly-feature-pack-build.xml b/testsuite/unstable-api-annotation/feature-pack/feature-pack/wildfly-feature-pack-build.xml
new file mode 100644
index 00000000000..d8f4fd8082c
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/feature-pack/wildfly-feature-pack-build.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ org.wildfly:wildfly-ee-galleon-pack
+
+
+
+
+
+
+
+
+
+
+
+
+ org.wildfly.core.test.extension.unstable-api-annotation-test-subsystem
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/pom.xml b/testsuite/unstable-api-annotation/feature-pack/pom.xml
new file mode 100644
index 00000000000..f7f6fa9186c
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/pom.xml
@@ -0,0 +1,46 @@
+
+
+
+ 4.0.0
+
+
+ org.wildfly.core
+ wildfly-core-parent
+ 25.0.0.Beta5-SNAPSHOT
+ ../../../pom.xml
+
+
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-parent
+ pom
+
+ WildFly Core Test Suite: Unstable API Annotation Feature Pack Parent
+
+
+ feature-pack
+ subsystem
+
+
+
+
+
+ ${project.groupId}
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ ${project.version}
+
+
+ ${project.groupId}
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-subsystem
+ ${project.version}
+
+
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/pom.xml b/testsuite/unstable-api-annotation/feature-pack/subsystem/pom.xml
new file mode 100644
index 00000000000..9227de26073
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/pom.xml
@@ -0,0 +1,58 @@
+
+
+
+ 4.0.0
+
+
+ org.wildfly.core
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-parent
+ 25.0.0.Beta5-SNAPSHOT
+
+
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack-subsystem
+ jar
+
+ WildFly Core Test Suite: Unstable API Annotation Feature Pack Subsystem
+
+
+
+ org.jboss.logging
+ jboss-logging
+ provided
+
+
+
+ org.jboss.logging
+ jboss-logging-annotations
+ provided
+ true
+
+
+
+ org.jboss.logging
+ jboss-logging-processor
+ provided
+ true
+
+
+
+ ${project.groupId}
+ wildfly-controller
+ provided
+
+
+
+ ${project.groupId}
+ wildfly-server
+ provided
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/_private/UnstableAnnotationApiTestLogger.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/_private/UnstableAnnotationApiTestLogger.java
new file mode 100644
index 00000000000..49ea16e7d24
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/_private/UnstableAnnotationApiTestLogger.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes._private;
+
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.logging.BasicLogger;
+import org.jboss.logging.Logger;
+import org.jboss.logging.annotations.LogMessage;
+import org.jboss.logging.annotations.Message;
+import org.jboss.logging.annotations.MessageLogger;
+
+import static org.jboss.logging.Logger.Level.INFO;
+
+/**
+ * Log messages for our template subsystem.
+ *
+ * @author Kabir Khan (c) 2019 Red Hat inc.
+ */
+// TODO Make the projectCode in the @MessageLogger annotation some abbreviation to identify your subsystem
+@MessageLogger(projectCode = "WFLYGPTMPL", length = 4)
+// TODO Rename to something that makes sense for your subsystem.
+public interface UnstableAnnotationApiTestLogger extends BasicLogger {
+
+ UnstableAnnotationApiTestLogger LOGGER = Logger.getMessageLogger(UnstableAnnotationApiTestLogger.class, "org.wildfly.extension.galleon.pack.template.subsystem");
+
+ /**
+ * Logs an informational message indicating the subsystem is being activated.
+ */
+ @LogMessage(level = INFO)
+ @Message(id = 1, value = "Activating Unstable Annotation API Subsystem")
+ void activatingSubsystem();
+
+
+ @Message(id = 2, value = "Deployment %s requires use of the '%s' capability but it is not currently registered")
+ DeploymentUnitProcessingException deploymentRequiresCapability(String deploymentName, String capabilityName);
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/AnnotatedAnnotation.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/AnnotatedAnnotation.java
new file mode 100644
index 00000000000..f424dd8b0d7
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/AnnotatedAnnotation.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+@Unstable
+public @interface AnnotatedAnnotation {
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedField.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedField.java
new file mode 100644
index 00000000000..02976461d5a
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedField.java
@@ -0,0 +1,11 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+public class TestClassWithAnnotatedField {
+ @Unstable
+ public static int annotatedField;
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedMethod.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedMethod.java
new file mode 100644
index 00000000000..cc8c8cc7ccf
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotatedMethod.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+public class TestClassWithAnnotatedMethod {
+ @Unstable
+ public static void annotatedMethod() {
+ }
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForExtends.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForExtends.java
new file mode 100644
index 00000000000..aba3b2eca86
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForExtends.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+@Unstable
+public class TestClassWithAnnotationForExtends {
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForUsage.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForUsage.java
new file mode 100644
index 00000000000..0b5c827a472
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestClassWithAnnotationForUsage.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+@Unstable
+public class TestClassWithAnnotationForUsage {
+ public void methodWithNoAnnotation() {
+
+ }
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestInterfaceWithAnnotation.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestInterfaceWithAnnotation.java
new file mode 100644
index 00000000000..891f1d38ecc
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/TestInterfaceWithAnnotation.java
@@ -0,0 +1,10 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+@Unstable
+public interface TestInterfaceWithAnnotation {
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/Unstable.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/Unstable.java
new file mode 100644
index 00000000000..2c08a5d6f4a
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/api/Unstable.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.api;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Unstable {
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestDependencyProcessor.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestDependencyProcessor.java
new file mode 100644
index 00000000000..6667fbb5a67
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestDependencyProcessor.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.subsystem;
+
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleLoader;
+
+/**
+ * @author Kabir Khan
+ */
+public class UnstableApiAnnotationTestDependencyProcessor implements DeploymentUnitProcessor {
+
+ @Override
+ public void deploy(DeploymentPhaseContext phaseContext) {
+ DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+
+ addModuleDependencies(deploymentUnit);
+ }
+
+ @Override
+ public void undeploy(DeploymentUnit context) {
+ }
+
+ private void addModuleDependencies(DeploymentUnit deploymentUnit) {
+ final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
+ final ModuleLoader moduleLoader = Module.getBootModuleLoader();
+
+ // Pull in dependencies needed by deployments in the subsystem
+
+ // This is needed if running with a security manager, and seems to be needed by arquillian in all cases
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, "org.wildfly.security.manager", false, false, true, false));
+ moduleSpecification.addSystemDependency(
+ cdiDependency(new ModuleDependency(moduleLoader, "org.wildfly.core.test.extension.unstable-api-annotation-test-subsystem", false, false, true, false)));
+ }
+
+
+ private ModuleDependency cdiDependency(ModuleDependency moduleDependency) {
+ // This is needed following https://issues.redhat.com/browse/WFLY-13641 / https://github.com/wildfly/wildfly/pull/13406
+ moduleDependency.addImportFilter(s -> s.equals("META-INF"), true);
+ return moduleDependency;
+ }
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestExtension.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestExtension.java
new file mode 100644
index 00000000000..cb252b29149
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestExtension.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.subsystem;
+
+import org.jboss.as.controller.Extension;
+import org.jboss.as.controller.ExtensionContext;
+import org.jboss.as.controller.ModelVersion;
+import org.jboss.as.controller.PathElement;
+import org.jboss.as.controller.SubsystemRegistration;
+import org.jboss.as.controller.descriptions.ResourceDescriptionResolver;
+import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
+import org.jboss.as.controller.operations.common.GenericSubsystemDescribeHandler;
+import org.jboss.as.controller.parsing.ExtensionParsingContext;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
+
+/**
+ * @author Kabir Khan
+ */
+public class UnstableApiAnnotationTestExtension implements Extension {
+
+ public static final String SUBSYSTEM_NAME = "unstable-api-annotation-test";
+
+ protected static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(SUBSYSTEM, SUBSYSTEM_NAME);
+
+ private static final String RESOURCE_NAME = UnstableApiAnnotationTestExtension.class.getPackage().getName() + ".LocalDescriptions";
+
+ protected static final ModelVersion VERSION_1_0_0 = ModelVersion.create(1, 0, 0);
+ private static final ModelVersion CURRENT_MODEL_VERSION = VERSION_1_0_0;
+
+ private static final UnstableApiAnnotationTestSubsystemParser_1_0 CURRENT_PARSER = new UnstableApiAnnotationTestSubsystemParser_1_0();
+
+ static ResourceDescriptionResolver getResourceDescriptionResolver(final String... keyPrefix) {
+ return getResourceDescriptionResolver(true, keyPrefix);
+
+ }
+
+ static ResourceDescriptionResolver getResourceDescriptionResolver(final boolean useUnprefixedChildTypes, final String... keyPrefix) {
+ StringBuilder prefix = new StringBuilder();
+ for (String kp : keyPrefix) {
+ if (prefix.length() > 0){
+ prefix.append('.');
+ }
+ prefix.append(kp);
+ }
+ return new StandardResourceDescriptionResolver(prefix.toString(), RESOURCE_NAME, UnstableApiAnnotationTestExtension.class.getClassLoader(), true, useUnprefixedChildTypes);
+ }
+
+
+ @Override
+ public void initialize(ExtensionContext extensionContext) {
+ final SubsystemRegistration sr = extensionContext.registerSubsystem(SUBSYSTEM_NAME, CURRENT_MODEL_VERSION);
+ sr.registerXMLElementWriter(CURRENT_PARSER);
+ final ManagementResourceRegistration root = sr.registerSubsystemModel(new UnstableApiAnnotationTestSubsystemDefinition());
+ root.registerOperationHandler(GenericSubsystemDescribeHandler.DEFINITION, GenericSubsystemDescribeHandler.INSTANCE, false);
+ }
+
+ @Override
+ public void initializeParsers(ExtensionParsingContext extensionParsingContext) {
+ extensionParsingContext.setSubsystemXmlMapping(SUBSYSTEM_NAME, UnstableApiAnnotationTestSubsystemParser_1_0.NAMESPACE, CURRENT_PARSER);
+ }
+
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemDefinition.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemDefinition.java
new file mode 100644
index 00000000000..10807f7ce28
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemDefinition.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.subsystem;
+
+import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
+import org.jboss.as.controller.AttributeDefinition;
+import org.jboss.as.controller.ModelOnlyRemoveStepHandler;
+import org.jboss.as.controller.OperationContext;
+import org.jboss.as.controller.OperationFailedException;
+import org.jboss.as.controller.PersistentResourceDefinition;
+import org.jboss.as.controller.capability.RuntimeCapability;
+import org.jboss.as.controller.registry.ManagementResourceRegistration;
+import org.jboss.as.server.AbstractDeploymentChainStep;
+import org.jboss.as.server.DeploymentProcessorTarget;
+import org.jboss.dmr.ModelNode;
+import org.wildfly.core.test.unstable.api.annotation.classes._private.UnstableAnnotationApiTestLogger;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.jboss.as.controller.OperationContext.Stage.RUNTIME;
+import static org.jboss.as.server.deployment.Phase.DEPENDENCIES;
+
+/**
+ * @author Kabir Khan
+ */
+public class UnstableApiAnnotationTestSubsystemDefinition extends PersistentResourceDefinition {
+
+ private static final String UNSTABLE_API_ANNOTATION_SUBSYSTEM_CAPABILITY_NAME = "org.wildfly.core.test.unstable-api-annotation";
+
+ private static final RuntimeCapability CONTEXT_PROPAGATION_CAPABILITY = RuntimeCapability.Builder
+ .of(UNSTABLE_API_ANNOTATION_SUBSYSTEM_CAPABILITY_NAME)
+ .build();
+
+ public UnstableApiAnnotationTestSubsystemDefinition() {
+ super(
+ new Parameters(
+ UnstableApiAnnotationTestExtension.SUBSYSTEM_PATH,
+ UnstableApiAnnotationTestExtension.getResourceDescriptionResolver(UnstableApiAnnotationTestExtension.SUBSYSTEM_NAME))
+ .setAddHandler(AddHandler.INSTANCE)
+ .setRemoveHandler(new ModelOnlyRemoveStepHandler())
+ .setCapabilities(CONTEXT_PROPAGATION_CAPABILITY)
+ );
+ }
+
+ @Override
+ public Collection getAttributes() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public void registerAdditionalRuntimePackages(ManagementResourceRegistration resourceRegistration) {
+ super.registerAdditionalRuntimePackages(resourceRegistration);
+ }
+
+ static class AddHandler extends AbstractBoottimeAddStepHandler {
+
+ static AddHandler INSTANCE = new AddHandler();
+
+ private AddHandler() {
+ super();
+ }
+
+ @Override
+ protected void performBoottime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
+ super.performBoottime(context, operation, model);
+
+ context.addStep(new AbstractDeploymentChainStep() {
+ public void execute(DeploymentProcessorTarget processorTarget) {
+ final int DEPENDENCIES_TEMPLATE = 6304;
+ processorTarget.addDeploymentProcessor(UnstableApiAnnotationTestExtension.SUBSYSTEM_NAME, DEPENDENCIES, DEPENDENCIES_TEMPLATE, new UnstableApiAnnotationTestDependencyProcessor());
+ }
+ }, RUNTIME);
+
+ UnstableAnnotationApiTestLogger.LOGGER.activatingSubsystem();
+ }
+ }
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemParser_1_0.java b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemParser_1_0.java
new file mode 100644
index 00000000000..e6491612060
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/java/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/UnstableApiAnnotationTestSubsystemParser_1_0.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.classes.subsystem;
+
+import org.jboss.as.controller.PersistentResourceXMLDescription;
+import org.jboss.as.controller.PersistentResourceXMLParser;
+
+import static org.jboss.as.controller.PersistentResourceXMLDescription.builder;
+
+/**
+ * @author Kabir Khan
+ */
+public class UnstableApiAnnotationTestSubsystemParser_1_0 extends PersistentResourceXMLParser {
+
+ public static final String NAMESPACE = "urn:wildfly:unstable-api-annotation-test-subsystem:1.0";
+
+ private static final PersistentResourceXMLDescription xmlDescription = builder(UnstableApiAnnotationTestExtension.SUBSYSTEM_PATH, NAMESPACE)
+ .build();
+
+ @Override
+ public PersistentResourceXMLDescription getParserDescription() {
+ return xmlDescription;
+ }
+
+}
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
new file mode 100644
index 00000000000..1c2251e9c8e
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/META-INF/services/org.jboss.as.controller.Extension
@@ -0,0 +1,6 @@
+#
+# Copyright The WildFly Authors
+# SPDX-License-Identifier: Apache-2.0
+#
+
+org.wildfly.core.test.unstable.api.annotation.classes.subsystem.UnstableApiAnnotationTestExtension
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/LocalDescriptions.properties b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/LocalDescriptions.properties
new file mode 100644
index 00000000000..e95404c5de2
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/org/wildfly/core/test/unstable/api/annotation/classes/subsystem/LocalDescriptions.properties
@@ -0,0 +1,8 @@
+#
+# Copyright The WildFly Authors
+# SPDX-License-Identifier: Apache-2.0
+#
+
+unstable-api-annotation-test=The Unstable API Annotation Test subsystem
+unstable-api-annotation-test.add=Adds the Unstable API Annotation Test subsystem
+unstable-api-annotation-test.remove=Removes the Unstable API Annotation Test subsystem
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/schema/unstable-annotation-api-test-subsystem_1_0.xsd b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/schema/unstable-annotation-api-test-subsystem_1_0.xsd
new file mode 100644
index 00000000000..ce7523e6c3b
--- /dev/null
+++ b/testsuite/unstable-api-annotation/feature-pack/subsystem/src/main/resources/schema/unstable-annotation-api-test-subsystem_1_0.xsd
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/unstable-api-annotation/pom.xml b/testsuite/unstable-api-annotation/pom.xml
new file mode 100644
index 00000000000..eb5692c5d09
--- /dev/null
+++ b/testsuite/unstable-api-annotation/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ 4.0.0
+
+
+ org.wildfly.core
+ wildfly-core-testsuite
+ 25.0.0.Beta5-SNAPSHOT
+
+
+ wildfly-core-testsuite-unstable-api-annotation
+ pom
+
+ WildFly Core Test Suite: Unstable API Annotation Parent
+
+
+ feature-pack
+ tests
+
+
+
+
+
+ ${project.groupId}
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ zip
+ test
+ ${project.version}
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/tests/pom.xml b/testsuite/unstable-api-annotation/tests/pom.xml
new file mode 100644
index 00000000000..5fe61c58b65
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/pom.xml
@@ -0,0 +1,271 @@
+
+
+
+
+ 4.0.0
+
+
+ org.wildfly.core
+ wildfly-core-testsuite-unstable-api-annotation
+ 25.0.0.Beta5-SNAPSHOT
+
+
+ wildfly-core-testsuite-unstable-api-annotation-tests
+ jar
+
+ WildFly Core Test Suite: Unstable API Annotation Tests
+
+
+ ${basedir}/..
+ ${jbossas.ts.integ.dir}/..
+ ${jbossas.ts.dir}
+ ${project.basedir}/target/wildfly-core
+ nothing-to-exclude
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ ${exclude.tests}
+
+ false
+
+ ${testLogToFile}
+
+
+ ${jvm.args.ip.client} ${jvm.args.timeouts} ${surefire.system.args} -Djava.util.logging.manager=org.jboss.logmanager.LogManager
+
+
+ ${wildfly.home}
+
+ Hello world
+
+
+
+ ${modular.jdk.args} -Dmaven.repo.local=${settings.localRepository}
+ ${wildfly.home}
+
+ ${settings.localRepository}
+ -Dmaven.repo.local=${settings.localRepository} ${surefire.system.args} ${jvm.args.ip.server} ${jvm.args.security} ${jvm.args.other} ${jvm.args.timeouts} -Djbossas.ts.dir=${jbossas.ts.dir}
+
+
+
+
+ org.wildfly.plugins
+ wildfly-maven-plugin
+
+
+ server-provisioning
+
+ provision
+
+ compile
+
+ ${project.build.directory}/${server.output.dir.prefix}
+ false
+ ${galleon.log.time}
+ true
+ true
+
+
+ ${galleon.fork.embedded}
+ passive+
+
+
+
+ org.wildfly.core
+ wildfly-core-galleon-pack
+ ${project.version}
+ false
+ false
+
+
+ org.jboss.as.patching.cli
+
+
+ product.conf
+
+
+
+ org.wildfly.core
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ ${project.version}
+ false
+ false
+
+
+
+ core-server
+ core-tools
+ deployment-scanner
+ unstable-api-annotation-test
+
+
+
+
+
+
+
+
+
+
+
+ ${project.groupId}
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ zip
+ test
+
+
+ jakarta.inject
+ jakarta.inject-api
+ test
+
+
+ org.wildfly.core
+ wildfly-core-management-subsystem
+ test
+
+
+
+
+
+ layers.profile
+
+
+ ts.layers
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+ slimmed-server-surefire
+ test
+
+ test
+
+
+
+
+ org.wildfly.core.test.standalone.mgmt.api.core.ReadConfigAsFeaturesStandaloneTestCase.java
+
+ org.jboss.as.test.integration.credential.store.ManagementAuthenticationUsersTestCase.java
+
+
+
+
+
+
+
+
+
+
+
+ bootablejar.profile
+
+
+ ts.bootable
+
+
+
+
+
+ org.wildfly.plugins
+ wildfly-maven-plugin
+
+
+
+ server-provisioning
+
+ provision
+
+ none
+
+
+
+
+ org.wildfly.plugins
+ wildfly-jar-maven-plugin
+
+
+
+ bootable-jar-packaging
+
+ package
+
+ compile
+
+ test-wildfly.jar
+ true
+ false
+ ${galleon.log.time}
+ true
+
+
+ ${galleon.fork.embedded}
+
+
+
+ org.wildfly.core
+ wildfly-core-galleon-pack
+ ${project.version}
+
+
+ org.wildfly.core
+ wildfly-core-testsuite-unstable-api-annotation-feature-pack
+ ${project.version}
+
+
+
+ core-server
+ core-tools
+ deployment-scanner
+ unstable-api-annotation-test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+ bootable-server-surefire
+ test
+
+ test
+
+
+
+ true
+ ${project.build.directory}/test-wildfly.jar
+ ${project.build.directory}/${server.output.dir.prefix}
+
+
+
+
+
+
+
+
+
+
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/UnstableApiAnnotationScannerTestCase.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/UnstableApiAnnotationScannerTestCase.java
new file mode 100644
index 00000000000..7d6caf9488f
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/UnstableApiAnnotationScannerTestCase.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter;
+
+import jakarta.inject.Inject;
+import org.jboss.as.controller.PathAddress;
+import org.jboss.as.controller.client.ModelControllerClient;
+import org.jboss.as.controller.client.Operation;
+import org.jboss.as.controller.operations.common.Util;
+import org.jboss.as.test.integration.management.ManagementOperations;
+import org.jboss.as.test.integration.management.util.MgmtOperationException;
+import org.jboss.as.test.integration.management.util.ServerReload;
+import org.jboss.dmr.ModelNode;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotatedField;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotatedMethod;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotationForExtends;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotationForUsage;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestInterfaceWithAnnotation;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedAnnotationUsage;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedClassExtendsUsage;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedClassUsage;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedFieldUsage;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedInterfaceImplementsUsage;
+import org.wildfly.core.test.unstable.api.annotation.reporter.classes.AnnotatedMethodUsage;
+import org.wildfly.core.testrunner.ManagementClient;
+import org.wildfly.core.testrunner.ServerSetup;
+import org.wildfly.core.testrunner.ServerSetupTask;
+import org.wildfly.core.testrunner.WildFlyRunner;
+import org.wildfly.extension.core.management.CoreManagementExtension;
+import org.wildfly.extension.core.management.UnstableApiAnnotationResourceDefinition;
+import org.wildfly.test.stability.StabilityServerSetupSnapshotRestoreTasks;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION;
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SYSTEM_PROPERTY;
+
+@RunWith(WildFlyRunner.class)
+@ServerSetup({UnstableApiAnnotationScannerTestCase.AddUnstableApiAnnotationResourceSetupTask.class, UnstableApiAnnotationScannerTestCase.SystemPropertyServerSetupTask.class})
+public class UnstableApiAnnotationScannerTestCase {
+
+ @Inject
+ private ManagementClient managementClient;
+
+ private static final String INDEX_MODULE_DIR =
+ "system/layers/base/org/wildfly/_internal/unstable-api-annotation-index/main";
+
+ private static final String CONTENT = "content";
+ private static final String INDEX_INDEX_FILE = "index.txt";
+
+ private static final String TEST_FEATURE_PACK_INDEX = "wildfly-core-testsuite-unstable-api-annotation-feature-pack.txt";
+
+ @Test
+ public void testIndexExists() throws Exception {
+ String jbossHomeProp = System.getProperty("jboss.home");
+
+ Path jbossHome = Paths.get(jbossHomeProp);
+ Assert.assertTrue(Files.exists(jbossHome));
+
+ Path modulesPath = jbossHome.resolve("modules");
+ Assert.assertTrue(Files.exists(modulesPath));
+
+ Path indexModulePath = modulesPath.resolve(INDEX_MODULE_DIR);
+ Assert.assertTrue(Files.exists(indexModulePath));
+
+ Path indexContentDir = indexModulePath.resolve(CONTENT);
+ Assert.assertTrue(Files.exists(indexContentDir));
+
+ Path mainIndexFile = indexContentDir.resolve(INDEX_INDEX_FILE);
+ Assert.assertTrue(Files.exists(mainIndexFile));
+
+ List mainIndexFileList = Files.readAllLines(mainIndexFile)
+ .stream()
+ .filter(s -> !s.isEmpty())
+ .filter(s -> !s.startsWith("#"))
+ .collect(Collectors.toList());
+
+ Assert.assertEquals(1, mainIndexFileList.size());
+ Assert.assertTrue(mainIndexFileList.contains(TEST_FEATURE_PACK_INDEX));
+
+ Set indices = Files.list(indexContentDir)
+ .filter(p -> !p.getFileName().toString().equals(INDEX_INDEX_FILE))
+ .map(p -> p.getFileName().toString())
+ .collect(Collectors.toSet());
+
+ Assert.assertEquals(1, indices.size());
+ Assert.assertTrue(indices.toString(), indices.contains(TEST_FEATURE_PACK_INDEX));
+ }
+
+ @Test
+ public void testDeploymentWarning() throws Exception {
+ LogDiffer logDiffer = new LogDiffer();
+ logDiffer.takeSnapshot();
+
+
+ JavaArchive deployment = createDeploymentWithUnstableAnnotations();
+ ModelControllerClient mcc = managementClient.getControllerClient();
+ Operation deploymentOp = createDeploymentOp(deployment);
+
+ try {
+ ManagementOperations.executeOperation(mcc, deploymentOp);
+ List newLogEntries = logDiffer.getNewLogEntries();
+ Assert.assertFalse(newLogEntries.isEmpty());
+ Assert.assertEquals(8, newLogEntries.size());
+ checkExpectedNumberClasses(newLogEntries, 6);
+
+ checkLogOrErrorLines(newLogEntries);
+ } finally {
+ ManagementOperations.executeOperation(mcc, Util.createRemoveOperation(PathAddress.pathAddress("deployment", deployment.getName())));
+ }
+
+ }
+
+ @Test
+ public void testDeploymentError() throws Exception{
+ JavaArchive deployment = createDeploymentWithUnstableAnnotations();
+ ModelControllerClient mcc = managementClient.getControllerClient();
+
+ PathAddress address = PathAddress.pathAddress(CoreManagementExtension.SUBSYSTEM_PATH)
+ .append(UnstableApiAnnotationResourceDefinition.PATH);
+ ModelNode writeAttributeOp = Util.getWriteAttributeOperation(address,
+ UnstableApiAnnotationResourceDefinition.LEVEL.getName(),
+ UnstableApiAnnotationResourceDefinition.UnstableApiAnnotationLevel.ERROR.toString());
+ try {
+ ManagementOperations.executeOperation(mcc, writeAttributeOp);
+ ServerReload.executeReloadAndWaitForCompletion(mcc, false);
+
+ boolean deployed = false;
+ Operation deploymentOp = createDeploymentOp(deployment);
+ try {
+ ManagementOperations.executeOperation(mcc, deploymentOp);
+ deployed = true;
+ Assert.fail("Expected deployment to fail");
+ } catch (MgmtOperationException expected) {
+ String error = expected.getResult().get(FAILURE_DESCRIPTION).asString();
+ List lines = Arrays.asList(error.split("\n"));
+
+
+ } finally {
+ if (deployed) {
+ ManagementOperations.executeOperation(mcc, Util.createRemoveOperation(PathAddress.pathAddress("deployment", deployment.getName())));
+ }
+ }
+
+
+ } finally {
+ ManagementOperations.executeOperation(mcc, Util.getUndefineAttributeOperation(address, UnstableApiAnnotationResourceDefinition.LEVEL.getName()));
+ ServerReload.executeReloadAndWaitForCompletion(mcc, false);
+ }
+
+ LogDiffer logDiffer = new LogDiffer();
+ logDiffer.takeSnapshot();
+ // Deploy a deployment with unstable annotations
+ // Check that the log contains the expected warning
+ }
+
+ @Test
+ public void testNoWarmingIfUnstableApiAnnotationResourceIsNotDefined() throws Exception {
+
+
+ PathAddress address = PathAddress.pathAddress(CoreManagementExtension.SUBSYSTEM_PATH)
+ .append(UnstableApiAnnotationResourceDefinition.PATH);
+ ModelNode removeOp = Util.createRemoveOperation(address);
+ ManagementOperations.executeOperation(managementClient.getControllerClient(), removeOp);
+ try {
+ ServerReload.executeReloadAndWaitForCompletion(managementClient.getControllerClient());
+
+ LogDiffer logDiffer = new LogDiffer();
+ logDiffer.takeSnapshot();
+
+ JavaArchive deployment = createDeploymentWithUnstableAnnotations();
+ ModelControllerClient mcc = managementClient.getControllerClient();
+ Operation deploymentOp = createDeploymentOp(deployment);
+
+ try {
+ ManagementOperations.executeOperation(mcc, deploymentOp);
+ List newLogEntries = logDiffer.getNewLogEntries();
+ Assert.assertTrue(newLogEntries.isEmpty());
+ } finally {
+ ManagementOperations.executeOperation(mcc, Util.createRemoveOperation(PathAddress.pathAddress("deployment", deployment.getName())));
+ }
+
+ } finally {
+ ModelNode addOp = Util.createAddOperation(address);
+ ManagementOperations.executeOperation(managementClient.getControllerClient(), addOp);
+ ServerReload.executeReloadAndWaitForCompletion(managementClient.getControllerClient());
+ }
+ }
+
+ private void checkLogOrErrorLines(List lines) {
+ checkLogLine(lines.get(1), "WFLYCM0009", "deployment-with-unstable-annotations.jar");
+ checkLogLine(lines.get(2), "WFLYCM0010",
+ AnnotatedClassExtendsUsage.class.getName(),
+ TestClassWithAnnotationForExtends.class.getName());
+ checkLogLine(lines.get(3), "WFLYCM0011",
+ AnnotatedInterfaceImplementsUsage.class.getName(),
+ TestInterfaceWithAnnotation.class.getName());
+ checkLogLine(lines.get(4), "WFLYCM0012",
+ AnnotatedFieldUsage.class.getName(),
+ TestClassWithAnnotatedField.class.getName() + ".annotatedField");
+ checkLogLine(lines.get(5), "WFLYCM0013",
+ AnnotatedMethodUsage.class.getName(),
+ TestClassWithAnnotatedMethod.class.getName() + ".annotatedMethod()V");
+ checkLogLine(lines.get(6), "WFLYCM0014",
+ AnnotatedClassUsage.class.getName(),
+ TestClassWithAnnotationForUsage.class.getName());
+ checkLogLine(lines.get(7), "WFLYCM0015",
+ AnnotatedAnnotationUsage.class.getName());
+ }
+
+
+
+ private void checkExpectedNumberClasses(List newLogEntries, int numberClasses) {
+ Assert.assertTrue(!newLogEntries.isEmpty());
+ String last = newLogEntries.get(0);
+ checkLogLine(last, "WFLYCM0016", String.valueOf(numberClasses));
+ }
+
+ private void checkLogLine(String logLine, String loggingId, String...values) {
+ int index = logLine.indexOf(loggingId);
+ Assert.assertTrue("'" + logLine + "' does not contain '" + loggingId + "'",index != -1);
+ index += loggingId.length();
+ Assert.assertTrue(index < logLine.length());
+ String valuesPart = logLine.substring(index);
+ Set words = new HashSet<>(Arrays.asList(logLine.split(" ")));
+ for (String value : values) {
+ Assert.assertTrue("'" + logLine + "' does not contain '" + value + "'", words.contains(value));
+ }
+ }
+
+ private JavaArchive createDeploymentWithUnstableAnnotations() {
+ JavaArchive archive = ShrinkWrap.create(JavaArchive.class, "deployment-with-unstable-annotations.jar")
+ .addPackage(AnnotatedClassExtendsUsage.class.getPackage());
+
+ return archive;
+ }
+
+ private Operation createDeploymentOp(JavaArchive deployment) {
+ final List streams = new ArrayList<>();
+ streams.add(deployment.as(ZipExporter.class).exportAsInputStream());
+ final ModelNode addOperation = Util.createAddOperation(PathAddress.pathAddress("deployment", deployment.getName()));
+ addOperation.get("enabled").set(true);
+ addOperation.get("content").add().get("input-stream-index").set(0);
+ return Operation.Factory.create(addOperation, streams, true);
+ }
+
+ private static class LogDiffer {
+ Path logFile;
+
+ private List lastLogSnapshot = Collections.emptyList();
+
+
+ public LogDiffer() {
+ String jbossHomeProp = System.getProperty("jboss.home");
+ Path jbossHome = Paths.get(jbossHomeProp);
+ Assert.assertTrue(Files.exists(jbossHome));
+ this.logFile = jbossHome.resolve("standalone/log/server.log");
+ Assert.assertTrue(Files.exists(logFile));
+ }
+
+ public void takeSnapshot() {
+ try {
+ lastLogSnapshot = Files.readAllLines(logFile);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public List getNewLogEntries() {
+ try {
+ List currentLog = Files.readAllLines(logFile);
+ return currentLog.stream()
+ .filter(s -> !lastLogSnapshot.contains(s))
+ .filter(s -> s.contains("WFLYCM"))
+ .collect(Collectors.toList());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ }
+
+
+ public static class AddUnstableApiAnnotationResourceSetupTask extends StabilityServerSetupSnapshotRestoreTasks.Preview {
+ @Override
+ public void doSetup(ManagementClient managementClient) throws Exception {
+ PathAddress address = PathAddress.pathAddress(CoreManagementExtension.SUBSYSTEM_PATH)
+ .append(UnstableApiAnnotationResourceDefinition.PATH);
+ ModelNode addOp = Util.createAddOperation(address);
+ ManagementOperations.executeOperation(managementClient.getControllerClient(), addOp);
+ ServerReload.executeReloadAndWaitForCompletion(managementClient.getControllerClient());
+ }
+ }
+
+
+ public static class SystemPropertyServerSetupTask implements ServerSetupTask {
+ @Override
+ public void setup(ManagementClient managementClient) throws Exception {
+ ModelNode op = Util.createAddOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, "org.wildfly.test.unstable-api-annotation.extra-output"));
+ op.get("value").set("true");
+ ManagementOperations.executeOperation(managementClient.getControllerClient(), op);
+ // Reload so the system property is picked up by the deployer in order to print extra information
+ // about class count
+ ServerReload.executeReloadAndWaitForCompletion(managementClient.getControllerClient());
+ }
+
+ @Override
+ public void tearDown(ManagementClient managementClient) throws Exception {
+ ModelNode op = Util.createAddOperation(PathAddress.pathAddress(SYSTEM_PROPERTY, "org.wildfly.test.unstable-api-annotation.extra-output"));
+ op.get("value").set("true");
+ managementClient.getControllerClient().execute(op);
+ }
+ }
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedAnnotationUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedAnnotationUsage.java
new file mode 100644
index 00000000000..a7fb3d13a17
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedAnnotationUsage.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.AnnotatedAnnotation;
+
+@AnnotatedAnnotation
+public class AnnotatedAnnotationUsage {
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassExtendsUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassExtendsUsage.java
new file mode 100644
index 00000000000..5b3dc407fee
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassExtendsUsage.java
@@ -0,0 +1,12 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotationForExtends;
+
+public class AnnotatedClassExtendsUsage extends TestClassWithAnnotationForExtends {
+
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassUsage.java
new file mode 100644
index 00000000000..fb1b61ba082
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedClassUsage.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotationForUsage;
+import org.wildfly.core.test.unstable.api.annotation.classes.api.Unstable;
+
+@Unstable
+public class AnnotatedClassUsage {
+
+ public void test(TestClassWithAnnotationForUsage clazz) {
+ clazz.methodWithNoAnnotation();
+ }
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedFieldUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedFieldUsage.java
new file mode 100644
index 00000000000..29855bf8daf
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedFieldUsage.java
@@ -0,0 +1,15 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotatedField;
+
+public class AnnotatedFieldUsage {
+
+ public void test() {
+ TestClassWithAnnotatedField.annotatedField = 10;
+ }
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedInterfaceImplementsUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedInterfaceImplementsUsage.java
new file mode 100644
index 00000000000..50a530cb649
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedInterfaceImplementsUsage.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestInterfaceWithAnnotation;
+
+public class AnnotatedInterfaceImplementsUsage implements TestInterfaceWithAnnotation {
+
+
+}
diff --git a/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedMethodUsage.java b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedMethodUsage.java
new file mode 100644
index 00000000000..f6107bb3d54
--- /dev/null
+++ b/testsuite/unstable-api-annotation/tests/src/test/java/org/wildfly/core/test/unstable/api/annotation/reporter/classes/AnnotatedMethodUsage.java
@@ -0,0 +1,14 @@
+/*
+ * Copyright The WildFly Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.wildfly.core.test.unstable.api.annotation.reporter.classes;
+
+import org.wildfly.core.test.unstable.api.annotation.classes.api.TestClassWithAnnotatedMethod;
+
+public class AnnotatedMethodUsage {
+ public void test() {
+ TestClassWithAnnotatedMethod.annotatedMethod();
+ }
+}