Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.rhocas.featuregen.ap.FeatureIDEFeaturesProcessor Maven / Gradle / Ivy
package de.rhocas.featuregen.ap;
import com.google.common.base.Objects;
import de.rhocas.featuregen.ap.FeatureIDEFeatures;
import de.rhocas.featuregen.ap.FeatureNameConverter;
import de.rhocas.featuregen.ap.NameProvider;
import de.rhocas.featuregen.featureide.model.feature.BranchedFeatureType;
import de.rhocas.featuregen.featureide.model.feature.FeatureModel;
import de.rhocas.featuregen.featureide.model.feature.FeatureModelType;
import de.rhocas.featuregen.featureide.model.feature.FeatureType;
import de.rhocas.featuregen.featureide.model.feature.StructType;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import org.eclipse.xtend.lib.macro.AbstractClassProcessor;
import org.eclipse.xtend.lib.macro.RegisterGlobalsContext;
import org.eclipse.xtend.lib.macro.TransformationContext;
import org.eclipse.xtend.lib.macro.declaration.AnnotationReference;
import org.eclipse.xtend.lib.macro.declaration.ClassDeclaration;
import org.eclipse.xtend.lib.macro.declaration.EnumerationTypeDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableAnnotationTypeDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableAnnotationTypeElementDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableConstructorDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableEnumerationTypeDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableEnumerationValueDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableInterfaceDeclaration;
import org.eclipse.xtend.lib.macro.declaration.MutableMethodDeclaration;
import org.eclipse.xtend.lib.macro.declaration.Type;
import org.eclipse.xtend.lib.macro.declaration.TypeReference;
import org.eclipse.xtend.lib.macro.declaration.Visibility;
import org.eclipse.xtend.lib.macro.file.FileLocations;
import org.eclipse.xtend.lib.macro.file.FileSystemSupport;
import org.eclipse.xtend.lib.macro.file.Path;
import org.eclipse.xtend.lib.macro.services.AnnotationReferenceBuildContext;
import org.eclipse.xtend2.lib.StringConcatenation;
import org.eclipse.xtend2.lib.StringConcatenationClient;
import org.eclipse.xtext.xbase.lib.Exceptions;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.xtext.xbase.lib.Functions.Function0;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
/**
* This is the annotation processor for {@link FeatureIDEFeatures}.
*
* @author Nils Christian Ehmke
*
* @since 1.0.0
*/
@SuppressWarnings("all")
public final class FeatureIDEFeaturesProcessor extends AbstractClassProcessor {
@Extension
private final NameProvider _nameProvider = new NameProvider();
@Extension
private final FeatureNameConverter _featureNameConverter = new FeatureNameConverter();
private final JAXBContext jaxbContext = new Function0() {
public JAXBContext apply() {
try {
JAXBContext _newInstance = JAXBContext.newInstance(FeatureModel.class);
return _newInstance;
} catch (Throwable _e) {
throw Exceptions.sneakyThrow(_e);
}
}
}.apply();
@Override
public void doRegisterGlobals(final ClassDeclaration annotatedClass, @Extension final RegisterGlobalsContext context) {
final AnnotationReference annotationReference = annotatedClass.findAnnotation(context.findUpstreamType(FeatureIDEFeatures.class));
final Path modelFilePath = this.findModelFilePath(annotatedClass, annotationReference, context);
boolean _isFile = context.isFile(modelFilePath);
if (_isFile) {
final FeatureModelType featureModel = this.readFeatureModel(modelFilePath, context);
this.registerFeatureCheckService(annotatedClass, featureModel, context);
this.registerSelectedFeatures(annotatedClass, featureModel, context);
this.registerFeature(annotatedClass, featureModel, context);
this.registerVariant(annotatedClass, featureModel, context);
}
}
private Path findModelFilePath(final ClassDeclaration annotatedClass, final AnnotationReference annotationReference, @Extension final FileLocations context) {
String value = annotationReference.getStringValue("value");
boolean _equals = Objects.equal(value, "");
if (_equals) {
value = "model.xml";
}
Path path = null;
boolean _startsWith = value.startsWith("/");
if (_startsWith) {
path = context.getProjectFolder(annotatedClass.getCompilationUnit().getFilePath());
} else {
path = annotatedClass.getCompilationUnit().getFilePath().getParent();
}
return path.append("/").append(value);
}
private FeatureModelType readFeatureModel(final Path modelFilePath, @Extension final FileSystemSupport fileSystemSupport) {
try {
final Unmarshaller unmarshaller = this.jaxbContext.createUnmarshaller();
final InputStream stream = fileSystemSupport.getContentsAsStream(modelFilePath);
try {
Object _unmarshal = unmarshaller.unmarshal(stream);
return ((FeatureModelType) _unmarshal);
} finally {
stream.close();
}
} catch (Throwable _e) {
throw Exceptions.sneakyThrow(_e);
}
}
private void registerFeatureCheckService(final ClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final RegisterGlobalsContext context) {
final FeatureType root = this.getRoot(featureModel);
if ((root != null)) {
context.registerClass(this._nameProvider.getFullQualifiedFeatureCheckServiceClassName(annotatedClass, root.getName()));
}
}
private FeatureType getRoot(final FeatureModelType model) {
FeatureType _xblockexpression = null;
{
final StructType struct = model.getStruct();
FeatureType _xifexpression = null;
FeatureType _feature = struct.getFeature();
boolean _tripleNotEquals = (_feature != null);
if (_tripleNotEquals) {
_xifexpression = struct.getFeature();
} else {
BranchedFeatureType _xifexpression_1 = null;
BranchedFeatureType _and = struct.getAnd();
boolean _tripleNotEquals_1 = (_and != null);
if (_tripleNotEquals_1) {
_xifexpression_1 = struct.getAnd();
} else {
BranchedFeatureType _xifexpression_2 = null;
BranchedFeatureType _or = struct.getOr();
boolean _tripleNotEquals_2 = (_or != null);
if (_tripleNotEquals_2) {
_xifexpression_2 = struct.getOr();
} else {
_xifexpression_2 = struct.getAlt();
}
_xifexpression_1 = _xifexpression_2;
}
_xifexpression = _xifexpression_1;
}
_xblockexpression = _xifexpression;
}
return _xblockexpression;
}
private void registerSelectedFeatures(final ClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final RegisterGlobalsContext context) {
final FeatureType root = this.getRoot(featureModel);
if ((root != null)) {
context.registerAnnotationType(this._nameProvider.getFullQualifiedSelectedFeaturesAnnotationName(annotatedClass, root.getName()));
}
}
private void registerFeature(final ClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final RegisterGlobalsContext context) {
final FeatureType root = this.getRoot(featureModel);
if ((root != null)) {
context.registerEnumerationType(this._nameProvider.getFullQualifiedFeaturesEnumName(annotatedClass, root.getName()));
}
}
private void registerVariant(final ClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final RegisterGlobalsContext context) {
final FeatureType root = this.getRoot(featureModel);
if ((root != null)) {
context.registerInterface(this.getVariantName(annotatedClass, root));
}
}
private String getVariantName(final ClassDeclaration annotatedClass, final FeatureType root) {
StringConcatenation _builder = new StringConcatenation();
String _packageName = annotatedClass.getCompilationUnit().getPackageName();
_builder.append(_packageName);
_builder.append(".");
String _name = root.getName();
_builder.append(_name);
_builder.append("Variant");
return _builder.toString();
}
@Override
public void doTransform(final MutableClassDeclaration annotatedClass, @Extension final TransformationContext context) {
this.makeFinal(annotatedClass);
final AnnotationReference annotationReference = annotatedClass.findAnnotation(context.findTypeGlobally(FeatureIDEFeatures.class));
final Path modelFilePath = this.findModelFilePath(annotatedClass, annotationReference, context);
boolean _isFile = context.isFile(modelFilePath);
if (_isFile) {
final FeatureModelType featureModel = this.readFeatureModel(modelFilePath, context);
this.transformFeature(annotatedClass, featureModel, context);
this.transformSelectedFeatures(annotatedClass, featureModel, context);
this.transformVariant(annotatedClass, featureModel, context);
this.transformFeatureCheckService(annotatedClass, featureModel, context);
} else {
StringConcatenation _builder = new StringConcatenation();
_builder.append("The model file could not be found (Assumed path was: \'");
_builder.append(modelFilePath);
_builder.append("\').");
context.addError(annotatedClass, _builder.toString());
}
}
private void makeFinal(final MutableClassDeclaration annotatedClass) {
annotatedClass.setFinal(true);
}
private MutableMethodDeclaration transformFeatureCheckService(final MutableClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final TransformationContext context) {
MutableMethodDeclaration _xblockexpression = null;
{
final FeatureType root = this.getRoot(featureModel);
final MutableClassDeclaration featureCheckService = context.findClass(this._nameProvider.getFullQualifiedFeatureCheckServiceClassName(annotatedClass, root.getName()));
final MutableEnumerationTypeDeclaration featureEnum = context.findEnumerationType(this._nameProvider.getFullQualifiedFeaturesEnumName(annotatedClass, root.getName()));
featureCheckService.setFinal(true);
StringConcatenation _builder = new StringConcatenation();
_builder.append("This service allows to check which features are currently active. ");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("Note that instances of this class are immutable and thus inherent thread safe. ");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("This service is generated.");
_builder.newLine();
featureCheckService.setDocComment(_builder.toString());
final Procedure1 _function = (MutableFieldDeclaration it) -> {
it.setFinal(true);
it.setType(context.newTypeReference(Set.class));
};
featureCheckService.addField("activeFeatures", _function);
final Procedure1 _function_1 = (MutableFieldDeclaration it) -> {
it.setFinal(true);
it.setType(context.newTypeReference(String.class));
};
featureCheckService.addField("description", _function_1);
final Procedure1 _function_2 = (MutableConstructorDeclaration it) -> {
it.setVisibility(Visibility.PRIVATE);
it.addParameter("selectedFeatures", context.newTypeReference(List.class, context.newSelfTypeReference(featureEnum)));
it.addParameter("variantName", context.newTypeReference(String.class));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("activeFeatures = ");
TypeReference _newTypeReference = context.newTypeReference(EnumSet.class);
_builder.append(_newTypeReference);
_builder.append(".noneOf( ");
TypeReference _newTypeReference_1 = context.newTypeReference(featureEnum);
_builder.append(_newTypeReference_1);
_builder.append(".class );");
_builder.newLineIfNotEmpty();
_builder.append("activeFeatures.addAll( selectedFeatures );");
_builder.newLine();
_builder.newLine();
_builder.append("description = \"");
String _simpleName = featureCheckService.getSimpleName();
_builder.append(_simpleName);
_builder.append(" [\" + variantName + \"]\";");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client);
};
featureCheckService.addConstructor(_function_2);
final Procedure1 _function_3 = (MutableMethodDeclaration it) -> {
StringConcatenation _builder_1 = new StringConcatenation();
_builder_1.append("Checks whether the given feature is currently active or not.");
_builder_1.newLine();
_builder_1.newLine();
_builder_1.append("@param feature");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.append("The feature to check. Must not be {@code null}.");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.newLine();
_builder_1.append("@return true if and only if the given feature is active.");
_builder_1.newLine();
_builder_1.newLine();
_builder_1.append("@throws NullPointerException");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.append("If the given feature is {@code null}.");
_builder_1.newLine();
it.setDocComment(_builder_1.toString());
it.addParameter("feature", context.newTypeReference(context.findTypeGlobally(this._nameProvider.getFullQualifiedFeaturesEnumName(annotatedClass, root.getName()))));
it.setReturnType(context.getPrimitiveBoolean());
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
TypeReference _newTypeReference = context.newTypeReference(java.util.Objects.class);
_builder.append(_newTypeReference);
_builder.append(".requireNonNull( feature, \"The feature must not be null.\" );");
_builder.newLineIfNotEmpty();
_builder.newLine();
_builder.append("return activeFeatures.contains( feature );");
_builder.newLine();
}
};
it.setBody(_client);
};
featureCheckService.addMethod("isFeatureActive", _function_3);
final Procedure1 _function_4 = (MutableMethodDeclaration it) -> {
it.addAnnotation(context.newAnnotationReference(Override.class));
it.setReturnType(context.newTypeReference(String.class));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return description;");
_builder.newLine();
}
};
it.setBody(_client);
};
featureCheckService.addMethod("toString", _function_4);
final MutableInterfaceDeclaration variant = context.findInterface(this.getVariantName(annotatedClass, root));
final MutableAnnotationTypeDeclaration selectedFeaturesAnnotation = context.findAnnotationType(this._nameProvider.getFullQualifiedSelectedFeaturesAnnotationName(annotatedClass, root.getName()));
final Procedure1 _function_5 = (MutableMethodDeclaration it) -> {
it.setReturnType(context.newSelfTypeReference(featureCheckService));
it.setStatic(true);
StringConcatenation _builder_1 = new StringConcatenation();
_builder_1.append("Creates a new instance of this service with the features of the given variant.");
_builder_1.newLine();
_builder_1.newLine();
_builder_1.append("@param variant");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.append("The new variant. Must not be {@code null} and must be annotated with {@link ");
TypeReference _newTypeReference = context.newTypeReference(selectedFeaturesAnnotation);
_builder_1.append(_newTypeReference, "\t");
_builder_1.append("}.");
_builder_1.newLineIfNotEmpty();
_builder_1.newLine();
_builder_1.append("@return A new feature check service.");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.newLine();
_builder_1.append("@throws NullPointerException");
_builder_1.newLine();
_builder_1.append("\t");
_builder_1.append("If the given variant is {@code null} or not annotated with {@link ");
TypeReference _newTypeReference_1 = context.newTypeReference(selectedFeaturesAnnotation);
_builder_1.append(_newTypeReference_1, "\t");
_builder_1.append("}.");
_builder_1.newLineIfNotEmpty();
it.setDocComment(_builder_1.toString());
it.addParameter("variant", context.newTypeReference(Class.class, context.newWildcardTypeReference(context.newSelfTypeReference(variant))));
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
TypeReference _newTypeReference = context.newTypeReference(java.util.Objects.class);
_builder.append(_newTypeReference);
_builder.append(".requireNonNull( variant, \"The variant must not be null.\" );");
_builder.newLineIfNotEmpty();
_builder.newLine();
_builder.append("final ");
TypeReference _newTypeReference_1 = context.newTypeReference(selectedFeaturesAnnotation);
_builder.append(_newTypeReference_1);
_builder.append(" selectedFeaturesAnnotation = variant.getAnnotation( ");
TypeReference _newTypeReference_2 = context.newTypeReference(selectedFeaturesAnnotation);
_builder.append(_newTypeReference_2);
_builder.append(".class );");
_builder.newLineIfNotEmpty();
TypeReference _newTypeReference_3 = context.newTypeReference(java.util.Objects.class);
_builder.append(_newTypeReference_3);
_builder.append(".requireNonNull( selectedFeaturesAnnotation, \"The variant must be annotated with ");
String _simpleName = selectedFeaturesAnnotation.getSimpleName();
_builder.append(_simpleName);
_builder.append(".\" );");
_builder.newLineIfNotEmpty();
_builder.append("final ");
TypeReference _newTypeReference_4 = context.newTypeReference(List.class, context.newSelfTypeReference(featureEnum));
_builder.append(_newTypeReference_4);
_builder.append(" selectedFeatures = ");
TypeReference _newTypeReference_5 = context.newTypeReference(Arrays.class);
_builder.append(_newTypeReference_5);
_builder.append(".asList( selectedFeaturesAnnotation.value( ) );");
_builder.newLineIfNotEmpty();
_builder.newLine();
_builder.append("return new ");
TypeReference _newSelfTypeReference = context.newSelfTypeReference(featureCheckService);
_builder.append(_newSelfTypeReference);
_builder.append("( selectedFeatures, variant.getSimpleName( ) );");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client);
};
featureCheckService.addMethod("of", _function_5);
final Procedure1 _function_6 = (MutableMethodDeclaration it) -> {
it.setReturnType(context.newSelfTypeReference(featureCheckService));
it.setStatic(true);
StringConcatenation _builder_1 = new StringConcatenation();
_builder_1.append("Creates a new instance of this service without any active features.");
_builder_1.newLine();
_builder_1.newLine();
_builder_1.append("@return A new feature check service.");
_builder_1.newLine();
it.setDocComment(_builder_1.toString());
StringConcatenationClient _client = new StringConcatenationClient() {
@Override
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
_builder.append("return new ");
TypeReference _newSelfTypeReference = context.newSelfTypeReference(featureCheckService);
_builder.append(_newSelfTypeReference);
_builder.append("( ");
TypeReference _newSelfTypeReference_1 = context.newSelfTypeReference(context.findTypeGlobally(Collections.class));
_builder.append(_newSelfTypeReference_1);
_builder.append(".emptyList( ), \"Empty\" );");
_builder.newLineIfNotEmpty();
}
};
it.setBody(_client);
};
_xblockexpression = featureCheckService.addMethod("empty", _function_6);
}
return _xblockexpression;
}
private MutableAnnotationTypeElementDeclaration transformSelectedFeatures(final MutableClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final TransformationContext context) {
MutableAnnotationTypeElementDeclaration _xblockexpression = null;
{
final FeatureType root = this.getRoot(featureModel);
final MutableAnnotationTypeDeclaration selectedFeatures = context.findAnnotationType(this._nameProvider.getFullQualifiedSelectedFeaturesAnnotationName(annotatedClass, root.getName()));
StringConcatenation _builder = new StringConcatenation();
_builder.append("This annotation is used to mark which features the annotated variant provides. ");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("This annotation is generated.");
_builder.newLine();
selectedFeatures.setDocComment(_builder.toString());
final Procedure1 _function = (AnnotationReferenceBuildContext it) -> {
Type _findTypeGlobally = context.findTypeGlobally(RetentionPolicy.class);
it.setEnumValue("value", ((EnumerationTypeDeclaration) _findTypeGlobally).findDeclaredValue(RetentionPolicy.RUNTIME.name()));
};
selectedFeatures.addAnnotation(context.newAnnotationReference(Retention.class, _function));
final Procedure1 _function_1 = (AnnotationReferenceBuildContext it) -> {
Type _findTypeGlobally = context.findTypeGlobally(ElementType.class);
it.setEnumValue("value", ((EnumerationTypeDeclaration) _findTypeGlobally).findDeclaredValue(ElementType.TYPE.name()));
};
selectedFeatures.addAnnotation(context.newAnnotationReference(Target.class, _function_1));
final Procedure1 _function_2 = (MutableAnnotationTypeElementDeclaration it) -> {
it.setDocComment("The selected features.");
it.setType(context.newArrayTypeReference(context.newSelfTypeReference(context.findEnumerationType(this._nameProvider.getFullQualifiedFeaturesEnumName(annotatedClass, root.getName())))));
};
_xblockexpression = selectedFeatures.addAnnotationTypeElement("value", _function_2);
}
return _xblockexpression;
}
private void transformFeature(final MutableClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final TransformationContext context) {
final FeatureType root = this.getRoot(featureModel);
final MutableEnumerationTypeDeclaration feature = context.findEnumerationType(this._nameProvider.getFullQualifiedFeaturesEnumName(annotatedClass, root.getName()));
final AnnotationReference annotation = annotatedClass.findAnnotation(context.findTypeGlobally(FeatureIDEFeatures.class));
StringConcatenation _builder = new StringConcatenation();
_builder.append("This enumeration contains all available features. ");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("This enumeration is generated.");
_builder.newLine();
feature.setDocComment(_builder.toString());
this.addFeaturesToEnum(feature, annotation, root);
}
private void addFeaturesToEnum(final MutableEnumerationTypeDeclaration enumeration, final AnnotationReference annotationReference, final FeatureType type) {
if ((type != null)) {
boolean _equals = Boolean.TRUE.equals(type.isAbstract());
boolean _not = (!_equals);
if (_not) {
final Procedure1 _function = (MutableEnumerationValueDeclaration it) -> {
it.setDocComment(type.getDescription());
};
enumeration.addValue(this._featureNameConverter.convertToValidSimpleFeatureName(type.getName(), annotationReference), _function);
}
if ((type instanceof BranchedFeatureType)) {
List> _andOrOrOrAlt = ((BranchedFeatureType)type).getAndOrOrOrAlt();
for (final JAXBElement extends FeatureType> feature : _andOrOrOrAlt) {
this.addFeaturesToEnum(enumeration, annotationReference, feature.getValue());
}
}
}
}
private void transformVariant(final MutableClassDeclaration annotatedClass, final FeatureModelType featureModel, @Extension final TransformationContext context) {
final FeatureType root = this.getRoot(featureModel);
final MutableInterfaceDeclaration variant = context.findInterface(this.getVariantName(annotatedClass, root));
StringConcatenation _builder = new StringConcatenation();
_builder.append("This is a marker interface for all variants. ");
_builder.newLine();
_builder.append(" ");
_builder.newLine();
_builder.append("This interface is generated.");
_builder.newLine();
variant.setDocComment(_builder.toString());
}
}