/******************************************************************************* * Copyright (c) 2009, 2010 SAP AG and others. * 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: * SAP AG - initial API and implementation ******************************************************************************/ package org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.tasks; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.ocl.ecore.OCL; import org.eclipse.ocl.ecore.internal.OCLStandardLibraryImpl; import org.eclipse.ocl.ecore.opposites.OppositeEndFinder; import org.eclipse.ocl.examples.eventmanager.EventFilter; import org.eclipse.ocl.examples.impactanalyzer.ImpactAnalyzer; import org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.model.ResourceWithSize; import org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.notifications.RawNotification; import org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.ocl.EnvironmentFactory; import org.eclipse.ocl.examples.impactanalyzer.benchmark.preparation.ocl.OCLExpressionWithContext; @SuppressWarnings("restriction") public class ModelSizeVariationBenchmarkTask implements BenchmarkTask{ private final ImpactAnalyzer ia; private final RawNotification rawNotification; private Notification notification; private Resource model; private OCL ocl; /** * Also store original model in order to evaluate expression on model state before the value changed */ private Resource modelForIaAccuracyDetermination; private final LinkedHashMap<String, String> additionalInformation = new LinkedHashMap<String, String>(); private final LinkedHashMap<String, String> additionalMeasurementInformation = new LinkedHashMap<String, String>(); private Collection<EObject> result = null; private Collection<Object> evaluationResult = null; private final ArrayList<Collection<EObject>> allResults = new ArrayList<Collection<EObject>>(); private final OCLExpressionWithContext expression; private final OppositeEndFinder oppositeEndFinder; private AllInstanceEvaluationMeasurement allInstanceMeasurement; private boolean filterMatches; public ModelSizeVariationBenchmarkTask(OCLExpressionWithContext expression, RawNotification notification, ImpactAnalyzer imp, String oclId, String notificationId, String benchmarkTaskId, String optionId, String modelId, OppositeEndFinder oppositeEndFinder) { this.expression = expression; rawNotification = notification; ia = imp; this.oppositeEndFinder = oppositeEndFinder; additionalInformation.put("optionId", optionId); additionalInformation.put("benchmarkTaskId", benchmarkTaskId); additionalInformation.put("notificationId", notificationId); additionalInformation.put("oclId", oclId); additionalInformation.put("modelId", modelId); } public boolean activate(){ // For creating the notification the model is changed. Therefore the // creation of notifications shall be happen just before the benchmark task // is executed. assert getModel() != null; //additionalInformation.put("resourceUri", String.valueOf(getModel().getURI().toString().replaceAll("\t", ""))); additionalInformation.put("modelSize", String.valueOf(getModelSize(getModel()))); notification = getRawNotification().convertToNotification(getModel()); EventFilter filter = null; if(notification != null) { filter = ia.createFilterForExpression(); if(filter.matchesFor(notification)){ additionalInformation.put("filtered", "TRUE"); }else{ additionalInformation.put("filtered", "FALSE"); } } setOcl(org.eclipse.ocl.examples.impactanalyzer.util.OCL.newInstance(oppositeEndFinder)); if(expression.getOclWithPackage() != null){ setOcl(OCL.newInstance(new EnvironmentFactory().createPackageContext(ocl.getEnvironment(), expression.getOclWithPackage().getPackage()))); } additionalInformation.putAll(allInstanceMeasurement.getAdditionalInformation()); if (notification != null && filter != null) { long beforeFilterMatchCheck = System.nanoTime(); filterMatches = filter.matchesFor(notification); long afterFilterMatchCheck = System.nanoTime(); additionalInformation.put("eventFilterMatchCheckTime", String.valueOf(afterFilterMatchCheck - beforeFilterMatchCheck)); } return notification != null; } @SuppressWarnings("unused") private Collection<EObject> getAllInstancesForContext(EClass context) { Iterator<EObject> allObjectIterator = model.getAllContents(); List<EObject> resultSet = new LinkedList<EObject>(); while(allObjectIterator.hasNext()){ EObject next = allObjectIterator.next(); if(context.isInstance(next)){ resultSet.add(next); } } return resultSet; } public void beforeCall() { assert additionalMeasurementInformation.size() == 0; assert result == null; assert evaluationResult == null; evaluationResult = new ArrayList<Object>(); if(notification == null) throw new RuntimeException("notification cannot be created"); ((AllInstanceCallCountingOppositeEndFinder)getOppositeEndFinder()).resetAll(); } public Collection<EObject> call() throws Exception { if (filterMatches) { result = ia.getContextObjects(notification); } else { result = Collections.emptySet(); } return result; } public void callEvaluation() { /*for(EObject affectedElement : result){ evaluationResult.add(getOcl().evaluate(affectedElement, expression.getExpression())); }*/ } public void afterCall() { assert result != null; assert evaluationResult != null; int allInstancesCalls = ((AllInstanceCallCountingOppositeEndFinder)getOppositeEndFinder()).getAllInstancesCalled(); additionalMeasurementInformation.put("noIaAllInstanceCalls", String.valueOf(allInstancesCalls)); int findOppositeEndsCalls = ((AllInstanceCallCountingOppositeEndFinder)getOppositeEndFinder()).getFindOppositeEndsCalled(); additionalMeasurementInformation.put("noIaFindOppositeEndsCalls", String.valueOf(findOppositeEndsCalls)); int getAllOppositeEndsCalls = ((AllInstanceCallCountingOppositeEndFinder)getOppositeEndFinder()).getGetAllOppositeEndsCalled(); additionalMeasurementInformation.put("noIaGetAllOppositeEndsCalls", String.valueOf(getAllOppositeEndsCalls)); additionalMeasurementInformation.put("noContextObjects", String.valueOf(result.size())); int noOfInvalidEvaluations = getNoOfInvalidEvaluations(evaluationResult); additionalMeasurementInformation.put("noInvalidEvals", String.valueOf(noOfInvalidEvaluations)); int numberOfTracebackStepsExecuted = ((AllInstanceCallCountingOppositeEndFinder) getOppositeEndFinder()).getTracebackStepExecutions(); additionalMeasurementInformation.put("noTracebackStepsExecuted", String.valueOf(numberOfTracebackStepsExecuted)); ((AllInstanceCallCountingOppositeEndFinder)getOppositeEndFinder()).resetAll(); long timeToEvaluate = 0; long timeToEvaluateWithoutInvalidResults = 0; for(EObject affectedElement : result){ long before = System.nanoTime(); Object result = getOcl().evaluate(affectedElement, expression.getExpression()); long after = System.nanoTime(); evaluationResult.add(result); timeToEvaluate = timeToEvaluate + (after - before); if(result == null || !result.equals(OCLStandardLibraryImpl.INSTANCE.getInvalid())){ timeToEvaluateWithoutInvalidResults = timeToEvaluateWithoutInvalidResults + (after - before); } } additionalInformation.put("evaluationTimeAfter", String.valueOf(new Long(timeToEvaluate))); additionalInformation.put("evaluationTimeWoInvalid", String.valueOf(new Long(timeToEvaluateWithoutInvalidResults))); evaluationResult = null; allResults.add(result); result = null; } public boolean deactivate() { Collection<EObject> result = allResults.get(0); List<Object> beforeEvaluationResult = evaluateOnAffectedElement(result); additionalInformation.put("beforeNoInvalidEvals", String.valueOf(getNoOfInvalidEvaluations(beforeEvaluationResult))); // Change model by creating a real notification through changing the // original model rawNotification.convertToNotification(getModelForIaAccuracyDetermination()); List<Object> afterEvaluationResult = evaluateOnAffectedElement(result); additionalInformation.put("afterNoInvalidEvals", String.valueOf(getNoOfInvalidEvaluations(afterEvaluationResult))); additionalInformation.put("noEqualResultsBeforeAndAfter", String.valueOf(getNumberOfEqualResults(beforeEvaluationResult, afterEvaluationResult))); return true; } @SuppressWarnings("unchecked") private int getNumberOfEqualResults(List<Object> result1, List<Object> result2) { int equalCounter = 0; assert result1.size() == result2.size(); for (int i = 0; i < result1.size(); i++) { Object elementInResult1 = result1.get(i); Object elementInResult2 = result2.get(i); if (elementInResult1 instanceof EList<?> && elementInResult2 instanceof EList<?>) { if (((EList<EObject>) elementInResult1).containsAll((EList<EObject>) elementInResult2) && ((EList<EObject>) elementInResult2).containsAll((EList<EObject>) elementInResult1)) { equalCounter++; } } else if (elementInResult1 instanceof EObject && elementInResult2 instanceof EObject && EcoreUtil.equals((EObject) elementInResult1, (EObject) elementInResult2)) { equalCounter++; } else if (elementInResult1 == null && elementInResult2 == null){ equalCounter++; } else { if (elementInResult1 != null && elementInResult1.equals(elementInResult2)) { equalCounter++; } } } return equalCounter; } private List<Object> evaluateOnAffectedElement(Collection<EObject> result) { List<Object> evaluationResult = new LinkedList<Object>(); for(EObject affectedElement : result){ EObject element = getElementWithSameIdOutOfAnotherResource(model, affectedElement, getModelForIaAccuracyDetermination()); evaluationResult.add(ocl.evaluate(element, expression.getExpression())); } return evaluationResult; } private EObject getElementWithSameIdOutOfAnotherResource(Resource model2, EObject affectedElement, Resource originalModel2) { String id = model2.getURIFragment(affectedElement); return originalModel2.getEObject(id); } public int getNoOfInvalidEvaluations(Collection<Object> evaluationResult) { int invalidEvaluationCounter = 0; for(Object result : evaluationResult){ if(result != null && result.equals(OCLStandardLibraryImpl.INSTANCE.getInvalid())){ invalidEvaluationCounter++; } } return invalidEvaluationCounter; } public Notification getNotification(){ return notification; } @Override public String toString(){ return getAdditionalInformation().toString(); } public Notification getRecentNotificiation() { return notification; } public Map<String, String> getAdditionalInformation() { return additionalInformation; } private int getModelSize(Resource resource){ int resourceSize; if (resource instanceof ResourceWithSize) { resourceSize = ((ResourceWithSize) resource).getSize(); } else { resourceSize = 0; TreeIterator<EObject> iterator = resource.getAllContents(); while (iterator.hasNext()) { iterator.next(); resourceSize++; } } return resourceSize; } public Map<String, String> getAdditionalMeasurementInformation() { LinkedHashMap<String, String> result = new LinkedHashMap<String,String>(); result.putAll(additionalMeasurementInformation); additionalMeasurementInformation.clear(); return result; } public void setModel(Resource model) { this.model = model; } public Resource getModel() { return model; } public Object getResult() { return result; } public void setOcl(OCL ocl) { this.ocl = ocl; } public OCL getOcl() { return ocl; } public void setEvaluationResult(Collection<Object> evaluationResult) { this.evaluationResult = evaluationResult; } public Collection<Object> getEvaluationResult() { return evaluationResult; } public void setResult(Collection<EObject> result) { this.result = result; } public RawNotification getRawNotification() { return rawNotification; } public OCLExpressionWithContext getExpression() { return expression; } public void setModelForIaAccuracyDetermination(Resource modelForIaAccuracyDetermination) { this.modelForIaAccuracyDetermination = modelForIaAccuracyDetermination; } public Resource getModelForIaAccuracyDetermination() { return modelForIaAccuracyDetermination; } public OppositeEndFinder getOppositeEndFinder() { return oppositeEndFinder; } public void setAllInstanceEvaluationMeasurement(AllInstanceEvaluationMeasurement measurement) { allInstanceMeasurement = measurement; } }