Skip to content
Snippets Groups Projects
Commit 30c6848e authored by Lange, Dr. Herbert's avatar Lange, Dr. Herbert
Browse files

first working version

parent 99d80258
No related branches found
No related tags found
No related merge requests found
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>bundle</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
<excludes>
<exclude>de.uni_hamburg.corpora:corpus-services</exclude>
</excludes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>${project.build.outputDirectory}</directory>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
pom.xml 0 → 100644
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.uni_hamburg.corpora</groupId>
<artifactId>corpus-service-gui</artifactId>
<version>1.0-SNAPSHOT</version>
<name>corpus-service-gui</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mainClass>de.uni_hamburg.corpora.gui.GUIApp</mainClass>
</properties>
<dependencies>
<dependency>
<groupId>de.uni_hamburg.corpora</groupId>
<artifactId>corpus-services</artifactId>
<version>1.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<!-- archive>
<manifestEntries>
<Class-Path>corpus-services.jar</Class-Path>
<Main-Class>${mainClass}</Main-Class>
</manifestEntries>
</archive -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${mainClass}</mainClass>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${mainClass}</mainClass>
</manifest>
<!-- manifestEntries>
<Class-Path>corpus-services.jar</Class-Path>
</manifestEntries -->
</archive>
<descriptors>
<descriptor>jar-exclude-corpus-services.xml</descriptor>
</descriptors>
<!-- descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs -->
<appendAssemblyId>true</appendAssemblyId>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
#!/bin/bash
java -cp corpus-services.jar:target/corpus-service-gui-1.0-SNAPSHOT-jar-with-dependencies.jar de.uni_hamburg.corpora.gui.GUIApp
package de.uni_hamburg.corpora.gui;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* Class representing the YAML config created by the web interface
*/
public class Config {
@JsonProperty("corpus")
String name;
@JsonProperty("checker")
List<String> functions = new ArrayList<>();
// Properties parameters = new Properties();
@JsonProperty("parameters")
Map<String,String> parameters = new HashMap<>();
public Config() {
}
/**
* Reads a config file
* @param fileName the config file
* @return the configuration
* @throws IOException if reading fails
*/
public static Config read(String fileName) throws IOException {
// Instantiating a new ObjectMapper as a YAMLFactory
ObjectMapper om = new YAMLMapper()
// Don't expect quotes around strings when not necessary
.configure(YAMLGenerator.Feature.MINIMIZE_QUOTES,true)
// Don't fail if more information than expected
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.findAndRegisterModules();
return om.readValue(new File(fileName), Config.class);
}
/**
* Writes a configuration back as a YAML string
* @return the resulting YAML
* @throws JsonProcessingException if conversion fails
*/
public String write() throws JsonProcessingException {
ObjectMapper om = new YAMLMapper()
.configure(YAMLGenerator.Feature.MINIMIZE_QUOTES,true);
return om.writeValueAsString(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getFunctions() {
return functions;
}
public void setFunctions(List<String> functions) {
this.functions = functions;
}
@JsonAnyGetter
public Map<String,String> getParameters() {
return parameters;
}
@JsonAnySetter
public void setParameters(Map<String,String> parameters) {
this.parameters = parameters;
}
public Properties getParametersAsProperties() {
Properties props = new Properties();
props.putAll(this.parameters);
return props;
}
@Override
public String toString() {
return "Config{" +
"name='" + name + '\'' +
", functions=" + String.join(",", functions) +
", params=" + parameters +
'}';
}
}
package de.uni_hamburg.corpora.gui;
import de.uni_hamburg.corpora.CorpusData;
import de.uni_hamburg.corpora.CorpusFunction;
import de.uni_hamburg.corpora.Report;
import de.uni_hamburg.corpora.ReportItem;
import org.reflections.Reflections;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author bba1792 Dr. Herbert Lange
* @version 20220404
* Class encapsulating some corpus services functionality
*/
public class CorpusServices {
/**
* Gets the names of all corpus functions, ie all classes implementing CorpusFunction, defined in de.uni_hamburg.corpora.
*
* @return the list of corpus functions
*/
public static Set<String> getCorpusFunctions() {
// Get all classes implementing the interface via reflections
Reflections reflections = new Reflections("de.uni_hamburg.corpora");
Set<Class<? extends CorpusFunction>> classes = reflections.getSubTypesOf(CorpusFunction.class);
// Convert classes to class names
return classes.stream()
.filter((c) -> Modifier.isPublic(c.getModifiers()) && !Modifier.isAbstract(c.getModifiers()))
.map(Class::getCanonicalName)
.collect(Collectors.toSet());
}
/**
* Gets the class names of all corpus types, ie all classes derived from CorpusData, defined in de.uni_hamburg.corpora.
*
* @return the list of corpus types
*/
public static Set<String> getCorpusTypes () {
Reflections reflections = new Reflections("de.uni_hamburg.corpora");
HashSet<String> classNames = new HashSet<>();
Set<Class<? extends CorpusData>> classes = reflections.getSubTypesOf(CorpusData.class);
for (Class<? extends CorpusData> c : classes) {
classNames.add(c.getCanonicalName());
}
return classNames ;
}
/**
* Generate the summary of a report returning the count of items for each severity level.
*
* @param report the report
* @return the hash map
*/
public static HashMap<ReportItem.Severity,Integer> generateSummary(Report report) {
HashMap<ReportItem.Severity,Integer> results = new HashMap<>();
for (ReportItem item : report.getRawStatistics()) {
results.compute(item.getSeverity(),(k,v) -> (v==null) ? 1 : v + 1) ;
}
return results;
}
}
package de.uni_hamburg.corpora.gui;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.uni_hamburg.corpora.*;
import org.exmaralda.partitureditor.jexmaralda.JexmaraldaException;
import org.xml.sax.SAXException;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Logger;
class CorpusThread extends Thread {
private final Logger logger = Logger.getLogger(this.getClass().getName());
de.uni_hamburg.corpora.Report report = new de.uni_hamburg.corpora.Report();
String corpusName;
String inFile ;
List<String> functionNames;
String outFile;
Properties props; // The properties for the function calls
Function<String,Void> callbackFunction;
CorpusThread(String name, String infile, String outfile, List<String> functions, Properties properties,
Function<String, Void> callback) {
this.corpusName=name;
if (infile.equals("tmp"))
this.inFile = System.getProperty("java.io.tmpdir") + "/corpus-files";
else
this.inFile = infile;
this.functionNames = functions ;
this.props = properties;
if (outfile.equals("tmp")) {
File tmpDir = new File(System.getProperty("java.io.tmpdir") + "/" + corpusName);
// Create parent directory if it is missing
if (!tmpDir.exists())
tmpDir.mkdirs();
this.outFile = tmpDir + "/checker-report.html";
}
else
this.outFile = outfile;
callbackFunction = callback;
logger.info("Input: " + this.inFile + " output: " + this.outFile + " functions: " + functions + " params: " +
this.props);
}
public void run() {
Set<String> allFunctions = CorpusServices.getCorpusFunctions() ;
CorpusIO cio = new CorpusIO();
report.addNote("CorpusWebServices","Starting run at " +
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()));
try {
// Create corpus from given input file/folder
Corpus corpus;
if (corpusName != null && !corpusName.isEmpty()) {
URL baseUrl = new File(inFile).toURI().toURL();
corpus = new Corpus(corpusName,baseUrl,cio.read(baseUrl,report)) ;
}
else
corpus = new Corpus(cio.read(new File(inFile).toURI().toURL(),report)) ;
logger.info("Loaded " + corpus.getCorpusData().size() + " corpus files");
logger.info("Got report: " + report.getFullReports());
// For all functions to be applied, get their canonical name and create an object for them
Set<CorpusFunction> functions = new HashSet<>() ;
for (String function : functionNames) {
// Indicator if we encountered the function
boolean found = false ;
for (String canonical : allFunctions) {
if (canonical.toLowerCase(Locale.ROOT).endsWith("." + function.toLowerCase(Locale.ROOT))) {
// Create an object from canonical name. calls the constructor with thr constructor setting hasfixingoption to false
try {
functions.add((CorpusFunction) Class.forName(canonical).getDeclaredConstructor(Properties.class).newInstance(props));
found = true ;
}
catch (IllegalArgumentException | NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
logger.severe(String.format("Error creating %s", canonical));
report.addWarning("CorpusWebServices", "Test " + function + " cannot be created");
// e.printStackTrace();
}
}
}
if (!found) {
// Warn if we could not find the function
report.addWarning("CorpusWebServices", "Test " + function + " is not available");
logger.severe(String.format("Function %s is not available in corpus services", function));
}
}
for (CorpusFunction f : functions) {
logger.severe(String.format("Running function %s", f.getFunction()));
report.addNote("CorpusWebServices", "Run test " + f.getFunction());
de.uni_hamburg.corpora.Report result = f.execute(corpus);
report.merge(result);
report.addNote("CorpusWebServices", "Finish test " + f.getFunction());
logger.severe(String.format("Done with function %s", f.getFunction()));
}
} catch (URISyntaxException | ClassNotFoundException | IOException | SAXException | JexmaraldaException e) {
e.printStackTrace();
}
logger.info("Done with all functions");
report.addNote("CorpusWebServices","Finished all tests at " +
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss").format(LocalDateTime.now()));
logger.info("Creating report");
// Get summary
HashMap<ReportItem.Severity,Integer> summary = CorpusServices.generateSummary(report);
// try to convert to JSON
String jsonSummary = "{}";
try {
jsonSummary = new ObjectMapper().writeValueAsString(summary);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// Generate HTML report
Collection<ReportItem> rawStatistics = report.getRawStatistics();
String reportOutput = ReportItem.generateDataTableHTML(new ArrayList<>(rawStatistics),
report.getSummaryLines());
// Alternative: Generate XML
//XStream xstream = new XStream();
//String reportOutput = xstream.toXML(rawStatistics);
logger.info("Writing report to " + outFile);
try {
BufferedWriter out = new BufferedWriter(new FileWriter(outFile));
out.write(reportOutput);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
logger.info("Done with report");
callbackFunction.apply(outFile);
}
}
\ No newline at end of file
package de.uni_hamburg.corpora.gui;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.util.function.Function;
/**
* The definition of the GUI
* @author bba1792, Dr. Herbert Lange
* @version 20220802
*/
public class GUI {
// Information on how to download the corpus-services
private final String BRANCH = "develop-quest";
private final String FILE_URL = "https://gitlab.rrz.uni-hamburg.de/corpus-services/corpus-services/-/jobs/artifacts/" +
BRANCH + "/raw/target/corpus-services-1.0.jar?job=compile_withmaven";
// The main window
JFrame window;
// The path to the report created by the checkers
String reportFile;
/**
* Constructor setting up the GUI
*/
public GUI() {
window = new JFrame("Corpus-Services GUI");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel(new GridLayout(5,1));
JPanel corpusFiles = new JPanel(new GridLayout(1,3));
mainPanel.add(new JLabel("Corpus directory"));
final JTextField corpusPath = new JTextField();
corpusFiles.add(corpusPath);
final JButton corpusButton = new JButton("Select");
corpusButton.addActionListener(actionEvent -> {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = chooser.showOpenDialog(corpusButton);
if (result == JFileChooser.APPROVE_OPTION)
corpusPath.setText(chooser.getSelectedFile().toString());
});
corpusFiles.add(corpusButton);
mainPanel.add(corpusFiles);
mainPanel.add(new JLabel("Configuration file"));
JPanel configFile = new JPanel(new GridLayout(1,3));
final JTextField configPath = new JTextField();
configFile.add(configPath);
final JButton configButton = new JButton("Select");
configButton.addActionListener(actionEvent -> {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new FileNameExtensionFilter(
"YAML configurations", "yaml", "yml"));
int result = chooser.showOpenDialog(configButton);
if (result == JFileChooser.APPROVE_OPTION)
configPath.setText(chooser.getSelectedFile().toString());
});
configFile.add(configButton);
mainPanel.add(configFile);
JPanel buttonPanel = new JPanel(new GridLayout(1,4));
JButton checkButton = new JButton("Check corpus");
buttonPanel.add(checkButton);
JButton reportButton = new JButton("Show report");
reportButton.setEnabled(false);
buttonPanel.add(reportButton);
JButton updateButton = new JButton("Update corpus services");
buttonPanel.add(updateButton);
JButton exitButton = new JButton("Exit");
buttonPanel.add(exitButton);
// Handle check
// Create callback for after the check
Function<String, Void> callback =
(outFile) -> {
reportFile = outFile;
reportButton.setEnabled(true);
JOptionPane.showMessageDialog(window,
"Checks executed successfully. You can now check the report.",
"Success",
JOptionPane.INFORMATION_MESSAGE);
checkButton.setEnabled(true);
updateButton.setEnabled(true);
return null ;
};
checkButton.addActionListener(actionEvent -> {
checkButton.setEnabled(false);
updateButton.setEnabled(false);
// Do the checking
try {
Config config = Config.read(configPath.getText());
JOptionPane.showMessageDialog(window,
"Starting checks now. Depending on the corpus and the checks selected this can take" +
"a while",
"Info",
JOptionPane.INFORMATION_MESSAGE);
CorpusThread worker = new CorpusThread(
config.getName()
, corpusPath.getText()
, "tmp" // write report to tmp
, config.getFunctions()
, config.getParametersAsProperties()
, callback);
worker.start();
} catch (IOException e) {
JOptionPane.showMessageDialog(window,
"Problem loading configuration file",
"Error",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
checkButton.setEnabled(true);
updateButton.setEnabled(true);
}
});
// Handle update
updateButton.addActionListener(actionEvent -> {
checkButton.setEnabled(false);
updateButton.setEnabled(false);
exitButton.setEnabled(false);
JOptionPane.showMessageDialog(window,
"Download started. Depending on the internet connection this can take a few minutes",
"Info",
JOptionPane.INFORMATION_MESSAGE);
try {
BufferedInputStream in = new BufferedInputStream(new URL(FILE_URL).openStream());
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("corpus-services.jar"));
in.transferTo(out);
in.close();
out.close();
JOptionPane.showMessageDialog(window,
"Download successful. You now have to restart the application.",
"Success",
JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e) {
//custom title, error icon
JOptionPane.showMessageDialog(window,
"Error downloading file.",
"Error",
JOptionPane.ERROR_MESSAGE);
}
checkButton.setEnabled(true);
updateButton.setEnabled(true);
exitButton.setEnabled(true);
});
reportButton.addActionListener(actionEvent -> {
Desktop dt = Desktop.getDesktop();
try {
dt.open(new File(reportFile));
} catch (Exception e) {
JOptionPane.showMessageDialog(window,
"Error opening report file " + reportFile + ".",
"Error",
JOptionPane.ERROR_MESSAGE);
}
});
// Handle exit
exitButton.addActionListener(actionEvent -> {
// Close window
window.dispose();
});
mainPanel.add(buttonPanel);
window.getContentPane().add(mainPanel);
}
/**
* Shows the window
*/
public void show() {
window.setVisible(true);
}
}
package de.uni_hamburg.corpora.gui;
/**
* Simple GUI for the corpus services
* @author bba1792, Dr. Herbert Lange
* @version 20220802
*/
public class GUIApp
{
public static void main( String[] args )
{
// Create window
GUI gui = new GUI();
// Show window
gui.show();
// This app will continue running until the window is closed
}
}
package de.uni_hamburg.corpora;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment