All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.nakeduml.javageneration.basicjava.DerivedUnionImplementor Maven / Gradle / Ivy

package net.sf.nakeduml.javageneration.basicjava;

import java.util.List;

import net.sf.nakeduml.feature.visit.VisitAfter;
import net.sf.nakeduml.feature.visit.VisitBefore;
import net.sf.nakeduml.javageneration.AbstractJavaProducingVisitor;
import net.sf.nakeduml.javageneration.NakedStructuralFeatureMap;
import net.sf.nakeduml.javageneration.util.OJUtil;
import net.sf.nakeduml.javametamodel.OJBlock;
import net.sf.nakeduml.javametamodel.OJClass;
import net.sf.nakeduml.javametamodel.OJIfStatement;
import net.sf.nakeduml.javametamodel.OJOperation;
import net.sf.nakeduml.javametamodel.OJPathName;
import net.sf.nakeduml.javametamodel.annotation.OJAnnotatedField;
import net.sf.nakeduml.javametamodel.annotation.OJAnnotatedOperation;
import net.sf.nakeduml.metamodel.core.INakedClassifier;
import net.sf.nakeduml.metamodel.core.INakedEntity;
import net.sf.nakeduml.metamodel.core.INakedInterface;
import net.sf.nakeduml.metamodel.core.INakedProperty;
import net.sf.nakeduml.metamodel.core.INakedStructuredDataType;

public class DerivedUnionImplementor extends AbstractJavaProducingVisitor {
	@VisitBefore(matchSubclasses = true)
	public void property(INakedProperty p) {
		visitProperty(p.getOwner(), p);
	}

	@VisitBefore(matchSubclasses = true,match={INakedEntity.class, INakedStructuredDataType.class})
	public void classifier(INakedClassifier c) {		
		for (INakedProperty p : c.getEffectiveAttributes()) {
			if(p.getOwner() instanceof INakedInterface){
				visitProperty(c, p);
				if (p.isDerivedUnion()) {
					ensureDerivedUnionImplementation((INakedEntity) c, p);
				}
			}
		}
	}

	private void visitProperty(INakedClassifier owner, INakedProperty p) {
		if (p.isNavigable()) {
			NakedStructuralFeatureMap map = new NakedStructuralFeatureMap(p);
			OJClass c = findJavaClass(owner);
			if (p.isDerivedUnion()) {
				implementDefaultValueForDerivedUnion(map, c);
			}
			for (INakedProperty derivedUnion : p.getSubsettedProperties()) {
				addSubsetToUnion(map, c, derivedUnion);
			}
		}
	}

	@VisitAfter(matchSubclasses = true)
	public void visitFeature(INakedEntity entity) {
		for (INakedProperty p : entity.getEffectiveAttributes()) {
		}
	}
/**
 * Ensures that a derived union is implemented for properties inherited from interfaces
 * @param entity
 * @param p
 */
	private void ensureDerivedUnionImplementation(INakedEntity entity, INakedProperty p) {
		
		OJClass ojClass = findJavaClass(entity);
		List attrs = entity.getEffectiveAttributes();
		boolean implemented = false;

		for (INakedProperty attr : attrs) {
			if (attr != p) {
				boolean isSubsetted = attr.getSubsettedProperties().contains(p);
				boolean isOverRidden = attr.getName().equals(p.getName());
				if (isOverRidden || isSubsetted) {
					implemented = true;
					break;
				}
			}
		}
		if (!implemented) {
			NakedStructuralFeatureMap map = new NakedStructuralFeatureMap(p);
			OJOperation getter = OJUtil.findOperation(ojClass, map.getter());
			getter.getBody().getStatements().clear();
			ojClass.addToImports(map.javaDefaultTypePath());
			getter.getBody().addToStatements("return " + map.javaDefaultValue());
		}

	}

	private void implementDefaultValueForDerivedUnion(NakedStructuralFeatureMap subsettedMap, OJClass c) {
		// just a default implementation so that all subclasses are not required
		// to implement it
		OJOperation getter = OJUtil.findOperation(c, subsettedMap.getter());
		// TODO check this logic - only execute if another propert has not yet
		// built this getter
		if (getter.getBody() == null || (getter.getBody().getStatements().size() == 1)) {
			if (subsettedMap.isOne()) {
				getter.setBody(new OJBlock());
				c.addToImports(subsettedMap.javaDefaultTypePath());
				getter.getBody().addToStatements("return " + subsettedMap.javaDefaultValue());
			} else {
				OJPathName type = subsettedMap.javaTypePath();
				OJAnnotatedField sinit = new OJAnnotatedField();
				String returnParameterName = subsettedMap.umlName() + "Subsetting";
				sinit.setName(returnParameterName);
				sinit.setType(type);
				getter.setBody(new OJBlock());
				getter.getBody().addToLocals(sinit);
				sinit.setInitExp(subsettedMap.javaDefaultValue());
				c.addToImports(subsettedMap.javaDefaultTypePath());
				getter.getBody().addToStatements("return " + subsettedMap.javaDefaultValue());
			}
		}
	}

	private void addSubsetToUnion(NakedStructuralFeatureMap subsettingMap, OJClass c, INakedProperty derivedUnion) {
		NakedStructuralFeatureMap derivedUnionMap = new NakedStructuralFeatureMap(derivedUnion);
		OJPathName type = derivedUnionMap.javaTypePath();
		OJOperation sgetter = OJUtil.findOperation(c, derivedUnionMap.getter());
		String returnParameterName = derivedUnionMap.umlName() + "Subsetting";
		if (sgetter == null) {
			sgetter = buildGetterForDerivedUnion(c, type, derivedUnionMap, returnParameterName);
		} else {
			// TODO investigate why this is necessary
			if (sgetter.getBody().getStatements().size() > 0) {
				// remove return statement
				sgetter.getBody().getStatements().remove(sgetter.getBody().getStatements().size() - 1);
			}
		}
		OJAnnotatedField returnParameter = getReturnParameter(sgetter);
		returnParameter.setName(returnParameterName);
		returnParameter.setType(type);
		if (returnParameter.getInitExp() == null) {
			// retain the possible derivation rule initialization
			returnParameter.setInitExp(derivedUnionMap.javaDefaultValue());
		}
		c.addToImports(type);
		c.addToImports(derivedUnionMap.javaDefaultTypePath());
		String expression = buildExpression(subsettingMap, derivedUnion);

		if (subsettingMap.isOne()) {
			if (derivedUnionMap.isOne()) {
				// TODO this could be problematic if multiple subsetting
				// properties are not null
				OJIfStatement ifNotNull = new OJIfStatement(expression + "!=null", returnParameterName + "=" + expression);
				sgetter.getBody().addToStatements(ifNotNull);
			} else {
				OJIfStatement ifNotNull = new OJIfStatement(expression + "!=null", returnParameterName + ".add(" + expression + ")");
				sgetter.getBody().addToStatements(ifNotNull);
			}
		} else {
			if (derivedUnionMap.isOne()) {
				// TODO implement validation. This should not be allowed
			} else {
				sgetter.getBody().addToStatements(returnParameterName + ".addAll(" + expression + ")");
			}
		}
		sgetter.getBody().addToStatements("return " + returnParameterName);
	}

	private OJOperation buildGetterForDerivedUnion(OJClass c, OJPathName type, NakedStructuralFeatureMap derivedUnionMap, String returnParameterName) {
		OJOperation sgetter;
		// we typically end up here when the subsetted property is not
		// defined in this class, but in a superclass or interface
		sgetter = new OJAnnotatedOperation();
		sgetter.setName(derivedUnionMap.getter());
		sgetter.setReturnType(type);
		c.addToOperations(sgetter);
		// retrieve the potentially subsetting superclass implementation of
		// the property
		if (derivedUnionMap.isMany()) {
			sgetter.getBody().addToStatements(returnParameterName + ".addAll(super." + derivedUnionMap.getter() + "())");
		} else {
			sgetter.getBody().addToStatements(returnParameterName + "=super." + derivedUnionMap.getter() + "()");
		}
		return sgetter;
	}

	private String buildExpression(NakedStructuralFeatureMap mapOfSubsettingProperty, INakedProperty subsettedProperty) {
		String expression = mapOfSubsettingProperty.getter() + "()";
		if (subsettedProperty.getName().equals(mapOfSubsettingProperty.umlName())) {
			// we need to avoid recursion now
			if (mapOfSubsettingProperty.getFeature().isDerived()) {
				// do nothing the derivation rule will apply to the init
				// expression
			} else if (((INakedProperty) mapOfSubsettingProperty.getFeature()).isDerivedUnion()) {
				// TODO leverage the derivation here
				throw new IllegalStateException("DerivedUnion Subsetting with DerivedUnion Subsetted properties must have different names");
			} else {
				expression = "this." + mapOfSubsettingProperty.umlName();
			}
		}
		return expression;
	}

	private OJAnnotatedField getReturnParameter(OJOperation sgetter) {
		OJAnnotatedField init = null;
		if (sgetter.getBody().getLocals().size() == 1) {
			init = (OJAnnotatedField) sgetter.getBody().getLocals().get(0);
		} else {
			OJAnnotatedField sinit = new OJAnnotatedField();
			sgetter.getBody().addToLocals(sinit);
			init = sinit;
		}
		return init;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy