[TASK] Create observer window

This commit is contained in:
Jan Philipp Timme 2016-10-02 15:30:06 +02:00
parent 48e01f493f
commit 896fe022a8
4 changed files with 296 additions and 6 deletions

View File

@ -6,21 +6,22 @@ import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import eu.larkc.csparql.common.utils.CsparqlUtils;
import eu.larkc.csparql.common.utils.ReasonerChainingType;
import eu.larkc.csparql.core.engine.ConsoleFormatter; import eu.larkc.csparql.core.engine.ConsoleFormatter;
import eu.larkc.csparql.core.engine.CsparqlEngine; import eu.larkc.csparql.core.engine.CsparqlEngine;
import eu.larkc.csparql.core.engine.CsparqlEngineImpl; import eu.larkc.csparql.core.engine.CsparqlEngineImpl;
import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy; import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy;
import lu.jpt.csparqltest.gui.TextObserverWindow;
import lu.jpt.csparqltest.rentacar.RentACarSimulation; import lu.jpt.csparqltest.rentacar.RentACarSimulation;
import lu.jpt.csparqltest.util.RandomHelper;
import lu.jpt.csparqltest.util.TestStreamGenerator; import lu.jpt.csparqltest.util.TestStreamGenerator;
public class Main { public class Main {
private static Logger logger = LoggerFactory.getLogger(Main.class); private static Logger logger = LoggerFactory.getLogger(Main.class);
public static TextObserverWindow observerWindow;
public static void main(String[] args) { public static void main(String[] args) {
Main.observerWindow = new TextObserverWindow("Result observer window");
// Determines the time the engine will be run for // Determines the time the engine will be run for
final long millisecondsToRun = 50 * 1000; final long millisecondsToRun = 50 * 1000;
@ -71,7 +72,7 @@ public class Main {
testGeneratorThread.start(); testGeneratorThread.start();
// Now build a query to run - interchangeable // Now build a query to run - interchangeable
String query = Main.getNOTA(); String query = Main.getSPO();
//String query = RentACarSimulation.getEventUsingBackgroundKnowledge(); //String query = RentACarSimulation.getEventUsingBackgroundKnowledge();
// Create a result proxy by registering the query at the engine // Create a result proxy by registering the query at the engine
@ -99,6 +100,7 @@ public class Main {
// Add ConsoleFormatter as observer so it gets notified of every query result // Add ConsoleFormatter as observer so it gets notified of every query result
resultProxy.addObserver(new ConsoleFormatter()); resultProxy.addObserver(new ConsoleFormatter());
resultProxy.addObserver(Main.observerWindow);
// Let it all run for some time // Let it all run for some time
try { try {

View File

@ -0,0 +1,251 @@
package lu.jpt.csparqltest.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import eu.larkc.csparql.cep.api.RdfQuadruple;
import eu.larkc.csparql.common.RDFTable;
import eu.larkc.csparql.common.RDFTuple;
import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy;
/**
* Multi-purpose text window to allow for easy viewing of RdfStream quadruples,
* various logging or observing query results.
*/
public class TextObserverWindow extends JFrame implements Observer {
private static final long serialVersionUID = 1L;
private JTextPane textPane;
private volatile boolean autoScrollToBottom = true;
/**
* Constructor
* @param title of the window
*/
public TextObserverWindow(String title) {
this.initWindow(title);
}
/**
* Set whether the window is automatically scrolling to the bottom
* @param autoScrollToBottom
*/
public void setAutoScrollToBottom(boolean autoScrollToBottom) {
this.autoScrollToBottom = autoScrollToBottom;
}
/**
* Show the given text in the window
* @param text
*/
public void showText(String text) {
this.showText(text, Color.BLACK);
}
/**
* Show given text in the window using the given color
* @param text
* @param color
*/
public void showText(String text, Color color) {
this.appendToTextPane(text, true, color);
}
/**
* Show the given token in the window without appending linebreaks
* @param text
*/
public void showToken(String token) {
this.showText(token, Color.BLACK);
}
/**
* Show given token in the window using the given color without appending linebreaks
* @param text
* @param color
*/
public void showToken(String token, Color color) {
this.appendToTextPane(token, false, color);
}
/**
* Show given RdfQuadruple in the window
* @param quad
*/
public void showQuadruple(RdfQuadruple quad) {
this.showQuadruple(quad, Color.BLACK);
}
/**
* Show given RdfQuadruple in window using given color
* @param quad
* @param color
*/
public void showQuadruple(RdfQuadruple quad, Color color) {
this.appendToTextPane(quad.toString(), true, color);
}
/**
* Internal method to set up the window and show it.
* @param title of the window
*/
private void initWindow(String title) {
// Little hack to be able to access myself from within ActionListeners
final TextObserverWindow textObserverWindow = this;
this.setTitle(title);
this.setResizable(true);
this.setUndecorated(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
// Get a TextPane ready
this.textPane = new JTextPane();
this.textPane.setEnabled(true);
this.textPane.setFocusable(false);
this.textPane.setAutoscrolls(true);
this.textPane.setMargin(new Insets(5, 5, 5, 5));
contentPane.add(this.textPane, BorderLayout.CENTER);
// Add a ScrollPane
JScrollPane scrollPane = new JScrollPane(this.textPane);
scrollPane.setPreferredSize(new Dimension(800, 500));
contentPane.add(scrollPane, BorderLayout.CENTER);
// Add a checkbox to toggle autoscroll
JCheckBox autoscrollCheckbox = new JCheckBox();
autoscrollCheckbox.setText("Automatically scroll to bottom");
autoscrollCheckbox.setEnabled(true);
autoscrollCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox) e.getSource();
textObserverWindow.setAutoScrollToBottom(checkBox.isSelected());
}
});
contentPane.add(autoscrollCheckbox, BorderLayout.SOUTH);
this.setVisible(true);
this.pack();
}
/**
* Internal method to append text to the textpane
* @param text to show within the window
* @param addLinebreak whether or not to add a linebreak (usually yes is better)
* @param color to display the text in
*/
private void appendToTextPane(String text, boolean addLinebreak, Color color) {
if (addLinebreak) text += "\n";
StyleContext styleContext = StyleContext.getDefaultStyleContext();
AttributeSet attributeSet = styleContext.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, color);
attributeSet = styleContext.addAttribute(attributeSet, StyleConstants.FontFamily, "Lucida Console");
attributeSet = styleContext.addAttribute(attributeSet, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);
int oldCaretPosition = this.textPane.getCaretPosition();
int length = this.textPane.getDocument().getLength();
this.textPane.setCaretPosition(length);
this.textPane.setCharacterAttributes(attributeSet, false);
this.textPane.replaceSelection(text);
// TODO: Fix behaviour when autoscroll is disabled!
if(this.autoScrollToBottom) {
Document textPaneDocument = this.textPane.getDocument();
this.textPane.select(textPaneDocument.getLength(), textPaneDocument.getLength());
} else {
this.textPane.setCaretPosition(oldCaretPosition);
}
}
/**
* Generic method of Observer interface to allow for use as an observer.
* In case no CsparqlQueryResultProxy is being observed, output can still be useful. :-)
* @param observable the incoming observable object
* @param argument the argument that came with it
*/
@Override
public void update(Observable observable, Object argument) {
if(observable instanceof CsparqlQueryResultProxy) {
CsparqlQueryResultProxy result = (CsparqlQueryResultProxy) observable;
RDFTable table = (RDFTable) argument;
this.showCsparqlQueryResult(result, table);
} else {
// Debug output in case this is not used to observe
this.showText(observable.getClass().toString(), Color.RED);
this.showText(observable.toString(), Color.BLUE);
this.showText(argument.getClass().toString(), Color.RED);
this.showText(argument.toString(), Color.BLACK);
}
}
/**
* Method to actually print the results of a Csparql query
* @param CsparqlQueryResultProxy result
* @param RDFTable table
*/
private void showCsparqlQueryResult(CsparqlQueryResultProxy result, RDFTable table) {
String queryTupleNames = table.getNames().toString();
Collection<RDFTuple> tuples = table.getTuples();
this.showText(queryTupleNames, Color.BLACK);
for(RDFTuple tuple : tuples) {
// This one is separated with \t. Due to the implementation of RDFTuple, it is
// implossible to access the list of its fields directly. Sorry for the mess. :-(
String tupleString = tuple.toString();
// Explode tupleString by \t and show each field with alternating color.
StringTokenizer tokenizer = new StringTokenizer(tupleString);
Color[] palette = this.getColorPaletteWithSize(tokenizer.countTokens());
int tokenIndex = 0;
while(tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken()+"\t";
this.showToken(token, palette[tokenIndex]);
tokenIndex++;
}
this.showText("\n", Color.BLACK);
}
}
/**
* Generates a color palette for the given number of colors
* @param sizeOfPalette number of colors
* @return color palette as an array
*/
private Color[] getColorPaletteWithSize(int sizeOfPalette) {
if(sizeOfPalette == 0) {
return new Color[] {Color.BLACK};
}
Color[] result = new Color[sizeOfPalette];
float h = 0.0f;
float s = 0.75f;
float b = 0.75f;
for(int i=0; i<sizeOfPalette; i++) {
h = (((float) i)/((float) sizeOfPalette));
result[i] = Color.getHSBColor(h, s, b);
}
return result;
}
}

View File

@ -0,0 +1,29 @@
package lu.jpt.csparqltest.util;
import eu.larkc.csparql.cep.api.RdfQuadruple;
import eu.larkc.csparql.cep.api.RdfStream;
/**
* Helper class to allow easy plugging of log mechanisms.
*/
public class LoggableRdfStream extends RdfStream {
public LoggableRdfStream(String iri) {
super(iri);
}
public void put(RdfQuadruple quad) {
super.put(quad);
// Call hook method to allow logging the RdfQuadruple.
this.log(quad);
}
/**
* This hook method gets called for every RdfQuadruple that is fed into the stream.
* @param quad that has been fed into the stream.
*/
public void log(RdfQuadruple quad) {
// Default: Do nothing.
}
}

View File

@ -4,15 +4,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import eu.larkc.csparql.cep.api.RdfQuadruple; import eu.larkc.csparql.cep.api.RdfQuadruple;
import eu.larkc.csparql.cep.api.RdfStream; import lu.jpt.csparqltest.gui.TextObserverWindow;
public class TestStreamGenerator extends RdfStream implements Runnable { public class TestStreamGenerator extends LoggableRdfStream implements Runnable {
protected final Logger logger = LoggerFactory.getLogger(TestStreamGenerator.class); protected final Logger logger = LoggerFactory.getLogger(TestStreamGenerator.class);
private volatile boolean keepRunning = false; private volatile boolean keepRunning = false;
private TextObserverWindow observerWindow;
public TestStreamGenerator(String iri) { public TestStreamGenerator(String iri) {
super(iri); super(iri);
observerWindow = new TextObserverWindow("TestStreamGenerator");
} }
public void pleaseStop() { public void pleaseStop() {
@ -44,5 +47,10 @@ public class TestStreamGenerator extends RdfStream implements Runnable {
} }
} }
@Override
public void log(RdfQuadruple quad) {
this.observerWindow.showQuadruple(quad);
}
} }