Skip to content

Commit

Permalink
IndexUtilities.uniqueObjectsFromDescriptions
Browse files Browse the repository at this point in the history
Convert a list of descriptions into a set of EObjects. Needed because,
apparently, we can have multiple IEObjectDescriptions for the same
EObject

Called from QueryProcessor.handleMultipleIEObjectDescriptions
  • Loading branch information
steve-hickman-epistimis committed Feb 20, 2024
1 parent 16d03e1 commit bdee943
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 79 deletions.
186 changes: 109 additions & 77 deletions com.epistimis.uddl/src/com/epistimis/uddl/QueryProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.EList;
Expand Down Expand Up @@ -68,19 +69,7 @@
*/
// TODO: Insert references to EntityProcessor

public abstract class QueryProcessor<ComposableElement extends UddlElement,
Characteristic extends EObject,
Entity extends ComposableElement,
Association extends Entity,
Composition extends Characteristic,
Participant extends Characteristic,
View extends UddlElement,
Query extends View,
CompositeQuery extends View,
QueryComposition extends EObject,
ElementalComposable extends ComposableElement,
Container extends UddlElement,
EProcessor extends EntityProcessor<ComposableElement,Characteristic,Entity, Association, Composition, Participant,ElementalComposable,Container>> {
public abstract class QueryProcessor<ComposableElement extends UddlElement, Characteristic extends EObject, Entity extends ComposableElement, Association extends Entity, Composition extends Characteristic, Participant extends Characteristic, View extends UddlElement, Query extends View, CompositeQuery extends View, QueryComposition extends EObject, ElementalComposable extends ComposableElement, Container extends UddlElement, EProcessor extends EntityProcessor<ComposableElement, Characteristic, Entity, Association, Composition, Participant, ElementalComposable, Container>> {
// @Inject
// private Provider<ResourceSet> resourceSetProvider;
//
Expand All @@ -105,7 +94,7 @@ public abstract class QueryProcessor<ComposableElement extends UddlElement,

// @Inject
// CLPExtractors clp;

@Inject
EProcessor eproc;

Expand Down Expand Up @@ -144,13 +133,14 @@ public abstract class QueryProcessor<ComposableElement extends UddlElement,
*/
abstract protected EClass getRelatedPackageEntityInstance(Query obj);


//Get the Characteristic's type, rolename, or bounds
// Get the Characteristic's type, rolename, or bounds
abstract protected ComposableElement getCharacteristicType(Characteristic obj);

abstract protected String getCharacteristicRolename(Characteristic obj);

abstract protected int getCharacteristicLowerBound(Characteristic obj);

abstract protected int getCharacteristicUpperBound(Characteristic obj);


static MessageFormat CharacteristicNotFoundMsgFmt = new MessageFormat(
"Entity {0} does not have a characteristic with rolename {1}");
Expand Down Expand Up @@ -313,9 +303,9 @@ public QueryStatement parseQuery(Query query) {
// TODO: This should also check for Parse errors - like unit tests do - and
// print out something.
logger.error("Query " + qnp.getFullyQualifiedName(query).toString() + " contains a malformed query: '"
+ queryText + "'",e);
+ queryText + "'", e);
// TODO Auto-generated catch block
//e.printStackTrace();
// e.printStackTrace();
}

return qspec;
Expand Down Expand Up @@ -413,17 +403,17 @@ public Map<String, Entity> matchQuerytoUDDL(Query q, QueryStatement qstmt)
IteratorExtensions.<EObject>toIterable(qstmt.eAllContents()), SelectedEntity.class);
for (SelectedEntity se : selectedEntities) {

Pair<String,String> ea = getEntityAndAlias(se);
Pair<String, String> ea = getEntityAndAlias(se);
String entityName = ea.getFirst();
String alias = ea.getSecond();

/**
* TODO: Gets a scope that is for this container hierarchy only. For imports,
* need to use IndexUtilities to get all visible IEObjectDescriptions and filter
* those. That will require RQNs processing.
*
* NOTE: The unmodifiableLists below are to address an NPE I was getting when attempting
* to get a value from globalDecs.
* NOTE: The unmodifiableLists below are to address an NPE I was getting when
* attempting to get a value from globalDecs.
*/
IScope searchScope = entityScope(q.eContainer());
List<IEObjectDescription> listOfDescriptions = Collections.unmodifiableList(IterableExtensions
Expand All @@ -450,11 +440,7 @@ public Map<String, Entity> matchQuerytoUDDL(Query q, QueryStatement qstmt)
}
break;
default:
/** found multiple - so print out their names */
String nameCollisionsMsg = ndxUtil.printIEObjectDescriptionNameCollisions(queryFQN,
getQueryType().getName(), globalDescs);
potentialExcp.addSuppressed(new NameCollisionException(nameCollisionsMsg));
// logger.info(nameCollisionsMsg);
handleMultipleIEObjectDescriptions(globalDescs, chosenEntities, potentialExcp, queryFQN, alias);
break;
}
}
Expand All @@ -466,11 +452,7 @@ public Map<String, Entity> matchQuerytoUDDL(Query q, QueryStatement qstmt)
}
break;
default:
/** found multiple - so print out their names */
String nameCollisionsMsg = ndxUtil.printIEObjectDescriptionNameCollisions(queryFQN,
getQueryType().getName(), listOfDescriptions);
potentialExcp.addSuppressed(new NameCollisionException(nameCollisionsMsg));
// logger.info(nameCollisionsMsg);
handleMultipleIEObjectDescriptions(listOfDescriptions, chosenEntities, potentialExcp, queryFQN, alias);
break;
}
}
Expand All @@ -482,6 +464,34 @@ public Map<String, Entity> matchQuerytoUDDL(Query q, QueryStatement qstmt)
return chosenEntities;
}

/**
* Common function for handling multipleIEObjectDescriptions, no matter how we got them
* @param descriptions
* @param chosenEntities
* @param potentialExcp
* @param queryFQN
* @param alias
*/
private void handleMultipleIEObjectDescriptions(List<IEObjectDescription> descriptions,
Map<String, Entity> chosenEntities, QueryMatchException potentialExcp, String queryFQN, String alias) {
/**
* found multiple - first we need to reduce this to a set of EObjects because we
* might have multiple descriptions for the same EObject
*/
Set<EObject> objSet = IndexUtilities.uniqueObjectsFromDescriptions(descriptions);
if (objSet.size() == 1) {
// There's really only 1, so use it
addChosenEntity(objSet.iterator().next(), alias, chosenEntities);
} else {
/* so print out their names */
String nameCollisionsMsg = ndxUtil.printEObjectNameCollisions(queryFQN, getQueryType().getName(), objSet);
potentialExcp.addSuppressed(new NameCollisionException(nameCollisionsMsg));
// logger.info(nameCollisionsMsg);

}

}

@SuppressWarnings("unchecked")
private void addChosenEntity(EObject obj, String key, Map<String, Entity> chosenEntities) {
Class<Entity> realType = getEntityType();
Expand All @@ -507,7 +517,7 @@ private void addChosenEntity(EObject obj, String key, Map<String, Entity> chosen
* @returns A map of (rolename, characteristic)
*/
public Map<String, Characteristic> selectCharacteristicsFromUDDL(Query q, QueryStatement qstmt,
Map<String, Entity> matchedEntities) {
Map<String, Entity> matchedEntities) {

// Initially, we just get the Entity names
Map<String, Characteristic> selectedCharacteristics = new HashMap<String, Characteristic>();
Expand All @@ -534,16 +544,16 @@ public Map<String, Characteristic> selectCharacteristicsFromUDDL(Query q, QueryS
} else {
// pce must be an ExplicitSelectedEntityCharacteristicReference
ExplicitSelectedEntityCharacteristicReference esecr = (ExplicitSelectedEntityCharacteristicReference) pce;
Pair<String,String> cRoleAndAlias = getCharacteristicRolenameAndAlias(esecr);
Pair<String, String> cRoleAndAlias = getCharacteristicRolenameAndAlias(esecr);

SelectedEntityCharacteristicReference secr = esecr.getSelectedEntityCharacteristicReference();
String roleNameOrAlias = cRoleAndAlias.getSecond();
Characteristic result = getSelectedEntityCharacteristic(secr,roleNameOrAlias, matchedEntities);

Characteristic result = getSelectedEntityCharacteristic(secr, roleNameOrAlias, matchedEntities);

selectedCharacteristics.put(roleNameOrAlias, result);

// QueryIdentifier se = (QueryIdentifier) .getSelectedEntity();
// QueryIdentifier se = (QueryIdentifier) .getSelectedEntity();
// if (se == null) {
// // If no selected entity, that means the characteristic only exists in one of
// // the entities specified
Expand Down Expand Up @@ -577,46 +587,52 @@ public Map<String, Characteristic> selectCharacteristicsFromUDDL(Query q, QueryS
return selectedCharacteristics;

}

/**
* Extract the entity name - and the value for the alias/ lookup key. The alias will be the entity name unless another value is provided
* Extract the entity name - and the value for the alias/ lookup key. The alias
* will be the entity name unless another value is provided
*
* @param se
* @return first is the entity name, second is the value for the alias
*/
private Pair<String,String> getEntityAndAlias(SelectedEntity se) {
private Pair<String, String> getEntityAndAlias(SelectedEntity se) {
QueryIdentifier qid = (QueryIdentifier) se.getEntityType();
String entityName = qid.getId();
String alias = entityName;
QueryIdentifier sea = (QueryIdentifier) se.getSelectedEntityAlias();
if (sea != null && (sea.getId().trim().length() > 0)) {
alias = sea.getId();
}
return new Pair<String,String>(entityName, alias);
return new Pair<String, String>(entityName, alias);
}

/**
* Extract the rolename - and the value for the alias/ lookup key. The alias will be the rolename unless another value is provided
* Extract the rolename - and the value for the alias/ lookup key. The alias
* will be the rolename unless another value is provided
*
* @param esecr
* @return first is the rolename, second is the value for the alias
*/
private Pair<String,String> getCharacteristicRolenameAndAlias(ExplicitSelectedEntityCharacteristicReference esecr) {
private Pair<String, String> getCharacteristicRolenameAndAlias(
ExplicitSelectedEntityCharacteristicReference esecr) {
SelectedEntityCharacteristicReference secr = esecr.getSelectedEntityCharacteristicReference();
QueryIdentifier alias = (QueryIdentifier) esecr.getProjectedCharacteristicAlias();
String roleName = ((QueryIdentifier) secr.getCharacteristic()).getId().trim();
String roleNameOrAlias = (alias != null) ? alias.getId() : roleName;
return new Pair<String,String>(roleName, roleNameOrAlias);
return new Pair<String, String>(roleName, roleNameOrAlias);
}

/**
* Return the referenced Characteristic - if it exists
*
* @param secr
* @param roleNameOrAlias - the name it will go by
* @param matchedEntities - the entities that this query references, keyed by entity name or alias
* @param matchedEntities - the entities that this query references, keyed by
* entity name or alias
* @return
*/
private Characteristic getSelectedEntityCharacteristic(SelectedEntityCharacteristicReference secr, String roleNameOrAlias,
Map<String, Entity> matchedEntities) {
private Characteristic getSelectedEntityCharacteristic(SelectedEntityCharacteristicReference secr,
String roleNameOrAlias, Map<String, Entity> matchedEntities) {
QueryIdentifier se = (QueryIdentifier) secr.getSelectedEntity();

Characteristic result = null;
Expand All @@ -627,12 +643,12 @@ private Characteristic getSelectedEntityCharacteristic(SelectedEntityCharacteris
boolean found = false;
for (Entity ent : matchedEntities.values()) {
try {
result = getCharacteristicByRolename(ent,roleNameOrAlias);
result = getCharacteristicByRolename(ent, roleNameOrAlias);
if (found) {
// Found a second time - ambiguous.
throw new NameCollisionException(roleNameOrAlias);
} else {
found = true;
found = true;
}
} catch (CharacteristicNotFoundException e) {
// Not found in that ent - try the next one
Expand All @@ -642,25 +658,31 @@ private Characteristic getSelectedEntityCharacteristic(SelectedEntityCharacteris
} else {
String entityOrAlias = ((QueryIdentifier) se).getId();
Entity ent = matchedEntities.get(entityOrAlias);
result = getCharacteristicByRolename(ent,roleNameOrAlias);
result = getCharacteristicByRolename(ent, roleNameOrAlias);
}
return result;
}

/**
* Process the joins. This method assumes joins are unambiguous - order of join expressions doesn't matter and references in the join criteria map uniquely based
* on alias if specified or else name/rolename (No use of name/rolename if alias is specified).
* Process the joins. This method assumes joins are unambiguous - order of join
* expressions doesn't matter and references in the join criteria map uniquely
* based on alias if specified or else name/rolename (No use of name/rolename if
* alias is specified).
*
* @param q
* @param qstmt
* @param matchedEntities
* @param rawSelections
* @return
*/
public Map<String, QuerySelectedComposition<Characteristic>> processJoins(Query q, QueryStatement qstmt, Map<String, Entity> matchedEntities, Map<String, Characteristic> rawSelections) {
public Map<String, QuerySelectedComposition<Characteristic>> processJoins(Query q, QueryStatement qstmt,
Map<String, Entity> matchedEntities, Map<String, Characteristic> rawSelections) {
// final Iterable<EntityJoinCriteria> joinCriteria = Iterables.<EntityJoinCriteria>filter(
// IteratorExtensions.<EObject>toIterable(qstmt.eAllContents()), EntityJoinCriteria.class);
Map<String, QuerySelectedComposition<Characteristic>> result = new HashMap<>();
// Initialize results with the content of rawSelections - this gives us the base cardinality
for (Map.Entry<String, Characteristic> entry: rawSelections.entrySet()) {
// Initialize results with the content of rawSelections - this gives us the base
// cardinality
for (Map.Entry<String, Characteristic> entry : rawSelections.entrySet()) {
QuerySelectedComposition<Characteristic> selection = new QuerySelectedComposition<Characteristic>();
selection.alias = entry.getKey();
selection.roleName = getCharacteristicRolename(entry.getValue());
Expand All @@ -670,55 +692,65 @@ public Map<String, QuerySelectedComposition<Characteristic>> processJoins(Query
result.put(entry.getKey(), selection);
}
EList<EntityJoinExpression> ejes = qstmt.getSelectedEntityExpression().getFrom().getEntity().getEje();
for (EntityJoinExpression eje: ejes) {
for (EntityJoinExpression eje : ejes) {
EntityJoinCriteria ejc = eje.getEntityJoinCriteria();
for (EntityTypeCharacteristicEquivalenceExpression etcee: ejc.getEtcee()) {
for (EntityTypeCharacteristicEquivalenceExpression etcee : ejc.getEtcee()) {
SelectedEntityCharacteristicReference secr = etcee.getSecr();
String roleNameOrAlias = ((QueryIdentifier)secr.getCharacteristic()).getId();
Characteristic joiningCharacteristic = getSelectedEntityCharacteristic(secr, roleNameOrAlias,matchedEntities);
String roleNameOrAlias = ((QueryIdentifier) secr.getCharacteristic()).getId();
Characteristic joiningCharacteristic = getSelectedEntityCharacteristic(secr, roleNameOrAlias,
matchedEntities);
ComposableElement ce = getCharacteristicType(joiningCharacteristic);
QualifiedName joiningCharTypeQN = qnp.getFullyQualifiedName(ce);

// By default, we join against the eje join entity
SelectedEntity se = (SelectedEntity) eje.getJoinEntity();
Entity joinedEnt = null;
// Is there a reference to the joined entity?
QueryIdentifier ser = (QueryIdentifier)etcee.getSelectedEntity();
QueryIdentifier ser = (QueryIdentifier) etcee.getSelectedEntity();
if (ser == null) {
// If the SelectEntityReference is null, then use the join entity
// If the SelectEntityReference is null, then use the join entity
Pair<String, String> entAlias = getEntityAndAlias(se);
joinedEnt = matchedEntities.get(entAlias.getSecond());
} else {
// If the SelectEntityReference is not null, then join on that referenced entity - we assume the reference uses
// If the SelectEntityReference is not null, then join on that referenced entity
// - we assume the reference uses
// the alias if one is specified.
joinedEnt = matchedEntities.get(ser.getId());
}

// Check: we need to match the type.
// That means that SelectedEntityCharacteristicReference must reference an element whose type matches
// the type of the joined entity. Because these are model elements, the type is captured in the FQN of the element
// Check: we need to match the type.
// That means that SelectedEntityCharacteristicReference must reference an
// element whose type matches
// the type of the joined entity. Because these are model elements, the type is
// captured in the FQN of the element
QualifiedName joinedEntQN = qnp.getFullyQualifiedName(joinedEnt);
if (!joinedEntQN.equals(joiningCharTypeQN)) {
String msg = MessageFormat.format(WRONG_TYPE_FMT, qnp.getFullyQualifiedName(joiningCharacteristic).toString(), joinedEntQN.toString(),
String msg = MessageFormat.format(WRONG_TYPE_FMT,
qnp.getFullyQualifiedName(joiningCharacteristic).toString(), joinedEntQN.toString(),
joiningCharTypeQN.toString());
throw new WrongTypeException(msg);
}
//If we get here, the join will work -
// Next: Determine impact on cardinality of characteristics from the join - cardinality is impacted by the
// joining Entity/Characteristic relationship - but applies to all the selected characteristics of the joinedEnt
// If we get here, the join will work -
// Next: Determine impact on cardinality of characteristics from the join -
// cardinality is impacted by the
// joining Entity/Characteristic relationship - but applies to all the selected
// characteristics of the joinedEnt
int applicableLB = getCharacteristicLowerBound(joiningCharacteristic);
int applicableUB = getCharacteristicUpperBound(joiningCharacteristic);
// Now loop through the selected characteristics - find the ones from the joinedEntity and update their bounds
for (QuerySelectedComposition<Characteristic> sel: result.values()) {
// Now loop through the selected characteristics - find the ones from the
// joinedEntity and update their bounds
for (QuerySelectedComposition<Characteristic> sel : result.values()) {
if (sel.referencedCharacteristic.eContainer() == joinedEnt) {
sel.updateBounds(applicableLB, applicableUB);
}
}
}
}
// At this point, all the selection cardinalities have been updated bsaed on the joins
// At this point, all the selection cardinalities have been updated bsaed on the
// joins
return result;
}

/**
* Taken from the book, SmallJavaLib.getSmallJavaObjectClass - and converted
* from XTend to Java
Expand Down Expand Up @@ -771,7 +803,7 @@ protected Collection<Characteristic> getCharacteristics(Entity obj) {
* @return The found characteristic
*/
protected Characteristic getCharacteristicByRolename(Entity ent, String roleName)
/*throws CharacteristicNotFoundException*/ {
/* throws CharacteristicNotFoundException */ {
return eproc.getCharacteristicByRolename(ent, roleName);
}

Expand Down
Loading

0 comments on commit bdee943

Please sign in to comment.