/*******************************************************************************
* Copyright (c) 2010-2012, Zoltan Ujhelyi, Tamas Szabo, 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:
* Zoltan Ujhelyi, Tamas Szabo - initial API and implementation
*******************************************************************************/
package org.eclipse.incquery.tooling.ui.queryexplorer.content.matcher;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.incquery.patternlanguage.helper.CorePatternLanguageHelper;
import org.eclipse.incquery.patternlanguage.patternLanguage.Pattern;
import org.eclipse.incquery.runtime.api.EngineManager;
import org.eclipse.incquery.runtime.api.GenericPatternMatcher;
import org.eclipse.incquery.runtime.api.IPatternMatch;
import org.eclipse.incquery.runtime.api.IncQueryEngine;
import org.eclipse.incquery.runtime.api.IncQueryMatcher;
import org.eclipse.incquery.runtime.exception.IncQueryException;
import org.eclipse.incquery.runtime.extensibility.EngineTaintListener;
import org.eclipse.incquery.tooling.ui.IncQueryGUIPlugin;
import org.eclipse.incquery.tooling.ui.queryexplorer.QueryExplorer;
import org.eclipse.incquery.tooling.ui.queryexplorer.preference.PreferenceConstants;
import org.eclipse.incquery.tooling.ui.queryexplorer.util.DatabindingUtil;
import org.eclipse.incquery.tooling.ui.queryexplorer.util.PatternRegistry;
import org.eclipse.ui.IEditorPart;
/**
* Each IEditingDomainProvider will be associated a PatternMatcherRoot element in the tree viewer. PatterMatcherRoots
* are indexed with a ViewerRootKey.
*
* It's children element will be PatterMatchers.
*
* @author Tamas Szabo
*
*/
public class ObservablePatternMatcherRoot extends EngineTaintListener {
private final Map<String, ObservablePatternMatcher> matchers;
private final List<ObservablePatternMatcher> sortedMatchers;
private final MatcherTreeViewerRootKey key;
private final ILog logger = IncQueryGUIPlugin.getDefault().getLog();
public ObservablePatternMatcherRoot(MatcherTreeViewerRootKey key) {
matchers = new HashMap<String, ObservablePatternMatcher>();
sortedMatchers = new LinkedList<ObservablePatternMatcher>();
this.key = key;
IncQueryEngine engine = key.getEngine();
if (engine == null) {
key.setEngine(createEngine());
}
if (engine != null) {
engine.getLogger().addAppender(this);
}
}
private IncQueryEngine createEngine() {
try {
IncQueryEngine engine = EngineManager.getInstance().createUnmanagedIncQueryEngine(key.getNotifier());
return engine;
} catch (IncQueryException e) {
logger.log(new Status(IStatus.ERROR, IncQueryGUIPlugin.PLUGIN_ID, "Could not retrieve IncQueryEngine for "
+ key.getNotifier(), e));
return null;
}
}
public void addMatcher(IncQueryMatcher<? extends IPatternMatch> matcher, String patternFqn, boolean generated,
String exceptionMessage) {
// This cast could not be avoided because later the filtered delta monitor will need the base IPatternMatch
@SuppressWarnings("unchecked")
ObservablePatternMatcher pm = new ObservablePatternMatcher(this, (IncQueryMatcher<IPatternMatch>) matcher,
patternFqn, generated, exceptionMessage);
this.matchers.put(patternFqn, pm);
// generated matchers are inserted in front of the list
if (generated) {
this.sortedMatchers.add(0, pm);
}
// generic matchers are inserted in the list according to the order in the eiq file
else {
this.sortedMatchers.add(pm);
}
if (QueryExplorer.getInstance() != null) {
QueryExplorer.getInstance().getMatcherTreeViewer().refresh(this);
}
}
public void removeMatcher(String patternFqn) {
// if the pattern is first deactivated then removed, than the matcher corresponding matcher is disposed
ObservablePatternMatcher matcher = this.matchers.get(patternFqn);
if (matcher != null) {
this.sortedMatchers.remove(matcher);
matcher.dispose();
this.matchers.remove(patternFqn);
if (QueryExplorer.getInstance() != null) {
QueryExplorer.getInstance().getMatcherTreeViewer().refresh(this);
}
}
}
public static final String MATCHERS_ID = "matchers";
public List<ObservablePatternMatcher> getMatchers() {
return sortedMatchers;
}
public String getText() {
return key.toString();
}
public void dispose() {
for (ObservablePatternMatcher pm : this.matchers.values()) {
pm.dispose();
}
IncQueryEngine engine = key.getEngine();// createEngine();
if (engine != null) {
engine.getLogger().removeAppender(this);
}
}
public boolean isTainted() {
IncQueryEngine engine = key.getEngine();// createEngine();
return (engine == null) ? true : engine.isTainted();
}
public MatcherTreeViewerRootKey getKey() {
return key;
}
public IEditorPart getEditorPart() {
return this.key.getEditorPart();
}
public Notifier getNotifier() {
return this.key.getNotifier();
}
@Override
public void engineBecameTainted() {
for (ObservablePatternMatcher matcher : this.matchers.values()) {
matcher.stopMonitoring();
}
}
public void registerPattern(final Pattern... patterns) {
boolean wildcardMode = IncQueryGUIPlugin.getDefault().getPreferenceStore()
.getBoolean(PreferenceConstants.WILDCARD_MODE);
IncQueryEngine engine;
try {
// engine = EngineManager.getInstance().getIncQueryEngine(getNotifier());
engine = key.getEngine();
try {
engine.setWildcardMode(wildcardMode);
} catch (IllegalStateException ex) {
// could not set wildcard mode
}
if (engine.getBaseIndex().isInWildcardMode()) {
addMatchersForPatterns(patterns);
} else {
engine.getBaseIndex().coalesceTraversals(new Callable<Void>() {
@Override
public Void call() throws Exception {
addMatchersForPatterns(patterns);
return null;
}
});
}
} catch (IncQueryException ex) {
logger.log(new Status(IStatus.ERROR, IncQueryGUIPlugin.PLUGIN_ID,
"Cannot initialize pattern matcher engine.", ex));
} catch (InvocationTargetException e) {
logger.log(new Status(IStatus.ERROR, IncQueryGUIPlugin.PLUGIN_ID,
"Error during pattern matcher construction: " + e.getCause().getMessage(), e.getCause()));
}
}
private void addMatchersForPatterns(Pattern... patterns) {
for (Pattern pattern : patterns) {
IncQueryMatcher<? extends IPatternMatch> matcher = null;
boolean isGenerated = PatternRegistry.getInstance().isGenerated(pattern);
String message = null;
try {
if (isGenerated) {
matcher = DatabindingUtil.getMatcherFactoryForGeneratedPattern(pattern).getMatcher(key.getEngine());
} else {
matcher = new GenericPatternMatcher(pattern, key.getEngine());
}
} catch (Exception e) {
logger.log(new Status(IStatus.ERROR, IncQueryGUIPlugin.PLUGIN_ID,
"Cannot initialize pattern matcher for pattern "
+ CorePatternLanguageHelper.getFullyQualifiedName(pattern), e));
matcher = null;
message = (e instanceof IncQueryException) ? ((IncQueryException) e).getShortMessage() : e.getMessage();
}
addMatcher(matcher, CorePatternLanguageHelper.getFullyQualifiedName(pattern), isGenerated, message);
}
}
public void unregisterPattern(Pattern pattern) {
removeMatcher(CorePatternLanguageHelper.getFullyQualifiedName(pattern));
}
}