/******************************************************************************* * Copyright (c) 2014-2016 IncQuery Labs Ltd. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Akos Horvath, Abel Hegedus, Marton Bur, Zoltan Ujhelyi, Robert Doczi - initial API and implementation *******************************************************************************/ package org.eclipse.viatra.examples.cps.xform.m2t.monitor; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.viatra.examples.cps.deployment.BehaviorState; import org.eclipse.viatra.examples.cps.deployment.BehaviorTransition; import org.eclipse.viatra.examples.cps.deployment.Deployment; import org.eclipse.viatra.examples.cps.deployment.DeploymentApplication; import org.eclipse.viatra.examples.cps.deployment.DeploymentElement; import org.eclipse.viatra.examples.cps.deployment.DeploymentHost; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.ApplicationBehaviorCurrentStateChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.ApplicationIdChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.BehaviorChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.DeploymentHostIpChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.DeploymentHostsChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.HostApplicationsChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.HostIpChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.TransitionChangeQuerySpecification; import org.eclipse.viatra.examples.cps.xform.m2t.monitor.util.TriggerChangeQuerySpecification; import org.eclipse.viatra.query.runtime.api.IMatchProcessor; import org.eclipse.viatra.query.runtime.api.IPatternMatch; import org.eclipse.viatra.query.runtime.api.IQuerySpecification; import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine; import org.eclipse.viatra.query.runtime.api.ViatraQueryMatcher; import org.eclipse.viatra.query.runtime.exception.ViatraQueryException; import org.eclipse.viatra.transformation.evm.api.ExecutionSchema; import org.eclipse.viatra.transformation.evm.api.Job; import org.eclipse.viatra.transformation.evm.api.RuleSpecification; import org.eclipse.viatra.transformation.evm.specific.ExecutionSchemas; import org.eclipse.viatra.transformation.evm.specific.Jobs; import org.eclipse.viatra.transformation.evm.specific.Lifecycles; import org.eclipse.viatra.transformation.evm.specific.Rules; import org.eclipse.viatra.transformation.evm.specific.Schedulers; import org.eclipse.viatra.transformation.evm.specific.crud.CRUDActivationStateEnum; import org.eclipse.viatra.transformation.evm.specific.job.EnableJob; import org.eclipse.viatra.transformation.evm.specific.scheduler.UpdateCompleteBasedScheduler.UpdateCompleteBasedSchedulerFactory; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @SuppressWarnings("unchecked") public class DeploymentChangeMonitor extends AbstractDeploymentChangeMonitor { private Set<DeploymentElement> appearBetweenCheckpoints; private Set<DeploymentElement> updateBetweenCheckpoints; private Set<DeploymentElement> disappearBetweenCheckpoints; private Set<DeploymentElement> appearAccumulator; private Set<DeploymentElement> updateAccumulator; private Set<DeploymentElement> disappearAccumulator; private boolean deploymentBetweenCheckpointsChanged; private boolean deploymentChanged; private ExecutionSchema executionSchema; private HashMap<DeploymentApplication, String> appsToIDs; private HashMap<DeploymentHost, String> hostsToIPs; public DeploymentChangeMonitor(Deployment deployment, ViatraQueryEngine engine) { super(deployment, engine); this.appearBetweenCheckpoints = Sets.newHashSet(); this.updateBetweenCheckpoints = Sets.newHashSet(); this.disappearBetweenCheckpoints = Sets.newHashSet(); this.appearAccumulator = Sets.newHashSet(); this.updateAccumulator = Sets.newHashSet(); this.disappearAccumulator = Sets.newHashSet(); deploymentBetweenCheckpointsChanged = false; deploymentChanged = false; UpdateCompleteBasedSchedulerFactory schedulerFactory = Schedulers .getQueryEngineSchedulerFactory(engine); executionSchema = ExecutionSchemas .createViatraQueryExecutionSchema(engine, schedulerFactory); hostsToIPs = Maps.newHashMap(); appsToIDs = Maps.newHashMap(); for (DeploymentHost deploymentHost : deployment.getHosts()) { hostsToIPs.put(deploymentHost, deploymentHost.getIp()); for (DeploymentApplication deploymentApplication : deploymentHost.getApplications()) { appsToIDs.put(deploymentApplication, deploymentApplication.getId()); } } executionSchema.getContext().put(ChangeMonitorJob.HOSTS,hostsToIPs); executionSchema.getContext().put(ChangeMonitorJob.APPLICATIONS,Maps.newHashMap()); } @Override public DeploymentChangeDelta createCheckpoint() { appearBetweenCheckpoints = appearAccumulator; updateBetweenCheckpoints = updateAccumulator; disappearBetweenCheckpoints = disappearAccumulator; appearAccumulator = Sets.newHashSet(); updateAccumulator = Sets.newHashSet(); disappearAccumulator = Sets.newHashSet(); deploymentBetweenCheckpointsChanged = deploymentChanged; Map<DeploymentElement, String> elementsUpdatedOrDeleted = (Map<DeploymentElement, String>) executionSchema.getContext().get(ChangeMonitorJob.OUTDATED_ELEMENTS); if(elementsUpdatedOrDeleted == null){ elementsUpdatedOrDeleted = Maps.newHashMap(); } for (DeploymentElement deploymentElement : elementsUpdatedOrDeleted.keySet()) { // Refresh the list of host IP addresses and app identifiers if(deploymentElement instanceof DeploymentHost){ hostsToIPs.put((DeploymentHost) deploymentElement, ((DeploymentHost) deploymentElement).getIp()); } else if(deploymentElement instanceof DeploymentApplication){ appsToIDs.put((DeploymentApplication) deploymentElement, ((DeploymentApplication) deploymentElement).getId()); } } executionSchema.getContext().put(ChangeMonitorJob.OUTDATED_ELEMENTS,Maps.newHashMap()); return new DeploymentChangeDelta( appearBetweenCheckpoints, updateBetweenCheckpoints, disappearBetweenCheckpoints, elementsUpdatedOrDeleted, deploymentBetweenCheckpointsChanged ); } @Override public DeploymentChangeDelta getDeltaSinceLastCheckpoint() { return new DeploymentChangeDelta( appearAccumulator, updateAccumulator, disappearAccumulator, (Map<DeploymentElement, String>) executionSchema.getContext().get(ChangeMonitorJob.OUTDATED_ELEMENTS), deploymentChanged ); } @Override public void startMonitoring() throws ViatraQueryException { ModelChangeListenerQueries.instance().prepare(engine); Set<Job<?>> allJobs = Sets.newHashSet(); Set<Job<IPatternMatch>> deploymentJobs = createDeploymentJobs(); allJobs.addAll(deploymentJobs); IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>> deploymentHostChangeQuerySpec = (IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) DeploymentHostsChangeQuerySpecification .instance(); IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>> deploymentHostIpChangeQuerySpec = (IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) DeploymentHostIpChangeQuerySpecification .instance(); registerJobsForPattern(executionSchema, deploymentJobs, deploymentHostChangeQuerySpec); registerJobsForPattern(executionSchema, deploymentJobs, deploymentHostIpChangeQuerySpec); Map<IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>, Set<Job<IPatternMatch>>> querySpecificationsToJobs = getDeploymentElementChangeQuerySpecifications(); for (IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>> querySpec : querySpecificationsToJobs .keySet()) { registerJobsForPattern(executionSchema, querySpecificationsToJobs.get(querySpec), querySpec); } Collection<Set<Job<IPatternMatch>>> registeredJobs = querySpecificationsToJobs .values(); for (Set<Job<IPatternMatch>> deploymentElementJobs : registeredJobs) { allJobs.addAll(deploymentElementJobs); } executionSchema.startUnscheduledExecution(); // Enable the jobs to listen to changes for (Job<?> job : allJobs) { EnableJob<?> enableJob = (EnableJob<?>) job; enableJob.setEnabled(true); } } private Set<Job<IPatternMatch>> createDeploymentJobs() { Set<Job<IPatternMatch>> jobs = Sets.newHashSet(); IMatchProcessor<IPatternMatch> matchProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { deploymentChanged = true; } }; Job<IPatternMatch> appear = Jobs.newStatelessJob( CRUDActivationStateEnum.CREATED, matchProcessor); Job<IPatternMatch> disappear = Jobs.newStatelessJob( CRUDActivationStateEnum.DELETED, matchProcessor); Job<IPatternMatch> update = Jobs.newStatelessJob( CRUDActivationStateEnum.UPDATED,matchProcessor); jobs.add(Jobs.newEnableJob(appear)); jobs.add(Jobs.newEnableJob(disappear)); jobs.add(Jobs.newEnableJob(update)); return jobs; } private void registerJobsForPattern( ExecutionSchema executionSchema, Set<Job<IPatternMatch>> deploymentElementJobs, IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>> changeQuerySpecification) { RuleSpecification<IPatternMatch> applicationRules = Rules .newMatcherRuleSpecification(changeQuerySpecification, Lifecycles.getDefault(true, true), deploymentElementJobs); executionSchema.addRule(applicationRules); } private Map<IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>, Set<Job<IPatternMatch>>> getDeploymentElementChangeQuerySpecifications() throws ViatraQueryException { Map<IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>, Set<Job<IPatternMatch>>> querySpecifications = Maps .newHashMap(); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) HostApplicationsChangeQuerySpecification .instance(), hostChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) HostIpChangeQuerySpecification .instance(), hostChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) ApplicationIdChangeQuerySpecification .instance(), applicationChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) ApplicationBehaviorCurrentStateChangeQuerySpecification .instance(), applicationChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) BehaviorChangeQuerySpecification .instance(), behaviorChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) TransitionChangeQuerySpecification .instance(), behaviorChangeJobs()); querySpecifications .put((IQuerySpecification<? extends ViatraQueryMatcher<IPatternMatch>>) TriggerChangeQuerySpecification .instance(), behaviorChangeJobs()); return querySpecifications; } private Set<Job<IPatternMatch>> hostChangeJobs() { IMatchProcessor<IPatternMatch> appearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerAppear(match); } }; IMatchProcessor<IPatternMatch> disappearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { DeploymentHost host = (DeploymentHost) match.get(0); if (host.eContainer() != null) { registerUpdate(match); } else { registerDisappear(match); } } }; IMatchProcessor<IPatternMatch> updateProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerUpdate(match); } }; return createDeploymentElementJobs(appearProcessor, disappearProcessor, updateProcessor); } /** * @return specific jobs for applicationChanges */ private Set<Job<IPatternMatch>> applicationChangeJobs() { IMatchProcessor<IPatternMatch> appearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerAppear(match); } }; IMatchProcessor<IPatternMatch> disappearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerDisappear(match); } }; IMatchProcessor<IPatternMatch> updateProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerUpdate(match); } }; return createDeploymentElementJobs(appearProcessor, disappearProcessor, updateProcessor); } private Set<Job<IPatternMatch>> behaviorChangeJobs() { IMatchProcessor<IPatternMatch> appearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerAppear(match); } }; IMatchProcessor<IPatternMatch> disappearProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { if (match.get("state") != null) { BehaviorState state = ((BehaviorState) match.get("state")); if (state.eContainer() == null) { registerUpdate(match); } } else if (match.get("transition") != null) { BehaviorTransition transition = ((BehaviorTransition) match .get("transition")); if (transition.eContainer() == null) { registerUpdate(match); } } else { registerDisappear(match); } } }; IMatchProcessor<IPatternMatch> updateProcessor = new IMatchProcessor<IPatternMatch>() { @Override public void process(IPatternMatch match) { registerUpdate(match); } }; return createDeploymentElementJobs(appearProcessor, disappearProcessor, updateProcessor); } private void registerUpdate(IPatternMatch match) { DeploymentElement deploymentElement = (DeploymentElement) match.get(0); if (!appearAccumulator.contains(deploymentElement)) { updateAccumulator.add(deploymentElement); } } private void registerAppear(IPatternMatch match) { DeploymentElement deploymentElement = (DeploymentElement) match.get(0); disappearAccumulator.remove(deploymentElement); updateAccumulator.remove(deploymentElement); appearAccumulator.add(deploymentElement); } private void registerDisappear(IPatternMatch match) { DeploymentElement deploymentElement = (DeploymentElement) match.get(0); appearAccumulator.remove(deploymentElement); updateAccumulator.remove(deploymentElement); disappearAccumulator.add(deploymentElement); } private Set<Job<IPatternMatch>> createDeploymentElementJobs( IMatchProcessor<IPatternMatch> appearProcessor, IMatchProcessor<IPatternMatch> disappearProcessor, IMatchProcessor<IPatternMatch> updateProcessor) { Set<Job<IPatternMatch>> jobs = Sets.newHashSet(); Job<IPatternMatch> appear = new ChangeMonitorJob<IPatternMatch>( CRUDActivationStateEnum.CREATED, appearProcessor); Job<IPatternMatch> disappear = new ChangeMonitorJob<IPatternMatch>( CRUDActivationStateEnum.DELETED, disappearProcessor); Job<IPatternMatch> update = new ChangeMonitorJob<IPatternMatch>( CRUDActivationStateEnum.UPDATED, updateProcessor); jobs.add(Jobs.newEnableJob(appear)); jobs.add(Jobs.newEnableJob(disappear)); jobs.add(Jobs.newEnableJob(update)); return jobs; } }