# baseURI: https://ekgf.org/dprod/spec/develop/contracts/shapes/
# imports: https://ekgf.org/dprod/spec/develop/contracts/
# imports: http://www.w3.org/ns/shacl#
# prefix: dprod-shapes

@base <https://ekgf.org/dprod/spec/develop/contracts/shapes/> .
@prefix dprod-shapes: <https://ekgf.org/dprod/spec/develop/contracts/shapes/> .
@prefix dprod: <https://ekgf.org/dprod/spec/develop/> .
@prefix dct: <http://purl.org/dc/terms/> .
@prefix odrl: <http://www.w3.org/ns/odrl/2/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix prov: <http://www.w3.org/ns/prov#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

dprod-shapes:
  a owl:Ontology ;
  dct:title "Shapes for DPROD Data Contracts"@en ;
  rdfs:label "DPROD contracts shapes"@en ;
  dct:description "SHACL validation shapes for DPROD data contract policies."@en ;
  rdfs:comment
    "This is intended to be used with SHACL, not as an ontology: the ontology element is to provide the metadata for the set of shapes."@en ;
  dct:license <https://creativecommons.org/licenses/by/4.0/> ;
  dct:modified "2026-08-20"^^xsd:date ;
  owl:imports <https://ekgf.org/dprod/spec/develop/contracts/> ;
  owl:imports sh: ;
  owl:versionInfo "0.7" ;
  sh:declare [
    sh:prefix "dprod" ;
    sh:namespace "https://ekgf.org/dprod/spec/develop/" ;
  ] ;
  sh:declare [
    sh:prefix "dprod-shapes" ;
    sh:namespace "https://ekgf.org/dprod/spec/develop/contracts/shapes/" ;
  ] ;
  sh:declare [
    sh:prefix "odrl" ;
    sh:namespace "http://www.w3.org/ns/odrl/2/" ;
  ] ;
.


############################# Reusable Property Groups #########################


dprod-shapes:OfferLifecycleStatusPropertyGroup
  a sh:PropertyShape ;
  sh:name "offer lifecycle status" ;
  sh:description "Optional authored lifecycle status for a DataOffer. The value must be a skos:Concept; DPROD's scheme is optional and profiles may use an enterprise taxonomy."@en ;
  sh:path dprod:offerLifecycleStatus ;
  sh:maxCount 1 ;
  sh:nodeKind sh:IRI ;
  sh:class skos:Concept ;
  sh:message "offerLifecycleStatus, if present, must be a single skos:Concept value." ;
.

dprod-shapes:ContractLifecycleStatusPropertyGroup
  a sh:PropertyShape ;
  sh:name "contract lifecycle status" ;
  sh:description "Optional authored lifecycle status for a DataContract. The value must be a skos:Concept; DPROD's scheme is optional and profiles may use an enterprise taxonomy."@en ;
  sh:path dprod:contractLifecycleStatus ;
  sh:maxCount 1 ;
  sh:nodeKind sh:IRI ;
  sh:class skos:Concept ;
  sh:message "contractLifecycleStatus, if present, must be a single skos:Concept value." ;
.

dprod-shapes:DutyStatePropertyGroup
  a sh:PropertyShape ;
  sh:name "duty state" ;
  sh:description "Optional evaluated state for a Duty. Value must be a skos:Concept; the four DPROD-defined concepts (Pending, Active, Fulfilled, Violated) are the canonical vocabulary that the standard evaluation algorithm transitions between."@en ;
  sh:path dprod:dutyState ;
  sh:maxCount 1 ;
  sh:nodeKind sh:IRI ;
  sh:class skos:Concept ;
  sh:message "dutyState, if present, must be a single skos:Concept value." ;
.

dprod-shapes:ProfilePropertyGroup
  a sh:PropertyShape ;
  sh:name "profile" ;
  sh:description "The ODRL profile token a policy must declare to be recognised as DPROD. Reused by Set, Offer, Agreement, DataOffer, and DataContract shapes."@en ;
  sh:path odrl:profile ;
  sh:minCount 1 ;
  sh:hasValue <https://ekgf.org/dprod/spec/develop/> ;
  sh:message "DPROD policies must declare odrl:profile <https://ekgf.org/dprod/spec/develop/>." ;
.

dprod-shapes:NonEmptyClausesConstraint
  a sh:NodeShape ;
  sh:or (
    [ sh:property [ sh:path odrl:permission ; sh:minCount 1 ] ]
    [ sh:property [ sh:path odrl:prohibition ; sh:minCount 1 ] ]
    [ sh:property [ sh:path odrl:obligation ; sh:minCount 1 ] ]
  ) ;
  sh:message "Policy must have at least one permission, prohibition, or obligation." ;
.


############################# Policy Shapes #########################


dprod-shapes:PolicyShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "policy shape" ;
  sh:targetClass odrl:Policy ;
  sh:name "Policy Shape" ;
  sh:property [
    sh:path odrl:profile ;
    sh:minCount 1 ;
    sh:hasValue <https://ekgf.org/dprod/spec/develop/> ;
    sh:message "DPROD policies must declare odrl:profile <https://ekgf.org/dprod/spec/develop/>."
  ] ;
.

dprod-shapes:SetShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "set shape" ;
  sh:targetClass odrl:Set ;
  sh:name "Set Shape" ;
  sh:property dprod-shapes:ProfilePropertyGroup ;
  sh:node dprod-shapes:NonEmptyClausesConstraint ;
  sh:property [
    sh:path odrl:target ;
    sh:message "Set policy may declare a policy-level target (inherited by rules)."
  ] ;
.

dprod-shapes:OfferShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "offer shape" ;
  sh:targetClass odrl:Offer ;
  sh:name "Offer Shape" ;
  sh:property dprod-shapes:ProfilePropertyGroup ;
  sh:node dprod-shapes:NonEmptyClausesConstraint ;
  sh:property [
    sh:path odrl:assigner ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Offer must have exactly one assigner."
  ] ;
.

dprod-shapes:AgreementShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "agreement shape" ;
  sh:targetClass odrl:Agreement ;
  sh:name "Agreement Shape" ;
  sh:property dprod-shapes:ProfilePropertyGroup ;
  sh:node dprod-shapes:NonEmptyClausesConstraint ;
  sh:property [
    sh:path odrl:assigner ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Agreement must have exactly one assigner."
  ] ;
  sh:property [
    sh:path odrl:assignee ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Agreement must have exactly one assignee."
  ] ;
.


############################# Rule Shapes #########################


dprod-shapes:PermissionShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "permission shape" ;
  sh:targetClass odrl:Permission ;
  sh:name "Permission Shape" ;
  sh:property [
    sh:path odrl:action ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Permission must have exactly one action."
  ] ;
  sh:property [
    sh:path odrl:target ;
    sh:maxCount 1 ;
    sh:message "Permission may have at most one target (inherits from policy if absent)."
  ] ;
.

dprod-shapes:ProhibitionShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "prohibition shape" ;
  sh:targetClass odrl:Prohibition ;
  sh:name "Prohibition Shape" ;
  sh:property [
    sh:path odrl:action ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Prohibition must have exactly one action."
  ] ;
  sh:property [
    sh:path odrl:target ;
    sh:maxCount 1 ;
    sh:message "Prohibition may have at most one target (inherits from policy if absent)."
  ] ;
.

dprod-shapes:DutyShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "duty shape" ;
  sh:targetClass odrl:Duty ;
  sh:name "Duty Shape" ;
  sh:property [
    sh:path odrl:action ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Duty must have exactly one action."
  ] ;
  sh:property [
    sh:path dprod:deadline ;
    sh:maxCount 1 ;
    sh:or (
      [ sh:datatype xsd:dateTime ]
      [ sh:datatype xsd:duration ]
    ) ;
    sh:message "Deadline must be xsd:dateTime or xsd:duration."
  ] ;
  sh:property [
    sh:path dprod:recurrence ;
    sh:maxCount 1 ;
    sh:datatype xsd:string ;
    sh:pattern "^FREQ=(SECONDLY|MINUTELY|HOURLY|DAILY|WEEKLY|MONTHLY|YEARLY)" ;
    sh:message "Recurrence must be a valid RFC 5545 RRULE starting with FREQ=."
  ] ;
  sh:property [
    sh:path dprod:subjectOfDuty ;
    sh:maxCount 1 ;
    sh:class odrl:Party ;
    sh:message "Duty subject must be a single odrl:Party."
  ] ;
  sh:property [
    sh:path dprod:objectOfDuty ;
    sh:maxCount 1 ;
    sh:class odrl:Party ;
    sh:message "Duty object must be a single odrl:Party."
  ] ;
  sh:property dprod-shapes:DutyStatePropertyGroup ;
.

# Duty-only properties (#239). Their OWL domains infer odrl:Duty rather than
# validate it, so a Permission or Prohibition carrying one would silently gain
# a second, ODRL-disjoint rule type. Reject that explicitly: the subject must be
# a Duty and must not be a Permission or Prohibition, whatever inference says.
dprod-shapes:DutyOnlyPropertiesShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "duty-only properties shape" ;
  sh:name "Duty-Only Properties Shape" ;
  sh:targetSubjectsOf dprod:deadline, dprod:recurrence, dprod:subjectOfDuty, dprod:objectOfDuty ;
  sh:class odrl:Duty ;
  sh:not [ sh:class odrl:Permission ] ;
  sh:not [ sh:class odrl:Prohibition ] ;
  sh:message "dprod:deadline, dprod:recurrence, dprod:subjectOfDuty and dprod:objectOfDuty are duty-only: the subject must be an odrl:Duty and not an odrl:Permission or odrl:Prohibition." ;
.


############################# Constraint Shapes #########################


dprod-shapes:ConstraintShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "constraint shape" ;
  sh:targetClass odrl:Constraint ;
  sh:name "Constraint Shape" ;
  sh:property [
    sh:path odrl:leftOperand ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Constraint must have exactly one leftOperand."
  ] ;
  sh:property [
    sh:path odrl:operator ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "Constraint must have exactly one operator."
  ] ;
  sh:property [
    sh:path odrl:rightOperand ;
    sh:minCount 1 ;
    sh:message "Constraint must have a rightOperand."
  ] ;
.

dprod-shapes:LogicalConstraintShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "logical constraint shape" ;
  sh:targetClass odrl:LogicalConstraint ;
  sh:name "Logical Constraint Shape" ;
  sh:xone (
    [ sh:property [ sh:path odrl:and ; sh:minCount 1 ; sh:maxCount 1 ] ]
    [ sh:property [ sh:path odrl:or ; sh:minCount 1 ; sh:maxCount 1 ] ]
    [ sh:property [ sh:path dprod:not ; sh:minCount 1 ; sh:maxCount 1 ] ]
  ) ;
  sh:message "LogicalConstraint must have exactly one of: odrl:and, odrl:or, or dprod:not." ;
.


############################# Contract Shapes #########################


dprod-shapes:DataOfferShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "data offer shape" ;
  sh:targetClass dprod:DataOffer ;
  sh:name "Data Offer Shape" ;
  sh:property dprod-shapes:ProfilePropertyGroup ;
  sh:node dprod-shapes:NonEmptyClausesConstraint ;
  sh:property [
    sh:path odrl:assigner ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "DataOffer must have exactly one assigner."
  ] ;
  sh:property dprod-shapes:OfferLifecycleStatusPropertyGroup ;
  sh:property [
    sh:path dprod:effectiveDate ;
    sh:maxCount 1 ;
    sh:datatype xsd:dateTime ;
    sh:message "effectiveDate, if present, must be a single xsd:dateTime value."
  ] ;
  sh:property [
    sh:path dprod:expirationDate ;
    sh:maxCount 1 ;
    sh:datatype xsd:dateTime ;
    sh:message "expirationDate, if present, must be a single xsd:dateTime value."
  ] ;
.

dprod-shapes:DataContractShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "data contract shape" ;
  sh:targetClass dprod:DataContract ;
  sh:name "Data Contract Shape" ;
  sh:property dprod-shapes:ProfilePropertyGroup ;
  sh:node dprod-shapes:NonEmptyClausesConstraint ;
  sh:property [
    sh:path odrl:assigner ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "DataContract must have exactly one assigner (data provider)."
  ] ;
  sh:property [
    sh:path odrl:assignee ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:message "DataContract must have exactly one assignee (data consumer)."
  ] ;
  sh:property [
    sh:path dprod:acceptsOffer ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:class dprod:DataOffer ;
    sh:message "DataContract must reference exactly one DataOffer."
  ] ;
  sh:property dprod-shapes:ContractLifecycleStatusPropertyGroup ;
  sh:property [
    sh:path dprod:effectiveDate ;
    sh:maxCount 1 ;
    sh:datatype xsd:dateTime ;
    sh:message "effectiveDate, if present, must be a single xsd:dateTime value."
  ] ;
  sh:property [
    sh:path dprod:expirationDate ;
    sh:maxCount 1 ;
    sh:datatype xsd:dateTime ;
    sh:message "expirationDate, if present, must be a single xsd:dateTime value."
  ] ;
.

dprod-shapes:RejectMixedLifecycleStatusOnDataOfferShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "reject mixed lifecycle status on data offer shape" ;
  sh:targetClass dprod:DataOffer ;
  sh:property [
    sh:path dprod:dataProductLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataOffer must not use dprod:dataProductLifecycleStatus."
  ] ;
  sh:property [
    sh:path dprod:contractLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataOffer must not use dprod:contractLifecycleStatus."
  ] ;
.

dprod-shapes:RejectMixedLifecycleStatusOnDataContractShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "reject mixed lifecycle status on data contract shape" ;
  sh:targetClass dprod:DataContract ;
  sh:property [
    sh:path dprod:dataProductLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataContract must not use dprod:dataProductLifecycleStatus."
  ] ;
  sh:property [
    sh:path dprod:offerLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataContract must not use dprod:offerLifecycleStatus."
  ] ;
.

dprod-shapes:RejectMixedLifecycleStatusOnDataProductShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "data product lifecycle status separation shape" ;
  sh:targetClass dprod:DataProduct ;
  sh:property [
    sh:path dprod:offerLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataProduct must not use dprod:offerLifecycleStatus."
  ] ;
  sh:property [
    sh:path dprod:contractLifecycleStatus ;
    sh:maxCount 0 ;
    sh:message "DataProduct must not use dprod:contractLifecycleStatus."
  ] ;
.


############################# Operand Shapes #########################


dprod-shapes:EvaluationContextShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "evaluation context shape" ;
  sh:targetClass dprod:EvaluationContext ;
  sh:property [
    sh:path dprod:request ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:message "An evaluation context must have exactly one dprod:request graph root."
  ] ;
  sh:property [
    sh:path dprod:state ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:nodeKind sh:BlankNodeOrIRI ;
    sh:class prov:Entity ;
    sh:message "An evaluation context must have exactly one immutable dprod:state snapshot, typed as prov:Entity."
  ] ;
  sh:property [
    sh:path dprod:agent ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:nodeKind sh:IRI ;
    sh:class odrl:Party ;
    sh:message "An evaluation context must have exactly one dprod:agent typed as odrl:Party."
  ] ;
  sh:property [
    sh:path dprod:clock ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
    sh:datatype xsd:dateTime ;
    sh:message "An evaluation context must have exactly one dprod:clock xsd:dateTime."
  ] ;
.


dprod-shapes:LeftOperandShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "left operand shape" ;
  sh:targetClass odrl:LeftOperand ;
  sh:targetObjectsOf odrl:leftOperand ;
  sh:name "Left Operand Shape" ;
  sh:or (
    [ sh:in (dprod:currentAgent odrl:dateTime) ]
    [
      sh:property [
        sh:path dprod:operandSource ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:nodeKind sh:IRI ;
        sh:in (dprod:requestSource dprod:stateSource dprod:contextSource)
      ]
    ]
  ) ;
  sh:message "Every left operand must declare exactly one dprod:operandSource: requestSource, stateSource, or contextSource." ;
  sh:or (
    [ sh:in (dprod:currentAgent odrl:dateTime) ]
    [
      sh:property [
        sh:path dprod:operandProperty ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:nodeKind sh:IRI
      ]
    ]
  ) ;
  sh:message "Every left operand must declare exactly one dprod:operandProperty, which must be IRI-valued." ;
.


############################# Rejection Shapes #########################
# Reject unsupported ODRL constructs


dprod-shapes:RejectRuntimeReferenceShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "obsolete runtime reference rejection shape" ;
  sh:targetClass dprod:RuntimeReference ;
  sh:property [
    sh:path rdf:type ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:RuntimeReference is obsolete; declare an odrl:LeftOperand with one source/property binding."
  ] ;
.

dprod-shapes:RejectOperandPathShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "obsolete operand path rejection shape" ;
  sh:targetSubjectsOf dprod:path ;
  sh:property [
    sh:path dprod:path ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:path is obsolete; normalize the source graph and use dprod:operandSource plus dprod:operandProperty."
  ] ;
.


dprod-shapes:RejectObsoleteOfferLifecycleStatusSpellingShape
  a sh:NodeShape ;
  sh:targetSubjectsOf dprod:offerLifeCycleStatus ;
  sh:property [
    sh:path dprod:offerLifeCycleStatus ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:offerLifeCycleStatus is obsolete; use dprod:offerLifecycleStatus."
  ] ;
.

dprod-shapes:RejectObsoleteContractLifecycleStatusSpellingShape
  a sh:NodeShape ;
  sh:targetSubjectsOf dprod:contractLifeCycleStatus ;
  sh:property [
    sh:path dprod:contractLifeCycleStatus ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:contractLifeCycleStatus is obsolete; use dprod:contractLifecycleStatus."
  ] ;
.


dprod-shapes:RejectXoneShape
  a sh:NodeShape ;
  sh:targetSubjectOf odrl:xone ;
  sh:property [
    sh:path odrl:xone ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "DPROD contracts do not support xone operator."
  ] ;
.

dprod-shapes:RejectRemedyShape
  a sh:NodeShape ;
  sh:targetSubjectOf odrl:remedy ;
  sh:property [
    sh:path odrl:remedy ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "DPROD contracts do not support odrl:remedy."
  ] ;
.

dprod-shapes:RejectConsequenceShape
  a sh:NodeShape ;
  sh:targetSubjectOf odrl:consequence ;
  sh:property [
    sh:path odrl:consequence ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "DPROD contracts do not support odrl:consequence."
  ] ;
.

dprod-shapes:RejectTicketShape
  a sh:NodeShape ;
  sh:targetClass odrl:Ticket ;
  sh:sparql [
    sh:message "DPROD contracts do not support odrl:Ticket." ;
    sh:severity sh:Violation ;
    sh:select """
      SELECT $this WHERE { $this a odrl:Ticket }
    """ ;
  ] ;
.

dprod-shapes:RejectRequestShape
  a sh:NodeShape ;
  sh:targetClass odrl:Request ;
  sh:sparql [
    sh:message "DPROD contracts reject odrl:Request because Offer-Request-Agreement semantics are undefined; support is deferred." ;
    sh:severity sh:Violation ;
    sh:select """
      SELECT $this WHERE { $this a odrl:Request }
    """ ;
  ] ;
.

dprod-shapes:PartOfShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "ODRL collection membership shape" ;
  sh:targetSubjectsOf odrl:partOf ;
  sh:or (
    [
      sh:class odrl:Asset ;
      sh:property [ sh:path odrl:partOf ; sh:class odrl:AssetCollection ]
    ]
    [
      sh:class odrl:AssetCollection ;
      sh:property [ sh:path odrl:partOf ; sh:class odrl:AssetCollection ]
    ]
    [
      sh:class odrl:Party ;
      sh:property [ sh:path odrl:partOf ; sh:class odrl:PartyCollection ]
    ]
    [
      sh:class odrl:PartyCollection ;
      sh:property [ sh:path odrl:partOf ; sh:class odrl:PartyCollection ]
    ]
  ) ;
  sh:message "odrl:partOf must link an odrl:Asset to an odrl:AssetCollection or an odrl:Party to an odrl:PartyCollection." ;
.

dprod-shapes:AssetCollectionShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "explicit asset collection shape" ;
  sh:targetClass odrl:AssetCollection ;
  sh:property [
    sh:path odrl:source ;
    sh:maxCount 0 ;
    sh:message "DPROD contracts support explicit collection membership only; odrl:source collection resolution is not supported."
  ] ;
  sh:property [
    sh:path odrl:refinement ;
    sh:maxCount 0 ;
    sh:message "DPROD contracts support explicit collection membership only; collection odrl:refinement is not supported."
  ] ;
.

dprod-shapes:PartyCollectionShape
  a sh:NodeShape ;
  rdfs:isDefinedBy dprod-shapes: ;
  rdfs:label "explicit party collection shape" ;
  sh:targetClass odrl:PartyCollection ;
  sh:property [
    sh:path odrl:source ;
    sh:maxCount 0 ;
    sh:message "DPROD contracts support explicit collection membership only; odrl:source collection resolution is not supported."
  ] ;
  sh:property [
    sh:path odrl:refinement ;
    sh:maxCount 0 ;
    sh:message "DPROD contracts support explicit collection membership only; collection odrl:refinement is not supported."
  ] ;
.

dprod-shapes:RejectObsoleteDprodPartOfShape
  a sh:NodeShape ;
  sh:targetSubjectsOf dprod:partOf ;
  sh:property [
    sh:path dprod:partOf ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:partOf is obsolete; use odrl:partOf."
  ] ;
.

dprod-shapes:RejectObsoleteDprodMemberOfShape
  a sh:NodeShape ;
  sh:targetSubjectsOf dprod:memberOf ;
  sh:property [
    sh:path dprod:memberOf ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "dprod:memberOf is obsolete; use odrl:partOf."
  ] ;
.

dprod-shapes:RejectInheritAllowedShape
  a sh:NodeShape ;
  sh:targetSubjectOf odrl:inheritAllowed ;
  sh:property [
    sh:path odrl:inheritAllowed ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "DPROD contracts do not support odrl:inheritAllowed."
  ] ;
.

dprod-shapes:RejectInheritFromShape
  a sh:NodeShape ;
  sh:targetSubjectOf odrl:inheritFrom ;
  sh:property [
    sh:path odrl:inheritFrom ;
    sh:maxCount 0 ;
    sh:severity sh:Violation ;
    sh:message "DPROD contracts do not support odrl:inheritFrom."
  ] ;
.
