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

org.apache.clerezza.utils.UnionGraph 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.graph.AbstractGraph;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

/**
 * This class represents the union of multiple triple collections. A UnionGraph
 * appears like a merge of the different graphs (see.
 * http://www.w3.org/TR/rdf-mt/#graphdefs).
 *
 * @author hasan
 */
public class UnionGraph extends AbstractGraph {

    protected Graph[] baseTripleCollections;
    private Lock readLock;
    private Lock writeLock;

    /**
     * Constructs a UnionGraph over the specified baseTripleCollections. Write
     * and delete operations are forwarded to the first baseTripleCollections.
     *
     * @param baseTripleCollections the baseTripleCollections
     */
    public UnionGraph(Graph... baseTripleCollections) {
        this.baseTripleCollections = baseTripleCollections;
        readLock = getPartialReadLock(0);
        writeLock = createWriteLock();
    }

    @Override
    public int performSize() {
        int size = 0;
        for (Graph graph : baseTripleCollections) {
            size += graph.size();
        }
        return size;
    }

    @Override
    public Iterator performFilter(final BlankNodeOrIRI subject,
                                          final IRI predicate, final RDFTerm object) {
        if (baseTripleCollections.length == 0) {
            return new HashSet(0).iterator();
        }
        return new Iterator() {

            int currentBaseTC = 0;
            Iterator currentBaseIter = baseTripleCollections[0].filter(
                    subject, predicate, object);
            private Triple lastReturned;

            @Override
            public boolean hasNext() {
                if (currentBaseIter.hasNext()) {
                    return true;
                }
                if (currentBaseTC == baseTripleCollections.length - 1) {
                    return false;
                }
                currentBaseTC++;
                currentBaseIter = baseTripleCollections[currentBaseTC].filter(
                        subject, predicate, object);
                return hasNext();
            }

            @Override
            public Triple next() {
                lastReturned = hasNext() ? currentBaseIter.next() : null;
                return lastReturned;
            }

            @Override
            public void remove() {
                if (lastReturned == null) {
                    throw new IllegalStateException();
                }
                if (currentBaseTC == 0) {
                    currentBaseIter.remove();
                }
                lastReturned = null;
            }
        };
    }

    @Override
    public boolean add(Triple e) {
        if (baseTripleCollections.length == 0) {
            throw new RuntimeException("no base graph for adding triples");
        }
        return baseTripleCollections[0].add(e);
    }

    @Override
    public boolean remove(Object e) {
        if (baseTripleCollections.length == 0) {
            throw new RuntimeException("no base graph for removing triples");
        }
        return baseTripleCollections[0].remove(e);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj.getClass().equals(getClass()))) {
            return false;
        }
        UnionGraph other = (UnionGraph) obj;
        Set otherGraphs
                = new HashSet(Arrays.asList(other.baseTripleCollections));
        Set thisGraphs
                = new HashSet(Arrays.asList(baseTripleCollections));
        return thisGraphs.equals(otherGraphs)
                && baseTripleCollections[0].equals(other.baseTripleCollections[0]);
    }

    @Override
    public int hashCode() {
        int hash = 0;
        for (Graph graph : baseTripleCollections) {
            hash += graph.hashCode();
        }
        hash *= baseTripleCollections[0].hashCode();
        return hash;
    }

    @Override
    public ReadWriteLock getLock() {
        return readWriteLock;
    }

    private ReadWriteLock readWriteLock = new ReadWriteLock() {

        @Override
        public Lock readLock() {
            return readLock;
        }

        @Override
        public Lock writeLock() {
            return writeLock;
        }
    };

    private Lock getPartialReadLock(int startPos) {
        ArrayList resultList = new ArrayList();
        for (int i = startPos; i < baseTripleCollections.length; i++) {
            Graph graph = baseTripleCollections[i];

            final Lock lock = graph.getLock().readLock();
            resultList.add(lock);
        }
        return new UnionLock(resultList.toArray(new Lock[resultList.size()]));
    }

    private Lock createWriteLock() {
        Lock partialReadLock = getPartialReadLock(1);

        Lock baseWriteLock
                = (baseTripleCollections[0]).getLock().writeLock();
        return new UnionLock(baseWriteLock, partialReadLock);

    }

    private static class UnionLock implements Lock {

        Lock[] locks;

        public UnionLock(Lock... locks) {
            this.locks = locks;
        }

        @Override
        public void lock() {
            boolean isLocked = false;
            while (!isLocked) {
                try {
                    isLocked = tryLock(10000, TimeUnit.NANOSECONDS);
                } catch (InterruptedException ex) {

                }
            }
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            Set aquiredLocks = new HashSet();
            try {
                for (Lock lock : locks) {
                    lock.lockInterruptibly();
                    aquiredLocks.add(lock);
                }
            } catch (InterruptedException e) {
                for (Lock lock : aquiredLocks) {
                    lock.unlock();
                }
                throw e;
            }
        }

        @Override
        public boolean tryLock() {
            Set aquiredLocks = new HashSet();
            for (Lock lock : locks) {
                if (!lock.tryLock()) {
                    for (Lock aquiredLock : aquiredLocks) {
                        aquiredLock.unlock();
                    }
                    return false;
                }
                aquiredLocks.add(lock);
            }
            return true;
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            Set aquiredLocks = new HashSet();
            long timeInNanos = unit.convert(time, TimeUnit.NANOSECONDS);
            long startTime = System.nanoTime();
            try {
                for (Lock lock : locks) {
                    if (!lock.tryLock((timeInNanos + startTime) - System.nanoTime(),
                            TimeUnit.NANOSECONDS)) {
                        for (Lock aquiredLock : aquiredLocks) {
                            aquiredLock.unlock();
                        }
                        return false;
                    }
                    aquiredLocks.add(lock);
                }
            } catch (InterruptedException e) {
                for (Lock lock : aquiredLocks) {
                    lock.unlock();
                }
                throw e;
            }
            return true;
        }

        @Override
        public void unlock() {
            for (Lock lock : locks) {
                lock.unlock();
            }
        }

        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException("Conditions not supported.");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy