initial commit
diff --git a/src/.DS_Store b/src/.DS_Store
new file mode 100644
index 0000000..16a96aa
--- /dev/null
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/main/.DS_Store b/src/main/.DS_Store
new file mode 100644
index 0000000..d94e183
--- /dev/null
+++ b/src/main/.DS_Store
Binary files differ
diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store
new file mode 100644
index 0000000..e282944
--- /dev/null
+++ b/src/main/java/.DS_Store
Binary files differ
diff --git a/src/main/java/de/.DS_Store b/src/main/java/de/.DS_Store
new file mode 100644
index 0000000..b276992
--- /dev/null
+++ b/src/main/java/de/.DS_Store
Binary files differ
diff --git a/src/main/java/de/ids_mannheim/.DS_Store b/src/main/java/de/ids_mannheim/.DS_Store
new file mode 100644
index 0000000..07256f1
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/.DS_Store
Binary files differ
diff --git a/src/main/java/de/ids_mannheim/korap/.DS_Store b/src/main/java/de/ids_mannheim/korap/.DS_Store
new file mode 100644
index 0000000..e540d83
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/.DS_Store
Binary files differ
diff --git a/src/main/java/de/ids_mannheim/korap/auditing/AuditRecord.java b/src/main/java/de/ids_mannheim/korap/auditing/AuditRecord.java
new file mode 100644
index 0000000..28f915d
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/auditing/AuditRecord.java
@@ -0,0 +1,157 @@
+package de.ids_mannheim.korap.auditing;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.TimeUtils;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Arrays;
+
+/**
+ * @author hanl
+ * <p/>
+ * Record holder for auditing requests. Holds the data until it can be persisted to a database
+ */
+@Getter
+@Setter
+public class AuditRecord {
+
+ // fixme: handle via status codes
+ @Deprecated
+ public enum Operation {
+ GET, INSERT, UPDATE, DELETE, CREATE
+ }
+
+ public enum CATEGORY {
+ SECURITY, DATABASE, RESOURCE, QUERY, SERVICE
+ }
+
+ @JsonIgnore
+ private Integer id;
+ //security access describes changes in user authorities and access control permissions of resources
+ private String userid;
+ private String target;
+
+ //fixme: replace with more specific error codes
+ private CATEGORY category;
+ private String loc;
+ private Long timestamp;
+ private Integer status = -1;
+ private String args;
+ private String field_1 = "None";
+
+ private AuditRecord() {
+ this.timestamp = TimeUtils.getNow().getMillis();
+ }
+
+ public AuditRecord(CATEGORY category) {
+ this();
+ this.category = category;
+ }
+
+ public AuditRecord(CATEGORY cat, Object userID, Integer status) {
+ this(cat);
+ this.status = status;
+ if (userID != null) {
+ //todo: client info!
+ // this.loc = clientInfoToString(user.getTokenContext().getHostAddress(),
+ // user.getTokenContext().getUserAgent());
+ this.loc = clientInfoToString("null", "null");
+ userid = String.valueOf(userID);
+ }else {
+ this.loc = clientInfoToString("null", "null");
+ userid = "-1";
+ }
+ }
+
+ public static AuditRecord serviceRecord(Object user, Integer status,
+ String... args) {
+ AuditRecord r = new AuditRecord(CATEGORY.SERVICE);
+ r.setArgs(Arrays.asList(args).toString());
+ r.setUserid(String.valueOf(user));
+ r.setStatus(status);
+ return r;
+ }
+
+ public static AuditRecord dbRecord(Object user, Integer status,
+ String... args) {
+ AuditRecord r = new AuditRecord(CATEGORY.DATABASE);
+ r.setArgs(Arrays.asList(args).toString());
+ r.setUserid(String.valueOf(user));
+ r.setStatus(status);
+ return r;
+ }
+
+ public AuditRecord fromJson(String json) {
+ JsonNode n = JsonUtils.readTree(json);
+ AuditRecord r = new AuditRecord();
+ r.setCategory(CATEGORY.valueOf(n.path("category").asText()));
+ r.setTarget(n.path("target").asText());
+ r.setField_1(n.path("field_1").asText());
+ r.setUserid(n.path("account").asText());
+ r.setStatus(n.path("status").asInt());
+ r.setLoc(n.path("loc").asText());
+ return r;
+ }
+
+ private String clientInfoToString(String IP, String userAgent) {
+ return userAgent + "@" + IP;
+ }
+
+ @Override
+ public String toString() {
+ return "Record{" +
+ "account='" + userid + '\'' +
+ ", category=" + category +
+ ", loc='" + loc + '\'' +
+ ", timestamp=" + timestamp +
+ ", status='" + status + '\'' +
+ ", field_1='" + field_1 + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ AuditRecord that = (AuditRecord) o;
+
+ if (userid != null ? !userid.equals(that.userid) : that.userid != null)
+ return false;
+ if (category != that.category)
+ return false;
+ if (status != null ? !status.equals(that.status) : that.status != null)
+ return false;
+ if (field_1 != null ?
+ !field_1.equals(that.field_1) :
+ that.field_1 != null)
+ return false;
+ if (loc != null ? !loc.equals(that.loc) : that.loc != null)
+ return false;
+ if (target != null ? !target.equals(that.target) : that.target != null)
+ return false;
+ if (timestamp != null ?
+ !timestamp.equals(that.timestamp) :
+ that.timestamp != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = userid != null ? userid.hashCode() : 0;
+ result = 31 * result + (target != null ? target.hashCode() : 0);
+ result = 31 * result + category.hashCode();
+ result = 31 * result + (loc != null ? loc.hashCode() : 0);
+ result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
+ result = 31 * result + (status != null ? status.hashCode() : 0);
+ result = 31 * result + (field_1 != null ? field_1.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/config/BeanConfiguration.java b/src/main/java/de/ids_mannheim/korap/config/BeanConfiguration.java
new file mode 100644
index 0000000..f4b72b1
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/config/BeanConfiguration.java
@@ -0,0 +1,69 @@
+package de.ids_mannheim.korap.config;
+
+import de.ids_mannheim.korap.interfaces.AuditingIface;
+import de.ids_mannheim.korap.plugins.PluginManager;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.context.support.FileSystemXmlApplicationContext;
+
+import java.net.URL;
+
+/**
+ * User: hanl
+ * Date: 10/9/13
+ * Time: 11:20 AM
+ */
+public class BeanConfiguration {
+
+ private static final String config_file = "default-config.xml";
+
+ private static ApplicationContext context = null;
+ private static PluginManager plugins;
+
+ private static void loadPlugins() {
+ plugins = new PluginManager();
+ plugins.loadPluginInterfaces();
+ }
+
+ public static void loadContext() {
+ URL url = BeanConfiguration.class.getClassLoader()
+ .getResource(config_file);
+ if (url != null && context == null)
+ context = new ClassPathXmlApplicationContext(config_file);
+ }
+
+ public static void loadContext(String filepath) {
+ if (filepath == null)
+ loadContext();
+ else {
+ if (context == null)
+ context = new FileSystemXmlApplicationContext(
+ "file:" + filepath);
+ }
+ }
+
+ public static <T extends KustvaktConfiguration> T getConfiguration() {
+ return (T) getBean("config");
+ }
+
+ public static <T extends KustvaktConfiguration> T getConfiguration(
+ Class<T> clazz) {
+ return getBean(clazz);
+ }
+
+ public static boolean hasContext() {
+ return context != null;
+ }
+
+ protected static <T> T getBean(Class<T> clazz) {
+ return context.getBean(clazz);
+ }
+
+ protected static <T> T getBean(String name) {
+ return (T) context.getBean(name);
+ }
+
+ public static AuditingIface getAuditingProvider() {
+ return (AuditingIface) context.getBean("auditingProvider");
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java b/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java
new file mode 100644
index 0000000..de4748e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/config/KustvaktClassLoader.java
@@ -0,0 +1,26 @@
+package de.ids_mannheim.korap.config;
+
+import org.reflections.Reflections;
+
+import java.util.Set;
+
+/**
+ * @author hanl
+ * @date 10/06/2015
+ */
+public class KustvaktClassLoader {
+
+ private static final Reflections reflections = new Reflections(
+ "de.ids_mannheim.korap");
+
+ /**
+ * loads interface implementations in current classpath
+ *
+ * @param iface
+ * @param <T>
+ * @return
+ */
+ public static <T> Set<Class<? extends T>> load(Class<T> iface) {
+ return reflections.getSubTypesOf(iface);
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java b/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
new file mode 100644
index 0000000..52ac3c7
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
@@ -0,0 +1,116 @@
+package de.ids_mannheim.korap.config;
+
+import de.ids_mannheim.korap.utils.KorAPLogger;
+import lombok.Getter;
+import org.apache.log4j.PropertyConfigurator;
+import org.slf4j.Logger;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * if configuration class is extended, load method should be overriden
+ * @author hanl
+ * @date 05/02/2014
+ */
+
+@Getter
+public class KustvaktConfiguration {
+
+ private final Logger jlog = KorAPLogger
+ .initiate(KustvaktConfiguration.class);
+
+ // deprec?!
+ private final BACKENDS DEFAULT_ENGINE = BACKENDS.LUCENE;
+ private int maxhits;
+
+ private int port;
+ private int returnhits;
+ private String serverHost;
+ private String indexDir;
+
+ private List<String> queryLanguages;
+ private String host;
+
+ private URL issuer;
+
+ /**
+ * loading of the properties and mapping to parameter variables
+ *
+ * @param korap
+ * @return
+ */
+ protected Properties load(Properties korap) {
+ String log4jconfig = korap
+ .getProperty("log4jconfig", "log4j.properties");
+ loadLog4jLogger(log4jconfig);
+ maxhits = new Integer(korap.getProperty("maxhits", "50000"));
+ returnhits = new Integer(korap.getProperty("returnhits", "50000"));
+ indexDir = korap.getProperty("lucene.indexDir", "");
+ port = new Integer(korap.getProperty("server.port", "8080"));
+ // server options
+ serverHost = String
+ .valueOf(korap.getProperty("server.host", "localhost"));
+ String queries = korap.getProperty("korap.ql", "");
+ String[] qls = queries.split(",");
+ queryLanguages = new ArrayList<>();
+ for (String querylang : qls)
+ queryLanguages.add(querylang.trim().toUpperCase());
+ // issuer = new URL(korap.getProperty("korap.issuer", ""));
+ return korap;
+ }
+
+ public void setProperties(Properties props) {
+ this.load(props);
+ }
+
+ public BACKENDS chooseBackend(String value) {
+ if (value == null || value.equals("null"))
+ return DEFAULT_ENGINE;
+ else
+ return Enum.valueOf(BACKENDS.class, value.toUpperCase());
+ }
+
+ private void loadLog4jLogger(String log4jconfig) {
+ /** load log4j configuration file programmatically */
+ Properties log4j = new Properties();
+ try {
+ if (!log4jconfig.equals("")) {
+ log4j.load(new FileInputStream(log4jconfig));
+ PropertyConfigurator.configure(log4j);
+ jlog.info(
+ "using local logging properties file ({}) to configure logging system",
+ log4jconfig);
+ }else
+ loadClassLogger();
+ }catch (Exception e) {
+ loadClassLogger();
+ }
+ }
+
+ public void loadClassLogger() {
+ Properties log4j = new Properties();
+ jlog.info(
+ "using class path logging properties file to configure logging system");
+
+ try {
+ log4j.load(KustvaktConfiguration.class.getClassLoader()
+ .getResourceAsStream("log4j.properties"));
+ }catch (IOException e) {
+ // do nothing
+ }
+
+ PropertyConfigurator.configure(log4j);
+ jlog.warn(
+ "No logger properties detected. Using default logger properties");
+ }
+
+ public enum BACKENDS {
+ NEO4J, LUCENE
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java b/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java
new file mode 100644
index 0000000..408f591
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java
@@ -0,0 +1,47 @@
+package de.ids_mannheim.korap.exceptions;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author hanl
+ * @date 29/01/2014
+ */
+@Getter
+public abstract class BaseException extends Exception {
+
+ protected List<AuditRecord> records = new ArrayList<>();
+ private Integer statusCode;
+ private String entity;
+
+
+ public BaseException(int code) {
+ this.statusCode = code;
+ }
+
+ public BaseException(int status, String message, String entity) {
+ super(message);
+ this.statusCode = status;
+ this.entity = entity;
+ }
+
+ public BaseException(int status, String entity) {
+ this(status);
+ this.entity = entity;
+ }
+
+ public BaseException(Throwable cause, int status) {
+ super(cause);
+ this.statusCode = status;
+
+ }
+
+ public BaseException(String message, Throwable cause, int status) {
+ super(message, cause);
+ this.statusCode = status;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/EmptyResultException.java b/src/main/java/de/ids_mannheim/korap/exceptions/EmptyResultException.java
new file mode 100644
index 0000000..5541695
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/EmptyResultException.java
@@ -0,0 +1,13 @@
+package de.ids_mannheim.korap.exceptions;
+
+/**
+ * @author hanl
+ * @date 25/03/2014
+ */
+public class EmptyResultException extends BaseException {
+
+ public EmptyResultException(String entity) {
+ super(StatusCodes.EMPTY_RESULTS, entity);
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/KorAPException.java b/src/main/java/de/ids_mannheim/korap/exceptions/KorAPException.java
new file mode 100644
index 0000000..a050770
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/KorAPException.java
@@ -0,0 +1,52 @@
+package de.ids_mannheim.korap.exceptions;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author hanl
+ * @date 11/12/2013
+ */
+@Setter
+@Getter
+public class KorAPException extends BaseException {
+
+ private String userid;
+
+ public KorAPException(Integer status) {
+ super(status);
+ }
+
+ public KorAPException(Object userid, Integer status) {
+ this(status);
+ this.userid = String.valueOf(userid);
+ }
+
+ public KorAPException(Object userid, Integer status, String message,
+ String entity) {
+ super(status, message, entity);
+ this.userid = String.valueOf(userid);
+ }
+
+ public KorAPException(Integer status, String message, String entity) {
+ super(status, message, entity);
+ }
+
+ public KorAPException(Throwable cause, Integer status) {
+ super(cause, status);
+ }
+
+ public KorAPException(String message, Throwable cause, Integer status) {
+ super(message, cause, status);
+ }
+
+ @Override
+ public String toString() {
+ return "Excpt{" +
+ "status=" + getStatusCode() +
+ ", message=" + getMessage() +
+ ", args=" + getEntity() +
+ ", userid=" + userid +
+ '}';
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/Message.java b/src/main/java/de/ids_mannheim/korap/exceptions/Message.java
new file mode 100644
index 0000000..f9021b4
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/Message.java
@@ -0,0 +1,109 @@
+package de.ids_mannheim.korap.exceptions;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * @author hanl
+ * @date 03/12/2014
+ */
+public class Message implements Cloneable {
+
+ ObjectMapper mapper = new ObjectMapper();
+ private String msg;
+ private int code = 0;
+ private LinkedList<String> parameters;
+
+ public Message(int code, String msg) {
+ this.code = code;
+ this.msg = msg;
+ }
+
+ public Message() {
+ }
+
+ @JsonIgnore
+ public Message setMessage(String msg) {
+ this.msg = msg;
+ return this;
+ }
+
+ @JsonIgnore
+ public String getMessage() {
+ return this.msg;
+ }
+
+ @JsonIgnore
+ public Message setCode(int code) {
+ this.code = code;
+ return this;
+ }
+
+ @JsonIgnore
+ public int getCode() {
+ return this.code;
+ }
+
+ public Message addParameter(String param) {
+ if (this.parameters == null) {
+ this.parameters = new LinkedList();
+ }
+
+ this.parameters.add(param);
+ return this;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Message clone = new Message();
+ if (this.msg != null) {
+ clone.msg = this.msg;
+ }
+
+ clone.code = this.code;
+ if (this.parameters != null) {
+ Iterator i$ = this.parameters.iterator();
+
+ while (i$.hasNext()) {
+ String p = (String) i$.next();
+ clone.addParameter(p);
+ }
+ }
+
+ return clone;
+ }
+
+ public JsonNode toJSONnode() {
+ ArrayNode message = this.mapper.createArrayNode();
+ if (this.code != 0) {
+ message.add(this.getCode());
+ }
+
+ message.add(this.getMessage());
+ if (this.parameters != null) {
+ Iterator i$ = this.parameters.iterator();
+
+ while (i$.hasNext()) {
+ String p = (String) i$.next();
+ message.add(p);
+ }
+ }
+
+ return message;
+ }
+
+ public String toJSON() {
+ String msg = "";
+
+ try {
+ return this.mapper.writeValueAsString(this.toJSONnode());
+ } catch (Exception var3) {
+ msg = ", \"" + var3.getLocalizedMessage() + "\"";
+ return "[620, \"Unable to generate JSON\"" + msg + "]";
+ }
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/Messages.java b/src/main/java/de/ids_mannheim/korap/exceptions/Messages.java
new file mode 100644
index 0000000..0729448
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/Messages.java
@@ -0,0 +1,167 @@
+package de.ids_mannheim.korap.exceptions;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * @author hanl
+ * @date 03/12/2014
+ */
+public class Messages implements Cloneable, Iterable<Message> {
+
+ private ArrayList<Message> messages = new ArrayList(3);
+
+ public Messages() {
+ }
+
+ public Iterator<Message> iterator() {
+ return new Messages.MessageIterator();
+ }
+
+ public Message add(int code, String message, String... terms) {
+ Message newMsg = new Message(code, message);
+ this.messages.add(newMsg);
+ if (terms != null) {
+ String[] arr$ = terms;
+ int len$ = terms.length;
+
+ for (int i$ = 0; i$ < len$; ++i$) {
+ String t = arr$[i$];
+ newMsg.addParameter(t);
+ }
+ }
+
+ return newMsg;
+ }
+
+ public Message add(Message msg) {
+ try {
+ Message e = (Message) msg.clone();
+ this.messages.add(e);
+ return e;
+ } catch (CloneNotSupportedException var3) {
+ return (Message) null;
+ }
+ }
+
+ public Message add(JsonNode msg) throws KorAPException {
+ if (msg.isArray() && msg.has(0)) {
+ Message newMsg = new Message();
+ short i = 1;
+ if (msg.get(0).isNumber()) {
+ newMsg.setCode(msg.get(0).asInt());
+ if (!msg.has(1)) {
+ throw new KorAPException(750, "Passed notifications are not well formed", null);
+ }
+
+ newMsg.setMessage(msg.get(1).asText());
+ ++i;
+ } else {
+ newMsg.setMessage(msg.get(0).asText());
+ }
+
+ while (msg.has(i)) {
+ newMsg.addParameter(msg.get(i++).asText());
+ }
+
+ this.add((Message) newMsg);
+ return newMsg;
+ } else {
+ throw new KorAPException(750, "Passed notifications are not well formed", null);
+ }
+ }
+
+ public Messages add(Messages msgs) {
+ try {
+ Iterator e = msgs.getMessages().iterator();
+
+ while (e.hasNext()) {
+ Message msg = (Message) e.next();
+ this.add((Message) ((Message) msg.clone()));
+ }
+ } catch (CloneNotSupportedException var4) {
+ ;
+ }
+
+ return this;
+ }
+
+ public Messages clear() {
+ this.messages.clear();
+ return this;
+ }
+
+ public int size() {
+ return this.messages.size();
+ }
+
+ @JsonIgnore
+ public Message get(int index) {
+ return index >= this.size() ? (Message) null : (Message) this.messages.get(index);
+ }
+
+ @JsonIgnore
+ public List<Message> getMessages() {
+ return this.messages;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ Messages clone = new Messages();
+ Iterator i$ = this.messages.iterator();
+
+ while (i$.hasNext()) {
+ Message m = (Message) i$.next();
+ clone.add((Message) ((Message) m.clone()));
+ }
+
+ return clone;
+ }
+
+ public JsonNode toJSONnode() {
+ ArrayNode messageArray = JsonUtils.createArrayNode();
+ Iterator i$ = this.messages.iterator();
+
+ while (i$.hasNext()) {
+ Message msg = (Message) i$.next();
+ messageArray.add(msg.toJSONnode());
+ }
+
+ return messageArray;
+ }
+
+ public String toJSON() {
+ String msg = "";
+
+ try {
+ return JsonUtils.toJSON(this.toJSONnode());
+ } catch (Exception var3) {
+ msg = ", \"" + var3.getLocalizedMessage() + "\"";
+ return "[620, \"Unable to generate JSON\"" + msg + "]";
+ }
+ }
+
+ private class MessageIterator implements Iterator<Message> {
+ int index = 0;
+
+ public MessageIterator() {
+ }
+
+ public boolean hasNext() {
+ return this.index < Messages.this.messages.size();
+ }
+
+ public Message next() {
+ return (Message) Messages.this.messages.get(this.index++);
+ }
+
+ public void remove() {
+ Messages.this.messages.remove(this.index);
+ }
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/NotAuthorizedException.java b/src/main/java/de/ids_mannheim/korap/exceptions/NotAuthorizedException.java
new file mode 100644
index 0000000..2b499c7
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/NotAuthorizedException.java
@@ -0,0 +1,33 @@
+package de.ids_mannheim.korap.exceptions;
+
+import lombok.Data;
+
+/**
+ * @author hanl
+ * @date 11/12/2013
+ */
+// a security table registers all these exceptions (failed authentication, failed access to a resource, etc.)
+@Data
+@Deprecated
+public class NotAuthorizedException extends BaseException {
+
+ public NotAuthorizedException(int status) {
+ super(status);
+ }
+
+ public NotAuthorizedException(int status, String entity) {
+ super(status, "", entity);
+ }
+
+ public NotAuthorizedException(int status, String message, String entity) {
+ super(status, message, entity);
+ }
+
+ public NotAuthorizedException(Throwable cause, int status) {
+ super(cause, status);
+ }
+
+ public NotAuthorizedException(String message, Throwable cause, int status) {
+ super(message, cause, status);
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
new file mode 100644
index 0000000..6db7b0e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -0,0 +1,103 @@
+package de.ids_mannheim.korap.exceptions;
+
+/**
+ * @author hanl
+ * @date 07/09/2014
+ */
+public class StatusCodes {
+
+ /**
+ * 100 status codes for standard system errors
+ */
+ public static final Integer EMPTY_RESULTS = 100;
+ public static final Integer REQUEST_INVALID = 101;
+ //fixme: redundancy?!
+ public static final Integer ENTRY_EXISTS = 102;
+ public static final Integer STATUS_OK = 103;
+ public static final Integer UNSUPPORTED_OPERATION = 104;
+ public static final Integer ILLEGAL_ARGUMENT = 105;
+ public static final Integer CONNECTION_ERROR = 106;
+ public static final Integer NOTHING_CHANGED = 107;
+ public static final Integer PARAMETER_VALIDATION_ERROR = 108;
+ public static final Integer DEFAULT_ERROR = 109;
+ public static final Integer NOT_SUPPORTED = 110;
+
+ /**
+ * 400 status codes for account/authentication relevant components
+ */
+
+ public static final Integer ACCOUNT_DEACTIVATED = 200;
+ public static final Integer ACCOUNT_CONFIRMATION_FAILED = 201;
+ public static final Integer ALREADY_LOGGED_IN = 202;
+ public static final Integer EXPIRED = 204;
+ public static final Integer BAD_CREDENTIALS = 205;
+ public static final Integer UNCONFIRMED_ACCOUNT = 206;
+ public static final Integer NAME_EXISTS = 207;
+ public static final Integer PASSWORD_RESET_FAILED = 208;
+ // fixme: ?!
+ public static final Integer AUTHENTICATION_DENIED = 209;
+
+ public static final Integer LOGIN_SUCCESSFUL = 210;
+ public static final Integer LOGIN_FAILED = 211;
+ public static final Integer LOGOUT_SUCCESSFUL = 212;
+ public static final Integer LOGOUT_FAILED = 213;
+
+ public static final Integer CLIENT_REGISTRATION_FAILURE = 214;
+ public static final Integer CLIENT_REMOVAL_FAILURE = 215;
+ public static final Integer CLIENT_AUTHORIZATION_FAILURE = 216;
+
+
+ /**
+ * 500 status codes for access control related components (also policy rewrite)
+ */
+ public static final Integer PERMISSION_DENIED = 401;
+ public static final Integer UNSUPPORTED_RESOURCE = 402;
+ public static final Integer UNSUPPORTED_FOUNDRY = 403;
+ public static final Integer UNSUPPORTED_CORPUS = 404;
+ public static final Integer UNSUPPORTED_LAYER = 405;
+ // make a distinction between no and invalid vc?
+ public static final Integer UNSUPPORTED_VIRTUALCOLLECTION = 406;
+ public static final Integer CORPUS_REWRITE = 407;
+ public static final Integer FOUNDRY_REWRITE = 408;
+ public static final Integer FOUNDRY_INJECTION = 409;
+ public static final Integer MISSING_ARGUMENTS = 410;
+ public static final Integer MISSING_VIRTUALCOLLECTION = 411;
+ public static final Integer MISSING_POLICY_TARGET = 412;
+ public static final Integer MISSING_POLICY_CONDITIONS = 413;
+ public static final Integer MISSING_POLICY_PERMISSION = 414;
+
+ // todo: extend according to policy rewrite possible!
+ // policy errors
+ public static final Integer POLICY_ERROR_DEFAULT = 500;
+ public static final Integer POLICY_CREATE_ERROR = 501;
+ public static final Integer NO_POLICIES = 502;
+
+ // database codes
+ public static final Integer DB_GET_FAILED = 601;
+ public static final Integer DB_INSERT_FAILED = 602;
+ public static final Integer DB_DELETE_FAILED = 603;
+ public static final Integer DB_UPDATE_FAILED = 604;
+
+ public static final Integer DB_GET_SUCCESSFUL = 605;
+ public static final Integer DB_INSERT_SUCCESSFUL = 606;
+ public static final Integer DB_DELETE_SUCCESSFUL = 607;
+ public static final Integer DB_UPDATE_SUCCESSFUL = 608;
+
+ // service status codes
+ public static final Integer CREATE_ACCOUNT_SUCCESSFUL = 700;
+ public static final Integer CREATE_ACCOUNT_FAILED = 701;
+ public static final Integer DELETE_ACCOUNT_SUCCESSFUL = 702;
+ public static final Integer DELETE_ACCOUNT_FAILED = 703;
+ public static final Integer UPDATE_ACCOUNT_SUCCESSFUL = 704;
+ public static final Integer UPDATE_ACCOUNT_FAILED = 705;
+
+ public static final Integer GET_ACCOUNT_SUCCESSFUL = 706;
+ public static final Integer GET_ACCOUNT_FAILED = 707;
+
+ /**
+ * 300 status codes for query language and serialization
+ */
+
+ public static final Integer NO_QUERY = 301;
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/WrappedException.java b/src/main/java/de/ids_mannheim/korap/exceptions/WrappedException.java
new file mode 100644
index 0000000..c180f1b
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/WrappedException.java
@@ -0,0 +1,35 @@
+package de.ids_mannheim.korap.exceptions;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+
+import java.util.Arrays;
+
+/**
+ * @author hanl
+ * @date 08/04/2015
+ */
+// should be a http exception that responds to a service point
+// is the extension of the notauthorized exception!
+public class WrappedException extends KorAPException {
+
+ private WrappedException(Object userid, Integer status, String message,
+ String args) {
+ super(String.valueOf(userid), status, message, args);
+ }
+
+ public WrappedException(Object userid, Integer status, String... args) {
+ this(userid, status, "", Arrays.asList(args).toString());
+ AuditRecord record = AuditRecord.serviceRecord(userid, status, args);
+ this.records.add(record);
+ }
+
+ public WrappedException(KorAPException e, Integer status, String... args) {
+ this(e.getUserid(), e.getStatusCode(), e.getMessage(), e.getEntity());
+ AuditRecord record = AuditRecord
+ .serviceRecord(e.getUserid(), status, args);
+ record.setField_1(e.toString());
+ this.records.addAll(e.getRecords());
+ this.records.add(record);
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/dbException.java b/src/main/java/de/ids_mannheim/korap/exceptions/dbException.java
new file mode 100644
index 0000000..d505e13
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/dbException.java
@@ -0,0 +1,48 @@
+package de.ids_mannheim.korap.exceptions;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+
+import java.util.Arrays;
+
+/**
+ * @author hanl
+ * @date 08/04/2015
+ */
+public class dbException extends KorAPException {
+
+ private dbException(Object userid, Integer status, String message,
+ String args) {
+ super(String.valueOf(userid), status, message, args);
+ }
+
+ public dbException(Object userid, String target, Integer status,
+ String... args) {
+ this(userid, status, "",
+ Arrays.asList(args).toString());
+ AuditRecord record = new AuditRecord(AuditRecord.CATEGORY.DATABASE);
+ record.setUserid(String.valueOf(userid));
+ record.setStatus(status);
+ record.setTarget(target);
+ record.setArgs(this.getEntity());
+ this.records.add(record);
+ }
+
+ public dbException(KorAPException e, Integer status, String... args) {
+ this(e.getUserid(), e.getStatusCode(), e.getMessage(), e.getEntity());
+ AuditRecord record = AuditRecord
+ .dbRecord(e.getUserid(), status, args);
+ record.setField_1(e.toString());
+ this.records.addAll(e.getRecords());
+ this.records.add(record);
+ }
+
+ @Override
+ public String toString() {
+ return "DBExcpt{" +
+ "status=" + getStatusCode() +
+ ", message=" + getMessage() +
+ ", args=" + getEntity() +
+ ", userid=" + this.getUserid() +
+ '}';
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuditingIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuditingIface.java
new file mode 100644
index 0000000..82bdd55
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuditingIface.java
@@ -0,0 +1,56 @@
+package de.ids_mannheim.korap.interfaces;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+import de.ids_mannheim.korap.user.User;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * User: hanl
+ * Date: 8/20/13
+ * Time: 10:45 AM
+ */
+//fixme: move table to different database!
+public abstract class AuditingIface implements Runnable {
+
+ protected static int BATCH_SIZE = 15;
+ protected final List<AuditRecord> records = new ArrayList<>(BATCH_SIZE + 5);
+ private final List<AuditRecord> buffer = new ArrayList<>(BATCH_SIZE + 5);
+
+ public abstract <T extends AuditRecord> List<T> retrieveRecords(
+ AuditRecord.CATEGORY category, DateTime day, DateTime until,
+ boolean exact, int limit);
+
+ public abstract <T extends AuditRecord> List<T> retrieveRecords(
+ AuditRecord.CATEGORY category, User user, int limit);
+
+ public abstract <T extends AuditRecord> List<T> retrieveRecords(
+ LocalDate day, int hitMax);
+
+ public abstract <T extends AuditRecord> List<T> retrieveRecords(
+ String userID, LocalDate start, LocalDate end, int hitMax);
+
+ private void addAndRun(AuditRecord record) {
+ if (buffer.size() > BATCH_SIZE) {
+ records.clear();
+ records.addAll(buffer);
+ run();
+ buffer.clear();
+ }
+ if (buffer.size() <= BATCH_SIZE)
+ buffer.add(record);
+ }
+
+ public <T extends AuditRecord> void audit(T request) {
+ addAndRun(request);
+ }
+
+ public <T extends AuditRecord> void audit(List<T> requests) {
+ for (T rec : requests)
+ addAndRun(rec);
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java
new file mode 100644
index 0000000..e02933e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationIface.java
@@ -0,0 +1,25 @@
+package de.ids_mannheim.korap.interfaces;
+
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.ext.security.AccessLevel;
+import de.ids_mannheim.korap.user.TokenContext;
+import de.ids_mannheim.korap.user.User;
+
+import java.util.Map;
+
+public abstract class AuthenticationIface {
+
+ public abstract TokenContext getUserStatus(String authToken)
+ throws KorAPException;
+
+ public abstract TokenContext createUserSession(User user,
+ Map<String, Object> attr) throws KorAPException;
+
+ public abstract void removeUserSession(String token) throws KorAPException;
+
+ public abstract AccessLevel[] retrieveLevelAccess(String authToken)
+ throws KorAPException;
+
+ public abstract String getIdentifier();
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java
new file mode 100644
index 0000000..0b00b31
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/EncryptionIface.java
@@ -0,0 +1,78 @@
+package de.ids_mannheim.korap.interfaces;
+
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.user.User;
+
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+
+public interface EncryptionIface {
+
+ public enum Encryption {
+ SIMPLE, ESAPICYPHER, BCRYPT
+ }
+
+ /**
+ * One-way hashing of String input. Used to canonicalize
+ *
+ * @param input
+ * @param salt
+ * @return
+ * @throws java.security.NoSuchAlgorithmException
+ * @throws java.io.UnsupportedEncodingException
+ */
+ public String produceSecureHash(String input, String salt)
+ throws NoSuchAlgorithmException, UnsupportedEncodingException,
+ KorAPException;
+
+ public String produceSecureHash(String input)
+ throws NoSuchAlgorithmException, UnsupportedEncodingException,
+ KorAPException;
+
+ public String hash(String value);
+
+ /**
+ * @param plain
+ * @param hash
+ * @param salt
+ * @return
+ */
+ public boolean checkHash(String plain, String hash, String salt);
+
+ public boolean checkHash(String plain, String hash);
+
+ public String getSalt(User user);
+
+ /**
+ * create random String to be used as authentication token
+ *
+ * @return
+ */
+ public String createToken(boolean hash, Object... obj);
+
+ public String createToken();
+
+ /**
+ * create a random Integer to be used as ID for databases
+ *
+ * @return
+ */
+ public String createID(Object... obj);
+
+ public String encodeBase();
+
+ public String validateIPAddress(String ipaddress) throws KorAPException;
+
+ public String validateEmail(String email) throws KorAPException;
+
+ public Map<String, Object> validateMap(Map<String, Object> map)
+ throws KorAPException;
+
+ public String validateString(String input) throws KorAPException;
+
+ public void validate(Object instance) throws KorAPException;
+
+ public String validatePassphrase(String pw) throws KorAPException;
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/EntityHandlerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/EntityHandlerIface.java
new file mode 100644
index 0000000..01cab35
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/EntityHandlerIface.java
@@ -0,0 +1,44 @@
+package de.ids_mannheim.korap.interfaces;
+
+import de.ids_mannheim.korap.exceptions.EmptyResultException;
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.user.UserDetails;
+import de.ids_mannheim.korap.user.UserSettings;
+
+/**
+ * User: hanl
+ * Date: 8/19/13
+ * Time: 11:04 AM
+ */
+public interface EntityHandlerIface {
+ public UserSettings getUserSettings(Integer userid) throws KorAPException;
+
+ public int updateSettings(UserSettings settings) throws KorAPException;
+
+ public UserDetails getUserDetails(Integer userid) throws KorAPException;
+
+ public int updateUserDetails(UserDetails details) throws KorAPException;
+
+ // public List<UserQuery> getUserQueries(User user) throws KorAPException;
+
+ // public UserQuery getUserQuery(String id) throws KorAPException;
+
+ // public void updateUserQueries(User user, List<UserQuery> newOnes) throws KorAPException;
+
+ public User getAccount(String username) throws
+ EmptyResultException, KorAPException;
+
+ public int updateAccount(User user) throws KorAPException;
+
+ public int createAccount(User user) throws KorAPException;
+
+ public int deleteAccount(Integer userid) throws KorAPException;
+
+ public int resetPassphrase(String username, String uriToken,
+ String passphrase) throws KorAPException;
+
+ public int activateAccount(String username, String uriToken)
+ throws KorAPException;
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/UserControllerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/UserControllerIface.java
new file mode 100644
index 0000000..67d6545
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/UserControllerIface.java
@@ -0,0 +1,59 @@
+package de.ids_mannheim.korap.interfaces;
+
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.user.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author hanl
+ * @date 15/06/2015
+ */
+public abstract class UserControllerIface {
+
+ private Map<String, AuthenticationIface> providers;
+
+ //todo: test if constr actually called
+ public UserControllerIface() {
+ this.providers = new HashMap<>();
+ }
+
+ public void setProviders(Set<AuthenticationIface> providers) {
+ for (AuthenticationIface i : providers)
+ this.providers.put(i.getIdentifier(), i);
+ }
+
+ protected AuthenticationIface getProvider(String key) {
+ AuthenticationIface iface;
+ if (key == null)
+ iface = this.providers.get(Attributes.API_AUTHENTICATION);
+ else
+ iface = this.providers.get(key.toUpperCase());
+ return iface;
+ }
+
+ public abstract User authenticate(int type, String username,
+ String password, Map<String, Object> attributes)
+ throws KorAPException;
+
+ public abstract void logout(TokenContext context) throws KorAPException;
+
+ public abstract void lockAccount(User user) throws KorAPException;
+
+ public abstract boolean updateAccount(User user) throws KorAPException;
+
+ public abstract boolean deleteAccount(User user) throws KorAPException;
+
+ public abstract UserDetails getUserDetails(User user) throws KorAPException;
+
+ public abstract UserSettings getUserSettings(User user)
+ throws KorAPException;
+
+ public abstract void updateUserDetails(User user, UserDetails details)
+ throws KorAPException;
+
+ public abstract void updateUserSettings(User user, UserSettings settings)
+ throws KorAPException;
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultAuditing.java b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultAuditing.java
new file mode 100644
index 0000000..cb0eef7
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultAuditing.java
@@ -0,0 +1,50 @@
+package de.ids_mannheim.korap.interfaces.defaults;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+import de.ids_mannheim.korap.interfaces.AuditingIface;
+import de.ids_mannheim.korap.user.User;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+
+import java.util.List;
+
+/**
+ * @author hanl
+ * @date 05/06/2015
+ */
+public class DefaultAuditing extends AuditingIface {
+
+ public DefaultAuditing() {
+
+ }
+
+ @Override
+ public <T extends AuditRecord> List<T> retrieveRecords(
+ AuditRecord.CATEGORY category, DateTime day, DateTime until,
+ boolean exact, int limit) {
+ return null;
+ }
+
+ @Override
+ public <T extends AuditRecord> List<T> retrieveRecords(
+ AuditRecord.CATEGORY category, User user, int limit) {
+ return null;
+ }
+
+ @Override
+ public <T extends AuditRecord> List<T> retrieveRecords(LocalDate day,
+ int hitMax) {
+ return null;
+ }
+
+ @Override
+ public <T extends AuditRecord> List<T> retrieveRecords(String userID,
+ LocalDate start, LocalDate end, int hitMax) {
+ return null;
+ }
+
+ @Override
+ public void run() {
+ //todo: append to logging file or other auditing file
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultEncryption.java b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultEncryption.java
new file mode 100644
index 0000000..8c787db
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/defaults/DefaultEncryption.java
@@ -0,0 +1,110 @@
+package de.ids_mannheim.korap.interfaces.defaults;
+
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.interfaces.EncryptionIface;
+import de.ids_mannheim.korap.user.User;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 05/06/2015
+ */
+public class DefaultEncryption implements EncryptionIface {
+
+ private SecureRandom randomizer;
+
+ public DefaultEncryption() {
+ randomizer = new SecureRandom();
+ }
+
+ @Override
+ public String produceSecureHash(String input, String salt)
+ throws NoSuchAlgorithmException, UnsupportedEncodingException,
+ KorAPException {
+ return null;
+ }
+
+ @Override
+ public String produceSecureHash(String input)
+ throws NoSuchAlgorithmException, UnsupportedEncodingException,
+ KorAPException {
+ return null;
+ }
+
+ @Override
+ public String hash(String value) {
+ return null;
+ }
+
+ @Override
+ public boolean checkHash(String plain, String hash, String salt) {
+ return false;
+ }
+
+ @Override
+ public boolean checkHash(String plain, String hash) {
+ return false;
+ }
+
+ @Override
+ public String getSalt(User user) {
+ return null;
+ }
+
+ @Override
+ public String createToken(boolean hash, Object... obj) {
+ return createToken();
+
+ }
+
+ @Override
+ public String createToken() {
+ return new BigInteger(100, randomizer).toString(20);
+ }
+
+ @Override
+ public String createID(Object... obj) {
+ return createToken();
+ }
+
+ @Override
+ public String encodeBase() {
+ return null;
+ }
+
+ @Override
+ public String validateIPAddress(String ipaddress) throws KorAPException {
+ return null;
+ }
+
+ @Override
+ public String validateEmail(String email) throws KorAPException {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> validateMap(Map<String, Object> map)
+ throws KorAPException {
+ return null;
+ }
+
+ @Override
+ public String validateString(String input) throws KorAPException {
+ return null;
+ }
+
+ @Override
+ public void validate(Object instance) throws KorAPException {
+
+ }
+
+ @Override
+ public String validatePassphrase(String pw) throws KorAPException {
+ return null;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/plugins/PluginManager.java b/src/main/java/de/ids_mannheim/korap/plugins/PluginManager.java
new file mode 100644
index 0000000..262985f
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/plugins/PluginManager.java
@@ -0,0 +1,31 @@
+package de.ids_mannheim.korap.plugins;
+
+import de.ids_mannheim.korap.interfaces.EntityHandlerIface;
+import de.ids_mannheim.korap.interfaces.UserControllerIface;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 15/06/2015
+ */
+// via spring a list of implementations is inserted, for which there will be default constructors loaded
+public class PluginManager {
+
+ private Map<String, Class> plugins;
+
+ public PluginManager() {
+ plugins = new HashMap<>();
+ }
+
+ public void loadPluginInterfaces() {
+ plugins.put("userdb", EntityHandlerIface.class);
+ plugins.put("usercontroller", UserControllerIface.class);
+ plugins.put("encrytion", EntityHandlerIface.class);
+ }
+
+ public void register(String key, Class cl) {
+ plugins.put(key, cl);
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/Attributes.java b/src/main/java/de/ids_mannheim/korap/user/Attributes.java
new file mode 100644
index 0000000..0bba5b7
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/Attributes.java
@@ -0,0 +1,143 @@
+package de.ids_mannheim.korap.user;
+
+public class Attributes {
+
+ public static final String AUTHORIZATION = "Authorization";
+ public static final String SESSION_AUTHENTICATION = "session_token";
+ public static final String API_AUTHENTICATION = "api_token";
+ public static final String OAUTH2_AUTHORIZATION = "bearer";
+ public static final String OPENID_AUTHENTICATION = "id_token";
+ public static final String BASIC_AUTHENTICATION = "basic";
+
+ public static final String CLIENT_ID = "client_id";
+ public static final String CLIENT_SECRET = "client_secret";
+ public static final String SCOPES = "scopes";
+
+ public static final String SERVICE_ACCESS = "service_access";
+ public static final String USER = "KorapUser";
+ public static final String SHIBUSER = "ShibUser";
+ public static final String DEMO_DISPLAY = "Anonymous";
+ public static final String DEMOUSER_PASSWORD = "demo";
+
+ public static final String SETTINGS = "LocalSettings";
+ // public static final String STORAGE_SETTINGS = "StorageSettings";
+
+ public static final String QUERY_ABBREVIATION = "Q";
+ public static final String LAYER = "layer";
+
+ public static final String TYPE = "type";
+
+ public static final String UID = "accountID";
+ public static final String USERNAME = "username";
+ public static final String PASSWORD = "password";
+ public static final String GENDER = "gender";
+ public static final String FIRSTNAME = "firstName";
+ public static final String LASTNAME = "lastName";
+ public static final String PHONE = "phone";
+ public static final String INSTITUTION = "institution";
+ public static final String EMAIL = "email";
+ public static final String ADDRESS = "address";
+ public static final String COUNTRY = "country";
+ public static final String ACCOUNT_CREATION = "accountCreation";
+ public static final String ACCOUNTLOCK = "accountLock";
+ public static final String ACCOUNTLINK = "accountLink";
+ public static final String URI = "uri";
+ public static final String URI_FRAGMENT = "URIFragment";
+ public static final String URI_EXPIRATION = "uriExpiration";
+ public static final String PRIVATE_USAGE = "privateUsage";
+
+ /**
+ * token context
+ */
+ public static final String TOKEN = "authToken";
+ public static final String TOKEN_EXPIRATION = "tokenExpires";
+ public static final String TOKEN_CREATION = "tokenCreated";
+ public static final String USER_AGENT = "User-Agent";
+ public static final String HOST = "userIP";
+
+ public static final String QUERY_PARAM_URI = "uri";
+ public static final String QUERY_PARAM_USER = "user";
+
+ /**
+ * shibboleth attribute names
+ */
+ public static final String EPPN = "eppn";
+ public static final String COMMON_NAME = "cn";
+ public static final String SURNAME = "sn";
+
+ public static final String EDUPERSON = "eduPersonPrincipalName";
+ public static final String CN = "cn";
+ public static final String MAIL = "mail";
+ public static final String EDU_AFFIL = "eduPersonScopedAffiliation";
+
+ /**
+ * resource mappings
+ */
+
+ public static final String RID = "id";
+ public static final String OWNER = "owner";
+ public static final String NAME = "name";
+ public static final String DESCRIPTION = "description";
+
+ public static final String REF_CORPUS = "refCorpus";
+ public static final String QUERY = "query";
+ public static final String CACHE = "cache";
+ public static final String DOCIDS = "docIDs";
+ public static final String FOUNDRIES = "foundries";
+ public static final String DEFAULT_VALUE = "defaultColl";
+
+ public static final String FILE_FORMAT_FOR_EXPORT = "fileFormatForExport";
+ public static final String FILENAME_FOR_EXPORT = "fileNameForExport";
+ @Deprecated
+ public static final String ITEM_FOR_SIMPLE_ANNOTATION = "itemForSimpleAnnotation";
+ public static final String LEFT_CONTEXT_ITEM_FOR_EXPORT = "leftContextItemForExport";
+ public static final String LEFT_CONTEXT_SIZE_FOR_EXPORT = "leftContextSizeForExport";
+ public static final String LOCALE = "locale";
+ public static final String LEFT_CONTEXT_ITEM = "leftContextItem";
+ public static final String LEFT_CONTEXT_SIZE = "leftContextSize";
+ public static final String RIGHT_CONTEXT_ITEM = "rightContextItem";
+ public static final String RIGHT_CONTEXT_ITEM_FOR_EXPORT = "rightContextItemForExport";
+ public static final String RIGHT_CONTEXT_SIZE = "rightContextSize";
+ public static final String RIGHT_CONTEXT_SIZE_FOR_EXPORT = "rightContextSizeForExport";
+ public static final String SELECTED_COLLECTION = "selectedCollection";
+ public static final String QUERY_LANGUAGE = "queryLanguage";
+ public static final String PAGE_LENGTH = "pageLength";
+ public static final String METADATA_QUERY_EXPERT_MODUS = "metadataQueryExpertModus";
+ @Deprecated
+ public static final String SEARCH_SETTINGS_TAB = "searchSettingsTab";
+ @Deprecated
+ public static final String SELECTED_BROWSER_PROPERTY = "selectedBrowserProperty";
+ @Deprecated
+ public static final String SELECTED_CONTEXT_ITEM = "selectedContextItem";
+ @Deprecated
+ public static final String SELECTED_GRAPH_TYPE = "selectedGraphType";
+ @Deprecated
+ public static final String SELECTED_SORT_TYPE = "selectedSortType";
+ @Deprecated
+ public static final String SELECTED_VIEW_FOR_SEARCH_RESULTS = "selectedViewForSearchResults";
+ public static final String COLLECT_AUDITING_DATA = "collectData";
+
+ /**
+ * default layers
+ */
+ public static final String DEFAULT_POS_FOUNDRY = "POSFoundry";
+ public static final String DEFAULT_LEMMA_FOUNDRY = "lemmaFoundry";
+ public static final String DEFAULT_CONST_FOUNDRY = "constFoundry";
+ public static final String DEFAULT_REL_FOUNDRY = "relFoundry";
+
+ /**
+ * db column keys
+ */
+
+ public static final String SELF_REF = "self";
+
+ public static final String SYM_USE = "sym_use";
+ public static final String COMMERCIAL = "commercial";
+ public static final String LICENCE = "licence";
+ public static final String QUERY_ONLY = "query_only";
+ public static final String EXPORT = "export";
+ public static final String TIME_SPANS = "spans";
+ public static final String RANGE = "range";
+
+}
+
diff --git a/src/main/java/de/ids_mannheim/korap/user/DemoUser.java b/src/main/java/de/ids_mannheim/korap/user/DemoUser.java
new file mode 100644
index 0000000..c88f5e1
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/DemoUser.java
@@ -0,0 +1,29 @@
+package de.ids_mannheim.korap.user;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+public class DemoUser extends User implements Serializable {
+ private static final long serialVersionUID = -5015206272520970500L;
+ public static final String DEMOUSER_NAME = "demo";
+ public static final Integer DEMOUSER_ID = 1654234534;
+ private static final long ACCOUNT_CREATED = 1377102171202L;
+ public static final String PASSPHRASE = "$2a$15$rGPvLWm5JJ1iYj0V61e5guYIGmSo.rjdBkAVIU1vWS/xdybmABxRa";
+
+ protected DemoUser() {
+ super(DEMOUSER_NAME, 2);
+ this.setDetails(new UserDetails());
+ this.setSettings(new UserSettings());
+ this.setAccountCreation(ACCOUNT_CREATED);
+ this.setQueries(UserQuery.demoUserQueries());
+ }
+
+ protected User clone() {
+ return new DemoUser();
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java b/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java
new file mode 100644
index 0000000..5eb6932
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java
@@ -0,0 +1,76 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.utils.KorAPLogger;
+import lombok.Getter;
+import lombok.Setter;
+import org.slf4j.Logger;
+
+@Getter
+@Setter
+public class KorAPUser extends User {
+ private static Logger jlog = KorAPLogger.initiate(KorAPUser.class);
+ private static final long serialVersionUID = -7108308497625884584L;
+
+ //fixme: accountlink to shibboleth account
+ private String accountLink;
+
+ private String password;
+ private String URIFragment;
+ private Long URIExpiration;
+
+ protected KorAPUser(String username) {
+ super(username, 0);
+ this.URIFragment = "";
+ this.URIExpiration = 0L;
+ }
+
+ public KorAPUser(Integer id, String username) {
+ this(username);
+ this.setId(id);
+ }
+
+ public KorAPUser() {
+ super();
+ }
+
+ @Override
+ protected User clone() {
+ KorAPUser user = new KorAPUser(this.getUsername());
+ user.setUsername(this.getUsername());
+ user.setAccountCreation(this.getAccountCreation());
+ return user;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = super.hashCode();
+ result = 31 * result + (jlog != null ? jlog.hashCode() : 0);
+ result = 31 * result + (password != null ? password.hashCode() : 0);
+ result = 31 * result + (URIFragment != null ?
+ URIFragment.hashCode() :
+ 0);
+ result = 31 * result + (URIExpiration != null ?
+ URIExpiration.hashCode() :
+ 0);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof KorAPUser))
+ return false;
+ if (!super.equals(o))
+ return false;
+
+ KorAPUser korAPUser = (KorAPUser) o;
+ if (URIExpiration != korAPUser.URIExpiration)
+ return false;
+ if (URIFragment != null ?
+ !URIFragment.equals(korAPUser.URIFragment) :
+ korAPUser.URIFragment != null)
+ return false;
+ return true;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/ShibUser.java b/src/main/java/de/ids_mannheim/korap/user/ShibUser.java
new file mode 100644
index 0000000..f3f60b1
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/ShibUser.java
@@ -0,0 +1,48 @@
+package de.ids_mannheim.korap.user;
+
+import lombok.Data;
+
+/**
+ * User: hanl
+ * Date: 10/16/13
+ * Time: 2:02 PM
+ */
+@Data
+public class ShibUser extends User {
+
+ private String mail;
+ private String affiliation;
+ private String cn;
+
+ protected ShibUser() {
+ super(1);
+ }
+
+ private ShibUser(String eduPersonID, String mail, String cn, String affiliation) {
+ this(eduPersonID);
+ this.setUsername(eduPersonID);
+ this.mail = mail;
+ this.affiliation = affiliation;
+ this.cn = cn;
+ }
+
+ public ShibUser(String username) {
+ super(username, 1);
+
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("ShibUser{");
+ sb.append(", mail='").append(mail).append('\'');
+ sb.append(", affiliation='").append(affiliation).append('\'');
+ sb.append(", cn='").append(cn).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ protected User clone() {
+ return new ShibUser(this.getUsername(), this.getMail(), this.getCn(), this.getAffiliation());
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/TokenContext.java b/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
new file mode 100644
index 0000000..8f244d3
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/TokenContext.java
@@ -0,0 +1,116 @@
+package de.ids_mannheim.korap.user;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import lombok.Data;
+import org.joda.time.DateTime;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 27/01/2014
+ */
+@Data
+public class TokenContext implements java.security.Principal {
+
+ /**
+ * session relevant data. Are never persisted into a database
+ */
+ private String username;
+ private Date expirationTime;
+ // either "session_token " / "api_token
+ private String tokenType;
+ private String token;
+
+ private boolean secureRequired;
+
+ private Map<String, Object> parameters;
+ private String hostAddress;
+ private String userAgent;
+
+ public TokenContext(String username) {
+ this();
+ this.username = username;
+ }
+
+ private TokenContext() {
+ this.parameters = new HashMap<>();
+ this.setUsername("");
+ this.setToken("");
+ this.setSecureRequired(false);
+ }
+
+ private Map statusMap() {
+ Map m = new HashMap();
+ if (username != null && !username.isEmpty())
+ m.put(Attributes.USERNAME, username);
+ m.put(Attributes.TOKEN_EXPIRATION,
+ new DateTime(expirationTime).toString());
+ m.put(Attributes.TOKEN, this.token);
+ return m;
+ }
+
+ public boolean match(TokenContext other) {
+ if (other.getToken().equals(this.token))
+ if (this.getHostAddress().equals(this.hostAddress))
+ // user agent should be irrelvant -- what about os system version?
+ // if (other.getUserAgent().equals(this.userAgent))
+ return true;
+ return false;
+ }
+
+ public void addContextParameter(String key, String value) {
+ this.parameters.put(key, value);
+ }
+
+ public void removeContextParameter(String key) {
+ this.parameters.remove(key);
+ }
+
+ public void setExpirationTime(long date) {
+ this.expirationTime = new Date(date);
+ }
+
+ public static TokenContext fromJSON(String s) {
+ JsonNode node = JsonUtils.readTree(s);
+ TokenContext c = new TokenContext(
+ node.path(Attributes.USERNAME).asText());
+ c.setToken(node.path(Attributes.TOKEN).asText());
+ return c;
+ }
+
+ public static TokenContext fromOAuth(String s) {
+ JsonNode node = JsonUtils.readTree(s);
+ TokenContext c = new TokenContext();
+ c.setToken(node.path("token").asText());
+ c.setTokenType(node.path("token_type").asText());
+ c.setExpirationTime(node.path("expires_in").asLong());
+ return c;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public String toJSON() {
+ return JsonUtils.toJSON(this.statusMap());
+ }
+
+ public String toResponse() {
+ ObjectNode node = JsonUtils.createObjectNode();
+ node.put("token", this.getToken());
+ node.put("expires", this.getExpirationTime().getTime());
+ node.put("token_type", this.getTokenType());
+ return JsonUtils.toJSON(node);
+ }
+
+ @Override
+ public String getName() {
+ return this.getUsername();
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/User.java b/src/main/java/de/ids_mannheim/korap/user/User.java
new file mode 100644
index 0000000..2b28edd
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/User.java
@@ -0,0 +1,214 @@
+package de.ids_mannheim.korap.user;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.TimeUtils;
+import lombok.Data;
+import org.joda.time.DateTime;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public abstract class User implements Serializable {
+
+ public static final int ADMINISTRATOR_ID = 34349733;
+ public static final String ADMINISTRATOR_NAME = "admin";
+
+ private Integer id;
+ // in local its username, in shib it's edupersonPrincipalName
+ private String username;
+ private Long accountCreation;
+ private boolean isAccountLocked;
+ private int type;
+ private Map<String, Object> fields;
+ private UserSettings settings;
+ private UserDetails details;
+ private List<UserQuery> queries;
+
+ protected User() {
+ this.accountCreation = TimeUtils.getNow().getMillis();
+ this.isAccountLocked = false;
+ this.username = "";
+ this.fields = new HashMap<>();
+ this.id = -1;
+ }
+
+ protected User(int type) {
+ this();
+ this.type = type;
+ }
+
+ protected User(String username, int type) {
+ this(type);
+ this.username = username;
+ }
+
+ public void setField(String key, Object value) {
+ this.fields.put(key, value);
+ }
+
+ public Object getField(String key) {
+ return this.fields.get(key);
+ }
+
+ //todo: repair transfer
+ public void transfer(User user) {
+ this.setSettings(user.getSettings());
+ this.setDetails(user.getDetails());
+ // this.setQueries(user.getQueries());
+ if (this instanceof KorAPUser) {
+ this.getSettings().setUserID(this.id);
+ this.getDetails().setUserID(this.id);
+ // for (UserQuery q : this.getQueries())
+ // q.setOwner(this.accountID);
+ }
+ }
+
+ public void setDetails(UserDetails details) {
+ if (details != null)
+ details.setUserID(this.id);
+ this.details = details;
+ }
+
+ public void setSettings(UserSettings settings) {
+ if (settings != null)
+ settings.setUserID(this.id);
+ this.settings = settings;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ if (this.settings != null)
+ this.settings.setUserID(this.id);
+ if (this.details != null)
+ this.details.setUserID(this.id);
+ }
+
+ public Map<String, Object> toMap() {
+ Map map = new HashMap();
+ map.put(Attributes.USERNAME, this.username);
+ //TimeUtils.format(new DateTime(this.accountCreation))
+ map.put(Attributes.ACCOUNT_CREATION, this.accountCreation);
+
+ if (this.getDetails() != null)
+ map.putAll(this.getDetails().toMap());
+ return map;
+ }
+
+ public String toJson() {
+ return JsonUtils.toJSON(this.toMap());
+ }
+
+ public Map toCache() {
+ Map map = new HashMap();
+ map.put(Attributes.UID, this.id);
+ map.put(Attributes.USERNAME, this.username);
+ map.put(Attributes.ACCOUNT_CREATION,
+ TimeUtils.format(new DateTime(this.accountCreation)));
+ map.put(Attributes.ACCOUNTLOCK, this.isAccountLocked);
+ map.put(Attributes.TYPE, this.type);
+ return map;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof User))
+ return false;
+ User user = (User) o;
+ if (!username.equals(user.username))
+ return false;
+ return true;
+ }
+
+ public boolean isDemo() {
+ return this.getUsername().equalsIgnoreCase(DemoUser.DEMOUSER_NAME);
+ }
+
+ public boolean isAdmin() {
+ return this.getUsername().equals(ADMINISTRATOR_ID);
+ }
+
+ protected abstract User clone();
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer();
+ sb.append("id='").append(id).append('\'');
+ sb.append(", username='").append(username).append('\'');
+ return sb.toString();
+ }
+
+ public static class UserFactory {
+
+ public static KorAPUser getUser(String username) {
+ return new KorAPUser(username);
+ }
+
+ public static KorAPUser getAdmin() {
+ return new KorAPUser(ADMINISTRATOR_ID, ADMINISTRATOR_NAME);
+ }
+
+ public static DemoUser getDemoUser() {
+ return new DemoUser();
+ }
+
+ public static DemoUser getDemoUser(Integer id) {
+ DemoUser demo = new DemoUser();
+ demo.setId(id);
+ return demo;
+ }
+
+ public static ShibUser getShibInstance(String eduPersonID, String mail,
+ String cn) {
+ ShibUser u = new ShibUser(eduPersonID);
+ u.setAffiliation("");
+ u.setMail(mail);
+ u.setUsername(eduPersonID);
+ u.setCn(cn);
+ return u;
+ }
+
+ public static User toUser(Map map) {
+ int type = map.get(Attributes.TYPE) == null ?
+ 0 :
+ (int) map.get(Attributes.TYPE);
+ User user;
+ DateTime dateTime = DateTime
+ .parse((String) map.get(Attributes.ACCOUNT_CREATION));
+ switch (type) {
+ case 0:
+ user = UserFactory
+ .getUser((String) map.get(Attributes.USERNAME));
+ user.setId((Integer) map.get(Attributes.UID));
+ user.setAccountLocked(
+ (Boolean) map.get(Attributes.ACCOUNTLOCK));
+ user.setAccountCreation(dateTime.getMillis());
+ break;
+ default:
+ user = UserFactory
+ .getDemoUser((Integer) map.get(Attributes.UID));
+ user.setAccountCreation(dateTime.getMillis());
+ }
+ return user;
+ }
+
+ public static KorAPUser toUser(String value) {
+ JsonNode node = JsonUtils.readTree(value);
+ KorAPUser user = UserFactory
+ .getUser(node.path(Attributes.USERNAME).asText());
+ user.setAccountLocked(
+ node.path(Attributes.ACCOUNTLOCK).asBoolean());
+ user.setAccountLink(node.path(Attributes.ACCOUNTLINK).asText());
+ user.setAccountCreation(
+ node.path(Attributes.ACCOUNT_CREATION).asLong());
+ user.setPassword(node.path(Attributes.PASSWORD).asText());
+ return user;
+ }
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserDetails.java b/src/main/java/de/ids_mannheim/korap/user/UserDetails.java
new file mode 100644
index 0000000..6b2ffdb
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserDetails.java
@@ -0,0 +1,111 @@
+package de.ids_mannheim.korap.user;
+
+import lombok.Data;
+import org.apache.commons.collections.map.CaseInsensitiveMap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: hanl
+ * Date: 8/14/13
+ * Time: 10:32 AM
+ */
+
+@Data
+public class UserDetails {
+
+ private Integer Id;
+ private Integer userID;
+ private String firstName;
+ private String lastName;
+ private String gender;
+ private String phone;
+ private String institution;
+ private String email;
+ private String address;
+ private String country;
+ private boolean privateUsage;
+
+ public UserDetails() {
+ setFirstName("");
+ setLastName("");
+ setPhone("");
+ setEmail("");
+ setGender("");
+ setAddress("");
+ setCountry("");
+ setInstitution("");
+ setPrivateUsage(true);
+ }
+
+ public static UserDetails newDetailsIterator(Map<String, Object> d) {
+ UserDetails details = new UserDetails();
+ Map<String, Object> detailMap = new CaseInsensitiveMap(d);
+
+ if (!detailMap.isEmpty()) {
+ details.setFirstName((String) detailMap.get(Attributes.FIRSTNAME));
+ details.setLastName((String) detailMap.get(Attributes.LASTNAME));
+ details.setPhone((String) detailMap.get(Attributes.PHONE));
+ details.setEmail((String) detailMap.get(Attributes.EMAIL));
+ details.setGender((String) detailMap.get(Attributes.GENDER));
+ details.setAddress((String) detailMap.get(Attributes.ADDRESS));
+ details.setCountry((String) detailMap.get(Attributes.COUNTRY));
+ details.setInstitution(
+ (String) detailMap.get(Attributes.INSTITUTION));
+ details.setPrivateUsage(
+ detailMap.get(Attributes.PRIVATE_USAGE) == null ?
+ true :
+ (Boolean) detailMap.get(Attributes.PRIVATE_USAGE));
+ }
+ return details;
+ }
+
+ public void updateDetails(Map<String, String> d) {
+ Map<String, String> detailMap = new CaseInsensitiveMap(d);
+
+ if (!detailMap.isEmpty()) {
+ if (detailMap.containsKey(Attributes.FIRSTNAME))
+ this.setFirstName(detailMap.get(Attributes.FIRSTNAME));
+ if (detailMap.containsKey(Attributes.LASTNAME))
+ this.setLastName(detailMap.get(Attributes.LASTNAME));
+ if (detailMap.containsKey(Attributes.PHONE))
+ this.setPhone(detailMap.get(Attributes.PHONE));
+ if (detailMap.containsKey(Attributes.EMAIL))
+ this.setEmail(detailMap.get(Attributes.EMAIL));
+ if (detailMap.containsKey(Attributes.GENDER))
+ this.setGender(detailMap.get(Attributes.GENDER));
+ if (detailMap.containsKey(Attributes.ADDRESS))
+ this.setAddress(detailMap.get(Attributes.ADDRESS));
+ if (detailMap.containsKey(Attributes.COUNTRY))
+ this.setCountry(detailMap.get(Attributes.COUNTRY));
+ if (detailMap.containsKey(Attributes.INSTITUTION))
+ this.setInstitution(detailMap.get(Attributes.INSTITUTION));
+ this.setPrivateUsage(
+ Boolean.valueOf(detailMap.get(Attributes.PRIVATE_USAGE)));
+ }
+ }
+
+ public Map<String, Object> toMap() {
+ Map<String, Object> details = new HashMap<>();
+ // shouldnt there be a mechanism that prevents the retrieval of all information if no scopes are given?
+ // and if so, are the access_tokens specific to the scopes then?
+ details.put(Attributes.EMAIL, this.email);
+ details.put(Attributes.FIRSTNAME, this.firstName);
+ details.put(Attributes.LASTNAME, this.lastName);
+ details.put(Attributes.GENDER, this.gender);
+ details.put(Attributes.PHONE, this.phone);
+ details.put(Attributes.INSTITUTION, this.institution);
+ details.put(Attributes.ADDRESS, this.address);
+ details.put(Attributes.COUNTRY, this.country);
+ details.put(Attributes.PRIVATE_USAGE, this.privateUsage);
+
+ for (Map.Entry<String, Object> pair : details.entrySet()) {
+ if (pair.getValue() == null || pair.getValue().equals("null"))
+ pair.setValue("");
+ }
+ return details;
+ }
+
+}
+
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserQuery.java b/src/main/java/de/ids_mannheim/korap/user/UserQuery.java
new file mode 100644
index 0000000..0e53aa0
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserQuery.java
@@ -0,0 +1,136 @@
+package de.ids_mannheim.korap.user;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * User: hanl
+ * Date: 9/16/13
+ * Time: 4:38 PM
+ */
+@Data
+public class UserQuery {
+
+ private Integer id;
+ private String queryLanguage;
+ private String query;
+ private String name;
+ private String description;
+ private Integer creator;
+
+ public UserQuery(Integer id, int creator) {
+ setId(id);
+ setCreator(creator);
+ setName("");
+ setDescription("");
+ setQuery("");
+ setQueryLanguage("");
+ }
+
+ public UserQuery(String ql, String query, String description) {
+ setDescription(description);
+ setQuery(query);
+ setQueryLanguage(ql);
+ }
+
+ public UserQuery() {
+ setDescription("");
+ setQuery("");
+ setQueryLanguage("");
+ setName("");
+ }
+
+ public void setQuery(String query) {
+ this.query = query;
+ setName("Query: " + query
+ .substring(0, query.length() > 20 ? 20 : query.length()));
+ }
+
+ // todo: use example queries or store in database
+ public static List<UserQuery> demoUserQueries() {
+
+ List<UserQuery> queries = new ArrayList<>();
+ UserQuery q1 = new UserQuery();
+ q1.setQueryLanguage("COSMAS2");
+ q1.setQuery("$wegen #IN(L) <s>");
+ q1.setDescription(
+ "Findet 'wegen' an Satzanfängen. Berücksichtigt auch Groß- und Kleinschreibung");
+
+ //todo: change query
+ UserQuery q2 = new UserQuery();
+ q2.setQueryLanguage("COSMAS2");
+ q2.setQuery("base/cons:Buchstabe base/aggr:Buchstabe");
+
+ UserQuery q3 = new UserQuery();
+ q3.setQueryLanguage("COSMAS2");
+ q3.setDescription("Regular Expression Search");
+ q3.setQuery("id:/WPD_AAA.*/ AND textClass:sport");
+
+ UserQuery q4 = new UserQuery();
+ q4.setQueryLanguage("COSMAS2");
+ q4.setQuery("mpt/syntax_pos:@CC\\|und");
+
+ UserQuery q5 = new UserQuery();
+ q5.setQueryLanguage("COSMAS2");
+ q5.setQuery("VVINF\\|.*en");
+
+ queries.add(q1);
+ // queries.add(q2);
+ // queries.add(q3);
+ queries.add(q4);
+ queries.add(q5);
+ return queries;
+ }
+
+ //id is irrevelant, since data was coming
+ // from frontend and thus this object does not contain a id that could be compared!
+ // same with the userAccount. Not set yet!
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof UserQuery))
+ return false;
+ UserQuery userQuery = (UserQuery) o;
+ if (!query.equals(userQuery.query))
+ return false;
+ if (!queryLanguage.equals(userQuery.queryLanguage))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = getId() != null ? getId().hashCode() : 0;
+ result = 31 * result + (queryLanguage != null ?
+ queryLanguage.hashCode() :
+ 0);
+ result = 31 * result + (query != null ? query.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb = new StringBuffer("UserQuery{");
+ sb.append("id=").append(getId());
+ // sb.append(", owner=").append(getOwner());
+ sb.append(", queryLanguage='").append(queryLanguage).append('\'');
+ sb.append(", query='").append(query).append('\'');
+ sb.append(", description='").append(getDescription()).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ public Map toMap() {
+ Map map = new HashMap();
+ map.put("name", this.name);
+ map.put("description", this.description);
+ map.put("query", this.query);
+ map.put("queryLanguage", this.queryLanguage);
+ return map;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/UserSettings.java b/src/main/java/de/ids_mannheim/korap/user/UserSettings.java
new file mode 100644
index 0000000..365e69a
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/UserSettings.java
@@ -0,0 +1,467 @@
+package de.ids_mannheim.korap.user;
+
+import de.ids_mannheim.korap.utils.BooleanUtils;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: hanl
+ * Date: 8/14/13
+ * Time: 10:26 AM
+ */
+
+@Getter
+@Setter
+public class UserSettings {
+
+ private Integer id;
+ private Integer userID;
+ private String fileNameForExport;
+ // @Deprecated
+ // private Integer itemForSimpleAnnotation;
+ private String leftContextItemForExport;
+ private Integer leftContextSizeForExport;
+ private String locale;
+ private String leftContextItem;
+ private Integer leftContextSize;
+ private String rightContextItem;
+ private String rightContextItemForExport;
+ private Integer rightContextSize;
+ private Integer rightContextSizeForExport;
+ private String selectedCollection;
+ private String queryLanguage;
+ private Integer pageLength;
+ private boolean metadataQueryExpertModus;
+ // @Deprecated
+ // private Integer searchSettingsTab;
+ // @Deprecated
+ // private Integer selectedGraphType;
+ // @Deprecated
+ // private String selectedSortType;
+ // @Deprecated
+ // private String selectedViewForSearchResults;
+
+ /**
+ * default values for foundry specification! of structure ff/lay
+ */
+ private String defaultPOSfoundry;
+ private String defaultLemmafoundry;
+ //default foundry for constituent information (syntax trees) --> there is no actual layer for this information
+ private String defaultConstfoundry;
+ private String defaultRelfoundry;
+
+ //todo: refactor to anonymous -- since data is collected either way!
+ private boolean collectData;
+
+ /**
+ * creates an instance of this object with default values, mapped from a database/configuration file
+ */
+ public UserSettings() {
+ setupDefaultSettings();
+ }
+
+ public static UserSettings fromObjectMap(Map<String, Object> m) {
+ UserSettings s = new UserSettings();
+ s.setFileNameForExport((String) m.get(Attributes.FILENAME_FOR_EXPORT));
+ // s.setItemForSimpleAnnotation(
+ // (Integer) m.get(Attributes.ITEM_FOR_SIMPLE_ANNOTATION));
+ s.setLeftContextItemForExport(
+ (String) m.get(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setLeftContextSizeForExport(
+ (Integer) m.get(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT));
+ s.setLocale((String) m.get(Attributes.LOCALE));
+ s.setLeftContextItem((String) m.get(Attributes.LEFT_CONTEXT_ITEM));
+ s.setLeftContextSize((Integer) m.get(Attributes.LEFT_CONTEXT_SIZE));
+ s.setRightContextItem((String) m.get(Attributes.RIGHT_CONTEXT_ITEM));
+ s.setRightContextItemForExport(
+ (String) m.get(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setRightContextSize((Integer) m.get(Attributes.RIGHT_CONTEXT_SIZE));
+ s.setRightContextSizeForExport(
+ (Integer) m.get(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT));
+ s.setSelectedCollection((String) m.get(Attributes.SELECTED_COLLECTION));
+ s.setQueryLanguage((String) m.get(Attributes.QUERY_LANGUAGE));
+ s.setPageLength((Integer) m.get(Attributes.PAGE_LENGTH));
+ s.setMetadataQueryExpertModus((Boolean) BooleanUtils
+ .getBoolean(m.get(Attributes.METADATA_QUERY_EXPERT_MODUS)));
+ // s.setSearchSettingsTab((Integer) m.get(Attributes.SEARCH_SETTINGS_TAB));
+ // s.setSelectedGraphType((Integer) m.get(Attributes.SELECTED_GRAPH_TYPE));
+ // s.setSelectedSortType((String) m.get(Attributes.SELECTED_SORT_TYPE));
+ // s.setSelectedViewForSearchResults(
+ // (String) m.get(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS));
+ s.setCollectData((Boolean) BooleanUtils
+ .getBoolean(m.get(Attributes.COLLECT_AUDITING_DATA)));
+
+ s.setDefaultConstfoundry(
+ (String) m.get(Attributes.DEFAULT_CONST_FOUNDRY));
+ s.setDefaultRelfoundry((String) m.get(Attributes.DEFAULT_REL_FOUNDRY));
+ s.setDefaultPOSfoundry((String) m.get(Attributes.DEFAULT_POS_FOUNDRY));
+ s.setDefaultLemmafoundry(
+ (String) m.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+
+ s.setId((Integer) m.get("Id"));
+ s.setUserID((Integer) m.get("userID"));
+ return s;
+ }
+
+ public static UserSettings fromMap(Map<String, String> m) {
+ UserSettings s = new UserSettings();
+ s.setFileNameForExport(m.get(Attributes.FILENAME_FOR_EXPORT));
+ // s.setItemForSimpleAnnotation(
+ // Integer.valueOf(m.get(Attributes.ITEM_FOR_SIMPLE_ANNOTATION)));
+ s.setLeftContextItemForExport(
+ m.get(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setLeftContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT)));
+ s.setLocale(m.get(Attributes.LOCALE));
+ s.setLeftContextItem(m.get(Attributes.LEFT_CONTEXT_ITEM));
+ s.setLeftContextSize(
+ Integer.valueOf(m.get(Attributes.LEFT_CONTEXT_SIZE)));
+ s.setRightContextItem(m.get(Attributes.RIGHT_CONTEXT_ITEM));
+ s.setRightContextItemForExport(
+ m.get(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setRightContextSize(
+ Integer.valueOf(m.get(Attributes.RIGHT_CONTEXT_SIZE)));
+ s.setRightContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT)));
+ s.setSelectedCollection(m.get(Attributes.SELECTED_COLLECTION));
+ s.setQueryLanguage(m.get(Attributes.QUERY_LANGUAGE));
+ s.setPageLength(Integer.valueOf(m.get(Attributes.PAGE_LENGTH)));
+ s.setMetadataQueryExpertModus(
+ Boolean.valueOf(m.get(Attributes.METADATA_QUERY_EXPERT_MODUS)));
+ // s.setSearchSettingsTab(
+ // Integer.valueOf(m.get(Attributes.SEARCH_SETTINGS_TAB)));
+ // s.setSelectedGraphType(
+ // Integer.valueOf(m.get(Attributes.SELECTED_GRAPH_TYPE)));
+ // s.setSelectedSortType(m.get(Attributes.SELECTED_SORT_TYPE));
+ // s.setSelectedViewForSearchResults(
+ // m.get(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS));
+
+ s.setCollectData(
+ Boolean.valueOf(m.get(Attributes.COLLECT_AUDITING_DATA)));
+ s.setDefaultConstfoundry(m.get(Attributes.DEFAULT_CONST_FOUNDRY));
+ s.setDefaultRelfoundry(m.get(Attributes.DEFAULT_REL_FOUNDRY));
+ s.setDefaultPOSfoundry(m.get(Attributes.DEFAULT_POS_FOUNDRY));
+ s.setDefaultLemmafoundry(m.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+ return s;
+ }
+
+ public static UserSettings newSettingsIterator(Map<String, String> m) {
+ UserSettings s = new UserSettings();
+ if (m.isEmpty())
+ return s;
+
+ s.setFileNameForExport(m.get(Attributes.FILENAME_FOR_EXPORT));
+ // s.setItemForSimpleAnnotation(
+ // Integer.valueOf(m.get(Attributes.ITEM_FOR_SIMPLE_ANNOTATION)));
+ s.setLeftContextItemForExport(
+ m.get(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setLeftContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT)));
+ s.setLocale(m.get(Attributes.LOCALE));
+ s.setLeftContextItem(m.get(Attributes.LEFT_CONTEXT_ITEM));
+ s.setLeftContextSize(
+ Integer.valueOf(m.get(Attributes.LEFT_CONTEXT_SIZE)));
+ s.setRightContextItem(m.get(Attributes.RIGHT_CONTEXT_ITEM));
+ s.setRightContextItemForExport(
+ m.get(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT));
+ s.setRightContextSize(
+ Integer.valueOf(m.get(Attributes.RIGHT_CONTEXT_SIZE)));
+ s.setRightContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT)));
+ s.setSelectedCollection(m.get(Attributes.SELECTED_COLLECTION));
+ s.setQueryLanguage(m.get(Attributes.QUERY_LANGUAGE));
+ s.setPageLength(Integer.valueOf(m.get(Attributes.PAGE_LENGTH)));
+ s.setMetadataQueryExpertModus(
+ Boolean.valueOf(m.get(Attributes.METADATA_QUERY_EXPERT_MODUS)));
+ // s.setSearchSettingsTab(
+ // Integer.valueOf(m.get(Attributes.SEARCH_SETTINGS_TAB)));
+ // s.setSelectedGraphType(
+ // Integer.valueOf(m.get(Attributes.SELECTED_GRAPH_TYPE)));
+ // s.setSelectedSortType(m.get(Attributes.SELECTED_SORT_TYPE));
+ // s.setSelectedViewForSearchResults(
+ // m.get(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS));
+
+ s.setCollectData(
+ Boolean.valueOf(m.get(Attributes.COLLECT_AUDITING_DATA)));
+ s.setDefaultConstfoundry(m.get(Attributes.DEFAULT_CONST_FOUNDRY));
+ s.setDefaultRelfoundry(m.get(Attributes.DEFAULT_REL_FOUNDRY));
+ s.setDefaultPOSfoundry(m.get(Attributes.DEFAULT_POS_FOUNDRY));
+ s.setDefaultLemmafoundry(m.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+ return s;
+ }
+
+ public void updateStringSettings(Map<String, String> m) {
+ this.setFileNameForExport(m.get(Attributes.FILENAME_FOR_EXPORT));
+ // this.setItemForSimpleAnnotation(
+ // Integer.valueOf(m.get(Attributes.ITEM_FOR_SIMPLE_ANNOTATION)));
+ this.setLeftContextItemForExport(
+ m.get(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT));
+ this.setLeftContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT)));
+ this.setLocale(m.get(Attributes.LOCALE));
+ this.setLeftContextItem(m.get(Attributes.LEFT_CONTEXT_ITEM));
+ this.setLeftContextSize(
+ Integer.valueOf(m.get(Attributes.LEFT_CONTEXT_SIZE)));
+ this.setRightContextItem(m.get(Attributes.RIGHT_CONTEXT_ITEM));
+ this.setRightContextItemForExport(
+ m.get(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT));
+ this.setRightContextSize(
+ Integer.valueOf(m.get(Attributes.RIGHT_CONTEXT_SIZE)));
+ this.setRightContextSizeForExport(Integer.valueOf(
+ m.get(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT)));
+ this.setSelectedCollection(m.get(Attributes.SELECTED_COLLECTION));
+ this.setQueryLanguage(m.get(Attributes.QUERY_LANGUAGE));
+ this.setPageLength(Integer.valueOf(m.get(Attributes.PAGE_LENGTH)));
+ this.setMetadataQueryExpertModus(
+ Boolean.valueOf(m.get(Attributes.METADATA_QUERY_EXPERT_MODUS)));
+ // this.setSearchSettingsTab(
+ // Integer.valueOf(m.get(Attributes.SEARCH_SETTINGS_TAB)));
+ // this.setSelectedGraphType(
+ // Integer.valueOf(m.get(Attributes.SELECTED_GRAPH_TYPE)));
+ // this.setSelectedSortType(m.get(Attributes.SELECTED_SORT_TYPE));
+ // this.setSelectedViewForSearchResults(
+ // m.get(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS));
+
+ this.setCollectData(
+ Boolean.valueOf(m.get(Attributes.COLLECT_AUDITING_DATA)));
+ this.setDefaultPOSfoundry(m.get(Attributes.DEFAULT_POS_FOUNDRY));
+ this.setDefaultLemmafoundry(m.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+ this.setDefaultConstfoundry(m.get(Attributes.DEFAULT_CONST_FOUNDRY));
+ this.setDefaultRelfoundry(m.get(Attributes.DEFAULT_REL_FOUNDRY));
+ }
+
+ public void updateObjectSettings(Map<String, Object> m) {
+ this.setFileNameForExport(
+ (String) m.get(Attributes.FILENAME_FOR_EXPORT));
+ // this.setItemForSimpleAnnotation(
+ // (Integer) m.get(Attributes.ITEM_FOR_SIMPLE_ANNOTATION));
+ this.setLeftContextItemForExport(
+ (String) m.get(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT));
+ this.setLeftContextSizeForExport(
+ (Integer) m.get(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT));
+ this.setLocale((String) m.get(Attributes.LOCALE));
+ this.setLeftContextItem((String) m.get(Attributes.LEFT_CONTEXT_ITEM));
+ this.setLeftContextSize((Integer) m.get(Attributes.LEFT_CONTEXT_SIZE));
+ this.setRightContextItem((String) m.get(Attributes.RIGHT_CONTEXT_ITEM));
+ this.setRightContextItemForExport(
+ (String) m.get(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT));
+ this.setRightContextSize(
+ (Integer) m.get(Attributes.RIGHT_CONTEXT_SIZE));
+ this.setRightContextSizeForExport(
+ (Integer) m.get(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT));
+ this.setSelectedCollection(
+ (String) m.get(Attributes.SELECTED_COLLECTION));
+ this.setQueryLanguage((String) m.get(Attributes.QUERY_LANGUAGE));
+ this.setPageLength((Integer) m.get(Attributes.PAGE_LENGTH));
+ this.setMetadataQueryExpertModus(
+ (Boolean) m.get(Attributes.METADATA_QUERY_EXPERT_MODUS));
+ // this.setSearchSettingsTab(
+ // (Integer) m.get(Attributes.SEARCH_SETTINGS_TAB));
+ // this.setSelectedGraphType(
+ // (Integer) m.get(Attributes.SELECTED_GRAPH_TYPE));
+ // this.setSelectedSortType((String) m.get(Attributes.SELECTED_SORT_TYPE));
+ // this.setSelectedViewForSearchResults(
+ // (String) m.get(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS));
+
+ this.setCollectData((Boolean) m.get(Attributes.COLLECT_AUDITING_DATA));
+ this.setDefaultPOSfoundry(
+ (String) m.get(Attributes.DEFAULT_POS_FOUNDRY));
+ this.setDefaultLemmafoundry(
+ (String) m.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+ this.setDefaultConstfoundry(
+ (String) m.get(Attributes.DEFAULT_CONST_FOUNDRY));
+ this.setDefaultRelfoundry(
+ (String) m.get(Attributes.DEFAULT_REL_FOUNDRY));
+ }
+
+ //load from configuration?
+ private void setupDefaultSettings() {
+ this.setFileNameForExport("export");
+ // this.setItemForSimpleAnnotation(0);
+ this.setLocale("de");
+ this.setLeftContextItemForExport("char");
+ this.setLeftContextSizeForExport(100);
+ this.setLeftContextItem("char");
+ this.setLeftContextSize(200);
+ this.setRightContextItem("char");
+ this.setRightContextItemForExport("char");
+ this.setRightContextSize(200);
+ this.setRightContextSizeForExport(100);
+ // persistent id for wikipedia!
+ this.setSelectedCollection(
+ "ZGU0ZTllNTFkYzc3M2VhZmViYzdkYWE2ODI5NDc3NTk4NGQ1YThhOTMwOTNhOWYxNWMwN2M3Y2YyZmE3N2RlNQ==");
+ this.setQueryLanguage("COSMAS2");
+ this.setPageLength(25);
+ this.setMetadataQueryExpertModus(true);
+ // this.setSearchSettingsTab(0);
+ // this.setSelectedGraphType(1);
+ // this.setSelectedSortType("FIFO");
+ // this.setSelectedViewForSearchResults("KWIC");
+
+ this.setCollectData(true);
+ this.setDefaultConstfoundry("mate");
+ this.setDefaultRelfoundry("mate");
+ this.setDefaultPOSfoundry("tt");
+ this.setDefaultLemmafoundry("tt");
+ }
+
+ public Map toStringMap() {
+ Map<String, String> m = new HashMap<>();
+ m.put(Attributes.FILENAME_FOR_EXPORT, this.getFileNameForExport());
+ // m.put(Attributes.ITEM_FOR_SIMPLE_ANNOTATION,
+ // String.valueOf(this.getItemForSimpleAnnotation()));
+ m.put(Attributes.LEFT_CONTEXT_SIZE,
+ String.valueOf(this.getLeftContextSize()));
+ m.put(Attributes.LEFT_CONTEXT_ITEM,
+ String.valueOf(this.getLeftContextItem()));
+ m.put(Attributes.LOCALE, this.getLocale());
+ m.put(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT,
+ String.valueOf(this.getLeftContextSizeForExport()));
+ m.put(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT,
+ String.valueOf(this.getLeftContextItemForExport()));
+ m.put(Attributes.RIGHT_CONTEXT_ITEM,
+ String.valueOf(this.getRightContextItem()));
+ m.put(Attributes.RIGHT_CONTEXT_SIZE,
+ String.valueOf(this.getRightContextSize()));
+ m.put(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT,
+ String.valueOf(this.getRightContextItemForExport()));
+ m.put(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT,
+ String.valueOf(this.getRightContextSizeForExport()));
+ m.put(Attributes.SELECTED_COLLECTION, this.getSelectedCollection());
+ m.put(Attributes.QUERY_LANGUAGE, this.getQueryLanguage());
+ m.put(Attributes.PAGE_LENGTH, String.valueOf(this.getPageLength()));
+ m.put(Attributes.METADATA_QUERY_EXPERT_MODUS,
+ String.valueOf(this.isMetadataQueryExpertModus()));
+ // m.put(Attributes.SEARCH_SETTINGS_TAB,
+ // String.valueOf(this.getSearchSettingsTab()));
+ // m.put(Attributes.SELECTED_GRAPH_TYPE,
+ // String.valueOf(this.getSelectedGraphType()));
+ // m.put(Attributes.SELECTED_SORT_TYPE, this.getSelectedSortType());
+ // m.put(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS,
+ // this.getSelectedViewForSearchResults());
+ m.put(Attributes.DEFAULT_POS_FOUNDRY, this.getDefaultPOSfoundry());
+ m.put(Attributes.DEFAULT_LEMMA_FOUNDRY, this.getDefaultLemmafoundry());
+ m.put(Attributes.DEFAULT_CONST_FOUNDRY, this.getDefaultConstfoundry());
+ m.put(Attributes.DEFAULT_REL_FOUNDRY, this.getDefaultRelfoundry());
+ m.put(Attributes.COLLECT_AUDITING_DATA,
+ String.valueOf(this.isCollectData()));
+
+ for (Map.Entry pair : m.entrySet()) {
+ if (pair.getValue() == null)
+ pair.setValue("");
+ }
+ return m;
+ }
+
+ public Map toObjectMap() {
+ Map<String, Object> m = new HashMap<>();
+ m.put(Attributes.FILENAME_FOR_EXPORT, this.getFileNameForExport());
+ // m.put(Attributes.ITEM_FOR_SIMPLE_ANNOTATION,
+ // this.getItemForSimpleAnnotation());
+ m.put(Attributes.LEFT_CONTEXT_SIZE, this.getLeftContextSize());
+ m.put(Attributes.LEFT_CONTEXT_ITEM, this.getLeftContextItem());
+ m.put(Attributes.LOCALE, this.getLocale());
+ m.put(Attributes.LEFT_CONTEXT_SIZE_FOR_EXPORT,
+ this.getLeftContextSizeForExport());
+ m.put(Attributes.LEFT_CONTEXT_ITEM_FOR_EXPORT,
+ this.getLeftContextItemForExport());
+ m.put(Attributes.RIGHT_CONTEXT_ITEM, this.getRightContextItem());
+ m.put(Attributes.RIGHT_CONTEXT_SIZE, this.getRightContextSize());
+ m.put(Attributes.RIGHT_CONTEXT_ITEM_FOR_EXPORT,
+ this.getRightContextItemForExport());
+ m.put(Attributes.RIGHT_CONTEXT_SIZE_FOR_EXPORT,
+ this.getRightContextSizeForExport());
+ m.put(Attributes.SELECTED_COLLECTION, this.getSelectedCollection());
+ m.put(Attributes.QUERY_LANGUAGE, this.getQueryLanguage());
+ m.put(Attributes.PAGE_LENGTH, this.getPageLength());
+ m.put(Attributes.METADATA_QUERY_EXPERT_MODUS,
+ this.isMetadataQueryExpertModus());
+ // m.put(Attributes.SEARCH_SETTINGS_TAB, this.getSearchSettingsTab());
+ // m.put(Attributes.SELECTED_GRAPH_TYPE, this.getSelectedGraphType());
+ // m.put(Attributes.SELECTED_SORT_TYPE, this.getSelectedSortType());
+ // m.put(Attributes.SELECTED_VIEW_FOR_SEARCH_RESULTS,
+ // this.getSelectedViewForSearchResults());
+ m.put(Attributes.DEFAULT_POS_FOUNDRY, this.getDefaultPOSfoundry());
+ m.put(Attributes.DEFAULT_LEMMA_FOUNDRY, this.getDefaultLemmafoundry());
+ m.put(Attributes.DEFAULT_CONST_FOUNDRY, this.getDefaultConstfoundry());
+ m.put(Attributes.DEFAULT_REL_FOUNDRY, this.getDefaultRelfoundry());
+ m.put(Attributes.COLLECT_AUDITING_DATA, this.isCollectData());
+ for (Map.Entry pair : m.entrySet()) {
+ if (pair.getValue() == null)
+ pair.setValue("");
+ }
+ return m;
+ }
+
+ @Override
+ public String toString() {
+ return "UserSettings{" +
+ "id=" + id +
+ ", userid=" + userID +
+ ", fileNameForExport='" + fileNameForExport + '\'' +
+ ", leftContextItemForExport='" + leftContextItemForExport + '\''
+ +
+ ", leftContextSizeForExport=" + leftContextSizeForExport +
+ ", locale='" + locale + '\'' +
+ ", leftContextItem='" + leftContextItem + '\'' +
+ ", leftContextSize=" + leftContextSize +
+ ", rightContextItem='" + rightContextItem + '\'' +
+ ", rightContextItemForExport='" + rightContextItemForExport
+ + '\'' +
+ ", rightContextSize=" + rightContextSize +
+ ", rightContextSizeForExport=" + rightContextSizeForExport +
+ ", selectedCollection='" + selectedCollection + '\'' +
+ ", queryLanguage='" + queryLanguage + '\'' +
+ ", pageLength=" + pageLength +
+ ", metadataQueryExpertModus=" + metadataQueryExpertModus +
+ ", defaultPOSfoundry='" + defaultPOSfoundry + '\'' +
+ ", defaultLemmafoundry='" + defaultLemmafoundry + '\'' +
+ ", defaultConstfoundry='" + defaultConstfoundry + '\'' +
+ ", defaultRelfoundry='" + defaultRelfoundry + '\'' +
+ ", collectData='" + collectData + "\'" +
+ '}';
+ }
+
+ public static UserSettings fromString(String value) {
+ Map<String, Object> map;
+ try {
+ map = JsonUtils.read(value, Map.class);
+ }catch (IOException e) {
+ return new UserSettings();
+ }
+ return UserSettings.fromObjectMap(map);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ UserSettings that = (UserSettings) o;
+
+ if (userID != null ? userID != that.userID : that.userID != null)
+ return false;
+ if (id != null ? !id.equals(that.id) : that.id != null)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id != null ? id.hashCode() : 0;
+ result = 31 * result + (userID != null ? userID.hashCode() : 0);
+ return result;
+ }
+
+ public String toJSON() {
+ return JsonUtils.toJSON(this);
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/Benchmark.java b/src/main/java/de/ids_mannheim/korap/utils/Benchmark.java
new file mode 100644
index 0000000..1f06897
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/Benchmark.java
@@ -0,0 +1,15 @@
+package de.ids_mannheim.korap.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author hanl
+ * @date 29/04/2014
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Benchmark {
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/BooleanUtils.java b/src/main/java/de/ids_mannheim/korap/utils/BooleanUtils.java
new file mode 100644
index 0000000..2e767ed
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/BooleanUtils.java
@@ -0,0 +1,23 @@
+package de.ids_mannheim.korap.utils;
+
+/**
+ * @author hanl
+ * @date 19/02/2014
+ */
+public class BooleanUtils {
+
+ public static String dbname;
+
+ public static Object getBoolean(Object val) {
+ if (val == null) val = false;
+ if (dbname != null
+ && dbname.equalsIgnoreCase("sqlite")) {
+ if (val instanceof Boolean) {
+ return (val == true) ? 1 : 0;
+ } else if (val instanceof Integer) {
+ return ((Integer) val == 1);
+ }
+ }
+ return val;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder.java b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder.java
new file mode 100644
index 0000000..b68feac
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder.java
@@ -0,0 +1,319 @@
+package de.ids_mannheim.korap.utils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author hanl
+ * @date 06/12/2013
+ */
+@Deprecated
+public class CollectionQueryBuilder {
+
+ private enum Relation {
+ OR, AND
+ }
+
+ private CollectionTypes types;
+ private List<Map> rq;
+ private Multimap<String, String> mfilter;
+ private Multimap<String, String> mextension;
+ private Relation simpleFilterRel = Relation.OR;
+ private Relation simpleExtendRel = Relation.OR;
+
+
+ public CollectionQueryBuilder() {
+ this.rq = new ArrayList<>();
+ this.mfilter = ArrayListMultimap.create();
+ this.mextension = ArrayListMultimap.create();
+ this.types = new CollectionTypes();
+ }
+
+ public CollectionQueryBuilder addResource(String query) {
+ try {
+ List v = JsonUtils.read(query, LinkedList.class);
+ this.rq.addAll(v);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Conversion went wrong!");
+ }
+ return this;
+ }
+
+ public CollectionQueryBuilder addResources(List<String> queries) {
+ for (String query : queries)
+ addResource(query);
+ return this;
+ }
+
+ public CollectionQueryBuilder addMetaFilter(String key, String value) {
+ this.mfilter.put(key, value);
+ return this;
+ }
+
+
+ public CollectionQueryBuilder addMetaFilterQuery(String queries) {
+ this.mfilter.putAll(resRel(queries));
+ return this;
+ }
+
+ public CollectionQueryBuilder addMetaExtend(String key, String value) {
+ this.mextension.put(key, value);
+ return this;
+ }
+
+
+ public CollectionQueryBuilder setFilterAttributeRelation(Relation rel) {
+ simpleFilterRel = rel;
+ return this;
+ }
+
+
+ public CollectionQueryBuilder setExtendAttributeRelation(Relation rel) {
+ simpleExtendRel = rel;
+ return this;
+ }
+
+ public CollectionQueryBuilder addMetaExtendQuery(String queries) {
+ this.mextension.putAll(resRel(queries));
+ return this;
+ }
+
+
+ @Deprecated
+ private List<Map> createFilter(Relation rel) {
+ String relation = rel == Relation.AND ? "and" : "or";
+ List<Map> mfil = new ArrayList<>();
+ boolean multypes = this.mfilter.keySet().size() > 1;
+ String def_key = null;
+
+ if (!multypes) {
+ Multiset<String> keys = this.mfilter.keys();
+ def_key = keys.toArray(new String[keys.size()])[0];
+ }
+
+ List value = this.createValue(this.mfilter);
+
+ if (mfilter.values().size() == 1)
+ Collections.addAll(mfil, types.createMetaFilter((Map) value.get(0)));
+ else {
+ Map group;
+ if (!multypes)
+ group = types.createGroup(relation, def_key, value);
+ else
+ group = types.createGroup(relation, null, value);
+ Collections.addAll(mfil, types.createMetaFilter(group));
+ }
+ return mfil;
+ }
+
+ @Deprecated
+ private List<Map> createExtender(Relation rel) {
+ String relation = rel == Relation.AND ? "and" : "or";
+ List<Map> mex = new ArrayList();
+ boolean multypes = this.mextension.keys().size() > 1;
+ String def_key = null;
+
+ if (!multypes)
+ def_key = this.mextension.keys().toArray(new String[0])[0];
+
+ List value = this.createValue(this.mextension);
+ // todo: missing: - takes only one resource, but resources can be chained!
+ if (this.mextension.values().size() == 1)
+ Collections.addAll(mex, types.createMetaExtend((Map) value.get(0)));
+ else {
+ Map group;
+ if (!multypes)
+ group = types.createGroup(relation, def_key, value);
+ else
+ group = types.createGroup(relation, null, value);
+ Collections.addAll(mex, types.createMetaExtend(group));
+ }
+ return mex;
+ }
+
+ private List<Map> join() {
+ List<Map> cursor = new ArrayList<>(this.rq);
+ if (!this.mfilter.isEmpty())
+ cursor.addAll(this.createFilter(simpleFilterRel));
+ if (!this.mextension.isEmpty())
+ cursor.addAll(this.createExtender(simpleExtendRel));
+ return cursor;
+ }
+
+ private List createValue(Multimap<String, String> map) {
+ List value = new ArrayList<>();
+ String[] dates = new String[3];
+ for (String key : map.keySet()) {
+ if (key.equals("pubDate")) {
+ dates = processDates((List<String>) map.get(key));
+ continue;
+ }
+
+ if (map.get(key).size() == 1) {
+ Map term = types.createTerm(key, null,
+ map.get(key).toArray(new String[0])[0], null);
+ value.add(term);
+ } else {
+ boolean multypes = map.keySet().size() > 1;
+ List g = new ArrayList();
+ for (String v : map.get(key))
+ g.add(types.createTerm(null, v, null));
+
+ if (multypes) {
+ Map group = types.createGroup("and", key, g);
+ value.add(group);
+ } else
+ value.addAll(g);
+
+ }
+ }
+
+ int idx = 3;
+ if (dates[0] != null && dates[0].equals("r")) {
+ Map term1 = types.createTerm(null, dates[1], "korap:date");
+ Map term2 = types.createTerm(null, dates[2], "korap:date");
+ Map group = types.createGroup("between", "pubDate", Arrays.asList(term1, term2));
+ value.add(group);
+ } else if (dates[1] != null) {
+ Map term1 = types.createTerm(null, dates[1], "korap:date");
+ Map group = types.createGroup("since", "pubDate", Arrays.asList(term1));
+ value.add(group);
+ } else if (dates[2] != null) {
+ Map term1 = types.createTerm(null, dates[2], "korap:date");
+ Map group = types.createGroup("until", "pubDate", Arrays.asList(term1));
+ value.add(group);
+ }
+
+ for (int i = idx; i < dates.length; i++) {
+ if (dates[i] != null) {
+ Map term1 = types.createTerm(dates[i], "korap:date");
+ Map group = types.createGroup("exact", "pubDate", Arrays.asList(term1));
+ value.add(group);
+ }
+ }
+ return value;
+ }
+
+ private String[] processDates(List<String> dates) {
+ if (dates.isEmpty())
+ return new String[3];
+ String[] el = new String[dates.size() + 3];
+ int idx = 3;
+ for (String value : dates) {
+ if (value.contains("<")) {
+ String[] sp = value.split("<");
+ el[1] = sp[1];
+ } else if (value.contains(">")) {
+ String[] sp = value.split(">");
+ el[2] = sp[1];
+ } else {
+ el[idx] = value;
+ idx++;
+ }
+ }
+ if (el[1] != null && el[2] != null)
+ el[0] = "r";
+ return el;
+ }
+
+ public List<Map> raw() {
+ return join();
+ }
+
+ public String toCollections() {
+ Map meta = new LinkedHashMap();
+ meta.put("collections", join());
+ return JsonUtils.toJSON(meta);
+ }
+
+ /**
+ * returns all references to parents and meta query as string representation
+ *
+ * @return
+ */
+ public JsonNode toNode() {
+ return JsonUtils.valueToTree(join());
+ }
+
+ public String toJSON() {
+ return JsonUtils.toJSON(join());
+ }
+
+
+ /**
+ * resolves all queries as equal (hierarchy) AND/OR relations
+ * grouping is not supported!
+ *
+ * @param queries
+ * @return
+ */
+ private Multimap<String, String> resRel(String queries) {
+ Multimap<String, String> qmap = ArrayListMultimap.create();
+ String op = null;
+ if (queries.contains("AND") | queries.contains("OR"))
+ op = queries.contains("AND") ? "AND" : "OR";
+ else if (queries.contains("&") | queries.contains("|"))
+ op = queries.contains("&") ? "&" : "|";
+
+ if (op == null)
+ return qmap;
+
+ String[] spl = queries.trim().split(op);
+ for (String query : spl) {
+ String[] q = query.split("=");
+ if (q.length > 1) {
+ String attr = q[0].trim();
+ String val = q[1].trim();
+ qmap.put(attr, val);
+ }
+ // todo: return error when query not well-formed
+ }
+ return qmap;
+ }
+
+ /**
+ * resolve relations and allow grouping of attributes: (tc1 and tc1) or (tc3)
+ *
+ * @param queries
+ * @param filter flag if either filter or extend collection
+ * @return
+ */
+ private void resRelation(String queries, boolean filter) {
+ Pattern p = Pattern.compile("\\(([\\w\\s:]+)\\)");
+ List _fill = new ArrayList();
+ Matcher m = p.matcher(queries);
+ while (m.find()) {
+ String gr = m.group(1);
+ _fill.add(gr);
+ String whole = "(" + gr + ")";
+ int fin = queries.lastIndexOf(whole);
+ String sub = queries.substring(queries.indexOf(whole), queries.lastIndexOf(whole));
+ queries.replace(whole, "");
+ }
+ }
+
+ private void v(String queries, boolean filter) {
+ // and exclude sub-groups?? : ((tc=121))
+ Pattern p = Pattern.compile("\\(([\\w\\s=]+)\\)");
+ List _fill = new ArrayList();
+ Matcher m = p.matcher(queries);
+ while (m.find()) {
+ String gr = m.group(1);
+
+ }
+
+ }
+
+ public void clear() {
+ this.rq.clear();
+ this.mfilter.clear();
+ this.mextension.clear();
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder2.java b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder2.java
new file mode 100644
index 0000000..1058f5b
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder2.java
@@ -0,0 +1,86 @@
+package de.ids_mannheim.korap.utils;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * @author hanl
+ * @date 13/05/2014
+ */
+@Deprecated
+public class CollectionQueryBuilder2 {
+
+ private List<Map> rq;
+ private Map groups;
+ private CollectionTypes types;
+ private boolean verbose;
+
+ public CollectionQueryBuilder2() {
+ this.verbose = false;
+ this.rq = new ArrayList<>();
+ this.groups = new HashMap();
+ this.types = new CollectionTypes();
+ }
+
+ public CollectionQueryBuilder2(boolean verbose) {
+ this();
+ this.verbose = verbose;
+ }
+
+
+ public CollectionQueryBuilder2 addResource(String collections) {
+ try {
+ List v = JsonUtils.read(collections, LinkedList.class);
+ this.rq.addAll(v);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Conversion went wrong!");
+ }
+ return this;
+ }
+
+ public CollectionQueryBuilder2 addResources(List<String> queries) {
+ for (String query : queries)
+ addResource(query);
+ return this;
+ }
+
+// public CollectionQueryBuilder2 setQuery(String query) {
+// CollectionQueryProcessor tree = new CollectionQueryProcessor();
+// tree.process(query);
+// this.groups = tree.getRequestMap();
+// return this;
+// }
+
+ public List raw() {
+ List list = new ArrayList(this.rq);
+ list.add(types.createMetaFilter(this.groups));
+ return list;
+ }
+
+ private Object raw2() {
+ return this.groups;
+ }
+
+ public String toCollections() {
+ Map value = new HashMap();
+ value.put("collections", raw2());
+ return JsonUtils.toJSON(value);
+ }
+
+ public JsonNode toNode() {
+ return JsonUtils.valueToTree(raw2());
+ }
+
+ public String toJSON() {
+ return JsonUtils.toJSON(raw2());
+ }
+
+
+ // add public filter to original query
+ private void addToGroup() {
+ Map first = this.rq.get(0);
+
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder3.java b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder3.java
new file mode 100644
index 0000000..1217085
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/CollectionQueryBuilder3.java
@@ -0,0 +1,79 @@
+package de.ids_mannheim.korap.utils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * convenience builder class for collection query -- new one
+ *
+ * @author hanl
+ * @date 16/09/2014
+ */
+public class CollectionQueryBuilder3 {
+
+ private boolean verbose;
+ private List<Map> rq;
+ private StringBuilder builder;
+
+ public CollectionQueryBuilder3() {
+ this(false);
+ }
+
+ public CollectionQueryBuilder3(boolean verbose) {
+ this.verbose = verbose;
+ this.builder = new StringBuilder();
+ this.rq = new LinkedList<>();
+ }
+
+
+ public CollectionQueryBuilder3 addSegment(String field, String value) {
+ String f = field + "=" + value;
+ this.builder.append(f);
+ return this;
+ }
+
+ public CollectionQueryBuilder3 add(String query) {
+ this.builder.append(query);
+ return this;
+ }
+
+ public CollectionQueryBuilder3 and() {
+ this.builder.append(" & ");
+ return this;
+ }
+
+ public CollectionQueryBuilder3 or() {
+ this.builder.append(" | ");
+ return this;
+ }
+
+ public CollectionQueryBuilder3 addResource(String collection) {
+ try {
+ List v = JsonUtils.read(collection, LinkedList.class);
+ this.rq.addAll(v);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Conversion went wrong!");
+ }
+ return this;
+ }
+
+ public List getRequest() {
+ List list = new ArrayList();
+ if (!this.rq.isEmpty())
+ list.addAll(this.rq);
+ System.out.println("RAW QUERY " + this.builder.toString());
+// CollectionQueryProcessor tree = new CollectionQueryProcessor(this.verbose);
+// tree.process(this.builder.toString());
+// list.add(tree.getRequestMap());
+ return list;
+ }
+
+ public String toJSON() {
+ return JsonUtils.toJSON(getRequest());
+ }
+
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/CollectionTypes.java b/src/main/java/de/ids_mannheim/korap/utils/CollectionTypes.java
new file mode 100644
index 0000000..2f90f57
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/CollectionTypes.java
@@ -0,0 +1,95 @@
+package de.ids_mannheim.korap.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 04/12/2013
+ */
+public class CollectionTypes {
+
+ private ObjectMapper mapper;
+
+ public CollectionTypes() {
+ this.mapper = new ObjectMapper();
+ }
+
+ public Map createGroup(String relation, String field, List terms) {
+ if (relation == null)
+ return null;
+
+ Map kgroup = new LinkedHashMap<>();
+ kgroup.put("@type", "korap:group");
+ if (field != null)
+ kgroup.put("@field", "korap:field#" + field);
+ kgroup.put("relation", relation);
+ kgroup.put("operands", terms);
+ return kgroup;
+ }
+
+ public Map createTerm(String field, String subtype, String value, String type) {
+ Map term = new LinkedHashMap<>();
+ if (type == null)
+ type = "korap:term";
+ term.put("@type", type);
+ if (field != null)
+ term.put("@field", "korap:field#" + field);
+ if (subtype != null)
+ term.put("@subtype", "korap:value#" + subtype);
+ term.put("@value", value);
+ return term;
+ }
+
+ public Map createTerm(String field, String value, String type) {
+ return createTerm(field, null, value, type);
+ }
+
+ public Map createTerm(String field, String value) {
+ return createTerm(field, value, null);
+ }
+
+ public Map createResourceFilter(String resource, Map value) {
+ Map meta = new LinkedHashMap();
+ meta.put("@type", "korap:meta-filter");
+ meta.put("@id", "korap-filter#" + resource);
+ meta.put("@value", value);
+ return meta;
+ }
+
+ public Map createResourceFilter(String resource, String value) throws IOException {
+ return createResourceFilter(resource, mapify(value));
+ }
+
+ public Map createResourceExtend(String resource, Map value) {
+ Map meta = new LinkedHashMap();
+ meta.put("@type", "korap:meta-extend");
+ meta.put("@id", "korap-filter#" + resource);
+ meta.put("@value", value);
+ return meta;
+ }
+
+ public Map createMetaFilter(Map value) {
+ Map meta = new LinkedHashMap();
+ meta.put("@type", "korap:meta-filter");
+ meta.put("@value", value);
+ return meta;
+ }
+
+ public Map createMetaExtend(Map value) {
+ Map meta = new LinkedHashMap();
+ meta.put("@type", "korap:meta-extend");
+ meta.put("@value", value);
+ return meta;
+ }
+
+
+ public Map mapify(String s) throws IOException {
+ return mapper.readValue(s, Map.class);
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/ConcurrentMultiMap.java b/src/main/java/de/ids_mannheim/korap/utils/ConcurrentMultiMap.java
new file mode 100644
index 0000000..5bb811e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/ConcurrentMultiMap.java
@@ -0,0 +1,132 @@
+package de.ids_mannheim.korap.utils;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentMap;
+
+import com.google.common.collect.Sets;
+
+import java.util.Collection;
+import java.util.Set;
+
+
+/**
+ * A general purpose Multimap implementation for delayed processing and concurrent insertion/deletes.
+ * This code is based on an implementation by Guido Medina!
+ *
+ * @param <K> A comparable Key
+ * @param <V> A comparable Value
+ */
+
+/**
+ * User: hanl
+ * Date: 8/27/13
+ * Time: 11:18 AM
+ */
+
+public class ConcurrentMultiMap<K extends Comparable, V extends Comparable> {
+
+ private final int initialCapacity;
+ private final LockMap<K> locks;
+ private final ConcurrentMap<K, List<V>> cache;
+
+ public ConcurrentMultiMap() {
+ this(16, 64);
+ }
+
+ public ConcurrentMultiMap(final int concurrencyLevel) {
+ this(concurrencyLevel, 64);
+ }
+
+ public ConcurrentMultiMap(final int concurrencyLevel, final int initialCapacity) {
+ this.initialCapacity = initialCapacity;
+ cache = new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(initialCapacity).makeMap();
+ locks = new LockMap<K>(concurrencyLevel, initialCapacity);
+ }
+
+ public void put(final K key, final V value) {
+ synchronized (locks.getLock(key)) {
+ List<V> set = cache.get(key);
+ if (set == null) {
+ set = Lists.newArrayListWithExpectedSize(initialCapacity);
+ cache.put(key, set);
+ }
+ set.add(value);
+ }
+ }
+
+ public void putAll(final K key, final Collection<V> values) {
+ synchronized (locks.getLock(key)) {
+ List<V> set = cache.get(key);
+ if (set == null) {
+ set = Lists.newArrayListWithExpectedSize(initialCapacity);
+ cache.put(key, set);
+ }
+ set.addAll(values);
+ }
+ }
+
+ public List<V> remove(final K key) {
+ synchronized (locks.getLock(key)) {
+ return cache.remove(key);
+ }
+ }
+
+
+ public void remove(final K key, final V value) {
+ List<V> values = cache.get(key);
+ synchronized (locks.getLock(key)) {
+ values.remove(value);
+ }
+ }
+
+
+ public Set<K> getKeySet() {
+ return cache.keySet();
+ }
+
+ public int size() {
+ return cache.size();
+ }
+
+ public boolean containsKey(K key) {
+ return cache.containsKey(key);
+ }
+
+ public List<V> get(K key) {
+ return cache.get(key);
+ }
+
+
+ public class LockMap<K extends Comparable> {
+ private final ConcurrentMap<K, Object> locks;
+
+ public LockMap() {
+ this(16, 64);
+ }
+
+ public LockMap(final int concurrencyLevel) {
+ this(concurrencyLevel, 64);
+ }
+
+ public LockMap(final int concurrencyLevel, final int initialCapacity) {
+ locks = new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(initialCapacity).weakValues().makeMap();
+ }
+
+ public Object getLock(final K key) {
+ final Object object = new Object();
+ Object lock = locks.putIfAbsent(key, object);
+ return lock == null ? object : lock;
+ }
+
+ }
+
+
+ public String toString() {
+ return cache.toString();
+ }
+
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java b/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java
new file mode 100644
index 0000000..85c7e3e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/JsonUtils.java
@@ -0,0 +1,93 @@
+package de.ids_mannheim.korap.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 28/01/2014
+ */
+public class JsonUtils {
+ private static ObjectMapper mapper = new ObjectMapper();
+
+ private JsonUtils() {
+ }
+
+ public static String toJSON(Object values) {
+ try {
+ return mapper.writeValueAsString(values);
+ }catch (JsonProcessingException e) {
+ return "";
+ }
+ }
+
+ public static JsonNode readTree(String s) {
+ try {
+ return mapper.readTree(s);
+ }catch (IOException e) {
+ return null;
+ }
+ }
+
+ public static ObjectNode createObjectNode() {
+ return mapper.createObjectNode();
+ }
+
+ public static ArrayNode createArrayNode() {
+ return mapper.createArrayNode();
+ }
+
+ public static JsonNode valueToTree(Object value) {
+ return mapper.valueToTree(value);
+ }
+
+ public static <T> T read(String json, Class<T> cl) throws IOException {
+ return mapper.readValue(json, cl);
+ }
+
+ public static <T> T readFile(String path, Class<T> clazz)
+ throws IOException {
+ return mapper.readValue(new File(path), clazz);
+ }
+
+ public static void writeFile(String path, String content) throws IOException {
+ mapper.writeValue(new File(path), content);
+ }
+
+ public static <T> T readSimple(String json, Class<T> cl) {
+ try {
+ return mapper.readValue(json, cl);
+ }catch (IOException e) {
+ return null;
+ }
+ }
+
+ public static List<Map<String, Object>> convertToList(String json)
+ throws JsonProcessingException {
+ List d = new ArrayList();
+ JsonNode node = JsonUtils.readTree(json);
+ if (node.isArray()) {
+ Iterator<JsonNode> nodes = node.iterator();
+ while (nodes.hasNext()) {
+ Map<String, Object> map = mapper
+ .treeToValue(nodes.next(), Map.class);
+ d.add(map);
+ }
+ }else if (node.isObject()) {
+ Map<String, Object> map = mapper.treeToValue(node, Map.class);
+ d.add(map);
+ }
+ return d;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/KorAPLogger.java b/src/main/java/de/ids_mannheim/korap/utils/KorAPLogger.java
new file mode 100644
index 0000000..5fc876f
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/KorAPLogger.java
@@ -0,0 +1,373 @@
+package de.ids_mannheim.korap.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Marker;
+
+/**
+ * @author hanl
+ * @date 28/03/2014
+ */
+
+public class KorAPLogger implements Logger {
+ // debugging flag, info, warn, error will always be logged though!
+ public static boolean DEBUG = false;
+
+ public static final String ERROR_LOG = "errorLog";
+ public static final String SECURITY_LOG = "securityLog";
+
+ //fixme:
+ public static final KorAPLogger ERROR_LOGGER = KorAPLogger
+ .initiate(ERROR_LOG);
+ public static final KorAPLogger QUERY_LOGGER = KorAPLogger.initiate("ql");
+
+ @Deprecated
+ public static final KorAPLogger SECURITY_LOGGER = KorAPLogger
+ .initiate("security");
+ private Logger log;
+
+ public static KorAPLogger initiate(Class cl) {
+ KorAPLogger l = new KorAPLogger();
+ l.log = LoggerFactory.getLogger(cl);
+ return l;
+ }
+
+ public static KorAPLogger initiate(String name) {
+ KorAPLogger l = new KorAPLogger();
+ l.log = LoggerFactory.getLogger(name);
+ return l;
+ }
+
+ private KorAPLogger() {
+ }
+
+ @Override
+ public String getName() {
+ return log.getName();
+ }
+
+ @Override
+ public boolean isTraceEnabled() {
+ return log.isTraceEnabled();
+ }
+
+ @Override
+ public void trace(String s) {
+ if (DEBUG)
+ this.log.trace(s);
+
+ }
+
+ @Override
+ public void trace(String s, Object o) {
+ if (DEBUG)
+ this.log.trace(s, o);
+ }
+
+ @Override
+ public void trace(String s, Object o, Object o2) {
+ if (DEBUG)
+ this.log.trace(s, o, o2);
+ }
+
+ @Override
+ public void trace(String s, Object... objects) {
+ if (DEBUG)
+ this.log.trace(s, objects);
+ }
+
+ @Override
+ public void trace(String s, Throwable throwable) {
+ if (DEBUG)
+ this.log.trace(s, throwable);
+ }
+
+ @Override
+ public boolean isTraceEnabled(Marker marker) {
+ if (DEBUG)
+ return true;
+ return false;
+ }
+
+ @Override
+ public void trace(Marker marker, String s) {
+ if (DEBUG)
+ this.log.trace(marker, s);
+ }
+
+ @Override
+ public void trace(Marker marker, String s, Object o) {
+ if (DEBUG)
+ this.log.trace(marker, s, o);
+ }
+
+ @Override
+ public void trace(Marker marker, String s, Object o, Object o2) {
+ if (DEBUG)
+ this.log.trace(marker, s, o, o2);
+ }
+
+ @Override
+ public void trace(Marker marker, String s, Object... objects) {
+ if (DEBUG)
+ this.log.trace(marker, s, objects);
+ }
+
+ @Override
+ public void trace(Marker marker, String s, Throwable throwable) {
+ if (DEBUG)
+ this.log.trace(marker, s, throwable);
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ if (DEBUG)
+ return true;
+ return false;
+ }
+
+ @Override
+ public void debug(String s) {
+ if (DEBUG)
+ this.log.debug(s);
+ }
+
+ @Override
+ public void debug(String s, Object o) {
+ if (DEBUG)
+ this.log.debug(s, o);
+ }
+
+ @Override
+ public void debug(String s, Object o, Object o2) {
+ if (DEBUG)
+ this.log.debug(s, o, o2);
+ }
+
+ @Override
+ public void debug(String s, Object... objects) {
+ if (DEBUG)
+ this.log.debug(s);
+ }
+
+ @Override
+ public void debug(String s, Throwable throwable) {
+ if (DEBUG)
+ this.log.debug(s, throwable);
+ }
+
+ @Override
+ public boolean isDebugEnabled(Marker marker) {
+ return this.log.isDebugEnabled(marker);
+ }
+
+ @Override
+ public void debug(Marker marker, String s) {
+ if (DEBUG)
+ this.log.debug(marker, s);
+ }
+
+ @Override
+ public void debug(Marker marker, String s, Object o) {
+ if (DEBUG)
+ this.log.debug(marker, s, o);
+ }
+
+ @Override
+ public void debug(Marker marker, String s, Object o, Object o2) {
+ if (DEBUG)
+ this.log.debug(marker, s, o, o2);
+ }
+
+ @Override
+ public void debug(Marker marker, String s, Object... objects) {
+ if (DEBUG)
+ this.log.debug(marker, s, objects);
+ }
+
+ @Override
+ public void debug(Marker marker, String s, Throwable throwable) {
+ if (DEBUG)
+ this.log.debug(marker, s, throwable);
+ }
+
+ @Override
+ public boolean isInfoEnabled() {
+ return this.log.isInfoEnabled();
+ }
+
+ @Override
+ public void info(String s) {
+ this.log.info(s);
+ }
+
+ @Override
+ public void info(String s, Object o) {
+ this.log.info(s, o);
+ }
+
+ @Override
+ public void info(String s, Object o, Object o2) {
+ this.log.info(s, o, o2);
+ }
+
+ @Override
+ public void info(String s, Object... objects) {
+ this.log.info(s, objects);
+ }
+
+ @Override
+ public void info(String s, Throwable throwable) {
+ this.log.info(s, throwable);
+ }
+
+ @Override
+ public boolean isInfoEnabled(Marker marker) {
+ return this.log.isInfoEnabled(marker);
+ }
+
+ @Override
+ public void info(Marker marker, String s) {
+ this.log.info(marker, s);
+ }
+
+ @Override
+ public void info(Marker marker, String s, Object o) {
+ this.log.info(marker, s, o);
+ }
+
+ @Override
+ public void info(Marker marker, String s, Object o, Object o2) {
+ this.log.info(marker, s, o, o2);
+ }
+
+ @Override
+ public void info(Marker marker, String s, Object... objects) {
+ this.log.info(marker, s, objects);
+ }
+
+ @Override
+ public void info(Marker marker, String s, Throwable throwable) {
+ this.log.info(marker, s, throwable);
+ }
+
+ @Override
+ public boolean isWarnEnabled() {
+ return this.log.isWarnEnabled();
+ }
+
+ @Override
+ public void warn(String s) {
+ this.log.warn(s);
+ }
+
+ @Override
+ public void warn(String s, Object o) {
+ this.log.warn(s, o);
+ }
+
+ @Override
+ public void warn(String s, Object... objects) {
+ this.log.warn(s, objects);
+ }
+
+ @Override
+ public void warn(String s, Object o, Object o2) {
+ this.log.warn(s, o, o2);
+ }
+
+ @Override
+ public void warn(String s, Throwable throwable) {
+ this.log.warn(s, throwable);
+ }
+
+ @Override
+ public boolean isWarnEnabled(Marker marker) {
+ return this.log.isTraceEnabled(marker);
+ }
+
+ @Override
+ public void warn(Marker marker, String s) {
+ this.log.warn(marker, s);
+ }
+
+ @Override
+ public void warn(Marker marker, String s, Object o) {
+ this.log.warn(marker, s, o);
+ }
+
+ @Override
+ public void warn(Marker marker, String s, Object o, Object o2) {
+ this.log.warn(marker, s, o, o2);
+ }
+
+ @Override
+ public void warn(Marker marker, String s, Object... objects) {
+ this.log.warn(marker, s, objects);
+ }
+
+ @Override
+ public void warn(Marker marker, String s, Throwable throwable) {
+ this.log.warn(marker, s, throwable);
+ }
+
+ @Override
+ public boolean isErrorEnabled() {
+ return this.log.isErrorEnabled();
+ }
+
+ @Override
+ public void error(String s) {
+ this.log.error(s);
+ }
+
+ @Override
+ public void error(String s, Object o) {
+ this.log.error(s, o);
+ }
+
+ @Override
+ public void error(String s, Object o, Object o2) {
+ this.log.error(s, o, o2);
+ }
+
+ @Override
+ public void error(String s, Object... objects) {
+ this.log.error(s, objects);
+ }
+
+ @Override
+ public void error(String s, Throwable throwable) {
+ this.log.error(s, throwable);
+ }
+
+ @Override
+ public boolean isErrorEnabled(Marker marker) {
+ return this.log.isErrorEnabled(marker);
+ }
+
+ @Override
+ public void error(Marker marker, String s) {
+ this.log.error(marker, s);
+ }
+
+ @Override
+ public void error(Marker marker, String s, Object o) {
+ this.log.error(marker, s, o);
+ }
+
+ @Override
+ public void error(Marker marker, String s, Object o, Object o2) {
+ this.log.error(marker, s, o, o2);
+ }
+
+ @Override
+ public void error(Marker marker, String s, Object... objects) {
+ this.log.error(marker, s, objects);
+ }
+
+ @Override
+ public void error(Marker marker, String s, Throwable throwable) {
+ this.log.error(marker, s, throwable);
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/PrefixTreeMap.java b/src/main/java/de/ids_mannheim/korap/utils/PrefixTreeMap.java
new file mode 100644
index 0000000..493a574
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/PrefixTreeMap.java
@@ -0,0 +1,46 @@
+package de.ids_mannheim.korap.utils;
+
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * @author hanl
+ * @date 01/07/2014
+ */
+public class PrefixTreeMap<V> extends TreeMap<String, V> {
+
+
+ public SortedMap<String, V> getPrefixSubMap(String prefix) {
+ if (prefix.length() > 0) {
+ SortedMap d = this.subMap(prefix, getEnd(prefix));
+ if (d.isEmpty())
+ return null;
+ return d;
+ }
+ return null;
+ }
+
+ private String getEnd(String prefix) {
+ char nextLetter = (char) (prefix.charAt(prefix.length() - 1) + 1);
+ return prefix.substring(0, prefix.length() - 1) + nextLetter;
+
+ }
+
+ public V getFirstValue(String prefix) {
+ if (prefix.length() > 0) {
+ String first = this.subMap(prefix, getEnd(prefix)).firstKey();
+ return this.get(first);
+ }
+ return null;
+ }
+
+ public V getLastValue(String prefix) {
+ if (prefix.length() > 0) {
+ String last = this.subMap(prefix, getEnd(prefix)).lastKey();
+ return this.get(last);
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java b/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java
new file mode 100644
index 0000000..a7120aa
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java
@@ -0,0 +1,191 @@
+package de.ids_mannheim.korap.utils;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.slf4j.Logger;
+
+import java.util.*;
+
+public class StringUtils {
+ private final static Logger jlog = KorAPLogger.initiate(StringUtils.class);
+
+ private static final String SLASH = "/";
+ private static final String SEP = ";";
+
+ public static Collection<UUID> stringToUUIDList(String s) {
+ String[] array = s.split(SEP);
+ List<UUID> list = new LinkedList<>();
+ for (String att : array) {
+ list.add(UUID.fromString(att));
+ }
+ return list;
+ }
+
+ public static List<String> toList(String values) {
+ List<String> list = new ArrayList<>();
+ StringTokenizer tokenizer = new StringTokenizer(values, SEP);
+ while (tokenizer.hasMoreTokens())
+ list.add(tokenizer.nextToken());
+ return list;
+ }
+
+ public static Set<String> toSet(String values, String sep) {
+ Set<String> set = new HashSet<>();
+ StringTokenizer tokenizer = new StringTokenizer(values, sep);
+ while (tokenizer.hasMoreTokens())
+ set.add(tokenizer.nextToken());
+ return set;
+ }
+
+ public static Set<String> toSet(String values) {
+ return toSet(values, SEP);
+ }
+
+ public static String toString(Collection<String> values) {
+ return StringUtils.toString(values, SEP);
+ }
+
+ public static String toString(Collection<String> values, String sep) {
+ StringBuffer b = new StringBuffer();
+ for (String s : values)
+ b.append(s).append(sep);
+
+ if (b.length() > 0)
+ b.deleteCharAt(b.length() - 1);
+ return b.toString();
+ }
+
+ public static String orderedToString(Collection<String> hash) {
+ Set<String> orderedSet = new TreeSet<>();
+ orderedSet.addAll(hash);
+ if (orderedSet.isEmpty()) {
+ return "";
+ }else {
+ StringBuilder builder = new StringBuilder();
+ for (String s : orderedSet) {
+ builder.append(s);
+ builder.append(SEP);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+ }
+
+ public static String UUIDsetToString(Collection<UUID> hash) {
+ Set<UUID> orderedSet = new TreeSet<>();
+ orderedSet.addAll(hash);
+ if (orderedSet.isEmpty()) {
+ return "";
+ }else {
+ StringBuilder builder = new StringBuilder();
+ for (UUID s : orderedSet) {
+ builder.append(s);
+ builder.append(SEP);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+ }
+
+ public static String buildSQLRegex(String path) {
+ StringBuilder b = new StringBuilder();
+ String[] match = path.split("/");
+ b.append(match[0]);
+ b.append("(" + "/" + match[1] + ")");
+ b.append("*$");
+ return b.toString();
+ }
+
+ public static Collection<String> joinStringSet(Collection<String> source,
+ String other) {
+ Set<String> set = new HashSet<>(source);
+ set.add(other);
+ return set;
+ }
+
+ public static Collection<UUID> joinUUIDSet(Collection<UUID> source,
+ UUID other) {
+ Set<UUID> set = new HashSet<>(source);
+ set.add(other);
+ return set;
+ }
+
+ public static String joinResources(String first, String second) {
+ String res;
+ if (first != null && !first.isEmpty())
+ res = first + SLASH + second;
+ else
+ res = second;
+ return res.replaceAll("\\s", "");
+ }
+
+ public static String[] splitAnnotations(String joined) {
+ String[] spl = joined.split(SLASH);
+ if (spl.length == 2)
+ return spl;
+ else
+ return null;
+ }
+
+ public static String stripTokenType(String token) {
+ int idx = token.lastIndexOf(" ");
+ if (idx == -1)
+ return token;
+ return token.substring(idx).replaceAll("\\s", "");
+ }
+
+ public static String getTokenType(String token) {
+ return token.substring(0, token.lastIndexOf(" ")).replaceAll("\\s", "")
+ .toLowerCase();
+ }
+
+ public static boolean isInteger(String value) {
+ try {
+ Integer.valueOf(value);
+ return true;
+ }catch (IllegalArgumentException e) {
+ // do nothing!
+ return false;
+ }
+ }
+
+ public static String normalize(String value) {
+ return value.trim().toLowerCase();
+ }
+
+ public static String normalizeHTML(String value) {
+ return StringEscapeUtils.escapeHtml4(value);
+ }
+
+ public static String decodeHTML(String value) {
+ return StringEscapeUtils.unescapeHtml4(value);
+ }
+
+ /**
+ * constructs a lucene query from query string and corpus parameters as set
+ *
+ * @param query
+ * @param corpusIDs
+ * @return
+ */
+ public static String queryBuilder(String query,
+ Collection<String> corpusIDs) {
+ String completeQuery; // holds original query and corpus
+ // selection
+ /**
+ * find documents with metadataquery TODO: does not intercept with
+ * parameters foundries and corpusIDs
+ */
+
+ /* add corpus ids to corpus query */
+ StringBuilder corpusQuery = new StringBuilder("corpus:/(");
+ for (String corpusId : corpusIDs) {
+ corpusQuery.append(corpusId + "|");
+ }
+ corpusQuery.deleteCharAt(corpusQuery.length() - 1);
+ corpusQuery.append(")/");
+ completeQuery = "(" + query + ") AND " + corpusQuery.toString();
+ jlog.debug("Searching documents matching '" + completeQuery + "'.");
+ return completeQuery;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java b/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java
new file mode 100644
index 0000000..b4f1d30
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java
@@ -0,0 +1,207 @@
+package de.ids_mannheim.korap.utils;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.slf4j.Logger;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * @author hanl
+ * <p/>
+ * calculates current, expiration and inactive time for security
+ * purposes.
+ * @return
+ */
+public class TimeUtils {
+
+ private static DecimalFormat df = new DecimalFormat("#.#############");
+ private static final DateTimeZone dtz = DateTimeZone.forID("Europe/Berlin");
+ private static Logger jlog = KorAPLogger.initiate(TimeUtils.class);
+
+ public static int convertTimeToSeconds(String expirationVal) {
+ expirationVal = expirationVal.trim();
+ int finIndex = expirationVal.length() - 1;
+ char entity = expirationVal.charAt(finIndex);
+ int returnSec = Integer.valueOf(expirationVal.substring(0, finIndex));
+ jlog.debug("setting time value to {} with time in {}", returnSec,
+ entity);
+ switch (entity) {
+ case 'D':
+ return returnSec * 60 * 60 * 24;
+ case 'H':
+ return returnSec * 60 * 60;
+ case 'M':
+ return returnSec * 60;
+ case 'S':
+ return returnSec;
+ default:
+ jlog.debug(
+ "no time unit specified. Trying to read from default (minutes)");
+ return Integer.valueOf(expirationVal) * 60;
+ }
+
+ }
+
+ //todo: time zone is wrong!
+ public static DateTime getNow() {
+ return DateTime.now().withZone(dtz);
+ }
+
+ //returns difference in milliseconds
+ public static long calcDiff(DateTime now, DateTime future) {
+ long diff = (future.withZone(dtz).getMillis() - now.withZone(dtz)
+ .getMillis());
+ return diff;
+ }
+
+ public static boolean isPassed(long time) {
+ return getNow().isAfter(time);
+
+ }
+
+ public static boolean isPassed(DateTime time) {
+ return isPassed(time.getMillis());
+ }
+
+ // returns difference in seconds in floating number
+ public static float floating(DateTime past, DateTime now) {
+ long diff = (now.withZone(dtz).getMillis() - past.withZone(dtz)
+ .getMillis());
+ double fin = diff / 1000.0;
+ BigDecimal bd = new BigDecimal(fin).setScale(8, RoundingMode.HALF_EVEN);
+ return bd.floatValue();
+ }
+
+ public static DateTime fromCosmas(String date) {
+ int idx = date.length();
+ try {
+ Integer sec = Integer.valueOf(
+ date.substring((idx = idx - 2), date.length()).trim());
+ Integer min = Integer
+ .valueOf(date.substring((idx = idx - 2), idx + 2).trim());
+ Integer hours = Integer
+ .valueOf(date.substring((idx = idx - 2), idx + 2).trim());
+ Integer day = Integer
+ .valueOf(date.substring((idx = idx - 2), idx + 2).trim());
+ Integer month = Integer
+ .valueOf(date.substring((idx = idx - 2), idx + 2).trim());
+ Integer year = Integer
+ .valueOf(date.substring((idx = idx - 4), idx + 4).trim());
+ return new DateTime(year, month, day, hours, min, sec);
+ }catch (NumberFormatException e) {
+ return getNow().toDateTime();
+ }
+ }
+
+ public static String formatDiff(DateTime now, DateTime after) {
+ return df.format(calcDiff(now, after));
+ }
+
+ /**
+ * converts time to the ISO8601 standard.
+ *
+ * @param time
+ * @return
+ */
+ public static String format(DateTime time) {
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+ return fmt.print(time);
+ }
+
+ public static String format(long time) {
+ DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
+ return fmt.print(time);
+ }
+
+ /**
+ * calculate expiration time
+ *
+ * @param creation
+ * @param plus time in seconds
+ * @return
+ */
+ public static DateTime plusSeconds(long creation, int plus) {
+ return new DateTime(creation).withZone(dtz).plusSeconds(plus);
+ }
+
+ public static DateTime getExpiration(long now, int exp) {
+ return new DateTime(now).withZone(dtz).plusSeconds(exp);
+ }
+
+ /**
+ * @param plus
+ * @return
+ */
+ public static DateTime plusSeconds(int plus) {
+ return getNow().withZone(dtz).plusSeconds(plus);
+ }
+
+ public static DateTime plusHours(int hours) {
+ return getNow().withZone(dtz).plusHours(hours);
+ }
+
+ public static DateTime plusMinutes(int minutes) {
+ return getNow().withZone(dtz).plusMinutes(minutes);
+ }
+
+ /**
+ * create time stamp from long value
+ *
+ * @param t time
+ * @return Timestamp
+ */
+ public static LocalDate getTimeStamp(long t) {
+ return new DateTime(t).withZone(dtz).toLocalDate();
+ }
+
+ public static DateTime getDate(int day, int month, int year) {
+ DateTime date = new DateTime().withZone(dtz);
+ return date.withDate(year, month, day);
+ }
+
+ public static String toString(long val, Locale locale) {
+ if (locale == Locale.GERMAN)
+ return new DateTime(val)
+ .toString("dd. MMMM yyyy, HH:mm", Locale.GERMAN);
+ else
+ return new DateTime(val)
+ .toString("MM-dd-yyyy, hh:mm", Locale.ENGLISH);
+
+ }
+
+ public static String dateToString(long val, int i) {
+ switch (i) {
+ case 1:
+ return new DateTime(val).toString("yyyy-MM");
+ case 2:
+ return new DateTime(val).toString("yyyy-MM-dd");
+ default:
+ return new DateTime(val).toString("yyyy");
+ }
+ }
+
+ private static final List<DateTime> times = new ArrayList<>();
+
+ @Deprecated
+ public static float benchmark(boolean getFinal) {
+ float value = 0;
+ times.add(getNow());
+ if (getFinal && times.size() > 1) {
+ value = floating(times.get(0), times.get(times.size() - 1));
+ times.clear();
+ }else if (times.size() > 1)
+ value = floating(times.get(times.size() - 2),
+ times.get(times.size() - 1));
+ return value;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/.DS_Store b/src/main/java/de/ids_mannheim/korap/web/.DS_Store
new file mode 100644
index 0000000..32f11f9
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/.DS_Store
Binary files differ
diff --git a/src/main/java/de/ids_mannheim/korap/web/ClientsHandler.java b/src/main/java/de/ids_mannheim/korap/web/ClientsHandler.java
new file mode 100644
index 0000000..8b846eb
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/ClientsHandler.java
@@ -0,0 +1,52 @@
+package de.ids_mannheim.korap.web;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.api.client.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+
+import javax.ws.rs.core.MultivaluedMap;
+import java.net.URI;
+
+/**
+ * @author hanl
+ * @date 10/12/2013
+ */
+// use for Piotr Ps. rest api connection
+public class ClientsHandler {
+
+ private WebResource service;
+
+ public ClientsHandler(URI address) {
+ ClientConfig config = new DefaultClientConfig();
+ Client client = Client.create(config);
+ this.service = client.resource(address);
+ }
+
+ public String getResponse(String path, String key, Object value) throws KorAPException {
+ MultivaluedMap map = new MultivaluedMapImpl();
+ map.add(key, value);
+ try {
+ return service.path(path).queryParams(map).get(String.class);
+ } catch (UniformInterfaceException e) {
+ throw new KorAPException(StatusCodes.REQUEST_INVALID);
+ }
+ }
+
+ public String getResponse(MultivaluedMap map, String... paths) throws KorAPException {
+ try {
+ WebResource resource = service;
+ for (String p : paths)
+ resource = resource.path(p);
+ resource = resource.queryParams(map);
+ return resource.get(String.class);
+ } catch (UniformInterfaceException e) {
+ throw new KorAPException(StatusCodes.REQUEST_INVALID);
+ }
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/Kustvakt.java b/src/main/java/de/ids_mannheim/korap/web/Kustvakt.java
new file mode 100644
index 0000000..f9349e6
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/Kustvakt.java
@@ -0,0 +1,54 @@
+package de.ids_mannheim.korap.web;
+
+import com.sun.grizzly.http.embed.GrizzlyWebServer;
+import com.sun.grizzly.http.servlet.ServletAdapter;
+import com.sun.jersey.spi.container.servlet.ServletContainer;
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.utils.KorAPLogger;
+
+import java.io.IOException;
+
+/**
+ * @author hanl
+ * @date 01/06/2015
+ */
+public class Kustvakt {
+
+ private static Integer PORT = -1;
+
+ public static void main(String[] args) throws Exception {
+ attributes(args);
+ BeanConfiguration.loadContext();
+ grizzlyServer(PORT);
+ }
+
+ public static void grizzlyServer(int port) throws IOException {
+ if (port == -1)
+ port = BeanConfiguration.getConfiguration().getPort();
+ System.out.println("Starting grizzly on port " + port + " ...");
+ GrizzlyWebServer gws = new GrizzlyWebServer(port);
+ ServletAdapter jerseyAdapter = new ServletAdapter();
+ jerseyAdapter
+ .addInitParameter("com.sun.jersey.config.property.packages",
+ "de.ids_mannheim.korap.web.service");
+ jerseyAdapter.setContextPath("/api");
+ jerseyAdapter.setServletInstance(new ServletContainer());
+
+ gws.addGrizzlyAdapter(jerseyAdapter, new String[] { "/api" });
+ gws.start();
+ }
+
+ private static void attributes(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ switch ((args[i])) {
+ case "--debug":
+ KorAPLogger.DEBUG = true;
+ break;
+ case "--port":
+ PORT = Integer.valueOf(args[i + 1]);
+ break;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/SearchLucene.java b/src/main/java/de/ids_mannheim/korap/web/SearchLucene.java
new file mode 100644
index 0000000..be19540
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/SearchLucene.java
@@ -0,0 +1,313 @@
+// Connector to the Lucene Backend
+package de.ids_mannheim.korap.web;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.Krill;
+import de.ids_mannheim.korap.KrillCollection;
+import de.ids_mannheim.korap.KrillIndex;
+import de.ids_mannheim.korap.response.Match;
+import de.ids_mannheim.korap.response.Result;
+import de.ids_mannheim.korap.util.QueryException;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.KorAPLogger;
+import org.apache.lucene.store.MMapDirectory;
+import org.slf4j.Logger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * The SearchLucene class allows for searching in the Lucene backend
+ * by JSON-LD serialized queries.
+ * It supports span queries, virtual collections, and paging.
+ *
+ * @author Nils Diewald
+ */
+public class SearchLucene {
+ private final static Logger qlog = KorAPLogger.initiate("queryLogger");
+ private final static Logger log = KorAPLogger.initiate(SearchLucene.class);
+ // Temporary
+ String indexDir = "/data/prep_corpus/index/";
+ String i = "/Users/hanl/Projects/prep_corpus";
+ String klinux10 = "/vol/work/hanl/indices";
+
+ private KrillIndex index;
+
+ /**
+ * Constructor
+ */
+ // todo: use korap.config to get index location
+ public SearchLucene(String path) {
+ try {
+ File f = new File(path);
+ log.info("Loading index from " + path);
+ if (!f.exists()) {
+ KorAPLogger.ERROR_LOGGER.error("Index not found!");
+ System.exit(-1);
+ }
+ this.index = new KrillIndex(new MMapDirectory(new File(path)));
+ }catch (IOException e) {
+ KorAPLogger.ERROR_LOGGER
+ .error("Unable to load index: {}", e.getMessage());
+ }
+ }
+
+ /**
+ * Search in the Lucene index.
+ *
+ * @param json JSON-LD string with search and potential meta filters.
+ */
+ public String search(String json) {
+ qlog.trace(json);
+ if (this.index != null)
+ return new Krill(json).setIndex(this.index).toJsonString();
+
+ Result kr = new Result();
+ // kr.setError("Index not found");
+ return kr.toJsonString();
+ }
+
+ ;
+
+ /**
+ * Search in the Lucene index and return matches as token lists.
+ *
+ * @param json JSON-LD string with search and potential meta filters.
+ */
+ public String searchTokenList(String json) {
+ qlog.trace(json);
+ if (this.index != null)
+ return new Krill(json).setIndex(this.index).toJsonString();
+
+ Result kr = new Result();
+ // kr.setError("Index not found");
+ return kr.toJsonString();
+ }
+
+ ;
+
+ /**
+ * Get info on a match - by means of a richly annotated html snippet.
+ *
+ * @param id match id
+ */
+ public String getMatch(String id) {
+
+ if (this.index != null) {
+ try {
+ return this.index.getMatch(id).toJsonString();
+ }catch (QueryException qe) {
+ Match km = new Match();
+ km.setError(qe.getMessage());
+ return km.toJsonString();
+ }
+ }
+
+ Match km = new Match();
+ km.setError("Index not found");
+ return km.toJsonString();
+ }
+
+ public String getMatch(String id, List<String> foundries,
+ List<String> layers, boolean includeSpans,
+ boolean includeHighlights, boolean sentenceExpansion) {
+ if (this.index != null) {
+ try {
+
+ return this.index
+ .getMatchInfo(id, "tokens", true, foundries, layers,
+ includeSpans, includeHighlights,
+ sentenceExpansion).toJsonString();
+ }catch (QueryException qe) {
+ Match km = new Match();
+ km.setError(qe.getMessage());
+ return km.toJsonString();
+ }
+ }
+
+ Match km = new Match();
+ km.setError("Index not found");
+ return km.toJsonString();
+
+ }
+
+ /**
+ * Get info on a match - by means of a richly annotated html snippet.
+ *
+ * @param id match id
+ * @param foundry the foundry of interest - may be null
+ * @param layer the layer of interest - may be null
+ * @param includeSpans Should spans be included (or only token infos)?
+ * @param includeHighlights Should highlight markup be included?
+ */
+ public String getMatch(String id, String foundry, String layer,
+ boolean includeSpans, boolean includeHighlights,
+ boolean sentenceExpansion) {
+
+ if (this.index != null) {
+ try {
+
+ /*
+ For multiple foundries/layers use
+ String idString,
+ "tokens",
+ true,
+ ArrayList<String> foundry,
+ ArrayList<String> layer,
+ boolean includeSpans,
+ boolean includeHighlights,
+ boolean extendToSentence
+ */
+
+ return this.index.getMatchInfo(id, "tokens", foundry, layer,
+ includeSpans, includeHighlights, sentenceExpansion)
+ .toJsonString();
+ }catch (QueryException qe) {
+ Match km = new Match();
+ km.setError(qe.getMessage());
+ return km.toJsonString();
+ }
+ }
+
+ Match km = new Match();
+ km.setError("Index not found");
+ return km.toJsonString();
+ }
+
+ /**
+ * Get statistics on (virtual) collections.
+ *
+ * @param json JSON-LD string with potential meta filters.
+ */
+ public String getStatisticsLegacy(JsonNode json) throws QueryException {
+ qlog.trace(JsonUtils.toJSON(json));
+ System.out.println("THE NODE BEFORE GETTING STATISTICS " + json);
+
+ if (this.index == null) {
+ return "{\"documents\" : -1, error\" : \"No index given\" }";
+ }
+
+ // Create Virtula VCollection from json search
+ KrillCollection kc = new KrillCollection();
+ kc.fromJsonLegacy(json);
+
+ // Set index
+ kc.setIndex(this.index);
+
+ long docs = 0,
+ tokens = 0,
+ sentences = 0,
+ paragraphs = 0;
+
+ // Get numbers from index (currently slow)
+ try {
+ docs = kc.numberOf("documents");
+ tokens = kc.numberOf("tokens");
+ sentences = kc.numberOf("sentences");
+ paragraphs = kc.numberOf("paragraphs");
+ }catch (IOException e) {
+ e.printStackTrace();
+ }
+
+
+ /*
+ KorAPLogger.ERROR_LOGGER.error("Unable to retrieve statistics: {}", e.getMessage());
+ */
+
+ // Build json response
+ StringBuilder sb = new StringBuilder("{");
+ sb.append("\"documents\":").append(docs).append(",\"tokens\":")
+ .append(tokens).append(",\"sentences\":").append(sentences)
+ .append(",\"paragraphs\":").append(paragraphs).append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Get statistics on (virtual) collections.
+ *
+ * @param json JSON-LD string with potential meta filters.
+ */
+ public String getStatistics(String json) {
+ qlog.trace(json);
+
+ if (this.index == null) {
+ return "{\"documents\" : -1, error\" : \"No index given\" }";
+ }
+
+ // Create Virtual collection from json search
+ KrillCollection kc = new KrillCollection(json);
+
+ // Set index
+ kc.setIndex(this.index);
+
+ long docs = 0,
+ tokens = 0,
+ sentences = 0,
+ paragraphs = 0;
+
+ // Get numbers from index (currently slow)
+ try {
+ docs = kc.numberOf("documents");
+ tokens = kc.numberOf("tokens");
+ sentences = kc.numberOf("sentences");
+ paragraphs = kc.numberOf("paragraphs");
+ }catch (IOException e) {
+ e.printStackTrace();
+ }
+
+
+ /*
+ KorAPLogger.ERROR_LOGGER.error("Unable to retrieve statistics: {}", e.getMessage());
+ */
+
+ // Build json response
+ StringBuilder sb = new StringBuilder("{");
+ sb.append("\"documents\":").append(docs).append(",\"tokens\":")
+ .append(tokens).append(",\"sentences\":").append(sentences)
+ .append(",\"paragraphs\":").append(paragraphs).append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Get set relations on field terms of (virtual) collections.
+ *
+ * @param json JSON-LD string with potential meta filters.
+ */
+ public String getTermRelation(String json, String field) {
+ qlog.trace(json);
+
+ if (this.index == null) {
+ return "{\"documents\" : -1, \"error\" : \"No index given\" }";
+ }
+
+ // Create Virtula VCollection from json search
+ KrillCollection kc = new KrillCollection(json);
+
+ // Set index
+ kc.setIndex(this.index);
+ long v = 0L;
+ try {
+ v = kc.numberOf("documents");
+ }catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ // Get term relations as a json string
+ return kc.getTermRelationJSON(field);
+ }catch (IOException e) {
+ KorAPLogger.ERROR_LOGGER
+ .error("Unable to retrieve term relations: {}",
+ e.getMessage());
+ return "{\"documents\" : -1, \"error\" : \"IO error\" }";
+ }
+ }
+
+ public String getMatchId(String type, String docid, String tofrom) {
+ return new StringBuilder().append("contains-").append(type).append("!")
+ .append(type).append("_").append(docid).append("-")
+ .append(tofrom).toString();
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/TRACE.java b/src/main/java/de/ids_mannheim/korap/web/TRACE.java
new file mode 100644
index 0000000..e33089d
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/TRACE.java
@@ -0,0 +1,17 @@
+package de.ids_mannheim.korap.web;
+
+import javax.ws.rs.HttpMethod;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author hanl
+ * @date 03/07/2014
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("TRACE")
+public @interface TRACE {
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/LightService.java b/src/main/java/de/ids_mannheim/korap/web/service/LightService.java
new file mode 100644
index 0000000..bd1be22
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/service/LightService.java
@@ -0,0 +1,346 @@
+package de.ids_mannheim.korap.web.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.graphdb.collo.ColloQuery;
+import de.ids_mannheim.korap.graphdb.collo.Dependency;
+import de.ids_mannheim.korap.query.serialize.IdWriter;
+import de.ids_mannheim.korap.query.serialize.MetaQueryBuilder;
+import de.ids_mannheim.korap.query.serialize.QuerySerializer;
+import de.ids_mannheim.korap.utils.CollectionQueryBuilder;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.KorAPLogger;
+import de.ids_mannheim.korap.utils.StringUtils;
+import de.ids_mannheim.korap.web.ClientsHandler;
+import de.ids_mannheim.korap.web.SearchLucene;
+import de.ids_mannheim.korap.web.TRACE;
+import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
+import org.slf4j.Logger;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author hanl
+ * @date 29/01/2014
+ */
+@Path("v0.1" + "/")
+@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+public class LightService {
+
+ private static Logger jlog = KorAPLogger.initiate(LightService.class);
+
+ private SearchLucene searchLucene;
+ private ClientsHandler graphDBhandler;
+
+ public LightService() {
+ this.searchLucene = new SearchLucene(
+ BeanConfiguration.getConfiguration().getIndexDir());
+ UriBuilder builder = UriBuilder.fromUri("http://10.0.10.13").port(9997);
+ this.graphDBhandler = new ClientsHandler(builder.build());
+ }
+
+ /**
+ * @param properties
+ * @param sfs
+ * @param limit
+ * @param query
+ * @param ql
+ * @param context
+ * @param foundry
+ * @param wPaths
+ * @return
+ */
+ //todo: add entry point where a json collection can be injected as well
+ @GET
+ @Path("colloc")
+ public Response getCollocationsAll(@QueryParam("props") String properties,
+ @QueryParam("sfskip") Integer sfs,
+ @QueryParam("sflimit") Integer limit, @QueryParam("q") String query,
+ @QueryParam("ql") String ql, @QueryParam("context") Integer context,
+ @QueryParam("foundry") String foundry,
+ @QueryParam("paths") Boolean wPaths) {
+ ColloQuery.ColloQueryBuilder builder;
+ String result;
+ try {
+ builder = new ColloQuery.ColloQueryBuilder();
+ QuerySerializer s = new QuerySerializer().setQuery(query, ql);
+ //todo: fix collectionbuilder
+ // s.setDeprCollection(builder);
+ IdWriter writer = new IdWriter(s.toJSON()).process();
+ List collprops = JsonUtils.convertToList(properties);
+
+ if (context != null)
+ builder.context(context).collocateProps(collprops);
+ if (limit != null)
+ builder.surfaceLimit(limit);
+ if (sfs != null)
+ builder.surfaceSkip(sfs);
+ if (foundry != null)
+ builder.foundry(foundry);
+ builder.nodeQueryJS(writer.toJSON())
+ .dep(new ArrayList<Dependency>()).withPaths(wPaths);
+
+ result = graphDBhandler
+ .getResponse("distCollo", "q", builder.build().toJSON());
+ }catch (KorAPException e) {
+ throw KustvaktResponseHandler.throwit(e);
+ }catch (JsonProcessingException e) {
+ throw KustvaktResponseHandler.throwit(StatusCodes.ILLEGAL_ARGUMENT);
+ }
+ return Response.ok(result).build();
+ }
+
+ @POST
+ @Path("colloc")
+ public Response getCollocatioBase(@QueryParam("q") String query) {
+ String result;
+ try {
+ result = graphDBhandler.getResponse("distCollo", "q", query);
+ }catch (KorAPException e) {
+ throw KustvaktResponseHandler.throwit(e);
+ }
+ return Response.ok(result).build();
+ }
+
+ public Response postMatchFavorite() {
+ return Response.ok().build();
+ }
+
+ @TRACE
+ @Path("search")
+ public Response buildQuery(@QueryParam("q") String q,
+ @QueryParam("ql") String ql, @QueryParam("v") String v,
+ @QueryParam("context") String context,
+ @QueryParam("cutoff") Boolean cutoff,
+ @QueryParam("count") Integer pageLength,
+ @QueryParam("offset") Integer pageIndex,
+ @QueryParam("page") Integer startPage,
+ @QueryParam("ref") String reference, @QueryParam("cq") String cq) {
+ QuerySerializer ss = new QuerySerializer().setQuery(q, ql, v);
+
+ MetaQueryBuilder meta = new MetaQueryBuilder();
+ if (pageIndex != null)
+ meta.addEntry("startIndex", pageIndex);
+ if (pageIndex == null && startPage != null)
+ meta.addEntry("startPage", startPage);
+ if (pageLength != null)
+ meta.addEntry("count", pageLength);
+ if (context != null)
+ meta.setSpanContext(context);
+ meta.addEntry("cutOff", cutoff);
+ ss.addMeta(meta);
+ //todo: test this
+ ss.setCollection(cq);
+ return Response.ok(ss.toJSON()).build();
+ }
+
+ @POST
+ @Path("search")
+ public Response queryRaw(@QueryParam("engine") String engine,
+ String jsonld) {
+ KustvaktConfiguration.BACKENDS eng = BeanConfiguration
+ .getConfiguration().chooseBackend(engine);
+
+ // todo: should be possible to add the meta part to the query serialization
+ jlog.info("Serialized search: {}", jsonld);
+
+ // todo: Security Parsing and rewrite
+ // fixme: to use the systemarchitecture pointcut thingis, searchlucene must be injected via
+ String result = searchLucene.search(jsonld);
+ KorAPLogger.QUERY_LOGGER.trace("The result set: {}", result);
+ return Response.ok(result).build();
+ }
+
+ @GET
+ @Path("search")
+ public Response searchbyNameAll(@Context SecurityContext securityContext,
+ @QueryParam("q") String q, @QueryParam("ql") String ql,
+ @QueryParam("v") String v, @QueryParam("context") String ctx,
+ @QueryParam("cutoff") Boolean cutoff,
+ @QueryParam("count") Integer pageLength,
+ @QueryParam("offset") Integer pageIndex,
+ @QueryParam("page") Integer pageInteger,
+ @QueryParam("cq") String cq, @QueryParam("engine") String engine) {
+ KustvaktConfiguration.BACKENDS eng = BeanConfiguration
+ .getConfiguration().chooseBackend(engine);
+
+ String result;
+ QuerySerializer serializer = new QuerySerializer().setQuery(q, ql, v);
+ MetaQueryBuilder meta = new MetaQueryBuilder();
+ meta.fillMeta(pageIndex, pageInteger, pageLength, ctx, cutoff);
+ // fixme: should only apply to CQL queries per default!
+ // meta.addEntry("itemsPerResource", 1);
+ serializer.addMeta(meta);
+
+ // policy rewrite!
+ String query = serializer.toJSON();
+ jlog.info("the serialized query {}", query);
+
+ if (eng.equals(KustvaktConfiguration.BACKENDS.NEO4J)) {
+ MultivaluedMap map = new MultivaluedMapImpl();
+ map.add("q", query);
+ map.add("count", String.valueOf(pageLength));
+ map.add("lctxs",
+ String.valueOf(meta.getSpanContext().getLeft_size()));
+ map.add("rctxs",
+ String.valueOf(meta.getSpanContext().getRight_size()));
+ try {
+ result = this.graphDBhandler.getResponse(map, "distKwic");
+ }catch (KorAPException e) {
+ throw KustvaktResponseHandler.throwit(e);
+ }
+ }else
+ result = searchLucene.search(query);
+ KorAPLogger.QUERY_LOGGER.trace("The result set: {}", result);
+ return Response.ok(result).build();
+ }
+
+ /**
+ * param context will be like this: context: "3-t,2-c"
+ * <p/>
+ * id does not have to be an integer. name is also possible, in which case a type reference is required
+ *
+ * @param query
+ * @param ql
+ * @param v
+ * @param ctx
+ * @param cutoff
+ * @param pageLength
+ * @param pageIndex
+ * @param pageInteger
+ * @param id
+ * @param type
+ * @param cq
+ * @param raw
+ * @param engine
+ * @return
+ */
+ //fixme: does not use policyrewrite!
+ @GET
+ @Path("/{type}/{id}/search")
+ public Response searchbyName(@QueryParam("q") String query,
+ @QueryParam("ql") String ql, @QueryParam("v") String v,
+ @QueryParam("context") String ctx,
+ @QueryParam("cutoff") Boolean cutoff,
+ @QueryParam("count") Integer pageLength,
+ @QueryParam("offset") Integer pageIndex,
+ @QueryParam("page") Integer pageInteger, @PathParam("id") String id,
+ @PathParam("type") String type, @QueryParam("cq") String cq,
+ @QueryParam("raw") Boolean raw,
+ @QueryParam("engine") String engine) {
+ // ref is a virtual collection id!
+ KustvaktConfiguration.BACKENDS eng = BeanConfiguration
+ .getConfiguration().chooseBackend(engine);
+ raw = raw == null ? false : raw;
+ MetaQueryBuilder meta = new MetaQueryBuilder();
+ if (!raw) {
+ QuerySerializer s = new QuerySerializer().setQuery(query, ql, v);
+ meta.fillMeta(pageIndex, pageInteger, pageLength, ctx, cutoff);
+ // should only apply to CQL queries
+ // meta.addEntry("itemsPerResource", 1);
+ s.addMeta(meta);
+ query = s.toJSON();
+ }
+ String result;
+ try {
+ if (eng.equals(KustvaktConfiguration.BACKENDS.NEO4J)) {
+ if (raw)
+ throw KustvaktResponseHandler
+ .throwit(StatusCodes.ILLEGAL_ARGUMENT,
+ "raw not supported!", null);
+ MultivaluedMap map = new MultivaluedMapImpl();
+ map.add("q", query);
+ map.add("count", String.valueOf(pageLength));
+ map.add("lctxs",
+ String.valueOf(meta.getSpanContext().getLeft_size()));
+ map.add("rctxs",
+ String.valueOf(meta.getSpanContext().getRight_size()));
+ result = this.graphDBhandler.getResponse(map, "distKwic");
+ }else
+ result = searchLucene.search(query);
+
+ }catch (Exception e) {
+ KorAPLogger.ERROR_LOGGER
+ .error("Exception for serialized query: " + query, e);
+ throw KustvaktResponseHandler.throwit(500, e.getMessage(), null);
+ }
+
+ KorAPLogger.QUERY_LOGGER.trace("The result set: {}", result);
+ return Response.ok(result).build();
+ }
+
+ //todo: switch to new serialization
+ @POST
+ @Path("stats")
+ public Response getStats(String json) {
+ CollectionQueryBuilder builder = new CollectionQueryBuilder();
+ builder.addResource(json);
+
+ String stats = searchLucene.getStatistics(builder.toCollections());
+ if (stats.contains("-1"))
+ throw KustvaktResponseHandler.throwit(StatusCodes.EMPTY_RESULTS);
+
+ return Response.ok(stats).build();
+ }
+
+ //fixme: only allowed for corpus?!
+ @GET
+ @Path("/corpus/{id}/{docid}/{rest}/matchInfo")
+ public Response getMatchInfo(@PathParam("id") String id,
+ @PathParam("docid") String docid, @PathParam("rest") String rest,
+ @QueryParam("foundry") Set<String> foundries,
+ @QueryParam("layer") Set<String> layers,
+ @QueryParam("spans") Boolean spans) {
+ spans = spans != null ? spans : false;
+ String matchid = searchLucene.getMatchId(id, docid, rest);
+
+ if (layers == null || layers.isEmpty())
+ layers = new HashSet<>();
+
+ boolean match_only = foundries == null || foundries.isEmpty();
+
+ String results;
+ // fixme: checks for policy matching
+ // fixme: currently disabled, due to mishab in foundry/layer spec
+ // fixme:
+ if (foundries != null && foundries.size() > 1000) {
+ Set<String> f_list = new HashSet<>();
+ Set<String> l_list = new HashSet<>();
+
+ for (String spl : new ArrayList<>(foundries)) {
+
+ String[] sep = StringUtils.splitAnnotations(spl);
+ if (spl != null) {
+ f_list.add(sep[0]);
+ l_list.add(sep[1]);
+ }
+ results = searchLucene
+ .getMatch(matchid, new ArrayList<>(f_list),
+ new ArrayList<>(l_list), spans, false, true);
+
+ }
+ }
+ try {
+ if (!match_only)
+ results = searchLucene
+ .getMatch(matchid, new ArrayList<>(foundries),
+ new ArrayList<>(layers), spans, false, true);
+ else
+ results = searchLucene.getMatch(matchid);
+ }catch (Exception e) {
+ KorAPLogger.ERROR_LOGGER.error("Exception encountered!", e);
+ throw KustvaktResponseHandler
+ .throwit(StatusCodes.ILLEGAL_ARGUMENT, e.getMessage(), "");
+ }
+ return Response.ok(results).build();
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/FormWrapper.java b/src/main/java/de/ids_mannheim/korap/web/utils/FormWrapper.java
new file mode 100644
index 0000000..b1dad85
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/FormWrapper.java
@@ -0,0 +1,35 @@
+package de.ids_mannheim.korap.web.utils;
+
+import javax.ws.rs.core.MultivaluedMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 18/05/2015
+ * Helper class to wrapp multivaluedmap into a hashmap. Depending on the strict parameter,
+ * list values are retained in the resulting wrapper map.
+ */
+public class FormWrapper extends HashMap<String, Object> {
+
+ public FormWrapper(MultivaluedMap form, boolean strict) {
+ super(toMap(form, strict));
+ }
+
+ public FormWrapper(MultivaluedMap form) {
+ super(toMap(form, true));
+ }
+
+ private static HashMap<String, Object> toMap(MultivaluedMap<String, Object> form,
+ boolean strict) {
+ HashMap<String, Object> map = new HashMap<>();
+ for (Map.Entry<String, List<Object>> e : form.entrySet()) {
+ if (e.getValue().size() == 1)
+ map.put(e.getKey(), e.getValue().get(0));
+ else if (!strict)
+ map.put(e.getKey(), e.getValue());
+ }
+ return map;
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/HTMLBuilder.java b/src/main/java/de/ids_mannheim/korap/web/utils/HTMLBuilder.java
new file mode 100644
index 0000000..f6da418
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/HTMLBuilder.java
@@ -0,0 +1,56 @@
+package de.ids_mannheim.korap.web.utils;
+
+/**
+ * @author hanl
+ * @date 12/04/2014
+ */
+public class HTMLBuilder {
+
+ private StringBuilder html;
+ private StringBuilder body;
+ private String bodyAttr;
+
+ public HTMLBuilder() {
+ html = new StringBuilder();
+ body = new StringBuilder();
+ bodyAttr = "";
+ html.append("<html>");
+ }
+
+
+ public void addHeader(String header, int h) {
+ html.append("<h" + h + ">");
+ html.append(header);
+ html.append("</h" + h + ">");
+ }
+
+ public void addToBody(String body) {
+ this.body.append(body);
+ }
+
+ public void addToBody(String body, String attributes) {
+ this.body.append(body);
+ bodyAttr = attributes;
+ }
+
+ public String build() {
+ if (bodyAttr.isEmpty())
+ html.append("<body>");
+ else {
+ html.append("<body ");
+ html.append(bodyAttr);
+ html.append(">");
+ }
+
+ html.append(body);
+ html.append("</body>");
+ html.append("</html>");
+ return html.toString();
+ }
+
+
+ @Override
+ public String toString() {
+ return build();
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java b/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
new file mode 100644
index 0000000..f99a520
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
@@ -0,0 +1,77 @@
+package de.ids_mannheim.korap.web.utils;
+
+import de.ids_mannheim.korap.auditing.AuditRecord;
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.exceptions.BaseException;
+import de.ids_mannheim.korap.exceptions.KorAPException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.AuditingIface;
+import de.ids_mannheim.korap.response.Notifications;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author hanl
+ * @date 29/01/2014
+ */
+public class KustvaktResponseHandler {
+
+ private static AuditingIface auditing = BeanConfiguration
+ .getAuditingProvider();
+
+ private static void register(List<AuditRecord> records) {
+ if (auditing != null && !records.isEmpty())
+ auditing.audit(records);
+ }
+
+ public static WebApplicationException throwit(BaseException e) {
+ //fixme: ??!
+ e.printStackTrace();
+ return new WebApplicationException(
+ Response.status(Response.Status.BAD_REQUEST)
+ .entity(buildNotification(e)).build());
+ }
+
+ @Deprecated
+ public static WebApplicationException throwit(int code) {
+ KorAPException e = new KorAPException(code);
+ return new WebApplicationException(
+ Response.status(Response.Status.OK).entity(buildNotification(e))
+ .build());
+ }
+
+ @Deprecated
+ public static WebApplicationException throwit(int code, String message,
+ String entity) {
+ KorAPException e = new KorAPException(code, message, entity);
+ return new WebApplicationException(
+ Response.status(Response.Status.OK).entity(buildNotification(e))
+ .build());
+ }
+
+ private static String buildNotification(BaseException e) {
+ KustvaktResponseHandler.register(e.getRecords());
+ return buildNotification(e.getStatusCode(), e.getMessage(),
+ e.getEntity());
+ }
+
+ private static String buildNotification(int code, String message,
+ String entity) {
+ Notifications notif = new Notifications();
+ notif.addError(code, message, entity);
+ return notif.toJsonString() + "\n";
+ }
+
+ public static WebApplicationException throwAuthenticationException() {
+ KorAPException e = new KorAPException(StatusCodes.BAD_CREDENTIALS);
+ return new WebApplicationException(
+ Response.status(Response.Status.UNAUTHORIZED)
+ .header(HttpHeaders.WWW_AUTHENTICATE,
+ "Basic realm=Kustvakt Authentication Service")
+ .entity(buildNotification(e)).build());
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/LocaleProvider.java b/src/main/java/de/ids_mannheim/korap/web/utils/LocaleProvider.java
new file mode 100644
index 0000000..47e8e03
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/LocaleProvider.java
@@ -0,0 +1,45 @@
+package de.ids_mannheim.korap.web.utils;
+
+import com.sun.jersey.api.core.HttpContext;
+import com.sun.jersey.core.spi.component.ComponentContext;
+import com.sun.jersey.core.spi.component.ComponentScope;
+import com.sun.jersey.server.impl.inject.AbstractHttpContextInjectable;
+import com.sun.jersey.spi.inject.Injectable;
+import com.sun.jersey.spi.inject.InjectableProvider;
+
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.Provider;
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * @author hanl
+ * @date 04/02/2014
+ */
+@Provider
+public class LocaleProvider
+ extends AbstractHttpContextInjectable<Locale>
+ implements InjectableProvider<Context, Type> {
+
+ @Override
+ public Locale getValue(HttpContext httpContext) {
+ final List<Locale> locales = httpContext.getRequest().getAcceptableLanguages();
+ if (locales.isEmpty())
+ return Locale.US;
+ return locales.get(0);
+ }
+
+ @Override
+ public ComponentScope getScope() {
+ return ComponentScope.PerRequest;
+ }
+
+ @Override
+ public Injectable getInjectable(ComponentContext ic, Context context, Type type) {
+ if (type.equals(Locale.class))
+ return this;
+ return null;
+ }
+}
+
diff --git a/src/main/resources/.DS_Store b/src/main/resources/.DS_Store
new file mode 100644
index 0000000..5008ddf
--- /dev/null
+++ b/src/main/resources/.DS_Store
Binary files differ
diff --git a/src/main/resources/changelog b/src/main/resources/changelog
new file mode 100644
index 0000000..50f47a7
--- /dev/null
+++ b/src/main/resources/changelog
@@ -0,0 +1,6 @@
+=== CHANGELOG FILE ===
+
+05/05/2015
+ - ADD: rest test suite for user service
+ - MOD: setup parameter modification
+ - ADD: oauth2 client unique constraint
diff --git a/src/main/resources/default-config.xml b/src/main/resources/default-config.xml
new file mode 100644
index 0000000..7e3c557
--- /dev/null
+++ b/src/main/resources/default-config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+ http://www.springframework.org/schema/util
+ http://www.springframework.org/schema/util/spring-util-4.0.xsd">
+
+
+ <!--<context:property-placeholder location="classpath:kustvakt.conf"/>-->
+
+ <util:properties id="props" location="classpath:kustvakt.conf"/>
+
+ <bean id="auditingProvider"
+ class="de.ids_mannheim.korap.interfaces.defaults.DefaultAuditing">
+ </bean>
+
+ <bean id="config"
+ class="de.ids_mannheim.korap.config.KustvaktConfiguration">
+ <property name="properties" ref="props"/>
+ </bean>
+
+ <bean name="encryption"
+ class="de.ids_mannheim.korap.interfaces.defaults.DefaultEncryption">
+ </bean>
+</beans>
\ No newline at end of file
diff --git a/src/test/.DS_Store b/src/test/.DS_Store
new file mode 100644
index 0000000..c7f4961
--- /dev/null
+++ b/src/test/.DS_Store
Binary files differ
diff --git a/src/test/java/.DS_Store b/src/test/java/.DS_Store
new file mode 100644
index 0000000..9462fb8
--- /dev/null
+++ b/src/test/java/.DS_Store
Binary files differ