Skip to content

Commit f880ec2

Browse files
committed
Continued Dependency Injection Refactor
1 parent a780739 commit f880ec2

50 files changed

Lines changed: 689 additions & 360 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ allprojects {
3131

3232

3333
dependencies {
34+
testCompile group: 'net.jodah', name: 'concurrentunit', version: '0.4.2'
3435
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
3536
testCompile group: 'junit', name: 'junit', version: '4.12'
3637
}
@@ -76,6 +77,7 @@ def os = osdetector.classifier.replace("osx", "macosx").replace("windows-x86_32"
7677
project(":core") {
7778
apply plugin: 'java'
7879
apply plugin: 'idea'
80+
apply plugin: 'jacoco'
7981
apply plugin: "com.github.johnrengelman.shadow"
8082

8183
configurations {
@@ -173,6 +175,7 @@ project(":core") {
173175
project(":ui") {
174176
apply plugin: 'java'
175177
apply plugin: 'idea'
178+
apply plugin: 'jacoco'
176179
apply plugin: 'application'
177180
apply from: 'http://dl.bintray.com/shemnon/javafx-gradle/8.1.1/javafx.plugin'
178181

core/src/main/java/edu/wpi/grip/core/Connection.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
import com.google.inject.Inject;
66
import com.google.inject.assistedinject.Assisted;
77
import com.thoughtworks.xstream.annotations.XStreamAlias;
8-
import edu.wpi.grip.core.events.ConnectionRemovedEvent;
9-
import edu.wpi.grip.core.events.SocketChangedEvent;
10-
import edu.wpi.grip.core.events.SourceRemovedEvent;
11-
import edu.wpi.grip.core.events.StepRemovedEvent;
8+
import edu.wpi.grip.core.events.*;
129

1310
import static com.google.common.base.Preconditions.checkArgument;
1411

@@ -38,7 +35,6 @@ public interface Factory <T> {
3835
this.outputSocket = outputSocket;
3936
this.inputSocket = inputSocket;
4037
checkArgument(pipeline.canConnect(outputSocket, inputSocket), "Cannot connect sockets");
41-
inputSocket.setValueOptional(outputSocket.getValue());
4238
}
4339

4440
public OutputSocket<? extends T> getOutputSocket() {
@@ -49,10 +45,21 @@ public InputSocket<T> getInputSocket() {
4945
return this.inputSocket;
5046
}
5147

48+
private void runConnection() {
49+
inputSocket.setValueOptional(outputSocket.getValue());
50+
}
51+
52+
@Subscribe
53+
public void onConnectionAdded(ConnectionAddedEvent event) {
54+
if (event.getConnection().equals(this)) {
55+
runConnection();
56+
}
57+
}
58+
5259
@Subscribe
5360
public void onOutputChanged(SocketChangedEvent e) {
5461
if (e.getSocket() == outputSocket) {
55-
inputSocket.setValueOptional(outputSocket.getValue());
62+
runConnection();
5663
}
5764
}
5865

core/src/main/java/edu/wpi/grip/core/GRIPCoreModule.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
4040

4141
bind(EventBus.class).toInstance(eventBus);
4242

43-
install(new FactoryModuleBuilder().build(Step.Factory.class));
44-
45-
46-
install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Number>>(){}));
47-
install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Double>>(){}));
4843
install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Object>>(){}));
4944

5045

core/src/main/java/edu/wpi/grip/core/Main.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919
*/
2020
public class Main {
2121

22-
@Inject private Project project;
23-
@Inject private EventBus eventBus;
22+
@Inject
23+
private Project project;
24+
@Inject
25+
private EventBus eventBus;
2426

27+
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
2528
public static void main(String[] args) throws Exception {
2629
final Injector injector = Guice.createInjector(new GRIPCoreModule());
2730
injector.getInstance(Main.class).start(args);
2831
}
2932

30-
public void start(String[] args) throws Exception {
33+
public void start(String[] args) throws IOException, InterruptedException {
3134
if (args.length != 1) {
3235
System.err.println("Usage: GRIP.jar project.grip");
3336
return;

core/src/main/java/edu/wpi/grip/core/Palette.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
@Singleton
1818
public class Palette {
1919

20-
@Inject private EventBus eventBus;
20+
private final EventBus eventBus;
21+
22+
@Inject
23+
Palette(EventBus eventBus) {
24+
this.eventBus = eventBus;
25+
}
2126

2227
private final Map<String, Operation> operations = new LinkedHashMap<>();
2328

core/src/main/java/edu/wpi/grip/core/Pipeline.java

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import java.util.*;
1212
import java.util.stream.Collectors;
1313

14+
import static com.google.common.base.Preconditions.checkArgument;
15+
import static com.google.common.base.Preconditions.checkNotNull;
16+
1417
/**
1518
* Pipeline has the list of steps in a computer vision algorithm, as well as the set of connections between the inputs
1619
* and outputs of different steps.
@@ -135,48 +138,50 @@ public void onSourceRemoved(SourceRemovedEvent event) {
135138
}
136139
}
137140

138-
@Subscribe
139-
public synchronized void onStepAdded(StepAddedEvent event) {
140-
final Step step = event.getStep();
141-
142-
this.steps.add(event.getIndex().or(this.steps.size()), step);
143-
this.eventBus.register(event.getStep());
141+
public synchronized void addStep(Step step, int index) {
142+
checkNotNull(step, "The step can not be null");
143+
this.steps.add(index, step);
144+
this.eventBus.register(step);
145+
this.eventBus.post(new StepAddedEvent(step, index));
144146
}
145147

146-
@Subscribe
147-
public synchronized void onStepRemoved(StepRemovedEvent event) {
148-
this.steps.remove(event.getStep());
149-
this.eventBus.unregister(event.getStep());
148+
public synchronized void addStep(Step step) {
149+
addStep(step, this.steps.size());
150+
}
150151

152+
public synchronized void removeStep(Step step) {
153+
checkNotNull(step, "The step can not be null");
154+
this.steps.remove(step);
151155
// Sockets of deleted steps should not be previewed
152-
for (OutputSocket<?> socket : event.getStep().getOutputSockets()) {
156+
for (OutputSocket<?> socket : step.getOutputSockets()) {
153157
socket.setPreviewed(false);
154158
}
159+
this.eventBus.post(new StepRemovedEvent(step));
160+
this.eventBus.unregister(step);
155161
}
156162

157-
@Subscribe
158-
public synchronized void onStepMoved(StepMovedEvent event) {
159-
final Step step = event.getStep();
163+
public synchronized void moveStep(Step step, int delta) {
164+
checkNotNull(step, "The step can not be null");
165+
checkArgument(this.steps.contains(step), "The step must exist in the pipeline to be moved");
160166

161167
final int oldIndex = this.steps.indexOf(step);
162168
this.steps.remove(oldIndex);
163169

164170
// Compute the new index of the step, clamping to the beginning or end of pipeline if it goes past either end
165-
final int newIndex = Math.min(Math.max(oldIndex + event.getDistance(), 0), this.steps.size());
171+
final int newIndex = Math.min(Math.max(oldIndex + delta, 0), this.steps.size());
166172
this.steps.add(newIndex, step);
173+
eventBus.post(new StepMovedEvent(step, delta));
167174
}
168175

169176
@Subscribe
170177
public void onConnectionAdded(ConnectionAddedEvent event) {
171-
this.connections.add(event.getConnection());
172-
this.eventBus.register(event.getConnection());
178+
final Connection connection = event.getConnection();
179+
this.connections.add(connection);
173180
}
174181

175182
@Subscribe
176183
public void onConnectionRemoved(ConnectionRemovedEvent event) {
177184
this.connections.remove(event.getConnection());
178185
this.eventBus.unregister(event.getConnection());
179186
}
180-
181-
182187
}

core/src/main/java/edu/wpi/grip/core/Step.java

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import com.google.common.eventbus.EventBus;
44
import com.google.common.eventbus.Subscribe;
55
import com.google.inject.Inject;
6-
import com.google.inject.assistedinject.Assisted;
6+
import com.google.inject.Singleton;
77
import com.thoughtworks.xstream.annotations.XStreamAlias;
88
import edu.wpi.grip.core.events.SocketChangedEvent;
99

@@ -20,43 +20,62 @@
2020
*/
2121
@XStreamAlias(value = "grip:Step")
2222
public class Step {
23-
private final Logger logger = Logger.getLogger(Step.class.getName());
24-
private Operation operation;
25-
private InputSocket<?>[] inputSockets;
26-
private OutputSocket<?>[] outputSockets;
27-
private Optional<?> data;
2823

29-
public interface Factory {
30-
Step create(Operation operation);
31-
}
24+
private final Logger logger = Logger.getLogger(Step.class.getName());
3225

33-
/**
34-
* @param eventBus The Guava {@link EventBus} used by the application.
35-
* @param operation The operation that is performed at this step.
36-
*/
37-
@Inject
38-
Step(EventBus eventBus, @Assisted Operation operation) {
39-
this.operation = operation;
26+
private final Operation operation;
27+
private final InputSocket<?>[] inputSockets;
28+
private final OutputSocket<?>[] outputSockets;
29+
private final Optional<?> data;
4030

41-
checkNotNull(eventBus);
42-
checkNotNull(operation);
31+
@Singleton
32+
public static class Factory {
33+
private final EventBus eventBus;
4334

44-
// Create the list of input and output sockets, and mark this step as their owner.
45-
inputSockets = operation.createInputSockets(eventBus);
46-
for (Socket<?> socket : inputSockets) {
47-
socket.setStep(Optional.of(this));
48-
eventBus.register(socket);
35+
@Inject
36+
public Factory(EventBus eventBus) {
37+
this.eventBus = eventBus;
4938
}
5039

51-
outputSockets = operation.createOutputSockets(eventBus);
52-
for (Socket<?> socket : outputSockets) {
53-
socket.setStep(Optional.of(this));
54-
eventBus.register(socket);
55-
}
40+
public Step create(Operation operation) {
41+
checkNotNull(operation, "The operation can not be null");
42+
// Create the list of input and output sockets, and mark this step as their owner.
43+
final InputSocket<?>[] inputSockets = operation.createInputSockets(eventBus);
5644

57-
data = operation.createData();
45+
for (Socket<?> socket : inputSockets) {
46+
eventBus.register(socket);
47+
}
48+
49+
final OutputSocket<?>[] outputSockets = operation.createOutputSockets(eventBus);
50+
for (Socket<?> socket : outputSockets) {
51+
eventBus.register(socket);
52+
}
5853

59-
runPerformIfPossible();
54+
final Step step = new Step(operation, inputSockets, outputSockets, operation.createData());
55+
eventBus.register(step);
56+
for (Socket<?> socket : inputSockets) {
57+
socket.setStep(Optional.of(step));
58+
}
59+
for (Socket<?> socket : outputSockets) {
60+
socket.setStep(Optional.of(step));
61+
}
62+
63+
step.runPerformIfPossible();
64+
return step;
65+
}
66+
}
67+
68+
/**
69+
* @param operation The operation that is performed at this step.
70+
* @param inputSockets The input sockets from the operation.
71+
* @param outputSockets The output sockets provided by the operation.
72+
* @param data The data provided by the operation.
73+
*/
74+
Step(Operation operation, InputSocket<?>[] inputSockets, OutputSocket<?>[] outputSockets, Optional<?> data) {
75+
this.operation = operation;
76+
this.inputSockets = inputSockets;
77+
this.outputSockets = outputSockets;
78+
this.data = data;
6079
}
6180

6281
/**

core/src/main/java/edu/wpi/grip/core/serialization/StepConverter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
99
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
1010
import edu.wpi.grip.core.*;
11-
import edu.wpi.grip.core.events.StepAddedEvent;
1211

1312
import javax.inject.Inject;
1413
import java.util.Optional;
@@ -25,6 +24,7 @@ public class StepConverter implements Converter {
2524

2625
@Inject private EventBus eventBus;
2726
@Inject private Palette palette;
27+
@Inject private Pipeline pipeline;
2828
@Inject private Step.Factory stepFactory;
2929

3030
@Override
@@ -54,7 +54,7 @@ public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext co
5454

5555
// Instead of simply returning the step and having XStream insert it into the pipeline using reflection, send a
5656
// StepAddedEvent. This allows other interested classes (such as PipelineView) to also know when steps are added.
57-
this.eventBus.post(new StepAddedEvent(stepFactory.create(operation.get())));
57+
pipeline.addStep(stepFactory.create(operation.get()));
5858

5959
while (reader.hasMoreChildren()) {
6060
context.convertAnother(this, Socket.class);

core/src/main/java/edu/wpi/grip/core/sources/CameraSource.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public interface Factory {
5757

5858
public interface FrameGrabberFactory {
5959
FrameGrabber create(int deviceNumber);
60+
6061
FrameGrabber create(String addressProperty) throws MalformedURLException;
6162
}
6263

@@ -192,7 +193,7 @@ public void start() throws IOException, IllegalStateException {
192193
eventBus.post(new UnexpectedThrowableEvent(exception, "Camera Frame Grabber Thread crashed with uncaught exception"));
193194
try {
194195
stop();
195-
} catch (TimeoutException e) {
196+
} catch (TimeoutException | IOException e) {
196197
// TODO: This should use the ExceptionWitness once that has a UI component added for it
197198
eventBus.post(new UnexpectedThrowableEvent(e, "Camera Frame Grabber could not be stopped!"));
198199
}
@@ -211,10 +212,11 @@ public void start() throws IOException, IllegalStateException {
211212
* This will stop the source publishing new socket values after this method returns.
212213
*
213214
* @return The source that was stopped
214-
* @throws TimeoutException if the thread running the source fails to stop.
215-
* @throws IOException If there is a problem stopping the Source
215+
* @throws TimeoutException If the thread running the source fails to stop.
216+
* @throws IOException If there is a problem stopping the Source
217+
* @throws IllegalStateException If the camera is already stopped.
216218
*/
217-
public final void stop() throws TimeoutException, IllegalStateException {
219+
public final void stop() throws TimeoutException, IOException {
218220
synchronized (this) {
219221
if (frameThread.isPresent()) {
220222
final Thread ex = frameThread.get();
@@ -235,7 +237,7 @@ public final void stop() throws TimeoutException, IllegalStateException {
235237
// Calling this multiple times will have no effect
236238
grabber.stop();
237239
} catch (FrameGrabber.Exception e) {
238-
throw new IllegalStateException("A problem occurred trying to stop the frame grabber", e);
240+
throw new IOException("A problem occurred trying to stop the frame grabber", e);
239241
}
240242
}
241243
} else {
@@ -252,7 +254,7 @@ public synchronized boolean isStarted() {
252254
}
253255

254256
@Subscribe
255-
public void onSourceRemovedEvent(SourceRemovedEvent event) throws TimeoutException {
257+
public void onSourceRemovedEvent(SourceRemovedEvent event) throws TimeoutException, IOException {
256258
if (event.getSource() == this) {
257259
try {
258260
if (this.isStarted()) this.stop();
@@ -270,7 +272,7 @@ private static Properties createProperties(String address) {
270272

271273
private static Properties createProperties(int deviceNumber) {
272274
final Properties properties = new Properties();
273-
properties.setProperty(DEVICE_NUMBER_PROPERTY, "" + deviceNumber);
275+
properties.setProperty(DEVICE_NUMBER_PROPERTY, Integer.toString(deviceNumber));
274276
return properties;
275277
}
276278

0 commit comments

Comments
 (0)