package org.reuseware.air.algebra; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.impl.EObjectImpl; import org.reuseware.air.core.cm.IFragment; import org.reuseware.air.core.util.GenericCompositionAlgebra; import org.reuseware.air.language.componentmodel.FragmentType; import org.reuseware.air.language.componentmodel.Slot; import org.reuseware.air.language.componentmodel.VariationPointName; public abstract class CompositionAlgebra extends EObjectImpl implements IFragment { String eURIPrefix = "http://www-st.inf.tu-dresden.de/reuseware/language/"; // different ways to use extend() protected enum ExtendVariant { DEFAULT, PREPEND, APPEND } /** * Replace a fragment (bind and replace) * * @param value */ public void bind(IFragment value) { try { if (this instanceof GenericFragment) { GenericFragment fragment = (GenericFragment)this; if (fragment.isLoaded()) { if (value instanceof GenericFragment) { // bind bind(fragment, (GenericFragment)value); } } else { // if the target fragment has not been loaded, then simply // initialize the target fragment set with the value fragment set fragment.setFragments(GenericCompositionAlgebra.copyFragments(((GenericFragment)value).getFragments())); //System.err.println("The target does not contain a concrete fragment."); } } } catch (java.lang.ArrayStoreException e) { System.err.println("The fragment type '" + ((GenericFragment)value).getType() + "' does not match the list structure it is being inserted into."); } catch (java.lang.ClassCastException e) { System.err.println("The fragment type '" + ((GenericFragment)value).getType() + "' cannot replace fragment type '" + ((GenericFragment)this).getType() + "'."); } return; } /** * Bind a sub-fragment with a fragment * * aka "bind with default value" * * @param fragments * @param value */ private void bind(GenericFragment target, GenericFragment value) { // When this method is called, the 'target' only consist of one fragment if (target != null) { // simple type check //if (typeValid(target, value)) { // -- for now: catch errors in bind/1 instead if (true) { // replace fragment List<EObject> result = GenericCompositionAlgebra.replace(target.getFragment(), value.getFragments()); // update transformed IFragment if (result != null) target.setFragments(result); } else { System.out.println("TYPE ERROR"); } } return; } /** * Bind a slot * * @param slotName * @param value */ public void bind(String slotName, IFragment value) { if (this instanceof GenericFragment) { GenericFragment fragment = (GenericFragment)this; if (fragment.isLoaded()) { if (value instanceof GenericFragment) { // bind bind(fragment.getFragments(), slotName, (GenericFragment)value); } } else { System.err.println("The target does not contain a concrete fragment."); } } } /** * * @param fragments * @param slotName * @param value */ private void bind(List<EObject> fragments, String slotName, GenericFragment value) { //System.out.println("BIND ABSTRACT"); // holds all positions (if several) within a fragment where a fragment is to be bound Collection<EObject> slotPositions = new ArrayList<EObject>(); EClass slotPositionType = null; for (EObject fragment : fragments) { @ SuppressWarnings("unchecked") Iterator j = fragment.eAllContents(); while (j.hasNext()) { EObject obj = (EObject) j.next(); // found a slot if (obj instanceof Slot) { Slot slot = (Slot) obj; // found the slot with the right name if (slotName.equals(((VariationPointName)slot.getName()).getName())) { //System.out.println("Found slot: " + slotName); EClass currentSlotType = null; // get the declared type of the slot if (slot.getType() != null) { String slotType = ((FragmentType)slot.getType()).getType(); String valueType = value.getType(); if (valueType.compareToIgnoreCase(slotType) != 0) { System.err.println("Invalid type! " + "Type '" + slotType + "' demended, but type '" + valueType + "' provided."); return; } currentSlotType = (EClass)slot.eContainmentFeature().getEType(); } // if it was not declared, derive it else { // check if the type is hard-coded // String name = slot.eClass().getName(); // System.out.println("TEST: " + name); // EPackage pkg = slot.eClass().getEPackage(); // System.out.println("PACKAGE (ext.): " + pkg); // System.out.println("SEARCHING FOR: " + name.substring(0, name.indexOf("SLOT"))); // // EPackage base = // EPackage.Registry.INSTANCE.getEPackage(eURIPrefix + "datalog" + ".ecore"); // // System.out.println("PACKAGE (bas.): " + base); // // EClassifier test = // base.getEClassifier(name.substring(0, name.indexOf("SLOT"))); // System.out.println("FOUND: " + test); // // currentSlotType = (EClass)test; currentSlotType = (EClass)slot.eContainmentFeature().getEType(); } // check the other occurrences of the same slot name // compare with other slot occurrences if (slotPositionType == null) { slotPositionType = currentSlotType; } // check if it is a direct match else if (!currentSlotType.equals(slotPositionType)) { // check if it is a match via subclass-of in the type hierarchy if (currentSlotType.getEAllSuperTypes().contains(slotPositionType)) { slotPositionType = currentSlotType; } // if not, report a typing error else if (!slotPositionType.getEAllSuperTypes().contains(currentSlotType)) { // TODO: better error handling System.err.println("Slot '" + slotName + "' is typed inconsistently!"); //problems.add(new FileProcessingProblem(slot, "Slot " + slotName.getName() + // " is typed inconsistently (" + thisType.getName() + " and " + positionType.getName() + ")")); } } // if (!slotPositionType.getEAllSuperTypes().contains(currentSlotType)) { // // System.err.println("Wrong type! " + slotPositionType.toString()); // return; // } // remember the found slot position slotPositions.add(slot); } } } } if (slotPositions.isEmpty()) { System.err.println("Slot " + slotName + " not found."); } else { //System.out.println(slotPositions.size() + " slots of name '" + slotName + "' found."); } if (slotPositionType != null) { //System.out.println("Position type: '" + slotPositionType.getName() + "'"); List<EObject> valueFragmentList = value.getFragments(); if (valueFragmentList != null && valueFragmentList.isEmpty()) System.out.println("EMPTY"); if (valueFragmentList != null && !valueFragmentList.isEmpty()) { System.out.println("Super types: " + valueFragmentList.get(0).eClass().getEAllSuperTypes()); System.out.println("Type to match: " + slotPositionType.getName()); // TYPE CHECK if (!valueFragmentList.get(0).eClass().getEAllSuperTypes().contains(slotPositionType)) { System.err.println("Wrong type, the type '" + valueFragmentList.get(0).eClass().getName() + "' does not match the type '" + slotPositionType.getName() + "'."); return; } // go through all the positions where the value fragment should be bound for (EObject position : slotPositions) { EObject container = position.eContainer(); EStructuralFeature containerFeature = position.eContainmentFeature(); Object eo = container.eGet(containerFeature); // copy fragments List<EObject> fragmentsToBind = valueFragmentList; List<EObject> fCopies = GenericCompositionAlgebra.copyFragments(fragmentsToBind); //System.out.println("Fragment to bind: " + fCopies.get(0).toString()); if (eo instanceof EList) { @ SuppressWarnings("unchecked") EList<EObject> el = (EList<EObject>) eo; if (!((EReference)containerFeature).isContainment()) { //System.out.println("OPT 1"); // bind several fragments in one go for (EObject f : fCopies) { el.add(el.indexOf(position), f); } // remove slot el.remove(position); //el.add(soloFragmentToBind); } else { //System.out.println("OPT 2: " + position + ", Num Of Fragments: " + fCopies.size()); // bind several fragments in one go for (EObject f : fCopies) { el.add(el.indexOf(position), f); } // remove slot el.remove(position); } } else { //System.out.println("OPT 3"); // only bind one copy container.eSet(containerFeature, fCopies.get(0)); } } } } } /** * Extend a target fragment with the value fragment * * @param target * @param value */ public void extend(IFragment value) { if (this instanceof GenericFragment) { extend((GenericFragment)this, ((GenericFragment)value).copy(), ExtendVariant.DEFAULT); } } /** * Prepend a fragment * * @param target * @param value */ public void prepend(IFragment value) { if (this instanceof GenericFragment) { extend((GenericFragment)this, ((GenericFragment)value).copy(), ExtendVariant.PREPEND); } } /** * Append a fragment * * @param target * @param value */ public void append(IFragment value) { if (this instanceof GenericFragment) { extend((GenericFragment)this, ((GenericFragment)value).copy(), ExtendVariant.APPEND); } } /** * Extend a target fragment with the value fragment * * @param target * @param value */ private void extend(GenericFragment target, IFragment valueFragment, ExtendVariant extend) { // if the target fragment box is not loaded, then extend the fragment box if (!target.isLoaded()) { //target.setFragments(GenericCompositionAlgebra.copyFragments(((GenericFragment)valueFragment).getFragments())); target.setFragments(((GenericFragment)valueFragment).getFragments()); return; } try { List<EObject> fragments = target.getFragments(); if (fragments != null && valueFragment != null) { if (valueFragment instanceof GenericFragment) { GenericFragment value = (GenericFragment)valueFragment; // add to existing loaded fragments, if: // 1. the fragment already contains a list of fragments, or // 2. the fragment does not have a container if (fragments.size() > 1 || (target.getFragment().eContainer() == null)) { // simple type check //EObject fragment = fragments.get(0); // check if the types are of the same kind // TODO: fix proper type check //if (fragment.eClass().equals(value.getFragment().eClass())) { if (true) { //System.out.println("SIZE>1"); // if fragments are the same, then copy the value fragments List<EObject> copies = //GenericCompositionAlgebra.copyFragments(value.getFragments()); value.getFragments(); for (EObject frgmt : copies) { target.getFragments().add(frgmt); } } } // only for single fragments, that have containers else if (fragments.size() < 2 && (target.getFragment().eContainer() != null)) { EObject fragment = fragments.get(0); // System.out.println("SINGLE: " + fragment); EObject container = fragment.eContainer(); EStructuralFeature containerFeature = fragment.eContainmentFeature(); Object eo = container.eGet(containerFeature); if (eo instanceof EList) { @ SuppressWarnings("unchecked") EList<EObject> el = (EList<EObject>) eo; // extend by adding the value fragment(s) // add fragments in correct place int position = el.indexOf(fragment); if (extend == ExtendVariant.PREPEND) { ; } else if (extend == ExtendVariant.APPEND) { position++; } // use as default else { // if the referenced object is last, extend after that object if (el.indexOf(fragment) == (el.size() - 1)) { position++; } } for (EObject frgmt : value.getFragments()) { el.add(position++, frgmt); } } } //System.out.println("CON: " + fragment.eContainer()); } } } catch (java.lang.ArrayStoreException e) { System.err.println("The fragment type '" + ((GenericFragment)valueFragment).getType() + "' does not match the list structure it is being inserted into."); } } /** * Extract a fragment (by reference) * * @param value */ public void collect(IFragment value) { if (this instanceof GenericFragment) { extract((GenericFragment)this, value); } } /** * Extract a fragment (by reference) * * @param target * @param value */ private void extract(GenericFragment target, IFragment valueFragment) { if (valueFragment instanceof GenericFragment) { GenericFragment value = (GenericFragment)valueFragment; if (!target.isLoaded()) { target.setFragments(value.getFragments()); } else { List<EObject> copies = value.getFragments(); for (EObject frgmt : copies) { target.getFragments().add(frgmt); } } } return; } /** * Extract a fragment (by reference) * * @param target * @param value */ // private void extract2(GenericFragment target, IFragment valueFragment) { // // // if the target fragment box is not loaded, then extend the fragment box // if (!target.isLoaded()) { // // target.setFragments(((GenericFragment)valueFragment).getFragments()); // return; // } // // // try { // List<EObject> fragments = target.getFragments(); // // if (fragments != null && valueFragment != null) { // // if (valueFragment instanceof GenericFragment) { // // GenericFragment value = (GenericFragment)valueFragment; // // // add to existing loaded fragments, if: // // 1. the fragment already contains a list of fragments, or // // 2. the fragment does not have a container // if (fragments.size() > 1 || // (target.getFragment().eContainer() == null)) // { // // simple type check // EObject fragment = fragments.get(0); // // check if the types are of the same kind // // TODO: fix proper type check // //if (fragment.eClass().equals(value.getFragment().eClass())) { // if (true) { // //System.out.println("SIZE>1"); // // // if fragments are the same, then copy the value fragments // List<EObject> copies = // //GenericCompositionAlgebra.copyFragments(value.getFragments()); // value.getFragments(); // // for (EObject frgmt : copies) { // target.getFragments().add(frgmt); // } // // } // } // // only for single fragments, that have containers // else if (fragments.size() < 2 && // (target.getFragment().eContainer() != null)) // { // // EObject fragment = fragments.get(0); // //// System.out.println("SINGLE: " + fragment); // // EObject container = fragment.eContainer(); // EStructuralFeature containerFeature = fragment.eContainmentFeature(); // // Object eo = container.eGet(containerFeature); // // if (eo instanceof EList) { // @ SuppressWarnings("unchecked") // EList<EObject> el = (EList<EObject>) eo; // // extend by adding the value fragment(s) // // add fragments in correct place // int position = el.indexOf(fragment); // // for (EObject frgmt : value.getFragments()) { // el.add(position++, frgmt); // } // } // } // // } // } // // } catch (java.lang.ArrayStoreException e) { // // System.err.println("The fragment type '" + ((GenericFragment)valueFragment).getType() + // "' does not match the list structure it is being inserted into."); // } // } /** * Checks if the target fragment can be replaced by the value fragment * * @param target * @param value * @return */ private boolean typeMatch(GenericFragment target, GenericFragment value) { if (target.getType().equals(value.getType())) { return true; } return false; } /** * Copy a fragment * * @param construct */ public static void copy(IFragment copy, IFragment value) { if (value instanceof GenericFragment) { GenericFragment gf = (GenericFragment)value; if (gf.getFragment() != null) { List<EObject> cp = GenericCompositionAlgebra.copyFragments(gf.getFragments()); if (copy instanceof GenericFragment) { GenericFragment cgf = (GenericFragment)copy; cgf.setFragments(cp); } } } // default return; } /** * * @param curObject * @param goal * @return */ private boolean inContextOf(EObject curObject, EClass goal) { //System.out.println("**** TMP START, with curObject: " + curObject); EObject container = curObject.eContainer(); // TODO: this is too general // E.g. a positiveAtom in a Datalog Body will match on filtering with HEAD // base case if (goal.isInstance(curObject)) return true; if (container != null) { EList<EStructuralFeature> features = container.eClass().getEAllStructuralFeatures(); // go through features for (EStructuralFeature feat : features) { //System.out.println("FEATURE: " + feat); // get the feature Object featObj = container.eGet(feat); //System.out.println("OBJ: " + featObj); if (featObj != null && !(featObj instanceof EList)) { if (featObj.equals(curObject)) { //System.out.println("MID MATCH"); if (goal.isInstance(featObj)) { //System.out.println("FOUND INSTANCE"); return true; } // recursive call boolean ret = inContextOf(container, goal); if (ret) return ret; } } // list structure else if (featObj != null && featObj instanceof EList) { //System.out.println("LIST"); @ SuppressWarnings("unchecked") EList<EObject> list = (EList<EObject>)featObj; for (EObject obj : list) { //System.out.println("LIST MATCH: " + obj); //System.out.println("TRYING MATCH: " + curObject); if (obj.equals(curObject)) { //System.out.println("MID MATCH in LIST"); // recursive call boolean ret = inContextOf(container, goal); if (ret) return ret; } } } } } return false; } /** * Check if fragment is in the context of a container * * @param fragment * @param requiredType * @return */ public boolean inContextOf(EClass requiredType) { // make sure we are a fragment if (this instanceof GenericFragment) { GenericFragment fragment = (GenericFragment)this; // Only get the first fragment EObject obj = fragment.getFragment(); boolean ret = inContextOf(obj, requiredType); if (ret) return ret; } return false; } /** * Checks if a fragment is directly contained in a container * * @param container */ public boolean isContainedIn(EClass container) { // make sure we are a fragment if (this instanceof GenericFragment) { GenericFragment fragment = (GenericFragment)this; // Only get the first fragment EObject obj = fragment.getFragment(); EClass cls = obj.eContainer().eClass(); if (cls.equals(container)) return true; } return false; } /** * Checks if a fragment is of certain type * */ public boolean isType(EClass type) { // make sure we are a fragment if (this instanceof GenericFragment) { GenericFragment fragment = (GenericFragment)this; // Only get the first fragment EObject obj = fragment.getFragment(); if (obj.eClass().equals(type)) return true; } return false; } /** * Checks if the fragment is last in a list * * @return */ public boolean isLast() { // make sure this object is a fragment if (this instanceof GenericFragment) { GenericFragment target = (GenericFragment)this; // assume only one fragment EObject fragment = target.getFragment(); return isLast(fragment); } // default return false; } /** * Checks if the fragment is last in a list * * @param fragment * @return */ private boolean isLast(EObject fragment) { if (fragment != null) { EObject container = fragment.eContainer(); EStructuralFeature containerFeature = fragment.eContainmentFeature(); Object eo = container.eGet(containerFeature); if (eo instanceof EList) { @ SuppressWarnings("unchecked") EList<EObject> list = (EList<EObject>)eo; // check if last if (list.contains(fragment) && (list.indexOf(fragment) == (list.size() - 1))) return true; } } // default return false; } /** * Checks if the fragment is last in a list * * @return */ public boolean isFirst() { // make sure this object is a fragment if (this instanceof GenericFragment) { GenericFragment target = (GenericFragment)this; // assume only one fragment EObject fragment = target.getFragment(); return isFirst(fragment); } // default return false; } /** * Checks if the fragment is last in a list * * @param fragment * @return */ private boolean isFirst(EObject fragment) { if (fragment != null) { EObject container = fragment.eContainer(); EStructuralFeature containerFeature = fragment.eContainmentFeature(); Object eo = container.eGet(containerFeature); if (eo instanceof EList) { @ SuppressWarnings("unchecked") EList<EObject> list = (EList<EObject>)eo; if (list.contains(fragment) && (list.get(0).equals(fragment))) return true; } } // default return false; } }