commit b92ca8a1aec86a440acc1f46c2d8e5c7517e083f parent 4e6988d678b18170a3300b968eb271333abf03a5 Author: Dan Callaghan <djc@djc.id.au> Date: Sun, 4 Apr 2010 12:25:38 +1000 move instantiation of Adaptations from the parser into the AdaptationFactory, to allow for Spring prototype beans --HG-- rename : src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationResolver.java => src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java rename : src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationResolver.java => src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java Diffstat:
15 files changed, 162 insertions(+), 147 deletions(-) diff --git a/src/main/antlr3/au/com/miskinhill/rdftemplate/selector/Selector.g b/src/main/antlr3/au/com/miskinhill/rdftemplate/selector/Selector.g @@ -12,12 +12,12 @@ import java.util.Map; throw new InvalidSelectorSyntaxException(e); } - private AdaptationResolver adaptationResolver; + private AdaptationFactory adaptationFactory; private PredicateResolver predicateResolver; private Map<String, String> namespacePrefixMap; - public void setAdaptationResolver(AdaptationResolver adaptationResolver) { - this.adaptationResolver = adaptationResolver; + public void setAdaptationFactory(AdaptationFactory adaptationFactory) { + this.adaptationFactory = adaptationFactory; } public void setPredicateResolver(PredicateResolver predicateResolver) { @@ -71,7 +71,6 @@ unionSelector returns [Selector<?> result] selector returns [Selector<?> result] @init { - Class<? extends Adaptation<?>> adaptationClass; Adaptation<?> adaptation = null; } : ( ts=traversingSelector { result = ts; } @@ -80,36 +79,18 @@ selector returns [Selector<?> result] ( '#' adaptationName=XMLTOKEN { - adaptationClass = adaptationResolver.getByName($adaptationName.text); - if (adaptationClass == null) - throw new InvalidSelectorSyntaxException("No adaptation named " + $adaptationName.text); + adaptation = adaptationFactory.getByName($adaptationName.text); } ( '(' ( startIndex=INTEGER { - try { - adaptation = adaptationClass.getConstructor(Integer.class) - .newInstance(Integer.parseInt($startIndex.text)); - } catch (Exception e) { - throw new InvalidSelectorSyntaxException(e); - } + adaptation.setArgs(new Object[] { Integer.parseInt($startIndex.text) }); } | sq=SINGLE_QUOTED { - try { - adaptation = adaptationClass.getConstructor(String.class) - .newInstance($sq.text); - } catch (Exception e) { - throw new InvalidSelectorSyntaxException(e); - } + adaptation.setArgs(new Object[] { $sq.text }); } ) ')' - | { - try { - adaptation = adaptationClass.newInstance(); - } catch (Exception e) { - throw new InvalidSelectorSyntaxException(e); - } - } + | ) { $result = new SelectorWithAdaptation(result, adaptation); } | diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractAdaptation.java @@ -0,0 +1,58 @@ +package au.com.miskinhill.rdftemplate.selector; + +import java.util.Arrays; + +import com.hp.hpl.jena.rdf.model.RDFNode; + +public abstract class AbstractAdaptation<DestType, NodeType extends RDFNode> implements Adaptation<DestType> { + + private final Class<DestType> destinationType; + private final Class<?>[] argTypes; + private final Class<NodeType> nodeType; + + protected AbstractAdaptation(Class<DestType> destinationType, Class<?>[] argTypes, Class<NodeType> nodeType) { + this.destinationType = destinationType; + this.argTypes = argTypes; + this.nodeType = nodeType; + } + + @Override + public Class<DestType> getDestinationType() { + return destinationType; + } + + @Override + public Class<?>[] getArgTypes() { + return argTypes; + } + + @Override + public void setArgs(Object[] args) { + if (args.length != argTypes.length) + throw new SelectorEvaluationException("Expected args of types " + Arrays.toString(argTypes) + + " but invoked with " + Arrays.toString(args)); + for (int i = 0; i < args.length; i ++) { + if (!argTypes[i].isAssignableFrom(args[i].getClass())) + throw new SelectorEvaluationException("Arg " + i + ": expected type " + argTypes[i] + + " but was " + args[i].getClass()); + } + setCheckedArgs(args); + } + + protected void setCheckedArgs(Object[] args) { + throw new UnsupportedOperationException(); + } + + @Override + public DestType adapt(RDFNode node) { + if (!nodeType.equals(RDFNode.class)) { + if (!node.canAs(nodeType)) + throw new SelectorEvaluationException("Adaptation can only be applied to " + nodeType + + " but was applied to " + node); + } + return doAdapt(node.as(nodeType)); + } + + protected abstract DestType doAdapt(NodeType node); + +} diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/Adaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/Adaptation.java @@ -6,6 +6,10 @@ public interface Adaptation<T> { Class<T> getDestinationType(); + Class<?>[] getArgTypes(); + + void setArgs(Object[] args); + T adapt(RDFNode node); } diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java @@ -0,0 +1,7 @@ +package au.com.miskinhill.rdftemplate.selector; + +public interface AdaptationFactory { + + Adaptation<?> getByName(String name); + +} diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationResolver.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationResolver.java @@ -1,7 +0,0 @@ -package au.com.miskinhill.rdftemplate.selector; - -public interface AdaptationResolver { - - Class<? extends Adaptation<?>> getByName(String name); - -} diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AntlrSelectorFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AntlrSelectorFactory.java @@ -10,15 +10,15 @@ import org.antlr.runtime.RecognitionException; public class AntlrSelectorFactory implements SelectorFactory { - private AdaptationResolver adaptationResolver = new DefaultAdaptationResolver(); + private AdaptationFactory adaptationFactory = new DefaultAdaptationFactory(); private PredicateResolver predicateResolver = new DefaultPredicateResolver(); private Map<String, String> namespacePrefixMap = Collections.emptyMap(); public AntlrSelectorFactory() { } - public void setAdaptationResolver(AdaptationResolver adaptationResolver) { - this.adaptationResolver = adaptationResolver; + public void setAdaptationFactory(AdaptationFactory adaptationFactory) { + this.adaptationFactory = adaptationFactory; } public void setPredicateResolver(PredicateResolver predicateResolver) { @@ -35,7 +35,7 @@ public class AntlrSelectorFactory implements SelectorFactory { SelectorLexer lexer = new SelectorLexer(stream); CommonTokenStream tokens = new CommonTokenStream(lexer); SelectorParser parser = new SelectorParser(tokens); - parser.setAdaptationResolver(adaptationResolver); + parser.setAdaptationFactory(adaptationFactory); parser.setPredicateResolver(predicateResolver); parser.setNamespacePrefixMap(namespacePrefixMap); try { diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/ComparableLiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/ComparableLiteralValueAdaptation.java @@ -1,21 +1,17 @@ package au.com.miskinhill.rdftemplate.selector; import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.RDFNode; -public class ComparableLiteralValueAdaptation implements Adaptation<Comparable> { +@SuppressWarnings("unchecked") +public class ComparableLiteralValueAdaptation extends AbstractAdaptation<Comparable, Literal> { - @Override - public Class<Comparable> getDestinationType() { - return Comparable.class; + public ComparableLiteralValueAdaptation() { + super(Comparable.class, new Class<?>[] { }, Literal.class); } - + @Override - public Comparable<?> adapt(RDFNode node) { - if (!node.isLiteral()) { - throw new SelectorEvaluationException("Attempted to apply #comparable-lv to non-literal node " + node); - } - Object literalValue = ((Literal) node).getValue(); + protected Comparable<?> doAdapt(Literal node) { + Object literalValue = node.getValue(); if (!(literalValue instanceof Comparable<?>)) { throw new SelectorEvaluationException("Attempted to apply #comparable-lv to non-Comparable node " + node + " with literal value of type " + literalValue.getClass()); diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java @@ -0,0 +1,30 @@ +package au.com.miskinhill.rdftemplate.selector; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.BeanUtils; + +public class DefaultAdaptationFactory implements AdaptationFactory { + + private static final Map<String, Class<? extends Adaptation<?>>> ADAPTATIONS = new HashMap<String, Class<? extends Adaptation<?>>>(); + static { + ADAPTATIONS.put("uri", UriAdaptation.class); + ADAPTATIONS.put("uri-slice", UriSliceAdaptation.class); + ADAPTATIONS.put("uri-anchor", UriAnchorAdaptation.class); + ADAPTATIONS.put("lv", LiteralValueAdaptation.class); + ADAPTATIONS.put("comparable-lv", ComparableLiteralValueAdaptation.class); + ADAPTATIONS.put("string-lv", StringLiteralValueAdaptation.class); + ADAPTATIONS.put("formatted-dt", FormattedDateTimeAdaptation.class); + } + + @Override + public Adaptation<?> getByName(String name) { + Class<? extends Adaptation<?>> adaptationClass = ADAPTATIONS.get(name); + if (adaptationClass == null) { + throw new InvalidSelectorSyntaxException("No adaptation named " + name); + } + return BeanUtils.instantiate(adaptationClass); + } + +} diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationResolver.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationResolver.java @@ -1,24 +0,0 @@ -package au.com.miskinhill.rdftemplate.selector; - -import java.util.HashMap; -import java.util.Map; - -public class DefaultAdaptationResolver implements AdaptationResolver { - - private static final Map<String, Class<? extends Adaptation<?>>> ADAPTATIONS = new HashMap<String, Class<? extends Adaptation<?>>>(); - static { - ADAPTATIONS.put("uri", UriAdaptation.class); - ADAPTATIONS.put("uri-slice", UriSliceAdaptation.class); - ADAPTATIONS.put("uri-anchor", UriAnchorAdaptation.class); - ADAPTATIONS.put("lv", LiteralValueAdaptation.class); - ADAPTATIONS.put("comparable-lv", ComparableLiteralValueAdaptation.class); - ADAPTATIONS.put("string-lv", StringLiteralValueAdaptation.class); - ADAPTATIONS.put("formatted-dt", FormattedDateTimeAdaptation.class); - } - - @Override - public Class<? extends Adaptation<?>> getByName(String name) { - return ADAPTATIONS.get(name); - } - -} diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/FormattedDateTimeAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/FormattedDateTimeAdaptation.java @@ -1,21 +1,25 @@ package au.com.miskinhill.rdftemplate.selector; import org.apache.commons.lang.builder.ToStringBuilder; - -import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.RDFNode; import org.joda.time.ReadableInstant; import org.joda.time.ReadablePartial; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; -public class FormattedDateTimeAdaptation implements Adaptation<String> { +import com.hp.hpl.jena.rdf.model.Literal; + +public class FormattedDateTimeAdaptation extends AbstractAdaptation<String, Literal> { + + private String pattern; + private DateTimeFormatter formatter; - private final String pattern; - private final DateTimeFormatter formatter; + public FormattedDateTimeAdaptation() { + super(String.class, new Class<?>[] { String.class }, Literal.class); + } - public FormattedDateTimeAdaptation(String pattern) { - this.pattern = pattern; + @Override + protected void setCheckedArgs(Object[] args) { + this.pattern = (String) args[0]; this.formatter = DateTimeFormat.forPattern(pattern.replace("\"", "'")); // for convenience in XML } @@ -24,16 +28,8 @@ public class FormattedDateTimeAdaptation implements Adaptation<String> { } @Override - public Class<String> getDestinationType() { - return String.class; - } - - @Override - public String adapt(RDFNode node) { - if (!node.isLiteral()) { - throw new SelectorEvaluationException("Attempted to apply #formatted-dt to non-literal node " + node); - } - Object lv = ((Literal) node).getValue(); + protected String doAdapt(Literal node) { + Object lv = node.getValue(); if (lv instanceof ReadableInstant) { ReadableInstant instant = (ReadableInstant) lv; return formatter.print(instant); diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/LiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/LiteralValueAdaptation.java @@ -1,21 +1,16 @@ package au.com.miskinhill.rdftemplate.selector; import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.RDFNode; -public class LiteralValueAdaptation implements Adaptation<Object> { +public class LiteralValueAdaptation extends AbstractAdaptation<Object, Literal> { - @Override - public Class<Object> getDestinationType() { - return Object.class; + public LiteralValueAdaptation() { + super(Object.class, new Class<?>[] { }, Literal.class); } - + @Override - public Object adapt(RDFNode node) { - if (!node.isLiteral()) { - throw new SelectorEvaluationException("Attempted to apply #lv to non-literal node " + node); - } - return ((Literal) node).getValue(); + protected Object doAdapt(Literal node) { + return node.getValue(); } } diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/StringLiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/StringLiteralValueAdaptation.java @@ -8,23 +8,17 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import com.hp.hpl.jena.rdf.model.Literal; -import com.hp.hpl.jena.rdf.model.RDFNode; -public class StringLiteralValueAdaptation implements Adaptation<String> { +public class StringLiteralValueAdaptation extends AbstractAdaptation<String, Literal> { private static final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - @Override - public Class<String> getDestinationType() { - return String.class; + public StringLiteralValueAdaptation() { + super(String.class, new Class<?>[] { }, Literal.class); } - + @Override - public String adapt(RDFNode node) { - if (!node.isLiteral()) { - throw new SelectorEvaluationException("Attempted to apply #lv to non-literal node " + node); - } - Literal literal = node.as(Literal.class); + protected String doAdapt(Literal literal) { if (literal.isWellFormedXML()) { try { return stripTags(literal.getLexicalForm()); diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAdaptation.java @@ -2,21 +2,15 @@ package au.com.miskinhill.rdftemplate.selector; import com.hp.hpl.jena.rdf.model.Resource; -import com.hp.hpl.jena.rdf.model.RDFNode; - -public class UriAdaptation implements Adaptation<String> { +public class UriAdaptation extends AbstractAdaptation<String, Resource> { - @Override - public Class<String> getDestinationType() { - return String.class; + public UriAdaptation() { + super(String.class, new Class<?>[] { }, Resource.class); } @Override - public String adapt(RDFNode node) { - if (!node.isResource()) { - throw new SelectorEvaluationException("Attempted to apply #uri to non-resource node " + node); - } - return ((Resource) node).getURI(); + protected String doAdapt(Resource node) { + return node.getURI(); } } diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptation.java @@ -1,25 +1,20 @@ package au.com.miskinhill.rdftemplate.selector; -import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; /** * Returns the anchor component of the node's URI (excluding initial #), or the * empty string if it has no anchor component. */ -public class UriAnchorAdaptation implements Adaptation<String> { +public class UriAnchorAdaptation extends AbstractAdaptation<String, Resource> { - @Override - public Class<String> getDestinationType() { - return String.class; + public UriAnchorAdaptation() { + super(String.class, new Class<?>[] { }, Resource.class); } - + @Override - public String adapt(RDFNode node) { - if (!node.isResource()) { - throw new SelectorEvaluationException("Attempted to apply #uri-anchor to non-resource node " + node); - } - String uri = ((Resource) node).getURI(); + protected String doAdapt(Resource node) { + String uri = node.getURI(); int hashIndex = uri.lastIndexOf('#'); if (hashIndex < 0) return ""; diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriSliceAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriSliceAdaptation.java @@ -1,14 +1,13 @@ package au.com.miskinhill.rdftemplate.selector; -import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.Resource; -public class UriSliceAdaptation implements Adaptation<String> { +public class UriSliceAdaptation extends AbstractAdaptation<String, Resource> { - private final Integer startIndex; + private Integer startIndex; - public UriSliceAdaptation(Integer startIndex) { - this.startIndex = startIndex; + public UriSliceAdaptation() { + super(String.class, new Class<?>[] { Integer.class }, Resource.class); } public Integer getStartIndex() { @@ -16,16 +15,13 @@ public class UriSliceAdaptation implements Adaptation<String> { } @Override - public Class<String> getDestinationType() { - return String.class; + protected void setCheckedArgs(Object[] args) { + this.startIndex = (Integer) args[0]; } - + @Override - public String adapt(RDFNode node) { - if (!node.isResource()) { - throw new SelectorEvaluationException("Attempted to apply #uri-slice to non-resource node " + node); - } - String uri = ((Resource) node).getURI(); + protected String doAdapt(Resource node) { + String uri = node.getURI(); return uri.substring(startIndex); }