aplcache
Changes
.gitignore 34(+34 -0)
pom.xml 73(+73 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/FlowchartWorkFlow.java 377(+377 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodEntry.java 60(+60 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodStats.java 151(+151 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityMetrics.java 124(+124 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityPatternDecider.java 93(+93 -0)
src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/LogTrace.java 95(+95 -0)
Details
.gitignore 34(+34 -0)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4a482b8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+# ignore eclipse project files
+.project
+.classpath
+
+# ignore Intellij Idea project files
+.idea
+*.iml
+
+# Netbeans
+/nbproject/
+/nbactions.xml
+
+# Netbeans deploy
+/build/
+
+# Maven deploy
+/target/
+
+# Ant deploy
+/dist/
+
+# Class files
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
pom.xml 73(+73 -0)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..bbae100
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>APLCache</name>
+ <groupId>br.ufrgs.inf.prosoft.adaptivecaching</groupId>
+ <artifactId>APLCache</artifactId>
+ <version>1.0</version>
+
+ <properties>
+ <aspectj.version>1.8.10</aspectj.version>
+ <java.version>1.8</java.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.21</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ehcache</groupId>
+ <artifactId>sizeof</artifactId>
+ <version>0.3.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.5</version>
+ </dependency>
+ <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.5</version>
+ </dependency>
+ <dependency>
+ <groupId>br.ufrgs.inf.prosoft.trace</groupId>
+ <artifactId>Trace</artifactId>
+ <version>1.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.3</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ <useIncrementalCompilation>false</useIncrementalCompilation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.1.0</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ <mainClass>br.ufrgs.inf.prosoft.approachescomparison.adapter.Main</mainClass>
+ </manifest>
+ </archive>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/CacheDecider.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/CacheDecider.java
new file mode 100644
index 0000000..3e96c30
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/CacheDecider.java
@@ -0,0 +1,10 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodStats;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+
+public interface CacheDecider {
+
+ boolean isCacheable(MethodInfo methodInfo, MethodStats methodStats);
+
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/FlowchartWorkFlow.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/FlowchartWorkFlow.java
new file mode 100644
index 0000000..3849488
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/FlowchartWorkFlow.java
@@ -0,0 +1,377 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.CacheDecider;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodEntry;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodStats;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.stats.CacheabilityMetrics;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.stats.CacheabilityPatternDecider;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.LogTrace;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class FlowchartWorkFlow {
+
+ private final long population;
+ protected HashMap<MethodInfo, MethodStats> methodsInfoMap;
+ Logger logger = LoggerFactory.getLogger(FlowchartWorkFlow.class);
+
+ private CacheDecider decider;
+
+ private double sumMissRatio;
+ private double sumHitRatio;
+ private double sumExecutionTime;
+ private double sumShareability;
+ private double sumFrequency;
+ private List<Double> hitRatios = new ArrayList<>();
+ private List<Double> missRatios = new ArrayList<>();
+ private List<Long> executionTimes = new ArrayList<>();
+ private List<Double> shareabilities = new ArrayList<>();
+ private List<Long> frequencies = new ArrayList<>();
+
+ public FlowchartWorkFlow(List<LogTrace> logList) {
+ this.decider = new CacheabilityPatternDecider(logList.size(), this);
+ this.methodsInfoMap = countOccurrences(logList);
+ this.population = logList.size();
+
+ logger.debug(methodsInfoMap.size() + " unique method calls identified from " + logList.size() + " original traces");
+
+ //sorting to get threshold, also excluding duplicates
+// Collections.sort(executionTimes);
+// hitRatios = hitRatios.stream().distinct().collect(Collectors.toList());
+// Collections.sort(hitRatios);
+// missRatios = missRatios.stream().distinct().collect(Collectors.toList());
+// Collections.sort(missRatios);
+// shareabilities = shareabilities.stream().distinct().collect(Collectors.toList());
+// Collections.sort(shareabilities);
+ logger.debug("Average ExecutionTime: " + getAverageExecutionTime());
+ logger.debug("Average HitRatio: " + getAverageHitRatio());
+ logger.debug("Average MissRatio: " + getAverageMissRatio());
+ logger.debug("Average shareability: " + getAverageShareability());
+ logger.debug("StdDv ExecutionTime: " + getStdDevExecutionTimeRatio());
+ logger.debug("StdDv HitRatio: " + getStdDevHitRatio());
+ logger.debug("StdDv MissRatio: " + getStdDevMissRatio());
+ logger.debug("StdDv shareability: " + getStdDevShareability());
+ logger.debug("StdDv frequency: " + getStdDevFrequency());
+
+ int k = 0;
+ logger.debug("Using " + k + " stdDev to calculate thresholds...");
+ logger.debug("Threshold ExecutionTime: " + expensivenessThreshold(k));
+ logger.debug("Threshold HitRatio: " + hitThreshold(k));
+ logger.debug("Threshold MissRatio: " + missThreshold(k));
+ logger.debug("Threshold Shareability: " + shareabilityThreshold(k));
+ logger.debug("Threshold frequency: " + frequencyThreshold(k));
+ }
+
+ public Set<MethodEntry> filterCacheableMethods(long expiryTime) {
+ logger.debug("Deciding if methods are cacheable...");
+
+ Set<MethodEntry> cacheableMethods = getMethodsInfoMap().keySet().stream()
+ .filter(mi -> decider.isCacheable(mi, getMethodsInfoMap().get(mi)))
+ .map(mi -> new MethodEntry(mi, getMethodsInfoMap().get(mi), System.currentTimeMillis() + expiryTime))
+ .collect(Collectors.toSet());
+
+ logger.info(cacheableMethods.size() + " cacheable methods detected. Printing files...");
+
+ //TODO remove: print all unique methods and metrics to csv file
+ try {
+ final PrintWriter pw = new PrintWriter(new File("allmethods.csv"));
+ pw.write("isStaticData,changeMoreThanUsed,usedByManyRequests,isUserSpecific,isCacheSizeLarge,isDataSizeLarge,isExpensive,signature,numberOfSameOccurrences,numberOfDifferentReturnOccurrences,totalOccurrences,sameOccurrencesAverageExecutionTime,sameOccurrencesTotalExecutionTime,hitRatio,missRatio\n");
+ getMethodsInfoMap().keySet().stream().forEach(mi -> pw.write(CacheabilityMetrics.allMetricsToString(mi, getMethodsInfoMap().get(mi), this, getMethodsInfoMap().size()) + "," + new MethodEntry(mi, getMethodsInfoMap().get(mi), System.currentTimeMillis() + expiryTime).getMethodInfo().getSignature() + "," + new MethodEntry(mi, getMethodsInfoMap().get(mi), System.currentTimeMillis() + expiryTime).getMethodStats().toCSV() + '\n'));
+ pw.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ //TODO remove: print cacheable methods to csv file
+ try {
+ final PrintWriter pw = new PrintWriter(new File("cacheablemethods.csv"));
+ pw.write("isStaticData,changeMoreThanUsed,usedByManyRequests,isUserSpecific,isCacheSizeLarge,isDataSizeLarge,isExpensive,signature,numberOfSameOccurrences,numberOfDifferentReturnOccurrences,totalOccurrences,sameOccurrencesAverageExecutionTime,sameOccurrencesTotalExecutionTime,hitRatio,missRatio\n");
+ cacheableMethods.stream().forEach(ma -> pw.write(CacheabilityMetrics.allMetricsToString(ma.getMethodInfo(), ma.getMethodStats(), this, getMethodsInfoMap().size()) + "," + ma.getMethodInfo().getSignature() + "," + ma.getMethodStats().toCSV() + '\n'));
+ pw.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ return cacheableMethods;
+ }
+
+ public HashMap<MethodInfo, MethodStats> countOccurrences(List<LogTrace> logs) {
+
+ sumExecutionTime = 0;
+ sumHitRatio = 0;
+ sumMissRatio = 0;
+ sumShareability = 0;
+ sumFrequency = 0;
+
+ HashMap<MethodInfo, MethodStats> methodInfoMap = new HashMap<>();
+
+ for (int i = 0; i < logs.size(); i++) {
+ LogTrace logTrace = logs.get(i);
+
+ if (methodInfoMap.containsKey(logTrace.getMethodInfo())) {
+ continue;
+ }
+
+ MethodStats methodStats = new MethodStats(logTrace);
+
+ for (int j = 0; j < logs.size(); j++) {
+ LogTrace traceCompare = logs.get(j);
+
+ if (i == j) {
+ continue;
+ }
+
+ //if similar methods: same signature and params, different return
+// if(logTrace.getMethodInfo().getHashedArguments())
+ if (traceCompare.getMethodInfo().equalsWithoutReturnedValue(logTrace.getMethodInfo()) // || traceCompare.getMethodInfo().equalsHashedWithoutReturnedValue(logTrace.getMethodInfo())
+ ) {
+
+ //if identical methods
+ if (EqualsBuilder.reflectionEquals(traceCompare.getMethodInfo().getReturnedValue(), logTrace.getMethodInfo().getReturnedValue()) // || Objects.equals(traceCompare.getMethodInfo().getHashedReturnedValue(), logTrace.getMethodInfo().getHashedReturnedValue())
+ ) {
+ methodStats.addSameOccurrence(traceCompare);
+ } else {
+ methodStats.addDifferentReturnOccurrence();
+ }
+ }
+ }
+
+ methodInfoMap.put(logTrace.getMethodInfo(), methodStats);
+
+ sumExecutionTime += methodStats.getSameOccurrencesTotalExecutionTime();
+ executionTimes.add(methodStats.getSameOccurrencesTotalExecutionTime());
+
+ sumHitRatio += methodStats.hitRatio();
+ hitRatios.add(methodStats.hitRatio());
+
+ sumMissRatio += methodStats.missRatio();
+ missRatios.add(methodStats.missRatio());
+
+ sumShareability += methodStats.shareability();
+ shareabilities.add(methodStats.shareability());
+
+ sumFrequency += methodStats.getNumberOfSameOccurrences();
+ frequencies.add(methodStats.getNumberOfSameOccurrences());
+ }
+
+ return methodInfoMap;
+ }
+
+ /**
+ * General mean hit ratio of all calls
+ *
+ * @return
+ */
+ public double getAverageHitRatio() {
+ if (population == 0) {
+ return 0;
+ }
+ return new BigDecimal(sumHitRatio).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public double getAverageMissRatio() {
+ if (population == 0) {
+ return 0;
+ }
+ return new BigDecimal(sumMissRatio).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public double getAverageExecutionTime() {
+ if (population == 0) {
+ return 0;
+ }
+ return new BigDecimal(sumExecutionTime).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public double getAverageShareability() {
+ if (population == 0) {
+ return 0;
+ }
+ return new BigDecimal(sumShareability).divide(new BigDecimal(population), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ private Double StdDevHitRatio;
+
+ public double getStdDevHitRatio() {
+ if (population == 0) {
+ return 0;
+ }
+ if (StdDevHitRatio != null) {
+ return StdDevHitRatio;
+ }
+
+ double mean = getAverageHitRatio();
+ double temp = 0;
+ for (double a : hitRatios) {
+ temp += (a - mean) * (a - mean);
+ }
+ StdDevHitRatio = Math.sqrt(temp / population);
+ return StdDevHitRatio;
+ }
+
+ private Double StdDevMissRatio;
+
+ public double getStdDevMissRatio() {
+ if (population == 0) {
+ return 0;
+ }
+ if (StdDevMissRatio != null) {
+ return StdDevMissRatio;
+ }
+
+ double mean = getAverageMissRatio();
+ double temp = 0;
+ for (double a : missRatios) {
+ temp += (a - mean) * (a - mean);
+ }
+ StdDevMissRatio = Math.sqrt(temp / population);
+ return StdDevMissRatio;
+ }
+
+ private Double StdDevExecutionTimeRatio;
+
+ public double getStdDevExecutionTimeRatio() {
+ if (population == 0) {
+ return 0;
+ }
+ if (StdDevExecutionTimeRatio != null) {
+ return StdDevExecutionTimeRatio;
+ }
+
+ double mean = getAverageExecutionTime();
+ double temp = 0;
+ for (Long a : executionTimes) {
+ temp += (a - mean) * (a - mean);
+ }
+ StdDevExecutionTimeRatio = Math.sqrt(temp / population);
+ return StdDevExecutionTimeRatio;
+ }
+
+ private Double StdDevFrequency;
+
+ public double getStdDevFrequency() {
+ if (population == 0) {
+ return 0;
+ }
+ if (StdDevFrequency != null) {
+ return StdDevFrequency;
+ }
+
+ double mean = getAverageFrequency();
+ double temp = 0;
+ for (Long a : frequencies) {
+ temp += (a - mean) * (a - mean);
+ }
+ StdDevFrequency = Math.sqrt(temp / population);
+ return StdDevFrequency;
+ }
+
+ private Double StdDevShareability;
+
+ public double getStdDevShareability() {
+ if (population == 0) {
+ return 0;
+ }
+ if (StdDevShareability != null) {
+ return StdDevShareability;
+ }
+
+ double mean = getAverageShareability();
+ double temp = 0;
+ for (Double a : shareabilities) {
+ temp += (a - mean) * (a - mean);
+ }
+ StdDevShareability = Math.sqrt(temp / population);
+ return StdDevShareability;
+ }
+
+ public HashMap<MethodInfo, MethodStats> getMethodsInfoMap() {
+ return methodsInfoMap;
+ }
+
+ //getting X% with most hits
+ public double hitThreshold(int kStdDev) {
+ return getAverageHitRatio() + (kStdDev * getStdDevHitRatio());
+ }
+
+ //getting X% with most misses
+ public double missThreshold(int kStdDev) {
+ return getAverageMissRatio() + (kStdDev * getStdDevMissRatio());
+ }
+
+ //getting X% most expensive methods
+ public double expensivenessThreshold(int kStdDev) {
+ return getAverageExecutionTime() + (kStdDev * getStdDevExecutionTimeRatio());
+ }
+
+ public double shareabilityThreshold(int kStdDev) {
+ return getAverageShareability() + (kStdDev * getStdDevShareability());
+ }
+
+ //getting X% most frenquent
+ public double frequencyThreshold(int kStdDev) {
+ return getAverageFrequency() + (kStdDev * getStdDevFrequency());
+ }
+
+ /**
+ * General miss ratio from a signature
+ *
+ * @param signature
+ * @return
+ */
+ public double getMissRatio(String signature) {
+ long occurrences = 0;
+ long methods = 0;
+ for (MethodInfo mi : methodsInfoMap.keySet()) {
+ if (mi.getSignature().equals(signature)) {
+ occurrences += methodsInfoMap.get(mi).getNumberOfSameOccurrences();
+ methods++;
+ }
+ }
+ return occurrences / methods;
+ }
+
+ /**
+ * General hit ratio from a signature
+ *
+ * @param signature
+ * @return
+ */
+ public double getHitRatio(String signature) {
+ long occurrences = 0;
+ long methods = 0;
+ for (MethodInfo mi : methodsInfoMap.keySet()) {
+ if (mi.getSignature().equals(signature)) {
+ occurrences += methodsInfoMap.get(mi).getNumberOfSameOccurrences();
+ methods++;
+ }
+ }
+ return occurrences / methods;
+ }
+
+ private Double AverageFrequency;
+
+ public double getAverageFrequency() {
+ if (frequencies.isEmpty()) {
+ return 0;
+ }
+ if (AverageFrequency != null) {
+ return AverageFrequency;
+ }
+
+ AverageFrequency = new BigDecimal(sumFrequency).divide(new BigDecimal(frequencies.size()), 5, RoundingMode.HALF_UP).doubleValue();
+ return AverageFrequency;
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodEntry.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodEntry.java
new file mode 100644
index 0000000..3ce0440
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodEntry.java
@@ -0,0 +1,60 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+
+public class MethodEntry {
+
+ private MethodInfo methodInfo;
+ private MethodStats methodStats;
+ private long lifetime;
+
+ public MethodEntry(){
+
+ }
+
+ public MethodEntry(MethodInfo methodInfo, MethodStats methodStats, long lifetime) {
+ this.methodInfo = methodInfo;
+ this.methodStats = methodStats;
+ this.lifetime = lifetime;
+ }
+
+ public MethodInfo getMethodInfo() {
+ return methodInfo;
+ }
+
+ public MethodStats getMethodStats() {
+ return methodStats;
+ }
+
+ @Override
+ public String toString() {
+ return "MethodEntry{" +
+ "methodInfo=" + methodInfo +
+ ", methodStats=" + methodStats +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof MethodEntry)) return false;
+
+ MethodEntry that = (MethodEntry) o;
+
+ if (!methodInfo.equals(that.methodInfo)) return false;
+ if (!methodStats.equals(that.methodStats)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = methodInfo.hashCode();
+ result = 31 * result + methodStats.hashCode();
+ return result;
+ }
+
+ public boolean expired() {
+ return lifetime < System.currentTimeMillis();
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodStats.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodStats.java
new file mode 100644
index 0000000..4287ad5
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/model/MethodStats.java
@@ -0,0 +1,151 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.LogTrace;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.HashSet;
+import java.util.Set;
+
+public class MethodStats {
+
+ //exactly same method calls
+ private Long sameOccurrences;
+
+ //number of same method calls with different return
+ private Long differentReturnOccurrences;
+ private Long sameOccurrencesExecutionTime;
+ private Long sameOccurrencesHigherExecutionTime;
+
+ private Long amountOfIdentifiedSameOccurences;
+ private Set<String> uniqueUsers;
+
+ public MethodStats() {
+ sameOccurrences = 0L;
+ differentReturnOccurrences = 0L;
+ sameOccurrencesExecutionTime = 0L;
+ sameOccurrencesHigherExecutionTime = 0L;
+ amountOfIdentifiedSameOccurences = 0L;
+ uniqueUsers = new HashSet<>();
+ }
+
+ public MethodStats(LogTrace logTrace) {
+ this();
+ addSameOccurrence(logTrace);
+ }
+
+ public void addSameOccurrence(LogTrace logTrace) {
+ sameOccurrences++;
+ addSameOccurrencesTotalExecutionTime(logTrace.totalTime());
+
+ //todo cannot be based on string
+ if (logTrace.getUserId() != null && !logTrace.getUserId().equals("Anonymous")) {
+ uniqueUsers.add(logTrace.getUserId());
+ addIdentifiedSameOccurence();
+ }
+ }
+
+ public void addDifferentReturnOccurrence() {
+ //todo if the request was identified, it should counts
+ //addIdentifiedSameOccurence();
+ differentReturnOccurrences += 1;
+ }
+
+ private void addSameOccurrencesTotalExecutionTime(Long executionTime) {
+ sameOccurrencesExecutionTime += executionTime;
+ if (executionTime > sameOccurrencesHigherExecutionTime)
+ sameOccurrencesHigherExecutionTime = executionTime;
+ }
+
+ public Long getSameOccurrencesTotalExecutionTime() {
+ return sameOccurrencesExecutionTime;
+ }
+
+ public double getSameOccurrencesAverageExecutionTime() {
+ return new BigDecimal(getSameOccurrencesTotalExecutionTime())
+ .divide(new BigDecimal(sameOccurrences), 5, RoundingMode.HALF_UP)
+ .doubleValue();
+ }
+
+ public long getSameOccurrencesHigherExecutionTime() {
+ return sameOccurrencesHigherExecutionTime;
+ }
+
+ /**
+ * @return All occurrences of a method, i.e. with different params and return or not
+ */
+ public Long getNumberOfOccurrences() {
+ return sameOccurrences + differentReturnOccurrences;
+ }
+
+ public Long getNumberOfSameOccurrences() {
+ return sameOccurrences;
+ }
+
+ public Long getNumberOfDifferentReturnOccurrences() {
+ return differentReturnOccurrences;
+ }
+
+ //from 0% to 100%
+ public double hitRatio() {
+ BigDecimal bd = new BigDecimal(getNumberOfSameOccurrences() * 100);
+ return bd.divide(new BigDecimal(getNumberOfOccurrences()), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ //from 0% to 100%
+ public double missRatio() {
+ BigDecimal bd = new BigDecimal(getNumberOfDifferentReturnOccurrences() * 100);
+ return bd.divide(new BigDecimal(getNumberOfOccurrences()), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public double shareability() {
+
+ Long amountOfIdentifiedSameOccurences = getAmountOfIdentifiedSameOccurences();
+ if (amountOfIdentifiedSameOccurences == 0)
+ return 100;
+
+ BigDecimal bd = new BigDecimal(getAmountOfUniqueIdentifiedSameOccurences() * 100);
+ return bd.divide(new BigDecimal(amountOfIdentifiedSameOccurences), 5, RoundingMode.HALF_UP).doubleValue();
+ }
+
+ public String toCSV() {
+ //numberOfSameOccurrences,numberOfDifferentReturnOccurrences,totalOccurrences,sameOccurrencesAverageExecutionTime,sameOccurrencesTotalExecutionTime,hitRatio,missRatio
+ return getNumberOfSameOccurrences() +
+ "," + getNumberOfDifferentReturnOccurrences() +
+ "," + getNumberOfOccurrences() +
+ "," + getSameOccurrencesAverageExecutionTime() +
+ "," + getSameOccurrencesTotalExecutionTime() +
+ "," + hitRatio() +
+ "," + missRatio();
+ }
+
+ @Override
+ public String toString() {
+ return
+ "MethodStats{" +
+ "numberOfSameOccurrences=" + getNumberOfSameOccurrences() +
+ ", numberOfDifferentReturnOccurrences=" + getNumberOfDifferentReturnOccurrences() +
+ ", totalOccurrences =" + getNumberOfOccurrences() +
+ ", sameOccurrencesAverageExecutionTime =" + getSameOccurrencesAverageExecutionTime() +
+ ", sameOccurrencesTotalExecutionTime =" + getSameOccurrencesTotalExecutionTime() +
+ ", hitRatio =" + hitRatio() +
+ ", missRatio =" + missRatio() +
+ '}';
+ }
+
+ public Long getAmountOfIdentifiedSameOccurences() {
+ return amountOfIdentifiedSameOccurences;
+ }
+
+ public int getAmountOfUniqueIdentifiedSameOccurences() {
+ return uniqueUsers.size();
+ }
+
+ public Long getAmountOfAnonymousSameOccurences() {
+ return sameOccurrences - amountOfIdentifiedSameOccurences;
+ }
+
+ private void addIdentifiedSameOccurence() {
+ amountOfIdentifiedSameOccurences++;
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityMetrics.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityMetrics.java
new file mode 100644
index 0000000..c90f88b
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityMetrics.java
@@ -0,0 +1,124 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.stats;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.FlowchartWorkFlow;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodStats;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Optional;
+
+public class CacheabilityMetrics {
+
+ //total da população
+ public static long sampleSize(long N, double Z, double e) {
+ //Nível de confiança 90% -> Z=1.645
+ //Nível de confiança 95% -> Z=1.96
+ //Nível de confiança 99% -> Z=2.575
+ //Qual o nível de certeza que precisa ter de que a amostra retrata com precisão a sua população?
+ //double Z = 2.575;
+
+ //e = É a margem de erro máximo que eu quero admitir (p.e. 5%)
+ //Qual o nível de certeza que precisa ter de que os traces refletem as execuções da sua aplicação?
+ //double e = 0.03;
+ //p = É a proporção que esperamos encontrar. Este parâmetro tende confundir bastante à primeira vista:
+ double p = 0.5;
+
+ long n = (long) ((N * Math.pow(Z, 2) * p * (1 - p))
+ / ((N - 1) * Math.pow(e, 2) + Math.pow(Z, 2) * p * (1 - p)));
+
+ //simplified without the population
+ //int nn = (int) ((Math.pow(Z,2) * p * (1-p)) / Math.pow(e,2));
+ return n;
+ }
+
+ public static Optional<Boolean> isStaticData(MethodStats methodStats, FlowchartWorkFlow workflow, int population) {
+
+ //executions of a method should represent a good portion of total logs in order to avoid 1 occur == 100% hit
+// if (!(methodStats.getNumberOfSameOccurrences() >= sampleSize(methodStats.getNumberOfOccurrences(), 1.645, 0.05)
+// && methodStats.getNumberOfOccurrences() >= sampleSize(population, 1.645, 0.05))) {
+// return Optional.empty();
+// }
+ if (methodStats.getNumberOfSameOccurrences() < workflow.frequencyThreshold(0)) {
+ return Optional.empty();
+ }
+ if (methodStats.hitRatio() == 100.0) {
+ return Optional.of(true);
+ } else {
+ return Optional.of(false);
+ }
+ }
+
+ public static Optional<Boolean> changeMoreThanUsed(MethodStats methodStats, FlowchartWorkFlow workflow) {
+ //+/- k sds
+ if (methodStats.missRatio() > workflow.missThreshold(0)) {
+ return Optional.of(true);
+ } else {
+ return Optional.of(false);
+ }
+ }
+
+ public static Optional<Boolean> usedByManyRequests(MethodStats methodStats, FlowchartWorkFlow workflow, int population) {
+
+ //same executions of a method should represent a good portion of total execution of such method
+ if (methodStats.getNumberOfSameOccurrences() >= workflow.frequencyThreshold(0)) {
+// if (methodStats.getNumberOfOccurrences() >= sampleSize(population, 1.645, 0.05)) {
+ return Optional.of(true);
+ } else {
+ return Optional.of(false);
+ }
+ }
+
+ public static Optional<Boolean> isUserSpecific(MethodStats methodStats, FlowchartWorkFlow workflow) {
+
+ if (methodStats.getAmountOfIdentifiedSameOccurences() == 0) {
+ return Optional.empty();
+ }
+
+ //the less shareable, the more user specific
+ if (methodStats.shareability() < workflow.shareabilityThreshold(0)) {
+ return Optional.of(true);
+ } else {
+ return Optional.of(false);
+ }
+ }
+
+ public static Optional<Boolean> isDataSizeLarge(MethodInfo methodInfo) {
+
+ //TODO concept considered while caching
+ if (true) {
+ return Optional.of(false);
+ }
+
+ long shallowSize = methodInfo.getSizeOfReturnedValue(); // modified to interface
+
+ BigDecimal bd = new BigDecimal(shallowSize)
+ .multiply(new BigDecimal(100))
+ .divide(new BigDecimal(Long.MAX_VALUE), 5, RoundingMode.HALF_UP); //cache free space replaced to infinity
+ double dataSizePercent = bd.doubleValue();
+
+ if (dataSizePercent <= 2.0) {
+ return Optional.of(false);
+ } else {
+ return Optional.of(true);
+ }
+ }
+
+ public static Optional<Boolean> isExpensive(MethodStats methodStats, FlowchartWorkFlow workflow) {
+ if (methodStats.getSameOccurrencesAverageExecutionTime() >= workflow.expensivenessThreshold(0)) {
+ return Optional.of(true);
+ } else {
+ return Optional.of(false);
+ }
+ }
+
+ public static String allMetricsToString(MethodInfo methodInfo, MethodStats methodStats, FlowchartWorkFlow workflow, int population) {
+ //isStaticData,changeMoreThanUsed,usedByManyRequests,isUserSpecific,isCacheSizeLarge,isDataSizeLarge,isExpensive
+ return isStaticData(methodStats, workflow, population)
+ + "," + changeMoreThanUsed(methodStats, workflow)
+ + "," + usedByManyRequests(methodStats, workflow, population)
+ + "," + isUserSpecific(methodStats, workflow)
+ + "," + isDataSizeLarge(methodInfo)
+ + "," + isExpensive(methodStats, workflow);
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityPatternDecider.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityPatternDecider.java
new file mode 100644
index 0000000..ff9644f
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/analysis/decision/flowchart/stats/CacheabilityPatternDecider.java
@@ -0,0 +1,93 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.stats;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.CacheDecider;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.FlowchartWorkFlow;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodStats;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+/**
+ * TODO flowchart paper link
+ *
+ * @see
+ */
+public class CacheabilityPatternDecider implements CacheDecider {
+
+ private final int population;
+ Logger logger = LoggerFactory.getLogger(CacheabilityPatternDecider.class);
+
+ FlowchartWorkFlow workflow;
+
+ public CacheabilityPatternDecider(int size, FlowchartWorkFlow workflow) {
+ this.workflow = workflow;
+ this.population = size;
+ }
+
+ /**
+ * Flowchart definition
+ *
+ * @param methodStats
+ * @return
+ */
+ @Override
+ public boolean isCacheable(MethodInfo methodInfo, MethodStats methodStats) {
+
+ //used more than once, in many parts of the reasoning
+ Optional<Boolean> isCacheSizeLarge = Optional.of(true); // the cache is always large enough
+
+ //Is the data completely static?
+ Optional<Boolean> isStaticData = CacheabilityMetrics.isStaticData(methodStats, workflow, population);
+ if (isStaticData.isPresent() && isStaticData.get()) { // staticity yes
+
+ Optional<Boolean> isDataSizeLarge = CacheabilityMetrics.isDataSizeLarge(methodInfo);
+ if (isDataSizeLarge.isPresent() && !isDataSizeLarge.get()) {
+ return true;
+ } else {
+ if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ } else { // staticity no/not sure
+
+ Optional<Boolean> changeMoreThanUsed = CacheabilityMetrics.changeMoreThanUsed(methodStats, workflow);
+ if (changeMoreThanUsed.isPresent() && changeMoreThanUsed.get()) { //changeMoreThanUsed true
+ return false;
+ } else { //changeMoreThanUsed not/not sure
+ Optional<Boolean> usedByManyRequests = CacheabilityMetrics.usedByManyRequests(methodStats, workflow, population);
+ if (usedByManyRequests.isPresent() && !usedByManyRequests.get()) { //useByManyRequests no
+ return false;
+ } else {
+ Optional<Boolean> isUserSpecific = CacheabilityMetrics.isUserSpecific(methodStats, workflow);
+ if (isUserSpecific.isPresent() && isUserSpecific.get()) {
+ if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ Optional<Boolean> isExpensive = CacheabilityMetrics.isExpensive(methodStats, workflow);
+ if (!isExpensive.isPresent()) {
+
+ if (isCacheSizeLarge.isPresent() && isCacheSizeLarge.get()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if (isExpensive.get()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/LogTrace.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/LogTrace.java
new file mode 100644
index 0000000..635c4b0
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/LogTrace.java
@@ -0,0 +1,95 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata;
+
+public class LogTrace {
+
+ private MethodInfo methodInfo;
+ private long startTime;
+ private long endTime;
+ private String userId;
+
+ public MethodInfo getMethodInfo() {
+ return this.methodInfo;
+ }
+
+ public LogTrace setMethodInfo(MethodInfo methodInfo) {
+ this.methodInfo = methodInfo;
+ return this;
+ }
+
+ public long totalTime() {
+ return endTime - startTime;
+ }
+
+ public long getStartTime() {
+ return this.startTime;
+ }
+
+ public LogTrace setStartTime(long startTime) {
+ this.startTime = startTime;
+ return this;
+ }
+
+ public long getEndTime() {
+ return this.endTime;
+ }
+
+ public LogTrace setEndTime(long endTime) {
+ this.endTime = endTime;
+ return this;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public LogTrace setUserId(String userId) {
+ this.userId = userId;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof LogTrace)) {
+ return false;
+ }
+
+ LogTrace logTrace = (LogTrace) o;
+
+ if (endTime != logTrace.endTime) {
+ return false;
+ }
+ if (startTime != logTrace.startTime) {
+ return false;
+ }
+ if (methodInfo != null ? !methodInfo.equals(logTrace.methodInfo) : logTrace.methodInfo != null) {
+ return false;
+ }
+ if (userId != null ? !userId.equals(logTrace.userId) : logTrace.userId != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = methodInfo != null ? methodInfo.hashCode() : 0;
+ result = 31 * result + (int) (startTime ^ (startTime >>> 32));
+ result = 31 * result + (int) (endTime ^ (endTime >>> 32));
+ result = 31 * result + (userId != null ? userId.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "LogTrace{"
+ + "methodInfo=" + methodInfo
+ + ", startTime=" + startTime
+ + ", endTime=" + endTime
+ + ", userId='" + userId + '\''
+ + '}';
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/MethodInfo.java b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/MethodInfo.java
new file mode 100644
index 0000000..11a4384
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/adaptivecaching/monitoring/application/metadata/MethodInfo.java
@@ -0,0 +1,150 @@
+package br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+
+import java.util.Objects;
+import org.ehcache.sizeof.SizeOf;
+
+public class MethodInfo {
+
+ private String signature;
+
+ private transient Object[] arguments;
+
+ private transient Object returnedValue;
+
+
+ private long sizeOfReturnedValue;
+
+// private Integer hashedReturnedValue;
+// private Integer hashedArguments;
+
+ public MethodInfo(String signature, Object[] arguments) {
+ this.signature = signature;
+ this.arguments = arguments;
+
+// try {
+// //TODO hash or not???
+// this.hashedArguments = HashCodeBuilder.reflectionHashCode(arguments);
+// } catch (Exception e) {
+// }
+ }
+
+ public MethodInfo(String signature, Object[] arguments, Object returnedValue) {
+ this(signature, arguments);
+ this.returnedValue = returnedValue;
+ SizeOf sizeOf = SizeOf.newInstance();
+ this.sizeOfReturnedValue = sizeOf.sizeOf(this.returnedValue);
+
+// try {
+// //TODO hash or not???
+// this.hashedArguments = HashCodeBuilder.reflectionHashCode(arguments);
+// this.hashedReturnedValue = HashCodeBuilder.reflectionHashCode(returnedValue);
+// } catch (Exception e) {
+// }
+ }
+
+ public String getSignature() {
+ return this.signature;
+ }
+
+ public Object[] getArguments() {
+ return this.arguments;
+ }
+
+ public Object getReturnedValue() {
+ return this.returnedValue;
+ }
+ public boolean equalsWithoutReturnedValue(MethodInfo o) {
+
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ if (!signature.equals(o.signature)) {
+ return false;
+ }
+ if (!(Objects.deepEquals(arguments, o.arguments) || EqualsBuilder.reflectionEquals(arguments, o.arguments))) {
+ return false;
+ }
+
+ return true;
+ //return EqualsBuilder.reflectionEquals(this, o, "returnedValue", "key");
+ }
+
+ @Override
+ public boolean equals(Object o) {
+// return EqualsBuilder.reflectionEquals(this, o, "key");
+
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ MethodInfo that = (MethodInfo) o;
+
+ if (!signature.equals(that.signature)) {
+ return false;
+ }
+ if (!EqualsBuilder.reflectionEquals(arguments, that.arguments)) {
+ return false;
+ }
+ return EqualsBuilder.reflectionEquals(returnedValue, that.returnedValue) || Objects.deepEquals(returnedValue, that.returnedValue);
+ }
+
+// public boolean equalsHashed(Object o) {
+// if (this == o) return true;
+// if (o == null || getClass() != o.getClass()) return false;
+//
+// MethodInfo that = (MethodInfo) o;
+//
+// if (!signature.equals(that.signature)) return false;
+// if (!Objects.deepEquals(hashedArguments, that.hashedArguments)) return false;
+// return hashedReturnedValue != null ? Objects.deepEquals(hashedReturnedValue, that.hashedReturnedValue) : that.hashedReturnedValue == null;
+// }
+//
+// public boolean equalsHashedWithoutReturnedValue(Object o) {
+// if (this == o) return true;
+// if (o == null || getClass() != o.getClass()) return false;
+//
+// MethodInfo that = (MethodInfo) o;
+//
+// if (!signature.equals(that.signature)) return false;
+// if (!Objects.deepEquals(hashedArguments, that.hashedArguments)) return false;
+// return true;
+// }
+// public Integer getHashedReturnedValue() {
+// return hashedReturnedValue;
+// }
+//
+// public Integer getHashedArguments() {
+// return hashedArguments;
+// }
+//
+// public void setArguments(Object[] arguments) {
+// this.arguments = arguments;
+// }
+//
+// public void setReturnedValue(Object returnedValue) {
+// this.returnedValue = returnedValue;
+// }
+ @Override
+ public int hashCode() {
+ //TODO equals is enough to distinghish, not able to get a unique hashcode
+ return 1;
+ //return HashCodeBuilder.reflectionHashCode(this, "key");
+ }
+
+ public String toString() {
+ return "br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo(signature=" + this.signature + ", arguments=" + this.arguments + ", returnedValue=" + this.returnedValue + ")";
+ }
+
+ public long getSizeOfReturnedValue() {
+ return this.sizeOfReturnedValue;
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java
new file mode 100644
index 0000000..fff69c4
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/Main.java
@@ -0,0 +1,42 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.approachescomparison.adapter;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.FlowchartWorkFlow;
+import br.ufrgs.inf.prosoft.adaptivecaching.analysis.decision.flowchart.model.MethodEntry;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.LogTrace;
+import br.ufrgs.inf.prosoft.trace.Trace;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author romulo
+ */
+public class Main {
+
+ private static final Logger logger = Logger.getLogger(Main.class.getName());
+
+ public static void main(String[] args) {
+ System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tF %1$tT+%1$tL] [%4$-7s] [APLCache] %5$s %n");
+
+ String path = null;
+ if (args.length < 1) {
+ System.err.println("No path provided");
+ System.exit(1);
+ } else {
+ path = args[0];
+ }
+ logger.log(Level.INFO, "Reading traces");
+ List<Trace> traces = TraceReader.partiallyParseFile(path);
+ List<LogTrace> logList = TraceReader.getLogTraces(traces);
+ FlowchartWorkFlow flowchartWorkFlow = new FlowchartWorkFlow(logList);
+ Set<MethodEntry> process = flowchartWorkFlow.filterCacheableMethods(300000); // default value provided by the framework
+ logger.log(Level.INFO, "{0} cacheable methods identified", process.size());
+ }
+}
diff --git a/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java
new file mode 100644
index 0000000..c285686
--- /dev/null
+++ b/src/main/java/br/ufrgs/inf/prosoft/approachescomparison/adapter/TraceReader.java
@@ -0,0 +1,53 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package br.ufrgs.inf.prosoft.approachescomparison.adapter;
+
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.LogTrace;
+import br.ufrgs.inf.prosoft.adaptivecaching.monitoring.application.metadata.MethodInfo;
+import br.ufrgs.inf.prosoft.trace.Parameter;
+import br.ufrgs.inf.prosoft.trace.Trace;
+import br.ufrgs.inf.prosoft.trace.TraceReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author romulo
+ */
+public class TraceReader extends br.ufrgs.inf.prosoft.trace.TraceReader {
+
+ private static final Logger logger = Logger.getLogger(TraceReader.class.getName());
+
+ public static List<LogTrace> getLogTraces(List<Trace> traces) {
+ List<LogTrace> logTraces = new ArrayList<>();
+ while (!traces.isEmpty()) {
+ Trace trace = traces.remove(0);
+ try {
+ LogTrace logTrace;
+ if (trace instanceof TraceReference) {
+ TraceReference traceReference = (TraceReference) trace;
+ logTrace = new LogTrace().setStartTime(traceReference.getStartTime())
+ .setEndTime(traceReference.getEndTime());
+ } else {
+ logTrace = new LogTrace().setStartTime(trace.getStartTime())
+ .setEndTime(trace.getEndTime())
+ .setMethodInfo(new MethodInfo(trace.getName(),
+ trace.getParameters().stream().map(Parameter::getData)
+ .collect(Collectors.toList()).toArray(),
+ trace.getReturn().getData()));
+ }
+ logTraces.add(logTrace);
+ } catch (Exception e) {
+ logger.log(Level.INFO, "Trace discarted: {0}", trace);
+ }
+ }
+ return logTraces;
+ }
+
+}