/******************************************************************************* * Copyright 2014 Miami-Dade County * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package org.sharegov.cirm.rest; import static org.sharegov.cirm.OWL.and; import static org.sharegov.cirm.OWL.individual; import static org.sharegov.cirm.OWL.ontology; import static org.sharegov.cirm.OWL.owlClass; import static org.sharegov.cirm.OWL.reasoner; import static org.sharegov.cirm.utils.GenUtils.ko; import java.util.HashSet; import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.semanticweb.owlapi.model.OWLClassExpression; import org.semanticweb.owlapi.model.OWLException; import org.semanticweb.owlapi.model.OWLIndividual; import org.semanticweb.owlapi.model.OWLNamedIndividual; import org.semanticweb.owlapi.model.OWLOntology; import org.semanticweb.owlapi.reasoner.OWLReasoner; import org.sharegov.cirm.OWL; import org.sharegov.cirm.Refs; import org.sharegov.cirm.StartUp; import org.sharegov.cirm.legacy.Permissions; import org.sharegov.cirm.legacy.ServiceCaseManager; import org.sharegov.cirm.owl.OWLSerialEntityCache; import org.sharegov.cirm.utils.GenUtils; import org.sharegov.cirm.utils.ThreadLocalStopwatch; import org.sharegov.cirm.utils.TraceUtils; import mjson.Json; @Path("individuals") @Produces("application/json") public class OWLIndividuals extends RestService { public static boolean DBG = false; /** * <p> * Obtain all instances of a given class. * </p> * @param classname The name of the OWL class. This can be a full IRI or a short name using * one of the ontology prefixes registered with the system. * @param direct Whether to return instances only from the top-level global ontology (true), or * also from all imported ontologies (false). * @return All instance of the class described by the class expression parameter, serialized into * JSON an array of objects where each object represents a single individual. */ @GET @Path("/instances/{classname}") public Json getOWLClassInstances(@PathParam("classname") String classname, @QueryParam("direct") boolean direct) { try { OWLReasoner reasoner = reasoner(); OWLClassExpression expr = owlClass(classname); if (!isClientExempt() && reasoner.getSuperClasses(expr, false).containsEntity(owlClass("Protected"))) expr = and(expr, Permissions.constrain(individual("BO_View"), getUserActors())); else if (!isClientExempt() && !reasoner.getSubClasses(and(expr, owlClass("Protected")), false).isBottomSingleton()) { return ko("Access denied - protected resources could be returned, please split the query."); } Set<OWLNamedIndividual> S = reasoner().getInstances(expr, direct).getFlattened(); Json A = Json.array(); for (OWLIndividual ind : S) A.add(OWL.toJSON(ind)); return A; } catch (Throwable t) { TraceUtils.error(t); return Json.array(); } } /** * <p> * Retrieve the active configuration set as identified by the * <code>ontologyConfigSet</code> startup configuration parameter. * </p> * * @return A JSON object where each member of the <code>ConfigSet</code> * is a property with name the "Name" of the member and value the "Value" * of the member. Essentially a modified JSON representation of the config * set which by default would serialized into JSON as an array of 'hasMember' * properties. * */ @GET @Path("/predefined/configset") public Json getConfigSet() throws OWLException { OWLNamedIndividual ind = individual(StartUp.getConfig().at("ontologyConfigSet").asString()); try { OWLSerialEntityCache jsonEntities = Refs.owlJsonCache.resolve(); Json el = jsonEntities.individual(ind.getIRI()).resolve(); //OWL.toJSON(ontology(), ind); Json result = Json.object(); for (Json x : el.at("hasMember").asJsonList()) { if(x.has("Value")) { //System.out.println(x); result.set(x.at("Name").asString(), x.at("Value")); } else { result.set(x.at("Name").asString(), x.at("ValueObj")); } } if (!isClientExempt() && reasoner().getTypes(ind, false).containsEntity(OWL.owlClass("Protected")) && !!Permissions.check(individual("BO_View"), ind, getUserActors())) return ko("Permission denied."); return result; } catch (Throwable t) { t.printStackTrace(System.err); return Json.object(); } } /** * <p> * Retrieve an individual by its name. The name can be a full IRI or a prefixed short form where * the prefix is one of the prefixes registered with the system. * </p> * @param individualName The name of the individual (e.g. * <code>http://www.miamidade.gov.ontology#City_of_Miami</code> or <code>legacy:TM15</code>) * @return The standard JSON representation of the individual. * @throws OWLException */ @GET @Path("/{individual}") @Produces("application/json") public Json getOWLIndividual(@PathParam("individual") String individualName) throws OWLException { try { return getOWLIndividualByName(individualName); } catch (Throwable t) { t.printStackTrace(System.err); return Json.object(); } } public Json getOWLIndividualByName(String individualName) throws OWLException { OWLNamedIndividual ind = individual(individualName); Json el = OWL.toJSON(ontology(), ind); if (!isClientExempt() && reasoner().getTypes(ind, false).containsEntity(OWL.owlClass("Protected")) && !Permissions.check(individual("BO_View"), individual(individualName), getUserActors())) return ko("Permission denied."); return el; } /** * Determines if an OWL individual was modified after a specified time. * * This currently works for service case types, but not yet for other individuals. * Also, currently only local changes that were applied to an sr type after the server was started * are considered in determining modifiedAfter. * TODO consider changes in persisted managed ontology history * * @param indPrefixedIri the prefixed IRI of the individual (format "legacy:xxx") * @param timeMs specified time in milliseconds * @return ok with a boolean modifiedAfter property; false means not modified or individual changes not found. * @throws OWLException */ @GET @Path("/{individual}/modifiedAfter/{timeMs}") @Produces("application/json") public Json isOWLIndividualModifiedAfter(@PathParam("individual") String indPrefixedIri, @PathParam("timeMs") Long timeMs) throws OWLException { if (timeMs == null) return GenUtils.ko("timeMs parameter was null"); if (indPrefixedIri == null || indPrefixedIri.isEmpty()) return GenUtils.ko("indPrefixedIri was null or empty"); return GenUtils.ok().set("modifiedAfter", ServiceCaseManager.getInstance().isInvididualModifiedAfter(indPrefixedIri, timeMs)); } /** * <p> * Perform a query for individuals in the ontology using a DL class expression. * </p> * * @param queryAsString A DL (description logic) class expression using the * <a href="http://protegewiki.stanford.edu/wiki/DLQueryTab">Manchnester syntax</a> * @return All instance of the class described by the class expression parameter, serialized into * JSON an array of objects where each object represents a single individual. */ @GET @Path("/") public synchronized Json doQuery(@QueryParam("q") String queryAsString) { try { if (DBG) { ThreadLocalStopwatch.start("START doQuery: " + queryAsString); } OWLOntology ontology = ontology(); OWLReasoner reasoner = reasoner(ontology); OWLClassExpression expr = OWL.parseDL(queryAsString, ontology); Set<OWLNamedIndividual> allAllowed = null; if (!isClientExempt() && reasoner.getSuperClasses(expr, false).containsEntity(owlClass("Protected"))) { // queryAsString = Permissions.constrainClause(individual("BO_View"), getUserActors()) // + " and " + queryAsString; allAllowed = new HashSet<OWLNamedIndividual>(); Set<OWLNamedIndividual> policies = Permissions.policiesForActors(getUserActors()); for (OWLNamedIndividual x : policies) { Set<OWLNamedIndividual> policyObjects = OWL.objectProperties(x, "hasObject"); allAllowed.addAll(policyObjects); } } // The following is not a 100% test for protection. To be 100%, we'd have // to check that getInstances returns an empty set rather than getSubClasses, but // this will work in practice and it's a hopefully faster test else if (!isClientExempt() && !reasoner.getSubClasses(and(expr, owlClass("Protected")), false).isBottomSingleton()) { return ko("Access denied - protected resources could be returned, please split the query."); } OWLSerialEntityCache jsonEntities = Refs.owlJsonCache.resolve(); Json result = Json.array(); for (OWLNamedIndividual ind : OWL.queryIndividuals(queryAsString)) { if (allAllowed == null || allAllowed.contains(ind)) { result.add(jsonEntities.individual(ind.getIRI()).resolve()); } } if (DBG) { ThreadLocalStopwatch.stop("END doQuery"); } return result; } catch (Exception ex) { System.out.println("While get instances for " + queryAsString); ex.printStackTrace(); return ko(ex); } } public synchronized Json doInternalQuery (String queryAsString) { OWLOntology ontology = ontology(); OWLReasoner reasoner = reasoner(ontology); OWLClassExpression expr = OWL.parseDL(queryAsString, ontology); Set<OWLNamedIndividual> allAllowed = null; if (!isClientExempt() && reasoner.getSuperClasses(expr, false).containsEntity(owlClass("Protected"))) { allAllowed = new HashSet<OWLNamedIndividual>(); Set<OWLNamedIndividual> policies = Permissions.policiesForActors(getUserActors()); for (OWLNamedIndividual x : policies) { Set<OWLNamedIndividual> policyObjects = OWL.objectProperties(x, "hasObject"); allAllowed.addAll(policyObjects); } } // The following is not a 100% test for protection. To be 100%, we'd have // to check that getInstances returns an empty set rather than getSubClasses, but // this will work in practice and it's a hopefully faster test else if (!isClientExempt() && !reasoner.getSubClasses(and(expr, owlClass("Protected")), false).isBottomSingleton()) { throw new IllegalAccessError ("Access denied - protected resources could be returned, please split the query."); } // OWLSerialEntityCache jsonEntities = Refs.owlJsonCache.resolve(); Json j = Json.array(); for (OWLNamedIndividual ind : OWL.queryIndividuals(queryAsString)) if (allAllowed == null || allAllowed.contains(ind)) j.add(jsonEntities.individual(ind.getIRI()).resolve()); return j; } }