/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.barcelonamedia.uima.tools;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.prefs.Preferences;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.UIManager;
import org.apache.uima.UIMAException;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.analysis_engine.AnalysisEngineDescription;
import org.apache.uima.cas.CAS;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.metadata.FsIndexDescription;
import org.apache.uima.resource.metadata.TypeSystemDescription;
import org.apache.uima.tools.images.Images;
import org.apache.uima.tools.util.gui.AboutDialog;
import org.apache.uima.tools.util.gui.Caption;
import org.apache.uima.tools.util.gui.FileSelector;
import org.apache.uima.tools.util.gui.SpringUtilities;
import org.apache.uima.tools.util.htmlview.AnnotationViewGenerator;
import org.apache.uima.util.CasCreationUtils;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
import org.barcelonamedia.uima.tools.DAO.DAOFactory;
import org.barcelonamedia.uima.tools.DAO.XMIDAO;
import org.barcelonamedia.uima.tools.docanalyzer.DBAnnotationViewerDialog;
import org.barcelonamedia.uima.tools.docanalyzer.DBPrefsMediator;
/**
* Main Annotation Viewer GUI. Allows user to choose directory of XCAS or XMI files, then
* launches the AnnotationViewerDialog.
*
*
*/
public class DBAnnotationViewerMain extends JFrame{
private static final long serialVersionUID = -3201723535833938833L;
private static final String HELP_MESSAGE = "Instructions for using DB Annotation Viewer:\n\n"
+ "1) Specify MySQL database parameters, thats is, host, port, user, password and database.\n"
+ "Introduce the SQL query for selecting XMI ids as id field, and XMI files blobs as xmi fields.\n"
+ "Check the uncompress checkbox in case stored XMI files are compressed.\n"
+ "2) In the \"TypeSystem or AE Descriptor File\" field, either type or use the browse\n"
+ "button to select the TypeSystem or AE descriptor for the AE that generated the\n"
+ "XMI or XCAS files. (This is needed for type system infornation only.\n"
+ "Analysis will not be redone.)\n\n"
+ "3) Click the \"View\" button at the buttom of the window.\n\n"
+ "A list of the analyzed documents will be displayed.\n\n\n"
+ "4) Select the view type -- either the Java annotation viewer, HTML,\n"
+ "or XML. The Java annotation viewer is recommended.\n\n"
+ "5) Double-click on a document to view it.\n";
private File uimaHomeDir;
private JTextField inputHost;
private JTextField inputPort;
private JTextField inputUser;
private JTextField inputPassword;
private JTextField inputDatabase;
private JTextField inputQuery;
private JCheckBox checkBoxUncompress;
private FileSelector taeDescriptorFileSelector;
private JButton viewButton;
private JDialog aboutDialog;
/** Stores user preferences */
private Preferences prefs = Preferences.userRoot().node("org/apache/uima/tools/AnnotationViewer");
/** DAO Factory object. */
private DAOFactory daoFactory;
/**
* Constructor. Sets up the GUI.
*/
public DBAnnotationViewerMain(){
super("DB Annotation Viewer");
// set UIMA home dir
uimaHomeDir = new File(System.getProperty("uima.home", "C:/Program Files/apache-uima"));
this.daoFactory = DAOFactory.getDAOFactory(DAOFactory.MYSQL);
try{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e){
// I don't think this should ever happen, but if it does just print error and continue
// with defalt look and feel
System.err.println("Could not set look and feel: " + e.getMessage());
}
// Set frame icon image
try{
this.setIconImage(Images.getImage(Images.MICROSCOPE));
}
catch(IOException e){
System.err.println("Image could not be loaded: " + e.getMessage());
}
this.getContentPane().setBackground(Color.WHITE);
// create about dialog
aboutDialog = new AboutDialog(this, "About DB Annotation Viewer");
// Create Menu Bar
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu fileMenu = new JMenu("File");
JMenu helpMenu = new JMenu("Help");
// Menu Items
JMenuItem aboutMenuItem = new JMenuItem("About");
JMenuItem helpMenuItem = new JMenuItem("Help");
JMenuItem exitMenuItem = new JMenuItem("Exit");
fileMenu.add(exitMenuItem);
helpMenu.add(aboutMenuItem);
helpMenu.add(helpMenuItem);
menuBar.add(fileMenu);
menuBar.add(helpMenu);
// Labels to identify the text fields
final Caption labelInputHost = new Caption("Host: ");
final Caption labelInputPort = new Caption("Port: ");
final Caption labelInputUser = new Caption("User: ");
final Caption labelInputPassword = new Caption("Password: ");
final Caption labelInputDatabase = new Caption("Database: ");
final Caption labelInputQuery = new Caption("Query: ");
final Caption labelCheckboxUncompress = new Caption("Uncompress: ");
final Caption labelStyleMapFile = new Caption("TypeSystem or AE Descriptor File: ");
JPanel controlPanel = new JPanel();
controlPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
controlPanel.setLayout(new SpringLayout());
this.inputHost = new JTextField();
this.inputPort = new JTextField();
this.inputUser = new JTextField();
this.inputPassword = new JTextField();
this.inputDatabase = new JTextField();
this.inputQuery = new JTextField();
this.checkBoxUncompress = new JCheckBox();
this.taeDescriptorFileSelector = new FileSelector("", "TAE Descriptor File", JFileChooser.FILES_ONLY, uimaHomeDir);
File descriptorFile = new File(uimaHomeDir, "examples/descriptors/analysis_engine/PersonTitleAnnotator.xml");
this.taeDescriptorFileSelector.setSelected(descriptorFile.getAbsolutePath());
controlPanel.add(labelInputHost);
controlPanel.add(this.inputHost);
controlPanel.add(labelInputPort);
controlPanel.add(this.inputPort);
controlPanel.add(labelInputUser);
controlPanel.add(this.inputUser);
controlPanel.add(labelInputPassword);
controlPanel.add(this.inputPassword);
controlPanel.add(labelInputDatabase);
controlPanel.add(this.inputDatabase);
controlPanel.add(labelInputQuery);
controlPanel.add(this.inputQuery);
controlPanel.add(labelCheckboxUncompress);
controlPanel.add(this.checkBoxUncompress);
controlPanel.add(labelStyleMapFile);
controlPanel.add(this.taeDescriptorFileSelector);
// Once we add components to controlPanel, we'll
// call SpringUtilities::makeCompactGrid on it.
SpringUtilities.makeCompactGrid(controlPanel, 8, 2, // rows, cols
4, 4, // initX, initY
4, 4); // xPad, yPad
// Event Handlling of "Exit" Menu Item
exitMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
savePreferences();
System.exit(0);
}
});
// Event Handlling of "About" Menu Item
aboutMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
aboutDialog.setVisible(true);
}
});
// Event Handlling of "Help" Menu Item
helpMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JOptionPane.showMessageDialog(DBAnnotationViewerMain.this, HELP_MESSAGE, "DB Annotation Viewer Help", JOptionPane.PLAIN_MESSAGE);
}
});
// Add the panels to the frame
Container contentPanel = getContentPane();
contentPanel.add(controlPanel, BorderLayout.CENTER);
// add banner
JLabel banner = new JLabel(Images.getImageIcon(Images.BANNER));
contentPanel.add(banner, BorderLayout.NORTH);
// Add the view Button to run TAE
viewButton = new JButton("View");
// Add the view button to another panel
JPanel lowerButtonsPanel = new JPanel();
lowerButtonsPanel.add(viewButton);
contentPanel.add(lowerButtonsPanel, BorderLayout.SOUTH);
setContentPane(contentPanel);
JScrollPane jsp = new JScrollPane(controlPanel);
this.add(jsp);
// Event Handling of view Button
viewButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ee){
Hashtable<String, String> connectionParams = new Hashtable<String, String>();
connectionParams.put("server", DBAnnotationViewerMain.this.inputHost.getText());
connectionParams.put("port", DBAnnotationViewerMain.this.inputPort.getText());
connectionParams.put("database", DBAnnotationViewerMain.this.inputDatabase.getText());
connectionParams.put("user", DBAnnotationViewerMain.this.inputUser.getText());
connectionParams.put("password", DBAnnotationViewerMain.this.inputPassword.getText());
try{
viewDocuments(connectionParams);
}
catch(Exception e){
displayError(e);
}
}
});
// load user preferences
if (System.getProperty("uima.noprefs") == null) {
restorePreferences();
}
}
public void viewDocuments(Hashtable<String, String> connectionParams) throws InvalidXMLException, IOException, ResourceInitializationException {
File descriptorFile = new File(taeDescriptorFileSelector.getSelected());
if (!descriptorFile.exists() || descriptorFile.isDirectory()) {
displayError("Descriptor File \"" + descriptorFile.getPath() + "\" does not exist.");
return;
}
XMIDAO xmiDAO = this.daoFactory.getDocumentDAO(connectionParams);
xmiDAO.setSQLSentence(this.inputQuery.getText());
// parse descriptor. Could be either AE or TypeSystem descriptor
Object descriptor = UIMAFramework.getXMLParser().parse(new XMLInputSource(descriptorFile));
// instantiate CAS to get type system. Also build style map file if there is none.
CAS cas;
File styleMapFile;
if (descriptor instanceof AnalysisEngineDescription) {
cas = CasCreationUtils.createCas((AnalysisEngineDescription) descriptor);
styleMapFile = getStyleMapFile((AnalysisEngineDescription) descriptor, descriptorFile
.getPath());
}
else if (descriptor instanceof TypeSystemDescription) {
TypeSystemDescription tsDesc = (TypeSystemDescription) descriptor;
tsDesc.resolveImports();
cas = CasCreationUtils.createCas(tsDesc, null, new FsIndexDescription[0]);
styleMapFile = getStyleMapFile((TypeSystemDescription) descriptor, descriptorFile.getPath());
}
else {
displayError("Invalid Descriptor File \"" + descriptorFile.getPath() + "\""
+ "Must be either an AnalysisEngine or TypeSystem descriptor.");
return;
}
// create DB Annotation Viewer Main Panel
DBPrefsMediator dbPrefsMed = new DBPrefsMediator();
dbPrefsMed.setXmiDAO(xmiDAO);
dbPrefsMed.setUmcompress(this.checkBoxUncompress.isSelected());
DBAnnotationViewerDialog viewerDialog = new DBAnnotationViewerDialog(this, "Analyzed Documents", dbPrefsMed, styleMapFile, null, cas.getTypeSystem(), null, false, cas);
viewerDialog.pack();
viewerDialog.setModal(true);
viewerDialog.setVisible(true);
}
/**
* @param tae // *
* @param taeDescFileName
* @return
* @throws IOException
*/
private File getStyleMapFile(AnalysisEngineDescription tad, String descFileName) throws IOException{
File styleMapFile = getStyleMapFileName(descFileName);
if (!styleMapFile.exists()) {
// generate default style map
String xml = AnnotationViewGenerator.autoGenerateStyleMap(tad.getAnalysisEngineMetaData());
PrintWriter writer;
writer = new PrintWriter(new BufferedWriter(new FileWriter(styleMapFile)));
writer.println(xml);
writer.close();
}
return styleMapFile;
}
/**
* @param tae // *
* @param taeDescFileName
* @return
* @throws IOException
*/
private File getStyleMapFile(TypeSystemDescription tsd, String descFileName) throws IOException {
File styleMapFile = getStyleMapFileName(descFileName);
if (!styleMapFile.exists()) {
// generate default style map
String xml = AnnotationViewGenerator.autoGenerateStyleMap(tsd);
PrintWriter writer;
writer = new PrintWriter(new BufferedWriter(new FileWriter(styleMapFile)));
writer.println(xml);
writer.close();
}
return styleMapFile;
}
/**
* Gets the name of the style map file for the given AE or TypeSystem descriptor filename.
*/
public File getStyleMapFileName(String aDescriptorFileName){
String baseName;
int index = aDescriptorFileName.lastIndexOf(".");
if(index > 0){
baseName = aDescriptorFileName.substring(0, index);
}
else{
baseName = aDescriptorFileName;
}
return new File(baseName + "StyleMap.xml");
}
public static void main(String[] args){
final DBAnnotationViewerMain frame = new DBAnnotationViewerMain();
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
frame.savePreferences();
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
/**
* Save user's preferences using Java's Preference API.
*/
public void savePreferences(){
prefs.put("host", this.inputHost.getText());
prefs.put("port", this.inputPort.getText());
prefs.put("user", this.inputUser.getText());
prefs.put("password", this.inputPassword.getText());
prefs.put("database", this.inputDatabase.getText());
prefs.put("query", this.inputQuery.getText());
prefs.put("uncompress", String.valueOf(this.checkBoxUncompress.isSelected()));
prefs.put("taeDescriptorFile", this.taeDescriptorFileSelector.getSelected());
}
/**
* Reset GUI to preferences last saved via {@link #savePreferences}.
*/
public void restorePreferences(){
// figure defaults
File defaultInputDir = new File(uimaHomeDir, "examples/data/processed");
File defaultTaeDescriptorFile = new File(uimaHomeDir, "examples/descriptors/analysis_engine/PersonTitleAnnotator.xml");
// restore preferences
this.inputHost.setText(this.prefs.get("host", "localhost"));
this.inputPort.setText(this.prefs.get("port", "3306"));
this.inputUser.setText(this.prefs.get("user", ""));
this.inputPassword.setText(this.prefs.get("password", ""));
this.inputDatabase.setText(this.prefs.get("database", ""));
this.inputQuery.setText(this.prefs.get("query", ""));
if(this.prefs.get("uncompress", "false").equals("true")){
this.checkBoxUncompress.setSelected(true);
}
this.taeDescriptorFileSelector.setSelected(prefs.get("taeDescriptorFile", defaultTaeDescriptorFile.toString()));
}
/**
* Displays an error message to the user.
*
* @param aErrorString
* error message to display
*/
public void displayError(String aErrorString){
// word-wrap long mesages
StringBuffer buf = new StringBuffer(aErrorString.length());
final int CHARS_PER_LINE = 80;
int charCount = 0;
StringTokenizer tokenizer = new StringTokenizer(aErrorString, " \n", true);
while (tokenizer.hasMoreTokens()) {
String tok = tokenizer.nextToken();
if (tok.equals("\n")) {
buf.append("\n");
charCount = 0;
} else if ((charCount > 0) && ((charCount + tok.length()) > CHARS_PER_LINE)) {
buf.append("\n").append(tok);
charCount = tok.length();
} else {
buf.append(tok);
charCount += tok.length();
}
}
JOptionPane.showMessageDialog(DBAnnotationViewerMain.this, buf.toString(), "Error", JOptionPane.ERROR_MESSAGE);
}
/**
* Displays an error message to the user.
*
* @param aThrowable
* Throwable whose message is to be displayed.
*/
public void displayError(Throwable aThrowable){
aThrowable.printStackTrace();
String message = aThrowable.toString();
// For UIMAExceptions or UIMARuntimeExceptions, add cause info.
// We have to go through this nonsense to support Java 1.3.
// In 1.4 all exceptions can have a cause, so this wouldn't involve
// all of this typecasting.
while ((aThrowable instanceof UIMAException) || (aThrowable instanceof UIMARuntimeException)) {
if (aThrowable instanceof UIMAException) {
aThrowable = ((UIMAException) aThrowable).getCause();
} else if (aThrowable instanceof UIMARuntimeException) {
aThrowable = ((UIMARuntimeException) aThrowable).getCause();
}
if (aThrowable != null) {
message += ("\nCausedBy: " + aThrowable.toString());
}
}
displayError(message);
}
/*
* (non-Javadoc)-
*
* @see java.awt.Component#getPreferredSize()
*/
public Dimension getPreferredSize() {
return new Dimension(640, 350);
}
}