/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.wui.common.server;
import java.io.IOException;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.lang3.StringUtils;
import org.roda.core.data.v2.ip.IndexedAIP;
import org.roda.core.data.v2.ip.IndexedRepresentation;
import org.roda.core.data.v2.user.User;
import org.roda.wui.client.browse.MetadataValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XPathSelector;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.s9api.XdmValue;
public class ServerTools {
private static final Logger LOGGER = LoggerFactory.getLogger(ServerTools.class);
private ServerTools() {
// do nothing
}
/**
* Parse a locale string into a Locale
*
* @param localeString
* the locale string, e.g. en_US
* @return
*/
public static Locale parseLocale(String localeString) {
Locale locale = null;
if (StringUtils.isNotBlank(localeString)) {
String[] localeArgs = localeString.split("_");
if (localeArgs.length == 1) {
locale = new Locale(localeArgs[0]);
} else if (localeArgs.length == 2) {
locale = new Locale(localeArgs[0], localeArgs[1]);
} else if (localeArgs.length == 3) {
locale = new Locale(localeArgs[0], localeArgs[1], localeArgs[2]);
}
} else {
locale = Locale.ENGLISH;
}
return locale;
}
/**
* Encode XML entities and unicode control chars
*
* @param s
* the string to encode
* @return the encoded string
*/
public static String encodeXML(String s) {
if (s != null) {
StringBuilder ret = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == '<') {
ret.append("<");
} else if (ch == '>') {
ret.append(">");
} else if (ch == '"') {
ret.append(""");
} else if (ch == '\'') {
ret.append("'");
} else if (ch == '&') {
ret.append("&");
} else if (ch < 0x20 && ch != 0x9 && ch != 0xD && ch != 0xA) {
ret.append(ch <= 0xf ? "\\u000" : "\\u00").append(Integer.toHexString(ch).toUpperCase());
} else {
ret.append(ch);
}
}
return ret.toString();
} else {
return null;
}
}
/**
* Encode a CSV value, always adding quotes to the value and duplicating
* existing quotes
*
* @param s
* @return the encoded CSV value
*/
public static String encodeCSV(String s) {
return "\"" + s.replaceAll("\"", "\"\"") + "\"";
}
/**
* Check if a string matches an URL
*
* @param s
* @return true if it matches
*/
public static boolean isURL(String s) {
boolean isURL;
try {
new URL(s);
isURL = true;
} catch (MalformedURLException e) {
isURL = false;
}
return isURL;
}
public static Set<MetadataValue> transform(String content) {
Set<MetadataValue> values = new TreeSet<>();
if (content == null) {
return values;
}
Set<String> addedTags = new HashSet<>();
Handlebars handlebars = new Handlebars();
Template tmpl;
try {
handlebars.registerHelper("field", (context, options) -> {
if (options.hash.containsKey("name")) {
String tagID = (String) options.hash.get("name");
if (context != null && !addedTags.contains(tagID)) {
HashMap<String, String> newHash = new HashMap<>();
for (Entry<String, Object> hashEntry : options.hash.entrySet()) {
newHash.put(hashEntry.getKey(), hashEntry.getValue().toString());
}
values.add(new MetadataValue(tagID, new HashMap<>(newHash)));
addedTags.add(tagID);
}
}
return options.fn();
});
// Prevent errors from unknown helpers
handlebars.registerHelperMissing((o, options) -> options.fn());
tmpl = handlebars.compileInline(content);
tmpl.apply(new HashMap<>());
} catch (IOException e) {
LOGGER.error("Error getting the MetadataValue list from the template");
}
return values;
}
public static String autoGenerateAIPValue(IndexedAIP aip, User user, String generator) {
String result = null;
switch (generator) {
case "now":
result = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
break;
case "id":
result = aip.getId();
break;
case "title":
result = aip.getTitle();
break;
case "language":
result = Locale.getDefault().getDisplayLanguage();
break;
case "parentid":
result = aip.getParentID();
break;
case "level":
result = aip.getLevel();
break;
case "full-name":
result = user.getFullName();
break;
case "email":
result = user.getEmail();
break;
default:
break;
}
return result;
}
public static String autoGenerateRepresentationValue(IndexedRepresentation representation, String generator) {
String result = null;
switch (generator) {
case "now":
result = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
break;
case "id":
result = representation.getId();
break;
default:
break;
}
return result;
}
public static List<String> applyXpath(String xml, String xpathString) {
List<String> result = new ArrayList<>();
try {
Processor proc = new Processor(false);
XPathCompiler xpath = proc.newXPathCompiler();
DocumentBuilder builder = proc.newDocumentBuilder();
// Load the XML document.
StringReader reader = new StringReader(xml);
XdmNode doc = builder.build(new StreamSource(reader));
// Compile the xpath
XPathSelector selector = xpath.compile(xpathString).load();
selector.setContextItem(doc);
// Evaluate the expression.
XdmValue nodes = selector.evaluate();
for (XdmItem item : nodes) {
result.add(item.toString());
}
} catch (Exception e) {
LOGGER.error("Error applying XPath", e);
}
return result;
}
}