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

org.apache.clerezza.utils.RdfList Maven / Gradle / Ivy

/*
 * 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.utils;

import org.apache.clerezza.*;
import org.apache.clerezza.implementation.TripleImpl;
import org.apache.clerezza.ontologies.OWL;
import org.apache.clerezza.ontologies.RDF;
import org.apache.clerezza.representation.Serializer;
import org.apache.clerezza.representation.SupportedFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;

/**
 * An implementation of an java.util.List backed by an RDF
 * collection (rdf:List). The list allows modification that are reflected
 * to the underlying Graph. It reads the data from the
 * Graph when it is first needed, so changes to the
 * Graph 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 Graphs) is
 * not problematic.
 *
 * @author rbn, mir
 */
public class RdfList extends AbstractList {

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

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

    /**
     * Get a list for the specified resource.
     * 

* If the list is modified using the created instance * listRDFTerm will always be the first list. * * @param listRDFTerm * @param tc */ public RdfList(BlankNodeOrIRI listRDFTerm, Graph tc) { firstList = listRDFTerm; this.tc = tc; } /** * Get a list for the specified resource node. * * @param listNode */ public RdfList(GraphNode listNode) { this((BlankNodeOrIRI) listNode.getNode(), listNode.getGraph()); } /** * Creates an empty RdfList by writing a triple * "{@code listRDFTerm} owl:sameAs rdf.nil ." to {@code tc}. * * @param listRDFTerm * @param tc * @return an empty rdf:List. * @throws IllegalArgumentException if the provided {@code listRDFTerm} is a non-empty rdf:List. */ public static RdfList createEmptyList(BlankNodeOrIRI listRDFTerm, Graph tc) throws IllegalArgumentException { if (!tc.filter(listRDFTerm, RDF.first, null).hasNext()) { RdfList list = new RdfList(listRDFTerm, tc); list.tc.add(new TripleImpl(listRDFTerm, OWL.sameAs, RDF_NIL)); return list; } else { throw new IllegalArgumentException(listRDFTerm + "is a non-empty rdf:List."); } } private void expandTill(int pos) { if (totallyExpanded) { return; } BlankNodeOrIRI 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 RDFTerm 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, RDFTerm 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, RDFTerm element) { expandTill(index + 1); BlankNodeOrIRI newList = new BlankNode() { }; 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 RDFTerm 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 BlankNodeOrIRI getRest(BlankNodeOrIRI list) { return (BlankNodeOrIRI) tc.filter(list, RDF.rest, null).next().getObject(); } private RDFTerm getFirstEntry(final BlankNodeOrIRI listRDFTerm) { try { return tc.filter(listRDFTerm, RDF.first, null).next().getObject(); } catch (final NullPointerException e) { RuntimeException runtimeEx = AccessController.doPrivileged(new PrivilegedAction() { @Override public RuntimeException run() { try { final FileOutputStream fileOutputStream = new FileOutputStream("/tmp/broken-list.nt"); final GraphNode graphNode = new GraphNode(listRDFTerm, tc); Serializer.getInstance().serialize(fileOutputStream, graphNode.getNodeContext(), SupportedFormat.N_TRIPLE); fileOutputStream.flush(); logger.warn("GraphNode: " + graphNode); final Iterator properties = graphNode.getProperties(); while (properties.hasNext()) { logger.warn("available: " + properties.next()); } return new RuntimeException("broken list " + listRDFTerm, e); } catch (Exception ex) { return new RuntimeException(ex); } } }); throw runtimeEx; } } public BlankNodeOrIRI getListRDFTerm() { 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 GraphNode is * an element of. Sublists of other lists are not returned. * * @param element * @return */ public static Set findContainingLists(GraphNode element) { Set listNodes = findContainingListNodes(element); if (listNodes.isEmpty()) { return null; } Set rdfLists = new HashSet(); for (Iterator it = listNodes.iterator(); it.hasNext(); ) { GraphNode listNode = it.next(); rdfLists.add(new RdfList(listNode)); } return rdfLists; } /** * Returns a set of GraphNodeS which are the first list nodes (meaning * they are not the beginning of a sublist) of the list containing the specified * GraphNode as an element. * * @param element * @return */ public static Set findContainingListNodes(GraphNode element) { Iterator partOfaListNodesIter = element.getSubjectNodes(RDF.first); if (!partOfaListNodesIter.hasNext()) { return null; } Set listNodes = new HashSet(); while (partOfaListNodesIter.hasNext()) { listNodes.addAll(findAllListNodes(partOfaListNodesIter.next())); } return listNodes; } private static Set findAllListNodes(GraphNode listPart) { Iterator invRestNodesIter; Set listNodes = new HashSet(); 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy