fix optimisation with super session that may lead to integrity loss
at some point I've decided to stop ensuring ?1 cardinality was respected
when adding a new relation using a super session, to avoid the cost of
the delete query. That was yet discussable because it introduced unexpected
difference between execute and unsafe_execute, which is imo not worth it.
Also, now that rql() in migration script default to unsafe_execute, we
definitly don't want that implicit behaviour change (which already cause
bug when for instance adding another default workflow for an entity type:
without that fix we end up with *two* default workflows while the schema
tells we can have only one.
IMO we should go to the direction that super session skip all security
check, but nothing else, unless explicitly asked.
"""produces some Ontology Web Language schema and views
:organization: Logilab
:copyright: 2008-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
"""
__docformat__ = "restructuredtext en"
_ = unicode
from logilab.mtconverter import TransformError, xml_escape
from cubicweb.view import StartupView, EntityView
from cubicweb.selectors import none_rset, match_view
from cubicweb.web.action import Action
from cubicweb.web.views import schema
OWL_CARD_MAP = {'1': '<rdf:type rdf:resource="&owl;FunctionalProperty"/>',
'?': '<owl:maxCardinality rdf:datatype="&xsd;int">1</owl:maxCardinality>',
'+': '<owl:minCardinality rdf:datatype="&xsd;int">1</owl:minCardinality>',
'*': ''
}
OWL_TYPE_MAP = {'String': 'xsd:string',
'Datetime': 'xsd:dateTime',
'Bytes': 'xsd:byte',
'Float': 'xsd:float',
'Boolean': 'xsd:boolean',
'Int': 'xsd:int',
'Date':'xsd:date',
'Time': 'xsd:time',
'Password': 'xsd:byte',
'Decimal' : 'xsd:decimal',
'Interval': 'xsd:duration'
}
OWL_OPENING_ROOT = u'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rdf:RDF [
<!ENTITY owl "http://www.w3.org/2002/07/owl#" >
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
]>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns="http://logilab.org/owl/ontologies/%(appid)s#"
xmlns:%(appid)s="http://logilab.org/owl/ontologies/%(appid)s#"
xmlns:base="http://logilab.org/owl/ontologies/%(appid)s">
<owl:Ontology rdf:about="">
<rdfs:comment>
%(appid)s Cubicweb OWL Ontology
</rdfs:comment>
</owl:Ontology>'''
OWL_CLOSING_ROOT = u'</rdf:RDF>'
class OWLView(StartupView):
"""This view export in owl format schema database. It is the TBOX"""
__regid__ = 'owl'
title = _('owl')
templatable = False
content_type = 'application/xml' # 'text/xml'
def call(self, writeprefix=True):
skipmeta = int(self._cw.form.get('skipmeta', True))
if writeprefix:
self.w(OWL_OPENING_ROOT % {'appid': self._cw.vreg.schema.name})
self.visit_schema(skiptypes=skipmeta and schema.SKIP_TYPES or ())
if writeprefix:
self.w(OWL_CLOSING_ROOT)
def should_display_rschema(self, eschema, rschema, role):
return not rschema in self.skiptypes and (
rschema.may_have_permission('read', self._cw, eschema, role))
def visit_schema(self, skiptypes):
"""get a layout for a whole schema"""
self.skiptypes = skiptypes
entities = sorted(eschema for eschema in self._cw.vreg.schema.entities()
if not eschema.final or eschema in skiptypes)
self.w(u'<!-- classes definition -->')
for eschema in entities:
self.visit_entityschema(eschema)
self.w(u'<!-- property definition -->')
self.visit_property_schema(eschema)
self.w(u'<!-- datatype property -->')
self.visit_property_object_schema(eschema)
def visit_entityschema(self, eschema):
"""get a layout for an entity OWL schema"""
self.w(u'<owl:Class rdf:ID="%s">'% eschema)
self.w(u'<!-- relations -->')
for rschema, targetschemas, role in eschema.relation_definitions():
if not self.should_display_rschema(eschema, rschema, role):
continue
for oeschema in targetschemas:
card = rschema.role_rdef(eschema, oeschema, role).role_cardinality(role)
cardtag = OWL_CARD_MAP[card]
if cardtag:
self.w(u'''<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#%s"/>
%s
</owl:Restriction>
</rdfs:subClassOf>''' % (rschema, cardtag))
self.w(u'<!-- attributes -->')
for rschema, aschema in eschema.attribute_definitions():
if not self.should_display_rschema(eschema, rschema, 'subject'):
continue
self.w(u'''<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource="#%s"/>
<rdf:type rdf:resource="&owl;FunctionalProperty"/>
</owl:Restriction>
</rdfs:subClassOf>''' % rschema)
self.w(u'</owl:Class>')
def visit_property_schema(self, eschema):
"""get a layout for property entity OWL schema"""
for rschema, targetschemas, role in eschema.relation_definitions():
if not self.should_display_rschema(eschema, rschema, role):
continue
for oeschema in targetschemas:
self.w(u'''<owl:ObjectProperty rdf:ID="%s">
<rdfs:domain rdf:resource="#%s"/>
<rdfs:range rdf:resource="#%s"/>
</owl:ObjectProperty>''' % (rschema, eschema, oeschema.type))
def visit_property_object_schema(self, eschema):
for rschema, aschema in eschema.attribute_definitions():
if not self.should_display_rschema(eschema, rschema, 'subject'):
continue
self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
<rdfs:domain rdf:resource="#%s"/>
<rdfs:range rdf:resource="%s"/>
</owl:DatatypeProperty>''' % (rschema, eschema, OWL_TYPE_MAP[aschema.type]))
class OWLABOXView(EntityView):
'''This view represents a part of the ABOX for a given entity.'''
__regid__ = 'owlabox'
title = _('owlabox')
templatable = False
content_type = 'application/xml' # 'text/xml'
def call(self):
self.w(OWL_OPENING_ROOT % {'appid': self._cw.vreg.schema.name})
for i in xrange(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(OWL_CLOSING_ROOT)
def cell_call(self, row, col):
self.wview('owlaboxitem', self.cw_rset, row=row, col=col)
class OWLABOXItemView(EntityView):
'''This view represents a part of the ABOX for a given entity.'''
__regid__ = 'owlaboxitem'
templatable = False
content_type = 'application/xml' # 'text/xml'
def cell_call(self, row, col):
entity = self.cw_rset.complete_entity(row, col)
eschema = entity.e_schema
self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
self.w(u'<!--attributes-->')
for rschema, aschema in eschema.attribute_definitions():
if rschema.meta:
continue
rdef = rschema.rdef(eschema, aschema)
if not rdef.may_have_permission('read', self._cw):
continue
aname = rschema.type
if aname == 'eid':
continue
try:
attr = entity.printable_value(aname, format='text/plain')
if attr:
self.w(u'<%s>%s</%s>' % (aname, xml_escape(attr), aname))
except TransformError:
pass
self.w(u'<!--relations -->')
for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.meta:
continue
for tschema in targetschemas:
rdef = rschema.role_rdef(eschema, tschema, role)
if rdef.may_have_permission('read', self._cw):
break
else:
# no read perms to any relation of this type. Skip.
continue
if role == 'object':
attr = 'reverse_%s' % rschema.type
else:
attr = rschema.type
for x in getattr(entity, attr):
self.w(u'<%s>%s %s</%s>' % (attr, x.__regid__, x.eid, attr))
self.w(u'</%s>'% eschema)
class DownloadOWLSchemaAction(Action):
__regid__ = 'download_as_owl'
__select__ = none_rset() & match_view('schema')
category = 'mainactions'
title = _('download schema as owl')
def url(self):
return self._cw.build_url('view', vid='owl')