| /******************************************************************************* |
| * Copyright (c) 2018-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; |
| |
| |
| import org.eclipse.epsilon.eol.execute.operations.EolOperationFactory; |
| import org.eclipse.hawk.core.graph.timeaware.ITimeAwareGraphNode; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.AlwaysReducer; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.BoundedVersionQuantifierOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.EventuallyAtLeastReducer; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.EventuallyAtMostReducer; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.EventuallyReducer; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.NeverReducer; |
| import org.eclipse.hawk.timeaware.queries.operations.patterns.VersionQuantifierOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.EndingTimeAwareNodeWrapper; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.StartingTimeAwareNodeWrapper; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.annotations.AfterAnnotatedOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.annotations.BeforeAnnotatedOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.annotations.SinceAnnotatedOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.annotations.UntilAnnotatedOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.annotations.WhenAnnotatedOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.predicates.VersionRangeOperation; |
| import org.eclipse.hawk.timeaware.queries.operations.scopes.predicates.WhenOperation; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * Extended version of the EOL operation factory, adding a new set of first-order |
| * operations over the versions of types and nodes. |
| */ |
| public class TimeAwareEOLOperationFactory extends EolOperationFactory { |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(TimeAwareEOLOperationFactory.class); |
| |
| private final TimeAwareEOLQueryEngine containerModel; |
| |
| public TimeAwareEOLOperationFactory(TimeAwareEOLQueryEngine model) { |
| this.containerModel = model; |
| |
| operationCache.put("always", |
| new VersionQuantifierOperation(this::getContainerModel, new AlwaysReducer())); |
| operationCache.put("never", |
| new VersionQuantifierOperation(this::getContainerModel, new NeverReducer())); |
| operationCache.put("eventually", |
| new VersionQuantifierOperation(this::getContainerModel, new EventuallyReducer())); |
| operationCache.put("eventuallyAtMost", |
| new BoundedVersionQuantifierOperation(this::getContainerModel, (count -> new EventuallyAtMostReducer(count)))); |
| operationCache.put("eventuallyAtLeast", |
| new BoundedVersionQuantifierOperation(this::getContainerModel, (count -> new EventuallyAtLeastReducer(count)))); |
| |
| /* |
| * First-order operation that makes the target time-aware node travel to the |
| * first timepoint since the current timepoint where a particular predicate was |
| * true, if it exists. The returned time-aware node will only report the |
| * versions since that moment: any past history will be ignored. |
| * |
| * This means that if you want to search through the entire history of a node, |
| * you will have to use <code>node.earliest.since(...)</code>. This is done to |
| * make it easier to restrict the scope of the search in long histories. |
| * |
| * If no such timepoint exists, the operation will return an undefined value, |
| * which can be checked against with <code>.isDefined()</code>. |
| */ |
| operationCache.put("since", |
| new VersionRangeOperation(this::getContainerModel, |
| (original, match) -> new StartingTimeAwareNodeWrapper(match))); |
| |
| /* |
| * Variant of .since which does not include the matching version, implementing |
| * an exclusive starting range. |
| */ |
| operationCache.put("after", |
| new VersionRangeOperation(this::getContainerModel, |
| (original, version) -> { |
| try { |
| ITimeAwareGraphNode nextVersion = version.getNext(); |
| if (nextVersion != null) { |
| return new StartingTimeAwareNodeWrapper(nextVersion); |
| } |
| } catch (Exception e) { |
| LOGGER.error(e.getMessage(), e); |
| } |
| |
| return null; |
| } |
| )); |
| |
| /* |
| * First-order operation that returns a version of the current node which |
| * will only report versions up to and including the first timepoint for |
| * which the predicate is true. This implements a closed ending range. |
| * |
| * If no such timepoint exists, the operation will return an undefined value, |
| * which can be checked against with <code>.isDefined()</code>. |
| */ |
| operationCache.put("until", |
| new VersionRangeOperation(this::getContainerModel, |
| (original, version) -> new EndingTimeAwareNodeWrapper(original, version.getTime()) |
| )); |
| |
| /* |
| * First-order operation that returns a version of the current node which |
| * will only report versions before (excluding) the first timepoint for |
| * which the predicate is true. This implements an open ending range. |
| * |
| * If no such timepoint exists, the operation will return an undefined value, |
| * which can be checked against with <code>isDefined()</code>. |
| */ |
| operationCache.put("before", |
| new VersionRangeOperation(this::getContainerModel, (original, version) -> { |
| try { |
| final long prevInstant = version.getPreviousInstant(); |
| if (prevInstant != ITimeAwareGraphNode.NO_SUCH_INSTANT) { |
| return new EndingTimeAwareNodeWrapper(original, prevInstant); |
| } |
| } catch (Exception e) { |
| LOGGER.error("Could not retrieve previous instant for before", e); |
| } |
| |
| return null; |
| })); |
| |
| operationCache.put("when", new WhenOperation(this::getContainerModel)); |
| |
| /* |
| * Versions of these operations which use Boolean derived attributes in a |
| * time-aware node index. |
| */ |
| operationCache.put("whenAnnotated", new WhenAnnotatedOperation(this::getContainerModel)); |
| operationCache.put("sinceAnnotated", new SinceAnnotatedOperation(this::getContainerModel)); |
| operationCache.put("afterAnnotated", new AfterAnnotatedOperation(this::getContainerModel)); |
| operationCache.put("untilAnnotated", new UntilAnnotatedOperation(this::getContainerModel)); |
| operationCache.put("beforeAnnotated", new BeforeAnnotatedOperation(this::getContainerModel)); |
| } |
| |
| public TimeAwareEOLQueryEngine getContainerModel() { |
| return containerModel; |
| } |
| |
| } |