Skip to content

Commit

Permalink
more on validation
Browse files Browse the repository at this point in the history
  • Loading branch information
michelegonella committed Sep 27, 2012
1 parent eb5bd91 commit fc8446d
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ output = AST;
}

tokens {
OBJECT;ARRAY;NAME;ENTRY;PRIMITIVE;VALUECHOICE;VALUESEQ;ENTRYSEQ;TYPEDEF;TYPEREF;
OBJECT;ARRAY;NAME;ENTRY;PRIMITIVE;VALUECHOICE;VALUESEQ;ENTRYSEQ;TYPEDEF;TYPEREF;EXISTENTIAL;
}

@header {
Expand Down Expand Up @@ -100,9 +100,9 @@ entry
;
lval
: LvalTkn
-> ^(NAME LvalTkn)
-> ^(NAME LvalTkn) EXISTENTIAL
| LvalTkn ExistentialTkn
-> ^(NAME LvalTkn ExistentialTkn)
-> ^(NAME LvalTkn) ^(EXISTENTIAL ExistentialTkn)
;
ExistentialTkn
: '!?'|'?!'|'!'|'?'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,60 +15,75 @@
*/
package com.nominanuda.dataobject.schema;

import java.nio.channels.IllegalSelectorException;
import java.util.Stack;

import com.nominanuda.dataobject.JsonContentHandler;

public abstract class EventConsumer implements JsonContentHandler {
private final Stack<EventConsumer> stack;
private ExistentialPredicate predicate;

public EventConsumer(Stack<EventConsumer> stack) {
this.stack = stack;
this.predicate = new ExistentialPredicate();
}

public EventConsumer(Stack<EventConsumer> stack, ExistentialPredicate predicate) {
this.stack = stack;
this.predicate = predicate;
}

public boolean isOptional() {
return predicate.isOptional();
}
public boolean isNullable() {
return predicate.isNullable();
}

@Override
public void startJSON() throws RuntimeException {
throw new UnsupportedOperationException();
throw new IllegalStateException();
}

@Override
public void endJSON() throws RuntimeException {
throw new UnsupportedOperationException();
throw new IllegalStateException();
}

@Override
public boolean startObject() throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected start of object");
}

@Override
public boolean endObject() throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected end of object");
}

@Override
public boolean startObjectEntry(String key) throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected start of object entry with key:"+key);
}

@Override
public boolean endObjectEntry() throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected end of object entry");
}

@Override
public boolean startArray() throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected start of array");
}

@Override
public boolean endArray() throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected end of array");
}

@Override
public boolean primitive(Object value) throws RuntimeException {
throw new UnsupportedOperationException();
throw new ValidationException("unespected primitive value "+value);
}

protected void pop() {
Expand All @@ -77,4 +92,8 @@ protected void pop() {
protected void push(EventConsumer c) {
stack.push(c);
}

public void setPredicate(ExistentialPredicate predicate) {
this.predicate = predicate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.nominanuda.dataobject.schema;

import com.nominanuda.code.Nullable;

public class ExistentialPredicate {
private boolean optional = false;
private boolean nullable = true;

public ExistentialPredicate(@Nullable String p) {
if(p != null) {
optional = p.contains("?");
nullable = !p.contains("!");
}
}

public ExistentialPredicate() {
}

public boolean isOptional() {
return optional;
}

public boolean isNullable() {
return nullable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
package com.nominanuda.dataobject.schema;

import java.io.StringReader;
import java.nio.channels.IllegalSelectorException;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;

import org.antlr.runtime.ANTLRReaderStream;
Expand All @@ -28,6 +30,7 @@
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

import com.nominanuda.code.Nullable;
import com.nominanuda.dataobject.JsonContentHandler;
import com.nominanuda.dataobject.WrappingRecognitionException;
import com.nominanuda.dataobject.transform.BaseJsonTransformer;
Expand Down Expand Up @@ -105,7 +108,8 @@ private EventConsumer makeConsumer(Tree node, Stack<EventConsumer> stack) {
for(int i = 0; i < node.getChildCount(); i++) {
Tree entry = node.getChild(i);
if(entry.getType() == ENTRY) {
EventConsumer c = makeConsumer(entry.getChild(1), stack);
EventConsumer c = makeConsumer(entry.getChild(2), stack);
c.setPredicate(tokenToPredicate(entry.getChild(1)));
String key = entry.getChild(0).getChild(0).getText();
entryConsumers.put(key, c);
} else if(entry.getType() == ENTRYSEQ) {
Expand Down Expand Up @@ -133,6 +137,11 @@ private EventConsumer makeConsumer(Tree node, Stack<EventConsumer> stack) {
}
}

private ExistentialPredicate tokenToPredicate(Tree predTnkNode) {
String p = predTnkNode.getChildCount() > 0 ? predTnkNode.getChild(0).getText() : null;
return new ExistentialPredicate(p);
}

private Fun1<Object, String> makePrimitiveValidator(Tree node) {
Tree t = node.getChild(0);
String typeDef = t == null
Expand All @@ -156,16 +165,48 @@ public boolean startObject() throws RuntimeException {

@Override
public boolean endObject() throws RuntimeException {
//TODO validate
validateExit();
pop();
return true;
}

@Override
public boolean primitive(Object value) throws RuntimeException {
if(value == null) {
if(! isNullable()) {
throw new ValidationException("null value of not-nul property");
} else {
return true;
}
} else {
throw new ValidationException("found "+value.toString()+" where object expected");
}
}
private void validateExit() {
for(Entry<String,EventConsumer> e : entryConsumers.entrySet()) {
String k = e.getKey();
EventConsumer c = e.getValue();
if(! isEntrySequence(k)) {
if(! c.isOptional()) {
throw new ValidationException("missing property:"+k);
}
}
}

}

private boolean isEntrySequence(String k) {
return "*".equals(k);
}

@Override
public boolean startObjectEntry(String key) throws RuntimeException {
EventConsumer c = entryConsumers.remove(key);
if(c == null && entryConsumers.size() == 1 && entryConsumers.containsKey("*")) {
c = entryConsumers.values().iterator().next();
if(c == null && entryConsumers.containsKey("*")) {
c = entryConsumers.get("*");
}
if(c == null) {
throw new ValidationException("unexpected entry with key "+key);
}
push(Check.notNull(c));
return true;
Expand All @@ -189,33 +230,56 @@ public ArrayConsumer(Stack<EventConsumer> stack, List<EventConsumer> elementsCon

@Override
public boolean primitive(Object value) throws RuntimeException {
nextConsumer().primitive(value);
EventConsumer c = pushNextConsumer();
c.primitive(value);
return true;
}

private EventConsumer pushNextConsumer() {
EventConsumer c = nextConsumer();
if(c == null) {
throw new ValidationException("wrong number of elements in array, at position "+i);
}
push(c);
return c;
}

@Override
public boolean startObject() throws RuntimeException {
push(nextConsumer());
EventConsumer c = pushNextConsumer();
c.startObject();
return true;
}

private boolean startArraySeen = false;
@Override
public boolean startArray() throws RuntimeException {
push(nextConsumer());
if(startArraySeen) {
EventConsumer c = pushNextConsumer();
c.startArray();
} else {
startArraySeen = true;
}
return true;
}

@Override
public boolean endArray() throws RuntimeException {
pop();
Check.illegalargument.assertEquals(i, elementsConsumers.size());
if(i != elementsConsumers.size()) {
throw new ValidationException("array expected "+elementsConsumers.size()+" elements, but got "+i);
}
return true;
}

private EventConsumer nextConsumer() {
EventConsumer c = elementsConsumers.get(i);
i++;
return c;
private @Nullable EventConsumer nextConsumer() {
if(i >= elementsConsumers.size()) {
return null;
} else {
EventConsumer c = elementsConsumers.get(i);
i++;
return c;
}
}
}

Expand Down Expand Up @@ -315,13 +379,22 @@ public PrimitiveConsumer(Stack<EventConsumer> stack, Fun1<Object, String> valida

@Override
public boolean primitive(Object value) throws RuntimeException {
String errorMessage = validator.apply(value);
if(errorMessage != null) {
throw new IllegalArgumentException(errorMessage);
if(value == null) {
if(! isNullable()) {
throw new ValidationException("null value of not-nul property");
} else {
return true;
}
} else {
String errorMessage = validator.apply(value);
if(errorMessage != null) {
throw new ValidationException(errorMessage);
}
pop();
return true;
}
pop();
return true;
}

}

public void setPrimitiveValidatorFactory(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nominanuda.dataobject.schema;

public class ValidationException extends RuntimeException {
public ValidationException(String msg) {
super(msg);
}

private static final long serialVersionUID = -451542828562571309L;

}
Loading

0 comments on commit fc8446d

Please sign in to comment.