package org.solrmarc.debug;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import net.miginfocom.swing.MigLayout;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.JPanel;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import java.awt.event.ActionEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import org.marc4j.MarcError;
import org.marc4j.MarcReader;
import org.marc4j.MarcReaderConfig;
import org.marc4j.MarcReaderFactory;
import org.marc4j.marc.Record;
import org.solrmarc.driver.BootableMain;
import org.solrmarc.index.indexer.AbstractValueIndexer;
import org.solrmarc.index.indexer.IndexerSpecException;
import org.solrmarc.index.indexer.ValueIndexerFactory;
//import org.solrmarc.marc.MarcReaderFactory;
import org.solrmarc.tools.PropertyUtils;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.swing.JSeparator;
import java.awt.event.InputEvent;
public class SolrMarcDebug extends BootableMain
{
private JFrame frmSolrmarcIndexSpecification;
// private final Action action = new SwingAction();
private Map<String, Record> recordMap;
private JTextPane configPane;
private JTextPane outputPane;
private JTextPane errorPane;
private JTextPane recordPane;
ValueIndexerFactory indexerFactory = null;
JComboBox<String> marcIdentifier = null;
//undo helpers
protected Action undoAction;
protected Action redoAction;
protected CompoundUndoManager undo = null;
HashMap<Object, Action> actions;
String previousConfigText = "";
List<AbstractValueIndexer<?>> indexers = null;
Properties readerProps = new Properties();
MarcReaderConfig readerConfig;
static int[] fontSizeArray = { 8, 10, 12, 14, 18, 22, 28, 36, 42 };
/**
* Launch the application.
*/
public static void main(final String[] args)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
SolrMarcDebug window = new SolrMarcDebug(args);
window.frmSolrmarcIndexSpecification.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public SolrMarcDebug(String args[])
{
super.processArgs(args, false);
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize()
{
indexerFactory = ValueIndexerFactory.initialize(homeDirStrs);
System.setProperty("solrmarc.indexer.test.fire.method", "true");
String inputSource[] = new String[1];
String propertyFileAsURLStr = PropertyUtils.getPropertyFileAbsoluteURL(homeDirStrs, options.valueOf(readOpts), true, inputSource);
try
{
readerProps.load(PropertyUtils.getPropertyFileInputStream(propertyFileAsURLStr));
}
catch (FileNotFoundException e2)
{
// TODO Auto-generated catch block
e2.printStackTrace();
}
catch (IOException e2)
{
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
readerConfig = new MarcReaderConfig(readerProps);
}
catch (NoClassDefFoundError cnf)
{
readerConfig = null;
}
recordMap = new LinkedHashMap<String, Record>();
frmSolrmarcIndexSpecification = new JFrame();
frmSolrmarcIndexSpecification.setTitle("SolrMarc Index Specification Debugger");
frmSolrmarcIndexSpecification.setBounds(100, 100, 1024, 828);
frmSolrmarcIndexSpecification.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmSolrmarcIndexSpecification.getContentPane().setLayout(
new MigLayout("", "[512px,grow][][512px,grow]", "[42.00][361.00px,grow][::-2.00px][141.00px,grow][][100.00px,grow]"));
JPanel panel_1 = new JPanel();
frmSolrmarcIndexSpecification.getContentPane().add(panel_1, "cell 0 0 3 1,grow");
panel_1.setLayout(new MigLayout("", "[grow][][][]", "[][grow][]"));
marcIdentifier = new JComboBox<String>();
panel_1.add(marcIdentifier, "flowx,cell 0 0,grow");
JButton btnNextRecord = new JButton("Next >");
btnNextRecord.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
int index = marcIdentifier.getSelectedIndex();
int cnt = marcIdentifier.getItemCount();
if (index >= 0 && index < cnt - 1) marcIdentifier.setSelectedIndex(index + 1);
}
});
JButton btnApply = new JButton("Apply");
btnApply.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
int index = marcIdentifier.getSelectedIndex();
marcIdentifier.setSelectedIndex(index);
}
});
panel_1.add(btnApply, "cell 1 0");
JButton btnPrevRecord = new JButton("< Prev");
btnPrevRecord.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
int index = marcIdentifier.getSelectedIndex();
if (index > 0) marcIdentifier.setSelectedIndex(index - 1);
}
});
panel_1.add(btnPrevRecord, "cell 2 0,alignx left");
btnPrevRecord.setMnemonic('<');
panel_1.add(btnNextRecord, "cell 3 0");
btnNextRecord.setMnemonic('>');
marcIdentifier.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
@SuppressWarnings("unchecked")
JComboBox<String> source = ((JComboBox<String>) e.getSource());
Object selected = source.getSelectedItem();
if (selected != null)
{
String fKey = selected.toString();
Record rec = recordMap.get(fKey);
recordPane.setText(rec.toString());
recordPane.setCaretPosition(0);
// String fieldNameStr = fieldName.getText();
processRecordToOutput(rec);
}
}
});
JScrollPane scrollPane = new JScrollPane();
frmSolrmarcIndexSpecification.getContentPane().add(scrollPane, "cell 0 1,grow");
recordPane = new JTextPane();
recordPane.setEditable(false);
scrollPane.setViewportView(recordPane);
JScrollPane scrollPane_1 = new JScrollPane();
frmSolrmarcIndexSpecification.getContentPane().add(scrollPane_1, "cell 0 3 3 1,grow");
configPane = new JTextPane();
scrollPane_1.setViewportView(configPane);
// configPane.getDocument().
undo = new CompoundUndoManager(configPane);
configPane.getDocument().addUndoableEditListener(undo);
JScrollPane scrollPane_2 = new JScrollPane();
frmSolrmarcIndexSpecification.getContentPane().add(scrollPane_2, "cell 2 1,grow");
outputPane = new JTextPane();
outputPane.setEditable(false);
scrollPane_2.setViewportView(outputPane);
JSeparator separator_1 = new JSeparator();
frmSolrmarcIndexSpecification.getContentPane().add(separator_1, "cell 0 4 3 1");
JScrollPane scrollPane_3 = new JScrollPane();
frmSolrmarcIndexSpecification.getContentPane().add(scrollPane_3, "cell 0 5 3 1,grow");
errorPane = new JTextPane();
errorPane.setEditable(false);
scrollPane_3.setViewportView(errorPane);
setFontSize(getCurFontSize());
//Set up the menu bar.
actions=createActionTable(configPane);
JMenuBar menuBar = new JMenuBar();
frmSolrmarcIndexSpecification.setJMenuBar(menuBar);
JMenu mnNewMenu = new JMenu("File");
menuBar.add(mnNewMenu);
JMenuItem mntmOpenConfig = new JMenuItem("Open Config...");
mnNewMenu.add(mntmOpenConfig);
JMenuItem mntmOpenMarcRecord = new JMenuItem("Open Marc Record ...");
mnNewMenu.add(mntmOpenMarcRecord);
JMenu mnEdit = createEditMenu();
menuBar.add(mnEdit);
JMenu mnViewMenu = new JMenu("View");
menuBar.add(mnViewMenu);
JMenuItem mntmFontPlus = new JMenuItem("Increase Fontsize");
mntmFontPlus.setEnabled(true);
mntmFontPlus.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_MASK));
mnViewMenu.add(mntmFontPlus);
mntmFontPlus.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
increaseFontSize();
}
});
JMenuItem mntmFontMinus = new JMenuItem("Decrease Fontsize");
mntmFontMinus.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_MASK));
mnViewMenu.add(mntmFontMinus);
mntmFontMinus.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
decreaseFontSize();
}
});
mntmOpenConfig.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
File f = null; // new File("resources/testSpec.properties");
JFileChooser chooser = new JFileChooser(homeDirStrs[0]);
FileNameExtensionFilter filter = new FileNameExtensionFilter("Index Property Files", "properties");
chooser.setFileFilter(filter);
int returnVal = chooser.showOpenDialog(frmSolrmarcIndexSpecification);
if (returnVal == JFileChooser.APPROVE_OPTION)
{
f = chooser.getSelectedFile();
}
else
{
return;
}
openSpecifiedConfig(f, true);
}
});
mntmOpenMarcRecord.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
// File f = new File("resources/specTestRecs.mrc");
File f = null; // new File("resources/testSpec.properties");
JFileChooser chooser = new JFileChooser(homeDirStrs[0]);
FileNameExtensionFilter filter = new FileNameExtensionFilter("MARC Record Files", "mrc", "xml");
chooser.setFileFilter(filter);
int returnVal = chooser.showOpenDialog(frmSolrmarcIndexSpecification);
if (returnVal == JFileChooser.APPROVE_OPTION)
{
f = chooser.getSelectedFile();
}
else
{
return;
}
openSpecifiedMarcFile(f, true);
}
});
// read command line arguments to initialize windows
String specs = options.valueOf(configSpecs);
if (specs != null) configureIndexer(specs);
List<String> inputFiles = options.valuesOf(files);
boolean first = true;
for (String inputFile : inputFiles)
{
File marcFile = new File(inputFile);
openSpecifiedMarcFile(marcFile, first);
first = false;
}
}
public void configureIndexer(String indexSpecifications)
{
String[] indexSpecs = indexSpecifications.split("[ ]*,[ ]*");
File[] specFiles = new File[indexSpecs.length];
int i = 0;
// currently only reads the first one specified!
for (String indexSpec : indexSpecs)
{
File specFile = new File(indexSpec);
if (!specFile.isAbsolute()) specFile = PropertyUtils.findFirstExistingFile(homeDirStrs, indexSpec);
specFiles[i++] = specFile;
break; // if there is more than one, ignore the rest!
}
if (specFiles.length > 0 && specFiles[0].exists() && specFiles[0].canRead())
openSpecifiedConfig(specFiles[0], true);
}
private int getCurFontSize()
{
Font currFont = recordPane.getFont();
int fontSize = currFont.getSize();
return(fontSize);
}
private void increaseFontSize()
{
int fontSize = getCurFontSize();
int fontSizeIndex = getFontSizeIndex(fontSizeArray, fontSize);
if (fontSizeIndex < fontSizeArray.length-2)
{
fontSizeIndex++;
setFontSize(fontSizeArray[fontSizeIndex]);
}
}
private void decreaseFontSize()
{
int fontSize = getCurFontSize();
int fontSizeIndex = getFontSizeIndex(fontSizeArray, fontSize);
if (fontSizeIndex > 0)
{
fontSizeIndex--;
setFontSize(fontSizeArray[fontSizeIndex]);
}
}
private int getFontSizeIndex(int[] fontSizeArray, int fontSize)
{
for (int i = 0; i < fontSizeArray.length; i++)
{
if (fontSize >= fontSizeArray[i] && (i < fontSizeArray.length-1 ? fontSize < fontSizeArray[i+1] : true))
return(i);
}
return(1);
}
private void setFontSize(int fontSize)
{
Font currFont = recordPane.getFont();
recordPane.setFont(new Font("Courier New", currFont.getStyle(), fontSize));
currFont = configPane.getFont();
configPane.setFont(new Font("Courier New", currFont.getStyle(), fontSize));
currFont = outputPane.getFont();
outputPane.setFont(new Font("Courier New", currFont.getStyle(), fontSize));
currFont = errorPane.getFont();
errorPane.setFont(new Font("Courier New", currFont.getStyle(), fontSize));
}
private void openSpecifiedConfig(File f, boolean clear)
{
FileReader reader = null;
try
{
configPane.read(new FileReader(f), null);
configPane.getDocument().addUndoableEditListener(undo);
undo.discardAllEdits();
undoAction.setEnabled(false);
redoAction.setEnabled(false);
}
catch (FileNotFoundException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
finally
{
if (reader != null)
{
try
{
reader.close();
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
private void openSpecifiedMarcFile(File marcFile, boolean pointToFirst)
{
MarcReader reader;
String firstId = null;
try
{
reader = MarcReaderFactory.makeReader(readerConfig, new FileInputStream(marcFile));
while (reader.hasNext())
{
Record record = reader.next();
String id = record.getControlNumber();
if (pointToFirst && firstId == null) firstId = id;
if (!recordMap.containsKey(id))
{
recordMap.put(id, record);
marcIdentifier.addItem(id);
}
else
{
recordMap.put(id, record);
}
}
if (pointToFirst) marcIdentifier.setSelectedItem(firstId);
}
catch (IOException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//Create the edit menu.
protected JMenu createEditMenu() {
JMenu menu = new JMenu("Edit");
//Undo and redo are actions of our own creation.
undoAction = undo.getUndoAction();
menu.add(undoAction);
redoAction = undo.getRedoAction();
menu.add(redoAction);
menu.addSeparator();
//These actions come from the default editor kit.
//Get the ones we want and stick them in the menu.
menu.add(getActionByName(DefaultEditorKit.cutAction, "Cut", KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_DOWN_MASK)));
menu.add(getActionByName(DefaultEditorKit.copyAction, "Copy", KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK)));
menu.add(getActionByName(DefaultEditorKit.pasteAction, "Paste", KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK)));
// menu.addSeparator();
// menu.add(getActionByName(DefaultEditorKit.selectAllAction));
return menu;
}
//The following two methods allow us to find an
//action provided by the editor kit by its name.
private HashMap<Object, Action> createActionTable(JTextComponent textComponent)
{
HashMap<Object, Action> actions = new HashMap<Object, Action>();
Action[] actionsArray = textComponent.getActions();
for (int i = 0; i < actionsArray.length; i++)
{
Action a = actionsArray[i];
actions.put(a.getValue(Action.NAME), a);
}
return actions;
}
private Action getActionByName(String name, String label, KeyStroke keyStroke)
{
Action action = actions.get(name);
action.putValue(Action.NAME, label);
if (keyStroke != null) action.putValue(Action.ACCELERATOR_KEY, keyStroke);
return action;
}
private void processRecordToOutput(Record rec)
{
String currentConfigText = configPane.getText();
if (! currentConfigText.equals(previousConfigText) || indexers == null)
{
try
{
currentConfigText = currentConfigText.replaceAll(",[ \t]*\n[ \t]+", ",");
indexers = indexerFactory.createValueIndexers(currentConfigText.split("\n"));
previousConfigText = currentConfigText;
}
catch (IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InstantiationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
List<IndexerSpecException> exceptions = indexerFactory.getValidationExceptions();
errorPane.setText(getTextForExceptions(exceptions));
indexerFactory.clearPerRecordErrors();
outputPane.setText("");
SimpleAttributeSet attributesErr = new SimpleAttributeSet();
attributesErr = new SimpleAttributeSet();
attributesErr.addAttribute(StyleConstants.CharacterConstants.Bold, Boolean.FALSE);
attributesErr.addAttribute(StyleConstants.CharacterConstants.Italic, Boolean.FALSE);
attributesErr.addAttribute(StyleConstants.CharacterConstants.Foreground, Color.RED);
Document doc = outputPane.getDocument();
for (AbstractValueIndexer<?> indexer : indexers)
{
Collection<String> fieldNameList = indexer.getSolrFieldNames();
Collection<String> results = null;
try
{
results = indexer.getFieldData(rec);
for (String fieldName : fieldNameList)
{
for (String result : results)
{
String outLine = fieldName + " : " + result + "\n";
try
{
doc.insertString(doc.getLength(), outLine, null);
}
catch (BadLocationException exc)
{
exc.printStackTrace();
}
}
}
}
catch (InvocationTargetException ioe)
{
Throwable wrapped = ioe.getTargetException();
String outLine = "marc_error : " + indexer.getSolrFieldNames().toString() + wrapped.getMessage() + "\n";
try
{
doc.insertString(doc.getLength(), outLine, attributesErr);
}
catch (BadLocationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
catch (IllegalArgumentException e)
{
String outLine = "marc_error : " + indexer.getSolrFieldNames().toString() + e.getMessage() + "\n";
try
{
doc.insertString(doc.getLength(), outLine, attributesErr);
}
catch (BadLocationException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
catch (IndexerSpecException e)
{
String outLine = "marc_error : " + indexer.getSolrFieldNames().toString() + e.getMessage() + "\n";
try
{
doc.insertString(doc.getLength(), outLine, attributesErr);
}
catch (BadLocationException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
catch (Exception e)
{
String outLine = "marc_error : " + indexer.getSolrFieldNames().toString() + e.getMessage() + "\n";
try
{
doc.insertString(doc.getLength(), outLine, attributesErr);
}
catch (BadLocationException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
List<IndexerSpecException> perRecordExceptions = indexerFactory.getPerRecordErrors();
try
{
doc.insertString(doc.getLength(), getTextForMarcErrorsAndExceptions(rec, perRecordExceptions), attributesErr);
}
catch (BadLocationException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
outputPane.setCaretPosition(0);
}
private String getTextForMarcErrorsAndExceptions(Record rec, List<IndexerSpecException> exceptions)
{
StringBuilder text = new StringBuilder();
if (rec.hasErrors())
{
for (MarcError err : rec.getErrors())
{
text.append("Marc Record Error: ").append(err.toString()).append("\n");
}
}
if (exceptions != null)
{
for (IndexerSpecException e : exceptions)
{
if (e.getSolrField() == null) e.setSolrFieldAndSpec("marc_error", null);
text.append(e.getMessage()).append("\n");
for (Throwable cause = e.getCause(); cause != null; cause = cause.getCause())
{
text.append(e.getSolrField()).append(" : ").append(cause.getMessage()).append("\n");
}
}
}
return(text.toString());
}
private String getTextForExceptions(List<IndexerSpecException> exceptions)
{
StringBuilder text = new StringBuilder();
String lastSpec = "";
for (IndexerSpecException e : exceptions)
{
String specMessage = e.getSpecMessage();
if (!specMessage.equals(lastSpec))
{
text.append(specMessage).append("\n");
}
lastSpec = specMessage;
text.append(e.getMessage()).append("\n");
for (Throwable cause = e.getCause(); cause != null; cause = cause.getCause())
{
text.append(e.getSolrField()).append(" : ").append(cause.getMessage()).append("\n");
}
}
return (text.toString());
}
}