/******************************************************************************* * Copyright (c) 2004-2012 Gabor Bergmann, Istvan Rath and Daniel Varro * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Gabor Bergmann - initial API and implementation * Istvan Rath - temporary modifications to remove compile errors *******************************************************************************/ package org.eclipse.incquery.runtime.internal.boundary.unused; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Setting; import org.eclipse.incquery.patternlanguage.patternLanguage.Pattern; import org.eclipse.incquery.runtime.api.IncQueryEngine; import org.eclipse.incquery.runtime.base.api.FeatureListener; import org.eclipse.incquery.runtime.base.api.NavigationHelper; import org.eclipse.incquery.runtime.base.exception.IncQueryBaseException; import org.eclipse.incquery.runtime.rete.boundary.Disconnectable; import org.eclipse.incquery.runtime.rete.boundary.ReteBoundary; import org.eclipse.incquery.runtime.rete.index.IdentityIndexer; import org.eclipse.incquery.runtime.rete.index.NullIndexer; import org.eclipse.incquery.runtime.rete.index.ProjectionIndexer; import org.eclipse.incquery.runtime.rete.index.SpecializedProjectionIndexer; import org.eclipse.incquery.runtime.rete.matcher.ReteEngine; import org.eclipse.incquery.runtime.rete.network.Direction; import org.eclipse.incquery.runtime.rete.network.ReteContainer; import org.eclipse.incquery.runtime.rete.network.StandardNode; import org.eclipse.incquery.runtime.rete.tuple.FlatTuple; import org.eclipse.incquery.runtime.rete.tuple.Tuple; import org.eclipse.incquery.runtime.rete.tuple.TupleMask; import org.eclipse.incquery.runtime.rete.util.Options; /** * Input node relying on the NavigationUtil base index. * Represents the set of instance edges corresponding to a given {@link EStructuralFeature}. * * @author Bergmann Gábor * */ public class EStructuralFeatureBinaryInputNode extends StandardNode implements Disconnectable { private EStructuralFeature feature; private IncQueryEngine engine; private NavigationHelper baseIndex; private ReteEngine<Pattern> reteEngine; private ReteBoundary<Pattern> boundary; static final TupleMask nullMask = TupleMask.linear(0, 2); static final TupleMask sourceKnown = TupleMask.selectSingle(0, 2); static final TupleMask targetKnown = TupleMask.selectSingle(1, 2); static final TupleMask identityMask = TupleMask.identity(2); private NullIndexer nullIndexer; private IdentityIndexer identityIndexer; private ProjectionIndexer sourceIndexer; private ProjectionIndexer targetIndexer; // TODO more indexers private FeatureListener listener = new FeatureListener() { @Override public void featureInserted(EObject host, EStructuralFeature feature, Object value) { final Tuple tuple = makeTuple(host, value); propagate(Direction.INSERT, tuple); } @Override public void featureDeleted(EObject host, EStructuralFeature feature, Object value) { final Tuple tuple = makeTuple(host, value); propagate(Direction.REVOKE, tuple); } }; /** * @param engine * @param reteContainer * @param feature * @throws IncQueryBaseException */ public EStructuralFeatureBinaryInputNode(IncQueryEngine engine, ReteContainer reteContainer, EStructuralFeature feature) throws IncQueryBaseException { super(reteContainer); this.engine = engine; // this.baseIndex = engine.getBaseIndex(); // this.reteEngine = engine.getReteEngine(); this.boundary = reteEngine.getBoundary(); this.feature = feature; setTag(feature.getName()); baseIndex.registerFeatureListener(Collections.singleton(feature), listener); reteEngine.addDisconnectable(this); } /* (non-Javadoc) * @see org.eclipse.incquery.runtimerete.network.Supplier#pullInto(java.util.Collection) */ @Override public void pullInto(Collection<Tuple> collector) { // Collection<Setting> allSettings = baseIndex.getAllValuesOfFeature(feature); // for (Setting setting : allSettings) { // collector.add(makeTuple(setting.getEObject(), setting.get(true))); // } collector.addAll(tuples()); } /* (non-Javadoc) * @see org.eclipse.incquery.runtimerete.boundary.Disconnectable#disconnect() */ @Override public void disconnect() { baseIndex.unregisterFeatureListener(Collections.singleton(feature), listener); } protected Tuple makeTuple(EObject source, Object target) { return new FlatTuple(boundary.wrapElement(source), boundary.wrapElement(target)); } protected Tuple makeTupleSingle(Object element) { return new FlatTuple(boundary.wrapElement(element)); } protected void propagate(Direction direction, final Tuple tuple) { propagateUpdate(direction, tuple); if (identityIndexer != null) identityIndexer.propagate(direction, tuple); if (nullIndexer != null) nullIndexer.propagate(direction, tuple); } protected Collection<Tuple> tuples() { final Collection<Tuple> result = new HashSet<Tuple>(); // final Set<Setting> settings = baseIndex.getOccurrencesOfFeature(feature); // if (settings != null) for (Setting setting : settings) { // result.add(makeTuple(setting.getEObject(), setting.get(true))); // } return result; } /* (non-Javadoc) * @see org.eclipse.incquery.runtimerete.network.StandardNode#constructIndex(org.eclipse.incquery.runtimerete.tuple.TupleMask) */ @Override public ProjectionIndexer constructIndex(TupleMask mask) { if (Options.employTrivialIndexers) { if (nullMask.equals(mask)) return getNullIndexer(); if (identityMask.equals(mask)) return getIdentityIndexer(); if (sourceKnown.equals(mask)) return getSourceIndexer(); if (targetKnown.equals(mask)) return getTargetIndexer(); } return super.constructIndex(mask); } /** * @return the nullIndexer */ public NullIndexer getNullIndexer() { if (nullIndexer == null) { nullIndexer= new NullIndexer(reteContainer, 2, this, this) { @Override protected Collection<Tuple> getTuples() { return tuples(); } /* (non-Javadoc) * @see org.eclipse.incquery.runtimerete.index.NullIndexer#isEmpty() */ @Override protected boolean isEmpty() { // final Set<? extends Object> values = baseIndex.getValuesOfFeature(feature); // return values == null || values.isEmpty(); return false; } /* (non-Javadoc) * @see org.eclipse.incquery.runtimerete.index.NullIndexer#isSingleElement() */ @Override protected boolean isSingleElement() { // final Set<Setting> settings = baseIndex.getOccurrencesOfFeature(feature); // return settings != null && settings.size()==1; return false; } }; } return nullIndexer; } /** * @return the identityIndexer */ public IdentityIndexer getIdentityIndexer() { if (identityIndexer == null) { identityIndexer = new IdentityIndexer(reteContainer, 2, this, this) { @Override protected Collection<Tuple> getTuples() { return tuples(); } @Override protected boolean contains(Tuple signature) { return signature.getSize() == 2 && (baseIndex.findByFeatureValue(signature.get(1), feature).contains(signature.get(0))); } }; } return identityIndexer; } /** * @return the sourceIndexer */ public ProjectionIndexer getSourceIndexer() { if (sourceIndexer == null) { sourceIndexer = new SpecializedProjectionIndexer(reteContainer, sourceKnown, this, this) { @Override public Iterator<Tuple> iterator() { return tuples().iterator(); } @Override public Collection<Tuple> get(Tuple signature) { if (signature.getSize() == 1) { final Object object = signature.get(0); if (object instanceof EObject) { try { final EObject source = (EObject) object; if (feature.isMany()) { final Collection<? extends Object> values = (Collection<?>) source.eGet(feature); if (!values.isEmpty()) { Collection<Tuple> result = new HashSet<Tuple>(); for (Object value : values) { result.add(makeTuple(source, value)); } } } else { final Object value = source.eGet(feature); if (value!=null) return Collections.singleton(makeTuple(source, value)); } } catch (Exception ex) { //engine.getLogger().logError( // "EMF-IncQuery encountered an error in processing the EMF model. ", // ex); return null; } } } return null; } @Override public Collection<Tuple> getSignatures() { final Collection<EObject> holders = baseIndex.getHoldersOfFeature(feature); if (holders == null || holders.size() == 0) return null; Collection<Tuple> result = new HashSet<Tuple>(); for (EObject holder : holders) { result.add(makeTupleSingle(holder)); } return result; } }; } return sourceIndexer; } /** * @return the targetIndexer */ public ProjectionIndexer getTargetIndexer() { if (targetIndexer == null) { targetIndexer = new SpecializedProjectionIndexer(reteContainer, targetKnown, this, this) { @Override public Iterator<Tuple> iterator() { return tuples().iterator(); } @Override public Collection<Tuple> get(Tuple signature) { if (signature.getSize() == 1) { final Object value = signature.get(0); Collection<EObject> holders = baseIndex.findByFeatureValue(value, feature); if (holders == null || holders.size() == 0) return null; Collection<Tuple> result = new HashSet<Tuple>(); for (EObject source : holders) { result.add(makeTuple(source, value)); } return result; } return null; } @Override public Collection<Tuple> getSignatures() { //final Collection<? extends Object> values = baseIndex.getValuesOfFeature(feature); //if (values == null || values.size() == 0) return null; //Collection<Tuple> result = new HashSet<Tuple>(); //for (Object value : values) { // result.add(makeTupleSingle(value)); //} //return result; return null; } }; } return targetIndexer; } }