Coverage Summary for Class: WikiFieldHelper (org.kitodo.production.helper)
Class |
Class, %
|
Method, %
|
Line, %
|
WikiFieldHelper |
100%
(1/1)
|
66,7%
(14/21)
|
58,1%
(115/198)
|
/*
* (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
*
* This file is part of the Kitodo project.
*
* It is licensed under GNU General Public License version 3 or later.
*
* For the full copyright and license information, please read the
* GPL3-License.txt file that was distributed with this source code.
*/
package org.kitodo.production.helper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.kitodo.data.database.beans.Comment;
import org.kitodo.data.database.beans.Process;
import org.kitodo.data.database.beans.Property;
import org.kitodo.data.database.beans.Task;
import org.kitodo.data.database.beans.User;
import org.kitodo.data.database.enums.CommentType;
import org.kitodo.data.database.exceptions.DAOException;
import org.kitodo.data.exceptions.DataException;
import org.kitodo.production.services.ServiceManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class WikiFieldHelper {
private static final Logger logger = LogManager.getLogger(WikiFieldHelper.class);
private static final String CORRECTION_FOR_TASK_DE = "Korrektur fuer Schritt";
private static final String CORRECTION_FOR_TASK_EN = "Correction for step";
/**
* Private constructor to hide the implicit public one.
*/
private WikiFieldHelper() {
}
/**
* transform wiki field to Comment objects.
*
* @param process
* process as object.
*/
public static Process transformWikiFieldToComment(Process process) throws DAOException, DataException, ParseException {
String wikiField = process.getWikiField();
wikiField = wikiField.replaceAll("ü", "ue");
wikiField = wikiField.replaceAll("ü", "ue");
if (!wikiField.isEmpty()) {
wikiField = wikiField.replace("</p>", "");
String[] comments = wikiField.split("<p>");
if (!comments[0].isEmpty()) {
String oldComments = comments[0];
oldComments = "<messages>" + oldComments + "</messages>";
Document document = convertStringToDocument(oldComments);
transformOldFormatWikifieldToComments(document, process);
}
List<String> list = new ArrayList<>(Arrays.asList(comments));
list.remove(list.get(0));
comments = list.toArray(new String[0]);
transformNewFormatWikiFieldToComments(comments, process);
Process processWithoutProperties = deleteProcessCorrectionProperties(process);
processWithoutProperties.setWikiField("");
ServiceManager.getProcessService().save(processWithoutProperties);
return processWithoutProperties;
}
return process;
}
private static Property getCorrectionRequiredProperty(Process process, String message) {
List<Property> properties = process.getProperties();
for (Property property : properties) {
String translation = Helper.getTranslation("correctionNecessary");
String msg = getWikiFieldMessage(message);
if (property.getTitle().equals(translation) && property.getValue().contains(msg)) {
return property;
}
}
return null;
}
private static Property getCorrectionPerformedProperty(Process process, String message, String language) {
List<Property> properties = process.getProperties();
for (Property property : properties) {
Task task = getWikiFieldCorrectionTask(message, process, language);
if (Objects.nonNull(task) && property.getTitle().equals(Helper.getTranslation("correctionPerformed"))
&& property.getValue().endsWith(task.getTitle())) {
return property;
}
}
return null;
}
private static Task getCorrectionTask(Property property) throws DAOException {
int correctionTaskId = Integer.parseInt(property.getValue()
.substring(property.getValue().indexOf(" CorrectionTask: ") + 17, property.getValue().indexOf(')')));
return ServiceManager.getTaskService().getById(correctionTaskId);
}
private static Task getCurrentTask(Property property) throws DAOException {
int currentTaskId = Integer.parseInt(property.getValue().substring(
property.getValue().indexOf("(CurrentTask: ") + 14, property.getValue().indexOf(" CorrectionTask: ")));
return ServiceManager.getTaskService().getById(currentTaskId);
}
private static Date getCreationDate(Property property) throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(property.getValue().substring(1, 20));
}
private static String getWikiFieldMessage(String message) {
return message.substring(message.indexOf(':') + 1).trim();
}
private static User getWikiFieldAuthor(String message, String lang) {
String[] parts = message.split(":");
if (parts.length < 2) {
return null;
}
String authorName = parts[0];
if ("de".equals(lang)) {
authorName = authorName.split(CORRECTION_FOR_TASK_DE)[0];
} else if ("en".equals(lang)) {
authorName = authorName.split(CORRECTION_FOR_TASK_EN)[0];
}
if (authorName.contains("Red K ")) {
authorName = authorName.replace("Red K ", "");
} else if (authorName.contains("Orange K ")) {
authorName = authorName.replace("Orange K ", "");
}
return getUserByFullName(authorName);
}
private static Task getWikiFieldCorrectionTask(String message, Process process, String lang) {
String[] parts = message.split(":");
if (parts.length < 2) {
return null;
}
String correctionTaskName = parts[0];
if ("en".equals(lang)) {
correctionTaskName = correctionTaskName.split(CORRECTION_FOR_TASK_EN)[1];
} else if ("de".equals(lang)) {
correctionTaskName = correctionTaskName.split(CORRECTION_FOR_TASK_DE)[1];
}
for (Task task : process.getTasks()) {
if (task.getTitle().equals(correctionTaskName.trim())) {
return task;
}
}
return null;
}
private static void deleteProperty(Process process, Property property) throws DAOException, DataException {
property.getProcesses().clear();
process.getProperties().remove(property);
ServiceManager.getProcessService().save(process);
ServiceManager.getPropertyService().removeFromDatabase(property);
}
/*
* Example of wiki Field's new format: <p>Admin, test: bla bla <p>Orange K
* Admin, test Korrektur für Schritt Scanning: bla bla <p>Red K Admin,
* test Korrektur für Schritt Scanning: bla bla
*/
private static void transformNewFormatWikiFieldToComments(String[] messages, Process process)
throws DAOException, DataException, ParseException {
List<Comment> newComments = new ArrayList<>();
for (String message : messages) {
String lang = getMessageLanguage(message);
Comment comment = new Comment();
comment.setProcess(process);
comment.setMessage(getWikiFieldMessage(message));
comment.setAuthor(getWikiFieldAuthor(message, lang));
if (message.contains("Red K")) {
comment.setType(CommentType.ERROR);
Property correctionRequiredProperty = getCorrectionRequiredProperty(process, message);
if (Objects.nonNull(correctionRequiredProperty)) {
comment.setCreationDate(getCreationDate(correctionRequiredProperty));
comment.setCurrentTask(getCurrentTask(correctionRequiredProperty));
comment.setCorrectionTask(getCorrectionTask(correctionRequiredProperty));
deleteProperty(process, correctionRequiredProperty);
}
} else if (message.contains("Orange K")) {
comment.setType(CommentType.ERROR);
comment.setCorrected(Boolean.TRUE);
Property correctionPerformed = getCorrectionPerformedProperty(process, message, lang);
if (Objects.nonNull(correctionPerformed)) {
comment.setCreationDate(correctionPerformed.getCreationDate());
comment.setCorrectionDate(getCreationDate(correctionPerformed));
deleteProperty(process, correctionPerformed);
}
comment.setCurrentTask(ServiceManager.getProcessService().getCurrentTask(process));
comment.setCorrectionTask(getWikiFieldCorrectionTask(message, process, lang));
} else {
comment.setType(CommentType.INFO);
}
newComments.add(comment);
}
saveComments(newComments);
}
private static String getMessageLanguage(String message) {
if (message.contains(CORRECTION_FOR_TASK_EN)) {
return "en";
} else if (message.contains(CORRECTION_FOR_TASK_DE)) {
return "de";
}
return "";
}
/*
Example of wiki Field's very old format (#FF0000:Correction comment, #006600: is corrected, #0033CC: Info comment):
<font color="#FF0000">Jun 16, 2016 1:12:58 PM: Korrektur für Schritt Scannen: bla bla bla.. (Admin, test)</font><br/>
<font color="#006600">Jun 17, 2016 10:36:43 AM: bla bla (Admin, test)</font><br/>
<font color="#0033CC">Jun 17, 2016 10:40:43 AM: bla bla (Admin, test)</font>
Another existing format, with German-style formatted date:
<font color="#FF0000">06.04.2017 09:38:58: bla bla (User, Example)</font><br/>
*/
private static void transformOldFormatWikifieldToComments(Document document, Process process) {
Element root = document.getDocumentElement();
NodeList nodeList = root.getElementsByTagName("font");
List<Comment> commentList = new ArrayList<>();
for (int i = 0; i < nodeList.getLength(); i++) {
Element element = (Element) nodeList.item(i);
String color = element.getAttribute("color");
if (Objects.equals(color, "#FF0000") || Objects.equals(color, "#0033CC")) {
Comment comment = new Comment();
comment.setProcess(process);
String message = element.getTextContent();
String lang = getMessageLanguage(message);
comment.setCreationDate(getCreationDateOld(message));
comment.setMessage(getOldComment(message, lang));
String authorName = message.substring(message.lastIndexOf('(') + 1, message.lastIndexOf(')'));
comment.setAuthor(getUserByFullName(authorName));
if (Objects.equals(color, "#FF0000")) {
comment.setType(CommentType.ERROR);
comment.setCorrected(true);
comment.setCorrectionTask(getOldCorrectionTask(message, process, lang));
} else if (Objects.equals(color, "#0033CC")) {
comment.setType(CommentType.INFO);
}
commentList.add(comment);
}
}
if (!commentList.isEmpty()) {
saveComments(commentList);
}
}
private static void saveComments(List<Comment> commentList) {
try {
ServiceManager.getCommentService().saveList(commentList);
} catch (DAOException e) {
logger.error(e.getMessage(), e);
}
}
/*
* fullName = surname, name
*/
private static User getUserByFullName(String fullName) {
Map<String, Object> parameters = new HashMap<>();
parameters.put("surname", fullName.split(",")[0].trim());
parameters.put("name", fullName.split(",")[1].trim());
List<User> userList = ServiceManager.getUserService()
.getByQuery("FROM User WHERE name = :name AND surname = :surname", parameters);
if (userList.isEmpty()) {
return null;
}
return userList.get(0);
}
private static Document convertStringToDocument(String xmlString) {
Document document = null;
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder
.parse(new InputSource(new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8))));
} catch (ParserConfigurationException | IOException | SAXException e) {
logger.error("{} Could not parse XML string '{}'!", e.getMessage(), xmlString, e);
}
return document;
}
private static Date getCreationDateOld(String message) {
try {
Pattern pattern = Pattern.compile("^\\d{2}\\.\\d{2}\\.\\d{4} \\d{2}:\\d{2}:\\d{2}(?=: )");
Matcher matcher = pattern.matcher(message);
if (matcher.find()) {
return new SimpleDateFormat("dd.MM.yyy hh:mm:ss").parse(matcher.group());
}
int index = message.contains("PM") ? message.indexOf("PM") : message.indexOf("AM");
String date = message.substring(0, index + 2);
DateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy h:mm:ss a", Locale.ENGLISH);
return dateFormat.parse(date);
} catch (ParseException e) {
logger.error(e.getMessage(), e);
}
return null;
}
private static String getOldComment(String message, String language) {
String comment;
if ("de".equals(language)) {
comment = message.substring(message.indexOf(':', message.indexOf(CORRECTION_FOR_TASK_DE)) + 1,
message.lastIndexOf('('));
} else if ("en".equals(language)) {
comment = message.substring(message.indexOf(':', message.indexOf(CORRECTION_FOR_TASK_EN)) + 1,
message.lastIndexOf('('));
} else {
int index = message.contains("PM:") ? message.indexOf("PM:") : message.indexOf("AM:");
comment = message.substring(index + 3, message.lastIndexOf('('));
}
return comment;
}
private static Task getOldCorrectionTask(String message, Process process, String language) {
String correctionTaskName;
if ("de".equals(language)) {
int index = message.indexOf(CORRECTION_FOR_TASK_DE);
correctionTaskName = message.substring(index + 23, message.indexOf(':', index));
} else {
int index = message.indexOf(CORRECTION_FOR_TASK_EN);
correctionTaskName = message.substring(index + 20, message.indexOf(':', index));
}
for (Task task : process.getTasks()) {
if (task.getTitle().equals(correctionTaskName.trim())) {
return task;
}
}
return null;
}
private static Process deleteProcessCorrectionProperties(Process process) throws DAOException, DataException {
List<Property> properties = new ArrayList<>(process.getProperties());
for (Property property : properties) {
String title = property.getTitle();
if ("Korrektur notwendig".equals(title) || "Correction required".equals(title)
|| "Korrektur durchgef\\u00FChrt".equals(title) || "Correction performed".equals(title)) {
process.getProperties().remove(property);
ServiceManager.getProcessService().save(process);
ServiceManager.getPropertyService().removeFromDatabase(property);
property.getProcesses().remove(process);
ServiceManager.getPropertyService().removeFromDatabase(property);
return ServiceManager.getProcessService().getById(process.getId());
}
}
return process;
}
}