/******************************************************************************* | |
* 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; | |
} | |
} |