Re: parsing and matching triples

2018-05-08 Thread Adam Jacobs
That's a great idea.
+1


From: ajs6f 
Sent: Tuesday, May 8, 2018 10:55 AM
To: dev@jena.apache.org
Subject: Re: parsing and matching triples

Forking a thread off to dev@:

Do we have a global policy about where null is accepted as a wildcard? I know 
it works in at least some places...

I would love to (over an appropriate period of time and with lots of warnings 
and deprecation and so forth) stop letting it be a wildcard and require code to 
use the actual wildcard objects.

ajs6f

> On May 8, 2018, at 11:51 AM, Andy Seaborne  wrote:
>
> Barry,
>
> As a general concept "matching" happens at different levels.
>
> Triple.match corresponds to the matching done by Graph.find - RDF terms (URI, 
> bnode, literal) match exactly, and Node.ANY is a wildcard.
>
> Triple t1 = Triple.ANY;
> Triple t2 = SSE.parseTriple("(:s :p :o)");
> t1.matches(t2) -> true
> t2.matches(t1) -> false
>
> Variables are a concept for SPARQL - and matches usefully need to return 
> which variable matched which RDF Term.
>
> Triple patterns match against graphs and return an iterator of ways they 
> match.
>
> Consider cases like "?x ?p ?x" where the variables impose am additional shape.
>
> If you want variable bindings, you could build a SPARQL query or wrap up some 
> of the internal code e.g.
>
> /** Evaluate a triple pattern */
> private static QueryIterator match(Graph source, Triple pattern) {
>ExecutionContext execContext =
>  new ExecutionContext(ARQ.getContext(), source, null, null) ;
>QueryIterator chain = QueryIterRoot.create(execContext)
>chain = new QueryIterTriplePattern(chain, pattern, execContext) ;
>return chain ;
> }
>
>Andy
>
> On 08/05/18 09:21, Nouwt, B. (Barry) wrote:
>> Hi everybody,
>> I’m trying to reuse Apache Jena code that parses and matches triples. I’m 
>> currently looking at the SSE class’s parseTriple() method. This seems to fit 
>> my purpose for parsing a string representation of a triple into a triple 
>> object. I also noticed the following Javadoc on the Node.maches(Node) method:
>> Answer true iff this node accepts the other one as a match.
>> The default is an equality test; it is over-ridden in subclasses to
>> provide the appropriate semantics for literals, ANY, and variables.
>> Since this is exactly what I’m looking for, I’ve tried to match two triples 
>> using the matches() method, but it does not seem to work:
>> Triple t1 = SSE.parseTriple("(?s ?p ?o)");
>> Triple t2 = SSE.parseTriple("(test:subject test:predicate test:object)", pm);
>> t1.matches(t2)
>> The final statement returns false, while I would expect it to return true. 
>> Either, I’m missing something (which is completely realistic ), or I should 
>> use some other method to match two triples in the way described above.
>> Any help is appreciated!
>> Regards, Barry
>> This message may contain information that is not intended for you. If you 
>> are not the addressee or if this message was sent to you by mistake, you are 
>> requested to inform the sender and delete the message. TNO accepts no 
>> liability for the content of this e-mail, for the manner in which you use it 
>> and for damage of any kind resulting from the risks inherent to the 
>> electronic transmission of messages.



Re: Dataset.getUnionModel()

2018-04-18 Thread Adam Jacobs
Hi Andy,

We are using the general dataset.
Our use case is simply that we are taking quads in from clients, which may or 
may not include a default graph.
We use the union model for several things, but one example is SHACL validation. 
So we always need to remember to include the default graph into the union model.
Currently, I've subclassed the DatasetImpl to override the unionModel() method; 
but it sounds like we may be an edge case.

Thanks,
-Adam

From: Andy Seaborne <a...@apache.org>
Sent: Saturday, April 14, 2018 5:01 PM
To: dev@jena.apache.org
Subject: Re: Dataset.getUnionModel()

Hi Adam,

Yes, the union model is the graph union of the named graphs and does not
include the default graph. This choice is intentional and is driven by
the SPARQL side of things.

It's a useful way to have manageability of the data by using the SPARQL
Graph Store Protocol to PUT and POST graphs that together make the
default graph to be queried. This matches the behaviour some other
triple stores.

Which kind of dataset are you using?

For the general dataset that can include any models, a graph can be
added twice so the default graph can be added as named graph as well and
so included in the union.

What is your application usage that naturally wanted the default model
to be included?

 Andy

On 14/04/18 21:00, Adam Jacobs wrote:
> Dataset.getUnionModel() excludes the default graph.
> Would it be appropriate to include the default graph in this method, or to 
> add an additional unioning method to the Dataset interface which includes the 
> default graph?
> It seems like an oversight, but maybe there was a reason for excluding it?
>


Dataset.getUnionModel()

2018-04-14 Thread Adam Jacobs
Dataset.getUnionModel() excludes the default graph.
Would it be appropriate to include the default graph in this method, or to add 
an additional unioning method to the Dataset interface which includes the 
default graph?
It seems like an oversight, but maybe there was a reason for excluding it?

[jira] [Comment Edited] (JENA-1499) The TIM dataset retains a memory of named graphs after deleting all quads.

2018-03-06 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1499?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16388781#comment-16388781
 ] 

Adam Jacobs edited comment on JENA-1499 at 3/7/18 12:43 AM:


>From the API side, I've noticed empty graphs are consistently treated as 
>"unimportant" and are often created superfluously.
{code:java}
Dataset ds = DatasetFactory.create();
ds.containsNamedModel("foo");
ds.removeNamedModel("bar");
Iterator iterator = ds.listNames();
System.out.println(iterator.next());
System.out.println(iterator.next());{code}
As mentioned, this is significant when serializing to TRIG.


was (Author: jaco0646):
>From the API side, I've noticed empty graphs are consistently treated as 
>"unimportant" and are often created superfluously.

 

{{Dataset ds = DatasetFactory.create();}}
{{ds.containsNamedModel("foo");}}
{{ds.removeNamedModel("bar");}}
{{Iterator iterator = ds.listNames();}}
{{System.out.println(iterator.next());}}
{{System.out.println(iterator.next());}}

 

As mentioned, this is significant when serializing to TRIG.

> The TIM dataset retains a memory of named graphs after deleting all quads.
> --
>
> Key: JENA-1499
> URL: https://issues.apache.org/jira/browse/JENA-1499
> Project: Apache Jena
>  Issue Type: Bug
>Affects Versions: Jena 3.6.0
>Reporter: Andy Seaborne
>Priority: Major
>
> Illustration:
> {noformat}
> DatasetGraph dsg = DatasetGraphFactory.createTxnMem();
> Quad q = SSE.parseQuad("(:g :s :p :o)");
> dsg.add(q);
> dsg.delete(q);
> Iter.print(dsg.listGraphNodes());
> {noformat}
> prints {{http://example/g}}.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)


[jira] [Commented] (JENA-1499) The TIM dataset retains a memory of named graphs after deleting all quads.

2018-03-06 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1499?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16388781#comment-16388781
 ] 

Adam Jacobs commented on JENA-1499:
---

>From the API side, I've noticed empty graphs are consistently treated as 
>"unimportant" and are often created superfluously.

 

{{Dataset ds = DatasetFactory.create();}}
{{ds.containsNamedModel("foo");}}
{{ds.removeNamedModel("bar");}}
{{Iterator iterator = ds.listNames();}}
{{System.out.println(iterator.next());}}
{{System.out.println(iterator.next());}}

 

As mentioned, this is significant when serializing to TRIG.

> The TIM dataset retains a memory of named graphs after deleting all quads.
> --
>
> Key: JENA-1499
> URL: https://issues.apache.org/jira/browse/JENA-1499
> Project: Apache Jena
>  Issue Type: Bug
>Affects Versions: Jena 3.6.0
>Reporter: Andy Seaborne
>Priority: Major
>
> Illustration:
> {noformat}
> DatasetGraph dsg = DatasetGraphFactory.createTxnMem();
> Quad q = SSE.parseQuad("(:g :s :p :o)");
> dsg.add(q);
> dsg.delete(q);
> Iter.print(dsg.listGraphNodes());
> {noformat}
> prints {{http://example/g}}.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)


[jira] [Commented] (JENA-1391) Add Convenience Methods to Dataset

2018-03-01 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16382936#comment-16382936
 ] 

Adam Jacobs commented on JENA-1391:
---

This looks fine to me. Nice work.

> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>    Reporter: Adam Jacobs
>Assignee: A. Soroka
>Priority: Trivial
>
> The Dataset interface could provide several convenience methods similar to 
> the Model interface, allowing usability of RDF quads on par with RDF triples. 
> Specific examples include,
> # add(Dataset)
> # remove(Dataset)
> # union(Dataset)
> # intersection(Dataset)
> # difference(Dataset)
> # isEmpty()
> Following is a possible implementation of these methods.
> {code:java}
> default Dataset add(Dataset d) {
> this.getDefaultModel().add(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).add(d.getNamedModel(name)));
> return this;
> }
> default Dataset remove(Dataset d) {
> this.getDefaultModel().remove(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).remove(d.getNamedModel(name)));
> return this;
> }
> default Dataset union(Dataset d) {
> return DatasetFactory.create().add(this).add(d);
> }
> default Dataset difference(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
> this.listNames().forEachRemaining(name -> {
> Model difference = 
> this.getNamedModel(name).difference(d.getNamedModel(name));
> if (!difference.isEmpty()) output.addNamedModel(name, difference);
> });
> return output;
> }
> default Dataset intersection(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
> Set names = this.names();
> names.retainAll(d.names());
> names.forEach(name -> {
> Model intersection = 
> this.getNamedModel(name).intersection(d.getNamedModel(name));
> if (!intersection.isEmpty()) output.addNamedModel(name, 
> intersection);
> });
> return output;
> }
> default Set names() {
> Set names = new HashSet<>();
> this.listNames().forEachRemaining(names::add);
> return names;
> }
> default boolean isEmpty() {
> return this.asDatasetGraph().isEmpty();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)


[jira] [Created] (JENA-1495) Covariant return type for Model's PrefixMapping methods.

2018-02-27 Thread Adam Jacobs (JIRA)
Adam Jacobs created JENA-1495:
-

 Summary: Covariant return type for Model's PrefixMapping methods.
 Key: JENA-1495
 URL: https://issues.apache.org/jira/browse/JENA-1495
 Project: Apache Jena
  Issue Type: Improvement
  Components: Core
Affects Versions: Jena 3.6.0
Reporter: Adam Jacobs


The {{Model}} interface inherits several methods from {{PrefixMapping}} which 
return {{this}}.
 The return type of these methods can be refined to allow call chaining with 
the {{Model}} object.

There appear to be two concrete implementations of {{Model}} which override the 
{{PrefixMapping}} methods: {{ModelCom}} and {{SecuredModelImpl}}. Steps to add 
covariant return types for prefix mapping are as follows.

Add these six methods to the Model interface.
 # Model setNsPrefix( String prefix, String uri );
 # Model removeNsPrefix( String prefix );
 # Model clearNsPrefixMap();
 # Model setNsPrefixes( PrefixMapping other );
 # Model setNsPrefixes( Map<String, String> map );
 # Model withDefaultMappings( PrefixMapping map );

...and update ModelCom accordingly.

Add these six methods to the SecuredModel interface.
 # SecuredModel setNsPrefix( String prefix, String uri );
 # SecuredModel removeNsPrefix( String prefix ); // This method is already 
defined.
 # SecuredModel clearNsPrefixMap();
 # SecuredModel setNsPrefixes( PrefixMapping other );
 # SecuredModel setNsPrefixes( Map<String, String> map );
 # SecuredModel withDefaultMappings( PrefixMapping map );

...and update SecuredModelImpl accordingly.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)


Re: JsonLD @vocab

2018-01-07 Thread Adam Jacobs
Do you know where jsonld discussions are at?
I'm having trouble finding a mailing list.



From: Andy Seaborne <a...@apache.org>
Sent: Thursday, January 4, 2018 2:34 PM
To: dev@jena.apache.org
Subject: Re: JsonLD @vocab

Adam,

In the first instance, this seems like something to raise with the
jsonld-java team to find out if that is intentional. Could you open a
discussion issue there?

IIRC empty prefix and the base are mixed up in JSON-LD.

 Andy

On 04/01/18 03:34, Adam Jacobs wrote:
> The @vocab prefix is dropped by Jena when parsing JsonLD.
> An empty prefix is correctly translated into @vocab during serialization, but 
> is lost during deserialization.
> Below code demonstrates the point.
>
>  public static void main(String... args) {
>  String base = "http://www.ns.com/base/;;
>  String prefix = "http://www.ns.com/prefix/;;
>
>  Model m = ModelFactory.createDefaultModel();
>  m.setNsPrefix("", base);
>  m.setNsPrefix("prefix", prefix);
>
>  m.add(m.createResource(base + "foo"), m.createProperty(prefix + 
> "bar"), m.createResource(base + "baz"));
>  String jsonLD = serializeJsonLD(m);
>  System.out.println(jsonLD);
>
>  InputStream in = new ByteArrayInputStream(jsonLD.getBytes());
>  Model m2 = ModelFactory.createDefaultModel().read(in, null, 
> "jsonld");
>  System.out.println(serializeJsonLD(m2));
>  }
>
>  public static String serializeJsonLD(Model m) {
>  OutputStream out = new ByteArrayOutputStream();
>  m.write(out, "jsonld");
>  return out.toString();
>  }
>
>  From what I can see, jsonld-java is intentionally ignoring the @vocab key at 
> line 277 of Context.java.
>  
> https://github.com/jsonld-java/jsonld-java/blob/master/core/src/main/java/com/github/jsonldjava/core/Context.java
>
> I'm not sure if this is a bug in jsonld-java, or intentional behavior from a 
> jsonld perspective that Jena should work around e.g. in JsonLDReader?
>


Re: PROV vocabulary class

2018-01-07 Thread Adam Jacobs
Is it a good idea to have a public mutable model?




From: Cotton Franck 
Sent: Sunday, January 7, 2018 11:47 AM
To: dev@jena.apache.org
Subject: RE:PROV vocabulary class

Hi Adam. Here: https://gist.github.com/FranckCo/889d1f137dc412ceab214159a49375e2

Franck

De : ajs6f [aj...@apache.org]
Envoyé : dimanche 7 janvier 2018 18:07
À : dev@jena.apache.org
Objet : Re: PROV vocabulary class

This list doesn't permit attachments. Can you please send your work as a PR on 
Github, or failing that, as a gist or pastebin or the like?

Adam Soroka

> On Jan 7, 2018, at 12:00 PM, Cotton Franck  wrote:
>
> Hello
>
> For my own needs, I created this class corresponding to the W3C PROV 
> vocabulary. It could fit in the org.apache.jena.vocabulary package. Please 
> fill free to add the relevant license text, I don't claim any IP on the class.
>
> Cheers
> Franck



JsonLD @vocab

2018-01-03 Thread Adam Jacobs
The @vocab prefix is dropped by Jena when parsing JsonLD.
An empty prefix is correctly translated into @vocab during serialization, but 
is lost during deserialization.
Below code demonstrates the point.

public static void main(String... args) {
String base = "http://www.ns.com/base/;;
String prefix = "http://www.ns.com/prefix/;;

Model m = ModelFactory.createDefaultModel();
m.setNsPrefix("", base);
m.setNsPrefix("prefix", prefix);

m.add(m.createResource(base + "foo"), m.createProperty(prefix + "bar"), 
m.createResource(base + "baz"));
String jsonLD = serializeJsonLD(m);
System.out.println(jsonLD);

InputStream in = new ByteArrayInputStream(jsonLD.getBytes());
Model m2 = ModelFactory.createDefaultModel().read(in, null, "jsonld");
System.out.println(serializeJsonLD(m2));
}

public static String serializeJsonLD(Model m) {
OutputStream out = new ByteArrayOutputStream();
m.write(out, "jsonld");
return out.toString();
}

>From what I can see, jsonld-java is intentionally ignoring the @vocab key at 
>line 277 of Context.java.

https://github.com/jsonld-java/jsonld-java/blob/master/core/src/main/java/com/github/jsonldjava/core/Context.java

I'm not sure if this is a bug in jsonld-java, or intentional behavior from a 
jsonld perspective that Jena should work around e.g. in JsonLDReader?


[jira] [Commented] (JENA-1452) Special case GraphUnionRead for one graph.

2017-12-20 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1452?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16299446#comment-16299446
 ] 

Adam Jacobs commented on JENA-1452:
---

It looks like {{TestGraphUnionRead}} only covers the {{find()}} method.
What is the expectation when {{add()}}, {{delete()}}, etc. are called on this 
graph?
Is the behavior of those methods consistent for this special case?

> Special case GraphUnionRead for one graph.
> --
>
> Key: JENA-1452
> URL: https://issues.apache.org/jira/browse/JENA-1452
> Project: Apache Jena
>  Issue Type: Improvement
>Affects Versions: Jena 3.6.0
>Reporter: Andy Seaborne
>Assignee: Andy Seaborne
>Priority: Minor
> Fix For: Jena 3.7.0
>
>




--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


Re: potential new API Was: Immutability

2017-12-17 Thread Adam Jacobs
I just want to mention that it was not my intent to derail progress on 
Jena-1391 (https://issues.apache.org/jira/browse/JENA-1391) by raising the 
issue of immutability,
particularly if immutability would be implemented via a new API. I don't think 
it should be considered a blocker to that story. Apologies if I threw a wrench 
into the plan.



From: ajs6f 
Sent: Wednesday, December 13, 2017 10:39 AM
To: dev@jena.apache.org
Subject: potential new API Was: Immutability

Yes, the SPI is likely fine, or we will find out otherwise if we try a new API. 
:)

A new API is clearly no small thing. I suppose one way to approach the thing 
would be to look at what Clerezza and RDF4J 4 and Commons RDF have come up 
with, what worked and what didn't, and then bring in our own use cases and 
ideas...

The two "asks" I've heard recently from Jena users are: immutability and 
Streams. I'm guessing there are others. I would like to take advantage of 
Optional for some of the attributes of a node (e.g. return the lang of a 
literal as Optional).

Other thoughts? It's fun to make wish lists at the end of the year. :grin:

ajs6f

> On Nov 16, 2017, at 11:47 AM, Andy Seaborne  wrote:
>
> Yes, I think it is best done as a new API.
>
> Modifications to the existing one are likely to run into problems somewhere 
> and given the number of users, and the change over time on upgrades, having 
> compatibility matters as does gradual migration
>
> A complicates case: Dataset.getModel(String) returns a model. No idea whether 
> it is immutable or not or how it will be used.  Assigning to a ImmutableModel 
> does not guaratee anything - it helps the caller not make mistakes but the 
> model is not immutable.  Some code calling getModel can change it. And the 
> union model isn't immutable! - it's a dynamic union and any name graph change 
> will be reflected. The world is multithreaded.
>
> But the main reason for a new API is that this is just one of several 
> features to include so to make it a success these different features need to 
> come together into one *agreed* design.
>
> The good news is that it can target the SPI.
> (I see no value in changing the SPI for this - that's not it's role)
>
> ARQ's API is really very small. A design that took a dataset+model view of 
> the world would be a good thing.
>
>Andy
>
> See also commons-rdf.
> That is RDF 1.1 compliant
>
> On 15/11/17 15:52, aj...@apache.org wrote:
>> So it seems to me that if we want to introduce immutable types, we might 
>> want to do that in the context of a completely new API. The use of the Java 
>> 8 Streams API is also something that has been mooted as something that might 
>> merit a new Jena API. (Instead of mixing things up in the current one.)
>> I'm not sure how that plays out with ARQ, though. We would want people to be 
>> able to use the new types with ARQ without much difficulty.



Re: Jena-1427 - nextOptional()

2017-12-17 Thread Adam Jacobs
Note that the original request in Jena-1427 was for a nextOrElse() method 
accepting an instance of Supplier.
The implementation of nextOptional(), released in version 3.6, solves my use 
case just as well.

The only reason I had not requested nextOptional() directly is that 
ExtendedIterator was already composed of custom functional-programming-oriented 
methods.
In my experience, the API of ExtendedIterator is superior (i.e. more user 
friendly) than what Java 8 offers in its Streams, so I thought it was worth 
considering alternatives.

For me, there is no wrong choice here as any of several options solve my 
problem.
I appreciate everyone who has contributed to the discussion.


From: ajs6f 
Sent: Sunday, December 17, 2017 1:28 PM
To: dev@jena.apache.org
Subject: Re: Jena-1427 - nextOptional()

> On Dec 17, 2017, at 2:18 PM, Claude Warren  wrote:
> It seems that much of the rest of  the discussion is covered by adding a 
> method to convert the iterator to a stream (probably just a call to an 
> existing Java method.

Just to this point alone-- this is something that came up _in_ the discussion 
(we even already have Iter::asStream for the purpose), and I don't agree with 
it. Converting an iterator to a stream is a useful thing, to be sure, but 
although it doesn't really speak to the optimizations that people (rightly) 
associate with a stream (i.e. it doesn't push filters or other computations 
back to whatever they might look like closer to the source of elements) it does 
create a bunch of objects and machinery. I'd rather not encourage people to do 
this-- I'd rather encourage them to use plain iterators unless/until we can 
actually supply an API with real streams.

Otherwise:

> Perhaps we should add a next( T default ) method that will return the default 
> if hasNext() returns false.  This seem better than polluting the environment 
> with Optionals that don't really belong.


I don't agree at all that Optional doesn't belong here, but if the original 
requestor can confirm that this would meet the use case, and if we can come up 
with something for throwing a custom exception that does pass Claude's "smell 
test", then I'm fine with it. I'd rather not add method after method to 
ExtendedIterator for every possible syntactic convenience. (This ain't Scala! 
:wink:)

ajs6f

> On Dec 17, 2017, at 2:18 PM, Claude Warren  wrote:
>
> From the original request it seems the requirements were:
> 1. return a default value if the iterator is empty.
> 2. throw a custom exception if the iterator is empty.
>
>
> Perhaps we should add a next( T default ) method that will return the
> default if hasNext() returns false.  This seem better than polluting the
> environment with Optionals that don't really belong.
>
> If we want to provide a method to throw an custom exception we could add
> something like next( Class e ) to create and throw the
> exception.  But I don't like this one for some reason.  Like the Optional
> it doesn't pass the smell test for me.
>
> It seems that much of the rest of  the discussion is covered by adding a
> method to convert the iterator to a stream (probably just a call to an
> existing Java method.
>
> Claude
>
>
> On Sun, Dec 17, 2017 at 5:50 PM, Andy Seaborne  wrote:
>
>> We seem to have drifted a bit here - the original use case wasn't about
>> streaming as I read it. list* get used to write zero/one tests and one/many
>> tests dealing with properties etc.
>>
>> And, of course, we want to avoid the anti-pattern of Optional/if-empty.
>>
>> Claude - thoughts on the use case? How might we evolve the current API
>> without method bloat?
>>
>>Andy
>>
>>
>> On 14/12/17 17:46, Claude Warren wrote:
>>
>>> I was expecting that with the discovery that optional throws a null
>>> pointer
>>> exception when the retrieved value is null would be enough to remove this
>>> functionality.
>>>
>>> I am concerned that once added it will be difficult to remove and that its
>>> operation is not congruent with stream based optional usage.
>>>
>>> Claude
>>>
>>> On 14 Dec 2017 10:33, "Andy Seaborne"  wrote:
>>>
>>> Claude,

 The JIRA ticket ends:

 [[
 ASF GitHub Bot added a comment - 04/Dec/17 15:36

 That was already the case in the PR and I've added text to call it out
 explicitly into the javadoc.
 
 githubbot ASF GitHub Bot added a comment - 04/Dec/17 15:40

 Github user ajs6f commented on the issue:

 https://github.com/apache/jena/pull/323

 Okay, that works for me!
 
 Andy Seaborne added a comment - 04/Dec/17 15:58

 nextOptional added for release 3.6.0.

 Proposal: close this JIRA for now, see how nextOptional works out and
 revisit orElse* based on experience.
 
 ajs6f A. Soroka added a comment - 1 week ago

 +1
 ]]

 Adding 

[jira] [Created] (JENA-1451) DatasetFactory.createGeneral() never contains default graph

2017-12-17 Thread Adam Jacobs (JIRA)
Adam Jacobs created JENA-1451:
-

 Summary: DatasetFactory.createGeneral() never contains default 
graph
 Key: JENA-1451
 URL: https://issues.apache.org/jira/browse/JENA-1451
 Project: Apache Jena
  Issue Type: Bug
  Components: ARQ
Affects Versions: Jena 3.6.0
Reporter: Adam Jacobs
Priority: Minor


See: 
http://mail-archives.apache.org/mod_mbox/jena-dev/201712.mbox/<0a67c2ce-f414-3eae-51dc-226768d4facd%40apache.org>
   

Model m1 = ModelFactory.createDefaultModel();
m1.add(m1.createResource(), m1.createProperty("foo"), 
m1.createResource());

Dataset memory = DatasetFactory.create();
Dataset general = DatasetFactory.createGeneral();

memory.getDefaultModel().add(m1);
general.getDefaultModel().add(m1);

//Memory model contains default graph. General model does not.

System.out.println(memory.containsNamedModel(Quad.defaultGraphIRI.getURI()));  
//true

System.out.println(general.containsNamedModel(Quad.defaultGraphIRI.getURI()));  
//false



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


DatasetFactory.createGeneral()

2017-12-17 Thread Adam Jacobs
I've noticed a couple of differences between DatasetFactory.create() and 
DatasetFactory.createGeneral().
My understanding is that the former is intended to create deep copies of its 
graphs whereas the latter maintains shallow links.
The DatasetFactory has quite a few creational methods, and their documentation 
tends to be brief; but a couple of behaviors stood out to me.

 1. In the general dataset, containsNamedModel() always returns false for 
the default graph.
  This seems unexpected whether from the perspective of copies or links.
 2. In the general dataset, addNamedModel() appears to perform the same 
function as replaceNamedModel().
  This is understandable for simplicity; but from the memory dataset 
perspective, a combined view of identically-named graphs would be expected.
  ~ Fun with words: can we say that "identically-named graphs" are 
homonymous?  ;) ~

Following is some code demonstrating the two points above. Are these behaviors 
intentional?

public static void main(String... args) {
Model m1 = ModelFactory.createDefaultModel();
m1.add(m1.createResource(), m1.createProperty("foo"), 
m1.createResource());
Model m2 = ModelFactory.createDefaultModel();
m2.add(m2.createResource(), m2.createProperty("bar"), 
m2.createResource());

Dataset memory = DatasetFactory.create();
Dataset general = DatasetFactory.createGeneral();

memory.getDefaultModel().add(m1);
general.getDefaultModel().add(m1);
memory.addNamedModel("bar", m2);
general.addNamedModel("bar", m2);

//Memory model contains default graph. General model does not.

System.out.println(memory.containsNamedModel(Quad.defaultGraphIRI.getURI()));  
//true

System.out.println(general.containsNamedModel(Quad.defaultGraphIRI.getURI()));  
//false

memory.addNamedModel("bar", ModelFactory.createDefaultModel());
general.addNamedModel("bar", ModelFactory.createDefaultModel());

//Memory model add == merge. General model add == replace.
System.out.println(memory.getNamedModel("bar"));  //merge
System.out.println(general.getNamedModel("bar"));  //replace
}

Re: consistent blank id values from RDFConnection

2017-12-17 Thread Adam Jacobs
You're right, that section does seem conclusive, at least insofar as SPARQL is 
concerned.



From: ajs6f <aj...@apache.org>
Sent: Sunday, December 17, 2017 10:19 AM
To: dev@jena.apache.org
Subject: Re: consistent blank id values from RDFConnection

That's not how I understand:

https://www.w3.org/TR/sparql11-query/#BlankNodesInResults

"Blank node labels are scoped to a result set (see "SPARQL Query Results XML 
Format" and "SPARQL 1.1 Query Results JSON Format") or, for the CONSTRUCT query 
form, the result graph."

Multiple calls to a single graph => multiple queries => multiple result sets 
(or result graphs) => multiple scopes.

ajs6f

> On Dec 17, 2017, at 11:15 AM, Adam Jacobs <jacobs_...@hotmail.com> wrote:
>
> My understanding is there's nothing wrong with maintaining labels among 
> multiple calls to a single graph.
> The danger would be the risk of maintaining labels among calls to multiple 
> graphs.
> At least, that's what I get out of this SO answer: 
> https://stackoverflow.com/questions/44477876/grouping-by-blank-nodes/44498034#44498034
>
> 
> From: ajs6f <aj...@apache.org>
> Sent: Sunday, December 17, 2017 10:11 AM
> To: dev@jena.apache.org
> Subject: Re: consistent blank id values from RDFConnection
>
>> On Dec 17, 2017, at 11:08 AM, Andy Seaborne <a...@apache.org> wrote:
>>
>>> Why would it be dangerous?
>
> As I wrote:
>
>>>> (in the sense in which you used the phrase "dubious in terms of spec 
>>>> compliance")
>
> It might confuse people into thinking that maintaining bnode labeling is a 
> normal part of using SPARQL, when it isn't-- it's something extra that Jena 
> provides.
>
> If there's no reason this is an undocumented feature, I'm going to document 
> it at:
>
> https://jena.apache.org/documentation/query/app_api.html
>
> ajs6f
>
>> On Dec 17, 2017, at 11:08 AM, Andy Seaborne <a...@apache.org> wrote:
>>
>> Why would it be dangerous?
>>
>> On 17/12/17 15:46, ajs6f wrote:
>>> That is useful, and it's undocumented. Is that because it is dangerous (in 
>>> the sense in which you used the phrase "dubious in terms of spec 
>>> compliance") or just because we never have documented it?
>>> ajs6f
>>>> On Dec 17, 2017, at 10:43 AM, Andy Seaborne <a...@apache.org> wrote:
>>>>
>>>> ARQ.enableBlankNodeResultLabels()
>>>>
>>>> On 17/12/17 15:39, ajs6f wrote:
>>>>> Where? I found nothing documented.
>>>>> ajs6f
>>>>>> On Dec 17, 2017, at 10:38 AM, Andy Seaborne <a...@apache.org> wrote:
>>>>>>
>>>>>> On 17/12/17 15:19, ajs6f wrote:
>>>>>>> Claude-- I'm looking at RDFConnection, but it's an interface. I think 
>>>>>>> you mean around L220 of JSONInput itself, right?
>>>>>>> It looks like SyntaxLabels has some LabelToNode factory methods that 
>>>>>>> might fit the bill, like createNodeToLabelAsGiven(), but JSONInput 
>>>>>>> doesn't offer any way to select which method to use. At L195 it uses 
>>>>>>> SyntaxLabels.createLabelToNode().
>>>>>>> We could thread such a mapping choice all the way through the call 
>>>>>>> stack, but that seems a bit difficult to me. Maybe we could introduce a 
>>>>>>> Context setting for this purpose?
>>>>>>
>>>>>> They already exist!
>



Re: consistent blank id values from RDFConnection

2017-12-17 Thread Adam Jacobs
My understanding is there's nothing wrong with maintaining labels among 
multiple calls to a single graph.
The danger would be the risk of maintaining labels among calls to multiple 
graphs.
At least, that's what I get out of this SO answer: 
https://stackoverflow.com/questions/44477876/grouping-by-blank-nodes/44498034#44498034


From: ajs6f 
Sent: Sunday, December 17, 2017 10:11 AM
To: dev@jena.apache.org
Subject: Re: consistent blank id values from RDFConnection

> On Dec 17, 2017, at 11:08 AM, Andy Seaborne  wrote:
>
>> Why would it be dangerous?

As I wrote:

>>> (in the sense in which you used the phrase "dubious in terms of spec 
>>> compliance")

It might confuse people into thinking that maintaining bnode labeling is a 
normal part of using SPARQL, when it isn't-- it's something extra that Jena 
provides.

If there's no reason this is an undocumented feature, I'm going to document it 
at:

https://jena.apache.org/documentation/query/app_api.html

ajs6f

> On Dec 17, 2017, at 11:08 AM, Andy Seaborne  wrote:
>
> Why would it be dangerous?
>
> On 17/12/17 15:46, ajs6f wrote:
>> That is useful, and it's undocumented. Is that because it is dangerous (in 
>> the sense in which you used the phrase "dubious in terms of spec 
>> compliance") or just because we never have documented it?
>> ajs6f
>>> On Dec 17, 2017, at 10:43 AM, Andy Seaborne  wrote:
>>>
>>> ARQ.enableBlankNodeResultLabels()
>>>
>>> On 17/12/17 15:39, ajs6f wrote:
 Where? I found nothing documented.
 ajs6f
> On Dec 17, 2017, at 10:38 AM, Andy Seaborne  wrote:
>
> On 17/12/17 15:19, ajs6f wrote:
>> Claude-- I'm looking at RDFConnection, but it's an interface. I think 
>> you mean around L220 of JSONInput itself, right?
>> It looks like SyntaxLabels has some LabelToNode factory methods that 
>> might fit the bill, like createNodeToLabelAsGiven(), but JSONInput 
>> doesn't offer any way to select which method to use. At L195 it uses 
>> SyntaxLabels.createLabelToNode().
>> We could thread such a mapping choice all the way through the call 
>> stack, but that seems a bit difficult to me. Maybe we could introduce a 
>> Context setting for this purpose?
>
> They already exist!



[jira] [Commented] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-22 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16263362#comment-16263362
 ] 

Adam Jacobs commented on JENA-1427:
---

Sounds great to me. Whether integrating with Java's {{Optional}} or 
implementing equivalent functionality, either way will work.

> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>    Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Commented] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16257388#comment-16257388
 ] 

Adam Jacobs commented on JENA-1427:
---

Utility methods don't enable the same fluent style of functional programming as 
what {{ExtendedIterator}} offers today...

> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>    Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Commented] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16257356#comment-16257356
 ] 

Adam Jacobs commented on JENA-1427:
---

One more thought, rather than adding more functional methods to 
{{ExtendedIterator}}, perhaps give it the ability to convert into a Java 
{{Stream}}.
https://stackoverflow.com/questions/24511052/how-to-convert-an-iterator-to-a-stream
{noformat}
public default Stream toStream() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(this, 
Spliterator.ORDERED), false);
}
{noformat}

Or give ExtendedIterator all of these methods!  :)

> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>    Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Commented] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16257346#comment-16257346
 ] 

Adam Jacobs commented on JENA-1427:
---

{{Optional}} does add an extra object and an extra call in the functional chain.
{noformat}
RDFNode object = model.listObjectsOfProperty(subject, 
predicate).nextOptional().orElseThrow(() -> new IllegalStateException("No 
objects found for subject and predicate..."));
{noformat}

But it would still solve my use case. Perhaps this is a better method for 
ExtendedIterator?
{noformat}
public default Optional nextOptional() {
return hasNext() ? Optional.of(next()) : Optional.empty();
}
{noformat}

I wouldn't mind having both methods!  :)

> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


Re: Generic RDFVisitor

2017-11-17 Thread Adam Jacobs
I don't actually have a use case for the generics. I just saw that the 
interface was implemented in a pre-Java 5 style and wondered if it would help 
to modernize it, without breaking backwards compatibility of course. If the 
interface isn't used much, that probably answers my question.   :)




From: ajs6f <aj...@apache.org>
Sent: Friday, November 17, 2017 11:03 AM
To: dev@jena.apache.org
Subject: Re: Generic RDFVisitor

Perhaps you can say a little more about your use case here? I think we could 
probably work something out for this feature, but I am curious about why you 
are reaching for the visitor pattern?

ajs6f

> On Nov 17, 2017, at 11:27 AM, Adam Jacobs <jacobs_...@hotmail.com> wrote:
>
> Perhaps only a single generic parameter then, if each method should return 
> the same type.
> Or a sub-interface in which all three parameters are the same, the way that 
> Java's `UnaryOperator` is related to `Function`.
>
>
> 
> From: ajs6f <aj...@apache.org>
> Sent: Friday, November 17, 2017 10:01 AM
> To: dev@jena.apache.org
> Subject: Re: Generic RDFVisitor
>
> Not sure how that would play against:
>
> Object org.apache.jena.rdf.model.impl.ResourceImpl.visitWith(RDFVisitor)
>
> OTOH, I'm not sure how much use the visitor pattern there has ever really 
> gotten...
>
> ajs6f
>
>> On Nov 17, 2017, at 10:55 AM, Adam Jacobs <jacobs_...@hotmail.com> wrote:
>>
>> I wonder if it would be useful to generify the `RDFVisitor` interface...
>>
>> public interface RDFVisitor<B,U,L> {
>>
>>   B visitBlank( Resource r, AnonId id );
>>   U visitURI( Resource r, String uri );
>>   L visitLiteral( Literal l );
>>
>> }
>



[jira] [Commented] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16257292#comment-16257292
 ] 

Adam Jacobs commented on JENA-1427:
---

The use case would be to consume only one element (or none) from the iterator.

{noformat}
RDFNode object = model.listObjectsOfProperty(subject, predicate).nextOrElse(() 
-> {throw new IllegalStateException("No objects found for subject and 
predicate...");});
{noformat}

Often I have an {{ExtendedIterator}} as a result of one of the list...() 
methods on {{Model}} (listObjects, listResources, etc.).
I expect one matching element to a query. If no element is present, I would 
like to throw a custom exception; otherwise, consume the element.
More rarely, there is a sensible default value in case no elements are found. 
If multiple elements match the query, I do not need more than one. 
Occasionally, multiple elements could be considered an exception as well; but 
most often they do not matter.

Writing this comment made me realize that a {{Model}} method which takes a SPO 
and returns an {{Optional}} might solve this case too; but there are so many 
variations of list methods on Model, to provide a version of each one that 
returns Optional.

> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Updated] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)

 [ 
https://issues.apache.org/jira/browse/JENA-1427?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Adam Jacobs updated JENA-1427:
--
Description: 
Allow a functional approach for returning a default value or throwing a custom 
exception from a Jena iterator.

The following method may be added to the ExtendedIterator interface.
{noformat}
/**
 Answer the next object, if it exists, otherwise invoke the _supplier_.
 */
public default T nextOrElse( Supplier supplier ) {
return hasNext() ? next() : supplier.get();
}
{noformat}

  was:
Allow a functional approach for returning a default value or throwing a custom 
exception from a Jena iterator.

The following method may be added to the ExtendedIterator interface.
{{/**
 Answer the next object, if it exists, otherwise invoke the _supplier_.
 */
public default T nextOrElse( Supplier supplier ) {
return hasNext() ? next() : supplier.get();
}
}}


> Add nextOrElse() method in ExtendedIterator
> ---
>
> Key: JENA-1427
> URL: https://issues.apache.org/jira/browse/JENA-1427
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: Core
>Affects Versions: Jena 3.5.0
>    Reporter: Adam Jacobs
>Priority: Trivial
>  Labels: easytask
>
> Allow a functional approach for returning a default value or throwing a 
> custom exception from a Jena iterator.
> The following method may be added to the ExtendedIterator interface.
> {noformat}
> /**
>  Answer the next object, if it exists, otherwise invoke the 
> _supplier_.
>  */
> public default T nextOrElse( Supplier supplier ) {
> return hasNext() ? next() : supplier.get();
> }
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Created] (JENA-1427) Add nextOrElse() method in ExtendedIterator

2017-11-17 Thread Adam Jacobs (JIRA)
Adam Jacobs created JENA-1427:
-

 Summary: Add nextOrElse() method in ExtendedIterator
 Key: JENA-1427
 URL: https://issues.apache.org/jira/browse/JENA-1427
 Project: Apache Jena
  Issue Type: Improvement
  Components: Core
Affects Versions: Jena 3.5.0
Reporter: Adam Jacobs
Priority: Trivial


Allow a functional approach for returning a default value or throwing a custom 
exception from a Jena iterator.

The following method may be added to the ExtendedIterator interface.
{{/**
 Answer the next object, if it exists, otherwise invoke the _supplier_.
 */
public default T nextOrElse( Supplier supplier ) {
return hasNext() ? next() : supplier.get();
}
}}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


Re: Generic RDFVisitor

2017-11-17 Thread Adam Jacobs
Perhaps only a single generic parameter then, if each method should return the 
same type.
Or a sub-interface in which all three parameters are the same, the way that 
Java's `UnaryOperator` is related to `Function`.



From: ajs6f <aj...@apache.org>
Sent: Friday, November 17, 2017 10:01 AM
To: dev@jena.apache.org
Subject: Re: Generic RDFVisitor

Not sure how that would play against:

Object org.apache.jena.rdf.model.impl.ResourceImpl.visitWith(RDFVisitor)

OTOH, I'm not sure how much use the visitor pattern there has ever really 
gotten...

ajs6f

> On Nov 17, 2017, at 10:55 AM, Adam Jacobs <jacobs_...@hotmail.com> wrote:
>
> I wonder if it would be useful to generify the `RDFVisitor` interface...
>
> public interface RDFVisitor<B,U,L> {
>
>B visitBlank( Resource r, AnonId id );
>U visitURI( Resource r, String uri );
>L visitLiteral( Literal l );
>
> }



Immutability

2017-11-13 Thread Adam Jacobs
The subject of immutability was raised in JENA-1391 
(https://issues.apache.org/jira/browse/JENA-1391).

Specifically, the `getUnionModel` method in Jena 3.4 returns an immutable model 
view, and the implementation of the aforementioned story includes methods that 
will return an immutable dataset view.

The question is whether these immutable views deserve their own interfaces. 
Currently, the views are returned using what I called "unexpected immutability" 
because they implement mutable interfaces. This introduces the potential for 
`UnsupportedOperationException`s.

Unfortunately, that (degenerate) pattern is used in Java's `Collections` 
utility as well 
(https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html) but 
Scala is a clean example to draw inspiration from: by implementing immutable 
interfaces as parents to their mutable counterparts (rather than vice verse) we 
can satisfy the Liskov Substitution Principle.

Obviously, implementing that solution is easier to do from scratch than in an 
existing code base; but I imagine it could be done in multiple phases, by 
introducing the new interfaces and using them in new methods (with easy 
conversion to mutability via union) while gradually retrofitting older methods.

The question then, is whether such a change is worthwhile...

[jira] [Commented] (JENA-1391) Add Convenience Methods to Dataset

2017-11-06 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16241171#comment-16241171
 ] 

Adam Jacobs commented on JENA-1391:
---

One additional method from the {{Model}} interface that would be nice to have 
on {{Dataset}} would be {{isIsomorphicWith}}.
Presumably it's just a matter of iterating over the graphs and comparing them. 

> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>    Reporter: Adam Jacobs
>Assignee: A. Soroka
>Priority: Trivial
>
> The Dataset interface could provide several convenience methods similar to 
> the Model interface, allowing usability of RDF quads on par with RDF triples. 
> Specific examples include,
> # add(Dataset)
> # remove(Dataset)
> # union(Dataset)
> # intersection(Dataset)
> # difference(Dataset)
> # isEmpty()
> Following is a possible implementation of these methods.
> {code:java}
> default Dataset add(Dataset d) {
> this.getDefaultModel().add(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).add(d.getNamedModel(name)));
> return this;
> }
> default Dataset remove(Dataset d) {
> this.getDefaultModel().remove(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).remove(d.getNamedModel(name)));
> return this;
> }
> default Dataset union(Dataset d) {
> return DatasetFactory.create().add(this).add(d);
> }
> default Dataset difference(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
> this.listNames().forEachRemaining(name -> {
> Model difference = 
> this.getNamedModel(name).difference(d.getNamedModel(name));
> if (!difference.isEmpty()) output.addNamedModel(name, difference);
> });
> return output;
> }
> default Dataset intersection(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
> Set names = this.names();
> names.retainAll(d.names());
> names.forEach(name -> {
> Model intersection = 
> this.getNamedModel(name).intersection(d.getNamedModel(name));
> if (!intersection.isEmpty()) output.addNamedModel(name, 
> intersection);
> });
> return output;
> }
> default Set names() {
> Set names = new HashSet<>();
> this.listNames().forEachRemaining(names::add);
> return names;
> }
> default boolean isEmpty() {
> return this.asDatasetGraph().isEmpty();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Comment Edited] (JENA-1391) Add Convenience Methods to Dataset

2017-11-05 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16239546#comment-16239546
 ] 

Adam Jacobs edited comment on JENA-1391 at 11/5/17 1:55 PM:


The integration with Java's {{Collector}} interface looks very nice. That 
should help future-proof the design.

Given an immutable view of the underlying graph, having the {{DatasetLib}} 
return a new {{ImmutableDataset}} interface would avoid the potential for 
{{UnsupportedOperationException}} s. Since the implementation of the 
{{getUnionModel}} method in Jena 3.4, I've been bitten a couple of times by 
unexpected immutability. In retrospect, I wish there was an {{ImmutableModel}} 
interface for that method to return as well.


was (Author: jaco0646):
The integration with Java's {{Collector}} interface looks very nice. That 
should help future-proof the design.

Given an immutable view of the underlying graph, having the {{DatasetLib}} 
return a new {{ImmutableDataset}} interface would avoid the potential for 
{{UnsupportedOperationException}}s. (Since the implementation of the 
{{getUnionModel}} method in Jena 3.4, I've been bitten a couple of times by 
unexpected immutability. In retrospect, I wish there was an {{ImmutableModel}} 
interface for that method to return as well.)

> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>    Reporter: Adam Jacobs
>Assignee: A. Soroka
>Priority: Trivial
>
> The Dataset interface could provide several convenience methods similar to 
> the Model interface, allowing usability of RDF quads on par with RDF triples. 
> Specific examples include,
> # add(Dataset)
> # remove(Dataset)
> # union(Dataset)
> # intersection(Dataset)
> # difference(Dataset)
> # isEmpty()
> Following is a possible implementation of these methods.
> {code:java}
> default Dataset add(Dataset d) {
> this.getDefaultModel().add(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).add(d.getNamedModel(name)));
> return this;
> }
> default Dataset remove(Dataset d) {
> this.getDefaultModel().remove(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).remove(d.getNamedModel(name)));
> return this;
> }
> default Dataset union(Dataset d) {
> return DatasetFactory.create().add(this).add(d);
> }
> default Dataset difference(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
> this.listNames().forEachRemaining(name -> {
> Model difference = 
> this.getNamedModel(name).difference(d.getNamedModel(name));
> if (!difference.isEmpty()) output.addNamedModel(name, difference);
> });
> return output;
> }
> default Dataset intersection(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
> Set names = this.names();
> names.retainAll(d.names());
> names.forEach(name -> {
> Model intersection = 
> this.getNamedModel(name).intersection(d.getNamedModel(name));
> if (!intersection.isEmpty()) output.addNamedModel(name, 
> intersection);
> });
> return output;
> }
> default Set names() {
> Set names = new HashSet<>();
> this.listNames().forEachRemaining(names::add);
> return names;
> }
> default boolean isEmpty() {
> return this.asDatasetGraph().isEmpty();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Commented] (JENA-1391) Add Convenience Methods to Dataset

2017-11-05 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16239546#comment-16239546
 ] 

Adam Jacobs commented on JENA-1391:
---

The integration with Java's {{Collector}} interface looks very nice. That 
should help future-proof the design.

Given an immutable view of the underlying graph, having the {{DatasetLib}} 
return a new {{ImmutableDataset}} interface would avoid the potential for 
{{UnsupportedOperationException}}s. (Since the implementation of the 
{{getUnionModel}} method in Jena 3.4, I've been bitten a couple of times by 
unexpected immutability. In retrospect, I wish there was an {{ImmutableModel}} 
interface for that method to return as well.)

> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>    Reporter: Adam Jacobs
>Assignee: A. Soroka
>Priority: Trivial
>
> The Dataset interface could provide several convenience methods similar to 
> the Model interface, allowing usability of RDF quads on par with RDF triples. 
> Specific examples include,
> # add(Dataset)
> # remove(Dataset)
> # union(Dataset)
> # intersection(Dataset)
> # difference(Dataset)
> # isEmpty()
> Following is a possible implementation of these methods.
> {code:java}
> default Dataset add(Dataset d) {
> this.getDefaultModel().add(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).add(d.getNamedModel(name)));
> return this;
> }
> default Dataset remove(Dataset d) {
> this.getDefaultModel().remove(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).remove(d.getNamedModel(name)));
> return this;
> }
> default Dataset union(Dataset d) {
> return DatasetFactory.create().add(this).add(d);
> }
> default Dataset difference(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
> this.listNames().forEachRemaining(name -> {
> Model difference = 
> this.getNamedModel(name).difference(d.getNamedModel(name));
> if (!difference.isEmpty()) output.addNamedModel(name, difference);
> });
> return output;
> }
> default Dataset intersection(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
> Set names = this.names();
> names.retainAll(d.names());
> names.forEach(name -> {
> Model intersection = 
> this.getNamedModel(name).intersection(d.getNamedModel(name));
> if (!intersection.isEmpty()) output.addNamedModel(name, 
> intersection);
> });
> return output;
> }
> default Set names() {
> Set names = new HashSet<>();
> this.listNames().forEachRemaining(names::add);
> return names;
> }
> default boolean isEmpty() {
> return this.asDatasetGraph().isEmpty();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Updated] (JENA-1391) Add Convenience Methods to Dataset

2017-09-06 Thread Adam Jacobs (JIRA)

 [ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Adam Jacobs updated JENA-1391:
--
Description: 
The Dataset interface could provide several convenience methods similar to the 
Model interface, allowing usability of RDF quads on par with RDF triples. 
Specific examples include,
# add(Dataset)
# remove(Dataset)
# union(Dataset)
# intersection(Dataset)
# difference(Dataset)
# isEmpty()

Following is a possible implementation of these methods.

{code:java}
default Dataset add(Dataset d) {
this.getDefaultModel().add(d.getDefaultModel());
d.listNames().forEachRemaining(name -> 
this.getNamedModel(name).add(d.getNamedModel(name)));
return this;
}

default Dataset remove(Dataset d) {
this.getDefaultModel().remove(d.getDefaultModel());
d.listNames().forEachRemaining(name -> 
this.getNamedModel(name).remove(d.getNamedModel(name)));
return this;
}

default Dataset union(Dataset d) {
return DatasetFactory.create().add(this).add(d);
}

default Dataset difference(Dataset d) {
Dataset output = DatasetFactory.create();

output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
this.listNames().forEachRemaining(name -> {
Model difference = 
this.getNamedModel(name).difference(d.getNamedModel(name));
if (!difference.isEmpty()) output.addNamedModel(name, difference);
});
return output;
}

default Dataset intersection(Dataset d) {
Dataset output = DatasetFactory.create();

output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
Set names = this.names();
names.retainAll(d.names());
names.forEach(name -> {
Model intersection = 
this.getNamedModel(name).intersection(d.getNamedModel(name));
if (!intersection.isEmpty()) output.addNamedModel(name, 
intersection);
});
return output;
}

default Set names() {
Set names = new HashSet<>();
this.listNames().forEachRemaining(names::add);
return names;
}

default boolean isEmpty() {
return this.asDatasetGraph().isEmpty();
}
{code}


  was:
The Dataset interface could provide several convenience methods similar to the 
Model interface, allowing usability of RDF quads on par with RDF triples. 
Specific examples include,
# add(Dataset)
# remove(Dataset)
# union(Dataset)
# intersection(Dataset)
# difference(Dataset)
# isEmpty()

Following is a possible implementation of these methods.

{code:java}
default Dataset add(Dataset d) {
this.getDefaultModel().add(d.getDefaultModel());
d.listNames().forEachRemaining(name -> 
this.getNamedModel(name).add(d.getNamedModel(name)));
return this;
}

default Dataset remove(Dataset d) {
this.getDefaultModel().remove(d.getDefaultModel());
d.listNames().forEachRemaining(name -> 
this.getNamedModel(name).remove(d.getNamedModel(name)));
return this;
}

default Dataset union(Dataset d) {
return DatasetFactory.create().add(this).add(d);
}

default Dataset difference(Dataset d) {
Dataset output = DatasetFactory.create();

output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
this.listNames().forEachRemaining(name -> {
Model difference = 
this.getNamedModel(name).difference(d.getNamedModel(name));
if (!difference.isEmpty()) output.addNamedModel(name, difference);
});
return output;
}

default Dataset intersection(Dataset d) {
Dataset output = DatasetFactory.create();

output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
Set names = this.names();
names.retainAll(d.names());
names.forEach(name -> {
Model intersection = 
this.getNamedModel(name).intersection(d.getNamedModel(name));
if (!intersection.isEmpty()) output.addNamedModel(name, 
intersection);
});
return output;
}

default Set names() {
Set names = new HashSet<>();
this.listNames().forEachRemaining(names::add);
return names;
}

default boolean isEmpty() {
return !listNames().hasNext() && getDefaultModel().isEmpty();
}
{code}



> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>Reporter: Adam Jacobs
>Priority: Trivial
>
> The Dataset interface could provide several con

[jira] [Commented] (JENA-1391) Add Convenience Methods to Dataset

2017-09-06 Thread Adam Jacobs (JIRA)

[ 
https://issues.apache.org/jira/browse/JENA-1391?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16155374#comment-16155374
 ] 

Adam Jacobs commented on JENA-1391:
---

Consistency between the `Dataset` and `Model` interfaces seems desirable to me; 
also, in my experience, single-argument methods play nicer with lambdas and 
streams in Java.

I'm not sure about storages or transactions. Are these concerns different for 
Datasets vs. Models?

Definitely could implement these in the SPI layer rather than API. I see the 
`isEmpty()` method is already there.

> Add Convenience Methods to Dataset
> --
>
> Key: JENA-1391
> URL: https://issues.apache.org/jira/browse/JENA-1391
> Project: Apache Jena
>  Issue Type: Improvement
>  Components: ARQ
>Affects Versions: Jena 3.4.0
>    Reporter: Adam Jacobs
>Priority: Trivial
>
> The Dataset interface could provide several convenience methods similar to 
> the Model interface, allowing usability of RDF quads on par with RDF triples. 
> Specific examples include,
> # add(Dataset)
> # remove(Dataset)
> # union(Dataset)
> # intersection(Dataset)
> # difference(Dataset)
> # isEmpty()
> Following is a possible implementation of these methods.
> {code:java}
> default Dataset add(Dataset d) {
> this.getDefaultModel().add(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).add(d.getNamedModel(name)));
> return this;
> }
> default Dataset remove(Dataset d) {
> this.getDefaultModel().remove(d.getDefaultModel());
> d.listNames().forEachRemaining(name -> 
> this.getNamedModel(name).remove(d.getNamedModel(name)));
> return this;
> }
> default Dataset union(Dataset d) {
> return DatasetFactory.create().add(this).add(d);
> }
> default Dataset difference(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().difference(d.getDefaultModel()));
> this.listNames().forEachRemaining(name -> {
> Model difference = 
> this.getNamedModel(name).difference(d.getNamedModel(name));
> if (!difference.isEmpty()) output.addNamedModel(name, difference);
> });
> return output;
> }
> default Dataset intersection(Dataset d) {
> Dataset output = DatasetFactory.create();
> 
> output.setDefaultModel(this.getDefaultModel().intersection(d.getDefaultModel()));
> Set names = this.names();
> names.retainAll(d.names());
> names.forEach(name -> {
> Model intersection = 
> this.getNamedModel(name).intersection(d.getNamedModel(name));
> if (!intersection.isEmpty()) output.addNamedModel(name, 
> intersection);
> });
> return output;
> }
> default Set names() {
> Set names = new HashSet<>();
> this.listNames().forEachRemaining(names::add);
> return names;
> }
> default boolean isEmpty() {
> return !listNames().hasNext() && getDefaultModel().isEmpty();
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Created] (JENA-1390) Add toModel() method in StmtIterator

2017-09-01 Thread Adam Jacobs (JIRA)
Adam Jacobs created JENA-1390:
-

 Summary: Add toModel() method in StmtIterator
 Key: JENA-1390
 URL: https://issues.apache.org/jira/browse/JENA-1390
 Project: Apache Jena
  Issue Type: Improvement
  Components: Core
Affects Versions: Jena 3.4.0
Reporter: Adam Jacobs
Priority: Trivial


Add direct conversion of org.apache.jena.rdf.model.StmtIterator to Model.
This would align with the toList() and toSet() functionality of 
ExtendedIterator.

The following method may be added to the StmtIterator interface.

/**
 Answer a Model of the [remaining] Statements of this iterator,
 consuming this iterator.
 */
public default Model toModel() {
Model m = ModelFactory.createDefaultModel();
this.forEachRemaining(m::add);
return m;
}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Created] (JENA-1389) Return `this` rather than `void` from Dataset

2017-09-01 Thread Adam Jacobs (JIRA)
Adam Jacobs created JENA-1389:
-

 Summary: Return `this` rather than `void` from Dataset
 Key: JENA-1389
 URL: https://issues.apache.org/jira/browse/JENA-1389
 Project: Apache Jena
  Issue Type: Improvement
  Components: ARQ
Affects Versions: Jena 3.4.0
Reporter: Adam Jacobs
Priority: Trivial


Allow method chaining from the org.apache.jena.query.Dataset interface by 
returning `this` rather than `void` from the following methods.
# setDefaultModel
# addNamedModel
# removeNamedModel
# replaceNamedModel

Allowing method chaining would align with the behavior of the add and remove 
methods in org.apache.jena.rdf.model.Model.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)