/**
* File: $HeadURL: https://hdt-java.googlecode.com/svn/trunk/hdt-java/src/org/rdfhdt/hdt/triples/impl/TriplesList.java $
* Revision: $Rev: 191 $
* Last modified: $Date: 2013-03-03 11:41:43 +0000 (dom, 03 mar 2013) $
* Last modified by: $Author: mario.arias $
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Contacting the authors:
* Mario Arias: mario.arias@deri.org
* Javier D. Fernandez: jfergar@infor.uva.es
* Miguel A. Martinez-Prieto: migumar2@infor.uva.es
* Alejandro Andres: fuzzy.alej@gmail.com
*/
package org.rdfhdt.hdt.triples.impl;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import org.rdfhdt.hdt.enums.ResultEstimationType;
import org.rdfhdt.hdt.enums.TripleComponentOrder;
import org.rdfhdt.hdt.exceptions.NotImplementedException;
import org.rdfhdt.hdt.hdt.HDTVocabulary;
import org.rdfhdt.hdt.header.Header;
import org.rdfhdt.hdt.iterator.SequentialSearchIteratorTripleID;
import org.rdfhdt.hdt.listener.ProgressListener;
import org.rdfhdt.hdt.options.ControlInfo;
import org.rdfhdt.hdt.options.HDTOptions;
import org.rdfhdt.hdt.triples.IteratorTripleID;
import org.rdfhdt.hdt.triples.TempTriples;
import org.rdfhdt.hdt.triples.TripleID;
import org.rdfhdt.hdt.triples.TripleIDComparator;
import org.rdfhdt.hdt.triples.Triples;
import org.rdfhdt.hdt.util.RDFInfo;
import org.rdfhdt.hdt.util.io.CountInputStream;
import org.rdfhdt.hdt.util.io.IOUtil;
import org.rdfhdt.hdt.util.listener.ListenerUtil;
/**
* Implementation of TempTriples using a List of TripleID.
*
*/
public class TriplesList implements TempTriples {
/** The array to hold the triples */
private ArrayList<TripleID> arrayOfTriples;
/** The order of the triples */
private TripleComponentOrder order;
private long numValidTriples;
private boolean sorted;
/**
* Constructor, given an order to sort by
*
* @param order
* The order to sort by
*/
public TriplesList(HDTOptions specification) {
//precise allocation of the array (minimal memory wasting)
long numTriples = RDFInfo.getTriples(specification);
numTriples = (numTriples>0)?numTriples:100;
this.arrayOfTriples = new ArrayList<TripleID>((int)numTriples);
//choosing starting(or default) component order
String orderStr = specification.get("triplesOrder");
if(orderStr==null) {
orderStr = "SPO";
}
this.order = TripleComponentOrder.valueOf(orderStr);
this.numValidTriples = 0;
}
/**
* A method for setting the size of the arrayList (so no reallocation occurs).
* If not empty does nothing and returns false.
*/
public boolean reallocateIfEmpty(int numTriples){
if (arrayOfTriples.isEmpty()) {
arrayOfTriples = new ArrayList<TripleID>(numTriples);
return true;
} else {
return false;
}
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#search(hdt.triples.TripleID)
*/
@Override
public IteratorTripleID search(TripleID pattern) {
String patternStr = pattern.getPatternString();
if(patternStr.equals("???")) {
return new TriplesListIterator(this);
} else {
return new SequentialSearchIteratorTripleID(pattern, new TriplesListIterator(this));
}
}
/* (non-Javadoc)
* @see hdt.triples.Triples#searchAll()
*/
@Override
public IteratorTripleID searchAll() {
TripleID all = new TripleID(0,0,0);
return this.search(all);
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#getNumberOfElements()
*/
@Override
public long getNumberOfElements() {
return numValidTriples;
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#size()
*/
@Override
public long size() {
return this.getNumberOfElements()*TripleID.size();
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#save(java.io.OutputStream)
*/
@Override
public void save(OutputStream output, ControlInfo controlInformation, ProgressListener listener) throws IOException {
controlInformation.clear();
controlInformation.setInt("numTriples", numValidTriples);
controlInformation.setFormat(HDTVocabulary.TRIPLES_TYPE_TRIPLESLIST);
controlInformation.setInt("order", order.ordinal());
controlInformation.save(output);
DataOutputStream dout = new DataOutputStream(output);
int count = 0;
for (TripleID triple : arrayOfTriples) {
if(triple.isValid()) {
dout.writeInt(triple.getSubject());
dout.writeInt(triple.getPredicate());
dout.writeInt(triple.getObject());
ListenerUtil.notifyCond(listener, "Saving TriplesList", count, arrayOfTriples.size());
}
count++;
}
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#load(java.io.InputStream)
*/
@Override
public void load(InputStream input, ControlInfo controlInformation, ProgressListener listener) throws IOException {
order = TripleComponentOrder.values()[(int)controlInformation.getInt("order")];
long totalTriples = controlInformation.getInt("numTriples");
int numRead=0;
while(numRead<totalTriples) {
arrayOfTriples.add(new TripleID(IOUtil.readInt(input), IOUtil.readInt(input), IOUtil.readInt(input)));
numRead++;
numValidTriples++;
ListenerUtil.notifyCond(listener, "Loading TriplesList", numRead, totalTriples);
}
sorted = false;
}
/*
* (non-Javadoc)
*
* @see hdt.triples.Triples#load(hdt.triples.TempTriples)
*/
@Override
public void load(TempTriples input, ProgressListener listener) {
IteratorTripleID iterator = input.searchAll();
while (iterator.hasNext()) {
arrayOfTriples.add(iterator.next());
numValidTriples++;
}
sorted = false;
}
/**
* @param order
* the order to set
*/
public void setOrder(TripleComponentOrder order) {
if (this.order.equals(order))
return;
this.order = order;
sorted = false;
}
@Override
public TripleComponentOrder getOrder() {
return order;
}
/*
* (non-Javadoc)
*
* @see hdt.triples.TempTriples#insert(hdt.triples.TripleID[])
*/
@Override
public boolean insert(TripleID... triples) {
for (TripleID triple : triples) {
arrayOfTriples.add(new TripleID(triple));
numValidTriples++;
}
sorted = false;
return true;
}
/* (non-Javadoc)
* @see hdt.triples.TempTriples#insert(int, int, int)
*/
@Override
public boolean insert(int subject, int predicate, int object) {
arrayOfTriples.add(new TripleID(subject,predicate,object));
numValidTriples++;
sorted = false;
return true;
}
@Override
public boolean update(TripleID triple, int subj, int pred, int obj) {
if (triple==null)
return false;
triple.setAll(subj, pred, obj);
sorted = false;
return true;
}
/*
* (non-Javadoc)
*
* @see hdt.triples.TempTriples#delete(hdt.triples.TripleID[])
*/
@Override
public boolean remove(TripleID... patterns) {
boolean removed = false;
for(TripleID triple : arrayOfTriples){
for(TripleID pattern : patterns) {
if(triple.match(pattern)) {
triple.clear();
removed = true;
numValidTriples--;
break;
}
}
}
return removed;
}
/*
* (non-Javadoc)
*
* @see hdt.triples.TempTriples#sort(datatypes.TripleComponentOrder)
*/
@Override
public void sort(ProgressListener listener) {
if(!sorted) {
Collections.sort(arrayOfTriples, TripleIDComparator.getComparator(order));
}
sorted = true;
}
/**
* If called while triples not sorted nothing will happen!
*/
@Override
public void removeDuplicates(ProgressListener listener) {
if(arrayOfTriples.size()<=1 || !sorted) {
return;
}
if(order==TripleComponentOrder.Unknown || !sorted) {
throw new IllegalArgumentException("Cannot remove duplicates unless sorted");
}
int j = 0;
for(int i=1; i<arrayOfTriples.size(); i++) {
if(arrayOfTriples.get(i).compareTo(arrayOfTriples.get(j))!=0) {
j++;
arrayOfTriples.set(j, arrayOfTriples.get(i));
}
ListenerUtil.notifyCond(listener, "Removing duplicate triples", i, arrayOfTriples.size());
}
while(arrayOfTriples.size()>j+1) {
arrayOfTriples.remove(arrayOfTriples.size()-1);
}
arrayOfTriples.trimToSize();
numValidTriples = j+1;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "TriplesList [" + arrayOfTriples + "\n order=" + order + "]";
}
/* (non-Javadoc)
* @see hdt.triples.Triples#populateHeader(hdt.header.Header, java.lang.String)
*/
@Override
public void populateHeader(Header header, String rootNode) {
header.insert(rootNode, HDTVocabulary.TRIPLES_TYPE, HDTVocabulary.TRIPLES_TYPE_TRIPLESLIST);
header.insert(rootNode, HDTVocabulary.TRIPLES_NUM_TRIPLES, getNumberOfElements() );
header.insert(rootNode, HDTVocabulary.TRIPLES_ORDER, order.ordinal() );
}
public String getType() {
return HDTVocabulary.TRIPLES_TYPE_TRIPLESLIST;
}
@Override
public void generateIndex(ProgressListener listener) {
// TODO Auto-generated method stub
}
@Override
public void loadIndex(InputStream input, ControlInfo ci, ProgressListener listener) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void saveIndex(OutputStream output, ControlInfo ci, ProgressListener listener) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void clear() {
this.arrayOfTriples.clear();
this.numValidTriples=0;
this.order = TripleComponentOrder.Unknown;
sorted = false;
}
@Override
public void load(Triples triples, ProgressListener listener) {
this.clear();
IteratorTripleID it = triples.searchAll();
while(it.hasNext()) {
TripleID triple = it.next();
this.insert(triple.getSubject(), triple.getPredicate(), triple.getObject());
}
sorted = false;
}
@Override
public void close() throws IOException {
}
/**
* Iterator implementation to iterate over a TriplesList object
*
* @author mario.arias
*
*/
public class TriplesListIterator implements IteratorTripleID {
private TriplesList triplesList;
private int pos;
public TriplesListIterator(TriplesList triplesList) {
this.triplesList = triplesList;
this.pos = 0;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#hasNext()
*/
@Override
public boolean hasNext() {
return pos<triplesList.getNumberOfElements();
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#next()
*/
@Override
public TripleID next() {
return triplesList.arrayOfTriples.get((int)pos++);
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#hasPrevious()
*/
@Override
public boolean hasPrevious() {
return pos>0;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#previous()
*/
@Override
public TripleID previous() {
return triplesList.arrayOfTriples.get((int)--pos);
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#goToStart()
*/
@Override
public void goToStart() {
pos = 0;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#estimatedNumResults()
*/
@Override
public long estimatedNumResults() {
return triplesList.getNumberOfElements();
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#numResultEstimation()
*/
@Override
public ResultEstimationType numResultEstimation() {
return ResultEstimationType.EXACT;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#canGoTo()
*/
@Override
public boolean canGoTo() {
return true;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#goTo(int)
*/
@Override
public void goTo(long pos) {
this.pos = (int)pos;
}
/* (non-Javadoc)
* @see hdt.iterator.IteratorTripleID#getOrder()
*/
@Override
public TripleComponentOrder getOrder() {
return triplesList.getOrder();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@Override
public void mapFromFile(CountInputStream in, File f, ProgressListener listener) throws IOException {
throw new NotImplementedException();
}
@Override
public void mapIndex(CountInputStream input, File f, ControlInfo ci, ProgressListener listener) throws IOException {
}
}