From d914372597d1d2b0296d8fb01e1d95989f42c670 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Sun, 25 Nov 2018 18:19:34 +0000 Subject: [PATCH] JENA-1639: Model.getList and Statement.getList --- .../java/org/apache/jena/rdf/model/Model.java | 8 +- .../org/apache/jena/rdf/model/ModelCon.java | 34 +++- .../org/apache/jena/rdf/model/Statement.java | 6 + .../apache/jena/rdf/model/impl/ModelCom.java | 12 +- .../jena/rdf/model/impl/StatementImpl.java | 5 + .../apache/jena/rdf/model/test/TestList.java | 171 ++++++------------ .../jena/permissions/model/SecuredModel.java | 28 ++- .../model/impl/SecuredModelImpl.java | 44 +++-- .../model/impl/SecuredStatementImpl.java | 18 +- 9 files changed, 174 insertions(+), 152 deletions(-) diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/Model.java b/jena-core/src/main/java/org/apache/jena/rdf/model/Model.java index 924256d4cff..9c972297842 100644 --- a/jena-core/src/main/java/org/apache/jena/rdf/model/Model.java +++ b/jena-core/src/main/java/org/apache/jena/rdf/model/Model.java @@ -287,7 +287,6 @@ will be equal to any other bnode with the same AnonId (even if they are in */ public RDFList createList(); - /** *

Answer a new list containing the resources from the given iterator, in order.

* @param members An iterator, each value of which is expected to be an RDFNode @@ -297,11 +296,14 @@ will be equal to any other bnode with the same AnonId (even if they are in /** - *

Answer a new list containing the nodes from the given array, in order

+ *

Answer a new list containing the nodes from the given eleemnts, in order. + * If the list of elements is empty, until the list is made the object or subject in the model, or has an element added, + * it will not appear in the model (e.g. when written out). + * * @param members An array of RDF nodes that will be the members of the list * @return An RDF-encoded list */ - public RDFList createList( RDFNode[] members ); + public RDFList createList( RDFNode... members ); /** Add a statement to this model. diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/ModelCon.java b/jena-core/src/main/java/org/apache/jena/rdf/model/ModelCon.java index 0a30710dd8d..949d28fcf5e 100644 --- a/jena-core/src/main/java/org/apache/jena/rdf/model/ModelCon.java +++ b/jena-core/src/main/java/org/apache/jena/rdf/model/ModelCon.java @@ -111,16 +111,17 @@ public interface ModelCon { * It is in effect an unsafe downcast.

* *

Subsequent operations on the returned Alt may modify this model.

- *

The bag is assumed to already exist in the model. If it does not, + *

The Alt is assumed to already exist in the model. If it does not, * createAlt should be used instead.

* @return an Alt instance * @param r an untyped Resource instance */ Alt getAlt(Resource r) ; + /** Return a Seq instance in this model. * - *

Subsequent operations on the returned bag may modify this model.

+ *

Subsequent operations on the returned sequence may modify this model.

*

The seq is assumed to already exist in the model. If it does not, * createSeq should be used instead.

* @return a seq instance @@ -128,7 +129,7 @@ public interface ModelCon { */ Seq getSeq(String uri) ; - + /** Return a Seq instance based on a given resource. * *

This method enables an application to treat any resource as a Seq. @@ -136,13 +137,36 @@ public interface ModelCon { * *

Subsequent operations on the returned Seq may modify this model.

*

The Seq is assumed to already exist in the model. If it does not, - * createAlt should be used instead.

- * @return an Alt instance + * createSeq should be used instead.

+ * @return an Seq instance * @param r an untyped Resource instance */ Seq getSeq(Resource r) ; +/** Return a RDF List instance in this model. + * + *

Subsequent operations on the returned list may modify this model.

+ *

The list is assumed to already exist in the model. If it does not, + * createList should be used instead.

+ * @return a list instance + * @param uri the URI of the list + */ + RDFList getList(String uri) ; + +/** Return a RDF List based on a given resource. + * + *

This method enables an application to treat any resource as a list. + * It is in effect an unsafe downcast.

+ * + *

Subsequent operations on the returned list may modify this model.

+ *

The list is assumed to already exist in the model. If it does not, + * createList should be used instead.

+ * @return a list instance + * @param r the resource of the list + */ + RDFList getList(Resource r) ; + /** Create a new anonymous resource with a given type. * *

Subsequent operations on the returned resource may modify this model. diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/Statement.java b/jena-core/src/main/java/org/apache/jena/rdf/model/Statement.java index 376659d759b..5568df0c46a 100644 --- a/jena-core/src/main/java/org/apache/jena/rdf/model/Statement.java +++ b/jena-core/src/main/java/org/apache/jena/rdf/model/Statement.java @@ -238,6 +238,12 @@ public interface Statement extends FrontsTriple */ public Seq getSeq() ; + /** Return the object of the statement as an RDF List. + *

An exception will be thrown if the object is not an {@link RDFList}.

+ * @return The object of the statement interpreted as a value as RDFList. + */ + public RDFList getList() ; + /** Return the language of the object of the statement. * *

An exception will be thrown if the object is not a Literal.

diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java index ab90d30675e..09124e28e28 100644 --- a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java +++ b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java @@ -876,13 +876,13 @@ public Seq createSeq() /** Answer a (the) new empty list + Until this is made the object or subject in the model, it will not appear in a written form. @return An RDF-encoded list of no elements (ie nil) */ @Override public RDFList createList() { return getResource( RDF.nil.getURI() ).as( RDFList.class ); } - /** *

Answer a new list containing the resources from the given iterator, in order.

* @param members An iterator, each value of which is expected to be an RDFNode. @@ -914,7 +914,7 @@ public RDFList createList( Iterator members ) * @return An RDF-encoded list */ @Override - public RDFList createList( RDFNode[] members ) { + public RDFList createList( RDFNode... members ) { return createList( Arrays.asList( members ).iterator() ); } @@ -953,6 +953,14 @@ public Bag getBag( String uri ) public Bag getBag( Resource r ) { return r.inModel( this ).as( Bag.class ); } + @Override + public RDFList getList( String uri ) + { return (RDFList)IteratorFactory.asResource( makeURI( uri ), RDFList.class, this ); } + + @Override + public RDFList getList( Resource r ) + { return r.inModel( this ).as( RDFList.class ); } + static private Node makeURI(String uri) { return uri == null ? NodeFactory.createBlankNode() : NodeFactory.createURI( uri ); } diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/StatementImpl.java b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/StatementImpl.java index e4a8f44b147..aa9b45ce4c3 100644 --- a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/StatementImpl.java +++ b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/StatementImpl.java @@ -129,6 +129,11 @@ public Seq getSeq() { return object.as( Seq.class ); } + @Override + public RDFList getList() { + return object.as( RDFList.class ); + } + /** it turns out to be handy to return the new StatementImpl as the result */ @Override protected StatementImpl replace( RDFNode n ) { StatementImpl s = new StatementImpl( subject, predicate, n, model ); diff --git a/jena-core/src/test/java/org/apache/jena/rdf/model/test/TestList.java b/jena-core/src/test/java/org/apache/jena/rdf/model/test/TestList.java index 826c3aa709e..87efc457e39 100644 --- a/jena-core/src/test/java/org/apache/jena/rdf/model/test/TestList.java +++ b/jena-core/src/test/java/org/apache/jena/rdf/model/test/TestList.java @@ -50,8 +50,7 @@ public class TestList extends AbstractModelTestBase public static final String NS = "uri:urn:x-rdf:test#"; /** Test that an iterator delivers the expected values */ - protected static void iteratorTest( final Iterator i, - final Object[] expected ) + protected static void iteratorTest( final Iterator i, final Object[] expected ) { final Logger logger = LoggerFactory.getLogger(TestList.class); final List expList = new ArrayList<>(); @@ -757,7 +756,6 @@ public void testTail() public void testValidity() { - final Resource root = model.createResource(TestList.NS + "root"); final Property p = model.createProperty(TestList.NS, "p"); @@ -783,125 +781,58 @@ public void testValidity() model.add(badList, RDF.rest, nil); checkValid("valid5", l1, true); + } + + public void testStmtGetList() + { + Resource root = model.createResource(TestList.NS + "root"); + Property p = model.createProperty(TestList.NS, "p"); + Resource r = model.createResource(TestList.NS + "r"); + Resource r1 = model.createResource(TestList.NS + "r1"); + Resource r2 = model.createResource(TestList.NS + "r2"); + + RDFList list0 = model.createList(r1, r2); + model.add(r, p, list0); + + Resource obj = model.listStatements(r, p, (Resource)null).next().getResource(); + + RDFList list1 = model.getList(obj); + + boolean b = list0.sameListAs(list1); + assertTrue("Different lists: expected: "+list0+" : got: "+list1, b); + } + + public void testModelGetList() + { + Resource root = model.createResource(TestList.NS + "root"); + Property p = model.createProperty(TestList.NS, "p"); + Resource r = model.createResource(TestList.NS + "r"); + Resource r1 = model.createResource(TestList.NS + "r1"); + Resource r2 = model.createResource(TestList.NS + "r2"); + + RDFList list0 = model.createList(r1, r2); + model.add(r, p, list0); + RDFList list1 = model.listStatements(r, p, (Resource)null).next().getList(); + + boolean b = list0.sameListAs(list1); + assertTrue("Different lists: expected: "+list0+" : got: "+list1, b); } - // public void testListSubclass() { - // String NS = "http://example.org/test#"; - // Resource a = model.createResource( NS + "a" ); - // Resource b = model.createResource( NS + "b" ); - // - // Resource cell0 = model.createResource(); - // Resource cell1 = model.createResource(); - // cell0.addProperty( RDF.first, a ); - // cell0.addProperty( RDF.rest, cell1 ); - // cell1.addProperty( RDF.first, b ); - // cell1.addProperty( RDF.rest, RDF.nil ); - // - // UserList ul = getUserListInstance(cell0); - // - // assertEquals( "User list length ", 2, ul.size() ); - // assertEquals( "head of user list ", a, ul.getHead() ); - // - // RDFList l = ul.as( RDFList.class ); - // assertNotNull( "RDFList facet of user-defined list subclass", l ); - // - // } - // - // /** A simple extension to RDFList to test user-subclassing of RDFList */ - // protected static interface UserList extends RDFList { - // } - // - // /** Impl of a simple extension to RDFList to test user-subclassing of - // RDFList */ - // protected static class UserListImpl extends RDFListImpl implements - // UserList { - // public UserListImpl( Node n, EnhGraph g ) { - // super( n, g ); - // } - // } - // - // public UserList getUserListInstance( Resource r ) - // { - // return new UserListImpl( r.asNode(), (EnhGraph) model ); - // } - // - // public void testUserDefinedList() { - // BuiltinPersonalities.model.add( UserDefList.class, - // UserDefListImpl.factoryForTests ); - // - // String NS = "http://example.org/test#"; - // Resource a = model.createResource( NS + "a" ); - // Resource b = model.createResource( NS + "b" ); - // - // Resource empty = model.createResource( UserDefListImpl.NIL.getURI() ); - // UserDefList ul = empty.as( UserDefList.class ); - // assertNotNull( "UserList facet of empty list", ul ); - // - // UserDefList ul0 = (UserDefList) ul.cons( b ); - // ul0 = (UserDefList) ul0.cons( a ); - // assertEquals( "should be length 2", 2, ul0.size() ); - // assertTrue( "first statement", model.contains( ul0, - // UserDefListImpl.FIRST, a ) ); - // } - // - // protected static interface UserDefList extends RDFList {} - // - // protected static class UserDefListImpl extends RDFListImpl implements - // UserDefList { - // @SuppressWarnings("hiding") public static final String NS = - // "http://example.org/testlist#"; - // public static final Property FIRST = ResourceFactory.createProperty( - // NS+"first" ); - // public static final Property REST = ResourceFactory.createProperty( - // NS+"rest" ); - // public static final Resource NIL = ResourceFactory.createResource( - // NS+"nil" ); - // public static final Resource LIST = ResourceFactory.createResource( - // NS+"List" ); - // - // /** - // * A factory for generating UserDefList facets from nodes in enhanced - // graphs. - // */ - // public static Implementation factoryForTests = new Implementation() { - // @Override public EnhNode wrap( Node n, EnhGraph eg ) { - // if (canWrap( n, eg )) { - // UserDefListImpl impl = new UserDefListImpl( n, eg ); - // - // Model model = impl.getModel(); - // impl.m_listFirst = FIRST.inModel( model ); - // impl.m_listRest = REST.inModel( model ); - // impl.m_listNil = NIL.inModel( model ); - // impl.m_listType = LIST.inModel( model ); - // - // return impl; - // } - // else { - // throw new JenaException( "Cannot convert node " + n + " to UserDefList"); - // } - // } - // - // @Override public boolean canWrap( Node node, EnhGraph eg ) { - // Graph g = eg.asGraph(); - // - // return node.equals( NIL.asNode() ) || - // g.contains( node, FIRST.asNode(), Node.ANY ) || - // g.contains( node, REST.asNode(), Node.ANY ) || - // g.contains( node, RDF.type.asNode(), LIST.asNode() ); - // } - // }; - // - // /** This method returns the Java class object that defines which - // abstraction facet is presented */ - // @Override public Class listAbstractionClass() { - // return UserDefList.class; - // } - // - // public UserDefListImpl( Node n, EnhGraph g ) { - // super( n, g ); - // } - // - // } + public void testModelGetEmptyList() + { + Resource root = model.createResource(TestList.NS + "root"); + Property p = model.createProperty(TestList.NS, "p"); + Resource r = model.createResource(TestList.NS + "r"); + + RDFList list0 = model.createList(); + model.add(r, p, list0); + + RDFList list1 = model.listStatements(r, p, (Resource)null).next().getList(); + + boolean b = list0.sameListAs(list1); + assertTrue("Different lists: expected: "+list0+" : got: "+list1, b); + } + } diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/model/SecuredModel.java b/jena-permissions/src/main/java/org/apache/jena/permissions/model/SecuredModel.java index 43d1685d391..4a64e71ae86 100644 --- a/jena-permissions/src/main/java/org/apache/jena/permissions/model/SecuredModel.java +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/model/SecuredModel.java @@ -563,7 +563,7 @@ public SecuredRDFList createList(final Iterator members) * if user is not authenticated and is required to be. */ @Override - public SecuredRDFList createList(final RDFNode[] members) + public SecuredRDFList createList(final RDFNode...members) throws AddDeniedException, UpdateDeniedException, AuthenticationRequiredException; /** @@ -1096,6 +1096,32 @@ public SecuredStatement getRequiredProperty(final Resource s, final Property p, @Override public SecuredSeq getSeq(final String uri) throws ReadDeniedException, AuthenticationRequiredException; + /** Return a RDF List instance in this model. + * + *

Subsequent operations on the returned list may modify this model.

+ *

The list is assumed to already exist in the model. If it does not, + * createList should be used instead.

+ * @return a list instance + * @param uri the URI of the list + */ + @Override + public SecuredRDFList getList(String uri) throws ReadDeniedException, AuthenticationRequiredException; + + /** Return a RDF List based on a given resource. + * + *

This method enables an application to treat any resource as a list. + * It is in effect an unsafe downcast.

+ * + *

Subsequent operations on the returned list may modify this model.

+ *

The list is assumed to already exist in the model. If it does not, + * createList should be used instead.

+ * @return a list instance + * @param r the resource of the list + */ + @Override + public SecuredRDFList getList(Resource r) throws ReadDeniedException, AuthenticationRequiredException; + + /** * * @sec.graph Read diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredModelImpl.java b/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredModelImpl.java index 358d928586b..dcea6dd3ad5 100644 --- a/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredModelImpl.java +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredModelImpl.java @@ -712,7 +712,7 @@ public SecuredRDFList createList(final Iterator members) } @Override - public SecuredRDFList createList(final RDFNode[] members) + public SecuredRDFList createList(RDFNode... members) throws UpdateDeniedException, AddDeniedException, AuthenticationRequiredException { return createList(Arrays.asList(members).iterator()); } @@ -1063,7 +1063,35 @@ public SecuredBag getBag(final String uri) throws ReadDeniedException, Authentic checkRead(new Triple(NodeFactory.createURI(uri), RDF.type.asNode(), RDF.Bag.asNode())); return SecuredBagImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getBag(uri)); } + + @Override + public SecuredSeq getSeq(final Resource r) throws ReadDeniedException, AuthenticationRequiredException { + checkRead(); + checkRead(new Triple(r.asNode(), RDF.type.asNode(), RDF.Seq.asNode())); + return SecuredSeqImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getSeq(r)); + } + @Override + public SecuredSeq getSeq(final String uri) throws ReadDeniedException, AuthenticationRequiredException { + checkRead(); + checkRead(new Triple(NodeFactory.createURI(uri), RDF.type.asNode(), RDF.Seq.asNode())); + return SecuredSeqImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getSeq(uri)); + } + + + + @Override + public SecuredRDFList getList( String uri ) throws ReadDeniedException, AuthenticationRequiredException { + checkRead(); + return SecuredRDFListImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getList(uri)); + } + + @Override + public SecuredRDFList getList( Resource r ) throws ReadDeniedException, AuthenticationRequiredException { + checkRead(); + return SecuredRDFListImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getList(r)); + } + @Override public SecuredGraph getGraph() { return graph; @@ -1241,20 +1269,6 @@ public SecuredResource getResource(final String uri, final ResourceF f) { return createResource(uri, f); } - @Override - public SecuredSeq getSeq(final Resource r) throws ReadDeniedException, AuthenticationRequiredException { - checkRead(); - checkRead(new Triple(r.asNode(), RDF.type.asNode(), RDF.Seq.asNode())); - return SecuredSeqImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getSeq(r)); - } - - @Override - public SecuredSeq getSeq(final String uri) throws ReadDeniedException, AuthenticationRequiredException { - checkRead(); - checkRead(new Triple(NodeFactory.createURI(uri), RDF.type.asNode(), RDF.Seq.asNode())); - return SecuredSeqImpl.getInstance(holder.getSecuredItem(), holder.getBaseItem().getSeq(uri)); - } - @Override public RDFWriter getWriter() { return holder.getBaseItem().getWriter(); diff --git a/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredStatementImpl.java b/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredStatementImpl.java index 700a4a75b14..01165ba4f58 100644 --- a/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredStatementImpl.java +++ b/jena-permissions/src/main/java/org/apache/jena/permissions/model/impl/SecuredStatementImpl.java @@ -279,6 +279,18 @@ public SecuredBag getBag() { } @Override + public SecuredSeq getSeq() { + return SecuredSeqImpl.getInstance(getModel(), holder.getBaseItem() + .getSeq()); + } + + @Override + public SecuredRDFList getList() { + return SecuredRDFListImpl.getInstance(getModel(), holder.getBaseItem() + .getList()); + } + + @Override public boolean getBoolean() throws ReadDeniedException, AuthenticationRequiredException { checkRead(); @@ -410,12 +422,6 @@ public SecuredResource getResource(final ResourceF f) { .getResource(f)); } - @Override - public SecuredSeq getSeq() { - return SecuredSeqImpl.getInstance(getModel(), holder.getBaseItem() - .getSeq()); - } - @Override public short getShort() throws ReadDeniedException, AuthenticationRequiredException {