blob: 3c05d5a91ae01f69259b2fd486d8fee7609263e9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 Aston University.
*
* 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:
* Antonio Garcia-Dominguez - initial API and implementation
******************************************************************************/
package org.eclipse.hawk.timeaware.queries.operations.scopes.predicates;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Function;
import java.util.function.Supplier;
import org.eclipse.epsilon.eol.dom.Expression;
import org.eclipse.epsilon.eol.exceptions.EolInternalException;
import org.eclipse.epsilon.eol.execute.context.FrameStack;
import org.eclipse.epsilon.eol.execute.context.FrameType;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
import org.eclipse.epsilon.eol.execute.context.Variable;
import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode;
import org.eclipse.hawk.timeaware.queries.TimeAwareEOLQueryEngine;
import org.eclipse.hawk.timeaware.queries.operations.TimeAwareNodeFirstOrderOperation;
/**
* <p>
* Generic EOL declarative operation which tries to find a timepoint matching
* a predicate from the current timepoint of the target node, and passes
* the original and matching nodes to a wrapper for decoration. The wrapper
* will usually limit the range of versions available to the returned node.
* </p>
*
* <p>
* If no such timepoint exists, the operation will return an undefined value,
* which can be checked against with <code>.isDefined()</code>.
* </p>
*/
public class VersionRangeOperation extends TimeAwareNodeFirstOrderOperation {
@FunctionalInterface
public interface IRangeBasedNodeScoper {
ITimeAwareGraphNode scope(ITimeAwareGraphNode original, ITimeAwareGraphNode predicateMatch);
}
private final IRangeBasedNodeScoper nodeScoper;
public VersionRangeOperation(Supplier<TimeAwareEOLQueryEngine> containerModelSupplier, IRangeBasedNodeScoper nodeScoper) {
super(containerModelSupplier);
this.nodeScoper = nodeScoper;
}
@Override
protected Object execute(Variable iterator, Expression expression, IEolContext context,
Function<ITimeAwareGraphNode, Object> versionWrapper, ITimeAwareGraphNode taNode)
throws EolInternalException {
try {
final long latestInstant = taNode.getLatestInstant();
final List<ITimeAwareGraphNode> versions = taNode.getVersionsBetween(taNode.getTime(), latestInstant);
final FrameStack scope = context.getFrameStack();
for (ListIterator<ITimeAwareGraphNode> itVersion = versions.listIterator(versions.size()); itVersion.hasPrevious(); ) {
final ITimeAwareGraphNode version = itVersion.previous();
final Object listItem = versionWrapper.apply(version);
if (iterator.getType()==null || iterator.getType().isKind(listItem)){
scope.enterLocal(FrameType.UNPROTECTED, expression);
scope.put(Variable.createReadOnlyVariable(iterator.getName(), listItem));
Object bodyResult = context.getExecutorFactory().execute(expression, context);
scope.leaveLocal(expression);
if (bodyResult instanceof Boolean && (boolean)bodyResult) {
final ITimeAwareGraphNode scoped = nodeScoper.scope(taNode, version);
if (scoped == null) {
return null;
} else {
return versionWrapper.apply(scoped);
}
}
}
}
} catch (Exception ex) {
throw new EolInternalException(ex, expression);
}
return null;
}
@Override
public boolean isOverridable() {
return false;
}
}