[TASK] A lot of cleanup + a new component.

This commit is contained in:
Jan Philipp Timme 2016-10-03 19:23:23 +02:00
parent 614fa9f06b
commit 7269663572
5 changed files with 419 additions and 31 deletions

View File

@ -2,6 +2,7 @@ package lu.jpt.csparqlproject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Observer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -10,7 +11,8 @@ import eu.larkc.csparql.cep.api.RdfStream;
import eu.larkc.csparql.core.engine.CsparqlEngine;
import eu.larkc.csparql.core.engine.CsparqlEngineImpl;
import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy;
import lu.jpt.csparqlproject.gui.TextObserverWindow;
import lu.jpt.csparqlproject.gui.FancyTextObserverWindow;
import lu.jpt.csparqlproject.gui.RawTextObserverWindow;
import lu.jpt.csparqlproject.rentacar.RentACarSimulation;
import lu.jpt.csparqlproject.util.CsparqlQueryHelper;
@ -167,12 +169,29 @@ public class SimulationContext {
SimulationContext.logger.error(query);
}
this.queryResultProxies.add(resultProxy);
resultProxy.addObserver(new TextObserverWindow("[ResultProxy] " + queryName));
Observer resultObserver = this.createResultObserverWindow(queryName);
resultProxy.addObserver(resultObserver);
}
// Setup complete, ready to run.
SimulationContext.logger.info("Simulation set up and ready to go!");
this.currentState = SimulationState.INITIALIZED;
}
/**
* Builds a query result observer depending on the given queryName.
* This is useful if a querys result set is larger than usual.
* @param queryName
* @return Observer for query result
*/
private Observer createResultObserverWindow(String queryName) {
Observer observer = null;
if(false && queryName.equals("getEvents")) {
observer = new RawTextObserverWindow("[ResultProxy] " + queryName);
} else {
observer = new FancyTextObserverWindow("[ResultProxy] " + queryName);
}
return observer;
}
}

View File

@ -22,11 +22,15 @@ import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.larkc.csparql.cep.api.RdfQuadruple;
import eu.larkc.csparql.common.RDFTable;
import eu.larkc.csparql.common.RDFTuple;
@ -37,8 +41,10 @@ import lu.jpt.csparqlproject.Main;
* 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 {
public class FancyTextObserverWindow extends JFrame implements Observer {
public static Logger logger = LoggerFactory.getLogger(FancyTextObserverWindow.class);
private static final long serialVersionUID = 1L;
private static final int TEXTPANE_WIDTH = 800;
private static final int TEXTPANE_HEIGHT = 240;
@ -51,7 +57,7 @@ public class TextObserverWindow extends JFrame implements Observer {
* Constructor
* @param title of the window
*/
public TextObserverWindow(String title) {
public FancyTextObserverWindow(String title) {
this.initWindow(title);
}
@ -131,7 +137,7 @@ public class TextObserverWindow extends JFrame implements Observer {
*/
private void initWindow(String title) {
// Little hack to be able to access myself from within ActionListeners
final TextObserverWindow textObserverWindow = this;
final FancyTextObserverWindow textObserverWindow = this;
this.setTitle(title);
this.setResizable(true);
@ -171,7 +177,7 @@ public class TextObserverWindow extends JFrame implements Observer {
// Add a ScrollPane
JScrollPane scrollPane = new JScrollPane(this.textPane);
scrollPane.setPreferredSize(new Dimension(TextObserverWindow.TEXTPANE_WIDTH, TextObserverWindow.TEXTPANE_HEIGHT));
scrollPane.setPreferredSize(new Dimension(FancyTextObserverWindow.TEXTPANE_WIDTH, FancyTextObserverWindow.TEXTPANE_HEIGHT));
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane, BorderLayout.CENTER);
@ -252,20 +258,52 @@ public class TextObserverWindow extends JFrame implements Observer {
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);
boolean success = false;
do {
try {
this.textPane.setCaretPosition(length);
this.textPane.setCharacterAttributes(attributeSet, false);
this.textPane.replaceSelection(text);
success = true;
} catch(Exception e) {
// Yes, i know. :-(
}
} while(!success);
// This is the place to enforce a line limit
//this.enforceLineLimit();
// 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);
}
}
/**
* Helper method to enforce a line limit for the window.
*/
private void enforceLineLimit() {
int MAX_LINES = 50;
String[] lines = this.textPane.getText().split("\n");
int totalLines = lines.length;
int characters = 0;
if(totalLines > MAX_LINES) {
int linesToRemove = (totalLines - MAX_LINES) - 1;
if(linesToRemove > 5) {
for(int currentLine = 0; currentLine < linesToRemove; currentLine++) {
characters += lines[currentLine].length() + 1;
}
try {
this.textPane.getDocument().remove(0, characters);
} catch (BadLocationException e) {
FancyTextObserverWindow.logger.error(e.toString());
FancyTextObserverWindow.logger.error(e.getMessage());
}
}
}
}
/**
* Generic method of Observer interface to allow for use as an observer.
* In case no CsparqlQueryResultProxy is being observed, output can still be useful. :-)
@ -274,16 +312,22 @@ public class TextObserverWindow extends JFrame implements Observer {
*/
@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);
try {
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);
}
} catch(Exception e) {
// This is to prevent the whole stack from crashing.
FancyTextObserverWindow.logger.error(e.toString());
FancyTextObserverWindow.logger.error(e.getMessage());
}
}

View File

@ -0,0 +1,325 @@
package lu.jpt.csparqlproject.gui;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import lu.jpt.csparqlproject.Main;
/**
* Multi-purpose text window to allow for easy viewing of RdfStream quadruples,
* various logging or observing query results.
*/
public class RawTextObserverWindow extends JFrame implements Observer {
public static Logger logger = LoggerFactory.getLogger(RawTextObserverWindow.class);
private static final long serialVersionUID = 1L;
private static final int TEXTAREA_WIDTH = 800;
private static final int TEXTAREA_HEIGHT = 240;
private JTextArea textArea;
private volatile boolean autoScrollToBottom = true;
private volatile boolean usePrefixManager = true;
/**
* Constructor
* @param title of the window
*/
public RawTextObserverWindow(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;
}
/**
* Set whether or not the PrefixManager shall be used to shorten
* uris in strings to prefixes.
* @param usePrefixManager
*/
public void setUsePrefixManager(boolean usePrefixManager) {
this.usePrefixManager = usePrefixManager;
}
/**
* Show given text in the window
* @param text
*/
public void showText(String text) {
this.appendToTextPane(text, true);
}
/**
* Show given token in the window without appending linebreaks
* @param text
*/
public void showToken(String token) {
this.appendToTextPane(token, false);
}
/**
* Show given RdfQuadruple in window
* @param quad
*/
public void showQuadruple(RdfQuadruple quad) {
String quadruple = this.shortenUriToPrefix(quad.toString());
this.appendToTextPane(quadruple, true);
}
/**
* 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 RawTextObserverWindow textObserverWindow = this;
this.setTitle(title);
this.setResizable(true);
this.setUndecorated(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
// Add a title label for convenience
JLabel titleLabel = new JLabel(title);
Font labelFont = titleLabel.getFont();
titleLabel.setFont(new Font(labelFont.getName(), Font.PLAIN, 18));
contentPane.add(titleLabel, BorderLayout.NORTH);
// Get a TextPane ready - a little hack to make it always scroll horizontally
this.textArea = new JTextArea() {
private static final long serialVersionUID = 1L;
public boolean getScrollableTracksViewportWidth() {
return false;
}
public void setSize(Dimension dimension) {
if (dimension.width < getParent().getSize().width) {
dimension.width = getParent().getSize().width;
}
super.setSize(dimension);
}
};
this.textArea.setEnabled(true);
this.textArea.setFocusable(false);
this.textArea.setEditable(true);
this.textArea.setAutoscrolls(true);
this.textArea.setMargin(new Insets(5, 5, 5, 5));
contentPane.add(this.textArea, BorderLayout.CENTER);
// Add a ScrollPane
JScrollPane scrollPane = new JScrollPane(this.textArea);
scrollPane.setPreferredSize(new Dimension(RawTextObserverWindow.TEXTAREA_WIDTH, RawTextObserverWindow.TEXTAREA_HEIGHT));
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
contentPane.add(scrollPane, BorderLayout.CENTER);
// Bottom Panel contains control elements
JPanel bottomPanel = new JPanel();
// Add a checkbox to toggle autoscroll
JCheckBox autoscrollCheckbox = new JCheckBox();
autoscrollCheckbox.setText("Automatically scroll to bottom");
autoscrollCheckbox.setEnabled(true);
autoscrollCheckbox.setSelected(true);
autoscrollCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox) e.getSource();
textObserverWindow.setAutoScrollToBottom(checkBox.isSelected());
}
});
bottomPanel.add(autoscrollCheckbox);
// Add a checkbox to toggle uri shortening using PrefixManager
JCheckBox usePrefixManagerCheckbox = new JCheckBox();
usePrefixManagerCheckbox.setText("Shorten URIs to prefixes");
usePrefixManagerCheckbox.setEnabled(true);
usePrefixManagerCheckbox.setSelected(true);
usePrefixManagerCheckbox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox) e.getSource();
textObserverWindow.setUsePrefixManager(checkBox.isSelected());
}
});
bottomPanel.add(usePrefixManagerCheckbox);
// Add buttons to increase/decrease font size
JButton increaseFontSizeButton = new JButton("+");
increaseFontSizeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Font currentFont = textObserverWindow.textArea.getFont();
textObserverWindow.textArea.setFont(
new Font(currentFont.getName(), currentFont.getStyle(), currentFont.getSize()+1)
);
}
});
bottomPanel.add(increaseFontSizeButton);
JButton decreaseFontSizeButton = new JButton("-");
decreaseFontSizeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Font currentFont = textObserverWindow.textArea.getFont();
textObserverWindow.textArea.setFont(
new Font(currentFont.getName(), currentFont.getStyle(), currentFont.getSize()-1)
);
}
});
bottomPanel.add(decreaseFontSizeButton);
// Add bottomPanel to contentPane
contentPane.add(bottomPanel, BorderLayout.SOUTH);
// Finally show the window
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)
*/
private void appendToTextPane(String text, boolean addLinebreak) {
if (addLinebreak) text += "\n";
int length = this.textArea.getDocument().getLength();
boolean success = false;
do {
try {
this.textArea.setCaretPosition(length);
this.textArea.replaceSelection(text);
success = true;
} catch(Exception e) {
// Yes, i know. :-(
}
} while(!success);
// TODO: Fix behaviour when autoscroll is disabled!
if(this.autoScrollToBottom) {
Document textPaneDocument = this.textArea.getDocument();
this.textArea.select(textPaneDocument.getLength(), textPaneDocument.getLength());
}
}
/**
* 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) {
try {
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());
this.showText(observable.toString());
this.showText(argument.getClass().toString());
this.showText(argument.toString());
}
} catch(Exception e) {
// This is to prevent the whole stack from crashing.
RawTextObserverWindow.logger.error(e.toString());
RawTextObserverWindow.logger.error(e.getMessage());
}
}
/**
* Method to actually pretty-print the results of a Csparql query
* @param CsparqlQueryResultProxy result
* @param RDFTable table
*/
private void showCsparqlQueryResult(CsparqlQueryResultProxy result, RDFTable table) {
long currentTime = System.currentTimeMillis();
Collection<String> tupleElementNames = table.getNames();
Collection<RDFTuple> tuples = table.getTuples();
this.showText("SystemTime=["+currentTime+"], Results=["+tuples.size()+"]");
// Show names in according color coding
this.showToken("Columns in order: [");
Iterator<String> elementNamesIterator = tupleElementNames.iterator();
while(elementNamesIterator.hasNext()) {
String elementName = elementNamesIterator.next();
if(elementName == "") elementName = "[NO VALUE]";
if(elementNamesIterator.hasNext()) {
elementName += ", ";
}
this.showToken(elementName);
}
this.showText("]");
for(RDFTuple tuple : tuples) {
// This one is separated with \t. Due to the implementation of RDFTuple, it is
// impossible 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);
while(tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
token = this.shortenUriToPrefix(token);
if(token == "") token = "[NO VALUE]";
if(tokenizer.hasMoreTokens()) {
token += "\t";
} else {
token += "\n";
}
this.showToken(token);
}
}
this.showText("End of results ----------------------------------------------------------------- \n");
}
/**
* Helper method to shorten strings using the PrefixManager if
* this window uses it
* @param str input string
* @return output string, shortened or not depending on usePrefixManager variable
*/
private String shortenUriToPrefix(String str) {
if(this.usePrefixManager) {
return Main.prefixManager.applyPrefix(str);
} else {
return str;
}
}
}

View File

@ -42,8 +42,8 @@ public class RentACarSimulation implements Runnable {
public RentACarSimulation() {
this.registerOwnPrefixes();
int numberOfCars = 5;
int numberOfCustomers = 5;
int numberOfCars = 1;
int numberOfCustomers = 1;
// Create a car pool and drivers
this.carPool = new CarPool(numberOfCars);
this.drivers = new ArrayList<Driver>();
@ -163,10 +163,10 @@ public class RentACarSimulation implements Runnable {
+ " ?e car:speed ?speed . "
+ " ?e car:motorRPM ?rpm . "
+ " ?e car:handbrakeEngaged ?handbrake . "
+ " ?e car:tirePressure1 ?pressure1 . "
+ " ?e car:tirePressure2 ?pressure2 . "
+ " ?e car:tirePressure3 ?pressure3 . "
+ " ?e car:tirePressure4 ?pressure4 . "
+ " ?e car:tirePressure1 ?tirePressure1 . "
+ " ?e car:tirePressure2 ?tirePressure2 . "
+ " ?e car:tirePressure3 ?tirePressure3 . "
+ " ?e car:tirePressure4 ?tirePressure4 . "
+ "}";
}

View File

@ -1,7 +1,7 @@
package lu.jpt.csparqlproject.util;
import eu.larkc.csparql.cep.api.RdfQuadruple;
import lu.jpt.csparqlproject.gui.TextObserverWindow;
import lu.jpt.csparqlproject.gui.RawTextObserverWindow;
/**
* Using this class, RdfStreams can automatically be made visible
@ -9,7 +9,7 @@ import lu.jpt.csparqlproject.gui.TextObserverWindow;
*/
public class WindowLoggingRdfStream extends LoggableRdfStream {
private TextObserverWindow observerWindow;
private RawTextObserverWindow observerWindow;
public WindowLoggingRdfStream(String iri) {
super(iri);
@ -17,7 +17,7 @@ public class WindowLoggingRdfStream extends LoggableRdfStream {
final WindowLoggingRdfStream me = this;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
me.observerWindow = new TextObserverWindow("[RdfStream] "+iri);
me.observerWindow = new RawTextObserverWindow("[RdfStream] "+iri);
}
});
}