Skip to content

Commit

Permalink
Merge pull request #99 from jfdenise/issue_98
Browse files Browse the repository at this point in the history
Fix for Issue #98, Introduce a rule that discover layer based on an Annotated type
  • Loading branch information
jfdenise authored Nov 26, 2024
2 parents 6cd2239 + 7871ff2 commit e93e22b
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 0 deletions.
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;
}

0 comments on commit e93e22b

Please sign in to comment.