All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.coinsweb.sdk.injectors.WOAInjector Maven / Gradle / Ivy

There is a newer version: 1.1.606
Show newest version
/**
 * MIT License
 *
 * Copyright (c) 2016 Bouw Informatie Raad
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 **/
package nl.coinsweb.sdk.injectors;

import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.impl.PropertyImpl;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import nl.coinsweb.sdk.CoinsModel;
import nl.coinsweb.sdk.exceptions.WOAAccessDeniedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @author Bastiaan Bijl, Sysunite 2016
 */
public class WOAInjector implements Injector {

  protected static final Logger log = LoggerFactory.getLogger(WOAInjector.class);

  private static final String NO_ACCESS = "http://www.coinsweb.nl/COINSWOA.rdf#NoAccess";
  private static final String READ_ACCESS = "http://www.coinsweb.nl/COINSWOA.rdf#ReadAccess";
  private static final String WRITE_ACCESS = "http://www.coinsweb.nl/COINSWOA.rdf#WriteAccess";

  Model woaModel;
  OntModel instanceModel;
  HashMap cache = new HashMap<>();

  public WOAInjector(Model woaModel, OntModel instanceModel) {
    this.woaModel = woaModel;
    this.instanceModel = instanceModel;

    // Init the cache
    buildCache();
  }

  /*

      http://www.coinsweb.nl/wiki/index.php/Window_of_Authorization

      Finally, all (non-function fulfiller) information objects that cannot be reached
      using above procedure will receive by default write-access rights.

   */

  public void buildCache() {

    String queryString =

        " PREFIX rdf:  \n" +
        " PREFIX rdfs:       \n" +
        " PREFIX owl:               \n" +
        " PREFIX woa:         \n" +
        " SELECT ?uri ?level ?depth                                 \n" +
        " WHERE                                                     \n" +
        " {                                                         \n" +
        "    ?uri rdf:type ?level .                                 \n" +
        "    OPTIONAL {                                             \n" +
        "      ?uri woa:layerdepth ?depth .                         \n" +
        "    }                                                      \n" +
        " }                                                           ";

    // Execute the query and obtain results
    QueryExecution queryExecution = QueryExecutionFactory.create(queryString, Syntax.syntaxSPARQL_11, woaModel);
    ResultSet result = queryExecution.execSelect();

    // Output query results
    while (result.hasNext()) {

      QuerySolution row = result.next();

      RDFNode uri = row.get("uri");
      RDFNode level = row.get("level");
      RDFNode depth = row.get("depth");

      if(!uri.isResource() || !level.isResource()) {
        continue;
      }

      int depthInt = 0;
      if(depth!=null && depth.isLiteral()) {
        depthInt = depth.asLiteral().getInt();
      }

      // Check if the level is valid
      if(!NO_ACCESS.equals(level.toString()) && !READ_ACCESS.equals(level.toString()) && !WRITE_ACCESS.equals(level.toString())) {
        continue;
      }

      setCacheValue(new Clearance(uri.toString(), level.toString(), 0));
      List subParts = getParts(new ArrayList(), uri.asNode(), 1, depthInt, level.toString());
      for(Clearance part : subParts) {
        setCacheValue(part);
      }
    }

    queryExecution.close();
  }

  private void setCacheValue(Clearance clearance) {

    // Is the level was not set already, easy
    if(!cache.containsKey(clearance.uri)) {
      log.info("Set level "+clearance.level+" for "+clearance.uri);
      cache.put(clearance.uri, clearance);
      return;
    }

    // Else, see which is the more precise
    Clearance current = cache.get(clearance.uri);

    // Keep the old one
    if(current.distance < clearance.distance) {
      return;
    }

    // Take the new one
    if(clearance.distance < current.distance) {
      log.info("Set level "+clearance.level+" for "+clearance.uri);
      cache.put(clearance.uri, clearance);
      return;
    }

    // If the distance is equal, pick the more restrictive
    if(NO_ACCESS.equals(clearance.level) || NO_ACCESS.equals(current.level)) {
      log.info("Set level "+NO_ACCESS+" for "+clearance.uri);
      cache.put(clearance.uri, new Clearance(clearance.uri, NO_ACCESS, clearance.distance));
      return;
    }

    if(READ_ACCESS.equals(clearance.level) || READ_ACCESS.equals(current.level)) {
      log.info("Set level "+READ_ACCESS+" for "+clearance.uri);
      cache.put(clearance.uri, new Clearance(clearance.uri, READ_ACCESS, clearance.distance));
      return;
    }

    if(WRITE_ACCESS.equals(clearance.level) || WRITE_ACCESS.equals(current.level)) {
      log.info("Set level "+WRITE_ACCESS+" for "+clearance.uri);
      cache.put(clearance.uri, new Clearance(clearance.uri, WRITE_ACCESS, clearance.distance));
      return;
    }

  }

  private boolean hasClearance(String uri, String level) {

    // Grant by default
    if(!cache.containsKey(uri)) {
      return true;
    }

    // If requesting read access only no_access can block
    if(READ_ACCESS.equals(level) && cache.get(uri).level.equals(NO_ACCESS)) {
      return false;
    }

    // If requesting write access both no_access and read_access can block
    if(WRITE_ACCESS.equals(level) && cache.get(uri).level.equals(NO_ACCESS) ||
       WRITE_ACCESS.equals(level) && cache.get(uri).level.equals(READ_ACCESS)) {
      return false;
    }

    return true;
  }

  private class Clearance {
    public String uri;
    public String level;
    public int distance;
    public Clearance(String uri, String level, int distance) {
      this.uri = uri;
      this.level = level;
      this.distance = distance;
    }
    @Override
    public int hashCode() {
      return level.hashCode();
    }
    @Override
    public boolean equals(Object o) {
      return level.equals(o);
    }
  }




  @Override
  public boolean proposeRead(CoinsModel model, String subject) {



    if(!hasClearance(subject, READ_ACCESS)) {
      log.trace("Received \uD83D\uDEC2 propose read, deny.");
      throw new WOAAccessDeniedException("WOA restriction blocked operation.");
    }

    log.trace("Received \uD83D\uDEC2 propose read, grant." );
    return true;
  }

  @Override
  public boolean proposeRead(CoinsModel model, String subject, String predicate) {

    if(!hasClearance(subject, READ_ACCESS)) {
      log.trace("Received \uD83D\uDEC2 propose read, deny.");
      throw new WOAAccessDeniedException("WOA restriction blocked operation.");
    }

    log.trace("Received \uD83D\uDEC2 propose read, grant." );
    return true;
  }

  @Override
  public boolean proposeWrite(CoinsModel model, String subject, String predicate, String object) {

    if(!hasClearance(subject, WRITE_ACCESS)) {
      log.trace("Received \uD83D\uDEC2 propose write, deny.");
      throw new WOAAccessDeniedException("WOA restriction blocked operation.");
    }

    log.trace("Received \uD83D\uDEC2 propose write, grant." );
    return true;
  }


  /**
   *
   * @param parts
   * @param uri
   * @param currentDepth  starts with 1 and when bigger than totalDepth stop
   * @param totalDepth
   * @return
   */
  private List getParts(ArrayList parts, Node uri, int currentDepth, int totalDepth, String level) {

    if(currentDepth > totalDepth) {
      return parts;
    }

    HashSet containsRelations = new HashSet<>();
    ExtendedIterator iterator;

    // Assembly --hasContainsRelation--> ContainsRelation
    iterator = instanceModel.getGraph().find(uri, new PropertyImpl("http://www.coinsweb.nl/cbim-2.0.rdf#hasContainsRelation").asNode(), Node.ANY);
    while (iterator.hasNext()) {

      Triple triple = iterator.next();
      Node containsRelation = triple.getObject();
      if (containsRelation.isURI()) {

        // Add it
        containsRelations.add(containsRelation);
      }
    }

    // ContainsRelation --hasAssembly--> Assembly
    iterator = instanceModel.getGraph().find(Node.ANY, new PropertyImpl("http://www.coinsweb.nl/cbim-2.0.rdf#hasAssembly").asNode(), uri);
    while (iterator.hasNext()) {

      Triple triple = iterator.next();
      Node containsRelation = triple.getSubject();
      if (containsRelation.isURI()) {

        // Add it
        containsRelations.add(containsRelation);
      }
    }

    Iterator relIterator = containsRelations.iterator();
    while(relIterator.hasNext()) {
      Node containsRelation = relIterator.next();



      // ContainsRelation --hasPart--> Part
      iterator = instanceModel.getGraph().find(containsRelation, new PropertyImpl("http://www.coinsweb.nl/cbim-2.0.rdf#hasPart").asNode(), Node.ANY);
      while (iterator.hasNext()) {

        Triple triple = iterator.next();
        Node part = triple.getObject();
        if (part.isURI()) {

          // Add it
          parts.add(new Clearance(part.getURI(), level, currentDepth));

          // Add all sub parts
          getParts(parts, part, currentDepth+1, totalDepth, level);
        }
      }

      // Part --partOf--> ContainsRelation
      iterator = instanceModel.getGraph().find(Node.ANY, new PropertyImpl("http://www.coinsweb.nl/cbim-2.0.rdf#partOf").asNode(), containsRelation);
      while (iterator.hasNext()) {

        Triple triple = iterator.next();
        Node part = triple.getSubject();
        if (part.isURI()) {

          // Add it
          parts.add(new Clearance(part.getURI(), level, currentDepth));

          // Add all sub parts
          getParts(parts, part, currentDepth - 1, totalDepth, level);
        }
      }
    }

    return parts;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy