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

tools.vitruv.change.testutils.changevisualization.tree.decoder.echange.AbstractChangeDecoder Maven / Gradle / Ivy

The newest version!
package tools.vitruv.change.testutils.changevisualization.tree.decoder.echange;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;

import tools.vitruv.change.atomic.EChange;
import tools.vitruv.change.testutils.changevisualization.utils.ModelHelper;

/**
 * A basic change decoder which ensures that only change events of a given eClassName are processed
 * and that all required structural features exist. Their values might be null, but the feature itself must exist.
 * Subclasses must implement generateString() to create the actual result of the decoder in case all requirements are met
 * and should not override decode(EChange echange)
 * 
 * @author Andreas Loeffler
 */
public abstract class AbstractChangeDecoder implements ChangeDecoder {
	
	/**
	 * The string used to display null values
	 */
	protected static final String NULL_STRING="-";
	
	/**
	 * Extracts the name of the affectedFeature
	 * 
	 * @param structuralFeatures2values The relevant structural features
	 * @return The name of the affected eAttribute
	 */
	protected static String extractAffectedFeatureName(Map structuralFeatures2values) {
		Object feature=structuralFeatures2values.get("affectedFeature");
		if(feature==null||!(feature instanceof EObject)) {
			return null;
		}
		feature=ModelHelper.getStructuralFeatureValue((EObject)feature,"name");
		return String.valueOf(feature);
	}

	/**
	 * Extracts the name of the affectedEObject
	 * 
	 * @param structuralFeatures2values The relevant structural features
	 * @return The name of the affected eObject
	 */
	protected static String extractAffectedEObjectName(Map structuralFeatures2values) {
		Object eObject=structuralFeatures2values.get("affectedEObject");
		if(eObject==null||!(eObject instanceof EObject)) {
			return null;
		}
		return extractEObjectName((EObject)eObject);
	}	
	
	/**
	 * Extracts the name of the given eObject
	 * 
	 * @param eObject The eObject whose name (=entityName) gets queried	 
	 * @return The name of the eObject
	 */
	protected static String extractEObjectName(EObject eObject) {
		if(eObject==null) {
			return null;
		}
		Object sf = ModelHelper.getStructuralFeatureValue(eObject,"entityName");
		return sf==null?null:sf.toString();
	}	


	/**
	 * the required eClass name
	 */
	private final String eClassName;

	/**
	 * A List of all required structural features
	 */
	private final List requiredFeatures;

	/**
	 * Creates a ChangeDecoder that ensures only change events of the given eClassName are processed
	 * and that all required structural features exist.
	 *  
	 * @param eClassName
	 * @param requiredFeatures
	 */
	protected AbstractChangeDecoder(String eClassName, String[] requiredFeatures) {
		this.eClassName=eClassName;
		this.requiredFeatures=java.util.Arrays.asList(requiredFeatures);
	}
	
	@Override
	public String getDecodedEClassName() {
		return eClassName;
	}

	@Override
	public String decode(EChange echange) {
		//If null as echange gets here or an echange with no eclass, return a fallback-error. this should never happen.
		//I prefer not throwing RuntimeExceptions or any other candidates that might exit the java vm "just" because of this		
		if(echange==null||echange.eClass()==null) {
			return "null value given";
		}

		//If the wrong eChanges get here, return null
		if(!eClassName.equals(echange.eClass().getName())) {
			return null;
		}

		//extract all structural features required
		Map structuralFeatures2values=extractRequiredStructuralFeatures(echange);
		
		//All found null values have been added by the called method under the given key, remove them.
		//Further details can be found in extractRequiredStructuralFeatures
		int nullValues=(Integer)structuralFeatures2values.remove("NULL_VALUES_FOUND");		

		//If not all requiredFeatures where found, return null
		if(structuralFeatures2values.size()+nullValues!=requiredFeatures.size()) {
			return null;
		}

		//let the subclass derive the string from the required features.
		//values might be null, then they are not in the hashtable, but at least the feature existed
		return generateString(echange,structuralFeatures2values);
	}	

	/**
	 * Extracts all required structural features from a given eChange
	 * @param echange The eChange
	 * @return Map of structuralFeature names ==> values
	 */
	private Map extractRequiredStructuralFeatures(EChange echange) {
		//Generate the result hashtable
		Map structuralFeatures2values=new Hashtable();		

		//It is necessary to count null values, since they will not occur in the hashtable. Without this information
		//it is not possible to decide whether all required structural features existed
		int nullValues=0;

		//Get all structural features existent
		EList features = echange.eClass().getEAllStructuralFeatures();

		//Walk them and process the required ones
		for(EStructuralFeature feature:features) {
			if(feature==null) continue;
			if(requiredFeatures.contains(feature.getName())){
				Object value=echange.eGet(feature);
				if(value==null) {
					nullValues++;
				}else {
					structuralFeatures2values.put(feature.getName(),value);
				}
			}
		}

		//the number of found null values is temporarily stored in the hashtable
		//and gets removed after this method returns
		structuralFeatures2values.put("NULL_VALUES_FOUND",nullValues);

		return structuralFeatures2values;
	}

	/**
	 * ChangeDecoder subclassing AbstractChangeDecoder should only implement this method and not override decode(Echange echange)
	 * This way the correct eClass is assured as well as all required structural features exist. If any requirement is not met.
	 * 
	 * @param eChange The eChange object decoded
	 * @param structuralFeatures2values The extracted values of all required structural features
	 * 
	 * @return The string used for display in a treenode of a jtree, null in case of any error
	 */
	protected abstract String generateString(EChange eChange,Map structuralFeatures2values);	

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy