Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object counts per condition context #199

Merged
merged 17 commits into from
Nov 17, 2016
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ http://www.wetransform.to/services/support
<feature id="eu.esdihumboldt.hale.ui.feature.dropins"/>
<feature id="de.fhg.igd.hale.fme.feature"/>
<feature id="eu.esdihumboldt.hale.platform.resources"/>
<feature id="eu.esdihumboldt.hale.ui.feature.updates"/>
<feature id="eu.esdihumboldt.hale.io.feature.msaccess"/>
</features>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,34 @@

package eu.esdihumboldt.hale.ui.service.population.internal;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.PlatformUI;

import eu.esdihumboldt.hale.common.align.model.AlignmentUtil;
import eu.esdihumboldt.hale.common.align.model.ChildContext;
import eu.esdihumboldt.hale.common.align.model.EntityDefinition;
import eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition;
import eu.esdihumboldt.hale.common.instance.model.DataSet;
import eu.esdihumboldt.hale.common.instance.model.Group;
import eu.esdihumboldt.hale.common.instance.model.Instance;
import eu.esdihumboldt.hale.common.instance.model.InstanceCollection;
import eu.esdihumboldt.hale.common.instance.model.ResourceIterator;
import eu.esdihumboldt.hale.common.instance.model.TypeFilter;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.ui.common.service.population.Population;
import eu.esdihumboldt.hale.ui.common.service.population.PopulationService;
import eu.esdihumboldt.hale.ui.common.service.population.impl.AbstractPopulationService;
import eu.esdihumboldt.hale.ui.service.entity.EntityDefinitionService;
import eu.esdihumboldt.hale.ui.service.entity.EntityDefinitionServiceListener;
import eu.esdihumboldt.hale.ui.service.instance.InstanceService;
import eu.esdihumboldt.hale.ui.service.instance.InstanceServiceAdapter;

Expand Down Expand Up @@ -67,17 +79,53 @@ public int getOverallCount() {
return Population.UNKNOWN;
}
};

private final Map<EntityDefinition, PopulationImpl> sourcePopulation = new HashMap<EntityDefinition, PopulationImpl>();

private final Map<EntityDefinition, PopulationImpl> targetPopulation = new HashMap<EntityDefinition, PopulationImpl>();

private final EntityDefinitionService entityDefinitionService;

/**
* Create a population service instance.
*
* @param instanceService the instance service
*/
public PopulationServiceImpl(final InstanceService instanceService) {

entityDefinitionService = PlatformUI.getWorkbench()
.getService(EntityDefinitionService.class);

entityDefinitionService.addListener(new EntityDefinitionServiceListener() {

@Override
public void contextsAdded(Iterable<EntityDefinition> contextEntities) {

for (EntityDefinition ed : contextEntities) {
contextAdded(ed);
}

}

@Override
public void contextRemoved(EntityDefinition contextEntity) {
// Not needed
}

@Override
public void contextAdded(EntityDefinition contextEntity) {
// go through instances to determine occurring values
// if population is already counted before for given Entity,
// then no need to count it again
Map<EntityDefinition, PopulationImpl> population = (contextEntity
.getSchemaSpace() == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);
if (population.get(contextEntity) == null) {
Job job = new PopulationCountJob(contextEntity);
job.schedule();
}
}
});

instanceService.addListener(new InstanceServiceAdapter() {

@Override
Expand Down Expand Up @@ -124,6 +172,7 @@ public void datasetChanged(DataSet type) {
}

});

}

/**
Expand All @@ -135,7 +184,6 @@ public Population getPopulation(EntityDefinition entity) {
// can't determine population
return UNKNOWN_POPULATION;
}

Population population;
synchronized (this) {
switch (entity.getSchemaSpace()) {
Expand All @@ -162,8 +210,8 @@ public Population getPopulation(EntityDefinition entity) {
@Override
public boolean hasPopulation(SchemaSpaceID schemaSpace) {
synchronized (this) {
Map<EntityDefinition, PopulationImpl> population = (schemaSpace == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);
Map<EntityDefinition, PopulationImpl> population = (schemaSpace == SchemaSpaceID.TARGET)
? (targetPopulation) : (sourcePopulation);
return !population.isEmpty();
}
}
Expand Down Expand Up @@ -196,11 +244,16 @@ public void addToPopulation(Instance instance, DataSet dataSet) {
throw new IllegalArgumentException("Invalid data set specified.");
}

// count type
EntityDefinition def = new TypeEntityDefinition(instance.getDefinition(), schemaSpace, null);
increase(def, 1);
// count for each Type definitions of instance type
Collection<? extends TypeEntityDefinition> typeDefinitions = entityDefinitionService
.getTypeEntities(instance.getDefinition(), schemaSpace);

addToPopulation(instance, def);
for (TypeEntityDefinition def : typeDefinitions) {
if (def.getFilter() == null || def.getFilter().match(instance)) {
increase(def, 1);
addToPopulation(instance, def, def.getPropertyPath());
}
}
}

/**
Expand All @@ -219,8 +272,8 @@ public void resetPopulation(DataSet dataSet) {
}

synchronized (this) {
Map<EntityDefinition, PopulationImpl> population = (schemaSpace == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);
Map<EntityDefinition, PopulationImpl> population = (schemaSpace == SchemaSpaceID.TARGET)
? (targetPopulation) : (sourcePopulation);
population.clear();
}

Expand All @@ -232,22 +285,103 @@ public void resetPopulation(DataSet dataSet) {
*
* @param group the group
* @param groupDef the group entity definition
* @param path A Child Context path
*/
private void addToPopulation(Group group, EntityDefinition groupDef) {
for (QName propertyName : group.getPropertyNames()) {
EntityDefinition propertyDef = AlignmentUtil.getChild(groupDef, propertyName);
private void addToPopulation(Group group, EntityDefinition groupDef, List<ChildContext> path) {
Iterable<? extends EntityDefinition> children = entityDefinitionService
.getChildren(groupDef);
if (children != null && children.iterator().hasNext()) {
for (EntityDefinition def : children) {
if (groupDef instanceof TypeEntityDefinition)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this ever happen?

path = def.getPropertyPath();
evaluateContext(group, def, path);
}
}
else {
evaluateContext(group, groupDef, path);
}
}

private void evaluateContext(Group group, EntityDefinition groupDef, List<ChildContext> path) {

if (propertyDef != null) {
Object[] values = group.getProperty(propertyName);
if (path == null || path.isEmpty()) {
// group or instance at end of path
increase(groupDef, 1);
}
else {
ChildContext context = path.get(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't here always the last path element relevant? Because that should be the path element that the child has in addition to its parent. The parent is on the instance side represented by the group.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I am starting to see that you changed the way that addToPopulation works by specifying what you want to limit the count to, via the provided EntityDefinition. It would be good if you would reflect that in the method documentation. "the group entity definition" does not tell anything - my first assumption was that it is directly related to the group.

List<ChildContext> subPath = null;
if (path.size() > 0) {
subPath = path.subList(1, path.size());
}
Object[] values = group.getProperty(context.getChild().getName());
if (values != null) {
// apply the possible source contexts
if (context.getIndex() != null) {
// select only the item at the index
int index = context.getIndex();
if (index < values.length) {
values = new Object[] { values[index] };
}
else {
values = new Object[] {};
}
}
if (context.getCondition() != null) {
// select only values that match the condition
List<Object> matchedValues = new ArrayList<Object>();
for (Object value : values) {
if (AlignmentUtil.matchCondition(context.getCondition(), value, group)) {
matchedValues.add(value);
}
}
values = matchedValues.toArray();
}

increase(propertyDef, values.length);
if (context.getChild().getName().equals(groupDef.getDefinition().getName())) {
increase(groupDef, values.length);
}

for (Object value : values) {
if (value instanceof Group) {
addToPopulation((Group) value, propertyDef);
addToPopulation((Group) value, groupDef, subPath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you pass all Group values on, but shouldn't that be done only for those that were counted for this level?
For instance: If it did not match the condition at this level, it should not be counted on the next.

}
}
}
else {
increase(groupDef, 0);
}

}

}

private void addNoneToPopulation(EntityDefinition groupDef, List<ChildContext> path) {
Iterable<? extends EntityDefinition> children = entityDefinitionService
.getChildren(groupDef);
if (children != null && children.iterator().hasNext()) {
for (EntityDefinition def : children) {
if (groupDef instanceof TypeEntityDefinition)
path = def.getPropertyPath();
addNoneToChildren(def, path);
}
}
else {
addNoneToChildren(groupDef, path);
}
}

private void addNoneToChildren(EntityDefinition groupDef, List<ChildContext> path) {
if (path == null || path.isEmpty()) {
increase(groupDef, 0);
}
else {
List<ChildContext> subPath = null;
if (path.size() > 0) {
subPath = path.subList(1, path.size());
}
increase(groupDef, 0);
addNoneToPopulation(groupDef, subPath);
}
}

Expand All @@ -259,20 +393,122 @@ private void addToPopulation(Group group, EntityDefinition groupDef) {
*/
private void increase(EntityDefinition entity, int values) {
synchronized (this) {
Map<EntityDefinition, PopulationImpl> population = (entity.getSchemaSpace() == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);
Map<EntityDefinition, PopulationImpl> population = (entity
.getSchemaSpace() == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);

PopulationImpl pop = population.get(entity);
if (pop == null) {
pop = new PopulationImpl(1, values);
pop = new PopulationImpl(values != 0 ? 1 : 0, values);
population.put(entity, pop);
}
else {
pop.increaseParents();
if (values != 0)
pop.increaseParents();
pop.increaseOverall(values);
}

}
}

/**
* Job determining the occurring values for a specific property entity.
*/
private class PopulationCountJob extends Job {

private final EntityDefinition ccEntityDefinition;
private InstanceCollection instanceCollection;

/**
* Create a Job to get the population of given {@link EntityDefinition}
*
* @param ccEntityDefinition the condition context entity definition
*/
public PopulationCountJob(EntityDefinition ccEntityDefinition) {
this(ccEntityDefinition, null);
}

/**
* Create a Job to get the population of given {@link EntityDefinition}
*
* @param ccEntityDefinition the condition context entity definition
* @param instanceCollection an instance collection
*/
public PopulationCountJob(EntityDefinition ccEntityDefinition,
InstanceCollection instanceCollection) {
super("Determinining count for contexts");
this.ccEntityDefinition = ccEntityDefinition;
this.instanceCollection = instanceCollection;

setUser(false);
}

@Override
protected IStatus run(IProgressMonitor monitor) {

String taskName = "Check instances for condition";

monitor.beginTask(taskName, IProgressMonitor.UNKNOWN);

if (this.instanceCollection == null) {
InstanceService instanceService = PlatformUI.getWorkbench()
.getService(InstanceService.class);

// determine data set
DataSet dataSet = DataSet.forSchemaSpace(ccEntityDefinition.getSchemaSpace());

this.instanceCollection = instanceService.getInstances(dataSet);
}

if (!instanceCollection.isEmpty()) {
// only select instances of the correct type
InstanceCollection instances = instanceCollection
.select(new TypeFilter(ccEntityDefinition.getType()));
// and apply an eventual filter
if (ccEntityDefinition.getFilter() != null) {
instances = instances.select(ccEntityDefinition.getFilter());
}

if (instances.isEmpty()) {
Map<EntityDefinition, PopulationImpl> population = (ccEntityDefinition
.getSchemaSpace() == SchemaSpaceID.TARGET) ? (targetPopulation)
: (sourcePopulation);

PopulationImpl pop = population.get(ccEntityDefinition);
if (pop == null) {
population.put(ccEntityDefinition, new PopulationImpl(0, 0));
}
addNoneToPopulation(ccEntityDefinition, ccEntityDefinition.getPropertyPath());
}
else {
// count instances
ResourceIterator<Instance> it = instances.iterator();
try {
while (it.hasNext()) {
List<ChildContext> path = ccEntityDefinition.getPropertyPath();
Instance instance = it.next();
if (path == null || path.isEmpty()) {
if (ccEntityDefinition.getFilter() == null
|| ccEntityDefinition.getFilter().match(instance)) {
PopulationServiceImpl.this.increase(ccEntityDefinition, 1);
PopulationServiceImpl.this.addToPopulation(instance,
ccEntityDefinition, path);
}
}
else {
PopulationServiceImpl.this.evaluateContext(instance,
ccEntityDefinition, path);
}
}
} finally {
it.close();
}
}
}
monitor.done();
firePopulationChanged(ccEntityDefinition.getSchemaSpace());
return Status.OK_STATUS;
}

}
}