Skip to content

Commit 126fe16

Browse files
committed
Finish Javadocs for public classes in core.execution
Also finish all outstanding TODO's Still needs to be done: - Documentation of executing objects for maintenance reasons. - Building a test suite for Metric definition.
1 parent 756d657 commit 126fe16

6 files changed

Lines changed: 128 additions & 39 deletions

File tree

src/main/java/nl/rug/jbi/jsm/core/calculator/MetricState.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ public Exception getExecutionException() {
5252

5353
/**
5454
* Invalidate this state with the given exception, once invalidated this state will cease evaluating and either
55-
* return an {@link nl.rug.jbi.jsm.core.execution.InvalidResult} if the metric is isolated or accumulate the
56-
* 'invalidMembers' count for shared metrics or producers.
55+
* return an error result if the metric is isolated or accumulate the 'invalidMembers' count for shared metrics or
56+
* producers.
5757
*
5858
* @param ex Exception that has caused invalidation.
5959
* @throws java.lang.NullPointerException if ex is NULL

src/main/java/nl/rug/jbi/jsm/core/execution/CalculationStageTask.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
import nl.rug.jbi.jsm.core.calculator.MetricResult;
88
import nl.rug.jbi.jsm.core.calculator.MetricState;
99
import nl.rug.jbi.jsm.core.event.EventBus;
10+
import org.apache.logging.log4j.LogManager;
11+
import org.apache.logging.log4j.Logger;
1012

1113
import java.util.List;
1214
import java.util.Map;
1315
import java.util.concurrent.CountDownLatch;
1416

1517
class CalculationStageTask implements Runnable {
16-
18+
private final static Logger logger = LogManager.getLogger(CalculationStageTask.class);
1719
private final CountDownLatch latch;
1820
private final Runnable modifier;
1921
private final EventBus dataStore;
@@ -57,7 +59,7 @@ public Class apply(final IsolatedMetric isolatedMetric) {
5759
if (state.isValid()) {
5860
results.add(m.getResult(this.dataStore.getIdentifier(), state));
5961
} else {
60-
//TODO: properly log this
62+
logger.warn("Failed to calculate '{}' for '{}'", m.getClass().getName(), state.getIdentifier());
6163
results.add(new InvalidResult(this.dataStore.getIdentifier(), m, "Error during calculation"));
6264
}
6365
}

src/main/java/nl/rug/jbi/jsm/core/execution/ClassVisitorFactory.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,24 @@
33
import nl.rug.jbi.jsm.core.event.EventBus;
44
import org.apache.bcel.classfile.JavaClass;
55

6+
/**
7+
* Factory for the ClassVisitor runnable, given the {@link org.apache.bcel.classfile.JavaClass} and the associated
8+
* EventBus, a class visitor needs to be created which extracts data from the JavaClass and publishes it through the
9+
* EventBus.
10+
* The default ClassVisitor is {@link nl.rug.jbi.jsm.bcel.ClassVisitor}.
11+
*
12+
* @author David van Leusen
13+
* @since 2014-06-02
14+
*/
615
public interface ClassVisitorFactory {
716

17+
/**
18+
* Create a class visitor for the given class and event bus, the produced object should be a Runnable and this
19+
* visitor should be start when {@link Runnable#run()} is called.
20+
*
21+
* @param targetClass Class to evaluate
22+
* @param eventBus EventBus associated with the given class.
23+
* @return Runnable that will execute the class visitor.
24+
*/
825
public Runnable createClassVisitor(final JavaClass targetClass, final EventBus eventBus);
926
}

src/main/java/nl/rug/jbi/jsm/core/execution/ControllerThread.java

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.apache.bcel.util.Repository;
1515
import org.apache.logging.log4j.LogManager;
1616
import org.apache.logging.log4j.Logger;
17+
import org.apache.logging.log4j.message.ParameterizedMessage;
1718

1819
import java.util.*;
1920
import java.util.concurrent.*;
@@ -32,18 +33,23 @@ public Class apply(Object metric) {
3233
return metric.getClass();
3334
}
3435
};
35-
private final PipelineExecutor executionPlan;
36+
private final int executionId = UNIQUE_EXECUTION_ID.incrementAndGet();
3637
private final ExecutorService executorPool = Executors.newFixedThreadPool(
3738
Runtime.getRuntime().availableProcessors(),
3839
new ThreadFactory() {
3940
private final AtomicInteger executionId = new AtomicInteger(0);
4041

4142
@Override
4243
public Thread newThread(Runnable r) {
43-
return new Thread(r, String.format("JSM Execution Thread #%d", executionId.getAndIncrement()));
44+
return new Thread(r, String.format(
45+
"JSM Execution Thread #%d/%d",
46+
ControllerThread.this.executionId,
47+
executionId.getAndIncrement()
48+
));
4449
}
4550
}
4651
);
52+
private final PipelineExecutor executionPlan;
4753
private final Map<String, EventBus> stateContainers = Maps.newHashMap();
4854
private final Table<MetricScope, String, List<Object>> dataForFutureScope = Tables.newCustomTable(
4955
Maps.<MetricScope, Map<String, List<Object>>>newEnumMap(MetricScope.class),
@@ -63,7 +69,9 @@ public boolean apply(List<MetricResult> metricResults) {
6369
};
6470

6571
public ControllerThread(final PipelineExecutor executionPlan, final Set<String> classNames) {
66-
super(String.format("JSM Controller Thread #%d", ControllerThread.UNIQUE_EXECUTION_ID.getAndIncrement()));
72+
super();
73+
this.setName(String.format("JSM Controller Thread #%d", this.executionId));
74+
6775
this.executionPlan = executionPlan;
6876

6977
final HandlerMap classHandlerMap = this.executionPlan.getHandlerMap(MetricScope.CLASS);
@@ -107,8 +115,7 @@ public void run() {
107115
cvFactory.createClassVisitor(jc, entry.getValue())
108116
));
109117
} catch (ClassNotFoundException e) {
110-
//TODO: proper handling
111-
logger.debug(e);
118+
logger.error("Failed to load '{}', it will not be evaluated.", e);
112119
}
113120
}
114121

@@ -125,8 +132,7 @@ public void run() {
125132
try {
126133
performCalculationStage(taskQueue, currentFrame.getIsolatedMetrics());
127134
} catch (InterruptedException e) {
128-
//TODO: handle interruption correctly.
129-
logger.debug(e);
135+
logger.warn("Execution interrupted, stopping evaluation.", e);
130136
break;
131137
}
132138

@@ -145,8 +151,7 @@ public void run() {
145151
performCollectionStage(dataMap, currentFrame, produceList);
146152
}
147153
} catch (InterruptedException e) {
148-
//TODO: handle interruption correctly.
149-
logger.debug(e);
154+
logger.warn("Execution interrupted, stopping evaluation.", e);
150155
break;
151156
}
152157

@@ -182,7 +187,11 @@ public void run() {
182187
logger.debug("State containers and tasks added for next scope.");
183188
}
184189

185-
prepareCalculatorsForNextFrame(taskQueue, nextFrameExecutionData);
190+
prepareCalculatorsForNextFrame(
191+
taskQueue,
192+
nextFrameExecutionData,
193+
this.executionPlan.getHandlerMap(currentScope)
194+
);
186195

187196
logger.debug("Tasks for next frame prepared.");
188197
}
@@ -194,11 +203,23 @@ public void run() {
194203

195204
private void prepareCalculatorsForNextFrame(
196205
final Queue<Pair<EventBus, Runnable>> taskQueue,
197-
final Map<String, List<Object>> executionData
206+
final Map<String, List<Object>> executionData,
207+
final HandlerMap hMap
198208
) {
199209
for (final Map.Entry<String, List<Object>> entry : executionData.entrySet()) {
200-
final EventBus eBus = this.stateContainers.get(entry.getKey());
201-
//TODO: if eBus == null, try to fix it....
210+
final EventBus eBus;
211+
if (this.stateContainers.containsKey(entry.getKey())) {
212+
eBus = this.stateContainers.get(entry.getKey());
213+
} else {
214+
logger.warn(
215+
"Request for undefined identifier, might indicate that " +
216+
"a producer is returning wrong data: '{}'",
217+
entry.getKey()
218+
);
219+
220+
eBus = new EventBus(entry.getKey(), hMap);
221+
this.stateContainers.put(entry.getKey(), eBus);
222+
}
202223
taskQueue.add(new Pair<EventBus, Runnable>(eBus, new DataListDispatcher(eBus, entry.getValue())));
203224
}
204225
}
@@ -238,36 +259,44 @@ private void performCollectionStage(
238259

239260
final CountDownLatch latch = createCountdownLatch(sharedMetrics.size() + producerMetrics.size());
240261

241-
//TODO: use Pair to link Futures to the metrics, for logging purposes
242-
final List<Future<List<MetricResult>>> futureResults = Lists.newLinkedList();
243-
final List<Future<List<ProducerMetric.Produce>>> futureProduce = Lists.newLinkedList();
262+
final List<Pair<SharedMetric, Future<List<MetricResult>>>> futureResults = Lists.newLinkedList();
263+
final List<Pair<ProducerMetric, Future<List<ProducerMetric.Produce>>>> futureProduce = Lists.newLinkedList();
244264

245265
for (final SharedMetric metric : sharedMetrics) {
246266
final Map<String, MetricState> data = dataMap.get(metric.getClass());
247-
futureResults.add(this.executorPool.submit(CollectionStageTask.forSharedMetric(metric, data, latch)));
267+
futureResults.add(new Pair<SharedMetric, Future<List<MetricResult>>>(
268+
metric,
269+
this.executorPool.submit(CollectionStageTask.forSharedMetric(metric, data, latch))
270+
));
248271
}
249272

250273
for (final ProducerMetric metric : producerMetrics) {
251274
final Map<String, MetricState> data = dataMap.get(metric.getClass());
252-
futureProduce.add(this.executorPool.submit(CollectionStageTask.forProducer(metric, data, latch)));
275+
futureProduce.add(new Pair<ProducerMetric, Future<List<ProducerMetric.Produce>>>(
276+
metric,
277+
this.executorPool.submit(CollectionStageTask.forProducer(metric, data, latch)))
278+
);
253279
}
254280

255281
//Await completion of async collection.
256282
latch.await();
257283

258284
//Collection Results
259285
final List<MetricResult> results = Lists.newLinkedList();
260-
for (final Future<List<MetricResult>> fResult : futureResults) {
286+
for (final Pair<SharedMetric, Future<List<MetricResult>>> fResult : futureResults) {
261287
try {
262-
final List<MetricResult> resList = fResult.get();
288+
final List<MetricResult> resList = fResult.second.get();
263289
if (resList != null) {
264290
results.addAll(resList);
265291
} else {
266-
//TODO: log invalid metric
292+
logger.warn("'{}' returned null as a list of results.", fResult.first.getClass().getName());
267293
}
268294
} catch (ExecutionException e) {
269-
//TODO: how to handle errors here (do they even happen?)
270-
logger.warn("Exception getting results", e);
295+
logger.warn(new ParameterizedMessage(
296+
"Exception occurred whilst calculating results for '{}': {}",
297+
fResult.first.getClass().getName(),
298+
e.getCause().getMessage()
299+
), e);
271300
}
272301
}
273302

@@ -276,17 +305,20 @@ private void performCollectionStage(
276305
this.resultsCallback.apply(results);
277306

278307
//Collect and return produce.
279-
for (final Future<List<ProducerMetric.Produce>> fProduce : futureProduce) {
308+
for (final Pair<ProducerMetric, Future<List<ProducerMetric.Produce>>> fProduce : futureProduce) {
280309
try {
281-
final List<ProducerMetric.Produce> prodList = fProduce.get();
310+
final List<ProducerMetric.Produce> prodList = fProduce.second.get();
282311
if (prodList != null) {
283312
produceOutput.addAll(prodList);
284313
} else {
285-
//TODO: log invalid metric
314+
logger.warn("'{}' returned null as a list of produce.", fProduce.first.getClass().getName());
286315
}
287316
} catch (ExecutionException e) {
288-
//TODO: how to handle errors here (do they even happen?)
289-
logger.warn("Exception getting results", e);
317+
logger.warn(new ParameterizedMessage(
318+
"Exception occurred whilst calculating produce for '{}': {}",
319+
fProduce.first.getClass().getName(),
320+
e.getCause().getMessage()
321+
), e);
290322
}
291323
}
292324
}

src/main/java/nl/rug/jbi/jsm/core/execution/InvalidResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import nl.rug.jbi.jsm.core.calculator.BaseMetric;
44
import nl.rug.jbi.jsm.core.calculator.MetricResult;
55

6-
public class InvalidResult extends MetricResult {
6+
class InvalidResult extends MetricResult {
77
public InvalidResult(String identifier, BaseMetric m, String msg) {
88
super(identifier, m.getClass(), m.getResultScopes().iterator().next(), msg);
99
}

src/main/java/nl/rug/jbi/jsm/core/execution/PipelineExecutor.java

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,22 @@
1010
import nl.rug.jbi.jsm.frontend.Frontend;
1111
import org.apache.bcel.util.ClassLoaderRepository;
1212
import org.apache.bcel.util.Repository;
13+
import org.apache.logging.log4j.LogManager;
14+
import org.apache.logging.log4j.Logger;
1315

1416
import java.util.List;
1517
import java.util.Map;
1618
import java.util.Set;
1719

20+
/**
21+
* Executor for a previously constructed {@link nl.rug.jbi.jsm.core.pipeline.Pipeline}. Execution happens completely
22+
* asynchronously and will call {@link nl.rug.jbi.jsm.frontend.Frontend#signalDone()}.
23+
*
24+
* @author David van Leusen
25+
* @since 2014-06-02
26+
*/
1827
public class PipelineExecutor {
28+
private final static Logger logger = LogManager.getLogger(PipelineExecutor.class);
1929
private final Frontend frontend;
2030
private final CompositeBCELClassLoader dataSource;
2131
private final Repository repo;
@@ -28,41 +38,69 @@ public class PipelineExecutor {
2838
private Runnable finishCallback = null;
2939
private ClassVisitorFactory cvFactory = JSMClassVisitorFactory.INSTANCE;
3040

41+
/**
42+
* Construct an executor for the given data and target
43+
*
44+
* @param frontend Frontend callback for results.
45+
* @param executionPlan Pipeline describing the handlers and execution-frames.
46+
* @param dataSource ClassLoader to build the {@link org.apache.bcel.util.ClassLoaderRepository} from.
47+
* @param classNames Set of classes that need to be evaluated.
48+
*/
3149
public PipelineExecutor(
3250
final Frontend frontend,
33-
final Pipeline pipe,
51+
final Pipeline executionPlan,
3452
final CompositeBCELClassLoader dataSource,
3553
final Set<String> classNames
3654
) {
3755
this.frontend = frontend;
3856
this.dataSource = dataSource;
3957
this.repo = new ClassLoaderRepository(dataSource);
40-
this.handlerMap = pipe.getHandlerMaps();
41-
this.frameMap = pipe.getPipelineFrames();
58+
this.handlerMap = executionPlan.getHandlerMaps();
59+
this.frameMap = executionPlan.getPipelineFrames();
4260
this.controllerThread = new ControllerThread(this, classNames);
4361
}
4462

45-
public HandlerMap getHandlerMap(final MetricScope scope) {
63+
HandlerMap getHandlerMap(final MetricScope scope) {
4664
return this.handlerMap.get(Preconditions.checkNotNull(scope));
4765
}
4866

49-
public PipelineFrame getPipelineFrame(final MetricScope scope) {
67+
PipelineFrame getPipelineFrame(final MetricScope scope) {
5068
return this.frameMap.get(Preconditions.checkNotNull(scope));
5169
}
5270

71+
/**
72+
* Sets a callback that is to be executed once processing has been finished.
73+
*
74+
* @param finishCallback the callback to be executed.
75+
*/
5376
public void setFinishCallback(final Runnable finishCallback) {
5477
this.finishCallback = finishCallback;
5578
}
5679

80+
/**
81+
* Begin the asynchronous execution of this executor, this call will not block.
82+
*/
5783
public void beginExecution() {
58-
//TODO: custom exception handler
84+
this.controllerThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
85+
@Override
86+
public void uncaughtException(Thread t, Throwable e) {
87+
logger.error("Uncaught exception has caused execution to fail", e);
88+
PipelineExecutor.this.onFinish(); //Ensure the system doesn't get stuck.
89+
}
90+
});
5991
this.controllerThread.start();
6092
}
6193

6294
ClassVisitorFactory getClassVisitorFactory() {
6395
return this.cvFactory;
6496
}
6597

98+
/**
99+
* Sets the ClassVisitor factory for this executor, this needs to be set to use custom ClassVisitors.
100+
* It will default to a factory that creates {@link nl.rug.jbi.jsm.bcel.ClassVisitor}.
101+
*
102+
* @param cvFactory ClassVisitor factory
103+
*/
66104
public void setClassVisitorFactory(final ClassVisitorFactory cvFactory) {
67105
this.cvFactory = Preconditions.checkNotNull(cvFactory);
68106
}

0 commit comments

Comments
 (0)