Skip to content

Commit

Permalink
Merge pull request #28 from Grundlefleck/plugin-pull-request
Browse files Browse the repository at this point in the history
Plugin pull request
  • Loading branch information
scarytom committed Nov 1, 2013
2 parents f4faa20 + a53433e commit 34e24bc
Show file tree
Hide file tree
Showing 31 changed files with 420 additions and 112 deletions.
1 change: 1 addition & 0 deletions .classpath
Expand Up @@ -5,6 +5,7 @@
<classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/test/webapp"/>
<classpathentry kind="src" path="src/immersiontest/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry exported="true" kind="lib" path="vendor/jslib"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="lib" path="vendor/lib/commons-codec-1.6.jar" sourcepath="vendor/src/commons-codec-1.6-src.zip"/>
Expand Down
3 changes: 2 additions & 1 deletion build.xml
Expand Up @@ -79,7 +79,8 @@
<attribute name="Implementation-Title" value="${ant.project.name}"/>
<attribute name="Implementation-Version" value="${version.label}"/>
<attribute name="Built-Date" value="${build.timestamp}"/>
</manifest>
</manifest>
<fileset dir="${basedir}/src/main/resources" includes="**/META-INF/**"/>
</jar>
</target>

Expand Down
@@ -0,0 +1,11 @@
package org.netmelody.cieye.core.observation;

import org.netmelody.cieye.core.domain.CiServerType;

public interface ForeignAgencies {
ObservationAgency agencyFor(CiServerType type);

void registerInterestInChanges(Object interested);

final class RosterChangedEvent {}
}
@@ -1,8 +1,9 @@
package org.netmelody.cieye.core.observation;

import org.netmelody.cieye.core.domain.CiServerType;
import org.netmelody.cieye.core.domain.Feature;

public interface ObservationAgency {

boolean canProvideSpyFor(CiServerType type);
CiSpy provideSpyFor(Feature feature, CommunicationNetwork network, KnownOffendersDirectory directory);
}
5 changes: 4 additions & 1 deletion src/main/java/org/netmelody/cieye/server/CiEyeServer.java
Expand Up @@ -21,12 +21,15 @@ public final class CiEyeServer {

private final ServerConfiguration agency = new ServerConfiguration();
private final CommunicationNetwork network = new JsonRestRequesterBuilder();
private final IntelligenceAgency intelligenceAgency = IntelligenceAgency.create(network,
agency.detective(),
agency.foreignAgents());
private final Container container =
new ResourceContainer(new CiEyeResourceEngine(agency.observationTargetDirectory(),
agency.album(),
agency.information(),
new CachedRequestOriginTracker(agency.detective()),
new IntelligenceAgency(network, agency.detective()),
intelligenceAgency,
new GovernmentReport(new GovernmentWatchdog(network))));
private final Connection connection;
private final InetSocketAddress address;
Expand Down
8 changes: 0 additions & 8 deletions src/main/java/org/netmelody/cieye/server/CiSpyAllocator.java

This file was deleted.

5 changes: 4 additions & 1 deletion src/main/java/org/netmelody/cieye/server/CiSpyHandler.java
Expand Up @@ -2,12 +2,15 @@

import org.netmelody.cieye.core.domain.Feature;
import org.netmelody.cieye.core.domain.TargetDetailGroup;
import org.netmelody.cieye.core.domain.TargetId;

public interface CiSpyHandler {

TargetDetailGroup statusOf(Feature feature);

long millisecondsUntilNextUpdate(Feature feature);

boolean takeNoteOf(String targetId, String note);
boolean takeNoteOf(TargetId targetId, String note);

void endMission();
}
@@ -0,0 +1,9 @@
package org.netmelody.cieye.server;

import org.netmelody.cieye.core.domain.Feature;
import org.netmelody.cieye.core.domain.TargetId;

public interface CiSpyIntermediary {
TargetGroupBriefing briefingOn(Feature feature);
boolean passNoteOn(Feature feature, TargetId targetId, String note);
}
15 changes: 15 additions & 0 deletions src/main/java/org/netmelody/cieye/server/TargetGroupBriefing.java
@@ -0,0 +1,15 @@
package org.netmelody.cieye.server;

import org.netmelody.cieye.core.domain.TargetDetailGroup;

public final class TargetGroupBriefing {

public final TargetDetailGroup status;
public final long millisecondsUntilNextUpdate;

public TargetGroupBriefing(TargetDetailGroup targetDetailGroup, long millisecondsUntilNextUpdate) {
this.status = targetDetailGroup;
this.millisecondsUntilNextUpdate = millisecondsUntilNextUpdate;
}

}
@@ -0,0 +1,31 @@
package org.netmelody.cieye.server.configuration;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.SuffixFileFilter;

public final class PluginDirectory {

private final File directory;
private Date lastReadDate = new Date(0L);

public PluginDirectory(File directory) {
this.directory = directory;
}

public Iterable<File> jars() {
lastReadDate = new Date();
File[] jarFiles = directory.listFiles((FileFilter)new SuffixFileFilter(".jar"));
return jarFiles == null ? Collections.<File>emptySet() : Arrays.asList(jarFiles);
}

public boolean updateAvailable() {
return FileUtils.isFileNewer(directory, lastReadDate);
}

}
@@ -1,14 +1,16 @@
package org.netmelody.cieye.server.observation;
package org.netmelody.cieye.server.configuration;

import java.util.ResourceBundle;

import org.netmelody.cieye.core.domain.CiServerType;
import org.netmelody.cieye.core.observation.ForeignAgencies;
import org.netmelody.cieye.core.observation.ObservationAgency;

public final class ObservationAgencyConfiguration {
public final class ResourceBundleObservationAgencyConfiguration implements ForeignAgencies {

private static final ResourceBundle AGENCY_CONFIGURATION = ResourceBundle.getBundle(ObservationAgencyConfiguration.class.getName());
private static final ResourceBundle AGENCY_CONFIGURATION = ResourceBundle.getBundle(ResourceBundleObservationAgencyConfiguration.class.getName());

@Override
public ObservationAgency agencyFor(CiServerType type) {
final String typeName = type.name();
if (!AGENCY_CONFIGURATION.containsKey(typeName)) {
Expand All @@ -24,4 +26,10 @@ public ObservationAgency agencyFor(CiServerType type) {
throw new IllegalStateException("Failed to load CI Observation Module for " + typeName, e);
}
}

@Override
public void registerInterestInChanges(Object interested) {
// No-op, never changes
}

}
Expand Up @@ -4,6 +4,7 @@
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.netmelody.cieye.core.observation.ForeignAgencies;
import org.netmelody.cieye.core.observation.KnownOffendersDirectory;
import org.netmelody.cieye.server.CiEyeServerInformationFetcher;
import org.netmelody.cieye.server.LandscapeFetcher;
Expand All @@ -16,6 +17,7 @@ public final class ServerConfiguration {
private final ServerInformation information = new ServerInformation(settings.settingsLocation());
private final RecordedKnownOffenders detective = new RecordedKnownOffenders(settings.picturesFile());
private final RecordedObservationTargets targets = new RecordedObservationTargets(settings.viewsFile());
private final ServiceLoadingRecordedForeignAgencies foreignAgencies = new ServiceLoadingRecordedForeignAgencies(settings.pluginDirectory());
private final Album album = new Album(settings.picturesDirectory());

private static final class Refresher implements Runnable {
Expand All @@ -30,9 +32,10 @@ public void run() {
}

public ServerConfiguration() {
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
executor.scheduleWithFixedDelay(new Refresher(detective), 1L, 10L, TimeUnit.SECONDS);
executor.scheduleWithFixedDelay(new Refresher(targets), 1L, 10L, TimeUnit.SECONDS);
executor.scheduleWithFixedDelay(new Refresher(foreignAgencies), 1L, 10L, TimeUnit.SECONDS);
}

public KnownOffendersDirectory detective() {
Expand All @@ -50,4 +53,8 @@ public CiEyeServerInformationFetcher information() {
public PictureFetcher album() {
return album;
}

public ForeignAgencies foreignAgents() {
return foreignAgencies;
}
}
@@ -0,0 +1,102 @@
package org.netmelody.cieye.server.configuration;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import org.netmelody.cieye.core.domain.CiServerType;
import org.netmelody.cieye.core.logging.LogKeeper;
import org.netmelody.cieye.core.logging.Logbook;
import org.netmelody.cieye.core.observation.ForeignAgencies;
import org.netmelody.cieye.core.observation.ObservationAgency;

import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;

public final class ServiceLoadingRecordedForeignAgencies implements ForeignAgencies, Refreshable {
private final static Logbook LOGBOOK = LogKeeper.logbookFor(ServiceLoadingRecordedForeignAgencies.class);
private final EventBus eventBus = new EventBus(getClass().getName());

private final PluginDirectory pluginDirectory;
private final AtomicReference<ServiceLoader<ObservationAgency>> services;


public ServiceLoadingRecordedForeignAgencies(PluginDirectory pluginDirectory) {
this.pluginDirectory = pluginDirectory;
this.services = new AtomicReference<ServiceLoader<ObservationAgency>>(newServiceLoader());
}

@Override
public ObservationAgency agencyFor(CiServerType type) {
final String typeName = type.name();
Iterator<ObservationAgency> agencies = available();

while (agencies.hasNext()) {
ObservationAgency agency = agencies.next();
if (agency.canProvideSpyFor(type)) {
return agency;
}
}

throw new IllegalStateException("No CI Observation Module for " + typeName);
}

private ServiceLoader<ObservationAgency> newServiceLoader() {
return ServiceLoader.load(ObservationAgency.class, pluginsClassLoader());
}

private Iterator<ObservationAgency> available() {
return services.get().iterator();
}

private ClassLoader pluginsClassLoader() {
Iterable<File> jarFiles = pluginDirectory.jars();
return new URLClassLoader(FluentIterable.from(urlsOf(jarFiles)).toArray(URL.class));
}

private Set<URL> urlsOf(Iterable<File> jarFiles) {
Set<URL> urls = Sets.newHashSet();
Set<Throwable> problems = Sets.newHashSet();
for (File file : jarFiles) {
try {
urls.add(file.toURI().toURL());
} catch (MalformedURLException e) {
problems.add(e);
}
}

if (!problems.isEmpty()) {
logProblems(problems);
}

return ImmutableSet.copyOf(urls);
}

private static void logProblems(Set<Throwable> problems) {
System.out.printf("Found [%d] problems obtaining plugin jars. See logs for more details.%n", problems.size());
for (Throwable throwable : problems) {
LOGBOOK.error("Error loading plugin.", throwable);
}
}

@Override
public void refresh() {
if (pluginDirectory.updateAvailable()) {
this.services.set(newServiceLoader());
this.eventBus.post(new RosterChangedEvent());
}
}

@Override
public void registerInterestInChanges(Object interested) {
this.eventBus.register(interested);
}

}
Expand Up @@ -14,6 +14,7 @@ public final class SettingsInitialiser {
private final File viewsFile;
private final File picturesFile;
private final File picturesDir;
private final File pluginsDir;

public SettingsInitialiser() {
this(new File(FileUtils.getUserDirectory(), ".ci-eye"));
Expand All @@ -24,6 +25,7 @@ public SettingsInitialiser(File directory) {
this.viewsFile = new File(homeDir, "views.txt");
this.picturesFile = new File(homeDir, "pictures.txt");
this.picturesDir = new File(homeDir, "pictures");
this.pluginsDir = new File(homeDir, "plugins");

try {
startLogger();
Expand Down Expand Up @@ -62,6 +64,10 @@ private void terraform() throws IOException {
includePicture("stupid.png", "picture2.png.template");
}

if (!pluginsDir.exists()) {
pluginsDir.mkdir();
}

ensureSpecialPicturePresent("-doh-", "doh.png", "picture3.png.template");
ensureSpecialPicturePresent("-all-green-", "all-green.gif", "picture4.gif.template");
}
Expand Down Expand Up @@ -106,4 +112,8 @@ public String settingsLocation() {
throw new IllegalStateException("Unable to get settings directory", e);
}
}

public PluginDirectory pluginDirectory() {
return new PluginDirectory(pluginsDir);
}
}

0 comments on commit 34e24bc

Please sign in to comment.