Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serve an ontology when its IRI is dereferenced #616

Merged
merged 22 commits into from
Oct 11, 2017

Conversation

benjamingeer
Copy link

@benjamingeer benjamingeer commented Sep 25, 2017

This adds a route, /ontology, which makes it possible to dereference an ontology IRI like http://api.knora.org/ontology/knora-api/v2 or http://api.knora.org/ontology/incunabula/v2 and get the ontology as JSON-LD. This works only if the Knora API server is actually accessible at http://api.knora.org.

To make this work on localhost on macOS, add the following to /etc/hosts:

127.0.0.1    api.knora.org

Then run webapi/scripts/macOS-port-forwarding.sh to forward port 80 to port 3333. For details, see Mac pfctl Port Forwarding.

These routes can now handle both API v2 schemas (simple and with value objects):

  • /ontology
  • /v2/ontologies/namedgraphs
  • /v2/ontologies/classes
  • /v2/ontologies/properties

If you request multiple entities, they all have to belong to the same schema, otherwise you get an error.

The knora-api ontologies are stored as hard-coded Scala objects:

  • KnoraApiV2WithValueObjects
  • KnoraApiV2Simple

KnoraApiV2Simple includes some custom datatypes, such as knora-api:Date, which are defined by subclassing xsd:string and restricting it with a regular expression. This probably has no effect in the triplestore, but should be useful for documentation.

Value classes and custom datatypes are served by the ontology routes like any other class. Therefore, I renamed these properties defined in OntologyConstants:

  • hasOntologiesWithResourceClasses -> hasOntologiesWithClasses
  • hasResourceClasses -> hasClasses

Currently the v2 ontology routes only serve JSON-LD. In a subsequent PR I'll implement content negotiation so they can also serve XML and HTML.

Benjamin Geer added 15 commits September 22, 2017 17:16
# Conflicts:
#	webapi/src/main/scala/org/knora/webapi/messages/v2/responder/resourcemessages/ResourceMessagesV2.scala
#	webapi/src/main/scala/org/knora/webapi/messages/v2/responder/searchmessages/SearchMessagesV2.scala
#	webapi/src/main/scala/org/knora/webapi/responders/v2/OntologyResponderV2.scala
#	webapi/src/main/scala/org/knora/webapi/responders/v2/SearchResponderV2.scala
#	webapi/src/main/scala/org/knora/webapi/routing/v2/ResourcesRouteV2.scala
…renced.

- Add missing properties to API ontologies.
- Don't throw an exception in OntologyResponderV2 if information about
  an entity isn't found (so we can handle schema.org properties).
- Refactor OntologiesRouteV2.
@benjamingeer benjamingeer changed the title Add more ontology functionality in preparation for ontology updates Serve an ontology when its IRI is dereferenced Oct 4, 2017
@benjamingeer benjamingeer added the enhancement improve existing code or new feature label Oct 4, 2017
@benjamingeer benjamingeer added this to the On Deck milestone Oct 4, 2017
@benjamingeer
Copy link
Author

Something missing here: a GUI would like to know which properties are editable. It could find out by walking up the property hierarchy to find out which properties are subproperties of knora-api:hasValue or knora-api:hasLinkTo, but that would be a lot of work for the client. Similarly, it would like to know which classes extend knora-api:Resource, meaning that new instances of those classes can be created.

We could add annotations to properties and classes:

  • knora-api:isKnoraResourceProperty
  • knora-api:isKnoraResourceClass

@benjamingeer
Copy link
Author

Also, there are subclasses of knora-api:Resource that can't be instantiated, like StillImageRepresentation. For these, we could have an annotation:

  • knora-api:isAbstractClass

@benjamingeer
Copy link
Author

Conversation with @tobiasschweizer: would be better to use

  • knora-api:isEditable, which could then exclude things like hasStandoffLinkTo.

@tobiasschweizer
Copy link
Contributor

@benjamingeer Shall I look at this PR or do you want to implemented the additional things you suggested last week?

@benjamingeer
Copy link
Author

I'm working on those things now. Maybe you can look at it later today. I'll let you know.

@tobiasschweizer
Copy link
Contributor

Ok, just let me know.

@benjamingeer
Copy link
Author

OK, I added these to knora-api in the value object schema:

  • isEditable: Indicates that a property is a resource property and can be edited via the API.
  • canBeInstantiated: Indicates whether a class is a Knora resource class that can be instantiated via the API.

@tobiasschweizer
Copy link
Contributor

tobiasschweizer commented Oct 10, 2017

hasOntologiesWithResourceClasses -> hasOntologiesWithClasses
hasResourceClasses -> hasClasses

Shall I adapt the SALSAH 2 GUI accordingly? Are there other things that may break existing client code?

@benjamingeer
Copy link
Author

Shall I adapt the SALSAH 2 GUI accordingly?

Yes, and please see whether it works for you.

Are there other things that may break existing client code?

I don't think so, but we need to check.

One thing that I'm not sure about is that if you request a class or property that doesn't exist, you don't get an error message. I wanted to change this, but it wasn't so simple, because the ontology responder gets requests for information about XSD properties, which it doesn't have.

@tobiasschweizer
Copy link
Contributor

When I try this http://localhost:3333/v2/ontologies/namedgraphs/http%3A%2F%2Fapi.knora.org%2Fontology%2Fbeol%2Fv2

I get the error: "org.knora.webapi.BadRequestException: Can't identify schema of ontology entity http://xmlns.com/foaf/0.1/Person"

this is because beol:Person is a subclass of foaf:Person and now it tries to get more information about foaf:person which we do not provide. So do we need to represent the subclass relation in a different way? I remember that we had the idea of a special semantic subclass.

@benjamingeer
Copy link
Author

benjamingeer commented Oct 10, 2017

I can see two options:

  1. We could make a property called something like subClassOfInSimpleApi. But we would then have to add GraphDB inference rules to make this property transitive (like rdfs:subClassOf).
  2. We could just use rdfs:subClassOf and make the API more tolerant, so that if it finds a superclass that it doesn't know anything about, it just returns it unchanged. We could also do the same for subproperties.

@benjamingeer
Copy link
Author

Option (2) seems easier to me.

@benjamingeer
Copy link
Author

Try it now?

@tobiasschweizer
Copy link
Contributor

Try it now?

Yes, works fine now!

We could just use rdfs:subClassOf and make the API more tolerant, so that if it finds a superclass that it doesn't know anything about, it just returns it unchanged. We could also do the same for subproperties.

But would this be true for Knora Api complex too?

@benjamingeer
Copy link
Author

But would this be true for Knora Api complex too?

I guess so. Not sure what else we could do.

I'm leaving now, will see you tomorrow morning.

Copy link
Contributor

@tobiasschweizer tobiasschweizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, a self-documenting software :-)

Please see my comments. Please see also dhlab-basel/Salsah#86

Could we start to add some tests?

objectType = Some(OntologyConstants.Xsd.Boolean)
)

val CanBeInstantiated: PropertyEntityInfoV2 = makeProperty(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only present in JSONLD if set to true? (e.g., if false it is not present in JSONLD)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

)
)

val IsEditable: PropertyEntityInfoV2 = makeProperty(
Copy link
Contributor

@tobiasschweizer tobiasschweizer Oct 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same question as below: is it only present in JSONLD if set to true?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be this way, because I can't set it to false on properties we don't control, like rdfs:label.

Copy link
Contributor

@tobiasschweizer tobiasschweizer Oct 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain what you mean by "we don't control"? Sufficient permissions provided, a resource's rdfs:label can be edited.

Or do you want to say that we can't make assertions about rdfs:label as an entity at all because it is defined elsewhere and not in our ontology?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the latter.

makePredicate(
predicateIri = OntologyConstants.Rdfs.Label,
objectsWithLang = Map(
LanguageCodes.DE -> "hat Standofflink zu",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you see a practical possibility not to define rdfs:label and rdf:comment on entities (classes and properties) redundantly in knora-base.ttl and in KnoraApiV2Simple.scala as well as in KnoraApiV2WithValueObjects.scala?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the ontology cache is built on startup and all of knora-base is loaded, couldn't you just get this information form the cache (given the IRI)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, because the ontology cache contains knora-base, which doesn't have the same structure as the knora-api ontologies. There are properties and classes in knora-api that have no equivalent in knora-base. Also, some of the "same" classes have a different structure (e.g. DateValue). So it makes sense that the labels and comments could be different. For example, the comment for knora-base:DateValue should say that it stores Julian Day Numbers, but not the comment for knora-api:DateValue.

Also, the objects in KnoraApiV2Simple and KnoraApiV2WithValueObjects are constructed when the JVM starts, before the ontology responder starts.

Copy link
Contributor

@tobiasschweizer tobiasschweizer Oct 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the point if things are actually different, but wouldn't it make sense to share information if they are the same?

Also I do not understand why knora-api:Region has to be hard-coded. Like any other resource class defined in a project-ontology, it is a subclass of knora-base:Resource and we already have the mechanisms to convert that to knora-api.

I do understand why this is necessary for value classes though.

Copy link
Contributor

@tobiasschweizer tobiasschweizer Oct 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for instance, the current implementation knora-api:Region in complex JSONLD is incomplete (label and comment are missing):

{
    @id: "knora-api:Region",
    @type: "owl:Class",
    knora - api: belongsToOntology: "http://api.knora.org/ontology/knora-api/v2",
    knora - api: canBeInstantiated: true,
    rdfs: subClassOf: [
        "http://api.knora.org/ontology/knora-api/v2#Resource",
        {
            @type: "owl:Restriction",
            owl: maxCardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#lastModificationDate"
        },
        {
            @type: "owl:Restriction",
            owl: cardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#hasColor"
        },
        {
            @type: "owl:Restriction",
            owl: minCardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#hasGeometry"
        },
        {
            @type: "owl:Restriction",
            owl: minCardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#hasComment"
        },
        {
            @type: "owl:Restriction",
            owl: cardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#creationDate"
        },
        {
            @type: "owl:Restriction",
            owl: cardinality: 1,
            owl: onProperty: "http://schema.org/name"
        },
        {
            @type: "owl:Restriction",
            owl: cardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#hasPermissions"
        },
        {
            @type: "owl:Restriction",
            owl: minCardinality: 0,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#hasStandoffLinkTo"
        },
        {
            @type: "owl:Restriction",
            owl: cardinality: 1,
            owl: onProperty: "http://api.knora.org/ontology/knora-api/v2#isRegionOf"
        }
    ]
}

In general, our documentation is already poor (labels and comments are sometimes not available in all supported languages), and this won't improve if we have to do it in three different places.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would mean implementing some way of deciding whether to use a hard-coded API entity definition or to convert a knora-base definition. How would that decision be made?

Also, knora-base:Region has predicates that knora-api:Region doesn't have, and vice versa.

@benjamingeer
Copy link
Author

Could we start to add some tests?

Yes, I'll add some.

@tobiasschweizer
Copy link
Contributor

Yes, I'll add some.

Great, thx.

I guess that this is the perfection of documentation :-)

@benjamingeer
Copy link
Author

I added a test: OntologyV2R2RSpec.

Copy link
Contributor

@tobiasschweizer tobiasschweizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final final approval

Copy link
Contributor

@tobiasschweizer tobiasschweizer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final final final approval

@tobiasschweizer tobiasschweizer merged commit 365e62c into develop Oct 11, 2017
@benjamingeer benjamingeer deleted the wip/ontology-updates-2 branch October 11, 2017 16:18
SepidehAlassi added a commit that referenced this pull request Oct 31, 2017
* develop:
  fix (webapi): update lucene index on sparql update when using graphdb-free (#633)
  KnarQL Route and Documentation (#620)
  feature (extended search V1): support Boolean value in extended search V1 (#643)
  Make the hostname of project-specific API v2 ontologies configurable (#631)
  build (travis): deactivate browser tests (#640)
  test (salsah): add headless browser testing on Travis (#590)
  Serve an ontology when its IRI is dereferenced (#616)
  fix (webapi): When requested languages aren't available, take the first one in alphabetical order (#627). (#628)
  Use cardinalities to get referenced ontologies for XML import schemas. (#617)
  docs (webapi): add description (#622)
@benjamingeer benjamingeer mentioned this pull request Apr 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement improve existing code or new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants