created a simple plugin interface

This commit is contained in:
frosch95
2013-09-29 12:39:01 +02:00
parent 94441e06fa
commit ed708e836b
9 changed files with 241 additions and 10 deletions

View File

@@ -0,0 +1,103 @@
import de.frosch95.geofrogger.plugins.Plugin
import javafx.collections.FXCollections
import javafx.scene.chart.PieChart
import javafx.scene.control.Label
import javafx.scene.control.ScrollPane
import javafx.scene.layout.Pane
import javafx.scene.layout.VBox
import org.controlsfx.dialog.Dialog
import static javafx.scene.chart.PieChart.Data
class BasicListStatisticsPlugin implements Plugin {
private difficultyTerrainValues = ['1', '1.5', '2', '2.5', '3', '3.5', '4', '4.5', '5']
final String name = "Basic List Statistic"
final String version = "0.0.1"
@Override
void run(final Map context) {
showDialog(createHeader(context.sessionContext), createContent(context.sessionContext))
}
private javafx.scene.Node createHeader(sessionContext) {
def pane = new Pane()
def Label label = new Label()
label.text = "This example plugin shows some stats based on the current list.\nThese statistics are global statistics over all caches in list\nand not personalized statistics over own founds."
pane.children.add(label)
pane
}
/**
* creates the statistic charts to show
* @param sessionContext context with the cache list in it
* @return
*/
private javafx.scene.Node createContent(sessionContext) {
// get the cache list out of the context
def cacheList = sessionContext.getData("cache-list")
// create a vbox as layout container
VBox contenPane = new VBox()
// groovy maps for selecting the statistic numbers
def typeStats = [:]
def difficultyStats = [:]
def terrainStats = [:]
// iterate over all the caches and count the data
for (def cache in cacheList) {
incrementStats(typeStats, cache.type)
incrementStats(difficultyStats, cache.difficulty)
incrementStats(terrainStats, cache.terrain)
}
// create javafx chart
def typeData = FXCollections.observableArrayList()
typeStats.each() { key, value -> typeData.add(new Data(key as String, value as double)) }
def typeChart = new PieChart(typeData);
typeChart.setTitle("Number of cache types in list.");
// create javafx chart
def difficultyData = FXCollections.observableArrayList()
difficultyTerrainValues.each {
def value = difficultyStats[it]
if (value) difficultyData.add(new Data(it, value))
}
def difficultyChart = new PieChart(difficultyData);
difficultyChart.setTitle("Number of difficulties in list.");
// create javafx chart
def terrainData = FXCollections.observableArrayList()
difficultyTerrainValues.each {
def value = terrainStats[it]
if (value) terrainData.add(new Data(it, value))
}
def terrainChart = new PieChart(terrainData);
terrainChart.setTitle("Number of terrain in list.");
// add charts to layout container
contenPane.children.addAll(typeChart, difficultyChart, terrainChart)
// return the layout container
def scrollPane = new ScrollPane(contenPane)
scrollPane.minWidth = 600
scrollPane.prefWidth = 600
scrollPane.maxWidth = 600
scrollPane.minHeight = 450
scrollPane
}
private void incrementStats(map, key) {
map[key] = map[key] ? map[key] + 1 : 1
}
private void showDialog(header, content) {
Dialog dialog = new Dialog(null, name+" ("+version+")")
dialog.setMasthead(header)
dialog.setContent(content)
dialog.show()
}
}

View File

@@ -27,6 +27,8 @@ package de.frosch95.geofrogger.application;
import de.frosch95.geofrogger.gpx.GPXReader; import de.frosch95.geofrogger.gpx.GPXReader;
import de.frosch95.geofrogger.gpx.GroundspeakGPXReader; import de.frosch95.geofrogger.gpx.GroundspeakGPXReader;
import de.frosch95.geofrogger.plugins.PluginService;
import de.frosch95.geofrogger.plugins.PluginServiceImpl;
import de.frosch95.geofrogger.service.CacheService; import de.frosch95.geofrogger.service.CacheService;
import de.frosch95.geofrogger.service.CacheServiceImpl; import de.frosch95.geofrogger.service.CacheServiceImpl;
import de.frosch95.geofrogger.sql.DatabaseService; import de.frosch95.geofrogger.sql.DatabaseService;
@@ -42,6 +44,7 @@ public class ServiceManager {
private GPXReader gpxReader; private GPXReader gpxReader;
private DatabaseService databaseService; private DatabaseService databaseService;
private CacheService cacheService; private CacheService cacheService;
private PluginService pluginService;
private ServiceManager() { private ServiceManager() {
// private for singleton pattern // private for singleton pattern
@@ -72,4 +75,11 @@ public class ServiceManager {
return cacheService; return cacheService;
} }
public synchronized PluginService getPluginService() {
if (pluginService == null) {
pluginService = new PluginServiceImpl();
}
return pluginService;
}
} }

View File

@@ -30,6 +30,8 @@ import de.frosch95.geofrogger.application.ServiceManager;
import de.frosch95.geofrogger.application.SessionContext; import de.frosch95.geofrogger.application.SessionContext;
import de.frosch95.geofrogger.gpx.GPXReader; import de.frosch95.geofrogger.gpx.GPXReader;
import de.frosch95.geofrogger.model.Cache; import de.frosch95.geofrogger.model.Cache;
import de.frosch95.geofrogger.plugins.Plugin;
import de.frosch95.geofrogger.plugins.PluginService;
import de.frosch95.geofrogger.service.CacheService; import de.frosch95.geofrogger.service.CacheService;
import de.frosch95.geofrogger.service.CacheSortField; import de.frosch95.geofrogger.service.CacheSortField;
import de.frosch95.geofrogger.service.SortDirection; import de.frosch95.geofrogger.service.SortDirection;
@@ -39,12 +41,10 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.concurrent.Service; import javafx.concurrent.Service;
import javafx.concurrent.Task; import javafx.concurrent.Task;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label; import javafx.scene.control.*;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextArea;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.controlsfx.dialog.Dialog; import org.controlsfx.dialog.Dialog;
@@ -106,6 +106,7 @@ public class GeofroggerController implements Initializable {
private final GPXReader gpxReader = ServiceManager.getInstance().getGPXReader(); private final GPXReader gpxReader = ServiceManager.getInstance().getGPXReader();
private final CacheService cacheService = ServiceManager.getInstance().getCacheService(); private final CacheService cacheService = ServiceManager.getInstance().getCacheService();
private final PluginService pluginService = ServiceManager.getInstance().getPluginService();
@FXML @FXML
private Label leftStatus; private Label leftStatus;
@@ -113,6 +114,9 @@ public class GeofroggerController implements Initializable {
@FXML @FXML
private ProgressBar progress; private ProgressBar progress;
@FXML
private Menu pluginsMenu;
/** /**
* Initializes the controller class. * Initializes the controller class.
* *
@@ -121,14 +125,16 @@ public class GeofroggerController implements Initializable {
*/ */
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
gpxReader.addListener((ProgressEvent event) -> {
updateStatus(event.getMessage(), event.getProgress());
});
cacheService.addListener((ProgressEvent event) -> { List<Plugin> plugins = pluginService.getAllPlugins();
updateStatus(event.getMessage(), event.getProgress()); for (Plugin plugin: plugins) {
}); MenuItem menuItem = new MenuItem(plugin.getName()+" ("+plugin.getVersion()+")");
menuItem.setOnAction(actionEvent -> pluginService.executePlugin(plugin));
pluginsMenu.getItems().add(menuItem);
}
gpxReader.addListener((ProgressEvent event) -> updateStatus(event.getMessage(), event.getProgress()));
cacheService.addListener((ProgressEvent event) -> updateStatus(event.getMessage(), event.getProgress()));
loadFromDBService.start(); loadFromDBService.start();
} }

View File

@@ -18,6 +18,7 @@
<MenuItem mnemonicParsing="false" onAction="#exit" text="%menu.title.quit"/> <MenuItem mnemonicParsing="false" onAction="#exit" text="%menu.title.quit"/>
</items> </items>
</Menu> </Menu>
<Menu fx:id="pluginsMenu" mnemonicParsing="false" text="%menu.title.plugins"/>
<Menu mnemonicParsing="false" text="%menu.title.help"> <Menu mnemonicParsing="false" text="%menu.title.help">
<items> <items>
<MenuItem mnemonicParsing="false" onAction="#showAboutDialog" text="%menu.title.about"/> <MenuItem mnemonicParsing="false" onAction="#showAboutDialog" text="%menu.title.about"/>

View File

@@ -3,6 +3,7 @@ menu.title.file = Datei
menu.title.quit = Beenden menu.title.quit = Beenden
menu.title.help = Hilfe menu.title.help = Hilfe
menu.title.about = \u00dcber GeoFroggerFX menu.title.about = \u00dcber GeoFroggerFX
menu.title.plugins = Plugins
menu.title.sort = Sortieren menu.title.sort = Sortieren
menu.title.filter = Filtern menu.title.filter = Filtern

View File

@@ -3,6 +3,7 @@ menu.title.file = File
menu.title.quit = Quit menu.title.quit = Quit
menu.title.help = Help menu.title.help = Help
menu.title.about = About GeoFroggerFX menu.title.about = About GeoFroggerFX
menu.title.plugins = Plugins
menu.title.sort = Sort menu.title.sort = Sort
menu.title.filter = Filter menu.title.filter = Filter

View File

@@ -0,0 +1,30 @@
package de.frosch95.geofrogger.plugins;
import java.util.Map;
/**
* This interface defines the method a plugin has to provide to be called correctly
*
* @author abi
*/
public interface Plugin {
/**
* @return name
*/
String getName();
/**
* @return version
*/
String getVersion();
/**
* Run the main method of the plugin. All the logic is done in this method.
* Every run method will get a context map, with all the services inside,
* to use them.
* @param context services and data
*/
void run(Map context);
}

View File

@@ -0,0 +1,18 @@
package de.frosch95.geofrogger.plugins;
import java.util.List;
/**
* TODO: class description
*
* @author abi
*/
public interface PluginService {
List<Plugin> getAllPlugins();
void executePlugin(Plugin plugin);
}

View File

@@ -0,0 +1,61 @@
package de.frosch95.geofrogger.plugins;
import de.frosch95.geofrogger.application.ServiceManager;
import de.frosch95.geofrogger.application.SessionContext;
import groovy.lang.GroovyClassLoader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* TODO: class description
*
* @author abi
*/
public class PluginServiceImpl implements PluginService {
private final GroovyClassLoader gcl = new GroovyClassLoader();
private final ServiceManager serviceManager = ServiceManager.getInstance();
@Override
public List<Plugin> getAllPlugins() {
List<Plugin> plugins = new ArrayList<>();
try {
File file = new File("./plugins");
if (!file.exists()) {
throw new IllegalArgumentException("plugins folder does not exit");
}
File[] pluginFiles = file.listFiles((dir, name) -> name.endsWith("Plugin.groovy"));
for (File pluginFile: pluginFiles) {
Class clazz = gcl.parseClass(pluginFile);
for (Class interf: clazz.getInterfaces()) {
if (interf.equals(Plugin.class)) {
plugins.add((Plugin)clazz.newInstance());
break;
}
}
}
} catch (IOException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return plugins;
}
@Override
public void executePlugin(final Plugin plugin) {
Map<String, Object> context = new HashMap<>();
context.put("sessionContext", SessionContext.getInstance());
context.put("cacheService", serviceManager.getCacheService());
plugin.run(context);
}
}