blob: e67d101e57b03b0f7a39ccf0676f8c02c77627d5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2015 The University of York.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
*
* Contributors:
* Konstantinos Barmpis - initial API and implementation
******************************************************************************/
package org.eclipse.hawk.epsilon.emc;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.epsilon.common.parse.problem.ParseProblem;
import org.eclipse.epsilon.eol.EolModule;
import org.eclipse.epsilon.eol.execute.context.Variable;
import org.eclipse.hawk.core.IModelIndexer;
import org.eclipse.hawk.core.graph.IGraphNode;
import org.eclipse.hawk.epsilon.emc.EOLQueryEngine.GraphNodeWrapper;
import org.eclipse.hawk.epsilon.emc.pgetters.GraphPropertyGetter;
import org.eclipse.hawk.epsilon.emc.tracking.AccessListener;
import org.eclipse.hawk.graph.updater.DirtyDerivedFeaturesListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DeriveFeature {
private static final Logger LOGGER = LoggerFactory.getLogger(DeriveFeature.class);
public Object deriveFeature(Map<String, EolModule> cachedModules, IModelIndexer indexer, IGraphNode n,
EOLQueryEngine containerModel, String EOLScript) throws Exception {
// remove prefix (_NYD)
final String actualEOLScript = EOLScript.startsWith(DirtyDerivedFeaturesListener.NOT_YET_DERIVED_PREFIX)
? EOLScript.substring(DirtyDerivedFeaturesListener.NOT_YET_DERIVED_PREFIX.length())
: EOLScript;
try {
final EolModule currentModule = setupModule(cachedModules, indexer, n, containerModel, actualEOLScript);
if (currentModule == null) {
return "DERIVATION_PARSE_ERROR";
}
final GraphPropertyGetter pg = (GraphPropertyGetter) containerModel.getPropertyGetter();
final AccessListener accessListener = pg.getAccessListener();
accessListener.setSourceObject(n.getId() + "");
return runModule(n, currentModule);
} catch (Exception e) {
LOGGER.error("ERROR IN DERIVING ATTRIBUTE, returning \"DERIVATION_OTHER_ERROR\" as value", e);
}
return "DERIVATION_OTHER_ERROR";
}
public Object deriveTimelineAnnotation(Map<String, EolModule> cachedModules, IModelIndexer indexer, IGraphNode n,
EOLQueryEngine containerModel, String EOLScript) throws Exception {
final GraphPropertyGetter pg = (GraphPropertyGetter) containerModel.getPropertyGetter();
final boolean originalBroadcast = pg.getBroadcastStatus();
pg.setBroadcastAccess(false);
try {
final EolModule currentModule = setupModule(cachedModules, indexer, n, containerModel, EOLScript);
if (currentModule == null) {
return "DERIVATION_PARSE_ERROR";
}
return runModule(n, currentModule);
} catch (Exception e) {
LOGGER.error("ERROR IN DERIVING ATTRIBUTE, returning \"DERIVATION_OTHER_ERROR\" as value", e);
} finally {
pg.setBroadcastAccess(originalBroadcast);
}
return "DERIVATION_OTHER_ERROR";
}
private Object runModule(IGraphNode n, EolModule currentModule) {
try {
final Object ret = currentModule.execute();
return normalizeResult(ret);
} catch (Exception e) {
LOGGER.error("error in derive feature on {}, returning derivation execution error", n.getId());
LOGGER.error(e.getMessage(), e);
return "DERIVATION_EXECUTION_ERROR";
}
}
private Object normalizeResult(Object ret) {
if (!(ret instanceof Collection<?>)) {
return AbstractHawkModel.toPrimitive(ret);
} else {
Collection<Object> collection = null;
// check for uniqueness
if (ret instanceof Set<?>)
collection = new LinkedHashSet<>();
else
collection = new LinkedList<>();
final Collection<?> srcCollection = (Collection<?>) ret;
Class<?> elemClass = null;
for (Object o : srcCollection) {
Object converted = AbstractHawkModel.toPrimitive(o);
if (converted != null) {
collection.add(converted);
}
if (elemClass == null) {
elemClass = converted.getClass();
}
}
if (elemClass == null) {
elemClass = String.class;
}
Object r = Array.newInstance(elemClass, collection.size());
return collection.toArray((Object[]) r);
}
}
private EolModule setupModule(Map<String, EolModule> cachedModules, IModelIndexer indexer, IGraphNode n,
EOLQueryEngine containerModel, final String actualEOLScript) throws Exception {
EolModule currentModule;
if (!cachedModules.containsKey(actualEOLScript)) {
// not already parsed
LOGGER.debug("adding new module to cache, key: {}",
actualEOLScript.length() > 100
? actualEOLScript.substring(0, 100) + "\n[! long script, snipped !]"
: actualEOLScript
);
currentModule = initModule(indexer, containerModel);
currentModule.parse(actualEOLScript);
List<ParseProblem> pps = currentModule.getParseProblems();
for (ParseProblem p : pps) {
LOGGER.error("Parsing problem: {}", p);
}
if (pps.size() > 0) {
LOGGER.error("There were parse problems, returning \"DERIVATION_PARSE_ERROR\" as value\n");
return null;
} else {
cachedModules.put(actualEOLScript, currentModule);
}
} else {
// already parsed
currentModule = cachedModules.get(actualEOLScript);
}
final IGraphNode modelElementNode = n.getIncoming().iterator().next().getStartNode();
final GraphNodeWrapper meGW = containerModel.wrap(modelElementNode);
currentModule.getContext().getFrameStack().put(Variable.createReadOnlyVariable("self", meGW));
return currentModule;
}
private EolModule initModule(IModelIndexer m, EOLQueryEngine model) throws Exception {
EolModule currentModule = new EolModule();
model.load(m);
currentModule.getContext().getModelRepository().addModel(model);
return currentModule;
}
}