Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for Issue #98, Introduce a rule that discover layer based on an Annotated type #99

Merged
merged 1 commit into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
<groupId>org.wildfly.channel</groupId>
<artifactId>channel-core</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
Expand Down
61 changes: 61 additions & 0 deletions core/src/main/java/org/wildfly/glow/AnnotatedType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.glow;

import java.util.Map;

/**
* Contains the content of the rule that identify layers based on an annotated type.
* @author jdenise
*/
public class AnnotatedType {

private final String type;
private final Map<String, String> fields;
private final String annotation;
private final Layer layer;

/**
*
* @param type The java type
* @param annotation The annotation applied to the type
* @param fields Annotation field values (can be empty).
* @param layer The layer associated to the rule.
*/
public AnnotatedType(String type, String annotation, Map<String, String> fields, Layer layer) {
this.type = type;
this.annotation = annotation;
this.fields = fields;
this.layer = layer;
}

/**
* @return The annotation full class name.
*/
public String getAnnotation() {
return annotation;
}

/**
* @return The annotation fields.
*/
public Map<String, String> getFields() {
return fields;
}

/**
* @return The layer
*/
public Layer getLayer() {
return layer;
}

/**
* @return The java type.
*/
public String getType() {
return type;
}
}
33 changes: 33 additions & 0 deletions core/src/main/java/org/wildfly/glow/DeploymentScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,39 @@ private void scanAnnotations(DeploymentScanContext ctx) throws IOException {
// DataSourceDefinition are only added based on layers discovered in the above nested loop.
handleDataSourceDefinitionAnnotations(ai, ctx, foundLayer);
}
if (ai.target().kind() == AnnotationTarget.Kind.FIELD) {
Map<String, List<AnnotatedType>> annotatedTypes = ctx.mapping.getAnnotatedTypes().get(ai.name().toString());
if (annotatedTypes != null) {
String type = ai.target().asField().type().toString();
List<AnnotatedType> annotations = annotatedTypes.get(type);
if (annotations != null) {
for (AnnotatedType at : annotations) {
if (at.getFields().isEmpty()) {
LayerMapping.addRule(LayerMapping.RULE.ANNOTATED_TYPE, at.getLayer(), "@" + ai.name().toString() + "\n" + at.getType());
ctx.layers.add(at.getLayer());
} else {
for (Entry<String, String> entry : at.getFields().entrySet()) {
String val = getAnnotationValue(ai, entry.getKey());
if (val != null) {
if (Utils.isPattern(entry.getValue())) {
Pattern p = Pattern.compile(entry.getValue());
if (p.matcher(val).matches()) {
LayerMapping.addRule(LayerMapping.RULE.ANNOTATED_TYPE, at.getLayer(), "@" + ai.name().toString() + "_" + entry.getKey() + "=" + entry.getValue());
ctx.layers.add(at.getLayer());
}
} else {
if (val.equals(entry.getValue())) {
LayerMapping.addRule(LayerMapping.RULE.ANNOTATED_TYPE, at.getLayer(), "@" + ai.name().toString() + entry.getKey() + "=" + entry.getValue() + "\n" + at.getType());
ctx.layers.add(at.getLayer());
}
}
}
}
}
}
}
}
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/org/wildfly/glow/LayerMapping.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public enum RULE {
ALWAYS_INCLUDED,
ANNOTATION,
ANNOTATION_VALUE,
ANNOTATED_TYPE,
BASE_LAYER,
BRING_DATASOURCE,
EXPECTED_FILE,
Expand All @@ -51,6 +52,7 @@ public enum RULE {
private final Map<String, Set<Layer>> constantPoolClassInfos = new HashMap<>();
private final Map<String, Set<Layer>> annotations = new HashMap<>();
private final Map<String, Map<String, List<AnnotationFieldValue>>> annotationFieldValues = new HashMap<>();
private final Map<String, Map<String, List<AnnotatedType>>> annotatedTypes = new HashMap<>();
private final Map<String, Layer> activeProfilesLayers = new HashMap<>();
private final Map<String, Set<Layer>> allProfilesLayers = new HashMap<>();
private Layer defaultBaseLayer;
Expand Down Expand Up @@ -183,6 +185,10 @@ public Map<String, Map<String, List<AnnotationFieldValue>>> getAnnotationFieldVa
return annotationFieldValues;
}

public Map<String, Map<String, List<AnnotatedType>>> getAnnotatedTypes() {
return annotatedTypes;
}

public static String cleanupKey(String key) {
if (key.startsWith(LayerMetadata.HIDDEN_IF)) {
key = key.substring(key.indexOf(LayerMetadata.HIDDEN_IF) + LayerMetadata.HIDDEN_IF.length() + 1, key.length());
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/wildfly/glow/LayerMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public abstract class LayerMetadata {
public static final String ADD_ON_DEPENDS_ON = PREFIX + "add-on-depends-on";
public static final String ADD_ON_DESCRIPTION = PREFIX + "add-on-description";
public static final String ADD_ON_FIX = PREFIX + "add-on-fix-";
public static final String ANNOTATED_TYPE = PREFIX + "annotated.type";
public static final String ANNOTATIONS = PREFIX + "annotations";
public static final String ANNOTATION_FIELD_VALUE = PREFIX + "annotation.field.value";
public static final String BRING_DATASOURCE = PREFIX + "bring-datasource";
Expand All @@ -59,6 +60,7 @@ public abstract class LayerMetadata {
FULLY_NAMED_RULES.add(ADD_ON_DEPENDS_ON);
FULLY_NAMED_RULES.add(ADD_ON_DESCRIPTION);

FULLY_NAMED_RULES.add(ANNOTATED_TYPE);
FULLY_NAMED_RULES.add(ANNOTATIONS);
FULLY_NAMED_RULES.add(BRING_DATASOURCE);
FULLY_NAMED_RULES.add(CLASS);
Expand Down
70 changes: 70 additions & 0 deletions core/src/main/java/org/wildfly/glow/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,14 @@ public static LayerMapping buildMapping(Map<String, Layer> layers, Set<String> p
}
continue;
}
if (LayerMetadata.ANNOTATED_TYPE.equals(k)) {
String val = l.getProperties().get(k);
AnnotatedType type = parseAnnotatedType(val, l);
Map<String, List<AnnotatedType>> annotations = mapping.getAnnotatedTypes().computeIfAbsent(type.getAnnotation(), value -> new HashMap<>());
List<AnnotatedType> lst = annotations.computeIfAbsent(type.getType(), value -> new ArrayList<>());
lst.add(type);
continue;
}
if (k.startsWith(LayerMetadata.ANNOTATION_FIELD_VALUE)) {
String val = l.getProperties().get(k);
int i = val.indexOf(",");
Expand Down Expand Up @@ -610,6 +618,68 @@ public static LayerMapping buildMapping(Map<String, Layer> layers, Set<String> p
return mapping;
}

static final AnnotatedType parseAnnotatedType(String val, Layer layer) {
int i = val.indexOf(",");
String type = val.substring(0, i);
String fullAnnotation = val.substring(i + 1);
String annotationClass = fullAnnotation;
int fieldsIndex = fullAnnotation.indexOf("[");
Map<String, String> parsedFields = Collections.emptyMap();
if (fieldsIndex != -1) {
annotationClass = fullAnnotation.substring(0, fieldsIndex);
String fields = fullAnnotation.substring(fieldsIndex);
parsedFields = parseAnnotationFields(fields);
}
return new AnnotatedType(type, annotationClass, parsedFields, layer);
}

private static final Map<String, String> parseAnnotationFields(String fields) {
boolean expectField = true;
boolean expectValue = false;
boolean escape = false;
StringBuilder fieldBuilder = new StringBuilder();
StringBuilder valueBuilder = new StringBuilder();
Map<String, String> map = new HashMap<>();
for(int i = 0; i < fields.length(); i ++) {
char c = fields.charAt(i);
if (expectField && c == '[') {
continue;
}
if (c == '=' && expectField) {
expectField = false;
expectValue = true;
continue;
}
if (expectField) {
fieldBuilder.append(c);
continue;
}
if (c == '\\' && !escape) {
escape = true;
continue;
}
if (!escape && expectValue && (c == ']' || c == ',')) {
String value = valueBuilder.toString();
if(isPattern(value)) {
value = escapePattern(value);
}
String field = fieldBuilder.toString();
valueBuilder = new StringBuilder();
fieldBuilder = new StringBuilder();
map.put(field, value);
expectValue = false;
expectField = true;
continue;
}
if (expectValue) {
valueBuilder.append(c);
escape = false;
continue;
}
}
return map;
}

private static Set<String> getProfiles(Set<String> profiles, String k, Layer l) {
Set<String> ret = new TreeSet<>();
for (String p : profiles) {
Expand Down
46 changes: 46 additions & 0 deletions core/src/test/java/org/wildfly/glow/UtilsTestCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/
package org.wildfly.glow;

import java.util.Map;
import org.junit.Assert;
import org.junit.Test;

/**
*
* @author jdenise
*/
public class UtilsTestCase {
@Test
public void testParseAnnotationFields() {
{
String str = "type,annotation";
AnnotatedType type = Utils.parseAnnotatedType(str, null);
Assert.assertEquals("type", type.getType());
Assert.assertEquals("annotation", type.getAnnotation());
Assert.assertEquals(0, type.getFields().size());
}
{
String fields = "type,annotation[foo=bar]";
Map<String, String> results = Utils.parseAnnotatedType(fields, null).getFields();
Assert.assertEquals(1, results.size());
Assert.assertEquals("bar", results.get("foo"));
}
{
String fields = "type,annotation[foo=bar,foo2=bar2]";
Map<String, String> results = Utils.parseAnnotatedType(fields, null).getFields();
Assert.assertEquals(2, results.size());
Assert.assertEquals("bar", results.get("foo"));
Assert.assertEquals("bar2", results.get("foo2"));
}
{
String fields = "type,annotation[foo=bar*,foo2=\\=b\\,a\\]r2]";
Map<String, String> results = Utils.parseAnnotatedType(fields, null).getFields();
Assert.assertEquals(2, results.size());
Assert.assertEquals("bar.*", results.get("foo"));
Assert.assertEquals("=b,a]r2", results.get("foo2"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!--
~ Copyright The WildFly Authors
~ SPDX-License-Identifier: Apache-2.0
-->

<layer-spec xmlns="urn:jboss:galleon:layer-spec:2.0" name="annotated-type">
<props>
<prop name="org.wildfly.rule.annotated.type" value="java.lang.Object,org.wildfly.glow.test.rules.classes.annotation.field.value.FieldValue[prop=coco]"/>

</props>
</layer-spec>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.glow.rules.test.annotated.type;

import org.junit.Test;
import org.wildfly.glow.rules.test.AbstractLayerMetaDataTestCase;

public class AnnotatedTypeTestCase extends AbstractLayerMetaDataTestCase {

@Test
public void testValueAnnotationUsage() {
testSingleClassWar(AnnotatedTypeUsage.class, "annotated-type");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.glow.rules.test.annotated.type;

import org.wildfly.glow.test.rules.classes.annotation.field.value.FieldValue;


public class AnnotatedTypeUsage {
@FieldValue(prop = "coco")
private Object foo;
}