Major refactoring to support coherent notifications - some known issues in JSON responses included
diff --git a/src/main/java/de/ids_mannheim/korap/KorapCollection.java b/src/main/java/de/ids_mannheim/korap/KorapCollection.java
index dcb1461..eca212f 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapCollection.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapCollection.java
@@ -8,6 +8,7 @@
import de.ids_mannheim.korap.util.QueryException;
import de.ids_mannheim.korap.filter.BooleanFilter;
import de.ids_mannheim.korap.filter.FilterOperation;
+import de.ids_mannheim.korap.response.Notifications;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.*;
@@ -24,19 +25,29 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * That's a pretty ugly API to
+ * create virtual collections.
+ * It works - so I got that going for
+ * me, which is nice.
+ *
+ * @author Nils Diewald
+ */
+
+
// TODO: Make a cache for the bits!!! DELETE IT IN CASE OF AN EXTENSION OR A FILTER!
-// Todo: Maybe use randomaccessfilterstrategy
+// TODO: Maybe use randomaccessfilterstrategy
// TODO: Maybe a constantScoreQuery can make things faster?
// THIS MAY CHANGE for stuff like combining virtual collections
// See http://mail-archives.apache.org/mod_mbox/lucene-java-user/
// 200805.mbox/%3C17080852.post@talk.nabble.com%3E
-public class KorapCollection {
+public class KorapCollection extends Notifications {
private KorapIndex index;
private KorapDate created;
private String id;
- private String error;
+ // private String error;
private ArrayList<FilterOperation> filter;
private int filterCount = 0;
@@ -61,7 +72,7 @@
this.filter = new ArrayList<FilterOperation>(5);
try {
- JsonNode json = mapper.readValue(jsonString, JsonNode.class);
+ JsonNode json = mapper.readTree(jsonString);
if (json.has("collection")) {
this.fromJSON(json.get("collection"));
@@ -70,16 +81,25 @@
// Legacy collection serialization
// This will be removed!
else if (json.has("collections")) {
- if (DEBUG)
- log.warn("Using DEPRECATED collection!");
-
+ this.addMessage(
+ 850,
+ "Collections are deprecated in favour of a single collection"
+ );
for (JsonNode collection : json.get("collections")) {
this.fromJSONLegacy(collection);
};
};
}
- catch (Exception e) {
- this.error = e.getMessage();
+ catch (QueryException qe) {
+ this.addError(qe.getErrorCode(),qe.getMessage());
+ }
+ catch (IOException e) {
+ this.addError(
+ 621,
+ "Unable to parse JSON",
+ "KorapCollection",
+ e.getLocalizedMessage()
+ );
};
};
@@ -92,10 +112,10 @@
public void fromJSON (String jsonString) throws QueryException {
ObjectMapper mapper = new ObjectMapper();
try {
- this.fromJSON((JsonNode) mapper.readValue(jsonString, JsonNode.class));
+ this.fromJSON((JsonNode) mapper.readTree(jsonString));
}
catch (Exception e) {
- this.error = e.getMessage();
+ this.addError(621, "Unable to parse JSON", "KorapCollection");
};
};
@@ -114,7 +134,7 @@
this.fromJSONLegacy((JsonNode) mapper.readValue(jsonString, JsonNode.class));
}
catch (Exception e) {
- this.error = e.getMessage();
+ this.addError(621, "Unable to parse JSON", "KorapCollection");
};
};
@@ -124,10 +144,10 @@
*/
public void fromJSONLegacy (JsonNode json) throws QueryException {
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
if (!json.has("@value"))
- throw new QueryException(612, "Legacy filter need @value fields");
+ throw new QueryException(851, "Legacy filter need @value fields");
String type = json.get("@type").asText();
@@ -162,18 +182,18 @@
log.trace("Added filter: {}", filter.toString());
if (filter == null) {
- log.warn("No filter is given");
+ this.addWarning(830, "Filter was empty");
return this;
};
Filter f = (Filter) new QueryWrapperFilter(filter.toQuery());
if (f == null) {
- log.warn("Filter can't be wrapped");
+ this.addWarning(831, "Filter is not wrappable");
return this;
};
FilterOperation fo = new FilterOperation(f, false);
if (fo == null) {
- log.warn("Filter operation invalid");
+ this.addWarning(832, "Filter operation is invalid");
return this;
};
this.filter.add(fo);
@@ -329,14 +349,14 @@
public long numberOf (String foundry, String type) throws IOException {
if (this.index == null)
- return (long) 0;
+ return (long) -1;
return this.index.numberOf(this, foundry, type);
};
public long numberOf (String type) throws IOException {
if (this.index == null)
- return (long) 0;
+ return (long) -1;
return this.index.numberOf(this, "tokens", type);
};
@@ -410,8 +430,4 @@
sw.append("}");
return sw.getBuffer().toString();
};
-
- public String getError () {
- return this.error;
- };
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapDocument.java b/src/main/java/de/ids_mannheim/korap/KorapDocument.java
index e3dc9a0..2602b46 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapDocument.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapDocument.java
@@ -5,6 +5,7 @@
import de.ids_mannheim.korap.util.KorapDate;
import de.ids_mannheim.korap.document.KorapPrimaryData;
import de.ids_mannheim.korap.index.FieldDocument;
+import de.ids_mannheim.korap.response.KorapResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.*;
@@ -14,10 +15,10 @@
/**
* Abstract class representing a document in the KorAP index.
*
- * @author ndiewald
+ * @author Nils Diewald
*/
@JsonIgnoreProperties(ignoreUnknown = true)
-public abstract class KorapDocument {
+public abstract class KorapDocument extends KorapResponse {
private KorapPrimaryData primaryData;
@JsonIgnore
diff --git a/src/main/java/de/ids_mannheim/korap/KorapFilter.java b/src/main/java/de/ids_mannheim/korap/KorapFilter.java
index 9c271d9..32573f9 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapFilter.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapFilter.java
@@ -46,11 +46,9 @@
protected BooleanFilter fromJSON (JsonNode json, String field) throws QueryException {
BooleanFilter bfilter = new BooleanFilter();
- /*
- TODO: THIS UNFORTUNATELY BREAKS TESTS
+ // TODO: THIS UNFORTUNATELY BREAKS TESTS
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
- */
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
String type = json.get("@type").asText();
diff --git a/src/main/java/de/ids_mannheim/korap/KorapIndex.java b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
index 518bd36..a51eabd 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapIndex.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapIndex.java
@@ -99,7 +99,7 @@
private int commitCounter = 0;
private HashMap termContexts;
private ObjectMapper mapper = new ObjectMapper();
- private String version;
+ private String version, name;
private byte[] pl = new byte[4];
private static ByteBuffer bb = ByteBuffer.allocate(4),
@@ -120,7 +120,8 @@
try {
InputStream fr = new FileInputStream(f);
prop.load(fr);
- this.version = prop.getProperty("lucene.index.version");
+ this.version = prop.getProperty("lucene.version");
+ this.name = prop.getProperty("lucene.name");
}
catch (FileNotFoundException e) {
log.warn(e.getLocalizedMessage());
@@ -165,6 +166,11 @@
return this.version;
};
+ // Get system name
+ public String getName () {
+ return this.name;
+ };
+
// Close connection to index
public void close () throws IOException {
@@ -623,6 +629,9 @@
if (this.getVersion() != null)
match.setVersion(this.getVersion());
+ if (this.getName() != null)
+ match.setName(this.getName());
+
if (match.getStartPos() == -1)
return match;
@@ -1255,7 +1264,11 @@
kr.setTotalResults(cutoff ? -1 : i);
}
catch (IOException e) {
- kr.setError(600, e.getLocalizedMessage());
+ kr.addError(
+ 600,
+ "Unable to read index",
+ e.getLocalizedMessage()
+ );
log.warn( e.getLocalizedMessage() );
};
@@ -1371,7 +1384,11 @@
mc.setBenchmark(t1, System.nanoTime());
}
catch (IOException e) {
- mc.setError(600, e.getLocalizedMessage());
+ mc.addError(
+ 600,
+ "Unable to read index",
+ e.getLocalizedMessage()
+ );
log.warn(e.getLocalizedMessage());
};
diff --git a/src/main/java/de/ids_mannheim/korap/KorapMatch.java b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
index b8afd1d..98811db 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapMatch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapMatch.java
@@ -415,31 +415,6 @@
super.setID(id);
};
-
- /**
- * Set version of the index
- */
- @JsonIgnore
- public String getVersion () {
- if (this.version == null)
- return null;
- StringBuilder sb = new StringBuilder("lucene-backend-");
- return sb.append(this.version).toString();
- };
-
-
- /**
- * Set version number.
- *
- * @param version The version number of the index as
- * a string representation.
- */
- @JsonIgnore
- public void setVersion (String version) {
- this.version = version;
- };
-
-
/**
* Get the positional start offset of the match.
*/
diff --git a/src/main/java/de/ids_mannheim/korap/KorapQuery.java b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
index 70267c1..d7962e8 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapQuery.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapQuery.java
@@ -1,6 +1,7 @@
package de.ids_mannheim.korap;
import de.ids_mannheim.korap.query.wrap.*;
+import de.ids_mannheim.korap.response.Notifications;
import de.ids_mannheim.korap.util.QueryException;
import org.apache.lucene.search.spans.SpanQuery;
@@ -38,7 +39,7 @@
* KorapQuery implements a simple API for wrapping
* KorAP Lucene Index specific query classes.
*/
-public class KorapQuery {
+public class KorapQuery extends Notifications {
private String field;
private ObjectMapper json;
@@ -48,8 +49,6 @@
// This advices the java compiler to ignore all loggings
public static final boolean DEBUG = false;
- private String warning;
-
public static final byte
OVERLAP = SpanWithinQuery.OVERLAP,
REAL_OVERLAP = SpanWithinQuery.REAL_OVERLAP,
@@ -79,10 +78,10 @@
public Boundary (JsonNode json, int defaultMin, int defaultMax) throws QueryException {
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
if (!json.get("@type").asText().equals("korap:boundary"))
- throw new QueryException(612, "Boundary definition is not valid");
+ throw new QueryException(702, "Boundary definition is invalid");
// Set min boundary
if (json.has("min"))
@@ -108,7 +107,8 @@
}
catch (IOException e) {
String msg = e.getMessage();
- throw new QueryException(611, msg.split("\n")[0]);
+ log.warn("Unable to parse JSON: " + msg.split("\n")[0]);
+ throw new QueryException(621, "Unable to parse JSON");
};
if (!json.has("@type") && json.has("query"))
@@ -127,7 +127,7 @@
int number = 0;
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
String type = json.get("@type").asText();
@@ -137,7 +137,7 @@
SpanClassQueryWrapper classWrapper;
if (!json.has("operation"))
- throw new QueryException(612, "Group expects operation");
+ throw new QueryException(703, "Group expects operation");
String operation = json.get("operation").asText();
@@ -145,13 +145,13 @@
log.trace("Found {} group", operation);
if (!json.has("operands"))
- throw new QueryException(612, "Operation needs operand list");
+ throw new QueryException(704, "Operation needs operand list");
// Get all operands
JsonNode operands = json.get("operands");
if (!operands.isArray())
- throw new QueryException(612, "Operation needs operand list");
+ throw new QueryException(704, "Operation needs operand list");
if (DEBUG)
log.trace("Operands are {}", operands);
@@ -159,7 +159,6 @@
switch (operation) {
case "operation:or":
-
SpanAlterQueryWrapper ssaq = new SpanAlterQueryWrapper(this.field);
for (JsonNode operand : operands) {
ssaq.or(this.fromJSON(operand));
@@ -169,7 +168,7 @@
case "operation:position":
if (operands.size() != 2)
- throw new QueryException(612, "Position needs exactly two operands");
+ throw new QueryException(705, "Number of operands is not acceptable");
// TODO: Check for operands
// TODO: LEGACY and not future proof
@@ -215,14 +214,14 @@
};
};
default:
- throw new QueryException(613, "Frame type unknown");
+ throw new QueryException(706, "Frame type is unknown");
};
// Check for exclusion modificator
Boolean exclude;
if (json.has("exclude") && json.get("exclude").asBoolean())
throw new QueryException(
- 613,
+ 760,
"Exclusion is currently not supported in position operations"
);
@@ -236,16 +235,22 @@
case "operation:submatch":
if (operands.size() != 1)
- throw new QueryException(612, "Operation needs exactly two operands");
+ throw new QueryException(705, "Number of operands is not acceptable");
if (json.has("classRef")) {
if (json.has("classRefOp"))
- throw new QueryException(613, "Class reference operators not supported yet");
+ throw new QueryException(
+ 761,
+ "Class reference operators are currently not supported"
+ );
number = json.get("classRef").get(0).asInt();
}
else if (json.has("spanRef")) {
- throw new QueryException(613, "Span references not supported yet");
+ throw new QueryException(
+ 762,
+ "Span references are currently not supported"
+ );
};
return new SpanMatchModifyQueryWrapper(
@@ -254,10 +259,9 @@
case "operation:sequence":
- if (operands.size() == 1) {
- this.addWarning("Sequences with less than two operands are ignored");
+ // Sequence with only one operand
+ if (operands.size() == 1)
return this.fromJSON(operands.get(0));
- };
SpanSequenceQueryWrapper sseqqw = this.seq();
@@ -272,12 +276,13 @@
// TODO
if (json.has("exclude") && json.get("exclude").asBoolean())
throw new QueryException(
- 613, "Excluding distance constraints are not supported yet"
+ 763,
+ "Excluding distance constraints are currently not supported"
);
if (!json.get("distances").isArray()) {
throw new QueryException(
- 612,
+ 707,
"Distance Constraints have " +
"to be defined as arrays"
);
@@ -287,13 +292,13 @@
JsonNode firstDistance = json.get("distances").get(0);
if (!firstDistance.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
JsonNode distances;
if (firstDistance.get("@type").asText().equals("korap:group")) {
if (!firstDistance.has("operands") ||
!firstDistance.get("operands").isArray())
- throw new QueryException(612, "Groups need operands");
+ throw new QueryException(704, "Operation needs operand list");
distances = firstDistance.get("operands");
}
@@ -309,7 +314,7 @@
}
else
- throw new QueryException(612, "No valid distances defined");
+ throw new QueryException(708, "No valid distances defined");
// Add all distance constraint to query
for (JsonNode constraint : distances) {
@@ -350,7 +355,8 @@
max = min;
if (DEBUG)
- log.trace("Add distance constraint of '{}': {}-{}", unit, min, max);
+ log.trace("Add distance constraint of '{}': {}-{}",
+ unit, min, max);
sseqqw.withConstraint(min, max, unit);
};
@@ -380,18 +386,22 @@
};
if (json.has("classRefCheck"))
- this.addWarning("classRefCheck is not yet supported - " +
- "results may not be correct");
+ this.addWarning(
+ 764,
+ "Class reference checks are currently not supported - results may not be correct"
+ );
if (json.has("classRefOp"))
- this.addWarning("classRefOp is not yet supported - " +
- "results may not be correct");
+ throw new QueryException(
+ 761,
+ "Class reference operators are currently not supported"
+ );
if (number > 0) {
if (operands.size() != 1)
throw new QueryException(
- 612,
- "Class group expects exactly one operand in list"
+ 705,
+ "Number of operands is not acceptable"
);
if (DEBUG)
@@ -399,7 +409,7 @@
if (number > MAX_CLASS_NUM) {
throw new QueryException(
- 612, "Class numbers limited to " + MAX_CLASS_NUM
+ 709, "Valid class numbers exceeded"
);
};
@@ -412,17 +422,16 @@
return new SpanClassQueryWrapper(sqw, number);
};
- throw new QueryException(612, "Class group expects class attribute");
+ throw new QueryException(710, "Class attribute missing");
case "operation:repetition":
if (operands.size() != 1)
throw new QueryException(
- 612,
- "Class group expects exactly one operand in list"
+ 705,
+ "Number of operands is not acceptable"
);
-
int min = 0;
int max = 100;
@@ -468,52 +477,53 @@
return new SpanRepetitionQueryWrapper(sqw, min, max);
case "operation:relation":
- throw new QueryException(613, "Relations are not yet supported");
+ throw new QueryException(765, "Relations are currently not supported");
};
- throw new QueryException(613, "Unknown group operation");
+ throw new QueryException(711, "Unknown group operation");
case "korap:reference":
if (json.has("operation") &&
!json.get("operation").asText().equals("operation:focus"))
- throw new QueryException(613, "Reference operation " +
- json.get("operation").asText() +
- " not supported yet");
+ throw new QueryException(712, "Unknown reference operation");
if (!json.has("operands"))
throw new QueryException(
- 613, "Peripheral references are not supported yet"
+ 766, "Peripheral references are currently not supported"
);
operands = json.get("operands");
if (!operands.isArray())
- throw new QueryException(612, "Operation needs operand list");
+ throw new QueryException(704, "Operation needs operand list");
if (operands.size() == 0)
- throw new QueryException(612, "Operation needs operand list");
+ throw new QueryException(704, "Operation needs operand list");
if (operands.size() != 1)
- throw new QueryException(612, "Operation needs exactly two operands");
+ throw new QueryException(705, "Number of operands is not acceptable");
if (json.has("classRef")) {
if (json.has("classRefOp")) {
throw new QueryException(
- 613,
- "Class reference operators not supported yet"
+ 761,
+ "Class reference operators are currently not supported"
);
};
number = json.get("classRef").get(0).asInt();
+
if (number > MAX_CLASS_NUM)
throw new QueryException(
- 613,
- "Class numbers limited to " + MAX_CLASS_NUM
+ 709, "Valid class numbers exceeded"
);
}
else if (json.has("spanRef")) {
- throw new QueryException(613, "Span references not supported yet");
+ throw new QueryException(
+ 762,
+ "Span references are currently not supported"
+ );
};
if (DEBUG)
@@ -532,12 +542,9 @@
return this._segFromJSON(json.get("wrap"));
case "korap:span":
- if (!json.has("key"))
- throw new QueryException(612, "A span needs at least a key definition");
-
return this._termFromJSON(json);
};
- throw new QueryException(613, "Unknown serialized query type");
+ throw new QueryException(713, "Query type is not supported");
};
@@ -545,7 +552,7 @@
private SpanQueryWrapper _segFromJSON (JsonNode json) throws QueryException {
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
String type = json.get("@type").asText();
@@ -571,12 +578,12 @@
return this._termFromJSON(json);
};
- throw new QueryException(613, "Match relation unknown");
+ throw new QueryException(741, "Match relation unknown");
case "korap:termGroup":
if (!json.has("operands"))
- throw new QueryException(612, "Term group expects operands");
+ throw new QueryException(742, "Term group needs operand list");
// Get operands
JsonNode operands = json.get("operands");
@@ -584,7 +591,7 @@
SpanSegmentQueryWrapper ssegqw = this.seg();
if (!json.has("relation"))
- throw new QueryException(612, "Term group expects a relation");
+ throw new QueryException(743, "Term group expects a relation");
switch (json.get("relation").asText()) {
case "relation:and":
@@ -602,7 +609,7 @@
}
else {
throw new QueryException(
- 613, "Object not supported in segment queries"
+ 744, "Operand not supported in term group"
);
};
};
@@ -617,16 +624,16 @@
return ssaq;
};
};
- throw new QueryException(613, "Unknown token type");
+ throw new QueryException(745, "Token type is not supported");
};
private SpanQueryWrapper _termFromJSON (JsonNode json) throws QueryException {
if (!json.has("key") || json.get("key").asText().length() < 1)
- throw new QueryException(612, "Terms and spans have to provide key attributes");
+ throw new QueryException(740, "Key definition is missing in term or span");
if (!json.has("@type"))
- throw new QueryException(612, "JSON-LD group has no @type attribute");
+ throw new QueryException(701, "JSON-LD group has no @type attribute");
Boolean isTerm = json.get("@type").asText().equals("korap:term") ? true : false;
Boolean isCaseInsensitive = false;
@@ -658,6 +665,11 @@
break;
case "orth":
+ // TODO: THIS IS A BUG! AND SHOULD BE NAMED "SURFACE"
+ layer = "s";
+ break;
+
+ case "struct":
layer = "s";
break;
@@ -671,7 +683,10 @@
layer = "i";
}
else {
- this.addWarning("Layer does not support case insensitivity");
+ this.addWarning(
+ 767,
+ "Case insensitivity is currently not supported for this layer"
+ );
};
};
@@ -687,6 +702,9 @@
value.append(isCaseInsensitive ? key.toLowerCase() : key);
};
+ if (json.has("value") && json.get("value").asText().length() > 0)
+ value.append(':').append(json.get("value").asText());
+
// Regular expression or wildcard
if (isTerm && json.has("type")) {
switch (json.get("type").asText()) {
@@ -694,22 +712,25 @@
return this.seg(this.re(value.toString(), isCaseInsensitive));
case "type:wildcard":
return this.seq(this.wc(value.toString(), isCaseInsensitive));
+ case "type:string":
+ break;
+ default:
+ this.addWarning(746, "Term type is not supported - treated as a string");
};
};
- if (json.has("value") && json.get("value").asText().length() > 0)
- value.append(':').append(json.get("value").asText());
-
if (isTerm)
return this.seg(value.toString());
if (json.has("attr"))
- this.addWarning("Attributes are not yet supported - " +
- "results may not be correct");
+ this.addWarning(
+ 768,
+ "Attributes are currently not supported - results may not be correct");
return this.tag(value.toString());
};
+ /*
public boolean hasWarning () {
if (this.warning != null)
return true;
@@ -732,7 +753,7 @@
public void setWarning (String warning) {
this.warning = warning;
};
-
+ */
// SpanRegexQueryWrapper
/**
diff --git a/src/main/java/de/ids_mannheim/korap/KorapResult.java b/src/main/java/de/ids_mannheim/korap/KorapResult.java
index ab4389a..9b00870 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapResult.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapResult.java
@@ -10,7 +10,7 @@
import de.ids_mannheim.korap.index.PositionsToOffset;
import de.ids_mannheim.korap.index.SearchContext;
-import de.ids_mannheim.korap.server.KorapResponse;
+import de.ids_mannheim.korap.response.KorapResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,6 +21,7 @@
/*
TODO: Reuse the KorapSearch code for data serialization!
*/
+
@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class KorapResult extends KorapResponse {
@@ -29,6 +30,9 @@
@JsonIgnore
public static final short ITEMS_PER_PAGE = 25;
+ private int totalResults;
+ private long totalTexts;
+
private String query;
private List<KorapMatch> matches;
@@ -43,7 +47,6 @@
private String benchmarkSearchResults,
benchmarkHitCounter;
private String error = null;
- private String warning = null;
private JsonNode request;
@@ -70,15 +73,15 @@
this.matches = new ArrayList<>(itemsPerPage);
this.query = query;
this.startIndex = startIndex;
- this.itemsPerPage = (itemsPerPage > 50 || itemsPerPage < 1) ? ITEMS_PER_PAGE : itemsPerPage;
+ this.itemsPerPage = (itemsPerPage > 50 || itemsPerPage < 1) ?
+ ITEMS_PER_PAGE : itemsPerPage;
this.context = context;
- }
+ };
- public void add(KorapMatch km) {
+ public void add (KorapMatch km) {
this.matches.add(km);
- }
-
+ };
public KorapMatch addMatch (PositionsToOffset pto,
int localDocID,
@@ -89,23 +92,6 @@
// Temporary - should use the same interface like results
// in the future:
km.setContext(this.context);
-
- // Add pos for context
- // That's not really a good position for it,
- // to be honest ...
- // But maybe it will make the offset
- // information in the match be obsolete!
-
- // TODO:
- /*
- if (km.leftTokenContext) {
- pto.add(localDocID, startPos - this.leftContextOffset);
- };
- if (km.rightTokenContext) {
- pto.add(localDocID, endPos + this.rightContextOffset - 1);
- };
- */
-
this.add(km);
return km;
};
@@ -113,45 +99,15 @@
@Deprecated
public int totalResults() {
return this.getTotalResults();
- }
+ };
public short getItemsPerPage() {
return this.itemsPerPage;
- }
-
+ };
@Deprecated
public short itemsPerPage() {
return this.itemsPerPage;
- }
-
- /*
-
- public String getError() {
- return this.error;
- }
-
- public void setError(String msg) {
- this.error = msg;
- }
-
- */
-
- public String getWarning() {
- return this.warning;
- }
-
- public void addWarning (String msg) {
- if (msg == null)
- return;
- if (this.warning == null)
- this.warning = msg;
- else
- this.warning += "; " + warning;
- };
-
- public void setWarning (String warning) {
- this.warning = warning;
};
public void setRequest(JsonNode request) {
@@ -162,6 +118,7 @@
return this.request;
};
+ /*
@JsonIgnore
public void setBenchmarkHitCounter(long t1, long t2) {
this.benchmarkHitCounter =
@@ -177,6 +134,33 @@
return this.benchmarkHitCounter;
};
+ */
+
+ // Make this working in a KorapResult class
+ // that is independent from search and collection
+ public KorapResult setTotalTexts (long i) {
+ this.totalTexts = i;
+ return this;
+ };
+
+ public long getTotalTexts() {
+ return this.totalTexts;
+ };
+
+ public KorapResult setTotalResults (int i) {
+ this.totalResults = i;
+ return this;
+ };
+
+ public KorapResult incrTotalResults (int i) {
+ this.totalResults += i;
+ return this;
+ };
+
+ public int getTotalResults() {
+ return this.totalResults;
+ };
+
@JsonIgnore
public void setItemsPerResource (short value) {
this.itemsPerResource = value;
@@ -193,6 +177,8 @@
};
public void setTimeExceeded (boolean timeout) {
+ if (timeout)
+ this.addWarning(682, "Search time exceeded");
this.timeExceeded = timeout;
};
@@ -236,31 +222,41 @@
return this.context;
}
-
- // Identical to KorapMatch!
- public String toJSON () {
- ObjectNode json = (ObjectNode) mapper.valueToTree(this);
+ public JsonNode toJSONnode () {
+ ObjectNode json = (ObjectNode) mapper.valueToTree(super.toJSONnode());
if (this.context != null)
json.put("context", this.getContext().toJSON());
if (this.itemsPerResource > 0)
- json.put("itemsPerResource", this.itemsPerResource);
+ json.put("itemsPerResource",
+ this.itemsPerResource);
- if (this.getVersion() != null)
- json.put("version", this.getVersion());
+ json.put("itemsPerPage",
+ this.itemsPerPage);
+
+ // TODO: If test
+ if (this.request != null)
+ json.put("request", this.request);
+
+ // TODO: If test
+ if (this.request != null)
+ json.put("request", this.request);
+ if (this.query != null)
+ json.put("query", this.query);
+
+ json.put("startIndex", this.startIndex);
+
+ json.put("totalResults", this.getTotalResults());
+
+ if (this.timeExceeded)
+ json.put("timeExceeded", this.timeExceeded);
// Add matches
- json.putPOJO("matches", this.getMatches());
+ if (this.matches != null)
+ json.putPOJO("matches", this.getMatches());
- try {
- return mapper.writeValueAsString(json);
- }
- catch (Exception e) {
- log.warn(e.getLocalizedMessage());
- };
-
- return "{}";
+ return json;
};
@@ -268,9 +264,6 @@
public String toTokenListJSON () {
ObjectNode json = (ObjectNode) mapper.valueToTree(this);
- if (this.getVersion() != null)
- json.put("version", this.getVersion());
-
ArrayNode array = json.putArray("matches");
// Add matches as token lists
diff --git a/src/main/java/de/ids_mannheim/korap/KorapSearch.java b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
index 2d342b2..d145856 100644
--- a/src/main/java/de/ids_mannheim/korap/KorapSearch.java
+++ b/src/main/java/de/ids_mannheim/korap/KorapSearch.java
@@ -10,6 +10,7 @@
import de.ids_mannheim.korap.KorapResult;
import de.ids_mannheim.korap.util.QueryException;
import de.ids_mannheim.korap.index.SearchContext;
+import de.ids_mannheim.korap.response.Notifications;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
@@ -26,7 +27,7 @@
*
* KorapSearch implements an object for all search relevant parameters.
*/
-public class KorapSearch {
+public class KorapSearch extends Notifications {
private int startIndex = 0,
limit = 0;
private short count = 25,
@@ -36,7 +37,7 @@
private SpanQuery query;
private KorapCollection collection;
private KorapIndex index;
- private String error, warning;
+ // private String error, warning;
// Timeout search after milliseconds
private long timeout = (long) 120_000;
@@ -50,7 +51,6 @@
private long timeoutStart = Long.MIN_VALUE;
-
{
context = new SearchContext();
@@ -76,8 +76,10 @@
public KorapSearch (String jsonString) {
ObjectMapper mapper = new ObjectMapper();
+
try {
- this.request = mapper.readValue(jsonString, JsonNode.class);
+ // Todo - use correct method!
+ this.request = mapper.readTree(jsonString);
// "query" value
if (this.request.has("query")) {
@@ -86,39 +88,49 @@
SpanQueryWrapper qw = kq.fromJSON(this.request.get("query"));
if (qw.isEmpty()) {
- this.error = "This query matches everywhere";
+
+ // Unable to process result
+ this.addError(780, "This query matches everywhere");
}
else {
this.query = qw.toQuery();
if (qw.isOptional())
- this.addWarning("Optionality of query is ignored");
+ this.addWarning(781, "Optionality of query is ignored");
if (qw.isNegative())
- this.addWarning("Exclusivity of query is ignored");
+ this.addWarning(782, "Exclusivity of query is ignored");
- // Set query deserialization warning
- if (kq.hasWarning())
- this.addWarning(kq.getWarning());
};
+ // Copy notifications from query
+ this.copyNotificationsFrom(kq);
+ kq.clearNotifications();
}
catch (QueryException q) {
- this.error = q.getMessage();
+ this.addError(q.getErrorCode(), q.getMessage());
};
}
else {
- this.error = "No query defined";
+ this.addError(700, "No query given");
};
- // Legacy code: Report warning coming from the request
- if (this.request.has("warning") && this.request.get("warning").asText().length() > 0)
- this.addWarning(this.request.get("warning").asText());
+ // <legacycode>
+ if (this.request.has("warning") &&
+ this.request.get("warning").asText().length() > 0)
+ this.addWarning(
+ 799,
+ this.request.get("warning").asText()
+ );
+ // </legacycode>
+ // <legacycode>
if (this.request.has("warnings")) {
JsonNode warnings = this.request.get("warnings");
for (JsonNode node : warnings)
if (node.asText().length() > 0)
- this.addWarning(node.asText());
+ this.addWarning(799, node.asText());
};
- // end of legacy code
+ // </legacycode>
+ // Copy notifications from request
+ this.copyNotificationsFrom(this.request);
// virtual collections
if (this.request.has("collection") ||
@@ -126,7 +138,7 @@
this.request.has("collections"))
this.setCollection(new KorapCollection(jsonString));
- if (this.error == null) {
+ if (!this.hasErrors()) {
if (this.request.has("meta")) {
JsonNode meta = this.request.get("meta");
@@ -179,7 +191,7 @@
// Unable to parse JSON
catch (IOException e) {
- this.error = e.getMessage();
+ this.addError(621, "Unable to parse JSON");
};
};
@@ -189,7 +201,7 @@
this.query = sqwi.toQuery();
}
catch (QueryException q) {
- this.error = q.getMessage();
+ this.addError(q.getErrorCode(), q.getMessage());
};
};
@@ -208,24 +220,6 @@
this.timeout = timeout;
};
- public String getError () {
- return this.error;
- };
-
- public String getWarning () {
- return this.warning;
- };
-
- public void addWarning (String msg) {
- if (msg == null)
- return;
-
- if (this.warning == null)
- this.warning = msg;
- else
- this.warning += "; " + msg;
- };
-
public SpanQuery getQuery () {
return this.query;
};
@@ -235,11 +229,12 @@
};
public KorapSearch setQuery (SpanQueryWrapper sqwi) {
+ // this.copyNotifications(sqwi);
try {
this.query = sqwi.toQuery();
}
catch (QueryException q) {
- this.error = q.getMessage();
+ this.addError(q.getErrorCode(), q.getMessage());
};
return this;
};
@@ -354,8 +349,10 @@
public KorapSearch setCollection (KorapCollection kc) {
this.collection = kc;
- if (kc.getError() != null)
- this.error = kc.getError();
+
+ // Copy messages from the collection
+ this.copyNotificationsFrom(kc);
+ kc.clearNotifications();
return this;
};
@@ -371,27 +368,27 @@
KorapResult kr = new KorapResult();
kr.setRequest(this.request);
- if (this.error != null)
- kr.setError(this.error);
+ if (this.hasErrors())
+ kr.copyNotificationsFrom(this);
else
- kr.setError(this.getClass() + " expects a query");
+ kr.addError(700, "No query given");
return kr;
};
- if (this.error != null) {
+ if (this.hasErrors()) {
KorapResult kr = new KorapResult();
+
+ // TODO: dev mode
kr.setRequest(this.request);
- kr.setError(this.error);
- if (this.warning != null)
- kr.addWarning(this.warning);
+ kr.copyNotificationsFrom(this);
return kr;
};
this.getCollection().setIndex(ki);
KorapResult kr = ki.search(this);
kr.setRequest(this.request);
- if (this.warning != null)
- kr.addWarning(this.warning);
+ kr.copyNotificationsFrom(this);
+ this.clearNotifications();
return kr;
};
};
diff --git a/src/main/java/de/ids_mannheim/korap/index/MatchCollector.java b/src/main/java/de/ids_mannheim/korap/index/MatchCollector.java
index ca3f056..114adac 100644
--- a/src/main/java/de/ids_mannheim/korap/index/MatchCollector.java
+++ b/src/main/java/de/ids_mannheim/korap/index/MatchCollector.java
@@ -1,10 +1,12 @@
package de.ids_mannheim.korap.index;
import de.ids_mannheim.korap.KorapMatch;
-import de.ids_mannheim.korap.server.KorapResponse;
+import de.ids_mannheim.korap.response.KorapResponse;
import java.util.*;
public class MatchCollector extends KorapResponse {
public int totalResultDocs = 0;
+ private int totalResults;
+ private long totalTexts;
public void add (int uniqueDocID, int matchcount) {
this.totalResultDocs++;
@@ -25,6 +27,31 @@
return totalResultDocs;
};
+ // Make this working in a KorapResult class
+ // that is independent from search and collection
+ public MatchCollector setTotalTexts (long i) {
+ this.totalTexts = i;
+ return this;
+ };
+
+ public long getTotalTexts() {
+ return this.totalTexts;
+ };
+
+ public MatchCollector setTotalResults (int i) {
+ this.totalResults = i;
+ return this;
+ };
+
+ public MatchCollector incrTotalResults (int i) {
+ this.totalResults += i;
+ return this;
+ };
+
+ public int getTotalResults() {
+ return this.totalResults;
+ };
+
public void commit() {};
public void close() {};
diff --git a/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
new file mode 100644
index 0000000..6f43e32
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/KorapResponse.java
@@ -0,0 +1,147 @@
+package de.ids_mannheim.korap.response;
+
+import java.util.*;
+import java.io.*;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.response.Notifications;
+
+public class KorapResponse extends Notifications {
+ ObjectMapper mapper = new ObjectMapper();
+
+ private String
+ version,
+ name,
+ node,
+ listener;
+ private String benchmark;
+
+ // add timeout!!!
+ // remove totalResults, totalTexts
+
+ public KorapResponse () {};
+
+ /**
+ * Get version of the index
+ */
+ @JsonIgnore
+ public String getVersion () {
+ if (this.version == null)
+ return null;
+ return this.version;
+ };
+
+ /**
+ * Set version number.
+ *
+ * @param version The version number of the index as
+ * a string representation.
+ */
+ @JsonIgnore
+ public void setVersion (String version) {
+ this.version = version;
+ };
+
+ /**
+ * Get name the index
+ */
+ @JsonIgnore
+ public String getName () {
+ if (this.name == null)
+ return null;
+ return this.name;
+ };
+
+ /**
+ * Set name.
+ *
+ * @param name The name of the index as
+ * a string representation.
+ */
+ @JsonIgnore
+ public void setName (String name) {
+ this.name = name;
+ };
+
+ @JsonIgnore
+ public String getNode () {
+ return this.node;
+ };
+
+ @JsonIgnore
+ public KorapResponse setNode (String name) {
+ this.node = name;
+ return this;
+ };
+
+ @JsonIgnore
+ public KorapResponse setBenchmark (long t1, long t2) {
+ this.benchmark =
+ (t2 - t1) < 100_000_000 ?
+ // Store as miliseconds
+ (((double) (t2 - t1) * 1e-6) + " ms") :
+ // Store as seconds
+ (((double) (t2 - t1) / 1000000000.0) + " s");
+ return this;
+ };
+
+ @JsonIgnore
+ public KorapResponse setBenchmark (String bm) {
+ this.benchmark = bm;
+ return this;
+ };
+
+ @JsonIgnore
+ public String getBenchmark () {
+ return this.benchmark;
+ };
+
+ @JsonIgnore
+ public KorapResponse setListener (String listener) {
+ this.listener = listener;
+ return this;
+ };
+
+ @JsonIgnore
+ public String getListener () {
+ return this.listener;
+ }
+
+ /**
+ * Serialize response to JSON node.
+ */
+ @Override
+ public JsonNode toJSONnode () {
+
+ // Get notifications json response
+ ObjectNode json = (ObjectNode) super.toJSONnode();
+
+ StringBuilder sb = new StringBuilder();
+ if (this.getName() != null) {
+ sb.append(this.getName());
+
+ if (this.getVersion() != null)
+ sb.append("-").append(this.getVersion());
+ }
+ else if (this.getVersion() != null) {
+ sb.append(this.getVersion());
+ };
+
+ if (sb.length() > 0)
+ json.put("version", sb.toString());
+
+ if (this.getNode() != null)
+ json.put("node", this.getNode());
+
+ if (this.getListener() != null)
+ json.put("listener", this.getListener());
+
+ if (this.getBenchmark() != null)
+ json.put("benchmark", this.getBenchmark());
+
+ return (JsonNode) json;
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/Message.java b/src/main/java/de/ids_mannheim/korap/response/Message.java
new file mode 100644
index 0000000..4f7cd29
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/Message.java
@@ -0,0 +1,98 @@
+package de.ids_mannheim.korap.response;
+
+import java.util.LinkedList;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.*;
+
+public class Message implements Cloneable {
+ // Mapper for JSON serialization
+ 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 void setMessage (String msg) {
+ this.msg = msg;
+ };
+
+ @JsonIgnore
+ public String getMessage () {
+ return this.msg;
+ };
+
+ @JsonIgnore
+ public void setCode (int code) {
+ this.code = code;
+ };
+
+ @JsonIgnore
+ public int getCode () {
+ return this.code;
+ };
+
+ public void addParameter (String param) {
+ if (this.parameters == null)
+ this.parameters = new LinkedList<String>();
+ this.parameters.add(param);
+ };
+
+ 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) {
+ for (String p : this.parameters) {
+ clone.addParameter(p);
+ };
+ };
+
+ return clone;
+ };
+
+
+ public JsonNode toJSONnode () {
+ ArrayNode message = mapper.createArrayNode();
+
+ if (this.code != 0)
+ message.add(this.getCode());
+
+ message.add(this.getMessage());
+ if (parameters != null)
+ for (String p : parameters)
+ message.add(p);
+ return (JsonNode) message;
+ };
+
+ /**
+ * Get JSON string
+ */
+ public String toJSON () {
+ String msg = "";
+ try {
+ return mapper.writeValueAsString(this.toJSONnode());
+ }
+ catch (Exception e) {
+ msg = ", \"" + e.getLocalizedMessage() + "\"";
+ };
+
+ return
+ "[620, " +
+ "\"Unable to generate JSON\"" + msg + "]";
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/Messages.java b/src/main/java/de/ids_mannheim/korap/response/Messages.java
new file mode 100644
index 0000000..1af8614
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/Messages.java
@@ -0,0 +1,152 @@
+package de.ids_mannheim.korap.response;
+
+import de.ids_mannheim.korap.util.QueryException;
+import de.ids_mannheim.korap.response.Message;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Nils Diewald
+ *
+ * An array of messages.
+ */
+public class Messages implements Cloneable {
+
+ // Mapper for JSON serialization
+ ObjectMapper mapper = new ObjectMapper();
+ private ArrayList<Message> messages;
+
+ public Messages () {
+ this.messages = new ArrayList<Message>(3);
+ };
+
+ /**
+ * Add message
+ */
+ public Message add (int code,
+ String message,
+ String ... terms) {
+ Message newMsg = new Message(code, message);
+ messages.add(newMsg);
+ if (terms != null)
+ for (String t : terms)
+ newMsg.addParameter(t);
+ return newMsg;
+ };
+
+ /**
+ * Add message
+ */
+ public Message add (Message msg) {
+ messages.add(msg);
+ return msg;
+ };
+
+ /**
+ * Add message usng JsonNode
+ */
+ public Message add (JsonNode msg) throws QueryException {
+ if (!msg.isArray() || !msg.has(0))
+ throw new QueryException(
+ 750, "Passed notifications are not well formed"
+ );
+
+ // Valid message
+ Message newMsg = new Message();
+ short i = 1;
+ if (msg.get(0).isNumber()) {
+ newMsg.setCode(msg.get(0).asInt());
+ if (!msg.has(1))
+ throw new QueryException(
+ 750, "Passed notifications are not well formed"
+ );
+ newMsg.setMessage(msg.get(1).asText());
+ i++;
+ }
+ else {
+ newMsg.setMessage(msg.get(0).asText());
+ };
+
+ // Add parameters
+ while (msg.has(i))
+ newMsg.addParameter(msg.get(i++).asText());
+
+ // Add messages to list
+ this.add(newMsg);
+ return newMsg;
+ };
+
+
+ /**
+ * Add messages
+ */
+ public void add (Messages msgs) {
+ for (Message msg : msgs.getMessages()) {
+ this.add(msg);
+ };
+ };
+
+ /**
+ * Clear all messages
+ */
+ public void clear () {
+ messages.clear();
+ };
+
+ public int size () {
+ return this.messages.size();
+ };
+
+ @JsonIgnore
+ public Message get (int index) {
+ return this.messages.get(index);
+ };
+
+ @JsonIgnore
+ public List<Message> getMessages () {
+ return this.messages;
+ };
+
+ public Object clone () throws CloneNotSupportedException
+ {
+ Messages clone = new Messages();
+ for (Message m : this.messages) {
+ clone.add((Message) m.clone());
+ };
+
+ return clone;
+ };
+
+ /**
+ * Get JSON node
+ */
+ public JsonNode toJSONnode () {
+ ArrayNode messageArray = mapper.createArrayNode();
+ for (Message msg : this.messages)
+ messageArray.add(msg.toJSONnode());
+ return (JsonNode) messageArray;
+ };
+
+ /**
+ * Get JSON string
+ */
+ public String toJSON () {
+ String msg = "";
+ try {
+ return mapper.writeValueAsString(this.toJSONnode());
+ }
+ catch (Exception e) {
+ msg = ", \"" + e.getLocalizedMessage() + "\"";
+ };
+
+ return
+ "[620, " +
+ "\"Unable to generate JSON\"" + msg + "]";
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/response/Notifications.java b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
new file mode 100644
index 0000000..361fb9a
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/response/Notifications.java
@@ -0,0 +1,362 @@
+package de.ids_mannheim.korap.response;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.*;
+
+import java.util.*;
+import java.io.*;
+import de.ids_mannheim.korap.response.Message;
+import de.ids_mannheim.korap.response.Messages;
+import de.ids_mannheim.korap.util.QueryException;
+
+/**
+ * Unified notification class for KorAP related errors,
+ * warnings and messages.
+ *
+ * @author Nils Diewald
+ */
+
+@JsonInclude(Include.NON_NULL)
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Notifications {
+
+ // Create object mapper for JSON generation
+ ObjectMapper mapper = new ObjectMapper();
+
+ private Messages warnings,
+ errors,
+ messages;
+
+ /**
+ * Add a new warning.
+ *
+ * @param code Integer code representation of the warning
+ * @param msg String representation of the warning
+ */
+ public void addWarning (int code, String msg, String ... terms) {
+ if (this.warnings == null)
+ this.warnings = new Messages();
+ this.warnings.add(code, msg, terms);
+ };
+
+ public void addWarning (JsonNode msg) {
+ if (this.warnings == null)
+ this.warnings = new Messages();
+
+ try {
+ this.warnings.add(msg);
+ }
+ catch (QueryException qe) {
+ this.warnings.add(qe.getErrorCode(), qe.getMessage());
+ };
+ };
+
+ /**
+ * Add new warnings.
+ *
+ * @param msgs Array representation of the warning
+ */
+ public void addWarnings (Messages msgs) {
+ if (this.warnings == null)
+ this.warnings = msgs;
+ else
+ this.warnings.add(msgs);
+ };
+
+
+ /**
+ * Get all warnings.
+ */
+ public Messages getWarnings () {
+ return this.warnings;
+ };
+
+
+ public Message getWarning (int index) {
+ if (this.warnings != null)
+ return this.warnings.get(index);
+ return (Message) null;
+ };
+
+
+ /**
+ * Check for warnings.
+ */
+ public boolean hasWarnings () {
+ if (this.warnings == null || this.warnings.size() == 0)
+ return false;
+ return true;
+ };
+
+ /**
+ * Add a new error.
+ *
+ * @param code Integer code representation of the error
+ * @param msg String representation of the error
+ */
+ public void addError (int code, String msg, String ... terms) {
+ if (this.errors == null)
+ this.errors = new Messages();
+ this.errors.add(code, msg, terms);
+ };
+
+ public void addError (JsonNode msg) {
+ if (this.errors == null)
+ this.errors = new Messages();
+ try {
+ this.errors.add(msg);
+ }
+ catch (QueryException qe) {
+ this.errors.add(qe.getErrorCode(), qe.getMessage());
+ };
+ };
+
+
+ /**
+ * Add new warnings.
+ *
+ * @param msgs Array representation of the warning
+ */
+ public void addErrors (Messages msgs) {
+ if (this.errors == null)
+ this.errors = msgs;
+ else
+ this.errors.add(msgs);
+ };
+
+
+ /**
+ * Get all errors.
+ */
+ public Messages getErrors () {
+ return this.errors;
+ };
+
+ public Message getError (int index) {
+ if (this.errors != null)
+ return this.errors.get(index);
+ return (Message) null;
+ };
+
+ /**
+ * Check for errors.
+ */
+ public boolean hasErrors () {
+ if (this.errors == null || this.errors.size() == 0)
+ return false;
+ return true;
+ };
+
+
+ /**
+ * Add a new message.
+ *
+ * @param code Integer code representation of the message
+ * @param msg String representation of the message
+ */
+ public void addMessage (int code, String msg, String ... terms) {
+ if (this.messages == null)
+ this.messages = new Messages();
+ this.messages.add(code, msg, terms);
+ };
+
+ public void addMessage (JsonNode msg) {
+ if (this.messages == null)
+ this.messages = new Messages();
+ try {
+ this.messages.add(msg);
+ }
+ catch (QueryException qe) {
+ this.messages.add(qe.getErrorCode(), qe.getMessage());
+ };
+ };
+
+ /**
+ * Add new warnings.
+ *
+ * @param msgs Array representation of the warning
+ */
+ public void addMessages (Messages msgs) {
+ if (this.messages == null)
+ this.messages = msgs;
+ else
+ this.messages.add(msgs);
+ };
+
+
+ /**
+ * Get all messages.
+ */
+ public Messages getMessages () {
+ return this.messages;
+ };
+
+ public Message getMessage (int index) {
+ if (this.messages != null)
+ return this.messages.get(index);
+ return (Message) null;
+ };
+
+
+ /**
+ * Check for messages.
+ */
+ public boolean hasMessages () {
+ if (this.messages == null || this.messages.size() == 0)
+ return false;
+ return true;
+ };
+
+
+ /**
+ * Copy notifications
+ */
+ public void copyNotificationsFrom (Notifications notes) {
+ try {
+ if (notes.hasErrors())
+ this.addErrors((Messages) notes.getErrors().clone());
+ if (notes.hasWarnings())
+ this.addWarnings((Messages) notes.getWarnings().clone());
+ if (notes.hasMessages())
+ this.addMessages((Messages) notes.getMessages().clone());
+ }
+ catch (CloneNotSupportedException cnse) {
+ };
+ return;
+ };
+
+
+ /**
+ * Copy notifications from JsonNode
+ */
+ public void copyNotificationsFrom (JsonNode request) {
+
+ // Add warnings from JSON
+ if (request.has("warnings") &&
+ request.get("warnings").isArray()) {
+ JsonNode msgs = request.get("warnings");
+ for (JsonNode msg : msgs)
+ this.addWarning(msg);
+ };
+
+ // Add messages from JSON
+ if (request.has("messages") &&
+ request.get("messages").isArray()) {
+ JsonNode msgs = request.get("messages");
+ if (msgs.isArray())
+ for (JsonNode msg : msgs)
+ this.addMessage(msg);
+ };
+
+ // Add errors from JSON
+ if (request.has("errors") &&
+ request.get("errors").isArray()) {
+ JsonNode msgs = request.get("errors");
+ if (msgs.isArray())
+ for (JsonNode msg : msgs)
+ this.addError(msg);
+ };
+ };
+
+
+ /**
+ * Serialize response to JSON node.
+ */
+ public JsonNode toJSONnode () {
+ ObjectNode json = mapper.createObjectNode();
+
+ // Add messages
+ if (this.hasWarnings())
+ json.put("warnings", this.getWarnings().toJSONnode());
+ if (this.hasErrors())
+ json.put("errors", this.getErrors().toJSONnode());
+ if (this.hasMessages())
+ json.put("messages", this.getMessages().toJSONnode());
+
+ return (JsonNode) json;
+ };
+
+ /**
+ * Serialize response to JSON string.
+ */
+ public String toJSON () {
+ String msg = "";
+ try {
+ JsonNode node = this.toJSONnode();
+ if (node == null)
+ return "{}";
+ return mapper.writeValueAsString(node);
+ }
+ catch (Exception e) {
+ msg = ", \"" + e.getLocalizedMessage() + "\"";
+ };
+
+ return
+ "{\"errors\" : [" +
+ "[620, " +
+ "\"Unable to generate JSON\"" + msg + "]" +
+ "]}";
+ };
+
+ /**
+ * Clear all notifications.
+ */
+ public void clearNotifications () {
+ if (this.warnings != null)
+ this.warnings.clear();
+ if (this.messages != null)
+ this.messages.clear();
+ if (this.errors != null)
+ this.errors.clear();
+ };
+
+
+ // Remove:
+ @Deprecated
+ public void addError (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void addWarning (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void addMessage (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setError (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setWarning (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setMessage (String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setError (int code, String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setWarning (int code, String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+
+ @Deprecated
+ public void setMessage (int code, String msg) {
+ System.err.println("DEPRECATED " + msg);
+ };
+};
diff --git a/src/main/java/de/ids_mannheim/korap/server/KorapResponse.java b/src/main/java/de/ids_mannheim/korap/server/KorapResponse.java
deleted file mode 100644
index bcdd258..0000000
--- a/src/main/java/de/ids_mannheim/korap/server/KorapResponse.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package de.ids_mannheim.korap.server;
-
-import java.util.*;
-import java.io.*;
-
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-
-@JsonInclude(Include.NON_NULL)
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class KorapResponse {
- ObjectMapper mapper = new ObjectMapper();
-
- private String errstr, msg, version, node, listener;
- private int err;
- private int totalResults;
- private long totalTexts;
- private String benchmark;
-
- public KorapResponse (String node, String version) {
- this.setNode(node);
- this.setVersion(version);
- };
-
- public KorapResponse () {};
-
- @JsonIgnore
- public KorapResponse setError (int code, String msg) {
- this.err = code;
- this.errstr = msg;
- return this;
- };
-
- @JsonIgnore
- public KorapResponse setError (String msg) {
- this.err = 699;
- this.errstr = msg;
- return this;
- };
-
- public KorapResponse setErrstr (String msg) {
- this.errstr = msg;
- return this;
- };
-
- public String getErrstr () {
- return this.errstr;
- };
-
- public KorapResponse setErr (int num) {
- this.err = num;
- return this;
- };
-
- public int getErr () {
- return this.err;
- };
-
- public KorapResponse setMsg (String msg) {
- this.msg = msg;
- return this;
- };
-
- public String getMsg () {
- return this.msg;
- };
-
- public String getVersion () {
- return this.version;
- };
-
- public KorapResponse setVersion (String version) {
- this.version = version;
- return this;
- };
-
- public String getNode () {
- return this.node;
- };
-
- public KorapResponse setNode (String name) {
- this.node = name;
- return this;
- };
-
- public KorapResponse setTotalTexts (long i) {
- this.totalTexts = i;
- return this;
- };
-
- public long getTotalTexts() {
- return this.totalTexts;
- };
-
- public KorapResponse setTotalResults (int i) {
- this.totalResults = i;
- return this;
- };
-
- public KorapResponse incrTotalResults (int i) {
- this.totalResults += i;
- return this;
- };
-
-
- public int getTotalResults() {
- return this.totalResults;
- };
-
- @JsonIgnore
- public KorapResponse setBenchmark (long t1, long t2) {
- this.benchmark =
- (t2 - t1) < 100_000_000 ? (((double) (t2 - t1) * 1e-6) + " ms") :
- (((double) (t2 - t1) / 1000000000.0) + " s");
- return this;
- };
-
- public KorapResponse setBenchmark (String bm) {
- this.benchmark = bm;
- return this;
- };
-
- public String getBenchmark () {
- return this.benchmark;
- };
-
- public KorapResponse setListener (String listener) {
- this.listener = listener;
- return this;
- };
-
- public String getListener () {
- return this.listener;
- }
-
- // Serialize
- public String toJSON () {
- ObjectNode json = (ObjectNode) mapper.valueToTree(this);
- if (json.size() == 0)
- return "{}";
-
- try {
- return mapper.writeValueAsString(json);
- }
- catch (Exception e) {
- this.errstr = e.getLocalizedMessage();
- };
-
- return "{\"errstr\" : \"" + this.errstr + "\"}";
- };
-};
diff --git a/src/main/java/de/ids_mannheim/korap/server/Resource.java b/src/main/java/de/ids_mannheim/korap/server/Resource.java
index 1630bbc..6a663ae 100644
--- a/src/main/java/de/ids_mannheim/korap/server/Resource.java
+++ b/src/main/java/de/ids_mannheim/korap/server/Resource.java
@@ -26,7 +26,7 @@
import de.ids_mannheim.korap.KorapCollection;
import de.ids_mannheim.korap.KorapMatch;
import de.ids_mannheim.korap.KorapResult;
-import de.ids_mannheim.korap.server.KorapResponse;
+import de.ids_mannheim.korap.response.KorapResponse;
import de.ids_mannheim.korap.index.FieldDocument;
import de.ids_mannheim.korap.util.QueryException;
import de.ids_mannheim.korap.index.MatchCollector;
@@ -87,13 +87,21 @@
@Produces(MediaType.APPLICATION_JSON)
public String info () {
KorapIndex index = KorapNode.getIndex();
- KorapResponse kresp = new KorapResponse(KorapNode.getName(), index.getVersion());
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+ kresp.setName(index.getName());
+ kresp.setVersion(index.getVersion());
+
kresp.setListener(KorapNode.getListener());
long texts = -1;
-
- return kresp.setTotalTexts(index.numberOf("documents"))
- .setMsg("Up and running!")
- .toJSON();
+ /*
+ kresp.addMessage(
+ "Number of documents in the index",
+ String.parseLong(index.numberOf("documents"))
+ );
+ */
+ kresp.addMessage(680, "Server is up and running!");
+ return kresp.toJSON();
};
@@ -123,10 +131,17 @@
// Get index
KorapIndex index = KorapNode.getIndex();
- KorapResponse kresp = new KorapResponse(KorapNode.getName(), index.getVersion());
- if (index == null)
- return kresp.setError(601, "Unable to find index").toJSON();
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+
+ if (index == null) {
+ kresp.addError(601, "Unable to find index");
+ return kresp.toJSON();
+ };
+
+ kresp.setVersion(index.getVersion());
+ kresp.setName(index.getName());
String ID = "Unknown";
try {
@@ -134,15 +149,15 @@
ID = fd.getID();
}
// Set HTTP to ???
+ // TODO: This may be a field error!
catch (IOException e) {
-
- return kresp.setErrstr(e.getLocalizedMessage()).toJSON();
+ kresp.addError(602, "Unable to add document to index");
+ return kresp.toJSON();
};
// Set HTTP to 200
- return kresp.
- setMsg("Text \"" + ID + "\" was added successfully")
- .toJSON();
+ kresp.addMessage(681, "Document was added successfully", ID);
+ return kresp.toJSON();
};
@@ -157,13 +172,16 @@
// Get index
KorapIndex index = KorapNode.getIndex();
- KorapResponse kresp = new KorapResponse(KorapNode.getName(), index.getVersion());
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
- if (index == null)
- return kresp.setError(601, "Unable to find index").toJSON();
+ if (index == null) {
+ kresp.addError(601, "Unable to find index");
+ return kresp.toJSON();
+ };
- if (version == null)
- version = index.getVersion();
+ kresp.setVersion(index.getVersion());
+ kresp.setName(index.getName());
// There are documents to commit
try {
@@ -171,7 +189,8 @@
}
catch (IOException e) {
// Set HTTP to ???
- return kresp.setErrstr(e.getMessage()).toJSON();
+ kresp.addError(603, "Unable to commit staged data to index");
+ return kresp.toJSON();
};
// Set HTTP to ???
@@ -219,14 +238,18 @@
};
KorapResult kr = new KorapResult();
kr.setNode(KorapNode.getName());
- kr.setError(610, "No UUIDs given");
+ kr.addError(610, "Missing request parameters", "No unique IDs were given");
return kr.toJSON();
};
- return new KorapResponse(
- KorapNode.getName(),
- index.getVersion()
- ).setError(601, "Unable to find index").toJSON();
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+ kresp.setName(index.getName());
+ kresp.setVersion(index.getVersion());
+
+ kresp.addError(601, "Unable to find index");
+
+ return kresp.toJSON();
};
@@ -247,11 +270,12 @@
KorapIndex index = KorapNode.getIndex();
// No index found
- if (index == null)
- return new KorapResponse(
- KorapNode.getName(),
- index.getVersion()
- ).setError(601, "Unable to find index").toJSON();
+ if (index == null) {
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+ kresp.addError(601, "Unable to find index");
+ return kresp.toJSON();
+ };
// Get the database
try {
@@ -271,10 +295,13 @@
log.error(e.getLocalizedMessage());
};
- return new KorapResponse(
- KorapNode.getName(),
- index.getVersion()
- ).setError("Unable to connect to database").toJSON();
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+ kresp.setName(index.getName());
+ kresp.setVersion(index.getVersion());
+
+ kresp.addError(604, "Unable to connect to database");
+ return kresp.toJSON();
};
@@ -307,10 +334,13 @@
return kr.toJSON();
};
- return new KorapResponse(
- KorapNode.getName(),
- index.getVersion()
- ).setError(601, "Unable to find index").toJSON();
+ KorapResponse kresp = new KorapResponse();
+ kresp.setNode(KorapNode.getName());
+ kresp.setName(index.getName());
+ kresp.setVersion(index.getVersion());
+
+ kresp.addError(601, "Unable to find index");
+ return kresp.toJSON();
};
@GET
@@ -373,14 +403,14 @@
catch (QueryException qe) {
// Todo: Make KorapMatch rely on KorapResponse!
KorapMatch km = new KorapMatch();
- km.setError(qe.getMessage());
+ km.addError(qe.getErrorCode(), qe.getMessage());
return km.toJSON();
}
};
// Response with error message
KorapMatch km = new KorapMatch();
- km.setError("Index not found");
+ km.addError(601, "Unable to find index");
return km.toJSON();
};
diff --git a/src/main/java/de/ids_mannheim/korap/util/KorapString.java b/src/main/java/de/ids_mannheim/korap/util/KorapString.java
index 1a653de..2922425 100644
--- a/src/main/java/de/ids_mannheim/korap/util/KorapString.java
+++ b/src/main/java/de/ids_mannheim/korap/util/KorapString.java
@@ -13,11 +13,19 @@
*/
public class KorapString {
- public static String StringfromFile(String path, Charset encoding) throws IOException {
+ /**
+ * Get String from file
+ */
+ public static String StringfromFile (String path, Charset encoding)
+ throws IOException {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
};
+
+ /**
+ * Get String from file
+ */
public static String StringfromFile (String path) throws IOException {
return StringfromFile(path, StandardCharsets.UTF_8);
};
diff --git a/src/main/java/de/ids_mannheim/korap/util/QueryException.java b/src/main/java/de/ids_mannheim/korap/util/QueryException.java
index c4ed26b..dc9d002 100644
--- a/src/main/java/de/ids_mannheim/korap/util/QueryException.java
+++ b/src/main/java/de/ids_mannheim/korap/util/QueryException.java
@@ -18,8 +18,7 @@
public QueryException(Throwable cause) {
super(cause);
- };
-
+ };
public QueryException(int code, String message) {
super(message);
diff --git a/src/main/resources/index.properties b/src/main/resources/index.properties
index f9ecaaf..1c87567 100644
--- a/src/main/resources/index.properties
+++ b/src/main/resources/index.properties
@@ -1,4 +1,5 @@
-lucene.index.version = ${project.version}
+lucene.version = ${project.version}
+lucene.name = ${project.name}
lucene.index.commit.count = 134217000
lucene.index.commit.log = log/korap.commit.log
lucene.indexDir = /home/ndiewald/Repositories/korap/KorAP-modules/KorAP-lucene-index/sandbox/index-tanja