/* * ARX: Powerful Data Anonymization * Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors * * Licensed 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.deidentifier.arx; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import org.deidentifier.arx.DataHandleInternal.InterruptHandler; import org.deidentifier.arx.aggregates.StatisticsBuilder; /** * This implementation of a data handle projects a given data handle onto a given research subset. * @author Fabian Prasser * @author Florian Kohlmayer */ public class DataHandleSubset extends DataHandle { /** The original data handle. */ private final DataHandle source; /** The research subset. */ private final DataSubset subset; /** * Creates a new handle that represents the research subset. * * @param source * @param subset */ public DataHandleSubset(DataHandle source, DataSubset subset) { this.source = source; this.dataTypes = source.dataTypes; this.definition = source.definition; this.header = source.header; this.subset = subset; } @Override public String getAttributeName(int col) { checkRegistry(); return source.getAttributeName(col); } @Override public DataType<?> getDataType(String attribute) { checkRegistry(); return source.getDataType(attribute); } @Override public int getGeneralization(String attribute) { checkRegistry(); return source.getGeneralization(attribute); } @Override public int getNumColumns() { checkRegistry(); return source.getNumColumns(); } @Override public int getNumRows() { checkRegistry(); return this.subset.getArray().length; } @Override public StatisticsBuilder getStatistics() { return new StatisticsBuilder(new DataHandleInternal(this)); } /** * Returns the research subset. * * @return */ public int[] getSubset() { checkRegistry(); return this.subset.getArray(); } @Override public String getValue(int row, int col) { checkRegistry(); return source.getValue(this.subset.getArray()[row], col); } @Override public DataHandle getView(){ checkRegistry(); return this; } @Override public boolean isOptimized() { checkRegistry(); return source.isOptimized(); } @Override public boolean isOutlier(int row) { checkRegistry(); return super.isOutlier(this.subset.getArray()[row]); } @Override public Iterator<String[]> iterator() { checkRegistry(); return new Iterator<String[]>() { int index = -1; @Override public boolean hasNext() { return (index < subset.getArray().length); } @Override public String[] next() { if (index == -1) { index++; return header; } else { final String[] result = new String[header.length]; for (int i = 0; i < result.length; i++) { result[i] = getValue(index, i); } index++; return result; } } @Override public void remove() { throw new UnsupportedOperationException("Remove is unsupported!"); } }; } @Override public boolean replace(int column, String original, String replacement) { throw new UnsupportedOperationException("This operation is not supported by handles for data subsets"); } @Override protected void doRelease() { // Nothing to do } @Override protected ARXConfiguration getConfiguration() { return source.getConfiguration(); } @Override protected DataType<?>[][] getDataTypeArray() { return source.dataTypes; } @Override protected String[] getDistinctValues(int column, boolean ignoreSuppression, InterruptHandler handler) { // Check checkRegistry(); checkColumn(column); final Set<String> vals = new HashSet<String>(); for (int i = 0; i < getNumRows(); i++) { handler.checkInterrupt(); vals.add(internalGetValue(i, column, ignoreSuppression)); } handler.checkInterrupt(); return vals.toArray(new String[vals.size()]); } /** * Returns the underlying source data handle. * * @return */ protected DataHandle getSource(){ return source; } @Override protected int internalCompare(int row1, int row2, int[] columns, boolean ascending) { return source.internalCompare(this.subset.getArray()[row1], this.subset.getArray()[row2], columns, ascending); } @Override protected String internalGetValue(int row, int col, boolean ignoreSuppression) { return source.internalGetValue(this.subset.getArray()[row], col, ignoreSuppression); } /** * Rebuild array representation of subset. */ protected void internalRebuild() { int index = 0; for (int i = 0; i < subset.getSet().length(); i++) { if (this.subset.getSet().contains(i)) { this.subset.getArray()[index++] = i; } } } @Override protected boolean internalReplace(int column, String original, String replacement) { return source.internalReplace(column, original, replacement); } /** * Swaps the bits in the set representation. * * @param row1 * @param row2 */ protected void internalSwap(int row1, int row2) { this.subset.getSet().swap(row1, row2); } /** * Translates the row number. * * @param row * @return */ protected int internalTranslate(int row) { return this.subset.getArray()[row]; } @Override protected boolean isAnonymous() { return source.isAnonymous(); } }