Package org.apache.clerezza.rdf.utils

Source Code of org.apache.clerezza.rdf.utils.RdfList

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.apache.clerezza.rdf.utils;

import java.io.FileOutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.clerezza.rdf.core.BNode;
import org.apache.clerezza.rdf.core.NonLiteral;
import org.apache.clerezza.rdf.core.Resource;
import org.apache.clerezza.rdf.core.TripleCollection;
import org.apache.clerezza.rdf.core.UriRef;
import org.apache.clerezza.rdf.core.impl.TripleImpl;
import org.apache.clerezza.rdf.core.serializedform.Serializer;
import org.apache.clerezza.rdf.core.serializedform.SupportedFormat;
import org.apache.clerezza.rdf.ontologies.OWL;
import org.apache.clerezza.rdf.ontologies.RDF;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* An implementation of an <code>java.util.List</code> backed by an RDF
* collection (rdf:List). The list allows modification that are reflected
* to the underlying <code>TripleCollection</code>. It reads the data from the
* <code>TripleCollection</code> when it is first needed, so changes to the
* TripleCollection affecting the rdf:List may or may not have an effect on the
* values returned by instances of this class. For that reason only one
* instance of this class should be used for accessing an rdf:List of sublists
* thereof when the lists are being modified, having multiple lists exclusively
* for read operations (such as for immutable <code>TripleCollection</code>s) is
* not problematic.
*
* @author rbn, mir
*/
public class RdfList extends AbstractList<Resource> {

  private static final Logger logger = LoggerFactory.getLogger(RdfList.class);

  private final static UriRef RDF_NIL =
      new UriRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil");
  /**
   * a list of the linked rdf:List elements in order
   */
  private List<NonLiteral> listList = new ArrayList<NonLiteral>();
  private List<Resource> valueList = new ArrayList<Resource>();
  private NonLiteral firstList;
  private TripleCollection tc;
  private boolean totallyExpanded = false;

  /**
   * Get a list for the specified resource.
   *
   * If the list is modified using the created instance
   * <code>listResource</code> will always be the first list.
   *
   * @param listResource
   * @param tc
   */
  public RdfList(NonLiteral listResource, TripleCollection tc) {
    firstList = listResource;
    this.tc = tc;

  }

  /**
   * Get a list for the specified resource node.
   *
   * @param listNode
   */
  public RdfList(GraphNode listNode) {
    this((NonLiteral)listNode.getNode(), listNode.getGraph());
  }

  /**
   * Creates an empty RdfList by writing a triple
   * "{@code listResource} owl:sameAs rdf.nil ." to {@code tc}.
   *
   * @param listResource
   * @param tc
   * @return  an empty rdf:List.
   * @throws IllegalArgumentException
   *    if the provided {@code  listResource} is a non-empty rdf:List.
   */
  public static RdfList createEmptyList(NonLiteral listResource, TripleCollection tc)
      throws IllegalArgumentException {

    if (!tc.filter(listResource, RDF.first, null).hasNext()) {
      RdfList list = new RdfList(listResource, tc);
      list.tc.add(new TripleImpl(listResource, OWL.sameAs, RDF_NIL));
      return list;
    } else {
      throw new IllegalArgumentException(listResource + "is a non-empty rdf:List.");
    }
  }

  private void expandTill(int pos) {
    if (totallyExpanded) {
      return;
    }
    NonLiteral currentList;
    if (listList.size() > 0) {
      currentList = listList.get(listList.size()-1);
    } else {
      currentList = firstList;
      if (!tc.filter(currentList, RDF.first, null).hasNext()) {
        return;
      }
      listList.add(currentList);
      valueList.add(getFirstEntry(currentList));
    }
    if (listList.size() >= pos) {
      return;
    }
    while (true) {       
      currentList = getRest(currentList);
      if (currentList.equals(RDF_NIL)) {
        totallyExpanded = true;
        break;
      }
      if (listList.size() == pos) {
        break;
      }
      valueList.add(getFirstEntry(currentList));
      listList.add(currentList);
    }
  }



  @Override
  public Resource get(int index) {
    expandTill(index + 1);
    return valueList.get(index);
  }

  @Override
  public int size() {
    expandTill(Integer.MAX_VALUE);   
    return valueList.size();
  }

  @Override
  public void add(int index, Resource element) {
    expandTill(index);
    if (index == 0) {
      //special casing to make sure the first list remains the same resource
      if (listList.size() == 0) {
        tc.remove(new TripleImpl(firstList, OWL.sameAs, RDF_NIL));
        tc.add(new TripleImpl(firstList, RDF.rest, RDF_NIL));
        tc.add(new TripleImpl(firstList, RDF.first, element));
        listList.add(firstList);
      } else {
        tc.remove(new TripleImpl(listList.get(0), RDF.first, valueList.get(0)));
        tc.add(new TripleImpl(listList.get(0), RDF.first, element));
        addInRdfList(1, valueList.get(0));
      }
    } else {
      addInRdfList(index, element);
    }
    valueList.add(index, element);
  }
 
  /**
   *
   * @param index is > 0
   * @param element
   */
  private void addInRdfList(int index, Resource element) {
    expandTill(index+1);
    NonLiteral newList = new BNode() {
    };
    tc.add(new TripleImpl(newList, RDF.first, element));
    if (index < listList.size()) {
      tc.add(new TripleImpl(newList, RDF.rest, listList.get(index)));
      tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, listList.get(index)));
    } else {
      tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, RDF_NIL));
      tc.add(new TripleImpl(newList, RDF.rest, RDF_NIL));

    }
    tc.add(new TripleImpl(listList.get(index - 1), RDF.rest, newList));
    listList.add(index, newList);
  }

  @Override
  public Resource remove(int index) {
    //keeping the first list resource
    tc.remove(new TripleImpl(listList.get(index), RDF.first, valueList.get(index)));
    if (index == (listList.size() - 1)) {
      tc.remove(new TripleImpl(listList.get(index), RDF.rest, RDF_NIL))
      if (index > 0) {
        tc.remove(new TripleImpl(listList.get(index - 1), RDF.rest, listList.get(index)));
        tc.add(new TripleImpl(listList.get(index - 1), RDF.rest, RDF_NIL));
      } else {
        tc.add(new TripleImpl(listList.get(index), OWL.sameAs, RDF_NIL));
      }
      listList.remove(index);
    } else {
      tc.add(new TripleImpl(listList.get(index), RDF.first, valueList.get(index+1)));
      tc.remove(new TripleImpl(listList.get(index), RDF.rest, listList.get(index + 1)));
      tc.remove(new TripleImpl(listList.get(index + 1), RDF.first, valueList.get(index + 1)));
      if (index == (listList.size() - 2)) {
        tc.remove(new TripleImpl(listList.get(index + 1), RDF.rest, RDF_NIL));
        tc.add(new TripleImpl(listList.get(index), RDF.rest, RDF_NIL));
      } else {
        tc.remove(new TripleImpl(listList.get(index + 1), RDF.rest, listList.get(index + 2)));
        tc.add(new TripleImpl(listList.get(index), RDF.rest, listList.get(index + 2)));
      }
      listList.remove(index+1);
    }
    return valueList.remove(index);
  }

  private NonLiteral getRest(NonLiteral list) {
    return (NonLiteral) tc.filter(list, RDF.rest, null).next().getObject();
  }

  private Resource getFirstEntry(final NonLiteral listResource) {
    try {
      return tc.filter(listResource, RDF.first, null).next().getObject();
    } catch (final NullPointerException e) {
      RuntimeException runtimeEx = AccessController.doPrivileged(new PrivilegedAction<RuntimeException>() {
        @Override
        public RuntimeException run(){
          try {
            final FileOutputStream fileOutputStream = new FileOutputStream("/tmp/broken-list.nt");
            final GraphNode graphNode = new GraphNode(listResource, tc);
            Serializer.getInstance().serialize(fileOutputStream, graphNode.getNodeContext(), SupportedFormat.N_TRIPLE);
            fileOutputStream.flush();
            logger.warn("GraphNode: " + graphNode);
            final Iterator<UriRef> properties = graphNode.getProperties();
            while (properties.hasNext()) {
              logger.warn("available: " + properties.next());
            }
            return new RuntimeException("broken list " + listResource, e);
          } catch (Exception ex) {
            return new RuntimeException(ex);
          }

        }
      });
      throw runtimeEx;
    }
  }

  public NonLiteral getListResource() {
    return firstList;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    final RdfList other = (RdfList) obj;

    if (!other.firstList.equals(this.firstList)) {
      return false;
    }

    if (!other.tc.equals(this.tc)) {
      return false;
    }

    return true;
  }

  @Override
  public int hashCode() {
    return 17 * this.firstList.hashCode() + this.tc.hashCode();
  }

  /**
   * Returns the rdf lists of which the specified <code>GraphNode</code> is
   * an element of. Sublists of other lists are not returned.
   *
   * @param element
   * @return
   */
  public static Set<RdfList> findContainingLists(GraphNode element) {
    Set<GraphNode> listNodes = findContainingListNodes(element);
    if (listNodes.isEmpty()) {
      return null;
    }

    Set<RdfList> rdfLists = new HashSet<RdfList>();
    for (Iterator<GraphNode> it = listNodes.iterator(); it.hasNext();) {
      GraphNode listNode = it.next();
      rdfLists.add(new RdfList(listNode));
    }
    return rdfLists;
  }

  /**
   * Returns a set of <code>GraphNode</code>S which are the first list nodes (meaning
   * they are not the beginning of a sublist) of the list containing the specified
   * <code>GraphNode</code> as an element.
   *
   * @param element
   * @return
   */
  public static Set<GraphNode> findContainingListNodes(GraphNode element) {
    Iterator<GraphNode> partOfaListNodesIter = element.getSubjectNodes(RDF.first);
    if (!partOfaListNodesIter.hasNext()) {
      return null;
    }
    Set<GraphNode> listNodes = new HashSet<GraphNode>();

    while (partOfaListNodesIter.hasNext()) {
      listNodes.addAll(findAllListNodes(partOfaListNodesIter.next()));
    }
    return listNodes;
  }
 
  private static Set<GraphNode> findAllListNodes(GraphNode listPart) {
    Iterator<GraphNode> invRestNodesIter;
    Set<GraphNode> listNodes = new HashSet<GraphNode>();
    do {
      invRestNodesIter = listPart.getSubjectNodes(RDF.rest);
      if (invRestNodesIter.hasNext()) {
        listPart = invRestNodesIter.next();
        while (invRestNodesIter.hasNext()) {
          GraphNode graphNode = invRestNodesIter.next();
          listNodes.addAll(findAllListNodes(graphNode));
        }
      } else {
        listNodes.add(listPart);
        break;
      }
    } while (true);
    return listNodes;
  }
}
TOP

Related Classes of org.apache.clerezza.rdf.utils.RdfList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.