/* * 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.jena.propertytable.impl; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.jena.atlas.iterator.Iter; import org.apache.jena.atlas.iterator.IteratorConcat; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.propertytable.Column; import org.apache.jena.propertytable.PropertyTable; import org.apache.jena.propertytable.Row; import org.apache.jena.util.iterator.ExtendedIterator ; import org.apache.jena.util.iterator.WrappedIterator ; /** * A PropertyTable Implementation using a two dimension array. * It contains SPO and PSO indexes. * */ public class PropertyTableArrayImpl implements PropertyTable { private final List<Node> rowList; private final List<Node> columnList; private final Map<Node, Integer> rowKeyToIndex; private final Map<Node, Integer> columnKeyToIndex; private final Node[][] array; private final int rowNum; private final int columnNum; public PropertyTableArrayImpl(int rowNum, int columnNum){ rowList = new ArrayList<Node>(rowNum); columnList = new ArrayList<Node>(columnNum); rowKeyToIndex = new HashMap<Node, Integer>(); columnKeyToIndex = new HashMap<Node, Integer>(); this.rowNum = rowNum; this.columnNum = columnNum; array = new Node [rowNum][columnNum]; } @Override public ExtendedIterator<Triple> getTripleIterator(Column column, Node value) { if (column == null || column.getColumnKey() == null) throw new NullPointerException("column is null"); if (value == null){ throw new NullPointerException("value is null"); } ArrayList<Triple> triples = new ArrayList<Triple>(); Node p = column.getColumnKey(); Integer columnIndex = this.columnKeyToIndex.get(p); if (columnIndex != null){ for(int rowIndex=0; rowIndex< rowList.size();rowIndex++){ if ( value.equals( this.get(rowIndex, columnIndex))){ triples.add(Triple.create(rowList.get(rowIndex), p, value)); } } } return WrappedIterator.create(triples.iterator()); } @Override public ExtendedIterator<Triple> getTripleIterator(Column column) { if (column == null || column.getColumnKey() == null) throw new NullPointerException("column is null"); ArrayList<Triple> triples = new ArrayList<Triple>(); Node p = column.getColumnKey(); Integer columnIndex = this.columnKeyToIndex.get(p); if (columnIndex != null){ for(int rowIndex=0; rowIndex< rowList.size();rowIndex++){ if(this.get(rowIndex, columnIndex)!=null){ triples.add(Triple.create(rowList.get(rowIndex), p, this.get(rowIndex, columnIndex))); } } } return WrappedIterator.create(triples.iterator()); } @Override public ExtendedIterator<Triple> getTripleIterator(Node value) { if (value == null) throw new NullPointerException("value is null"); IteratorConcat<Triple> iter = new IteratorConcat<Triple>(); for (Column column : this.getColumns()) { ExtendedIterator<Triple> eIter = getTripleIterator(column,value); iter.add(eIter); } return WrappedIterator.create(Iter.distinct(iter)); } @Override public ExtendedIterator<Triple> getTripleIterator(Row row) { if (row == null || row.getRowKey() == null) throw new NullPointerException("row is null"); ArrayList<Triple> triples = new ArrayList<Triple>(); Integer rowIndex = this.rowKeyToIndex.get(row.getRowKey()); if (rowIndex != null){ for(int columnIndex=0; columnIndex < columnList.size(); columnIndex++){ triples.add(Triple.create( row.getRowKey(), columnList.get(columnIndex), this.get(rowIndex, columnIndex))); } } return WrappedIterator.create(triples.iterator()); } @Override public ExtendedIterator<Triple> getTripleIterator() { IteratorConcat<Triple> iter = new IteratorConcat<Triple>(); for (Column column : getColumns()) { iter.add(getTripleIterator(column)); } return WrappedIterator.create(Iter.distinct(iter)); } @Override public Collection<Column> getColumns() { Collection<Column> columns = new ArrayList<Column>(); for(Node p: columnKeyToIndex.keySet() ){ columns.add(new ColumnImpl(this, p)); } return columns; } @Override public Column getColumn(Node p) { if (p == null) throw new NullPointerException("column name is null"); Integer columnIndex = columnKeyToIndex.get(p); return (columnIndex == null) ? null : new ColumnImpl(this, p); } @Override public Column createColumn(Node p) { if (p == null) throw new NullPointerException("column name is null"); if (columnKeyToIndex.containsKey(p)) throw new IllegalArgumentException("column already exists: '" + p.toString()); if (columnList.size()>= columnNum) throw new IllegalArgumentException("cannot create new column for max column count: " + columnNum); columnList.add(p); columnKeyToIndex.put(p, columnList.indexOf(p)); return getColumn(p); } @Override public Row getRow(Node s) { if (s == null) throw new NullPointerException("subject node is null"); Integer rowIndex = rowKeyToIndex.get(s); return (rowIndex == null) ? null : new InternalRow(rowIndex); } @Override public Row createRow(Node s) { Row row = this.getRow(s); if (row != null) return row; if (rowList.size()>= rowNum) throw new IllegalArgumentException("cannot create new row for max row count: " + rowNum); rowList.add(s); int rowIndex = rowList.indexOf(s); rowKeyToIndex.put(s, rowIndex); return new InternalRow(rowIndex); } private void set(int rowIndex, int columnIndex, Node value) { if (rowIndex >= rowList.size()) throw new IllegalArgumentException("row index out of bound: " + rowList.size()); if (columnIndex >= columnList.size()) throw new IllegalArgumentException("column index out of bound: " + columnList.size()); array[rowIndex][columnIndex] = value; } public Node get(int rowIndex, int columnIndex) { if (rowIndex >= rowList.size()) throw new IllegalArgumentException("row index out of bound: " + rowList.size()); if (columnIndex >= columnList.size()) throw new IllegalArgumentException("column index out of bound: " + columnList.size()); return array[rowIndex][columnIndex]; } @Override public List<Row> getAllRows() { ArrayList<Row> rows = new ArrayList<Row>(); for (int rowIndex=0;rowIndex<rowList.size();rowIndex++){ rows.add( new InternalRow(rowIndex)); } return rows; } @Override public List<Node> getColumnValues(Column column) { if (column == null || column.getColumnKey() == null) throw new NullPointerException("column is null"); Node p = column.getColumnKey(); Integer columnIndex = this.columnKeyToIndex.get(p); List<Node> list = new ArrayList<Node>(); if (columnIndex != null){ for(int rowIndex=0; rowIndex< rowList.size();rowIndex++){ if(this.get(rowIndex, columnIndex)!=null){ list.add(this.get(rowIndex, columnIndex)); } } } return list; } @Override public Collection<Row> getMatchingRows(Column column, Node value) { if (column == null || column.getColumnKey() == null) throw new NullPointerException("column is null"); if (value == null){ throw new NullPointerException("value is null"); } final ArrayList<Row> matchingRows = new ArrayList<Row>(); Node p = column.getColumnKey(); Integer columnIndex = this.columnKeyToIndex.get(p); if (columnIndex != null){ for(int rowIndex=0; rowIndex< rowList.size();rowIndex++){ if ( value.equals( this.get(rowIndex, columnIndex))){ matchingRows.add( this.getRow( rowList.get(rowIndex) )); } } } return matchingRows; } private final class InternalRow implements Row { final int rowIndex; InternalRow(int rowIndex) { this.rowIndex = rowIndex; } @Override public PropertyTable getTable() { return PropertyTableArrayImpl.this; } @Override public void setValue(Column column, Node value) { if (column == null || column.getColumnKey() == null) throw new NullPointerException("column is null"); Integer columnIndex = columnKeyToIndex.get(column.getColumnKey()); if (columnIndex == null) throw new IllegalArgumentException("column index does not exist: " + column.getColumnKey()); set(rowIndex, columnIndex, value); } @Override public Node getValue(Column column) { if (column == null) throw new NullPointerException("column is null"); return this.getValue(column.getColumnKey()); } @Override public Node getValue(Node columnKey) { if (columnKey == null) throw new NullPointerException("column key is null"); Integer columnIndex = columnKeyToIndex.get(columnKey); if (columnIndex == null) throw new IllegalArgumentException("column index does not exist: " + columnKey); return get(rowIndex, columnIndex); } @Override public Node getRowKey() { return rowList.get(rowIndex); } @Override public ExtendedIterator<Triple> getTripleIterator() { ArrayList<Triple> triples = new ArrayList<Triple>(); for (int columnIndex=0;columnIndex<columnList.size();columnIndex++) { triples.add(Triple.create(getRowKey(), columnList.get(columnIndex), get(rowIndex, columnIndex))); } return WrappedIterator.create(triples.iterator()); } @Override public Collection<Column> getColumns() { return PropertyTableArrayImpl.this.getColumns(); } } }