Java tutorial
package com.monead.semantic.workbench; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Desktop; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridLayout; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.net.URL; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Properties; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ProgressMonitor; import javax.swing.ProgressMonitorInputStream; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.WindowConstants; import javax.swing.border.TitledBorder; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.filechooser.FileFilter; import javax.swing.table.AbstractTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import org.apache.commons.httpclient.HttpStatus; import org.apache.jena.atlas.web.auth.SimpleAuthenticator; import org.apache.jena.riot.RiotException; import org.apache.log4j.Logger; import org.mindswap.pellet.utils.VersionInfo; import com.hp.hpl.jena.ontology.ConversionException; import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModelSpec; import com.hp.hpl.jena.query.ARQ; import com.hp.hpl.jena.query.Query; import com.hp.hpl.jena.query.QueryExecution; import com.hp.hpl.jena.query.QueryExecutionFactory; import com.hp.hpl.jena.query.QueryFactory; import com.hp.hpl.jena.query.QueryParseException; import com.hp.hpl.jena.query.QuerySolution; import com.hp.hpl.jena.query.ResultSet; import com.hp.hpl.jena.query.Syntax; import com.hp.hpl.jena.rdf.model.Literal; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.sparql.engine.http.QueryExceptionHTTP; import com.hp.hpl.jena.update.GraphStore; import com.hp.hpl.jena.update.GraphStoreFactory; import com.hp.hpl.jena.update.UpdateAction; import com.hp.hpl.jena.update.UpdateExecutionFactory; import com.hp.hpl.jena.update.UpdateFactory; import com.hp.hpl.jena.update.UpdateProcessor; import com.hp.hpl.jena.update.UpdateRequest; import com.hp.hpl.jena.util.iterator.ExtendedIterator; import com.monead.semantic.workbench.images.ImageLibrary; import com.monead.semantic.workbench.queries.QueryHistory; import com.monead.semantic.workbench.queries.QueryInfo; import com.monead.semantic.workbench.queries.SparqlQuery; import com.monead.semantic.workbench.security.StarDogSparqlAuthenticator; import com.monead.semantic.workbench.sparqlservice.SparqlServer; import com.monead.semantic.workbench.tree.IndividualComparator; import com.monead.semantic.workbench.tree.OntClassComparator; import com.monead.semantic.workbench.tree.OntologyTreeCellRenderer; import com.monead.semantic.workbench.tree.StatementComparator; import com.monead.semantic.workbench.tree.Wrapper; import com.monead.semantic.workbench.tree.WrapperClass; import com.monead.semantic.workbench.tree.WrapperDataProperty; import com.monead.semantic.workbench.tree.WrapperInstance; import com.monead.semantic.workbench.tree.WrapperLiteral; import com.monead.semantic.workbench.tree.WrapperObjectProperty; import com.monead.semantic.workbench.utilities.CheckLatestVersion; import com.monead.semantic.workbench.utilities.FileFilterDefinition; import com.monead.semantic.workbench.utilities.FileSource; import com.monead.semantic.workbench.utilities.FontChooser; import com.monead.semantic.workbench.utilities.GuiUtilities; import com.monead.semantic.workbench.utilities.MemoryWarningSystem; import com.monead.semantic.workbench.utilities.NewVersionInformation; import com.monead.semantic.workbench.utilities.ReasonerSelection; import com.monead.semantic.workbench.utilities.SuffixFileFilter; import com.monead.semantic.workbench.utilities.TextProcessing; import com.monead.semantic.workbench.utilities.TextSearch; import com.monead.semantic.workbench.utilities.ValueFormatter; /** * SemanticWorkbench - A GUI to input assertions, work with inferencing engines * and SPARQL queries * * This program uses Jena and Pellet to provide the inference support. * * Copyright (C) 2010-2014 David S. Read * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * For information on Jena: http://jena.sourceforge.net/ For information on * Pellet: http://clarkparsia.com/pellet * * TODO Provide an option: When writing SPARQL results to a file, wrap URIs with * <>, * including data types on literals * * TODO Allow editing of an ontology/model from the tree view (graphical * ontology editor) * * TODO Add unsaved file detection for Assertions and SPARQL queries * * TODO Add a "File New" for assertions to clear hasIncompleteAssertionsInput * * TODO Add a cancel feature for long running tasks * * TODO Alerts for SPARQL service requests that are killed due to timeout * * TODO Encode user id and password in SPARQL query file as encrypted value * using a key entered by the user at startup if they enable that feature * * TODO Remove use of DefaultTreeModel with proprietary model that is backed by * the OntModel directly - hoping this speeds up creating the tree * * TODO Expand tree node option, expands all nodes under the selected node * * TODO Add option for creating a tree of individuals in the tree view * * TODO Log SPARQL response that cannot be parsed (e.g. error or JSON format, * etc) * * @author David Read * */ public class SemanticWorkbench extends JFrame implements Runnable, WindowListener, Observer { /** * The version identifier */ public static final String VERSION = "01.09.15"; /** * Serial UID */ private static final long serialVersionUID = 20140501; /** * The set of formats that can be loaded. These are defined by Jena */ private static final String[] FORMATS = { "N3", "N-Triples", "RDF/XML", "Turtle" }; /** * Tab number for the assertions */ private static final int TAB_NUMBER_ASSERTIONS = 0; /** * Tab number for the inferences */ private static final int TAB_NUMBER_INFERENCES = 1; /** * Tab number for the tree view */ private static final int TAB_NUMBER_TREE_VIEW = 2; /** * Tab number for the SPARQL interactions */ private static final int TAB_NUMBER_SPARQL = 3; /** * Prefix of comment in saved SPARQL query to indicate the service URL used */ private static final String SPARQL_QUERY_SAVE_SERVICE_URL_PARAM = "SERVICE_URL:"; /** * Value to be used as the value for the service URL comment in saved SPARQL * query to indicate that the local model (or service keyword) was used. * This value should not be changed since it is stored in saved SPARQL query * files to indicate the query is to be executed against the local model. */ private static final String SPARQL_QUERY_SAVE_SERVICE_URL_VALUE_FOR_NO_SERVICE_URL = "N/A"; /** * Text used to indicate a setting is not applicable */ private static final String NOT_APPLICABLE_DISPLAY = "N/A"; /** * Default value used for true/false property values set to true */ private static final String DEFAULT_PROPERTY_VALUE_YES = "Yes"; /** * Default value used for true/false property values set to false */ private static final String DEFAULT_PROPERTY_VALUE_NO = "No"; /** * Value to identify a Comma Separated Value export format */ private static final String EXPORT_FORMAT_LABEL_CSV = "CSV"; /** * Value to identify a Tab Separated Value export format */ private static final String EXPORT_FORMAT_LABEL_TSV = "TSV"; /** * Minimum allowed font size */ private static final int MINIMUM_FONT_SIZE = 5; /** * Prefix of the comment in the saved SPARQL query to indicate the default * graph URI used */ private static final String SPARQL_QUERY_SAVE_SERVICE_DEFAULT_GRAPH_PARAM = "DEFAULT_GRAPH_URI:"; /** * Minimum heap that must be available for the tree view to be created. If * this limit is reached while the tree is being build, it will be left in an * incomplete state. */ private static final long MINIMUM_BYTES_REQUIRED_FOR_TREE_BUILD = 10 * 1024 * 1024; /** * Logger Instance */ private static final Logger LOGGER = Logger.getLogger(SemanticWorkbench.class); /** * Standard prefixes * * In N3, N-Triples, RDF/XML and Turtle Order matches that of the FORMAT * array */ private static final String[][] STANDARD_PREFIXES = { // N3 { "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.", "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.", "@prefix owl: <http://www.w3.org/2002/07/owl#>.", "@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.", "@prefix dc: <http://purl.org/dc/elements/1.1/>.", }, // N-triples {}, // RDF/XML { "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"", " xmlns:rdfs=\"http://www.w3.org/2000/01/rdf-schema#\"", " xmlns:owl=\"http://www.w3.org/2002/07/owl#\"", " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema#\"", " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">" }, // Turtle { "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.", "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.", "@prefix owl: <http://www.w3.org/2002/07/owl#>.", "@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.", "@prefix dc: <http://purl.org/dc/elements/1.1/>.", }, // SPARQL { "prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>", "prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>", "prefix owl: <http://www.w3.org/2002/07/owl#>", "prefix xsd: <http://www.w3.org/2001/XMLSchema#>", "prefix dc: <http://purl.org/dc/elements/1.1/>", } }; /** * Service URLS to add in the drop down if none are defined */ private static final String[] DEFAULT_SERVICE_URLS = { "http://semantic.monead.com/vehicleinfo/mileage", "http://dbpedia.org/sparql", "http://lod.openlinksw.com/sparql/", }; /** * Default location for the divider location on the SPARQL tab */ private static final int DEFAULT_SPARQL_QUERY_AND_RESULTS_DIVIDER_LOCATION = 150; /** * Constant used if a value cannot be found in an array */ private static final int UNKNOWN = -1; /** * Maximum number of previous file names to retain */ private static final int MAX_PREVIOUS_FILES_TO_STORE = 10; /** * The prefix for SPARQL results files exported with the direct export option */ private static final String SPARQL_DIRECT_EXPORT_FILE_PREFIX = "Sem_WB_SPARQL_Results_"; /** * Number format for presenting integers in comma-separated form */ private static final NumberFormat INTEGER_COMMA_FORMAT = new DecimalFormat("#,##0"); /** * Normal foreground color for a tab's text */ private static final Color NORMAL_TAB_FG = new Color(51, 51, 51); /** * Normal background color for a tab */ private static final Color NORMAL_TAB_BG = new Color(184, 207, 229); /** * Maximum number of bytes to load into the assertions text area. * If a file is loaded which exceeds this amount, only the first * portion of the file will be loaded. However, the model * will be built using the whole file. * * TODO provide a scrolling window over the entire file */ private static final long MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA = 10 * 1024 * 1024; /** * File name for the properties file */ private static final String PROPERTIES_FILE_NAME = "semantic_workbench.properties"; /** * File name for the history of SPARQL queries */ private static final String SPARQL_QUERY_HISTORY_FILE_NAME = "SWB.SparqlQueryHistory.ser"; /** * URL to overview video */ private static final String OVERVIEW_VIDEO_LOCATION = "http://monead.com/semantic/semantic_workbench/8MinutesWithSemanticWorkbench/"; /** * Configuration properties */ private Properties properties; /** * Classes to be skipped when creating the tree view */ private Map<String, String> classesToSkipInTree; /** * Predicates (properties) to be skipped when creating the tree view */ private Map<String, String> predicatesToSkipInTree; /** * The name (and path if necessary) to the ontology being loaded */ private FileSource rdfFileSource; /** * Status of whether the ontology file has been saved since the last update */ private boolean rdfFileSaved; /** * The RDF file filter description last used by the user */ private String latestChosenRdfFileFilterDescription; /** * The name (and path if necessary) to the SPARQL file being loaded */ private File sparqlQueryFile; /** * Status of whether the SPARQL query file has been saved since the last * update */ private boolean sparqlQuerySaved; /** * The SPARQL file filter description last used by the user */ private String latestChosenSparqlFileFilterDescription; /** * The processed ontology */ private OntModel ontModel; /** * Is proxying enabled */ private boolean proxyEnabled; /** * The proxy server - used if proxying is enabled */ private String proxyServer; /** * The proxy port number - used if proxying is enabled */ private Integer proxyPort; /** * Whether to proxy HTTP requests - used if proxying is enabled */ private boolean proxyProtocolHttp; /** * Whether to proxy SOCKS protocol requests - used if proxying is enabled */ private boolean proxyProtocolSocks; /** * The assertions file menu - retained since the menu items include * the list of recently opened files which changes dynamically */ private JMenu fileAssertionsMenu; /** * File open triples menu item * * Used to load an ontology in to the assertions text area */ private JMenuItem fileOpenTriplesFile; /** * File open triples URL menu item * * Used to load an ontology from a remote source (generally HTTP endpoint) */ private JMenuItem fileOpenTriplesUrl; /** * File open recent triples file menu item * * Created dynamically from the list of recent triples files */ private JMenuItem[] fileOpenRecentTriplesFile; /** * File save triples menu item * * Used to save the asserted triples text to a file */ private JMenuItem fileSaveTriplesToFile; /** * File save model menu item * * Used to serialize the current model to a file */ private JMenuItem fileSaveSerializedModel; /** * End the program */ private JMenuItem fileExit; /** * The SPARQL file menu - retained since the menu items include * the list of recently opened files which changes dynamically */ private JMenu fileSparqlMenu; /** * File open SPARQL menu item * * Used to load a file with a SPARQL query into the SPARQL text area */ private JMenuItem fileOpenSparqlFile; /** * File open recent SPARQL file menu item * * Created dynamically from the list of recent SPARQL query files */ private JMenuItem[] fileOpenRecentSparqlFile; /** * File save SPARQL query menu item * * Used to save the SPARQL query from the SPARQL text area into a file */ private JMenuItem fileSaveSparqlQueryToFile; /** * File save SPARQL results menu item * * Used to save the SPARQL results to a file */ private JMenuItem fileSaveSparqlResultsToFile; /** * Clear the history of SPARQL queries */ private JMenuItem fileClearSparqlHistory; /** * Edit find text menu item * * Used to search for text in the assertions text area */ private JMenuItem editFind; /** * Edit find next text menu item * * Used to continue a search for text in the assertions text area */ private JMenuItem editFindNextMatch; /** * Edit insert prefixes menu item * * Used to insert standard prefixes as a convenience */ private JMenuItem editInsertPrefixes; /** * Toggle the selected SPARQL query lines between commented and not commented */ private JMenuItem editCommentToggle; /** * Expand all the nodes of the tree view of the model */ private JMenuItem editExpandAllTreeNodes; /** * Collapse all the nodes of the tree view of the model */ private JMenuItem editCollapseAllTreeNodes; /** * Edit the list of stored SPARQL service URLs */ private JMenuItem editEditListOfSparqlServiceUrls; /** * Generate list of inferred triples from the model */ private JMenuItem modelListInferredTriples; /** * Generate tree view of model */ private JMenuItem modelCreateTreeView; /** * The format to use when writing the RDF to a file */ private JCheckBoxMenuItem[] setupOutputAssertionLanguage; /** * Write only assertions when outputting the model */ private JCheckBoxMenuItem setupOutputModelTypeAssertions; /** * Write assertions and inferences when outputting the model */ private JCheckBoxMenuItem setupOutputModelTypeAssertionsAndInferences; /** * Allow multiple lines in the SPARQL result display cells */ private JCheckBoxMenuItem setupAllowMultilineResultOutput; /** * Show FQN for namespace instead of prefixes in SPARQL output */ private JCheckBoxMenuItem setupOutputFqnNamespaces; /** * Show data types for literals */ private JCheckBoxMenuItem setupOutputDatatypesForLiterals; /** * Flag literal values */ private JCheckBoxMenuItem setupOutputFlagLiteralValues; /** * Apply formatting rules to literal values */ private JCheckBoxMenuItem setupApplyFormattingToLiteralValues; /** * Display images in SPARQL results */ private JCheckBoxMenuItem setupDisplayImagesInSparqlResults; /** * Export SPARQL results in a Comma Separated Value file */ private JCheckBoxMenuItem setupExportSparqlResultsAsCsv; /** * Export SPARQL results in a Tab Separated Value file */ private JCheckBoxMenuItem setupExportSparqlResultsAsTsv; /** * Should SPARQL output be written directly to file rather than presented in * the results grid */ private JCheckBoxMenuItem setupSparqlResultsToFile; /** * Enable/disable strict mode. (From the Jena documentation: Strict mode means * that converting a common resource to a particular language element, such as * an ontology class, will be subject to some simple syntactic-level checks * for appropriateness.) */ private JCheckBoxMenuItem setupEnableStrictMode; /** * Set the font used for the major interface display widgets */ private JMenuItem setupFont; /** * Enable or disable the use of a proxy for remote SPARQL requests */ private JCheckBoxMenuItem setupProxyEnabled; /** * Setup the proxy configuration */ private JMenuItem setupProxyConfiguration; /** * Set whether the filters for classes and properties are enabled */ private JCheckBoxMenuItem filterEnableFilters; /** * Set whether the FQN for classes and objects are displayed in the tree */ private JCheckBoxMenuItem showFqnInTree; /** * Set whether anonymous classes, individuals and properties are shown in the * tree */ private JCheckBoxMenuItem filterShowAnonymousNodes; /** * Edit the list of currently filtered classes */ private JMenuItem filterEditFilteredClasses; /** * Edit the list of currently filtered properties */ private JMenuItem filterEditFilteredProperties; /** * Reset the tree */ private JMenuItem filterResetTree; /** * Set the maximum number of individuals to display for each class in the tree * view of the model */ private JMenuItem filterSetMaximumIndividualsPerClassInTree; /** * Startup the SPARQL service listener */ private JMenuItem sparqlServerStartup; /** * Shutdown the SPARQL service listener */ private JMenuItem sparqlServerShutdown; /** * Configure the SPARQL service */ private JMenuItem sparqlServerConfig; /** * Replace the model used by the SPARQL service with the current model */ private JMenuItem sparqlServerPublishCurrentModel; /** * View the about dialog */ private JMenuItem helpAbout; /** * View the overview video */ private JMenuItem helpOverviewVideo; /** * Allows selection of the reasoning level */ private JComboBox reasoningLevel; /** * Allows selection of the semantic syntax being used */ private JComboBox language; /** * Display the number of asserted triples in the model */ private JLabel assertedTripleCount; /** * Display the number of inferred triples in the current model */ private JLabel inferredTripleCount; /** * The semantic syntax used for the assertions * * Set when the assertions are loaded into the model */ private String assertionLanguage; /** * Run the inferencing engine */ private JButton runInferencing; /** * Execute the SPARQL query */ private JButton runSparql; /** * Display information about the SPARQL server */ private JLabel sparqlServerInfo; /** * Display information about proxy settings */ private JLabel proxyInfo; /** * The assertions */ private JTextArea assertionsInput; /** * SPARQL input */ private JTextArea sparqlInput; /** * Choose SPARQL service to use */ private JComboBox sparqlServiceUrl; /** * User id for accessing a secured SPARQL service */ private JTextField sparqlServiceUserId; /** * Password for accessing a secured SPARQL service */ private JPasswordField sparqlServicePassword; /** * The default graph URI (optional) */ private JTextField defaultGraphUri; /** * Bring up the next query in the history list */ private JButton nextQuery; /** * Bring up the previous query in the history list */ private JButton previousQuery; /** * SPARQL execution results */ private JTable sparqlResultsTable; /** * Main work area housing the assertions, output and SPARQL text areas */ private JTabbedPane tabbedPane; /** * Status reporting */ private JLabel status; /** * Holding this reference since its state is persisted in the properties file */ private JSplitPane sparqlQueryAndResults; /** * The inferred results from running the inferencing engine */ private JTextArea inferredTriples; /** * The resulting model displayed as a tree */ private JTree ontModelTree; /** * Flag to indicate whether alternate images for the tree view have been * located */ private boolean replaceTreeImages; /** * The last directory where a file was opened or saved */ private File lastDirectoryUsed; /** * Recently opened and saved asserted triples files */ private List<FileSource> recentAssertionsFiles = new ArrayList<FileSource>(); /** * Recently opened and save QPARQL query files */ private List<File> recentSparqlFiles = new ArrayList<File>(); /** * What operation is running on a thread (if any) */ private Operation runningOperation; /** * Flag if the loaded assertions were larger than what is shown in the * assertionsInput text area */ private boolean hasIncompleteAssertionsInput; /** * The file that the model is being written to */ private File modelExportFile; /** * The file that the SPARQL results are being written to */ private File sparqlResultsExportFile; /** * Is the current tree view in synch with the current model */ private boolean isTreeInSyncWithModel; /** * Are the currently displayed inferences in sync with the model */ private boolean areInferencesInSyncWithModel; /** * Are the currently displayed SPARQL query results in sync with the model and * the SPARQL query */ private boolean areSparqlResultsInSyncWithModel; /** * SPARQL query history */ private QueryHistory queryHistory = QueryHistory.getInstance(); /** * Set up the application's UI */ public SemanticWorkbench() { LOGGER.info("Startup"); addWindowListener(this); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); setTitle("Semantic Workbench"); setIcons(); loadProperties(); setupGUI(); processProperties(); queryHistory.retrieveHistory(new File(getUserHomeDirectory(), SPARQL_QUERY_HISTORY_FILE_NAME)); if (queryHistory.getNumberOfQueries() > 0) { processSparqlQueryHistoryMove(0); } enableControls(true); pack(); GuiUtilities.windowSizing(this, properties.getProperty(ConfigurationProperty.LAST_HEIGHT.key()), properties.getProperty(ConfigurationProperty.LAST_WIDTH.key()), properties.getProperty(ConfigurationProperty.LAST_TOP_X_POSITION.key()), properties.getProperty(ConfigurationProperty.LAST_TOP_Y_POSITION.key())); setStatus(""); rdfFileSaved = true; sparqlQuerySaved = true; setVisible(true); checkForNewVersion(); } /** * Check for a new version. The checking class will notify this class if a * newer version is available. */ private void checkForNewVersion() { final CheckLatestVersion versionCheck = new CheckLatestVersion(VERSION); versionCheck.addObserver(this); new Thread(versionCheck).start(); } /** * Sets the available icons for the windowing environment to use when the * program is running */ private void setIcons() { final List<Image> icons = new ArrayList<Image>(); try { icons.add(ImageLibrary.instance().getImageIcon(ImageLibrary.ICON_SEMANTIC_WORKBENCH_32X32).getImage()); icons.add(ImageLibrary.instance().getImageIcon(ImageLibrary.ICON_SEMANTIC_WORKBENCH_16X16).getImage()); setIconImages(icons); } catch (Throwable throwable) { LOGGER.warn("Cannot find application icons in the image library"); } } /** * Load the configuration properties file. */ private void loadProperties() { Reader reader = null; properties = new Properties(); try { reader = new FileReader(getUserHomeDirectory() + "/" + PROPERTIES_FILE_NAME); properties.load(reader); for (Object key : properties.keySet()) { LOGGER.debug("Startup Property [" + key + "] = [" + properties.getProperty(key.toString()) + "]"); } } catch (Throwable throwable) { LOGGER.warn("Unable to read the properties file: " + PROPERTIES_FILE_NAME, throwable); } finally { if (reader != null) { try { reader.close(); } catch (Throwable throwable) { LOGGER.warn("Unable to close the properties file: " + PROPERTIES_FILE_NAME, throwable); } } } } /** * Setup the program's initial state based on the configuration * properties. */ private void processProperties() { String value; lastDirectoryUsed = new File(properties.getProperty(ConfigurationProperty.LAST_DIRECTORY.key(), ".")); LOGGER.debug("Last directory used from properties file: " + lastDirectoryUsed.getAbsolutePath()); value = properties.getProperty(ConfigurationProperty.INPUT_LANGUAGE.key(), "?"); language.setSelectedItem(value); value = properties.getProperty(ConfigurationProperty.REASONING_LEVEL.key(), "-1"); try { final Integer index = Integer.parseInt(value); if (index < 0 || index >= reasoningLevel.getItemCount()) { throw new IllegalArgumentException("Incorrect reasoning level index property value: " + value); } reasoningLevel.setSelectedIndex(index); } catch (Throwable throwable) { LOGGER.warn("Index for reasoner level must be a number from zero to " + (reasoningLevel.getItemCount() - 1)); } reasoningLevel.setToolTipText(((ReasonerSelection) reasoningLevel.getSelectedItem()).description()); value = properties.getProperty(ConfigurationProperty.OUTPUT_FORMAT.key(), "?"); for (JCheckBoxMenuItem outputLanguage : setupOutputAssertionLanguage) { if (outputLanguage.getText().equalsIgnoreCase(value)) { outputLanguage.setSelected(true); } } value = properties.getProperty(ConfigurationProperty.OUTPUT_CONTENT.key(), "?"); if (setupOutputModelTypeAssertionsAndInferences.getText().equalsIgnoreCase(value)) { setupOutputModelTypeAssertionsAndInferences.setSelected(true); } else { setupOutputModelTypeAssertions.setSelected(true); } setupAllowMultilineResultOutput.setSelected( properties.getProperty(ConfigurationProperty.SPARQL_DISPLAY_ALLOW_MULTILINE_OUTPUT.key(), "Y") .toUpperCase().startsWith("Y")); setupOutputFqnNamespaces.setSelected(properties .getProperty(ConfigurationProperty.SHOW_FQN_NAMESPACES.key(), "Y").toUpperCase().startsWith("Y")); setupOutputDatatypesForLiterals .setSelected(properties.getProperty(ConfigurationProperty.SHOW_DATATYPES_ON_LITERALS.key(), "Y") .toUpperCase().startsWith("Y")); setupOutputFlagLiteralValues .setSelected(properties.getProperty(ConfigurationProperty.FLAG_LITERALS_IN_RESULTS.key(), "N") .toUpperCase().startsWith("Y")); setupApplyFormattingToLiteralValues.setSelected( properties.getProperty(ConfigurationProperty.APPLY_FORMATTING_TO_LITERAL_VALUES.key(), "N") .toUpperCase().startsWith("Y")); setupDisplayImagesInSparqlResults.setSelected( properties.getProperty(ConfigurationProperty.SPARQL_DISPLAY_IMAGES_IN_RESULTS.key(), "N") .toUpperCase().startsWith("Y")); // SPARQL query export format - default to CSV if (properties .getProperty(ConfigurationProperty.EXPORT_SPARQL_RESULTS_FORMAT.key(), EXPORT_FORMAT_LABEL_CSV) .equalsIgnoreCase(EXPORT_FORMAT_LABEL_TSV)) { setupExportSparqlResultsAsTsv.setSelected(true); } else { setupExportSparqlResultsAsCsv.setSelected(true); } setupSparqlResultsToFile .setSelected(properties.getProperty(ConfigurationProperty.SPARQL_RESULTS_TO_FILE.key(), "N") .toUpperCase().startsWith("Y")); value = properties.getProperty(ConfigurationProperty.SPARQL_SERVICE_USER_ID.key()); if (value != null) { sparqlServiceUserId.setText(value); } value = properties.getProperty(ConfigurationProperty.SPARQL_DEFAULT_GRAPH_URI.key()); if (value != null) { defaultGraphUri.setText(value); } setupEnableStrictMode.setSelected(properties .getProperty(ConfigurationProperty.ENABLE_STRICT_MODE.key(), "Y").toUpperCase().startsWith("Y")); filterEnableFilters .setSelected(properties.getProperty(ConfigurationProperty.ENFORCE_FILTERS_IN_TREE_VIEW.key(), "Y") .toUpperCase().startsWith("Y")); showFqnInTree.setSelected(properties.getProperty(ConfigurationProperty.DISPLAY_FQN_IN_TREE_VIEW.key(), "Y") .toUpperCase().startsWith("Y")); filterShowAnonymousNodes.setSelected( properties.getProperty(ConfigurationProperty.DISPLAY_ANONYMOUS_NODES_IN_TREE_VIEW.key(), "N") .toUpperCase().startsWith("Y")); setFont(getFontFromProperties(), getColorFromProperties()); extractSkipObjectsFromProperties(); extractRecentAssertedTriplesFilesFromProperties(); extractRecentSparqlQueryFilesFromProperties(); // SPARQL Split Pane Position value = properties.getProperty(ConfigurationProperty.SPARQL_SPLIT_PANE_POSITION.key()); if (value != null) { try { final int position = Integer.parseInt(value); if (position > 0) { sparqlQueryAndResults.setDividerLocation(position); } } catch (Throwable throwable) { LOGGER.warn("Cannot use the SPARQL split pane divider location value: " + value, throwable); } } // Sparql server port value = properties.getProperty(ConfigurationProperty.SPARQL_SERVER_PORT.key()); if (value != null) { try { final Integer port = Integer.parseInt(value); if (port > 0) { SparqlServer.getInstance().setListenerPort(port); } else { LOGGER.warn("Configured port for SPARQL Server must be greater than zero. Was set to " + port); } } catch (Throwable throwable) { LOGGER.warn("Configured port for SPARQL Server must be a number greater than zero. Was set to " + value); } } // SPARQL server max runtime value = properties.getProperty(ConfigurationProperty.SPARQL_SERVER_MAX_RUNTIME.key()); if (value != null) { try { final Integer maxRuntimeSeconds = Integer.parseInt(value); if (maxRuntimeSeconds > 0) { SparqlServer.getInstance().setMaxRuntimeSeconds(maxRuntimeSeconds); } else { LOGGER.warn( "Configured maximum runtime for the SPARQL Server must be greater than zero seconds. Was set to " + maxRuntimeSeconds); } } catch (Throwable throwable) { LOGGER.warn( "Configured maximum runtime for the SPARQL Server must be a number greater than zero. Was set to " + value); } } // SPARQL server remote updates permitted SparqlServer.getInstance().setRemoteUpdatesPermitted( properties.getProperty(ConfigurationProperty.SPARQL_SERVER_ALLOW_REMOTE_UPDATE.key(), "N") .toUpperCase().startsWith("Y")); // Proxy proxyServer = properties.getProperty(ConfigurationProperty.PROXY_SERVER.key()); value = properties.getProperty(ConfigurationProperty.PROXY_PORT.key()); if (value != null) { try { proxyPort = Integer.parseInt(value); } catch (Throwable throwable) { LOGGER.warn("Illegal proxy port number in the properties file: " + value); } } proxyProtocolHttp = properties.getProperty(ConfigurationProperty.PROXY_HTTP.key(), "N").toUpperCase() .startsWith("Y"); proxyProtocolSocks = properties.getProperty(ConfigurationProperty.PROXY_SOCKS.key(), "N").toUpperCase() .startsWith("Y"); proxyEnabled = properties.getProperty(ConfigurationProperty.PROXY_ENABLED.key(), "N").toUpperCase() .startsWith("Y"); setupProxy(); populateSparqlServiceUrls(); extractXsdFormatsFromProperties(); } /** * Populate the drop down of SPARQL service URLs from the * properties file. If none are found, populate with a * default list. */ private void populateSparqlServiceUrls() { final List<String> prefixNames = new ArrayList<String>(); boolean foundUrl; int lastSelectedIndex; /** * Find any keys for previous files */ for (Object key : properties.keySet()) { if (key.toString().startsWith(ConfigurationProperty.PREFIX_SPARQL_SERVICE_URL.key())) { prefixNames.add(key.toString()); } } // Want the files in order so the drop down is consistent from run to run // Also, the last selected index is used to select the last selected service Collections.sort(prefixNames); // This must be the first option - use the local model sparqlServiceUrl.addItem("Local Model, FROM or SERVICE Clause"); // Detect if at least one service URL is found in the properties file foundUrl = false; for (String key : prefixNames) { sparqlServiceUrl.addItem(properties.get(key)); foundUrl = true; } // If there are no service URLs defined, setup some defaults if (!foundUrl) { for (String url : DEFAULT_SERVICE_URLS) { sparqlServiceUrl.addItem(url); } } // If the last selected index value is legal, set the service selection to // that option try { lastSelectedIndex = Integer .parseInt(properties.getProperty(ConfigurationProperty.SELECTED_SPARQL_SERVICE_URL.key(), "0")); if (lastSelectedIndex < 0 || lastSelectedIndex >= sparqlServiceUrl.getItemCount()) { throw new IllegalArgumentException("SPARQL Service URL index in properties file out of range (0-" + sparqlServiceUrl.getItemCount() + "): " + lastSelectedIndex); } } catch (Throwable throwable) { LOGGER.warn("Illegal value for the last SPARQL service URL selection index", throwable); lastSelectedIndex = 0; } sparqlServiceUrl.setSelectedIndex(lastSelectedIndex); } /** * Obtain the list of recently opened or saved assertions * files to update the assertions file menu. */ private void extractRecentAssertedTriplesFilesFromProperties() { final List<String> prefixNames = new ArrayList<String>(); String value; String[] parsed; /** * Find any keys for previous files */ for (Object key : properties.keySet()) { if (key.toString().startsWith(ConfigurationProperty.PREFIX_RECENT_ASSERTIONS_FILE.key())) { prefixNames.add(key.toString()); } } // Want the files in order from most recent Collections.sort(prefixNames); // Only keep up to MAX_PREVIOUS_FILES_TO_STORE values for (int index = 0; index < MAX_PREVIOUS_FILES_TO_STORE && index < prefixNames.size(); index++) { value = properties.getProperty(prefixNames.get(index)); LOGGER.debug("Got previous filename: [" + value + "]"); try { if (value.startsWith("URL:")) { parsed = value.split(":", 2); recentAssertionsFiles.add(new FileSource(new URL(parsed[1]))); } else if (value.startsWith("FILE:")) { parsed = value.split(":", 2); recentAssertionsFiles.add(new FileSource(new File(parsed[1]))); } else { // Take a guess at what it is, File path or URL if (value.indexOf(':') > -1) { // Assume it is URL since it has a colon recentAssertionsFiles.add(new FileSource(new URL(value))); } else { recentAssertionsFiles.add(new FileSource(new File(value))); } } } catch (Throwable throwable) { LOGGER.warn("Unable to parse the File or URL from the properties file: " + value, throwable); } } setupAssertionsFileMenu(); } /** * Obtain the list of recently opened or saved SPARQL * files to update the SPARQL file menu. */ private void extractRecentSparqlQueryFilesFromProperties() { final List<String> prefixNames = new ArrayList<String>(); /** * Find any keys for previous files */ for (Object key : properties.keySet()) { if (key.toString().startsWith(ConfigurationProperty.PREFIX_RECENT_SPARQL_QUERY_FILE.key())) { prefixNames.add(key.toString()); } } // Want the files in order from most recent Collections.sort(prefixNames); // Only keep up to MAX_PREVIOUS_FILES_TO_STORE values for (int index = 0; index < MAX_PREVIOUS_FILES_TO_STORE && index < prefixNames.size(); index++) { recentSparqlFiles.add(new File(properties.getProperty(prefixNames.get(index)))); } setupSparqlFileMenu(); } /** * Add a file to the collection of recent asserted triples files * * @param file * The file to be added to the collection */ private void addRecentAssertedTriplesFile(FileSource file) { int matchAt; matchAt = recentAssertionsFiles.indexOf(file); if (matchAt == -1) { recentAssertionsFiles.add(0, file); } else if (matchAt > 0) { recentAssertionsFiles.remove(matchAt); recentAssertionsFiles.add(0, file); } // Assure only MAX_PREVIOUS_FILES_TO_STORE entries are stored while (recentAssertionsFiles.size() > MAX_PREVIOUS_FILES_TO_STORE) { recentAssertionsFiles.remove(recentAssertionsFiles.size() - 1); } setupAssertionsFileMenu(); } /** * Add a file to the collection of recent SPARQL query files * * @param file * The file to be added to the collection */ private void addRecentSparqlFile(File file) { int matchAt; matchAt = recentSparqlFiles.indexOf(file); if (matchAt == -1) { recentSparqlFiles.add(0, file); } else if (matchAt > 0) { recentSparqlFiles.remove(matchAt); recentSparqlFiles.add(0, file); } // Assure only MAX_PREVIOUS_FILES_TO_STORE entries are stored while (recentSparqlFiles.size() > MAX_PREVIOUS_FILES_TO_STORE) { recentSparqlFiles.remove(recentSparqlFiles.size() - 1); } setupSparqlFileMenu(); } /** * Get the property names to be skipped from the configuration properties * file. */ private void extractSkipObjectsFromProperties() { classesToSkipInTree = new HashMap<String, String>(); predicatesToSkipInTree = new HashMap<String, String>(); for (Object key : properties.keySet()) { if (key.toString().startsWith(ConfigurationProperty.PREFIX_SKIP_CLASS.key())) { classesToSkipInTree.put(properties.getProperty(key.toString()), ""); } else if (key.toString().startsWith(ConfigurationProperty.PREFIX_SKIP_PREDICATE.key())) { predicatesToSkipInTree.put(properties.getProperty(key.toString()), ""); } } } /** * Get the XSD and format mapping from the properties files. These * formats are used to display data that matches the supplied XSD type. */ private void extractXsdFormatsFromProperties() { boolean foundXsdFormat = false; for (Object key : properties.keySet()) { if (key.toString().startsWith(ConfigurationProperty.PREFIX_NUMERIC_DATA_XSD_FORMAT_MAPPING.key())) { ValueFormatter.setFormat( key.toString().substring( ConfigurationProperty.PREFIX_NUMERIC_DATA_XSD_FORMAT_MAPPING.key().length()), properties.getProperty(key.toString())); foundXsdFormat = true; } } if (!foundXsdFormat) { ValueFormatter.setFormat("decimal", "#,##0"); ValueFormatter.setFormat("double", "#,##0.0##"); properties.put(ConfigurationProperty.PREFIX_NUMERIC_DATA_XSD_FORMAT_MAPPING.key() + "decimal", "#,##0"); properties.put(ConfigurationProperty.PREFIX_NUMERIC_DATA_XSD_FORMAT_MAPPING.key() + "double", "#,##0.0##"); } } /** * Add a class or property to be filtered from the tree view when it is * created * * @param wrapper * An instance of a wrapper for an ontology class or property */ private void addToFilter(Wrapper wrapper) { if (wrapper instanceof WrapperClass) { classesToSkipInTree.put(wrapper.getUri(), ""); LOGGER.debug("Added class to skip in tree view: " + wrapper.getUri()); } else if (wrapper instanceof WrapperDataProperty || wrapper instanceof WrapperObjectProperty) { LOGGER.debug("Added property to skip in tree view: " + wrapper.getUri()); predicatesToSkipInTree.put(wrapper.getUri(), ""); } } /** * Setup the list of stored SPARQL service URLs from the dropdown into a map * and use the editFilterMap method to allow the user to remove unwanted * entries */ private void editListOfSparqlServiceUrls() { final Map<String, String> urls = new HashMap<String, String>(); int sizeBefore; int currentSelectedIndex; for (int index = 1; index < sparqlServiceUrl.getItemCount(); ++index) { urls.put(sparqlServiceUrl.getItemAt(index).toString(), ""); } sizeBefore = urls.size(); editFilterMap(urls); // If one or more values were removed, rebuild dropdown if (urls.size() != sizeBefore) { currentSelectedIndex = sparqlServiceUrl.getSelectedIndex(); // Figure out what was removed for (int index = 1; index < sparqlServiceUrl.getItemCount(); ++index) { if (urls.get(sparqlServiceUrl.getItemAt(index)) == null) { // Item was removed - remove from dropdown sparqlServiceUrl.removeItemAt(index); // If the currentSelection was this one, make the current Selection 0 if (currentSelectedIndex == index) { currentSelectedIndex = 0; } else if (currentSelectedIndex > index) { // If the current selection is after this deleted one // then it has moved up one position currentSelectedIndex--; } // Since an item was removed, back up one position so the next // iteration doesn't skip the new value in this position --index; } } // Select the proper item (either the previous one selected or the default // if the previously selected one was deleted sparqlServiceUrl.setSelectedIndex(currentSelectedIndex); } enableControls(true); } /** * Edit the list of filters. * * @param filterMap * The map whose entries are being edited */ private void editFilterMap(Map<String, String> filterMap) { final List<String> filteredItems = new ArrayList<String>(filterMap.keySet()); int[] selectedIndices; Collections.sort(filteredItems); final JList jListOfItems = new JList(filteredItems.toArray(new String[filteredItems.size()])); JOptionPane.showMessageDialog(this, jListOfItems, "Select Items to Remove", JOptionPane.QUESTION_MESSAGE); selectedIndices = jListOfItems.getSelectedIndices(); if (selectedIndices.length > 0) { LOGGER.debug( "Items to remove from the filter map: " + Arrays.toString(jListOfItems.getSelectedValues())); LOGGER.trace("Filtered list size before removal: " + filteredItems.size()); for (int index = 0; index < selectedIndices.length; ++index) { LOGGER.trace("Remove filtered item: " + filteredItems.get(selectedIndices[index])); filterMap.remove(filteredItems.get(selectedIndices[index])); } LOGGER.trace("Filtered list size after removal: " + filteredItems.size()); } else { LOGGER.debug("No items removed from filter map"); } } /** * Save the current program configuration to the properties file. */ private void saveProperties() { Writer writer = null; // Remove the recent asserted triples files entries. // They will be recreated from the new list removePrefixedProperties(ConfigurationProperty.PREFIX_RECENT_ASSERTIONS_FILE.key()); // Remove the recent SPARQL query files entries. // They will be recreated from the new list removePrefixedProperties(ConfigurationProperty.PREFIX_RECENT_SPARQL_QUERY_FILE.key()); // Remove the set of SPARQL service URL entries. // They will be recreated from the dropdown removePrefixedProperties(ConfigurationProperty.PREFIX_SPARQL_SERVICE_URL.key()); updatePropertiesWithClassesToSkipInTree(); updatePropertiesWithPredicatesToSkipInTree(); updatePropertiesWithServiceUrls(); // Add the set of recent asserted triples files for (int index = 0; index < MAX_PREVIOUS_FILES_TO_STORE && index < recentAssertionsFiles.size(); ++index) { properties.put(ConfigurationProperty.PREFIX_RECENT_ASSERTIONS_FILE.key() + index, (recentAssertionsFiles.get(index).isFile() ? "FILE:" : "URL:") + recentAssertionsFiles.get(index).getAbsolutePath()); } // Add the set of recent SPARQL query files for (int index = 0; index < MAX_PREVIOUS_FILES_TO_STORE && index < recentSparqlFiles.size(); ++index) { properties.put(ConfigurationProperty.PREFIX_RECENT_SPARQL_QUERY_FILE.key() + index, recentSparqlFiles.get(index).getAbsolutePath()); } properties.setProperty(ConfigurationProperty.LAST_HEIGHT.key(), this.getSize().height + ""); properties.setProperty(ConfigurationProperty.LAST_WIDTH.key(), this.getSize().width + ""); properties.setProperty(ConfigurationProperty.LAST_TOP_X_POSITION.key(), this.getLocation().x + ""); properties.setProperty(ConfigurationProperty.LAST_TOP_Y_POSITION.key(), this.getLocation().y + ""); // Only store the divider position if it is not at an extreme setting (e.g. // both the query and results panels are visible) if (sparqlQueryAndResults.getDividerLocation() > 1 && sparqlQueryAndResults.getHeight() - (sparqlQueryAndResults.getDividerLocation() + sparqlQueryAndResults.getDividerSize()) > 1) { properties.setProperty(ConfigurationProperty.SPARQL_SPLIT_PANE_POSITION.key(), sparqlQueryAndResults.getDividerLocation() + ""); } else { LOGGER.debug("SPARQL split pane position not being stored - Size:" + sparqlQueryAndResults.getHeight() + " DividerLoc:" + sparqlQueryAndResults.getDividerLocation() + " DividerSize:" + sparqlQueryAndResults.getDividerSize()); properties.remove(ConfigurationProperty.SPARQL_SPLIT_PANE_POSITION.key()); } properties.setProperty(ConfigurationProperty.LAST_DIRECTORY.key(), lastDirectoryUsed.getAbsolutePath()); properties.setProperty(ConfigurationProperty.INPUT_LANGUAGE.key(), language.getSelectedItem().toString()); properties.setProperty(ConfigurationProperty.REASONING_LEVEL.key(), reasoningLevel.getSelectedIndex() + ""); for (JCheckBoxMenuItem outputLanguage : setupOutputAssertionLanguage) { if (outputLanguage.isSelected()) { properties.setProperty(ConfigurationProperty.OUTPUT_FORMAT.key(), outputLanguage.getText()); } } if (setupOutputModelTypeAssertionsAndInferences.isSelected()) { properties.setProperty(ConfigurationProperty.OUTPUT_CONTENT.key(), setupOutputModelTypeAssertionsAndInferences.getText()); } else { properties.setProperty(ConfigurationProperty.OUTPUT_CONTENT.key(), setupOutputModelTypeAssertions.getText()); } properties.setProperty(ConfigurationProperty.SPARQL_DISPLAY_ALLOW_MULTILINE_OUTPUT.key(), setupAllowMultilineResultOutput.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.SHOW_FQN_NAMESPACES.key(), setupOutputFqnNamespaces.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.SHOW_DATATYPES_ON_LITERALS.key(), setupOutputDatatypesForLiterals.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.FLAG_LITERALS_IN_RESULTS.key(), setupOutputFlagLiteralValues.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.APPLY_FORMATTING_TO_LITERAL_VALUES.key(), setupApplyFormattingToLiteralValues.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.SPARQL_DISPLAY_IMAGES_IN_RESULTS.key(), setupDisplayImagesInSparqlResults.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); if (setupExportSparqlResultsAsTsv.isSelected()) { properties.setProperty(ConfigurationProperty.EXPORT_SPARQL_RESULTS_FORMAT.key(), EXPORT_FORMAT_LABEL_TSV); } else { properties.setProperty(ConfigurationProperty.EXPORT_SPARQL_RESULTS_FORMAT.key(), EXPORT_FORMAT_LABEL_CSV); } properties.setProperty(ConfigurationProperty.SPARQL_RESULTS_TO_FILE.key(), setupSparqlResultsToFile.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); if (sparqlServiceUserId.getText().trim().length() > 0) { properties.setProperty(ConfigurationProperty.SPARQL_SERVICE_USER_ID.key(), sparqlServiceUserId.getText().trim()); } else { properties.remove(ConfigurationProperty.SPARQL_SERVICE_USER_ID.key()); } if (defaultGraphUri.getText().trim().length() > 0) { properties.setProperty(ConfigurationProperty.SPARQL_DEFAULT_GRAPH_URI.key(), defaultGraphUri.getText().trim()); } else { properties.remove(ConfigurationProperty.SPARQL_DEFAULT_GRAPH_URI.key()); } properties.setProperty(ConfigurationProperty.ENABLE_STRICT_MODE.key(), setupEnableStrictMode.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.ENFORCE_FILTERS_IN_TREE_VIEW.key(), filterEnableFilters.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.DISPLAY_FQN_IN_TREE_VIEW.key(), showFqnInTree.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.DISPLAY_ANONYMOUS_NODES_IN_TREE_VIEW.key(), filterShowAnonymousNodes.isSelected() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.SPARQL_SERVER_PORT.key(), SparqlServer.getInstance().getListenerPort() + ""); properties.setProperty(ConfigurationProperty.SPARQL_SERVER_MAX_RUNTIME.key(), SparqlServer.getInstance().getMaxRuntimeSeconds() + ""); properties.setProperty(ConfigurationProperty.SPARQL_SERVER_ALLOW_REMOTE_UPDATE.key(), SparqlServer.getInstance().areRemoteUpdatesPermitted() ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.PROXY_ENABLED.key(), proxyEnabled ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); if (proxyServer != null) { properties.setProperty(ConfigurationProperty.PROXY_SERVER.key(), proxyServer); } else { properties.remove(ConfigurationProperty.PROXY_SERVER.key()); } if (proxyPort != null) { properties.setProperty(ConfigurationProperty.PROXY_PORT.key(), proxyPort + ""); } else { properties.remove(ConfigurationProperty.PROXY_PORT.key()); } properties.setProperty(ConfigurationProperty.PROXY_HTTP.key(), proxyProtocolHttp ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); properties.setProperty(ConfigurationProperty.PROXY_SOCKS.key(), proxyProtocolSocks ? DEFAULT_PROPERTY_VALUE_YES : DEFAULT_PROPERTY_VALUE_NO); try { writer = new FileWriter(getUserHomeDirectory() + "/" + PROPERTIES_FILE_NAME, false); properties.store(writer, "Generated by Semantic Workbench version " + VERSION + " on " + new Date()); } catch (Throwable throwable) { LOGGER.warn("Unable to write the properties file: " + PROPERTIES_FILE_NAME, throwable); } finally { if (writer != null) { try { writer.close(); } catch (Throwable throwable) { LOGGER.warn("Unable to close the properties file: " + PROPERTIES_FILE_NAME, throwable); } } } } /** * Save the set of SPARQL Service URLs. */ private void updatePropertiesWithServiceUrls() { // Start at 1 - skip the default "hardcoded" model entry for (int index = 1; index < sparqlServiceUrl.getItemCount(); ++index) { properties.setProperty(ConfigurationProperty.PREFIX_SPARQL_SERVICE_URL.key() + index, sparqlServiceUrl.getItemAt(index).toString()); } properties.setProperty(ConfigurationProperty.SELECTED_SPARQL_SERVICE_URL.key(), sparqlServiceUrl.getSelectedIndex() + ""); } /** * Remove all the properties in the properties collection that begin with the * supplied property key prefix. * * @param prefix * The property prefix for entries to be removed */ private void removePrefixedProperties(String prefix) { final List<String> propertiesToBeRemoved = new ArrayList<String>(); for (Object key : properties.keySet()) { if (key.toString().startsWith(prefix)) { propertiesToBeRemoved.add(key.toString()); } } for (String propertyToRemove : propertiesToBeRemoved) { properties.remove(propertyToRemove); } } /** * Add the classes to be skipped to the configuration properties. */ private void updatePropertiesWithClassesToSkipInTree() { int classNumber = 0; // Remove the existing class entries. They will be recreated from the new // list removePrefixedProperties(ConfigurationProperty.PREFIX_SKIP_CLASS.key()); for (String classToSkipInTree : classesToSkipInTree.keySet()) { ++classNumber; properties.put(ConfigurationProperty.PREFIX_SKIP_CLASS.key() + classNumber, classToSkipInTree); classesToSkipInTree.put(classToSkipInTree, ""); } } /** * Add the predicates (properties) to be skipped to the configuration * properties. */ private void updatePropertiesWithPredicatesToSkipInTree() { int propNumber = 0; // Remove the existing predicate entries. They will be recreated from the // new list for (String predicateToSkipInTree : predicatesToSkipInTree.keySet()) { ++propNumber; properties.put(ConfigurationProperty.PREFIX_SKIP_PREDICATE.key() + propNumber, predicateToSkipInTree); predicatesToSkipInTree.put(predicateToSkipInTree, ""); } } /** * Get the path to the user's home directory * * @return The user's home directory */ private String getUserHomeDirectory() { String home = System.getProperty("user.home"); if (home == null || home.trim().length() == 0) { home = "."; } else { home += "/SemanticWorkbench"; final File homeFile = new File(home); if (!homeFile.exists()) { homeFile.mkdirs(); } } return home; } /** * Place the components in the JFrame */ private void setupGUI() { JPanel panel; LOGGER.debug("SetupGUI"); setupControls(); setupMenus(); getContentPane().setLayout(new BorderLayout()); panel = new JPanel(); panel.setLayout(new BorderLayout()); getContentPane().add(panel, BorderLayout.CENTER); tabbedPane = new JTabbedPane(); // Assertions tabbedPane.add("Assertions", setupAssertionsPanel()); // Inferences tabbedPane.add("Inferences", setupInferencesPanel()); // Tree view tabbedPane.add("Tree View", setupTreePanel()); // SPARQL tabbedPane.add("SPARQL", setupSparqlPanel()); // Detect tab selections tabbedPane.addChangeListener(new TabbedPaneChangeListener()); // Add the tabbed pane to the main window panel.add(tabbedPane, BorderLayout.CENTER); // Status label, bottom of window panel.add(setupStatusPanel(), BorderLayout.SOUTH); } /** * Present the user with a font selection dialog and update the widgets if * the user chooses a font. */ private void configureFont() { FontChooser chooser; Font newFont; Color newColor; chooser = new FontChooser(this); chooser.setFont(getFontFromProperties()); chooser.setColor(getColorFromProperties()); LOGGER.debug("Font before choices: " + chooser.getNewFont()); chooser.setVisible(true); newFont = chooser.getNewFont(); newColor = chooser.getNewColor(); // Values will be null if user canceled request if (newFont != null && newColor != null) { properties.setProperty(ConfigurationProperty.FONT_NAME.key(), newFont.getName()); properties.setProperty(ConfigurationProperty.FONT_SIZE.key(), newFont.getSize() + ""); properties.setProperty(ConfigurationProperty.FONT_STYLE.key(), newFont.getStyle() + ""); properties.setProperty(ConfigurationProperty.FONT_COLOR.key(), newColor.getRGB() + ""); LOGGER.debug("Font after choices: " + newFont); setFont(newFont, newColor); } } /** * Get the font information from the configuration properties. * * @return A Font instance based on the configuration */ private Font getFontFromProperties() { Font newFont = null; final String fontName = properties.getProperty(ConfigurationProperty.FONT_NAME.key(), "Courier"); final String fontSize = properties.getProperty(ConfigurationProperty.FONT_SIZE.key(), "12"); final String fontStyle = properties.getProperty(ConfigurationProperty.FONT_STYLE.key(), "0"); try { newFont = new Font(fontName, Integer.parseInt(fontStyle), Integer.parseInt(fontSize)); if (newFont.getSize() < MINIMUM_FONT_SIZE) { throw new IllegalArgumentException("Font size too small: " + newFont.getSize()); } } catch (Throwable throwable) { LOGGER.warn("Cannot setup font from properties (" + fontName + "," + fontSize + "," + fontStyle + ")", throwable); } return newFont; } /** * Get the font color information from the configuration properties. * * @return A Color instance based on the properties */ private Color getColorFromProperties() { Color newColor = null; final String colorRgb = properties.getProperty(ConfigurationProperty.FONT_COLOR.key(), Color.BLACK.getRGB() + ""); try { newColor = new Color(Integer.parseInt(colorRgb), true); } catch (Throwable throwable) { LOGGER.warn("Cannot setup font color from property (" + colorRgb + ")", throwable); } return newColor; } /** * Set the font and foreground color used by the widgets. * * @param newFont * The Font for widgets to use. May be null, in which case it is * ignored. * @param newColor * The foreground color for widgets to use. May be null, in which * case it is ignored. */ private void setFont(Font newFont, Color newColor) { if (newFont != null) { assertionsInput.setFont(newFont); inferredTriples.setFont(newFont); sparqlInput.setFont(newFont); ontModelTree.setFont(newFont); sparqlResultsTable.setFont(newFont); sparqlResultsTable.getTableHeader().setFont(newFont); final SparqlResultItemRenderer renderer = new SparqlResultItemRenderer( setupAllowMultilineResultOutput.isSelected()); renderer.setFont(newFont); sparqlResultsTable.setDefaultRenderer(SparqlResultItem.class, renderer); ((AbstractTableModel) sparqlResultsTable.getModel()).fireTableStructureChanged(); status.setFont(newFont); } if (newColor != null) { assertionsInput.setForeground(newColor); inferredTriples.setForeground(newColor); sparqlInput.setForeground(newColor); ontModelTree.setForeground(newColor); ((DefaultTreeCellRenderer) ontModelTree.getCellRenderer()).setTextNonSelectionColor(newColor); sparqlResultsTable.setForeground(newColor); sparqlResultsTable.getTableHeader().setForeground(newColor); status.setForeground(newColor); } } /** * Create the assertions panel * * @return The assertions JPanel */ private JPanel setupAssertionsPanel() { JPanel assertionPanel; JPanel gridPanel; JPanel flowPanel; assertionPanel = new JPanel(); assertionPanel.setLayout(new BorderLayout()); // Top of panel will allow for configuration of // inferencing environment gridPanel = new JPanel(); gridPanel.setLayout(new GridLayout(0, 3)); // First Row // Create Model Button flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(runInferencing); gridPanel.add(flowPanel); // Model/Reasoner Choice flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("Model/Reasoning:")); flowPanel.add(reasoningLevel); gridPanel.add(flowPanel); // Number of asserted triples flowPanel = new JPanel(); flowPanel.setLayout(new GridLayout(1, 1)); flowPanel.add(assertedTripleCount); flowPanel.setBorder(BorderFactory.createTitledBorder("Asserted Triples")); gridPanel.add(flowPanel); // Second Row // Empty cell gridPanel.add(new JLabel()); // Language drop-down flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("Language:")); flowPanel.add(language); gridPanel.add(flowPanel); // Number of inferred triples flowPanel = new JPanel(); flowPanel.setLayout(new GridLayout(1, 1)); flowPanel.add(inferredTripleCount); flowPanel.setBorder(BorderFactory.createTitledBorder("Inferred Triples")); gridPanel.add(flowPanel); assertionPanel.add(gridPanel, BorderLayout.NORTH); gridPanel = new JPanel(); gridPanel.setLayout(new GridLayout(1, 1)); gridPanel.setBorder(BorderFactory.createTitledBorder("Assertions")); gridPanel.add(new JScrollPane(assertionsInput)); assertionPanel.add(gridPanel, BorderLayout.CENTER); return assertionPanel; } /** * Setup the inferences panel * * @return The inferences JPanel */ private JPanel setupInferencesPanel() { JPanel inferencesPanel; // output inferencesPanel = new JPanel(); inferencesPanel.setLayout(new GridLayout(1, 1)); inferencesPanel.add(new JScrollPane(inferredTriples)); return inferencesPanel; } /** * Setup the model tree display panel * * @return The model tree JPanel */ private JPanel setupTreePanel() { JPanel treePanel; treePanel = new JPanel(); treePanel.setLayout(new GridLayout(1, 1)); treePanel.add(new JScrollPane(ontModelTree)); return treePanel; } /** * Setup the SPARQL panel * * @return The SPARQL JPanel */ private JPanel setupSparqlPanel() { JPanel sparqlPanel; JPanel labelPanel; JPanel gridPanel; JPanel innerGridPanel; JPanel flowPanel; JPanel queryPanel; JPanel resultsPanel; JPanel controlGrid; sparqlPanel = new JPanel(); sparqlPanel.setLayout(new BorderLayout()); // Controls labelPanel = new JPanel(); labelPanel.setLayout(new BorderLayout()); gridPanel = new JPanel(); gridPanel.setLayout(new GridLayout(0, 1)); innerGridPanel = new JPanel(); innerGridPanel.setLayout(new GridLayout(1, 3)); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(runSparql); innerGridPanel.add(flowPanel); innerGridPanel.add(sparqlServerInfo); innerGridPanel.add(proxyInfo); gridPanel.add(innerGridPanel); innerGridPanel = new JPanel(); innerGridPanel.setLayout(new GridLayout(1, 2)); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("Service: ")); flowPanel.add(sparqlServiceUrl); innerGridPanel.add(flowPanel); controlGrid = new JPanel(); controlGrid.setLayout(new GridLayout(1, 2)); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("User Id:")); flowPanel.add(sparqlServiceUserId); controlGrid.add(flowPanel); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("Password:")); flowPanel.add(sparqlServicePassword); controlGrid.add(flowPanel); innerGridPanel.add(controlGrid); gridPanel.add(innerGridPanel); innerGridPanel = new JPanel(); innerGridPanel.setLayout(new GridLayout(1, 2)); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(new JLabel("Default Graph URI: ")); flowPanel.add(defaultGraphUri); innerGridPanel.add(flowPanel); flowPanel = new JPanel(); flowPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); flowPanel.add(previousQuery); flowPanel.add(nextQuery); innerGridPanel.add(flowPanel); gridPanel.add(innerGridPanel); sparqlPanel.add(gridPanel, BorderLayout.NORTH); // SPARQL query queryPanel = new JPanel(); queryPanel.setLayout(new GridLayout(1, 1)); queryPanel.setBorder(BorderFactory.createTitledBorder("Query")); queryPanel.add(new JScrollPane(sparqlInput)); // SPARQL results resultsPanel = new JPanel(); resultsPanel.setLayout(new GridLayout(1, 1)); resultsPanel.setBorder(BorderFactory.createTitledBorder("Results")); resultsPanel.add(new JScrollPane(sparqlResultsTable)); // Query and Results Split Pane sparqlQueryAndResults = new JSplitPane(JSplitPane.VERTICAL_SPLIT, queryPanel, resultsPanel); sparqlQueryAndResults.setDividerLocation(DEFAULT_SPARQL_QUERY_AND_RESULTS_DIVIDER_LOCATION); sparqlQueryAndResults.setOneTouchExpandable(true); sparqlPanel.add(sparqlQueryAndResults, BorderLayout.CENTER); return sparqlPanel; } /** * Setup the status panel * * @return The status JPanel */ private JPanel setupStatusPanel() { JPanel statusPanel; statusPanel = new JPanel(); statusPanel.setLayout(new GridLayout(1, 1)); statusPanel .setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "Status")); statusPanel.add(makeFlowPanel(status, FlowLayout.LEFT)); return statusPanel; } /** * Configures the assertions file menu. Called at startup * and whenever an assertions file is opened or saved since * the list of recent assertions files is presented on the * file menu. */ private void setupAssertionsFileMenu() { fileAssertionsMenu.removeAll(); fileOpenTriplesFile = new JMenuItem("Open Assertions File"); fileOpenTriplesFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_MASK)); fileOpenTriplesFile.setMnemonic('A'); fileOpenTriplesFile.setToolTipText("Open an asserted triples file"); fileOpenTriplesFile.addActionListener(new FileAssertedTriplesOpenListener()); fileAssertionsMenu.add(fileOpenTriplesFile); fileOpenTriplesUrl = new JMenuItem("Open Assertions Url"); fileOpenTriplesUrl.setMnemonic('U'); fileOpenTriplesUrl.setToolTipText("Access asserted triples from a URL"); fileOpenTriplesUrl.addActionListener(new FileAssertedTriplesUrlOpenListener()); fileAssertionsMenu.add(fileOpenTriplesUrl); fileAssertionsMenu.addSeparator(); // Create menu options to open recently accessed ontology files fileOpenRecentTriplesFile = new JMenuItem[recentAssertionsFiles.size()]; for (int recentFileNumber = 0; recentFileNumber < recentAssertionsFiles.size(); ++recentFileNumber) { fileOpenRecentTriplesFile[recentFileNumber] = new JMenuItem( recentAssertionsFiles.get(recentFileNumber).getName()); fileOpenRecentTriplesFile[recentFileNumber] .setToolTipText(recentAssertionsFiles.get(recentFileNumber).getAbsolutePath()); fileOpenRecentTriplesFile[recentFileNumber] .addActionListener(new RecentAssertedTriplesFileOpenListener()); fileAssertionsMenu.add(fileOpenRecentTriplesFile[recentFileNumber]); } if (fileOpenRecentTriplesFile.length > 0) { fileAssertionsMenu.addSeparator(); } fileSaveTriplesToFile = new JMenuItem("Save Assertions Text"); fileSaveTriplesToFile .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK)); fileSaveTriplesToFile.setMnemonic(KeyEvent.VK_S); fileSaveTriplesToFile.setToolTipText("Write the asserted triples to a file"); fileSaveTriplesToFile.addActionListener(new FileAssertedTriplesSaveListener()); fileAssertionsMenu.add(fileSaveTriplesToFile); fileSaveSerializedModel = new JMenuItem("Save Model (processed triples)"); fileSaveSerializedModel .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK)); fileSaveSerializedModel.setMnemonic(KeyEvent.VK_M); fileSaveSerializedModel.setToolTipText("Write the triples from the current model to a file"); fileSaveSerializedModel.addActionListener(new ModelSerializerListener()); fileAssertionsMenu.add(fileSaveSerializedModel); fileAssertionsMenu.addSeparator(); fileExit = new JMenuItem("Exit"); fileExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK)); fileExit.setMnemonic(KeyEvent.VK_X); fileExit.setToolTipText("Exit the application"); fileExit.addActionListener(new EndApplicationListener()); fileAssertionsMenu.add(fileExit); } /** * Configures the SPARQL file menu. Called at startup * and whenever an SPARQL file is opened or saved since * the list of recent SPARQL files is presented on the * file menu. */ private void setupSparqlFileMenu() { fileSparqlMenu.removeAll(); fileOpenSparqlFile = new JMenuItem("Open SPARQL File"); fileOpenSparqlFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_MASK)); fileOpenSparqlFile.setMnemonic(KeyEvent.VK_S); fileOpenSparqlFile.setToolTipText("Open a SPARQL query file"); fileOpenSparqlFile.addActionListener(new FileSparqlOpenListener()); fileSparqlMenu.add(fileOpenSparqlFile); fileSparqlMenu.addSeparator(); // Create menu options to open recently accessed SPARQL files fileOpenRecentSparqlFile = new JMenuItem[recentSparqlFiles.size()]; for (int recentFileNumber = 0; recentFileNumber < recentSparqlFiles.size(); ++recentFileNumber) { fileOpenRecentSparqlFile[recentFileNumber] = new JMenuItem( recentSparqlFiles.get(recentFileNumber).getName()); fileOpenRecentSparqlFile[recentFileNumber] .setToolTipText(recentSparqlFiles.get(recentFileNumber).getAbsolutePath()); fileOpenRecentSparqlFile[recentFileNumber].addActionListener(new RecentSparqlFileOpenListener()); fileSparqlMenu.add(fileOpenRecentSparqlFile[recentFileNumber]); } if (fileOpenRecentSparqlFile.length > 0) { fileSparqlMenu.addSeparator(); } fileSaveSparqlQueryToFile = new JMenuItem("Save SPARQL Query"); fileSaveSparqlQueryToFile .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK)); fileSaveSparqlQueryToFile.setMnemonic(KeyEvent.VK_Q); fileSaveSparqlQueryToFile.setToolTipText("Write the SPARQL query to a file"); fileSaveSparqlQueryToFile.addActionListener(new FileSparqlSaveListener()); fileSparqlMenu.add(fileSaveSparqlQueryToFile); fileSaveSparqlResultsToFile = new JMenuItem("Save SPARQL Results"); fileSaveSparqlResultsToFile .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK)); fileSaveSparqlResultsToFile.setMnemonic(KeyEvent.VK_R); fileSaveSparqlResultsToFile.setToolTipText("Write the current SPARQL results to a file"); fileSaveSparqlResultsToFile.addActionListener(new FileSparqlResultsSaveListener()); fileSparqlMenu.add(fileSaveSparqlResultsToFile); fileSparqlMenu.addSeparator(); fileClearSparqlHistory = new JMenuItem("Clear SPARQL Query History"); fileClearSparqlHistory.setMnemonic(KeyEvent.VK_C); fileClearSparqlHistory.setToolTipText("Clear the history of executed SPARQL queries"); fileClearSparqlHistory.addActionListener(new FileClearSparqlHistoryListener()); fileSparqlMenu.add(fileClearSparqlHistory); } /** * Setup the frame's menus */ private void setupMenus() { JMenuBar menuBar; menuBar = new JMenuBar(); setJMenuBar(menuBar); // Assertions file menu fileAssertionsMenu = new JMenu("File (Assertions)"); fileAssertionsMenu.setMnemonic(KeyEvent.VK_A); fileAssertionsMenu.setToolTipText("Menu items related to asserted triples file access"); menuBar.add(fileAssertionsMenu); setupAssertionsFileMenu(); // SPARQL file menu fileSparqlMenu = new JMenu("File (SPARQL)"); fileSparqlMenu.setMnemonic(KeyEvent.VK_S); fileSparqlMenu.setToolTipText("Menu items related to SPARQL file access"); menuBar.add(fileSparqlMenu); setupSparqlFileMenu(); // Edit Menu menuBar.add(setupEditMenu()); // Configuration Menu menuBar.add(setupConfigurationMenu()); // Model Menu menuBar.add(setupModelMenu()); // Filters Menu menuBar.add(setupFiltersMenu()); // SPARQL Server Menu menuBar.add(setupSparqlServerMenu()); // Help Menu menuBar.add(setupHelpMenu()); } /** * Create the edit menu * * @return The edit menu */ private JMenu setupEditMenu() { final JMenu menu = new JMenu("Edit"); menu.setMnemonic(KeyEvent.VK_E); menu.setToolTipText("Menu items related to editing the ontology"); editFind = new JMenuItem("Find (in assertions)"); editFind.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, KeyEvent.CTRL_MASK)); editFind.setMnemonic(KeyEvent.VK_F); editFind.setToolTipText("Find text in the assertions editor"); editFind.addActionListener(new FindAssertionsTextListener()); menu.add(editFind); editFindNextMatch = new JMenuItem("Next (matching assertion text)"); editFindNextMatch.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, KeyEvent.CTRL_MASK)); editFindNextMatch.setMnemonic(KeyEvent.VK_N); editFindNextMatch.setToolTipText("Find next text match in the assertions editor"); editFindNextMatch.addActionListener(new FindNextAssertionsTextListener()); menu.add(editFindNextMatch); menu.addSeparator(); editCommentToggle = new JMenuItem("Toggle Comment"); editCommentToggle.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK)); editCommentToggle.setMnemonic(KeyEvent.VK_T); editCommentToggle .setToolTipText("Switch the chosen assertion or query lines between commented and not commented"); editCommentToggle.addActionListener(new CommentToggleListener()); editCommentToggle.setEnabled(false); menu.add(editCommentToggle); editInsertPrefixes = new JMenuItem("Insert Prefixes"); editInsertPrefixes.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.CTRL_MASK)); editInsertPrefixes.setMnemonic(KeyEvent.VK_I); editInsertPrefixes.setToolTipText("Insert standard prefixes (namespaces)"); editInsertPrefixes.addActionListener(new InsertPrefixesListener()); menu.add(editInsertPrefixes); menu.addSeparator(); editExpandAllTreeNodes = new JMenuItem("Expand Entire Tree"); editExpandAllTreeNodes.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ADD, ActionEvent.ALT_MASK)); editExpandAllTreeNodes.setMnemonic(KeyEvent.VK_E); editExpandAllTreeNodes.setToolTipText("Expand all tree nodes"); editExpandAllTreeNodes.addActionListener(new ExpandTreeListener()); menu.add(editExpandAllTreeNodes); editCollapseAllTreeNodes = new JMenuItem("Collapse Entire Tree"); editCollapseAllTreeNodes.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, ActionEvent.ALT_MASK)); editCollapseAllTreeNodes.setMnemonic(KeyEvent.VK_C); editCollapseAllTreeNodes.setToolTipText("Expand all tree nodes"); editCollapseAllTreeNodes.addActionListener(new CollapseTreeListener()); menu.add(editCollapseAllTreeNodes); menu.addSeparator(); editEditListOfSparqlServiceUrls = new JMenuItem("Edit SPARQL Service URLs List"); editEditListOfSparqlServiceUrls.setMnemonic(KeyEvent.VK_S); editEditListOfSparqlServiceUrls.setToolTipText("Remove unwanted URLs from the dropdown list"); editEditListOfSparqlServiceUrls.addActionListener(new EditListOfSparqlServiceUrls()); menu.add(editEditListOfSparqlServiceUrls); return menu; } /** * Create the configuration menu * * @return The configuration menu */ private JMenu setupConfigurationMenu() { final JMenu menu = new JMenu("Configure"); ButtonGroup buttonGroup; menu.setMnemonic(KeyEvent.VK_C); menu.setToolTipText("Menu items related to configuration"); buttonGroup = new ButtonGroup(); setupOutputAssertionLanguage = new JCheckBoxMenuItem[FORMATS.length + 1]; setupOutputAssertionLanguage[0] = new JCheckBoxMenuItem("Output Format: Auto"); buttonGroup.add(setupOutputAssertionLanguage[0]); menu.add(setupOutputAssertionLanguage[0]); for (int index = 0; index < FORMATS.length; ++index) { setupOutputAssertionLanguage[index + 1] = new JCheckBoxMenuItem("Output Format: " + FORMATS[index]); buttonGroup.add(setupOutputAssertionLanguage[index + 1]); menu.add(setupOutputAssertionLanguage[index + 1]); } setupOutputAssertionLanguage[0].setSelected(true); menu.addSeparator(); buttonGroup = new ButtonGroup(); setupOutputModelTypeAssertions = new JCheckBoxMenuItem("Output Assertions Only"); buttonGroup.add(setupOutputModelTypeAssertions); menu.add(setupOutputModelTypeAssertions); setupOutputModelTypeAssertionsAndInferences = new JCheckBoxMenuItem("Output Assertions and Inferences"); buttonGroup.add(setupOutputModelTypeAssertionsAndInferences); menu.add(setupOutputModelTypeAssertionsAndInferences); setupOutputModelTypeAssertions.setSelected(true); menu.addSeparator(); setupAllowMultilineResultOutput = new JCheckBoxMenuItem( "Allow Multiple Lines of Text Per Row in SPARQL Query Output"); setupAllowMultilineResultOutput.setToolTipText("Wrap long values into multiple lines in a display cell"); setupAllowMultilineResultOutput.setSelected(false); menu.add(setupAllowMultilineResultOutput); setupOutputFqnNamespaces = new JCheckBoxMenuItem("Show FQN Namespaces Instead of Prefixes in Query Output"); setupOutputFqnNamespaces .setToolTipText("Use the fully qualified namespace. If unchecked use the prefix, if defined"); setupOutputFqnNamespaces.setSelected(false); menu.add(setupOutputFqnNamespaces); setupOutputDatatypesForLiterals = new JCheckBoxMenuItem("Show Datatypes on Literals"); setupOutputDatatypesForLiterals.setToolTipText("Display the datatype after the value, e.g. 4^^xsd:integer"); setupOutputDatatypesForLiterals.setSelected(false); menu.add(setupOutputDatatypesForLiterals); setupOutputFlagLiteralValues = new JCheckBoxMenuItem("Flag Literal Values in Query Output"); setupOutputFlagLiteralValues.setToolTipText("Includes the text 'Lit:' in front of any literal values"); setupOutputFlagLiteralValues.setSelected(false); menu.add(setupOutputFlagLiteralValues); setupApplyFormattingToLiteralValues = new JCheckBoxMenuItem("Apply Formatting to Literal Values"); setupApplyFormattingToLiteralValues.setToolTipText( "Apply the XSD-based formatting defined in the configuration to literal values in SPARQL results and tree view display"); setupApplyFormattingToLiteralValues.setSelected(true); menu.add(setupApplyFormattingToLiteralValues); setupDisplayImagesInSparqlResults = new JCheckBoxMenuItem( "Display Images in Query Output (Slows Results Retrieval)"); setupDisplayImagesInSparqlResults.setToolTipText("Attempts to download images linked in the results. " + "Can run very slowly depending on number and size of images"); setupDisplayImagesInSparqlResults.setSelected(true); menu.add(setupDisplayImagesInSparqlResults); menu.addSeparator(); buttonGroup = new ButtonGroup(); setupExportSparqlResultsAsCsv = new JCheckBoxMenuItem( "Export SPARQL Results to " + EXPORT_FORMAT_LABEL_CSV); setupExportSparqlResultsAsCsv.setToolTipText("Export to Comma Separated Value format"); buttonGroup.add(setupExportSparqlResultsAsCsv); menu.add(setupExportSparqlResultsAsCsv); setupExportSparqlResultsAsTsv = new JCheckBoxMenuItem( "Export SPARQL Results to " + EXPORT_FORMAT_LABEL_TSV); setupExportSparqlResultsAsTsv.setToolTipText("Export to Tab Separated Value format"); buttonGroup.add(setupExportSparqlResultsAsTsv); menu.add(setupExportSparqlResultsAsTsv); menu.addSeparator(); setupSparqlResultsToFile = new JCheckBoxMenuItem("Send SPARQL Results Directly to File"); setupSparqlResultsToFile.setToolTipText( "For large results sets this permits writing to file without trying to render on screen"); menu.add(setupSparqlResultsToFile); menu.addSeparator(); setupEnableStrictMode = new JCheckBoxMenuItem("Enable Strict Checking Mode"); setupEnableStrictMode.setSelected(true); setupEnableStrictMode.addActionListener(new ReasonerConfigurationChange()); menu.add(setupEnableStrictMode); menu.addSeparator(); setupFont = new JMenuItem("Font"); setupFont.setMnemonic(KeyEvent.VK_F); setupFont.setToolTipText("Set the font used for the display"); setupFont.addActionListener(new FontSetupListener()); menu.add(setupFont); menu.addSeparator(); setupProxyEnabled = new JCheckBoxMenuItem("Enable Proxy"); setupProxyEnabled.setToolTipText("Pass network SPARQL requests through a proxy"); setupProxyEnabled.addActionListener(new ProxyStatusChangeListener()); menu.add(setupProxyEnabled); setupProxyConfiguration = new JMenuItem("Proxy Settings"); setupProxyConfiguration.setToolTipText("Configure the proxy"); setupProxyConfiguration.addActionListener(new ProxySetupListener()); menu.add(setupProxyConfiguration); return menu; } /** * Create the model menu * * @return The model menu */ private JMenu setupModelMenu() { final JMenu menu = new JMenu("Model"); menu.setMnemonic(KeyEvent.VK_M); menu.setToolTipText("Menu items related to viewing the model"); modelCreateTreeView = new JMenuItem("Create Tree"); modelCreateTreeView.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.ALT_MASK)); modelCreateTreeView.setMnemonic(KeyEvent.VK_T); modelCreateTreeView.setToolTipText("Create tree representation of current model"); modelCreateTreeView.addActionListener(new GenerateTreeListener()); menu.add(modelCreateTreeView); modelListInferredTriples = new JMenuItem("Identify Inferred Triples"); modelListInferredTriples.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, ActionEvent.ALT_MASK)); modelListInferredTriples.setMnemonic(KeyEvent.VK_I); modelListInferredTriples.setToolTipText("Create a list of inferred triples from the current model"); modelListInferredTriples.addActionListener(new GenerateInferredTriplesListener()); menu.add(modelListInferredTriples); menu.addSeparator(); filterResetTree = new JMenuItem("Clear Tree"); filterResetTree .setToolTipText("Remove the tree view of the ontology. This may help if memory is running low"); filterResetTree.addActionListener(new ClearTreeModelListener()); menu.add(filterResetTree); return menu; } /** * Create the filters menu * * @return The filters menu */ private JMenu setupFiltersMenu() { final JMenu menu = new JMenu("Tree Filter"); menu.setMnemonic(KeyEvent.VK_F); menu.setToolTipText("Menu items related to filtering values out of the model's tree"); filterEnableFilters = new JCheckBoxMenuItem("Enable Filters"); filterEnableFilters.setSelected(true); filterEnableFilters .setToolTipText("Enforce the filtered list of classes and properties when creating the tree view"); menu.add(filterEnableFilters); filterShowAnonymousNodes = new JCheckBoxMenuItem("Show Anonymous Nodes"); filterShowAnonymousNodes.setSelected(false); filterShowAnonymousNodes.setToolTipText("Include anonymous nodes in the tree view"); menu.add(filterShowAnonymousNodes); showFqnInTree = new JCheckBoxMenuItem("Show FQN In Tree"); showFqnInTree.setSelected(false); showFqnInTree .setToolTipText("Show the fully qualified name for classes, properties and objects in the tree"); menu.add(showFqnInTree); menu.addSeparator(); filterEditFilteredClasses = new JMenuItem("Edit List of Filtered Classes"); filterEditFilteredClasses .setToolTipText("Present the list of filtered classes and allow them to be edited"); filterEditFilteredClasses.addActionListener(new EditFilteredClassesListener()); menu.add(filterEditFilteredClasses); filterEditFilteredProperties = new JMenuItem("Edit List of Filtered Properties"); filterEditFilteredProperties .setToolTipText("Present the list of filtered properties and allow them to be edited"); filterEditFilteredProperties.addActionListener(new EditFilteredPropertiesListener()); menu.add(filterEditFilteredProperties); menu.addSeparator(); filterSetMaximumIndividualsPerClassInTree = new JMenuItem("Set Maximum Individuals Per Class in Tree"); filterSetMaximumIndividualsPerClassInTree .setToolTipText("Limit number of individuals shown for each class in the tree view."); filterSetMaximumIndividualsPerClassInTree .addActionListener(new SetMaximumIndividualsPerClassInTreeListener()); menu.add(filterSetMaximumIndividualsPerClassInTree); return menu; } /** * Create the SPARQL server menu * * @return The SPARQL server menu */ private JMenu setupSparqlServerMenu() { final JMenu menu = new JMenu("SPARQL Server"); menu.setMnemonic(KeyEvent.VK_P); menu.setToolTipText("Options for using the SPARQL server"); sparqlServerStartup = new JMenuItem("Startup SPARQL Server"); sparqlServerStartup.setMnemonic(KeyEvent.VK_S); sparqlServerStartup.setToolTipText("Start the SPARQL server"); sparqlServerStartup.addActionListener(new SparqlServerStartupListener()); menu.add(sparqlServerStartup); sparqlServerShutdown = new JMenuItem("Shutdown SPARQL Server"); sparqlServerShutdown.setMnemonic(KeyEvent.VK_H); sparqlServerShutdown.setToolTipText("Stop the SPARQL server"); sparqlServerShutdown.addActionListener(new SparqlServerShutdownListener()); menu.add(sparqlServerShutdown); menu.addSeparator(); sparqlServerPublishCurrentModel = new JMenuItem("Publish Current Reasoned Model"); sparqlServerPublishCurrentModel.setMnemonic(KeyEvent.VK_P); sparqlServerPublishCurrentModel .setToolTipText("Set the model for the SPARQL server to the current one reasoned"); sparqlServerPublishCurrentModel.addActionListener(new SparqlServerPublishModelListener()); menu.add(sparqlServerPublishCurrentModel); menu.addSeparator(); sparqlServerConfig = new JMenuItem("Configure the SPARQL Server"); sparqlServerConfig.setMnemonic(KeyEvent.VK_C); sparqlServerConfig.setToolTipText("Configure the server endpoint"); sparqlServerConfig.addActionListener(new SparqlServerConfigurationListener()); menu.add(sparqlServerConfig); return menu; } /** * Create the help menu * * @return The help menu */ private JMenu setupHelpMenu() { final JMenu menu = new JMenu("Help"); menu.setMnemonic(KeyEvent.VK_H); menu.setToolTipText("Menu items related to user assistance"); helpOverviewVideo = new JMenuItem("8 Minute Overview Video"); helpOverviewVideo.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, ActionEvent.ALT_MASK)); helpOverviewVideo.setMnemonic(KeyEvent.VK_V); helpOverviewVideo.setToolTipText("View an 8 minute overview of Semantic Workbench"); helpOverviewVideo.addActionListener(new OverviewVideoListener()); menu.add(helpOverviewVideo); helpAbout = new JMenuItem("About"); helpAbout.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); helpAbout.setMnemonic(KeyEvent.VK_A); helpAbout.setToolTipText("View version information"); helpAbout.addActionListener(new AboutListener()); menu.add(helpAbout); return menu; } /** * Enable and disable controls based on current state * * @param enable * Whether to enable or disable controls */ private void enableControls(boolean enable) { String sparqlService; LOGGER.debug("Called enableControls with setting " + enable); // Don't allow editing if the ontology file did not load completely. This is // to avoid confusion for the user since when the ontology file isn't loaded // completely the reasoner will be run on the actual file rather than the // version in the text area, so text area edits would be ignored. // TODO Consider switching the status of hasIncompleteAssertionsInput if the // user edits the text area after an incomplete load. Would want to warn the // user about avoiding overwriting the complete version of the file assertionsInput.setEditable(enable && !hasIncompleteAssertionsInput); sparqlInput.setEditable(enable); fileOpenTriplesFile.setEnabled(enable); colorCodeTabs(); // If inferencing is completed and the models are setup, enable // the tree view and inferred triples listing options if (enable && ontModel != null) { modelCreateTreeView.setEnabled(true); modelListInferredTriples.setEnabled(true); fileSaveSerializedModel.setEnabled(true); } else { modelCreateTreeView.setEnabled(false); modelListInferredTriples.setEnabled(false); fileSaveSerializedModel.setEnabled(false); } enableAssertionsHandling(enable); if (enable && sparqlInput.getText().trim().length() > 0) { fileSaveSparqlQueryToFile.setEnabled(true); } else { fileSaveSparqlQueryToFile.setEnabled(false); } if (enable && sparqlResultsTable.getModel().getRowCount() > 0) { fileSaveSparqlResultsToFile.setEnabled(true); } else { fileSaveSparqlResultsToFile.setEnabled(false); } sparqlService = ((String) sparqlServiceUrl.getEditor().getItem()).trim(); if (!sparqlService.equals((String) sparqlServiceUrl.getItemAt(0)) && sparqlService.length() > 0 && sparqlInput.getText().trim().length() > 0) { runSparql.setEnabled(true); sparqlServicePassword.setEnabled(true); sparqlServiceUserId.setEnabled(true); LOGGER.debug("Enabled run query button (" + sparqlService + ")"); } else if (enable && sparqlInput.getText().trim().length() > 0 && ontModel != null) { runSparql.setEnabled(true); sparqlServicePassword.setEnabled(true); sparqlServiceUserId.setEnabled(true); LOGGER.debug("Enabled run query button (" + sparqlService + ")"); } else if (enable && (sparqlInput.getText().toLowerCase().indexOf("from") > -1 || sparqlInput.getText().toLowerCase().indexOf("service") > -1)) { runSparql.setEnabled(true); sparqlServicePassword.setEnabled(true); sparqlServiceUserId.setEnabled(true); LOGGER.debug("Enabled run query button due to 'from' clause (" + sparqlService + ")"); } else { runSparql.setEnabled(false); sparqlServicePassword.setEnabled(false); sparqlServiceUserId.setEnabled(false); LOGGER.debug("Disabled run query button (" + sparqlService + ")"); } // SPARQL Server sparqlServerShutdown.setEnabled(SparqlServer.getInstance().isActive()); sparqlServerConfig.setEnabled(!SparqlServer.getInstance().isActive()); sparqlServerPublishCurrentModel.setEnabled(SparqlServer.getInstance().isActive() && ontModel != null); sparqlServerStartup.setEnabled(!SparqlServer.getInstance().isActive() && ontModel != null); // Proxy setupProxyConfiguration.setEnabled(true); setupProxyEnabled.setEnabled(isProxyConfigOkay(false)); // Query history previousQuery.setEnabled(enable && queryHistory.hasPrevious()); nextQuery.setEnabled(enable && queryHistory.hasNext()); } /** * Enable or disable the assertions save and inferencing execution * * @param enable * Whether controls may be enabled */ private void enableAssertionsHandling(boolean enable) { boolean enableRunInferencing; boolean enableSaveTriples; enableRunInferencing = enable && assertionsInput.getText().trim().length() > 0; /* * The file save option is not available if a local file could not be loaded * completely (don't want to accidentally overwrite it with an incomplete * version) However, if the incomplete load is from a URL, then it can be * saved to a file for local manipulation. */ enableSaveTriples = enable && assertionsInput.getText().trim().length() > 0 && (!hasIncompleteAssertionsInput || (rdfFileSource != null && rdfFileSource.isUrl())); if (runInferencing.isEnabled() != enableRunInferencing) { runInferencing.setEnabled(enableRunInferencing); } if (fileSaveTriplesToFile.isEnabled() != enableSaveTriples) { fileSaveTriplesToFile.setEnabled(enableSaveTriples); } } /** * Setup the network environment based on the proxy configuration. If the * proxy is not enabled no changes will be made to the network operation. */ private void setupProxy() { if (isProxyConfigOkay(true) && proxyEnabled) { setupProxyEnabled.setSelected(proxyEnabled); if (proxyProtocolHttp) { System.setProperty("http.proxyHost", proxyServer); System.setProperty("http.proxyPort", proxyPort + ""); } if (proxyProtocolSocks) { System.setProperty("socksProxyHost", proxyServer); System.setProperty("socksProxyPort", proxyPort + ""); } proxyInfo.setText("Enabled (" + proxyServer + "@" + proxyPort + ")"); proxyInfo.setForeground(Color.red); } // Proxy definitions // -DsocksProxyHost=YourSocksServer // -DsocksProxyHost=YourSocksServer -DsocksProxyPort=port // -Dhttp.proxyHost=WebProxy -Dhttp.proxyPort=Port // System.setProperty("http.proxyHost", "localhost"); // System.setProperty("http.proxyPort", "8080"); } /** * Checks the proxy configuration and alerts the user if it is obviously * flawed. * * @param alertUser * Whether to popup a message dialog if an error exists in the proxy * configuration * * @return False if there is an issue with the proxy configuration */ private boolean isProxyConfigOkay(boolean alertUser) { String errorMessages = ""; if (proxyEnabled || !alertUser) { if (!proxyProtocolHttp && !proxyProtocolSocks) { errorMessages += "No protocols were set for proxying.\n"; } if (proxyServer == null || proxyServer.trim().length() == 0) { errorMessages += "No proxy server is defined.\n"; } if (proxyPort == null || proxyPort < 1) { errorMessages += "No proxy port is defined.\n"; } if (errorMessages.length() > 0 && alertUser) { // Force proxying off setupProxyEnabled.setSelected(false); JOptionPane.showMessageDialog(this, "Proxying cannot be enabled.\nPlease see the information below.\n\n" + errorMessages + "\nUse the Proxy Configuration option to update the proxy settings.", "Proxy Cannot Be Enabled", JOptionPane.ERROR_MESSAGE); } } return errorMessages.length() == 0; } /** * Enable or disable the use of a proxy for remote SPARQL requests */ private void changeProxyMode() { proxyEnabled = setupProxyEnabled.isSelected(); if (isProxyConfigOkay(true)) { String changeType; changeType = setupProxyEnabled.isSelected() ? "Enabled" : "Disabled"; JOptionPane.showMessageDialog(this, "You must restart the program for the proxy change to take effect.\n\nAfter the restart the proxy will be " + changeType, "Proxy Setting Changed: " + changeType, JOptionPane.INFORMATION_MESSAGE); } } /** * Configure the proxy settings for executing remote SPARQL queries through a * proxy */ private void configureProxy() { final ProxyConfigurationDialog dialog = new ProxyConfigurationDialog(this, proxyServer, proxyPort, proxyProtocolHttp, proxyProtocolSocks); if (dialog.isAccepted()) { if (dialog.getProxyServer().trim().length() > 0) { proxyServer = dialog.getProxyServer(); } else { JOptionPane.showMessageDialog(this, "The proxy server cannot be blank", "Proxy Server Required", JOptionPane.ERROR_MESSAGE); } if (dialog.getProxyPort() != null && dialog.getProxyPort() > 0) { proxyPort = dialog.getProxyPort(); } else { JOptionPane .showMessageDialog(this, "The proxy port number must be a number greater than 0\n\nEntered value: " + dialog.getProxyPort(), "Illegal Proxy Port Number", JOptionPane.ERROR_MESSAGE); } proxyProtocolHttp = dialog.isProtocolHttp(); proxyProtocolSocks = dialog.isProtocolSocks(); if (!proxyProtocolHttp && !proxyProtocolSocks) { JOptionPane.showMessageDialog(this, "No protocols were set for proxying.\nEnabling proxying will have no effect.", "Proxy Setting: No Protocols Selected", JOptionPane.WARNING_MESSAGE); } if (setupProxyEnabled.isSelected()) { JOptionPane.showMessageDialog(this, "You must restart the program for these changes to take effect", "Proxy Setting Changed", JOptionPane.INFORMATION_MESSAGE); } } enableControls(true); } /** * Startup the SPARQL server */ private void startSparqlServer() { if (!SparqlServer.getInstance().isActive()) { if (ontModel != null) { publishModelToTheSparqlServer(); SparqlServer.getInstance().addObserver(this); try { SparqlServer.getInstance().start(); } catch (Throwable throwable) { LOGGER.error("Unable to start the SPARQL server", throwable); SparqlServer.getInstance().deleteObserver(this); JOptionPane.showMessageDialog(this, "Unable to start the SPARQL server\n" + throwable.getMessage(), "Cannot Start the SPARQL Server", JOptionPane.ERROR_MESSAGE); } if (SparqlServer.getInstance().isActive()) { if (SparqlServer.getInstance().areRemoteUpdatesPermitted()) { sparqlServerInfo.setBorder( BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.red.darker()), "SPARQL Server Status (Updates Allowed)", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, BorderFactory.createTitledBorder("").getTitleFont(), Color.red.darker())); } sparqlServerInfo.setForeground(Color.blue.darker()); updateSparqlServerInfo(); setStatus("SPARQL server started on port " + SparqlServer.getInstance().getListenerPort() + (SparqlServer.getInstance().areRemoteUpdatesPermitted() ? " (Remote Updates Enabled)" : "")); } } else { JOptionPane.showMessageDialog(this, "You must create a model before starting the SPARQL server", "Cannot Start SPARQL Server", JOptionPane.WARNING_MESSAGE); } } else { setStatus("SPARQL server is already running"); } enableControls(true); } /** * Shutdown the SPARQL server */ private void stopSparqlServer() { if (SparqlServer.getInstance().isActive()) { SparqlServer.getInstance().stop(); setStatus("SPARQL server stopped"); SparqlServer.getInstance().deleteObserver(this); } else { setStatus("SPARQL server is not running"); } sparqlServerInfo.setBorder(BorderFactory.createTitledBorder("SPARQL Server Status")); sparqlServerInfo.setText("Shutdown"); sparqlServerInfo.setForeground(Color.black); enableControls(true); } /** * Show the SPARQL Server Status */ private void updateSparqlServerInfo() { sparqlServerInfo.setText("Port:" + SparqlServer.getInstance().getListenerPort() + " Requests: " + SparqlServer.getInstance().getConnectionsHandled()); } /** * Publishes the current ontology model to the SPARQL server endpoint */ private void publishModelToTheSparqlServer() { if (ontModel != null) { final OntModel newModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM); newModel.add(ontModel); SparqlServer.getInstance().setModel(newModel); } else { LOGGER.warn("There is no model to set on the SPARQL server"); setStatus("There is no model to set on the SPARQL server"); } } /** * Make this functional */ private void configureSparqlServer() { if (!SparqlServer.getInstance().isActive()) { final SparqlServerConfigurationDialog dialog = new SparqlServerConfigurationDialog(this, SparqlServer.getInstance().getListenerPort(), SparqlServer.getInstance().getMaxRuntimeSeconds(), SparqlServer.getInstance().areRemoteUpdatesPermitted()); if (dialog.isAccepted()) { if (dialog.getPortNumber() != null && dialog.getPortNumber() > 0) { SparqlServer.getInstance().setListenerPort(dialog.getPortNumber()); } else { JOptionPane .showMessageDialog(this, "The port number must be a number greater than 0\n\nEntered value: " + dialog.getPortNumber(), "Illegal Port Number", JOptionPane.ERROR_MESSAGE); } if (dialog.getMaxRuntime() != null && dialog.getMaxRuntime() > 0) { SparqlServer.getInstance().setMaxRuntimeSeconds(dialog.getMaxRuntime()); } else { JOptionPane .showMessageDialog(this, "The maximum runtime setting must be a number greater than 0\n\nEntered value: " + dialog.getMaxRuntime(), "Illegal Maximum Runtime", JOptionPane.ERROR_MESSAGE); } SparqlServer.getInstance().setRemoteUpdatesPermitted(dialog.areRemoteUpdatesAllowed()); } } } /** * Set the tab background and foreground color based on whether the tab's data * is out of synch with the model or other configuration changes */ private void colorCodeTabs() { if (hasIncompleteAssertionsInput) { tabbedPane.setForegroundAt(0, Color.orange.darker()); tabbedPane.setBackgroundAt(0, Color.yellow.brighter()); tabbedPane.setToolTipTextAt(0, "Only part of the assertions file is displayed"); } else { tabbedPane.setForegroundAt(0, NORMAL_TAB_FG); tabbedPane.setBackgroundAt(0, NORMAL_TAB_BG); tabbedPane.setToolTipTextAt(0, null); } if (!areInferencesInSyncWithModel && inferredTriples.getText().trim().length() > 0) { tabbedPane.setForegroundAt(1, Color.red); tabbedPane.setBackgroundAt(1, Color.pink); tabbedPane.setToolTipTextAt(1, "Inferences are out of sync with loaded assertions"); } else { tabbedPane.setForegroundAt(1, NORMAL_TAB_FG); tabbedPane.setBackgroundAt(1, NORMAL_TAB_BG); tabbedPane.setToolTipTextAt(1, null); } if (!isTreeInSyncWithModel && !ontModelTree.getModel().isLeaf(ontModelTree.getModel().getRoot())) { tabbedPane.setForegroundAt(2, Color.red); tabbedPane.setBackgroundAt(2, Color.pink); tabbedPane.setToolTipTextAt(2, "Tree is out of sync with loaded assertions"); } else { tabbedPane.setForegroundAt(2, NORMAL_TAB_FG); tabbedPane.setBackgroundAt(2, NORMAL_TAB_BG); tabbedPane.setToolTipTextAt(2, null); } if (!areSparqlResultsInSyncWithModel && sparqlResultsTable.getRowCount() > 0) { tabbedPane.setForegroundAt(3, Color.red); tabbedPane.setBackgroundAt(3, Color.pink); tabbedPane.setToolTipTextAt(3, "Results are out of sync with loaded assertions"); } else { tabbedPane.setForegroundAt(3, NORMAL_TAB_FG); tabbedPane.setBackgroundAt(3, NORMAL_TAB_BG); tabbedPane.setToolTipTextAt(3, null); } } /** * Setup all the components */ private void setupControls() { LOGGER.debug("setupControls"); reasoningLevel = new JComboBox(); for (ReasonerSelection reasoner : ReasonerSelection.values()) { reasoningLevel.addItem(reasoner); } reasoningLevel.setSelectedIndex(reasoningLevel.getItemCount() - 1); reasoningLevel.setToolTipText(((ReasonerSelection) reasoningLevel.getSelectedItem()).description()); reasoningLevel.addActionListener(new ReasonerConfigurationChange()); language = new JComboBox(); language.addItem("Auto"); for (String lang : FORMATS) { language.addItem(lang); } language.setSelectedIndex(0); assertedTripleCount = new JLabel(NOT_APPLICABLE_DISPLAY); assertedTripleCount.setHorizontalAlignment(JLabel.CENTER); inferredTripleCount = new JLabel(NOT_APPLICABLE_DISPLAY); inferredTripleCount.setHorizontalAlignment(JLabel.CENTER); runInferencing = new JButton("Create Model"); runInferencing.setToolTipText( "Creates an ontology model using the provieed assertions " + "and the selected reasoning level"); runInferencing.addActionListener(new ReasonerListener()); runSparql = new JButton("Run Query"); runSparql.addActionListener(new SparqlListener()); sparqlServerInfo = new JLabel("Shutdown"); sparqlServerInfo.setHorizontalAlignment(SwingConstants.CENTER); sparqlServerInfo.setBorder(BorderFactory.createTitledBorder("SPARQL Server Status")); proxyInfo = new JLabel("Disabled"); proxyInfo.setHorizontalAlignment(SwingConstants.CENTER); proxyInfo.setBorder(BorderFactory.createTitledBorder("Proxy Status")); assertionsInput = new JTextArea(10, 50); assertionsInput.addKeyListener(new UserInputListener()); assertionsInput.addCaretListener(new TextAreaCaratListener()); inferredTriples = new JTextArea(10, 50); inferredTriples.setEditable(false); // SPARQL Input sparqlInput = new JTextArea(10, 50); sparqlInput.addKeyListener(new UserInputListener()); sparqlInput.addCaretListener(new TextAreaCaratListener()); // User id and password for accessing secured SPARQL endpoints sparqlServiceUserId = new JTextField(10); sparqlServicePassword = new JPasswordField(10); // SPARQL service URLs sparqlServiceUrl = new JComboBox(); sparqlServiceUrl.setEditable(true); sparqlServiceUrl.addActionListener(new SparqlModelChoiceListener()); sparqlServiceUrl.getEditor().getEditorComponent().addKeyListener(new UserInputListener()); // Default graph if required defaultGraphUri = new JTextField(); defaultGraphUri.setColumns(20); // Move through query history previousQuery = new JButton("Previous"); previousQuery.addActionListener(new SparqlHistoryPreviousListener()); nextQuery = new JButton("Next"); nextQuery.addActionListener(new SparqlHistoryNextListener()); // A basic default query sparqlInput.setText("select ?s ?p ?o where { ?s ?p ?o } limit 100"); // Results table // sparqlResultsTable = new JTable(new SparqlTableModel()); sparqlResultsTable = new JTable(); // TODO Allow configuration to switch auto-resizing on/off (e.g. horizontal // scrolling) sparqlResultsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); sparqlResultsTable.setAutoCreateRowSorter(true); // Determine whether alternate tree icons exist if (ImageLibrary.instance().getImageIcon(ImageLibrary.ICON_TREE_CLASS) != null) { replaceTreeImages = true; } LOGGER.debug("Tree renderer, specialized icons available? " + replaceTreeImages); // Create the tree UI with a default model ontModelTree = new JTree(new DefaultTreeModel(new DefaultMutableTreeNode("No Tree Generated"))); ontModelTree.addMouseListener(new OntologyModelTreeMouseListener()); if (replaceTreeImages) { ToolTipManager.sharedInstance().registerComponent(ontModelTree); ontModelTree.setCellRenderer(new OntologyTreeCellRenderer()); } // Status label status = new JLabel("Initializing"); } /** * Create a JPanel that uses a FlowLayout and add a component to the JPanel. * The method creates a JPanel, sets its layout to FlowLayout and adds the * supplied component to itself. * * @param component * The component to be placed using a FlowLayout * @param alignment * How to align the component. Use a FlowLayout constant. * * @return The new JPanel instance */ private JPanel makeFlowPanel(JComponent component, int alignment) { JPanel panel; panel = new JPanel(); panel.setLayout(new FlowLayout(alignment)); panel.add(component); return panel; } /** * Expand all the nodes in the tree representation of the model * * @return The final status to display */ private String expandAll() { int numNodes; ProgressMonitor progress; boolean canceled; final DefaultMutableTreeNode root = (DefaultMutableTreeNode) ontModelTree.getModel().getRoot(); @SuppressWarnings("rawtypes") final Enumeration enumerateNodes = root.breadthFirstEnumeration(); numNodes = 0; while (enumerateNodes.hasMoreElements()) { enumerateNodes.nextElement(); ++numNodes; } LOGGER.debug("Expanding tree with row count: " + numNodes); progress = new ProgressMonitor(this, "Expanding Tree Nodes", "Starting node expansion", 0, numNodes); setStatus("Expanding all tree nodes"); for (int row = 0; !progress.isCanceled() && row < numNodes; ++row) { progress.setProgress(row); if (row % 1000 == 0) { progress.setNote("Row " + row + " of " + numNodes); } ontModelTree.expandRow(row); } canceled = progress.isCanceled(); progress.close(); ontModelTree.scrollRowToVisible(0); if (!canceled) { // Select the tree view tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_TREE_VIEW); } }); } return canceled ? "Tree node expansion canceled by user" : "Tree nodes expanded"; } /** * Collapse all the nodes in the tree representation of the model * * @return The final status to display */ private String collapseAll() { setStatus("Collapsing all tree nodes"); for (int row = ontModelTree.getRowCount(); row > 0; --row) { ontModelTree.collapseRow(row); } // Select the tree view tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_TREE_VIEW); } }); return "Tree nodes collapsed"; } /** * Set the status message to the supplied text. * * @param message * The message to place in the status field */ private void setStatus(String message) { status.setText(message); } /** * Sets the mouse pointer. If the supplied parameter is true then the wait * cursor (usually an hourglass) is displayed. otherwise the system default * cursor is displayed. * * @param wait * Whether to display the system default wait cursor */ private void setWaitCursor(boolean wait) { final JRootPane rootPane = getRootPane(); final Component glassPane = rootPane.getGlassPane(); if (wait) { final Cursor cursorWait = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); rootPane.setCursor(cursorWait); glassPane.setCursor(cursorWait); glassPane.setVisible(true); } else { final Cursor cursorDefault = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); glassPane.setVisible(false); glassPane.setCursor(cursorDefault); rootPane.setCursor(cursorDefault); } glassPane.invalidate(); rootPane.validate(); } /** * Run a thread to support long-running operations. */ public void run() { enableControls(false); String finalStatus = null; try { setStatus("Running..."); setWaitCursor(true); switch (runningOperation) { case LOAD_ASSERTIONS: finalStatus = loadOntologyFile(); break; case CREATE_MODEL: finalStatus = reasonerExecution(); break; case BUILD_TREE_VIEW: finalStatus = createTreeFromModel(); break; case IDENTIFY_ASSERTIONS: finalStatus = identifyInferredTriples(); break; case EXECUTE_SPARQL: finalStatus = sparqlExecution(); break; case EXPORT_MODEL: finalStatus = writeOntologyModel(); break; case EXPORT_SPARQL_RESULTS: finalStatus = writeSparqlResults(); break; case EXPAND_TREE: finalStatus = expandAll(); break; case COLLAPSE_TREE: finalStatus = collapseAll(); break; default: JOptionPane .showMessageDialog(this, "An instruction to execute a task was received\n" + "but the task was undefined. (" + runningOperation + ")", "Error: No Process to Run", JOptionPane.ERROR_MESSAGE); } } catch (ConversionException ce) { LOGGER.error("Failed during conversion within the model", ce); finalStatus = errorAlert(ce, "An error occurred when converting a resource to a language element within the model.\n" + "If strict checking mode is enabled you may want to try disabling it."); } catch (QueryExceptionHTTP httpExc) { LOGGER.error("Failed during remote execution", httpExc); finalStatus = errorAlert(httpExc, "Failure attempting to query against a remote data source"); } catch (Throwable throwable) { LOGGER.error("Failed during execution", throwable); finalStatus = errorAlert(throwable, null); } finally { setWaitCursor(false); enableControls(true); if (finalStatus != null) { setStatus(finalStatus); } else { setStatus(""); } runningOperation = null; } } /** * Creates the status message for the error, alerts the user with a popup. If * the issue is a recognized syntax error and the line and column numbers can * be found int he exception message, the cursor will be moved to that * position. * * @param throwable * The error that occurred * @param operationDetailMessage * A message specific to the operation that was running. This may be * null * * @return The message to be presented on the status line */ private String errorAlert(Throwable throwable, String operationDetailMessage) { String statusMessage; String alertMessage; String httpStatusMessage = null; String causeClass; String causeMessage; QueryExceptionHTTP httpExc = null; int[] lineAndColumn = new int[2]; int whichSelectedTab = -1; JTextArea whichFocusJTextArea = null; if (throwable.getCause() != null) { causeClass = throwable.getCause().getClass().getName(); causeMessage = throwable.getCause().getMessage(); } else { causeClass = throwable.getClass().getName(); causeMessage = throwable.getMessage(); } if (operationDetailMessage != null) { alertMessage = operationDetailMessage + "\n\n"; } else { alertMessage = "Error:"; } alertMessage += causeClass + "\n" + causeMessage; statusMessage = causeMessage.trim().length() > 0 ? causeMessage : causeClass; if (throwable instanceof QueryExceptionHTTP) { httpExc = (QueryExceptionHTTP) throwable; httpStatusMessage = httpExc.getResponseMessage(); if (httpStatusMessage == null || httpStatusMessage.trim().length() == 0) { try { httpStatusMessage = HttpStatus.getStatusText(httpExc.getResponseCode()); } catch (Throwable lookupExc) { LOGGER.info("Cannot find message for returned HTTP code of " + httpExc.getResponseCode()); } } } if (httpExc != null) { statusMessage += ": " + "Response Code: " + httpExc.getResponseCode() + (httpStatusMessage != null && httpStatusMessage.trim().length() > 0 ? " (" + httpStatusMessage + ")" : ""); JOptionPane.showMessageDialog(this, alertMessage + "\n\n" + "Response Code: " + httpExc.getResponseCode() + "\n" + (httpStatusMessage != null ? httpStatusMessage : ""), "Error", JOptionPane.ERROR_MESSAGE); } else { JOptionPane.showMessageDialog(this, alertMessage, "Error", JOptionPane.ERROR_MESSAGE); } // Attempt to deal with a syntax error and positioning the cursor if (runningOperation == Operation.CREATE_MODEL) { // Assertions processing issue RiotException riotExc = null; Throwable nextThrowable = throwable; while (riotExc == null && nextThrowable != null) { if (nextThrowable instanceof RiotException) { riotExc = (RiotException) nextThrowable; } else { LOGGER.trace("Not a riot exception, another? " + throwable.getClass().toString() + "->" + throwable.getCause()); nextThrowable = nextThrowable.getCause(); } } if (riotExc != null) { lineAndColumn = getSyntaxErrorLineColLocation(riotExc.getMessage().toLowerCase(), "line: ", ",", "col: ", "]"); whichSelectedTab = TAB_NUMBER_ASSERTIONS; whichFocusJTextArea = assertionsInput; } else { LOGGER.debug("No riot exception found so the caret cannot be positioned"); } } if (runningOperation == Operation.EXECUTE_SPARQL) { // SPARQL processing issue QueryParseException queryParseExc = null; Throwable nextThrowable = throwable; while (queryParseExc == null && nextThrowable != null) { if (nextThrowable instanceof QueryParseException) { queryParseExc = (QueryParseException) nextThrowable; } else { LOGGER.trace("Not a query parse exception, another? " + throwable.getClass().toString() + "->" + throwable.getCause()); nextThrowable = nextThrowable.getCause(); } } if (queryParseExc != null) { lineAndColumn = getSyntaxErrorLineColLocation(queryParseExc.getMessage().toLowerCase(), "at line ", ",", ", column ", "."); whichSelectedTab = TAB_NUMBER_SPARQL; whichFocusJTextArea = sparqlInput; } else { LOGGER.debug("No query parse exception found so the caret cannot be positioned"); } } if (lineAndColumn[0] > 0 && lineAndColumn[1] > 0) { LOGGER.debug("Attempt to set assertions caret to position (" + lineAndColumn[0] + "," + lineAndColumn[1] + ")"); final int finalLineNumber = lineAndColumn[0] - 1; final int finalColumnNumber = lineAndColumn[1] - 1; final int finalWhichSelectedTab = whichSelectedTab; final JTextArea finalWhichFocusJTextArea = whichFocusJTextArea; SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(finalWhichSelectedTab); try { finalWhichFocusJTextArea.setCaretPosition( finalWhichFocusJTextArea.getLineStartOffset(finalLineNumber) + finalColumnNumber); finalWhichFocusJTextArea.requestFocusInWindow(); } catch (Throwable throwable) { LOGGER.warn("Cannot set " + finalWhichFocusJTextArea.getName() + " carat position to (" + finalLineNumber + "," + finalColumnNumber + ") on tab " + finalWhichSelectedTab, throwable); } } }); } return statusMessage; } /** * Extract the line and column position in a reported syntax error. The * information is returned in a two-element int array. Index 0 is the line * number and index 1 is the column number. If the line or column number * cannot be found in the message, these values will be -1. * * @param message * The syntax error message containing the line and column position * of the error * @param lineNumStartToken * The token preceeding the line number in the message * @param lineNumEndToken * The token following the line number in the message * @param colNumStartToken * The token preceeding the column number in the message * @param colNumEndToken * The token following the column number in the message * * @return A 2-element array with the line number in element 0 and the column * number in element 1. The value for the line and/or column will be * -1 if the information cannot be found in the message. */ private int[] getSyntaxErrorLineColLocation(String message, String lineNumStartToken, String lineNumEndToken, String colNumStartToken, String colNumEndToken) { final int[] lineAndColumn = new int[2]; lineAndColumn[0] = -1; lineAndColumn[1] = -1; final int startLinePos = message.indexOf(lineNumStartToken); final int endLinePos = message.substring(startLinePos).indexOf(lineNumEndToken) + startLinePos; final int startColPos = message.indexOf(colNumStartToken); final int endColPos = message.substring(startColPos).indexOf(colNumEndToken) + startColPos; if (startLinePos > -1 && startColPos > startLinePos) { try { lineAndColumn[0] = Integer .parseInt(message.substring(startLinePos + lineNumStartToken.length(), endLinePos).trim()); lineAndColumn[1] = Integer .parseInt(message.substring(startColPos + colNumStartToken.length(), endColPos).trim()); } catch (Throwable parseError) { LOGGER.warn("Cannot extract line/col from exception message: " + message, parseError); } } return lineAndColumn; } /** * Check whether it is okay to start a new process (e.g. assure that no * threads are currently executing against the model). If a thread is * currently running, a message dialog is presented to the user indicate what * process is running and that a new process cannot be started. * * @return True if a new thread may be started */ private boolean okToRunThread() { final boolean okToRun = runningOperation == null; if (!okToRun) { JOptionPane.showMessageDialog(this, "A process is already running and must complete.\n\n" + "The program is currently " + runningOperation.description(), "Operation in Process", JOptionPane.INFORMATION_MESSAGE); } return okToRun; } /** * Setup to load the assertions and start a thread */ private void runModelLoad() { if (okToRunThread()) { runningOperation = Operation.LOAD_ASSERTIONS; new Thread(this).start(); } } /** * Setup to run the reasoner and start a thread */ private void runReasoner() { if (okToRunThread()) { runningOperation = Operation.CREATE_MODEL; new Thread(this).start(); } } /** * Setup to run the SPARQL query and start a thread */ private void runSparql() { if (okToRunThread()) { runningOperation = Operation.EXECUTE_SPARQL; new Thread(this).start(); } } /** * Setup to build the tree representation of the model. */ private void runCreateTreeFromModel() { if (okToRunThread()) { runningOperation = Operation.BUILD_TREE_VIEW; new Thread(this).start(); } } /** * Setup to build the list of inferred triples in the model and start a thread */ private void runIdentifyInferredTriples() { if (okToRunThread()) { runningOperation = Operation.IDENTIFY_ASSERTIONS; new Thread(this).start(); } } /** * Setup to export the model and start a thread */ private void runModelExport() { if (okToRunThread()) { runningOperation = Operation.EXPORT_MODEL; new Thread(this).start(); } } /** * Setup to export the SPARQL results to a file and start a thread */ private void runSparqlResultsExport() { if (okToRunThread()) { runningOperation = Operation.EXPORT_SPARQL_RESULTS; new Thread(this).start(); } } /** * Setup to expand all the tree nodes and start a thread */ private void runExpandAllTreeNodes() { if (okToRunThread()) { runningOperation = Operation.EXPAND_TREE; new Thread(this).start(); } } /** * Setup to collapse all tree nodes and start a thread */ private void runCollapseAllTreeNodes() { if (okToRunThread()) { runningOperation = Operation.COLLAPSE_TREE; new Thread(this).start(); } } /** * Execute the steps to run the reasoner * * @return The message to be presented on the status line */ private String reasonerExecution() { setStatus("Running reasoner..."); loadModel(); return "Reasoning complete"; } /** * Execute the steps to run the SPARQL query * * @return The message to be presented on the status line */ private String sparqlExecution() { String statusMessage; setStatus("Running SPARQL query..."); setWaitCursor(true); // Check if this is a local model SPARQL update if (sparqlInput.getText().toLowerCase().indexOf("delete") > -1 || sparqlInput.getText().toLowerCase().indexOf("insert") > -1) { statusMessage = callSparqlUpdateEngine(); } else { statusMessage = callSparqlEngine(); } areSparqlResultsInSyncWithModel = true; colorCodeTabs(); return statusMessage; } /** * Handle a SPARQL update request * * @return The message to be presented on the status line */ private String callSparqlUpdateEngine() { String serviceUrl; String message = "Update completed"; final SparqlTableModel tableModel = new SparqlTableModel(); final SparqlResultItemRenderer renderer = new SparqlResultItemRenderer( setupAllowMultilineResultOutput.isSelected()); renderer.setFont(sparqlResultsTable.getFont()); sparqlResultsTable.setDefaultRenderer(SparqlResultItem.class, renderer); tableModel.displayMessageInTable("SPARQL Update, No Results", new String[] {}); sparqlResultsTable.setModel(tableModel); serviceUrl = ((String) sparqlServiceUrl.getSelectedItem()).trim(); if (sparqlServiceUrl.getSelectedIndex() == 0 || serviceUrl.length() == 0) { // Updating the local model long originalAssertionCount = 0; long resultingAssertionCount = 0; final GraphStore graphStore = GraphStoreFactory.create(ontModel); originalAssertionCount = ontModel.size(); UpdateAction.parseExecute(sparqlInput.getText(), graphStore); resultingAssertionCount = ontModel.size(); message = "Local model update completed [Original Assertion Count:" + originalAssertionCount + " Resulting Assertion Count:" + resultingAssertionCount + "]"; /* * Assume the update modified the model: update counts then invalidate the * tree and inferences */ showModelTripleCounts(); isTreeInSyncWithModel = false; areInferencesInSyncWithModel = false; // Query history final SparqlQuery sparqlQuery = new SparqlQuery(sparqlInput.getText()); final QueryInfo queryInfo = new QueryInfo(sparqlQuery, sparqlServiceUrl.getSelectedIndex() == 0 ? null : sparqlServiceUrl.getSelectedItem().toString(), defaultGraphUri.getText(), tableModel); queryHistory.addQuery(queryInfo); } else { // Updating via a remote endpoint final UpdateRequest request = UpdateFactory.create(sparqlInput.getText()); UpdateProcessor processor; if (sparqlServiceUserId.getText().trim().length() == 0) { processor = UpdateExecutionFactory.createRemote(request, serviceUrl); } else { processor = UpdateExecutionFactory.createRemote(request, serviceUrl, new SimpleAuthenticator( sparqlServiceUserId.getText(), sparqlServicePassword.getPassword())); } processor.execute(); } return message; } /** * Handle a SPARQL query request, use the SPARQL engine and report the results * * @return The number of resulting rows */ private String callSparqlEngine() { QueryExecution qe; String serviceUrl; ResultSet resultSet = null; long numResults = 0; String message = null; final SparqlTableModel tableModel = new SparqlTableModel(); // Get the query final String queryString = sparqlInput.getText().trim(); /* * Query history initialized - in case the query fails it will be in the * history list */ final SparqlQuery sparqlQuery = new SparqlQuery(sparqlInput.getText()); QueryInfo queryInfo = new QueryInfo(sparqlQuery, sparqlServiceUrl.getSelectedIndex() == 0 ? null : sparqlServiceUrl.getSelectedItem().toString(), defaultGraphUri.getText(), null); queryHistory.addQuery(queryInfo); final Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); LOGGER.debug("Query Graph URIs? " + query.getGraphURIs()); serviceUrl = ((String) sparqlServiceUrl.getSelectedItem()).trim(); // Execute the query and obtain results if (query.getGraphURIs() != null && query.getGraphURIs().size() > 0) { LOGGER.debug("Query has Graph URIs: " + query.getGraphURIs().size()); qe = QueryExecutionFactory.create(query); } else if (sparqlServiceUrl.getSelectedIndex() == 0 || serviceUrl.length() == 0) { if (ontModel == null) { qe = QueryExecutionFactory.create(query, ModelFactory.createOntologyModel()); } else { qe = QueryExecutionFactory.create(query, ontModel); } } else { // ConnectionConfiguration final String defaultGraphUriText = defaultGraphUri.getText().trim(); // Check for default graph if (defaultGraphUriText.length() > 0) { // Use default graph definition // Check for User Id if (sparqlServiceUserId.getText().trim().length() == 0) { // Unauthenticated - open endpoint qe = QueryExecutionFactory.sparqlService(serviceUrl, query, defaultGraphUriText); } else { // Authenticated qe = QueryExecutionFactory.sparqlService(serviceUrl, query, defaultGraphUriText, new SimpleAuthenticator(sparqlServiceUserId.getText(), sparqlServicePassword.getPassword())); } } else { // No default graph // Check for User Id if (sparqlServiceUserId.getText().trim().length() == 0) { // Unauthenticated - open endpoint qe = QueryExecutionFactory.sparqlService(serviceUrl, query, new StarDogSparqlAuthenticator()); } else { // Authenticated qe = QueryExecutionFactory.sparqlService(serviceUrl, query, new SimpleAuthenticator( sparqlServiceUserId.getText(), sparqlServicePassword.getPassword())); } } } if (query.isDescribeType()) { final Model model = qe.execDescribe(); if (model != null) { tableModel.displayStatementsInTable(model.listStatements(), 1000, "Describe "); message = "DESCRIBE executed, resulting model size: " + model.size(); } else { message = "DESCRIBE executed, no model returned"; } } else if (query.isAskType()) { final boolean result = qe.execAsk(); message = "ASK executed, result: " + result; tableModel.displayMessageInTable(message, new String[] {}); } else if (query.isConstructType()) { final Model model = qe.execConstruct(); int numCreatedAssertions = 0; long numAddedAssertions = 0; if (model != null) { tableModel.displayStatementsInTable(model.listStatements(), 1000, "Constructed "); numCreatedAssertions = model.getGraph().size(); numAddedAssertions = ontModel.size(); ontModel.add(model); numAddedAssertions = ontModel.size() - numAddedAssertions; if (numAddedAssertions != 0) { // Assume the update modified the model: update counts then invalidate // the tree and inferences showModelTripleCounts(); isTreeInSyncWithModel = false; areInferencesInSyncWithModel = false; } } message = "CONSTRUCT executed [Created Assertions:" + numCreatedAssertions + " New Assertions:" + numAddedAssertions + "]"; } else { // Not a construct - assume select resultSet = qe.execSelect(); if (setupSparqlResultsToFile.isSelected()) { numResults = writeSparqlResultsDirectlyToFile(resultSet, new SparqlResultsFormatter(query, ontModel, setupApplyFormattingToLiteralValues.isSelected(), setupOutputFlagLiteralValues.isSelected(), setupOutputDatatypesForLiterals.isSelected(), setupOutputFqnNamespaces.isSelected())); /* * Release these results since writing directly to file often is used * for * very large result sets. Also, do not want to hold these results in * history */ resultSet = null; } } if (resultSet != null) { tableModel.setupModel(resultSet, query, ontModel, setupApplyFormattingToLiteralValues.isSelected(), setupOutputFlagLiteralValues.isSelected(), setupOutputDatatypesForLiterals.isSelected(), setupOutputFqnNamespaces.isSelected(), setupDisplayImagesInSparqlResults.isSelected()); } final SparqlResultItemRenderer renderer = new SparqlResultItemRenderer( setupAllowMultilineResultOutput.isSelected()); renderer.setFont(sparqlResultsTable.getFont()); sparqlResultsTable.setDefaultRenderer(SparqlResultItem.class, renderer); sparqlResultsTable.setModel(tableModel); numResults = tableModel.getRowCount(); if (numResults > 0) { // TODO Allow configuration to switch auto-resizing on/off (e.g. // horizontal scrolling) GuiUtilities.initColumnSizes(sparqlResultsTable, tableModel); } // Important - free up resources used running the query qe.close(); // Update query history with table model (which may be null) queryInfo = new QueryInfo(sparqlQuery, sparqlServiceUrl.getSelectedIndex() == 0 ? null : sparqlServiceUrl.getSelectedItem().toString(), defaultGraphUri.getText(), tableModel); queryHistory.addQuery(queryInfo); if (message == null) { message = "Number of query results: " + numResults; } return message; } /** * Get the set of defined ontology file formats that the program can load as * a CSV list String * * @return The known ontology file formats as a CSV list */ public static final String getFormatsAsCSV() { return getArrayAsCSV(FORMATS); } /** * Create a CSV list from a String array * * @param array * An array * @return The array values in a CSV list */ public static final String getArrayAsCSV(Object[] array) { StringBuffer csv; csv = new StringBuffer(); for (Object value : array) { if (csv.length() > 0) { csv.append(", "); } csv.append(value.toString()); } return csv.toString(); } /** * Set the RDF file , where the ontology is located * * @param pRdfFileSource * The FileSource of the ontology */ public void setRdfFileSource(FileSource pRdfFileSource) { rdfFileSource = pRdfFileSource; rdfFileSaved = true; setTitle(); } /** * Set the SPARQL query file * * @param pSparqlQueryFile * The FileSource of the SPARQL query */ public void setSparqlQueryFile(File pSparqlQueryFile) { sparqlQueryFile = pSparqlQueryFile; sparqlQuerySaved = true; addRecentSparqlFile(pSparqlQueryFile); setTitle(); } /** * Set the window title */ private void setTitle() { String title; title = "Semantic Workbench"; if (assertionLanguage != null) { title += " - " + assertionLanguage; } if (rdfFileSource != null) { title += " - " + rdfFileSource.getName(); if (!rdfFileSaved) { title += "*"; } } if (sparqlQueryFile != null) { title += " (" + sparqlQueryFile.getName(); if (!sparqlQuerySaved) { title += "*"; } title += ")"; } setTitle(title); } /** * Convert the ontology into a set of Strings representing the inferred * triples * * @return A Map containing Lists that relate subjects to objects and * predicates */ private String identifyInferredTriples() { StringWriter writer; Model tempModel; setStatus("Identifying inferences in the model..."); setWaitCursor(true); LOGGER.debug("Compute differences between reasoned and non-reasoned models to show inferred triples"); tempModel = ontModel.difference(ontModel.getBaseModel()); LOGGER.debug("Model differences computed to identify inferred triples"); writer = new StringWriter(); tempModel.write(writer, assertionLanguage); LOGGER.debug( "String representation of differences created to show inferred triples using " + assertionLanguage); inferredTriples.setText(writer.toString()); areInferencesInSyncWithModel = true; colorCodeTabs(); // Select the inferences tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_INFERENCES); } }); return "Listing of inferred triples created in " + assertionLanguage; } /** * Create a model with a reasoner set based on the chosen reasoning level. * * @param reasoner * The reasoner from the ReasonerSelection enum to be used with * this model * * @return The created ontology model */ private OntModel createModel(ReasonerSelection reasoner) { OntModel model = null; LOGGER.debug("Create reasoner: " + reasoner.reasonerName()); model = ModelFactory.createOntologyModel(reasoner.jenaSpecification()); model.setStrictMode(setupEnableStrictMode.isSelected()); return model; } /** * Load the assertions into the ontology model. */ private void loadModel() { String modelFormat; Throwable lastThrowable = null; modelFormat = null; isTreeInSyncWithModel = false; areInferencesInSyncWithModel = false; areSparqlResultsInSyncWithModel = false; if (language.getSelectedIndex() == 0) { for (String format : FORMATS) { try { tryFormat(format); modelFormat = format; break; } catch (Throwable throwable) { LOGGER.debug("Error processing assertions as format: " + format, throwable); lastThrowable = throwable; } } } else { try { tryFormat(language.getSelectedItem().toString()); modelFormat = language.getSelectedItem().toString(); } catch (Throwable throwable) { LOGGER.error("Error processing assertions as format: " + language.getSelectedItem().toString(), throwable); lastThrowable = throwable; } } if (modelFormat == null) { if (ontModel != null) { ontModel.close(); } invalidateModel(false); if (language.getSelectedIndex() == 0) { throw new IllegalStateException( "The assertions cannot be loaded using known languages.\nTried: " + getFormatsAsCSV(), lastThrowable); } else { throw new IllegalStateException("The assertions cannot be loaded using the input format: " + language.getSelectedItem().toString(), lastThrowable); } } else { LOGGER.info("Loaded assertions" + " using format: " + modelFormat); showModelTripleCounts(); } assertionLanguage = modelFormat; setTitle(); } /** * Display the triple counts from the local model */ private void showModelTripleCounts() { if (ontModel != null) { assertedTripleCount.setText(INTEGER_COMMA_FORMAT.format(ontModel.getBaseModel().size()) + ""); inferredTripleCount .setText(INTEGER_COMMA_FORMAT.format(ontModel.size() - ontModel.getBaseModel().size()) + ""); } else { assertedTripleCount.setText(NOT_APPLICABLE_DISPLAY); inferredTripleCount.setText(NOT_APPLICABLE_DISPLAY); } } /** * Attempt to load a set of assertions with the supplied format (e.g. N3, * RDF/XML, etc) * * @param format * The format to use, must be a value in the array FORMATS * * @throws IOException * If the file cannot be read */ private void tryFormat(String format) throws IOException { InputStream inputStream = null; try { LOGGER.debug("Start " + reasoningLevel.getSelectedItem().toString() + " model load and setup with format " + format); if (hasIncompleteAssertionsInput) { inputStream = new ProgressMonitorInputStream(this, "Reading file " + rdfFileSource.getAbsolutePath(), rdfFileSource.getInputStream()); if (rdfFileSource.isUrl()) { final ProgressMonitor pm = ((ProgressMonitorInputStream) inputStream).getProgressMonitor(); pm.setMaximum((int) rdfFileSource.length()); } LOGGER.debug("Using a ProgressMonitorInputStream"); } else { inputStream = new ByteArrayInputStream(assertionsInput.getText().getBytes("UTF-8")); } ontModel = createModel((ReasonerSelection) reasoningLevel.getSelectedItem()); LOGGER.debug("Begin loading model"); ontModel.read(inputStream, null, format.toUpperCase()); LOGGER.debug(reasoningLevel.getSelectedItem().toString() + " model load and setup completed"); } finally { if (inputStream != null) { try { inputStream.close(); } catch (Throwable throwable) { LOGGER.error("Error closing input file", throwable); } } } } /** * Clears the tree model */ private void clearTree() { ontModelTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("No Tree Generated"))); isTreeInSyncWithModel = true; colorCodeTabs(); } /** * Set the maximum number of individuals to display for each class in the tree * view of the model */ private void setMaximumIndividualsPerClassInTree() { final String currentValue = properties .getProperty(ConfigurationProperty.MAX_INDIVIDUALS_PER_CLASS_IN_TREE.key(), "0"); final String maximumChildNodes = JOptionPane.showInputDialog(this, "Enter the maximum number of individuals to be displayed\n" + "under each class in the tree view of the model.\n\n" + "Enter the value 0 (zero) to allow all the individuals\n" + "to be shown.\n\n" + "The current setting is: " + currentValue, "Limit Individuals Displayed Per Class in the Tree View", JOptionPane.QUESTION_MESSAGE); if (maximumChildNodes != null && maximumChildNodes.trim().length() > 0) { try { final int maxNodes = Integer.parseInt(maximumChildNodes); if (maxNodes >= 0) { properties.setProperty(ConfigurationProperty.MAX_INDIVIDUALS_PER_CLASS_IN_TREE.key(), maxNodes + ""); } else { JOptionPane.showMessageDialog(this, "The value entered for the maximum number of individuals\n" + "was less than 0. The original setting is unchanged.", "Negative Value Entered", JOptionPane.ERROR_MESSAGE); } } catch (Throwable throwable) { JOptionPane.showMessageDialog(this, "The value entered for the maximum number of individuals\n" + "was not a number. The original setting is unchanged.", "Non-numeric Value Entered", JOptionPane.ERROR_MESSAGE); } } } /** * Build a tree representation of the semantic model * * TODO aggregate items from duplicate nodes * * TODO Consider more efficient approach that scans the model once rather than * querying for each class, individual and property collection * * @see #addClassesToTree(DefaultMutableTreeNode, String) * @see OntologyTreeCellRenderer * * @return The message to be presented on the status line */ private String createTreeFromModel() { final String messagePrefix = "Creating the tree view"; DefaultMutableTreeNode treeTopNode; DefaultMutableTreeNode classesNode; String message; int maxIndividualsPerClass; setStatus(messagePrefix); setWaitCursor(true); clearTree(); try { maxIndividualsPerClass = Integer.parseInt( properties.getProperty(ConfigurationProperty.MAX_INDIVIDUALS_PER_CLASS_IN_TREE.key(), "0")); } catch (Throwable throwable) { maxIndividualsPerClass = 0; } treeTopNode = new DefaultMutableTreeNode("Model"); // Ignore latest value since we have just released the old tree (if there // was one) MemoryWarningSystem.hasLatestAvailableTenuredGenAfterCollectionChanged(this); // Classes classesNode = new DefaultMutableTreeNode("Classes"); treeTopNode.add(classesNode); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Building list of classes in the model"); } try { addClassesToTree(classesNode, maxIndividualsPerClass, messagePrefix); // Select the tree view tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_TREE_VIEW); } }); message = "Tree view of current model created"; if (maxIndividualsPerClass > 0) { message += " (individuals per class limited to " + maxIndividualsPerClass + ")"; } ontModelTree.setModel(new DefaultTreeModel(treeTopNode)); isTreeInSyncWithModel = true; colorCodeTabs(); } catch (IllegalStateException ise) { // Memory exhaustion, keep the incomplete tree SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_TREE_VIEW); } }); message = "Insufficient memory for entire tree, partial tree view of current model created"; ontModelTree.setModel(new DefaultTreeModel(treeTopNode)); isTreeInSyncWithModel = false; colorCodeTabs(); throw ise; } catch (RuntimeException rte) { if (rte.getMessage().contains("canceled by user")) { message = rte.getMessage(); } else { throw rte; } } return message; } /** * Add the classes to the tree view * * @see #addIndividualsToTree(OntClass, DefaultMutableTreeNode, * ProgressMonitor) * * @param classesNode * The classes parent node in the tree * @param maxIndividualsPerClass * The maximum number of individuals to display in each class * @param messagePrefix * Prefix for display messages */ private void addClassesToTree(DefaultMutableTreeNode classesNode, int maxIndividualsPerClass, String messagePrefix) { ProgressMonitor progress = null; DefaultMutableTreeNode oneClassNode; List<OntClass> ontClasses; ExtendedIterator<OntClass> classesIterator; int classNumber; try { classesIterator = ontModel.listClasses(); setStatus(messagePrefix + "... obtaining the list of classes"); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of classes built"); } ontClasses = new ArrayList<OntClass>(); while (classesIterator.hasNext()) { ontClasses.add(classesIterator.next()); } progress = new ProgressMonitor(this, "Create the model tree view", "Setting up the class list", 0, ontClasses.size()); Collections.sort(ontClasses, new OntClassComparator()); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of classes sorted. Num classes:" + ontClasses.size()); } classNumber = 0; for (OntClass ontClass : ontClasses) { setStatus(messagePrefix + " for class " + ontClass); if (MemoryWarningSystem.hasLatestAvailableTenuredGenAfterCollectionChanged(this) && MemoryWarningSystem .getLatestAvailableTenuredGenAfterCollection() < MINIMUM_BYTES_REQUIRED_FOR_TREE_BUILD) { throw new IllegalStateException( "Insufficient memory available to complete building the tree (class iteration)"); } if (progress.isCanceled()) { throw new RuntimeException("Tree model creation canceled by user"); } progress.setNote(ontClass.toString()); progress.setProgress(++classNumber); // Check whether class is to be skipped if (LOGGER.isTraceEnabled()) { LOGGER.trace("Check if class to be skipped: " + ontClass.getURI()); for (String skipClass : classesToSkipInTree.keySet()) { LOGGER.trace("Class to skip: " + skipClass + " equal? " + (skipClass.equals(ontClass.getURI()))); } } if (filterEnableFilters.isSelected() && classesToSkipInTree.get(ontClass.getURI()) != null) { LOGGER.debug("Class to be skipped: " + ontClass.getURI()); continue; } if (ontClass.isAnon()) { // Show anonymous classes based on configuration if (filterShowAnonymousNodes.isSelected()) { oneClassNode = new DefaultMutableTreeNode( new WrapperClass(ontClass.getId().getLabelString(), "[Anonymous class]", true)); } else { LOGGER.debug("Skip anonymous class: " + ontClass.getId().getLabelString()); continue; } } else { oneClassNode = new DefaultMutableTreeNode(new WrapperClass(ontClass.getLocalName(), ontClass.getURI(), showFqnInTree.isSelected())); LOGGER.debug("Add class node: " + ontClass.getLocalName() + " (" + ontClass.getURI() + ")"); } classesNode.add(oneClassNode); addIndividualsToTree(ontClass, oneClassNode, maxIndividualsPerClass, progress); } } finally { if (progress != null) { progress.close(); } } } /** * Add individuals of a class to the tree * * @see #addStatementsToTree(OntClass, Individual, DefaultMutableTreeNode, * ProgressMonitor) * * @param ontClass * The class of individuals to be added * @param oneClassNode * The class's node in the tree * @param maxIndividualsPerClass * The maximum number of individuals to display in each class * @param progress * A progress monitor to display progress to the user */ private void addIndividualsToTree(OntClass ontClass, DefaultMutableTreeNode oneClassNode, int maxIndividualsPerClass, ProgressMonitor progress) { DefaultMutableTreeNode oneIndividualNode; List<Individual> individuals; ExtendedIterator<Individual> individualsIterator; int nodeCount = 0; // Individuals if (LOGGER.isTraceEnabled()) { LOGGER.trace("Get list of individuals for " + ontClass.getURI()); } individualsIterator = ontModel.listIndividuals(ontClass); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of individuals built for " + ontClass.getURI() + " Is there at least one individual? " + individualsIterator.hasNext()); } individuals = new ArrayList<Individual>(); while (individualsIterator.hasNext()) { individuals.add(individualsIterator.next()); ++nodeCount; if (maxIndividualsPerClass > 0 && nodeCount >= maxIndividualsPerClass) { break; } } Collections.sort(individuals, new IndividualComparator()); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of individuals sorted for " + ontClass.getURI()); } for (Individual individual : individuals) { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Next individual: " + individual.getLocalName()); } if (MemoryWarningSystem.hasLatestAvailableTenuredGenAfterCollectionChanged(this) && MemoryWarningSystem .getLatestAvailableTenuredGenAfterCollection() < MINIMUM_BYTES_REQUIRED_FOR_TREE_BUILD) { throw new IllegalStateException( "Insufficient memory available to complete building the tree (individual iteration)"); } if (individual.isAnon()) { // Show anonymous individuals based on configuration if (filterShowAnonymousNodes.isSelected()) { if (individual.getId().getLabelString() != null) { oneIndividualNode = new DefaultMutableTreeNode(new WrapperInstance( individual.getId().getLabelString(), "[Anonymous individual]", true)); } else { oneIndividualNode = new DefaultMutableTreeNode(new WrapperInstance(individual.toString(), "[null label - anonymous individual]", true)); } } else { LOGGER.debug("Skip anonymous individual: " + individual.getId().getLabelString()); continue; } } else if (individual.getLocalName() != null) { oneIndividualNode = new DefaultMutableTreeNode(new WrapperInstance(individual.getLocalName(), individual.getURI(), showFqnInTree.isSelected())); } else { oneIndividualNode = new DefaultMutableTreeNode( new WrapperInstance(individual.toString(), "[null name - non anonymous]", true)); } oneClassNode.add(oneIndividualNode); addStatementsToTree(individual, oneIndividualNode, progress); } } /** * Add statements to the tree (predicates and properties) * * @param individual * The individual whose statements are to be added to the tree * @param oneIndividualNode * The individual's node in the tree * @param progress * A progress monitor to display progress to the user */ private void addStatementsToTree(Individual individual, DefaultMutableTreeNode oneIndividualNode, ProgressMonitor progress) { DefaultMutableTreeNode onePropertyNode; List<Statement> statements; Property property; RDFNode rdfNode; Literal literal; StmtIterator stmtIterator; // Properties (predicates) and Objects if (LOGGER.isTraceEnabled()) { LOGGER.trace("Get list of statements for " + individual.getURI()); } stmtIterator = individual.listProperties(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of statements built for " + individual.getURI()); } statements = new ArrayList<Statement>(); while (stmtIterator.hasNext()) { statements.add(stmtIterator.next()); } Collections.sort(statements, new StatementComparator()); if (LOGGER.isTraceEnabled()) { LOGGER.trace("List of statements sorted for " + individual.getURI()); } for (Statement statement : statements) { property = statement.getPredicate(); // Check whether predicate is to be skipped if (filterEnableFilters.isSelected() && predicatesToSkipInTree.get(property.getURI()) != null) { continue; } rdfNode = statement.getObject(); if (MemoryWarningSystem.hasLatestAvailableTenuredGenAfterCollectionChanged(this) && MemoryWarningSystem .getLatestAvailableTenuredGenAfterCollection() < MINIMUM_BYTES_REQUIRED_FOR_TREE_BUILD) { throw new IllegalStateException( "Insufficient memory available to complete building the tree (statement iteration)"); } if (property.isAnon()) { // Show anonymous properties based on configuration if (filterShowAnonymousNodes.isSelected()) { if (rdfNode.isLiteral()) { onePropertyNode = new DefaultMutableTreeNode(new WrapperDataProperty( property.getId().getLabelString(), "[Anonymous data property]", true)); } else { onePropertyNode = new DefaultMutableTreeNode(new WrapperObjectProperty( property.getId().getLabelString(), "[Anonymous object property]", true)); } } else { LOGGER.debug("Skip anonymous property: " + property.getId().getLabelString()); continue; } } else if (rdfNode.isLiteral() || !statement.getResource().isAnon() || filterShowAnonymousNodes.isSelected()) { if (rdfNode.isLiteral()) { onePropertyNode = new DefaultMutableTreeNode(new WrapperDataProperty(property.getLocalName(), property.getURI(), showFqnInTree.isSelected())); } else { onePropertyNode = new DefaultMutableTreeNode(new WrapperObjectProperty(property.getLocalName(), property.getURI(), showFqnInTree.isSelected())); } } else { LOGGER.debug("Skip concrete property of an anonymous individual: " + property.getURI() + ", " + statement.getResource().getId().getLabelString()); continue; } oneIndividualNode.add(onePropertyNode); if (rdfNode.isLiteral()) { literal = statement.getLiteral(); if (setupOutputDatatypesForLiterals.isSelected()) { onePropertyNode.add(new DefaultMutableTreeNode(new WrapperLiteral( ValueFormatter.getInstance().applyFormat(literal.getString(), literal.getDatatypeURI()) + " [" + literal.getDatatypeURI() + "]"))); } else { onePropertyNode.add(new DefaultMutableTreeNode(new WrapperLiteral(ValueFormatter.getInstance() .applyFormat(literal.getString(), literal.getDatatypeURI())))); } } else { if (statement.getResource().isAnon()) { if (filterShowAnonymousNodes.isSelected()) { onePropertyNode.add(new DefaultMutableTreeNode(new WrapperInstance( statement.getResource().getId().getLabelString(), "[Anonymous individual]", true))); } else { LOGGER.debug( "Skip anonymous individual: " + statement.getResource().getId().getLabelString()); continue; } } else { onePropertyNode.add( new DefaultMutableTreeNode(new WrapperInstance(statement.getResource().getLocalName(), statement.getResource().getURI(), showFqnInTree.isSelected()))); } } } } /** * Find a String value within an array of Strings. Return the index position * where the value was found. * * @param array * An array of string to search * @param name * The value to find in the array * * @return The position where the value was found in the array. Will be * equal to the constant UNKNOWN if the value cannot be found in the * collection of known reasoning levels */ public static final int getIndexValue(String[] array, String name) { Integer indexValue; indexValue = null; for (int index = 0; index < array.length && indexValue == null; ++index) { if (array[index].toUpperCase().equals(name.toUpperCase())) { indexValue = index; } } return indexValue == null ? UNKNOWN : indexValue; } /** * Handle left-mouse click on ontology model tree. * * If the selected node is an individual, the tree will be searched forward * (down) to jump to the next matching individual in the tree * * Otherwise, no action will be taken in response to the left mouse click in * the tree. * * @param event * The mouse click event */ private void processOntologyModelTreeLeftClick(MouseEvent event) { final Wrapper wrapper = getSelectedWrapperInTree(event); findMatchingIndividual(wrapper, true); } /** * Find a matching individual in the tree. * * @param wrapper * The individual to be matched * @param forward * True to search forward, false to search backward */ private void findMatchingIndividual(Wrapper wrapper, boolean forward) { final DefaultTreeModel treeModel = (DefaultTreeModel) ontModelTree.getModel(); final DefaultMutableTreeNode finalMatchAt; DefaultMutableTreeNode latestMatchAt = null; DefaultMutableTreeNode firstMatchAt = null; boolean foundClickedNode = false; boolean wrappedAroundBackward = false; if (wrapper != null && wrapper instanceof WrapperInstance) { final DefaultMutableTreeNode node = (DefaultMutableTreeNode) treeModel.getRoot(); @SuppressWarnings("unchecked") final Enumeration<DefaultMutableTreeNode> nodeEnumeration = node.preorderEnumeration(); while (nodeEnumeration.hasMoreElements()) { final DefaultMutableTreeNode nextNode = nodeEnumeration.nextElement(); if (nextNode.getUserObject() instanceof Wrapper) { final Wrapper nodeWrapper = (Wrapper) nextNode.getUserObject(); if (wrapper.getUuid().equals(nodeWrapper.getUuid())) { foundClickedNode = true; if (forward) { // If there is one past this location then // use it, otherwise wrap back to top latestMatchAt = null; } else { if (firstMatchAt != null || latestMatchAt != null) { // Searching backward and have found a previous one break; } wrappedAroundBackward = true; } } else if (!wrapper.getUuid().equals(nodeWrapper.getUuid()) && wrapper.getClass().equals(wrapper.getClass()) && wrapper.getLocalName().equals(nodeWrapper.getLocalName()) && wrapper.getUri().equals(nodeWrapper.getUri())) { if (firstMatchAt == null && !foundClickedNode) { // First one found, keep it in case we wrap around firstMatchAt = nextNode; LOGGER.debug("Found first matching node: search UUID: " + wrapper.getUuid() + " found UUID: " + nodeWrapper.getUuid()); } else { // Keep track of latest one found latestMatchAt = nextNode; LOGGER.debug("Found a following matching node: search UUID: " + wrapper.getUuid() + " found UUID: " + nodeWrapper.getUuid()); // If going forward then this is the next match if (forward && foundClickedNode) { break; } } } } } if ((!forward || foundClickedNode) && latestMatchAt != null) { finalMatchAt = latestMatchAt; if (forward) { setStatus("Next " + wrapper.getLocalName() + " found"); } else { if (wrappedAroundBackward) { setStatus("Wrapped to bottom of tree and found a " + wrapper.getLocalName()); } else { setStatus("Previous " + wrapper.getLocalName() + " found"); } } } else if (firstMatchAt != null) { finalMatchAt = firstMatchAt; if (forward) { setStatus("Wrapped to top of tree and found a " + wrapper.getLocalName()); } else { setStatus("Previous " + wrapper.getLocalName() + " found"); } } else { finalMatchAt = null; setStatus(wrapper.getLocalName() + " could not be found elsewhere in the tree"); } if (finalMatchAt != null) { ontModelTree.setExpandsSelectedPaths(true); // Scroll to the selected node SwingUtilities.invokeLater(new Runnable() { public void run() { ontModelTree.setSelectionPath(new TreePath(treeModel.getPathToRoot(finalMatchAt))); ontModelTree.scrollPathToVisible(new TreePath(treeModel.getPathToRoot(finalMatchAt))); final Rectangle visible = ontModelTree.getVisibleRect(); visible.x = 0; ontModelTree.scrollRectToVisible(visible); } }); } } } /** * Handle right-mouse click on ontology model tree. * * If the selected node is a class or property it will be added to the list of * suppressed classes and properties so that it won't show up in the tree. * * If the selected node is an individual, the tree will be searched backward * (up) to jump to the previous matching individual in the tree * * Otherwise, no action will be taken in response to the right mouse click in * the tree. * * @param event * The mouse click event */ private void processOntologyModelTreeRightClick(MouseEvent event) { final Wrapper wrapper = getSelectedWrapperInTree(event); if (wrapper != null) { if (wrapper instanceof WrapperClass || wrapper instanceof WrapperDataProperty || wrapper instanceof WrapperObjectProperty) { final FilterValuePopup popup = new FilterValuePopup(wrapper); popup.show(event.getComponent(), event.getX(), event.getY()); } else if (wrapper instanceof WrapperInstance) { findMatchingIndividual(wrapper, false); } } } /** * Invalidates the existing ontology model. * * @param alterControls * Whether or not the current enable/disable setting of GUI controls * should be updated */ private void invalidateModel(boolean alterControls) { if (ontModel != null) { ontModel.close(); } ontModel = null; showModelTripleCounts(); reasoningLevel.setToolTipText(((ReasonerSelection) reasoningLevel.getSelectedItem()).description()); isTreeInSyncWithModel = false; areInferencesInSyncWithModel = false; areSparqlResultsInSyncWithModel = false; if (alterControls) { enableControls(true); } } /** * Get the chosen Wrapper from the tree node that was clicked on. * * @param event * The mouse click event * * @return The Wrapper instance or null if the node is not a Wrapper */ private Wrapper getSelectedWrapperInTree(MouseEvent event) { Wrapper chosenWrapper = null; LOGGER.debug("Tree mouse event: " + event.paramString()); final TreePath path = ontModelTree.getPathForLocation(event.getX(), event.getY()); if (path != null) { LOGGER.debug("Tree right-mouse event on: " + path.getLastPathComponent() + " of class " + path.getLastPathComponent().getClass()); if (path.getLastPathComponent() instanceof DefaultMutableTreeNode) { final DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent(); final Object selectedObject = selectedNode.getUserObject(); LOGGER.debug("Class of object in the selected tree node: " + selectedObject.getClass().getName()); if (selectedObject instanceof Wrapper) { chosenWrapper = (Wrapper) selectedObject; LOGGER.debug("Wrapper found: " + selectedObject); } } } return chosenWrapper; } /** * Allow the user to select a file, which is expected to be an ontology, and * then load the file. */ private void openOntologyFile() { JFileChooser fileChooser; FileFilter defaultFileFilter = null; FileFilter preferredFileFilter = null; File chosenFile; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(lastDirectoryUsed); for (FileFilterDefinition filterDefinition : FileFilterDefinition.values()) { if (filterDefinition.name().startsWith("ONTOLOGY")) { final FileFilter fileFilter = new SuffixFileFilter(filterDefinition.description(), filterDefinition.acceptedSuffixes()); if (filterDefinition.isPreferredOption()) { preferredFileFilter = fileFilter; } fileChooser.addChoosableFileFilter(fileFilter); if (filterDefinition.description().equals(latestChosenRdfFileFilterDescription)) { defaultFileFilter = fileFilter; } } } if (defaultFileFilter != null) { fileChooser.setFileFilter(defaultFileFilter); } else if (latestChosenRdfFileFilterDescription != null && latestChosenRdfFileFilterDescription.startsWith("All")) { fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter()); } else if (preferredFileFilter != null) { fileChooser.setFileFilter(preferredFileFilter); } fileChooser.setDialogTitle("Open Assertions File"); fileChooser.showOpenDialog(this); try { latestChosenRdfFileFilterDescription = fileChooser.getFileFilter().getDescription(); } catch (Throwable throwable) { LOGGER.warn("Unable to determine which ontology file filter was chosen", throwable); } chosenFile = fileChooser.getSelectedFile(); if (chosenFile != null) { setupToLoadOntologyFile(new FileSource(chosenFile)); } } /** * Loads the assertions from a URL (e.g. across the network) */ private void openOntologyUrl() { String urlString = null; URL url = null; do { try { urlString = JOptionPane.showInputDialog(this, "Input the URL for the remote ontology file to load.", "Input Ontology File URL", JOptionPane.QUESTION_MESSAGE); if (urlString != null) { urlString = urlString.trim(); if (urlString.length() > 0) { url = new URL(urlString); } } } catch (Throwable throwable) { LOGGER.error("Unable to open the URL", throwable); JOptionPane.showMessageDialog(this, "Incorrect format for a URL, cannot be parsed\n" + urlString + "\n\n" + throwable.getMessage(), "Incorrect URL Format", JOptionPane.ERROR_MESSAGE); url = null; } } while (url == null && urlString != null && urlString.length() > 0); if (url != null) { setupToLoadOntologyFile(new FileSource(url)); } } /** * Allow the user to select a file, which is expected to be an ontology, and * then load the file. */ private void openSparqlQueryFile() { JFileChooser fileChooser; FileFilter defaultFileFilter = null; FileFilter preferredFileFilter = null; File chosenFile; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(lastDirectoryUsed); for (FileFilterDefinition filterDefinition : FileFilterDefinition.values()) { if (filterDefinition.name().startsWith("SPARQL")) { final FileFilter fileFilter = new SuffixFileFilter(filterDefinition.description(), filterDefinition.acceptedSuffixes()); if (filterDefinition.isPreferredOption()) { preferredFileFilter = fileFilter; } fileChooser.addChoosableFileFilter(fileFilter); if (filterDefinition.description().equals(latestChosenSparqlFileFilterDescription)) { defaultFileFilter = fileFilter; } } } if (defaultFileFilter != null) { fileChooser.setFileFilter(defaultFileFilter); } else if (latestChosenSparqlFileFilterDescription != null && latestChosenSparqlFileFilterDescription.startsWith("All")) { fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter()); } else if (preferredFileFilter != null) { fileChooser.setFileFilter(preferredFileFilter); } fileChooser.setDialogTitle("Open SPARQL Query File"); fileChooser.showOpenDialog(this); try { latestChosenSparqlFileFilterDescription = fileChooser.getFileFilter().getDescription(); } catch (Throwable throwable) { LOGGER.warn("Unable to determine which SPARQL file filter was chosen", throwable); } chosenFile = fileChooser.getSelectedFile(); if (chosenFile != null) { loadSparqlQueryFile(chosenFile); } } /** * Open a recently used ontology file chosen from the file menu. * * @param obj * The menu item selected - associated with the recently used file */ private void openRecentOntologyFile(Object obj) { int chosenFileIndex = -1; for (int index = 0; index < fileOpenRecentTriplesFile.length; ++index) { if (obj == fileOpenRecentTriplesFile[index]) { chosenFileIndex = index; } } if (chosenFileIndex > -1) { setupToLoadOntologyFile(recentAssertionsFiles.get(chosenFileIndex)); } } /** * Open a recently used SPARQL query file chosen from the file menu. * * @param obj * The menu item selected - associated with the recently used file */ private void openRecentSparqlQueryFile(Object obj) { int chosenFileIndex = -1; for (int index = 0; index < fileOpenRecentSparqlFile.length; ++index) { if (obj == fileOpenRecentSparqlFile[index]) { chosenFileIndex = index; } } if (chosenFileIndex > -1) { loadSparqlQueryFile(recentSparqlFiles.get(chosenFileIndex)); } } /** * Load the provided file as an ontology replacing any assertions currently * in the assertions text area. * * @return The message to be presented on the status line */ private String loadOntologyFile() { final int chunkSize = 32000; StringBuilder allData; char[] chunk; long totalBytesRead = 0; int chunksRead = 0; int maxChunks; int bytesRead = -1; ProgressMonitor monitor = null; Reader reader = null; String message; boolean loadCanceled = false; if (rdfFileSource.isFile()) { lastDirectoryUsed = rdfFileSource.getBackingFile().getParentFile(); } assertionsInput.setText(""); invalidateModel(false); allData = new StringBuilder(); chunk = new char[chunkSize]; setStatus("Loading file " + rdfFileSource.getAbsolutePath()); if (rdfFileSource.length() > 0 && rdfFileSource.length() < MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA) { maxChunks = (int) (rdfFileSource.length() / chunkSize); } else { maxChunks = (int) (MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA / chunkSize); } if (rdfFileSource.length() % chunkSize > 0) { ++maxChunks; } // Assume the file can be loaded hasIncompleteAssertionsInput = false; monitor = new ProgressMonitor(this, "Loading assertions from " + rdfFileSource.getName(), "0 bytes read", 0, maxChunks); try { reader = new InputStreamReader(rdfFileSource.getInputStream()); while (!loadCanceled && (rdfFileSource.isUrl() || chunksRead < maxChunks) && (bytesRead = reader.read(chunk)) > -1) { totalBytesRead += bytesRead; chunksRead = (int) (totalBytesRead / chunk.length); if (chunksRead < maxChunks) { allData.append(chunk, 0, bytesRead); } if (chunksRead >= maxChunks) { monitor.setMaximum(chunksRead + 1); } monitor.setProgress(chunksRead); monitor.setNote("Read " + INTEGER_COMMA_FORMAT.format(totalBytesRead) + (rdfFileSource.isFile() ? " of " + INTEGER_COMMA_FORMAT.format(rdfFileSource.length()) : " bytes") + (chunksRead >= maxChunks ? " (Determining total file size)" : "")); loadCanceled = monitor.isCanceled(); } if (!loadCanceled && rdfFileSource.isUrl()) { rdfFileSource.setLength(totalBytesRead); } if (!loadCanceled && rdfFileSource.length() > MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA) { // The entire file was not loaded hasIncompleteAssertionsInput = true; } if (hasIncompleteAssertionsInput) { StringBuilder warningMessage; warningMessage = new StringBuilder(); warningMessage.append("The file is too large to display. However the entire file will be loaded\n"); warningMessage.append("into the model when it is built.\n\nDisplay size limit (bytes): "); warningMessage.append(INTEGER_COMMA_FORMAT.format(MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA)); if (rdfFileSource.isFile()) { warningMessage.append("\nFile size (bytes):"); warningMessage.append(INTEGER_COMMA_FORMAT.format(rdfFileSource.length())); } warningMessage.append("\n\n"); warningMessage.append("Note that the assersions text area will not permit editing\n"); warningMessage.append("of the partially loaded file and the 'save assertions' menu\n"); warningMessage.append("option will be disabled. These limitations are enabled\n"); warningMessage.append("to prevent the accidental loss of information from the\n"); warningMessage.append("source assertions file."); JOptionPane.showMessageDialog(this, warningMessage.toString(), "Max Display Size Reached", JOptionPane.WARNING_MESSAGE); // Add text to the assertions text area to highlight the fact that the // entire file was not loaded into the text area allData.insert(0, "# First " + INTEGER_COMMA_FORMAT.format(MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA) + " of " + INTEGER_COMMA_FORMAT.format(rdfFileSource.length()) + " bytes displayed\n\n"); allData.insert(0, "# INCOMPLETE VERSION of the file: " + rdfFileSource.getAbsolutePath() + "\n"); allData.append("\n\n# INCOMPLETE VERSION of the file: " + rdfFileSource.getAbsolutePath() + "\n"); allData.append("# First " + INTEGER_COMMA_FORMAT.format(MAX_ASSERTION_BYTES_TO_LOAD_INTO_TEXT_AREA) + " of " + INTEGER_COMMA_FORMAT.format(rdfFileSource.length()) + " bytes displayed\n"); } // Set the loaded assertions into the text area, cleaning up Windows \r\n // endings, if found if (!loadCanceled) { assertionsInput.setText(allData.toString().replaceAll("\r\n", "\n")); assertionsInput.setSelectionEnd(0); assertionsInput.setSelectionStart(0); assertionsInput.moveCaretPosition(0); assertionsInput.scrollRectToVisible(new Rectangle(0, 0, 1, 1)); message = "Loaded file" + (hasIncompleteAssertionsInput ? " (incomplete)" : "") + ": " + rdfFileSource.getName(); addRecentAssertedTriplesFile(rdfFileSource); // Select the assertions tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_ASSERTIONS); setFocusOnCorrectTextArea(); } }); } else { message = "Assertions file load canceled by user"; } } catch (Throwable throwable) { setStatus("Unable to load file: " + rdfFileSource.getName()); JOptionPane.showMessageDialog(this, "Error: Unable to read file\n\n" + rdfFileSource.getAbsolutePath() + "\n\n" + throwable.getMessage(), "Error Reading File", JOptionPane.ERROR_MESSAGE); LOGGER.error("Unable to load the file: " + rdfFileSource.getAbsolutePath(), throwable); message = "Unable to load the file: " + rdfFileSource.getAbsolutePath(); } finally { if (reader != null) { try { reader.close(); } catch (Throwable throwable) { LOGGER.error("Unable to close input file", throwable); } } if (monitor != null) { monitor.close(); } } return message; } /** * Extract a value located in a comment in a file and idnetified by a prefix * in front of the value. This is used to store information such as the * service URL for a sparql query as a comment in the query file. * * @param data * The line containing the prefix and associated value * @param prefix * The prefix identifying the value * * @return The extracted value (following the prefix) or null if the prefix is * not found or no value follows it */ private String extractCommentData(String data, String prefix) { String extractedValue = null; int location; location = data.indexOf(prefix); if (location > -1 && data.length() > location + prefix.length()) { extractedValue = data.substring(location + prefix.length()).trim(); } return extractedValue; } /** * Load the provided file as a SPARQL query replacing any query currently * in the query text area. * * @param inputFile * The file to load (should be a SPARQL query) */ private void loadSparqlQueryFile(File inputFile) { BufferedReader reader; String data; StringBuffer allData; String serviceUrlFromFile = null; String defaultGraphUriFromFile = null; checkForUnsavedSparqlQuery(); lastDirectoryUsed = inputFile.getParentFile(); reader = null; allData = new StringBuffer(); try { reader = new BufferedReader(new FileReader(inputFile)); while ((data = reader.readLine()) != null) { if (data.indexOf(SPARQL_QUERY_SAVE_SERVICE_URL_PARAM) > -1) { serviceUrlFromFile = extractCommentData(data, SPARQL_QUERY_SAVE_SERVICE_URL_PARAM); } else if (data.indexOf(SPARQL_QUERY_SAVE_SERVICE_DEFAULT_GRAPH_PARAM) > -1) { defaultGraphUriFromFile = extractCommentData(data, SPARQL_QUERY_SAVE_SERVICE_DEFAULT_GRAPH_PARAM); } else { allData.append(data); allData.append('\n'); } } sparqlInput.setText(allData.toString()); sparqlInput.setSelectionEnd(0); sparqlInput.setSelectionStart(0); sparqlInput.moveCaretPosition(0); sparqlInput.scrollRectToVisible(new Rectangle(0, 0, 1, 1)); if (defaultGraphUriFromFile != null) { defaultGraphUri.setText(defaultGraphUriFromFile); } if (serviceUrlFromFile != null) { int matchAt = -1; if (serviceUrlFromFile.equals(SPARQL_QUERY_SAVE_SERVICE_URL_VALUE_FOR_NO_SERVICE_URL)) { matchAt = 0; } else { for (int index = 1; matchAt == -1 && index < sparqlServiceUrl.getItemCount(); ++index) { if (sparqlServiceUrl.getItemAt(index).toString().equals(serviceUrlFromFile)) { matchAt = index; } } } if (matchAt > -1) { sparqlServiceUrl.setSelectedIndex(matchAt); } else { sparqlServiceUrl.addItem(serviceUrlFromFile); } } setStatus("Loaded SPARQL query file: " + inputFile.getName()); setSparqlQueryFile(inputFile); // Select the SPARQL tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_SPARQL); setFocusOnCorrectTextArea(); } }); } catch (IOException ioExc) { setStatus("Unable to load file: " + inputFile.getName()); JOptionPane.showMessageDialog(this, "Error: Unable to read file\n\n" + inputFile.getAbsolutePath() + "\n\n" + ioExc.getMessage(), "Error Reading File", JOptionPane.ERROR_MESSAGE); LOGGER.error("Unable to load the file: " + inputFile.getAbsolutePath(), ioExc); } finally { if (reader != null) { try { reader.close(); } catch (Throwable throwable) { LOGGER.error("Unable to close input file", throwable); } } invalidateSparqlResults(true); setTitle(); } } /** * Remove prior SPARQL results if the SPARQL query changes * * @param alterControls * Whether or not the current enable/disable setting of GUI controls * should be updated */ private void invalidateSparqlResults(boolean alterControls) { areSparqlResultsInSyncWithModel = false; if (alterControls) { enableControls(true); } } /** * Save the text from the assertions text area to a file Note that this is * not the model and it may not be in an legal syntax for RDF triples. It is * simply storing what the user has placed in the text area. * * @see writeOntologyModel */ private void saveAssertionsToFile() { FileWriter out; JFileChooser fileChooser; File destinationFile; int choice; out = null; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(); if (rdfFileSource != null && rdfFileSource.isFile()) { fileChooser.setSelectedFile(rdfFileSource.getBackingFile()); } else { fileChooser.setSelectedFile(lastDirectoryUsed); } fileChooser.setDialogTitle("Save Assertions to File"); choice = fileChooser.showSaveDialog(this); destinationFile = fileChooser.getSelectedFile(); // Did not click save, did not select a file or chose a directory // So do not write anything if (choice != JFileChooser.APPROVE_OPTION || destinationFile == null || (destinationFile.exists() && !destinationFile.isFile())) { return; // EARLY EXIT! } if (okToOverwriteFile(destinationFile)) { LOGGER.info("Write assertions to file, " + destinationFile); try { out = new FileWriter(destinationFile, false); out.write(assertionsInput.getText()); setRdfFileSource(new FileSource(destinationFile)); addRecentAssertedTriplesFile(new FileSource(destinationFile)); } catch (IOException ioExc) { final String errorMessage = "Unable to write to file: " + destinationFile; LOGGER.error(errorMessage, ioExc); throw new RuntimeException(errorMessage, ioExc); } finally { if (out != null) { try { out.close(); } catch (Throwable throwable) { final String errorMessage = "Failed to close output file: " + destinationFile; LOGGER.error(errorMessage, throwable); throw new RuntimeException(errorMessage, throwable); } } } } } /** * Determine whether an output file already exists and if so, popup a dialog * asking they user whether it is okay to overwrite the existing file. * * @param destinationFile * The output file * * @return True of the file may be written (overwritten) */ private boolean okToOverwriteFile(File destinationFile) { boolean okayToWrite = !destinationFile.exists(); if (!okayToWrite) { int verifyOverwrite; verifyOverwrite = JOptionPane.showConfirmDialog(this, "The file exists: " + destinationFile.getName() + "\n\nOkay to overwrite?", "Overwrite File?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); okayToWrite = verifyOverwrite == JOptionPane.YES_OPTION; } return okayToWrite; } /** * Save the text from the SPARQL query text area to a file. * */ private void saveSparqlQueryToFile() { FileWriter out; JFileChooser fileChooser; FileFilter defaultFileFilter = null; FileFilter preferredFileFilter = null; File destinationFile; int choice; out = null; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(); for (FileFilterDefinition filterDefinition : FileFilterDefinition.values()) { if (filterDefinition.name().startsWith("SPARQL")) { final FileFilter fileFilter = new SuffixFileFilter(filterDefinition.description(), filterDefinition.acceptedSuffixes()); if (filterDefinition.isPreferredOption()) { preferredFileFilter = fileFilter; } fileChooser.addChoosableFileFilter(fileFilter); if (filterDefinition.description().equals(latestChosenSparqlFileFilterDescription)) { defaultFileFilter = fileFilter; } } } if (defaultFileFilter != null) { fileChooser.setFileFilter(defaultFileFilter); } else if (latestChosenSparqlFileFilterDescription != null && latestChosenSparqlFileFilterDescription.startsWith("All")) { fileChooser.setFileFilter(fileChooser.getAcceptAllFileFilter()); } else if (preferredFileFilter != null) { fileChooser.setFileFilter(preferredFileFilter); } if (sparqlQueryFile != null) { fileChooser.setSelectedFile(sparqlQueryFile); } else { fileChooser.setSelectedFile(lastDirectoryUsed); } fileChooser.setDialogTitle("Save SPARQL Query to File"); choice = fileChooser.showSaveDialog(this); try { latestChosenSparqlFileFilterDescription = fileChooser.getFileFilter().getDescription(); } catch (Throwable throwable) { LOGGER.warn("Unable to determine which SPARQL file filter was chosen", throwable); } destinationFile = fileChooser.getSelectedFile(); // Did not click save, did not select a file or chose a directory // So do not write anything if (choice != JFileChooser.APPROVE_OPTION || destinationFile == null || (destinationFile.exists() && !destinationFile.isFile())) { return; // EARLY EXIT! } // Adjust file suffix if necessary final FileFilter fileFilter = fileChooser.getFileFilter(); if (fileFilter != null && fileFilter instanceof SuffixFileFilter && !fileChooser.getFileFilter().accept(destinationFile)) { destinationFile = ((SuffixFileFilter) fileFilter).makeWithPrimarySuffix(destinationFile); } if (okToOverwriteFile(destinationFile)) { LOGGER.info("Write SPARQL query to file, " + destinationFile); try { out = new FileWriter(destinationFile, false); if (sparqlServiceUrl.getSelectedIndex() != 0) { out.write( "# " + SPARQL_QUERY_SAVE_SERVICE_URL_PARAM + sparqlServiceUrl.getSelectedItem() + "\n"); } else { out.write("# " + SPARQL_QUERY_SAVE_SERVICE_URL_PARAM + SPARQL_QUERY_SAVE_SERVICE_URL_VALUE_FOR_NO_SERVICE_URL + "\n"); } if (defaultGraphUri.getText().trim().length() > 0) { out.write("# " + SPARQL_QUERY_SAVE_SERVICE_DEFAULT_GRAPH_PARAM + defaultGraphUri.getText().trim() + "\n"); } out.write(sparqlInput.getText()); setSparqlQueryFile(destinationFile); } catch (IOException ioExc) { final String errorMessage = "Unable to write to file: " + destinationFile; LOGGER.error(errorMessage, ioExc); throw new RuntimeException(errorMessage, ioExc); } finally { if (out != null) { try { out.close(); } catch (Throwable throwable) { final String errorMessage = "Failed to close output file: " + destinationFile; LOGGER.error(errorMessage, throwable); throw new RuntimeException(errorMessage, throwable); } } setTitle(); } } } /** * Get the name of the selected output format * * @return the name of the output format (e.g. N3, Turtle, RDF/XML) */ private String getSelectedOutputLanguage() { int selectedItem; selectedItem = 0; for (int index = 1; selectedItem == 0 && index < setupOutputAssertionLanguage.length; ++index) { if (setupOutputAssertionLanguage[index].isSelected()) { selectedItem = index; } } return selectedItem == 0 ? assertionLanguage : FORMATS[selectedItem - 1]; } /** * Notify the user that a newer version of the program has been released. * * @param newVersionInformation * Information about the new version of the program */ private void notifyNewerVersion(NewVersionInformation newVersionInformation) { if (newVersionInformation.getUrlToDownloadPage() != null) { int choice; choice = JOptionPane.showConfirmDialog(this, "There is a newer version of Semantic Workbench Available\n" + "You are running version " + VERSION + " and the latest version is " + newVersionInformation.getLatestVersion() + "\n\n" + newVersionInformation.getDownloadInformation() + "\n" + "New features include:\n" + newVersionInformation.getNewFeaturesDescription() + "\n\n" + "Would you like to download the new version now?\n\n", "Newer Version Available (" + VERSION + "->" + newVersionInformation.getLatestVersion() + ")", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); if (choice == JOptionPane.YES_OPTION) { try { Desktop.getDesktop().browse(newVersionInformation.getUrlToDownloadPage().toURI()); } catch (Throwable throwable) { LOGGER.error("Cannot launch browser to access download page", throwable); JOptionPane.showMessageDialog(this, "Unable to launch a browser to access the download page\n" + "at " + newVersionInformation.getUrlToDownloadPage().toString() + "\n\n" + throwable.getMessage(), "Unable to Access Download Page", JOptionPane.ERROR_MESSAGE); } } } else { JOptionPane.showMessageDialog(this, "There is a newer version of Semantic Workbench Available\n" + "You are running version " + VERSION + " and the latest version is " + newVersionInformation.getLatestVersion() + "\n\n" + "New features include:\n" + newVersionInformation.getNewFeaturesDescription(), "Newer Version Available (" + VERSION + "->" + newVersionInformation.getLatestVersion() + ")", JOptionPane.INFORMATION_MESSAGE); } } /** * Search for text in the assertions text area. If found, the window will * scroll to the text location and the matching text will be highlighted. * * @see #findNextTextInAssertionsTextArea() */ private void findTextInAssertionsTextArea() { String textToFind; boolean found; textToFind = JOptionPane.showInputDialog(this, "Enter the text to find in the assertions editor", "Find Assertions Text", JOptionPane.QUESTION_MESSAGE); if (textToFind != null && textToFind.trim().length() > 0) { // Select the assertions tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_ASSERTIONS); } }); textToFind = textToFind.trim(); found = TextSearch.getInstance().startSearch(assertionsInput, textToFind); if (!found) { JOptionPane.showMessageDialog(this, "The text [" + textToFind + "] was not found", "Not Found", JOptionPane.INFORMATION_MESSAGE); setStatus("Did not find the assertions text: " + textToFind); } else { setStatus("Found matching text at line " + TextSearch.getInstance().getLineOfLastMatch(assertionsInput)); } } else { setStatus("No text entered to find"); } } /** * Find the next occurrence of text matching a search. If found, the window * will scroll to the text location and the matching text will be highlighted. * * @see #findTextInAssertionsTextArea() */ private void findNextTextInAssertionsTextArea() { boolean found; if (TextSearch.getInstance().hasActiveSearch(assertionsInput)) { // Select the assertions tab SwingUtilities.invokeLater(new Runnable() { public void run() { tabbedPane.setSelectedIndex(TAB_NUMBER_ASSERTIONS); } }); found = TextSearch.getInstance().continueSearch(assertionsInput); if (found && TextSearch.getInstance().lastSearchWrapped(assertionsInput)) { JOptionPane.showMessageDialog(this, "Wrapped back to the top when locating the text", "Wrapped To Top", JOptionPane.INFORMATION_MESSAGE); setStatus("Found matching text at line " + TextSearch.getInstance().getLineOfLastMatch(assertionsInput) + " (wrapped back to top)"); } else if (found) { setStatus("Found matching text at line " + TextSearch.getInstance().getLineOfLastMatch(assertionsInput)); } else { JOptionPane.showMessageDialog(this, "The text was not found", "Not Found", JOptionPane.INFORMATION_MESSAGE); } } } /** * Insert standard prefixes in the assertions text area. * * The user must choose the format (syntax) to use. */ private void insertPrefixes() { String whichFormat; int formatIndex; String[] formatsToChoose; List<String> formatsAvail; StringBuffer prefixesToAdd; JTextArea areaToUpdate; formatsAvail = new ArrayList<String>(); for (int format = 0; format < FORMATS.length; ++format) { if (STANDARD_PREFIXES[format].length > 0) { formatsAvail.add(FORMATS[format]); } } // SPARQL is a special case - not an RDF serialization formatsAvail.add("SPARQL (tab)"); formatsToChoose = new String[formatsAvail.size()]; for (int format = 0; format < formatsAvail.size(); ++format) { formatsToChoose[format] = formatsAvail.get(format); } whichFormat = (String) JOptionPane.showInputDialog(this, "Choose the format for the prefixes", "Choose Format", JOptionPane.QUESTION_MESSAGE, null, formatsToChoose, null); LOGGER.debug("Chosen format for prefixes: " + whichFormat); if (whichFormat != null) { formatIndex = getIndexValue(FORMATS, whichFormat); // SPARQL - special case - not an RDF serialization format if (formatIndex == UNKNOWN) { formatIndex = STANDARD_PREFIXES.length - 1; areaToUpdate = sparqlInput; } else { areaToUpdate = assertionsInput; } LOGGER.debug("Chosen format index for prefixes: " + formatIndex); if (formatIndex >= 0) { String currentData; currentData = areaToUpdate.getText(); prefixesToAdd = new StringBuffer(); for (int prefix = 0; prefix < STANDARD_PREFIXES[formatIndex].length; ++prefix) { prefixesToAdd.append(STANDARD_PREFIXES[formatIndex][prefix]); prefixesToAdd.append('\n'); } areaToUpdate.setText(prefixesToAdd.toString() + currentData); } } } /** * Setup to read assertions from a file source * * @param inputFileSource * The file source of the assertions */ private void setupToLoadOntologyFile(FileSource inputFileSource) { if (inputFileSource.isFile() && !inputFileSource.getBackingFile().isFile()) { JOptionPane.showMessageDialog(this, "Cannot read the file\n" + inputFileSource.getAbsolutePath(), "Cannot Read Assertions File", JOptionPane.ERROR_MESSAGE); } else { checkForUnsavedRdf(); setRdfFileSource(inputFileSource); runModelLoad(); } } /** * Setup the environment to save the current model to a file. * * @see #writeOntologyModel(File) */ private void setupToWriteOntologyModel() { JFileChooser fileChooser; File destinationFile; int choice; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(); if (rdfFileSource != null && rdfFileSource.isFile()) { fileChooser.setSelectedFile(rdfFileSource.getBackingFile()); } else { fileChooser.setSelectedFile(lastDirectoryUsed); } fileChooser.setDialogTitle("Save Ontology Model to File (" + getSelectedOutputLanguage() + ")"); choice = fileChooser.showSaveDialog(this); destinationFile = fileChooser.getSelectedFile(); // Did not click save, did not select a file or chose a directory // So do not write anything if (choice != JFileChooser.APPROVE_OPTION || destinationFile == null || (destinationFile.exists() && !destinationFile.isFile())) { return; // EARLY EXIT! } if (okToOverwriteFile(destinationFile)) { modelExportFile = destinationFile; runModelExport(); } } /** * Writes the triples to a data file. * * This writes the current model to the file. The current model is the last * model successfully run through the reasoner. The output will be in the * same language (N3, Turtle, RDF/XML) as the assertions input unless a * specific language was set for output. * * @see #setupToWriteOntologyModel() * * @return The message to be presented on the status line */ private String writeOntologyModel() { FileWriter out = null; String message = "model (" + (setupOutputModelTypeAssertionsAndInferences.isSelected() ? "assertions and inferences" : "assertions only") + ") to " + modelExportFile; setStatus("Writing " + message); LOGGER.info("Write model to file, " + modelExportFile + ", in format: " + getSelectedOutputLanguage()); try { out = new FileWriter(modelExportFile, false); if (setupOutputModelTypeAssertionsAndInferences.isSelected()) { LOGGER.info("Writing complete model (assertions and inferences)"); ontModel.writeAll(out, getSelectedOutputLanguage().toUpperCase(), null); } else { LOGGER.info("Writing assertions only"); ontModel.getBaseModel().write(out, getSelectedOutputLanguage().toUpperCase()); } message = "Completed writing " + message; } catch (IOException ioExc) { LOGGER.error("Unable to write file: " + modelExportFile, ioExc); setStatus("Failed to write file (check log) " + message); throw new RuntimeException("Unable to write output file (" + modelExportFile + ")", ioExc); } finally { if (out != null) { try { out.close(); } catch (Throwable throwable) { final String errorMessage = "Failed to close output file: " + modelExportFile; LOGGER.error(errorMessage, throwable); throw new RuntimeException(errorMessage, throwable); } } } return message; } /** * Setup the environment to save the current SPARQL results to a file. * * @see #writeSparqlResults(File) */ private void setupToWriteSparqlResults() { JFileChooser fileChooser; File destinationFile; int choice; if (lastDirectoryUsed == null) { lastDirectoryUsed = new File("."); } fileChooser = new JFileChooser(); if (sparqlResultsExportFile != null) { fileChooser.setSelectedFile(sparqlResultsExportFile); } else { fileChooser.setSelectedFile(lastDirectoryUsed); } fileChooser.setDialogTitle("Save SPARQL Results to File (Format:" + (setupExportSparqlResultsAsCsv.isSelected() ? "CSV" : "TSV") + ")"); choice = fileChooser.showSaveDialog(this); destinationFile = fileChooser.getSelectedFile(); // Did not click save, did not select a file or chose a directory // So do not write anything if (choice != JFileChooser.APPROVE_OPTION || destinationFile == null || (destinationFile.exists() && !destinationFile.isFile())) { return; // EARLY EXIT! } if (okToOverwriteFile(destinationFile)) { sparqlResultsExportFile = destinationFile; runSparqlResultsExport(); } } /** * Clear the history of executed SPARQL queries */ private void clearSparqlQueryHistory() { queryHistory.clearAllQueries(); enableControls(true); setStatus("SPARQL history cleared"); } /** * Send SPARQL results to a file without presenting them in the results table. * This allows for arbitrarily large result sets to be handled and written * since there is no memory limitation being imposed by attempting to * represent the results within the GUI * * @param results * The result set from the SPARQL query * @param formatter * The formatter to be used to output the results * * @return The number of result rows written to the file */ private long writeSparqlResultsDirectlyToFile(ResultSet results, SparqlResultsFormatter formatter) { String message; long numRows = 0; List<String> columns; PrintWriter out = null; final boolean toCsv = setupExportSparqlResultsAsCsv.isSelected(); int fileNumber = 0; File outputFile; File outputDirectory; final SparqlTableModel tableModel = (SparqlTableModel) sparqlResultsTable.getModel(); final SparqlResultItemRenderer renderer = new SparqlResultItemRenderer( setupAllowMultilineResultOutput.isSelected()); renderer.setFont(sparqlResultsTable.getFont()); sparqlResultsTable.setDefaultRenderer(SparqlResultItem.class, renderer); if (lastDirectoryUsed != null) { outputDirectory = lastDirectoryUsed; } else { outputDirectory = new File("."); } // Create a unique file do { ++fileNumber; outputFile = new File(outputDirectory, SPARQL_DIRECT_EXPORT_FILE_PREFIX + fileNumber + "." + (toCsv ? "csv" : "txt")); } while (outputFile.exists()); message = "SPARQL results (" + (toCsv ? EXPORT_FORMAT_LABEL_CSV : EXPORT_FORMAT_LABEL_TSV) + ") directly to " + outputFile.getAbsolutePath(); setStatus("Writing " + message); tableModel.displayMessageInTable("Exporting Results Directly to File", new String[] { outputFile.getAbsolutePath() }); LOGGER.info("Write SPARQL results to file, " + outputFile.getAbsolutePath()); try { out = new PrintWriter(new FileWriter(outputFile)); // Output column names columns = results.getResultVars(); for (int columnNumber = 0; columnNumber < columns.size(); ++columnNumber) { if (columnNumber > 0) { out.print(toCsv ? ',' : '\t'); } if (toCsv) { out.print(TextProcessing.formatForCsvColumn(columns.get(columnNumber))); } else { out.print(TextProcessing.formatForTsvColumn(columns.get(columnNumber))); } } out.println(); // Output data while (results.hasNext()) { ++numRows; final QuerySolution solution = results.next(); for (int columnNumber = 0; columnNumber < columns.size(); ++columnNumber) { if (columnNumber > 0) { out.print(toCsv ? ',' : '\t'); } if (toCsv) { out.print(TextProcessing .formatForCsvColumn(formatter.format(solution, columns.get(columnNumber), false))); } else { out.print(TextProcessing .formatForTsvColumn(formatter.format(solution, columns.get(columnNumber), false))); } } out.println(); } } catch (Throwable throwable) { LOGGER.error("Failed to write SPARQL results to " + outputFile.getAbsolutePath(), throwable); tableModel.displayMessageInTable("Exporting Results Directly to File", new String[] { "Failed to write the file", throwable.getMessage(), outputFile.getAbsolutePath() }); throw new RuntimeException("Failed to write SPARQL results to " + outputFile.getAbsolutePath(), throwable); } finally { if (out != null) { try { out.close(); } catch (Throwable throwable) { LOGGER.warn("Unable to close output file: " + outputFile); } } } return numRows; } /** * Writes the SPARQL results to a file. * * This writes the current SPARQL results to the file. The format used is * determined by the configuration (e.g. setupExportSparqlResultsAsCsv and * setupExportSparqlResultsAsTsv menu items). * * @see #setupToWriteSparqlResults() * * @return The message to be presented on the status line */ private String writeSparqlResults() { PrintWriter out = null; boolean toCsv; // Either CSV or TSV currently toCsv = setupExportSparqlResultsAsCsv.isSelected(); String message = "SPARQL results (" + (toCsv ? EXPORT_FORMAT_LABEL_CSV : EXPORT_FORMAT_LABEL_TSV) + ") to " + sparqlResultsExportFile; setStatus("Writing " + message); LOGGER.info("Write SPARQL results to file, " + sparqlResultsExportFile); try { out = new PrintWriter(new FileWriter(sparqlResultsExportFile, false)); final SparqlTableModel model = (SparqlTableModel) sparqlResultsTable.getModel(); // Output column names for (int columnNumber = 0; columnNumber < model.getColumnCount(); ++columnNumber) { if (columnNumber > 0) { out.print(toCsv ? ',' : '\t'); } if (toCsv) { out.print(TextProcessing.formatForCsvColumn(model.getColumnName(columnNumber))); } else { out.print(TextProcessing.formatForTsvColumn(model.getColumnName(columnNumber))); } } out.println(); // Output row data for (int rowNumber = 0; rowNumber < model.getRowCount(); ++rowNumber) { for (int columnNumber = 0; columnNumber < model.getColumnCount(); ++columnNumber) { if (columnNumber > 0) { out.print(toCsv ? ',' : '\t'); } if (toCsv) { out.print(TextProcessing.formatForCsvColumn(model.getValueAt(rowNumber, columnNumber))); } else { out.print(TextProcessing.formatForTsvColumn(model.getValueAt(rowNumber, columnNumber))); } } out.println(); } message = "Completed writing " + message; } catch (IOException ioExc) { LOGGER.error("Unable to write to file: " + sparqlResultsExportFile, ioExc); setStatus("Failed to write file (check log) " + message); throw new RuntimeException("Unable to write output file (" + sparqlResultsExportFile + ")", ioExc); } finally { if (out != null) { try { out.close(); } catch (Throwable throwable) { final String errorMessage = "Unable to close output file: " + sparqlResultsExportFile; LOGGER.error(errorMessage, throwable); throw new RuntimeException(errorMessage, throwable); } } } return message; } /** * Evaluate the SPARQL service field and see if a new service address has been * entered */ private void processSparqlServiceChoice() { String currentSelection; try { currentSelection = sparqlServiceUrl.getSelectedItem().toString(); LOGGER.debug("SPARQL Service URL Change: Index: " + sparqlServiceUrl.getSelectedIndex() + " Value: [" + currentSelection + "]"); // Add a new service URL to the dropdown // A new service URL will likely be at least 13 characters long // e.g. http://1.2.3.4 if (sparqlServiceUrl.getSelectedIndex() == -1 && currentSelection.trim().length() > 10) { sparqlServiceUrl.addItem(currentSelection); } } catch (Throwable throwable) { LOGGER.warn("Unable to set the SPARQL service value", throwable); // Set to local model if the field value cannot be processed sparqlServiceUrl.setSelectedIndex(0); } enableControls(true); } /** * Load a SPARQL query from the history collection. A direction of 1 or more * means to move to the next query in the history list. A value of -1 or less * means to move to the previous query in the history list. If the direction * is equal to 0 then it means to load the current history query. This is used * when the program starts up to load the latest query. * * @param direction * Direction to traverse history. 1=forward, -1=backward, 0=current */ private void processSparqlQueryHistoryMove(int direction) { if (direction < 0) { queryHistory.moveBackward(); } else if (direction > 0) { queryHistory.moveForward(); } final QueryInfo queryInfo = queryHistory.getCurrentQueryInfo(); sparqlInput.setText(queryInfo.getSparqlQuery().getSparqlStatement()); sparqlInput.setCaretPosition(0); if (queryInfo.getServiceUrl() == null) { sparqlServiceUrl.setSelectedIndex(0); } else { sparqlServiceUrl.setSelectedItem(queryInfo.getServiceUrl()); } String histDefaultGraphUri = queryInfo.getDefaultGraphUri(); if (histDefaultGraphUri == null) { histDefaultGraphUri = ""; } defaultGraphUri.setText(histDefaultGraphUri); final SparqlTableModel tableModel = queryInfo.getResults(); LOGGER.debug("Historical results: " + tableModel); if (tableModel != null) { final SparqlResultItemRenderer renderer = new SparqlResultItemRenderer( setupAllowMultilineResultOutput.isSelected()); renderer.setFont(sparqlResultsTable.getFont()); sparqlResultsTable.setDefaultRenderer(SparqlResultItem.class, renderer); sparqlResultsTable.setModel(tableModel); setStatus("Historical query retrieved. Number of query results: " + sparqlResultsTable.getRowCount()); } else { sparqlResultsTable.setModel(new SparqlTableModel()); setStatus("Historical query retrieved."); } setFocusOnCorrectTextArea(); sparqlQuerySaved = true; enableControls(true); } /** * Enable or disable the comment toggle menu item based on whether the * selected tab supports comment toggling and has one or more lines selected. */ private void enableCommentToggle() { final int selectedTab = tabbedPane.getSelectedIndex(); if (selectedTab == TAB_NUMBER_SPARQL) { editCommentToggle.setEnabled(sparqlInput.getSelectionEnd() > sparqlInput.getSelectionStart()); } else if (selectedTab == TAB_NUMBER_ASSERTIONS) { editCommentToggle.setEnabled(assertionsInput.getSelectionEnd() > assertionsInput.getSelectionStart()); } else { editCommentToggle.setEnabled(false); } } /** * Set the focus in the "default" text area for the tab (if there is one). * Also assure that the caret is visible. */ private void setFocusOnCorrectTextArea() { final int selectedTab = tabbedPane.getSelectedIndex(); if (selectedTab == TAB_NUMBER_SPARQL) { sparqlInput.requestFocus(); sparqlInput.getCaret().setVisible(true); } else if (selectedTab == TAB_NUMBER_ASSERTIONS) { assertionsInput.requestFocus(); assertionsInput.getCaret().setVisible(true); } } /** * Toggle the comment character on/off for the chosen lines. * * Currently this only supports using the pound sign (#) as the comment * character which works for most assertions formats except RDF/XML as well as * for SPARQL. */ private void commentToggle() { final int selectedTab = tabbedPane.getSelectedIndex(); if (selectedTab == TAB_NUMBER_SPARQL) { GuiUtilities.commentToggle(sparqlInput, "#"); } else if (selectedTab == TAB_NUMBER_ASSERTIONS) { GuiUtilities.commentToggle(assertionsInput, "#"); } } /** * Check for unsaved changes to information */ private void checkForUnsavedInformation() { checkForUnsavedRdf(); checkForUnsavedSparqlQuery(); } /** * Check for unsaved changes to the assertions. If there are unsaved changes, * verify with the user whether to save them. */ private void checkForUnsavedRdf() { if (!rdfFileSaved && assertionsInput.getText().trim().length() > 0) { if (checkWhetherToSaveFile("Assertion Data")) { saveAssertionsToFile(); } } } /** * Check for unsaved changes to the SPARQL query. If there are unsaved * changes, verify with the user whether to save them. */ private void checkForUnsavedSparqlQuery() { if (!sparqlQuerySaved && sparqlInput.getText().trim().length() > 0) { if (checkWhetherToSaveFile("SPARQL Query")) { saveSparqlQueryToFile(); } } } /** * Ask the user whether to save unsaved information to a file. * * @param description * The description of the information to be saved. It should be * written in the singular. * * @return True if the user wants to save the information to a file */ private boolean checkWhetherToSaveFile(String description) { return JOptionPane.showConfirmDialog(this, "The " + description + " has not been saved.\n\n" + "Do you want to save it?", "Unsaved Changes: " + description, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION; } /** * Presents a classic "About" box to the user displaying the current version * of the application. */ private void about() { String slMessage; slMessage = "Semantic Workbench\n\nVersion: " + VERSION + "\nJena Version: " + getJenaVersion() + "\nPellet Version: " + getPelletVersion() + "\n\nSystem information:\n Free Memory: " + INTEGER_COMMA_FORMAT.format(Runtime.getRuntime().freeMemory()) + "\n Total Memory: " + INTEGER_COMMA_FORMAT.format(Runtime.getRuntime().totalMemory()) + "\n Maximum Memory: " + INTEGER_COMMA_FORMAT.format(Runtime.getRuntime().maxMemory()) + "\n Available Processors: " + Runtime.getRuntime().availableProcessors() + "\n\n"; slMessage += "Graphical user interface for working with semantic " + "technology concepts including ontologies, reasoners and queries.\n\n"; slMessage += "David Read, www.monead.com\n\n"; slMessage += "Copyright (c) 2010-2014\n\n" + "This program is free software: you can redistribute it and/or modify " + "it under the terms of the GNU Affero General Public License as " + "published by the Free Software Foundation, either version 3 of the " + "License, or (at your option) any later version.\n\n" + "This program is distributed in the hope that it will be useful, " + "but WITHOUT ANY WARRANTY; without even the implied warranty of " + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " + "GNU Affero General Public License for more details.\n\n" + "You should have received a copy of the GNU Affero General Public License " + "along with this program. If not, see <http://www.gnu.org/licenses/>."; JOptionPane.showMessageDialog(this, TextProcessing.characterInsert(slMessage, "\n", 70, 90, " ."), "About Semantic Workbench", JOptionPane.INFORMATION_MESSAGE); } /** * Launch a browser pointed at the overview video */ private void viewOverviewVideo() { try { final URL url = new URL(OVERVIEW_VIDEO_LOCATION); Desktop.getDesktop().browse(url.toURI()); } catch (Throwable throwable) { LOGGER.error("Cannot launch browser to show the overview video", throwable); JOptionPane.showMessageDialog( this, "Unable to launch a browser to show the overview video\n" + "at " + OVERVIEW_VIDEO_LOCATION + "\n\n" + throwable.getMessage(), "Unable to Launch Video", JOptionPane.ERROR_MESSAGE); } } /** * Get the version of the loaded Jena library * * @return The version of the Jena library */ private String getJenaVersion() { return ARQ.VERSION; } /** * Get the version of the loaded Pellet library * * @return The version of the Pellet library */ private String getPelletVersion() { return VersionInfo.getInstance().getVersionString() + " (" + VersionInfo.getInstance().getReleaseDate() + ")"; } /** * End the application */ private void closeApplication() { checkForUnsavedInformation(); saveProperties(); queryHistory.saveHistory(new File(getUserHomeDirectory(), SPARQL_QUERY_HISTORY_FILE_NAME)); setVisible(false); LOGGER.info("Shutdown application"); System.exit(0); } @Override public void update(Observable o, Object arg) { LOGGER.debug("Update received from " + o.getClass().getName()); if (o instanceof SparqlServer) { updateSparqlServerInfo(); } else if (o instanceof CheckLatestVersion) { notifyNewerVersion((NewVersionInformation) arg); } } @Override public void windowActivated(WindowEvent arg0) { } @Override public void windowClosed(WindowEvent arg0) { } @Override public void windowClosing(WindowEvent arg0) { closeApplication(); } @Override public void windowDeactivated(WindowEvent arg0) { } @Override public void windowDeiconified(WindowEvent arg0) { } @Override public void windowIconified(WindowEvent arg0) { } @Override public void windowOpened(WindowEvent arg0) { } /** * Handle mnouse events in the ontology tree view */ private class OntologyModelTreeMouseListener extends MouseAdapter { /** * No operation */ public OntologyModelTreeMouseListener() { } @Override public void mouseClicked(MouseEvent event) { if (event.getButton() == MouseEvent.BUTTON1) { processOntologyModelTreeLeftClick(event); } else { // Assume right-mouse click (e.g. not button 1) processOntologyModelTreeRightClick(event); } } } /** * A popup menu for allowing the user to select a set of values to be removed * from a list */ private class FilterValuePopup extends JPopupMenu implements ActionListener { /** * Serial UID */ private static final long serialVersionUID = 6587807055541029847L; /** * The collection of items to be shown to the user */ private Wrapper wrappedObject; /** * The menu item to be presented to the user */ private JMenuItem menuItem; /** * Setup the menu item with the list of objects * * @param pWrappedObject * The collection of items to be shown to the user */ public FilterValuePopup(Wrapper pWrappedObject) { wrappedObject = pWrappedObject; menuItem = new JMenuItem("Filter out: " + wrappedObject.toString()); menuItem.addActionListener(this); add(menuItem); // Don't need listener, no action to take for cancel add(new JMenuItem("Cancel")); } @Override public void actionPerformed(ActionEvent event) { if (event.getSource() instanceof JMenuItem) { final JMenuItem source = (JMenuItem) event.getSource(); if (source == menuItem) { LOGGER.debug("FilterValuePopup choice: " + wrappedObject.getClass().toString() + " - " + wrappedObject); addToFilter(wrappedObject); } } } } /** * Executes the reasoner in response to action from any widget being * monitored */ private class ReasonerListener implements ActionListener { /** * No operation */ public ReasonerListener() { } @Override public void actionPerformed(ActionEvent e) { runReasoner(); } } /** * Used to detect configuration changes that would cause the reasoner to * behave differently, thereby invalidating the current model. */ private class ReasonerConfigurationChange implements ActionListener { /** * No operation */ public ReasonerConfigurationChange() { } @Override public void actionPerformed(ActionEvent e) { invalidateModel(true); } } /** * Executes the SPARQL query in response to action from any widget being * monitored */ private class SparqlListener implements ActionListener { /** * No operation */ public SparqlListener() { } @Override public void actionPerformed(ActionEvent e) { runSparql(); } } /** * Opens an ontology file */ private class FileAssertedTriplesOpenListener implements ActionListener { /** * No operation */ public FileAssertedTriplesOpenListener() { } @Override public void actionPerformed(ActionEvent e) { openOntologyFile(); } } /** * Opens an ontology using a URL */ private class FileAssertedTriplesUrlOpenListener implements ActionListener { /** * No operation */ public FileAssertedTriplesUrlOpenListener() { } @Override public void actionPerformed(ActionEvent e) { openOntologyUrl(); } } /** * Loads a recently accessed ontology file */ private class RecentAssertedTriplesFileOpenListener implements ActionListener { /** * No operation */ public RecentAssertedTriplesFileOpenListener() { } @Override public void actionPerformed(ActionEvent e) { openRecentOntologyFile(e.getSource()); } } /** * Loads a recently accessed ontology file */ private class RecentSparqlFileOpenListener implements ActionListener { /** * No operation */ public RecentSparqlFileOpenListener() { } @Override public void actionPerformed(ActionEvent e) { openRecentSparqlQueryFile(e.getSource()); } } /** * Opens a SPARQL query file */ private class FileSparqlOpenListener implements ActionListener { /** * No operation */ public FileSparqlOpenListener() { } @Override public void actionPerformed(ActionEvent e) { openSparqlQueryFile(); } } /** * Exits the application */ private class EndApplicationListener implements ActionListener { /** * No operation */ public EndApplicationListener() { } @Override public void actionPerformed(ActionEvent e) { closeApplication(); } } /** * Evaluates control status */ private class SparqlModelChoiceListener implements ActionListener { /** * No operation */ public SparqlModelChoiceListener() { } @Override public void actionPerformed(ActionEvent e) { processSparqlServiceChoice(); } } /** * Move to previous query in the query history */ private class SparqlHistoryPreviousListener implements ActionListener { /** * No operation */ public SparqlHistoryPreviousListener() { } @Override public void actionPerformed(ActionEvent e) { processSparqlQueryHistoryMove(-1); } } /** * Move to next query in the query history */ private class SparqlHistoryNextListener implements ActionListener { /** * No operation */ public SparqlHistoryNextListener() { } @Override public void actionPerformed(ActionEvent e) { processSparqlQueryHistoryMove(1); } } /** * Search for text in the assertions text area */ private class FindAssertionsTextListener implements ActionListener { /** * No operation */ public FindAssertionsTextListener() { } @Override public void actionPerformed(ActionEvent e) { findTextInAssertionsTextArea(); } } /** * Search for the next text match in the assertions text area */ private class FindNextAssertionsTextListener implements ActionListener { /** * No operation */ public FindNextAssertionsTextListener() { } @Override public void actionPerformed(ActionEvent e) { findNextTextInAssertionsTextArea(); } } /** * Toggles selected lines in the SPARQL query between commented and not * commented */ private class CommentToggleListener implements ActionListener { /** * No operation */ public CommentToggleListener() { } @Override public void actionPerformed(ActionEvent e) { commentToggle(); } } /** * Inserts standard prefixes */ private class InsertPrefixesListener implements ActionListener { /** * No operation */ public InsertPrefixesListener() { } @Override public void actionPerformed(ActionEvent e) { insertPrefixes(); } } /** * Writes assertions to a file */ private class FileAssertedTriplesSaveListener implements ActionListener { /** * No operation */ public FileAssertedTriplesSaveListener() { } @Override public void actionPerformed(ActionEvent e) { saveAssertionsToFile(); } } /** * Writes SPARQL query to a file */ private class FileSparqlSaveListener implements ActionListener { /** * No operation */ public FileSparqlSaveListener() { } @Override public void actionPerformed(ActionEvent e) { saveSparqlQueryToFile(); } } /** * Expands the nodes in the tree representation of the model */ private class ExpandTreeListener implements ActionListener { /** * No operation */ public ExpandTreeListener() { } @Override public void actionPerformed(ActionEvent e) { runExpandAllTreeNodes(); } } /** * Collapses the nodes in the tree representation of the model */ private class CollapseTreeListener implements ActionListener { /** * No operation */ public CollapseTreeListener() { } @Override public void actionPerformed(ActionEvent e) { runCollapseAllTreeNodes(); } } /** * Allows the user to edit the list of stored SPARQL service URLs in the * dropdown */ private class EditListOfSparqlServiceUrls implements ActionListener { /** * No operation */ public EditListOfSparqlServiceUrls() { } @Override public void actionPerformed(ActionEvent e) { editListOfSparqlServiceUrls(); } } /** * Allows the user to change the display font */ private class FontSetupListener implements ActionListener { /** * No operation */ public FontSetupListener() { } @Override public void actionPerformed(ActionEvent e) { configureFont(); } } /** * Writes the current model to an ontology file */ private class ModelSerializerListener implements ActionListener { /** * No operation */ public ModelSerializerListener() { } @Override public void actionPerformed(ActionEvent e) { setupToWriteOntologyModel(); } } /** * Writes the current SPARQL results to a CSV file */ private class FileSparqlResultsSaveListener implements ActionListener { /** * No operation */ public FileSparqlResultsSaveListener() { } @Override public void actionPerformed(ActionEvent e) { setupToWriteSparqlResults(); } } /** * Clears the history of executed SPARQL queries */ private class FileClearSparqlHistoryListener implements ActionListener { /** * No operation */ public FileClearSparqlHistoryListener() { } @Override public void actionPerformed(ActionEvent e) { clearSparqlQueryHistory(); } } /** * Allows the user to edit the list of classes filtered in the tree view */ private class EditFilteredClassesListener implements ActionListener { /** * No operation */ public EditFilteredClassesListener() { } @Override public void actionPerformed(ActionEvent e) { editFilterMap(classesToSkipInTree); } } /** * Allows the user to edit the list of properties filtered in the tree view */ private class EditFilteredPropertiesListener implements ActionListener { /** * No operation */ public EditFilteredPropertiesListener() { } @Override public void actionPerformed(ActionEvent e) { editFilterMap(predicatesToSkipInTree); } } /** * Clears the existing tree model */ private class ClearTreeModelListener implements ActionListener { /** * No operation */ public ClearTreeModelListener() { } @Override public void actionPerformed(ActionEvent e) { clearTree(); } } /** * Set the maximum number of individuals to display for each class in the tree * view of the model */ private class SetMaximumIndividualsPerClassInTreeListener implements ActionListener { /** * No operation */ public SetMaximumIndividualsPerClassInTreeListener() { } @Override public void actionPerformed(ActionEvent e) { setMaximumIndividualsPerClassInTree(); } } /** * Enable or disable the use of a proxy for network-based requests */ private class ProxyStatusChangeListener implements ActionListener { /** * No operation */ public ProxyStatusChangeListener() { } @Override public void actionPerformed(ActionEvent e) { changeProxyMode(); } } /** * Configure the proxy */ private class ProxySetupListener implements ActionListener { /** * No operation */ public ProxySetupListener() { } @Override public void actionPerformed(ActionEvent e) { configureProxy(); } } /** * Start the SPARQL server */ private class SparqlServerStartupListener implements ActionListener { /** * No operation */ public SparqlServerStartupListener() { } @Override public void actionPerformed(ActionEvent e) { startSparqlServer(); } } /** * Stop the SPARQL server */ private class SparqlServerShutdownListener implements ActionListener { /** * No operation */ public SparqlServerShutdownListener() { } @Override public void actionPerformed(ActionEvent e) { stopSparqlServer(); } } /** * Publish the current ontology model to the SPARQL server */ private class SparqlServerPublishModelListener implements ActionListener { /** * No operation */ public SparqlServerPublishModelListener() { } @Override public void actionPerformed(ActionEvent e) { publishModelToTheSparqlServer(); } } /** * Publish the current ontology model to the SPARQL server */ private class SparqlServerConfigurationListener implements ActionListener { /** * No operation */ public SparqlServerConfigurationListener() { } @Override public void actionPerformed(ActionEvent e) { configureSparqlServer(); } } /** * Displays overview video */ private class OverviewVideoListener implements ActionListener { /** * No operation */ public OverviewVideoListener() { } @Override public void actionPerformed(ActionEvent e) { viewOverviewVideo(); } } /** * Displays About dialog */ private class AboutListener implements ActionListener { /** * No operation */ public AboutListener() { } @Override public void actionPerformed(ActionEvent e) { about(); } } /** * Creates tree view of model * * @author David Read * */ private class GenerateTreeListener implements ActionListener { /** * No operation */ public GenerateTreeListener() { } @Override public void actionPerformed(ActionEvent e) { runCreateTreeFromModel(); } } /** * Creates a list of inferred triples from the model * * @author David Read * */ private class GenerateInferredTriplesListener implements ActionListener { /** * No operation */ public GenerateInferredTriplesListener() { } @Override public void actionPerformed(ActionEvent e) { runIdentifyInferredTriples(); } } /** * Listen for caret events on the SAPARQL text area. Intereted in whether text * has been selected in which case the comment toggle options needs to be * enabled. */ private class TextAreaCaratListener implements CaretListener { /** * No operation */ public TextAreaCaratListener() { } @Override public void caretUpdate(CaretEvent arg0) { enableCommentToggle(); } } /** * Detect tab selections */ private class TabbedPaneChangeListener implements ChangeListener { /** * No operation */ public TabbedPaneChangeListener() { } @Override public void stateChanged(ChangeEvent arg0) { enableCommentToggle(); setFocusOnCorrectTextArea(); } } /** * Updates state of controls based on changes to text widgets being * monitored */ private class UserInputListener implements KeyListener { /** * The content of the SPARQL input prior to the key release event */ private String lastSparql; /** * The content of the assertions input prior to the key release event */ private String lastAssertions; /** * No operation */ public UserInputListener() { } /** * Track current content of assertions and query fields to detect a change * if there is a current model or results * * @param arg0 * The key event received */ public void keyPressed(KeyEvent arg0) { if (arg0.getSource() == assertionsInput) { lastAssertions = assertionsInput.getText(); } if (arg0.getSource() == sparqlInput) { lastSparql = sparqlInput.getText(); } } /** * Detect whether a change was made to the assertions or query that would * require invalidating the model or results * * @param arg0 * The key event received */ public void keyReleased(KeyEvent arg0) { if (arg0.getSource() == assertionsInput) { if (!lastAssertions.equals(assertionsInput.getText())) { if (ontModel != null) { invalidateModel(true); } if (rdfFileSaved) { rdfFileSaved = false; setTitle(); } } enableAssertionsHandling(true); } else if (arg0.getSource() == sparqlInput) { if (!lastSparql.equals(sparqlInput.getText())) { if (sparqlResultsTable.getModel() instanceof SparqlTableModel && !((SparqlTableModel) sparqlResultsTable.getModel()).isEmpty() && !lastSparql.equals(sparqlInput.getText())) { invalidateSparqlResults(true); } if (sparqlQuerySaved) { sparqlQuerySaved = false; setTitle(); } } } } /** * No operation * * @param arg0 * The key event received */ public void keyTyped(KeyEvent arg0) { } } /** * The execution point for the program. Creates an instance of the * SemanticWorkbench class. * * @param args * The array of input arguments, not used yet */ public static void main(String[] args) { org.apache.log4j.PropertyConfigurator.configure("log4j.properties"); new SemanticWorkbench(); } }