blob: 139391e53fa4d98e7cfc80fc6a1c6a45478600fd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.ruta.query.ui;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.uima.UIMAFramework;
import org.apache.uima.analysis_engine.AnalysisEngine;
import org.apache.uima.analysis_engine.AnalysisEngineDescription;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.impl.XmiCasDeserializer;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.jcas.cas.FSArray;
import org.apache.uima.resource.ResourceManager;
import org.apache.uima.resource.ResourceSpecifier;
import org.apache.uima.resource.metadata.TypeSystemDescription;
import org.apache.uima.ruta.addons.RutaAddonsPlugin;
import org.apache.uima.ruta.engine.RutaEngine;
import org.apache.uima.ruta.extensions.IEngineLoader;
import org.apache.uima.ruta.extensions.IRutaActionExtension;
import org.apache.uima.ruta.extensions.IRutaBooleanFunctionExtension;
import org.apache.uima.ruta.extensions.IRutaConditionExtension;
import org.apache.uima.ruta.extensions.IRutaNumberFunctionExtension;
import org.apache.uima.ruta.extensions.IRutaStringFunctionExtension;
import org.apache.uima.ruta.extensions.IRutaTypeFunctionExtension;
import org.apache.uima.ruta.ide.core.RutaExtensionManager;
import org.apache.uima.ruta.ide.core.builder.RutaProjectUtils;
import org.apache.uima.util.CasCreationUtils;
import org.apache.uima.util.FileUtils;
import org.apache.uima.util.XMLInputSource;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.ui.handlers.HandlerUtil;
public class QueryActionHandler implements IHandler {
private class QueryJobChangeAdapter extends JobChangeAdapter {
private QueryComposite composite;
QueryJobChangeAdapter(QueryComposite composite) {
super();
this.composite = composite;
}
@Override
public void done(IJobChangeEvent event) {
if (event.getResult().isOK()) {
composite.getDisplay().asyncExec(new Runnable() {
public void run() {
composite.update();
}
});
}
}
}
private class QueryHandlerJob extends Job {
ExecutionEvent event;
private boolean recursive;
private String rules;
private String typeSystemLocation;
private String dataLocation;
QueryHandlerJob(ExecutionEvent event, String dir, String typeSystem, String rules,
boolean recurive) {
super("Query in " + dir + "...");
this.event = event;
this.dataLocation = dir;
this.typeSystemLocation = typeSystem;
this.rules = rules;
this.recursive = recurive;
setUser(true);
}
private String getText(File each) {
try {
return FileUtils.file2String(each, "UTF-8");
} catch (IOException e) {
DLTKCore.error(e.getMessage(), e);
}
return "";
}
@Override
public IStatus run(IProgressMonitor monitor) {
final QueryView queryView = (QueryView) HandlerUtil.getActivePart(event);
final QueryComposite queryComposite = queryView.getComposite();
// queryView.saveState();
queryView.showBusy(true);
monitor.beginTask("Initializing analysis engine...", 1);
queryComposite.getDisplay().asyncExec(new Runnable() {
public void run() {
queryComposite.setResult(null);
}
});
int files = 0;
int found = 0;
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
final List<QueryResult> result = new ArrayList<QueryResult>();
String script = "PACKAGE query;\n\n";
// script += "TYPESYSTEM " + typeSystemFileText.getText();
script += rules;
try {
URL aedesc = RutaEngine.class.getResource("BasicEngine.xml");
XMLInputSource inae = new XMLInputSource(aedesc);
ResourceSpecifier specifier = UIMAFramework.getXMLParser().parseResourceSpecifier(inae);
ResourceManager resMgr = UIMAFramework.newDefaultResourceManager();
AnalysisEngineDescription aed = (AnalysisEngineDescription) specifier;
TypeSystemDescription basicTypeSystem = aed.getAnalysisEngineMetaData().getTypeSystem();
if (!StringUtils.isEmpty(typeSystemLocation)) {
// TODO check on valid input and extend for scr
String tsLocation = typeSystemLocation;
Collection<TypeSystemDescription> tsds = new ArrayList<TypeSystemDescription>();
tsds.add(basicTypeSystem);
if (typeSystemLocation.endsWith(RutaEngine.SCRIPT_FILE_EXTENSION)) {
IFile iFile = QueryComposite.getIFile(typeSystemLocation);
IPath scriptPath = iFile.getLocation();
IProject project = iFile.getProject();
IPath descriptorRootPath = RutaProjectUtils.getDescriptorRootPath(project);
resMgr.setDataPath(descriptorRootPath.toPortableString());
IPath path = RutaProjectUtils.getTypeSystemDescriptorPath(scriptPath, project);
tsLocation = path.toPortableString();
}
File tsFile = new File(tsLocation);
XMLInputSource ints = new XMLInputSource(tsFile);
TypeSystemDescription importTSD = UIMAFramework.getXMLParser()
.parseTypeSystemDescription(ints);
importTSD.resolveImports(resMgr);
tsds.add(importTSD);
TypeSystemDescription mergeTypeSystems = CasCreationUtils.mergeTypeSystems(tsds);
aed.getAnalysisEngineMetaData().setTypeSystem(mergeTypeSystems);
}
aed.resolveImports(resMgr);
AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(aed, resMgr, null);
File tempFile = File.createTempFile("RutaQuery", RutaEngine.SCRIPT_FILE_EXTENSION);
tempFile.deleteOnExit();
FileUtils.saveString2File(script, tempFile, "UTF-8");
String portableString = Path.fromOSString(tempFile.getParentFile().getPath())
.toPortableString();
ae.setConfigParameterValue(RutaEngine.PARAM_SCRIPT_PATHS, new String[] { portableString });
String name = tempFile.getName().substring(0, tempFile.getName().length() - 5);
ae.setConfigParameterValue(RutaEngine.PARAM_MAIN_SCRIPT, name);
ae.setConfigParameterValue(RutaEngine.PARAM_DEBUG, true);
ae.setConfigParameterValue(RutaEngine.PARAM_DEBUG_WITH_MATCHES, true);
ae.setConfigParameterValue(RutaEngine.PARAM_PROFILE, false);
ae.setConfigParameterValue(RutaEngine.PARAM_STATISTICS, false);
IRutaConditionExtension[] conditionExtensions = RutaExtensionManager.getDefault()
.getRutaConditionExtensions();
IRutaActionExtension[] actionExtensions = RutaExtensionManager.getDefault()
.getRutaActionExtensions();
IRutaBooleanFunctionExtension[] booleanFunctionExtensions = RutaExtensionManager.getDefault()
.getRutaBooleanFunctionExtensions();
IRutaNumberFunctionExtension[] numberFunctionExtensions = RutaExtensionManager.getDefault()
.getRutaNumberFunctionExtensions();
IRutaStringFunctionExtension[] stringFunctionExtensions = RutaExtensionManager.getDefault()
.getRutaStringFunctionExtensions();
IRutaTypeFunctionExtension[] typeFunctionExtensions = RutaExtensionManager.getDefault()
.getRutaTypeFunctionExtensions();
List<String> languageExtensions = new ArrayList<String>();
for (IRutaConditionExtension each : conditionExtensions) {
languageExtensions.add(each.getClass().getName());
}
for (IRutaActionExtension each : actionExtensions) {
languageExtensions.add(each.getClass().getName());
}
for (IRutaBooleanFunctionExtension each : booleanFunctionExtensions) {
languageExtensions.add(each.getClass().getName());
}
for (IRutaNumberFunctionExtension each : numberFunctionExtensions) {
languageExtensions.add(each.getClass().getName());
}
for (IRutaStringFunctionExtension each : stringFunctionExtensions) {
languageExtensions.add(each.getClass().getName());
}
for (IRutaTypeFunctionExtension each : typeFunctionExtensions) {
languageExtensions.add(each.getClass().getName());
}
ae.setConfigParameterValue(RutaEngine.PARAM_ADDITIONAL_EXTENSIONS,
languageExtensions.toArray(new String[0]));
ae.reconfigure();
CAS cas = ae.newCAS();
monitor.worked(1);
if (monitor.isCanceled()) {
if (ae != null) {
ae.destroy();
}
if(cas != null) {
cas.release();
}
return Status.CANCEL_STATUS;
}
File dir = new File(dataLocation);
List<File> inputFiles = getFiles(dir, recursive);
monitor.beginTask("Query in " + dir.getName() + "...", inputFiles.size());
for (File each : inputFiles) {
monitor.setTaskName("Query in " + each.getName() + "...");
if (monitor.isCanceled()) {
if (ae != null) {
ae.destroy();
}
if(cas != null) {
cas.release();
}
return Status.CANCEL_STATUS;
}
cas.reset();
if (each.getName().endsWith("xmi")) {
XmiCasDeserializer.deserialize(new FileInputStream(each), cas, true);
} else {
cas.setDocumentText(getText(each));
}
Type matchedType = cas.getTypeSystem().getType(
"org.apache.uima.ruta.type.DebugMatchedRuleMatch");
Type ruleApplyType = cas.getTypeSystem().getType(
"org.apache.uima.ruta.type.DebugRuleApply");
Type blockApplyType = cas.getTypeSystem().getType(
"org.apache.uima.ruta.type.DebugBlockApply");
removeDebugAnnotations(cas, matchedType, ruleApplyType, blockApplyType);
ae.process(cas);
Feature innerApplyFeature = blockApplyType.getFeatureByBaseName("innerApply");
Feature ruleApplyFeature = blockApplyType.getFeatureByBaseName("rules");
FSIterator<AnnotationFS> iterator = cas.getAnnotationIndex(blockApplyType).iterator();
boolean foundOne = false;
while (iterator.isValid()) {
if (monitor.isCanceled()) {
if (ae != null) {
ae.destroy();
}
if(cas != null) {
cas.release();
}
return Status.CANCEL_STATUS;
}
AnnotationFS fs = iterator.get();
int find = findRuleMatches(result, fs, each, queryComposite, matchedType,
ruleApplyType, blockApplyType, innerApplyFeature, ruleApplyFeature);
iterator.moveToNext();
found += find;
if (!foundOne && find > 0) {
foundOne = true;
files++;
}
final int constFound = found;
final int constFiles = files;
queryComposite.getDisplay().syncExec(new Runnable() {
public void run() {
queryComposite.setResult(result);
queryComposite.setResultInfo(constFound, constFiles);
}
});
}
monitor.worked(1);
}
cas.release();
ae.destroy();
monitor.done();
} catch (Exception e) {
RutaAddonsPlugin.error(e);
}
return Status.OK_STATUS;
}
private void removeDebugAnnotations(CAS cas, Type matchedType, Type ruleApplyType,
Type blockApplyType) {
Collection<AnnotationFS> toRemove = new ArrayList<AnnotationFS>();
AnnotationIndex<AnnotationFS> annotationIndex = cas.getAnnotationIndex(blockApplyType);
for (AnnotationFS annotationFS : annotationIndex) {
toRemove.add(annotationFS);
}
annotationIndex = cas.getAnnotationIndex(ruleApplyType);
for (AnnotationFS annotationFS : annotationIndex) {
toRemove.add(annotationFS);
}
annotationIndex = cas.getAnnotationIndex(matchedType);
for (AnnotationFS annotationFS : annotationIndex) {
toRemove.add(annotationFS);
}
for (AnnotationFS annotationFS : toRemove) {
cas.removeFsFromIndexes(annotationFS);
}
}
public int findRuleMatches(final List<QueryResult> result, AnnotationFS fs, File file,
final QueryComposite queryComposite, Type matchedType, Type ruleApplyType,
Type blockApplyType, Feature innerApplyFeature, Feature ruleApplyFeature) {
int ret = 0;
if (fs.getType().equals(blockApplyType)) {
FeatureStructure featureValue = fs.getFeatureValue(innerApplyFeature);
FSArray array = (FSArray) featureValue;
for (int i = 0; i < array.size(); i++) {
AnnotationFS eachApply = (AnnotationFS) array.get(i);
ret += findRuleMatches(result, eachApply, file, queryComposite, matchedType,
ruleApplyType, blockApplyType, innerApplyFeature, ruleApplyFeature);
}
} else if (fs.getType().equals(ruleApplyType)) {
FeatureStructure featureValue = fs.getFeatureValue(ruleApplyFeature);
FSArray array = (FSArray) featureValue;
for (int i = 0; i < array.size(); i++) {
AnnotationFS eachApply = (AnnotationFS) array.get(i);
ret += findRuleMatches(result, eachApply, file, queryComposite, matchedType,
ruleApplyType, blockApplyType, innerApplyFeature, ruleApplyFeature);
}
} else if (fs.getType().equals(matchedType)) {
result.add(new QueryResult(fs.getBegin(), fs.getEnd(), fs.getCoveredText(), file));
ret += 1;
}
return ret;
}
}
public void addHandlerListener(IHandlerListener handlerListener) {
}
public void dispose() {
}
public Object execute(ExecutionEvent event) throws ExecutionException {
QueryView queryView = (QueryView) HandlerUtil.getActivePart(event);
QueryComposite queryComposite = queryView.getComposite();
String dir = queryComposite.getDataDirectory();
String typesystem = queryComposite.getTypeSystem();
String script = queryComposite.getScript();
boolean recurive = queryComposite.isRecursive();
QueryHandlerJob job = new QueryHandlerJob(event, dir, typesystem, script, recurive);
job.addJobChangeListener(new QueryJobChangeAdapter(queryComposite) {
});
job.schedule();
return null;
}
public boolean isEnabled() {
return true;
}
public boolean isHandled() {
return true;
}
public void removeHandlerListener(IHandlerListener handlerListener) {
}
public static List<File> getFiles(File dir, boolean recusive) {
List<File> result = new ArrayList<File>();
for (File each : dir.listFiles()) {
// TODO: find a solution for this hotfix
if (each.getName().endsWith(".svn")) {
continue;
}
result.add(each);
if (each.isDirectory() && recusive) {
result.addAll(getFiles(each, recusive));
}
}
return result;
}
}