001 /* 002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org 003 * Copyright (C) 2011 NightLabs Consulting GmbH 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 package org.cumulus4j.store.model; 019 020 import java.util.Collections; 021 import java.util.HashSet; 022 import java.util.Set; 023 024 /** 025 * Helper for en- & decoding the decrypted (plain) contents of 026 * {@link IndexEntry#getIndexValue() IndexEntry.indexValue}. This byte-array holds 027 * references to {@link DataEntry#getDataEntryID() DataEntry.dataEntryID}s. 028 * 029 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de 030 */ 031 public class IndexValue 032 { 033 private Set<Long> dataEntryIDs = new HashSet<Long>(); // A HashSet is faster than a TreeSet and I don't see a need for the sorting. 034 035 /** 036 * Create an empty instance of <code>IndexValue</code>. This is equivalent to 037 * calling {@link #IndexValue(byte[])} with a <code>null</code> or an empty argument. 038 */ 039 public IndexValue() { 040 this(null); 041 } 042 043 /** 044 * Create an <code>IndexValue</code> instance from the decrypted (plain) byte-array 045 * which is stored in {@link IndexEntry#getIndexValue() IndexEntry.indexValue}. 046 * 047 * @param indexValueByteArray the plain (decrypted) byte-array of {@link IndexEntry#getIndexValue()} or <code>null</code> 048 * (<code>null</code> is equivalent to an empty byte-array). This byte-array is what is created by {@link #toByteArray()}. 049 */ 050 public IndexValue(byte[] indexValueByteArray) { 051 if (indexValueByteArray != null) { 052 if ((indexValueByteArray.length % 8) != 0) 053 throw new IllegalArgumentException("indexValueByteArray.length is not dividable by 8!"); 054 055 for (int i = 0; i < indexValueByteArray.length / 8; ++i) { 056 long dataEntryID = 057 (((long)indexValueByteArray[i * 8 + 0] & 0xff) << 56) + 058 (((long)indexValueByteArray[i * 8 + 1] & 0xff) << 48) + 059 (((long)indexValueByteArray[i * 8 + 2] & 0xff) << 40) + 060 (((long)indexValueByteArray[i * 8 + 3] & 0xff) << 32) + 061 (((long)indexValueByteArray[i * 8 + 4] & 0xff) << 24) + 062 (((long)indexValueByteArray[i * 8 + 5] & 0xff) << 16) + 063 (((long)indexValueByteArray[i * 8 + 6] & 0xff) << 8) + 064 (indexValueByteArray[i * 8 + 7] & 0xff) 065 ; 066 dataEntryIDs.add(dataEntryID); 067 } 068 } 069 } 070 071 /** 072 * Get a byte-array with all {@link #getDataEntryIDs() dataEntryIDs}. It can be passed to 073 * {@link #IndexValue(byte[])} later (e.g. after encrypting, persisting, loading & decrypting). 074 * @return a byte-array holding all dataEntryIDs managed by this instance. 075 */ 076 public byte[] toByteArray() 077 { 078 byte[] result = new byte[dataEntryIDs.size() * 8]; 079 int i = -1; 080 for (Long dataEntryID : dataEntryIDs) { 081 long v = dataEntryID; 082 result[++i] = (byte)(v >>> 56); 083 result[++i] = (byte)(v >>> 48); 084 result[++i] = (byte)(v >>> 40); 085 result[++i] = (byte)(v >>> 32); 086 result[++i] = (byte)(v >>> 24); 087 result[++i] = (byte)(v >>> 16); 088 result[++i] = (byte)(v >>> 8); 089 result[++i] = (byte)v; 090 } 091 return result; 092 } 093 094 /** 095 * Get {@link DataEntry#getDataEntryID() dataEntryID}s referencing those {@link DataEntry}s which this <code>IndexValue</code> 096 * (or more precisely the {@link IndexEntry} from which this <code>IndexValue</code> was created) points to. 097 * @return the object-IDs of the <code>DataEntry</code> instances that are referenced by this index entry. 098 */ 099 public Set<Long> getDataEntryIDs() { 100 return Collections.unmodifiableSet(dataEntryIDs); 101 } 102 103 public boolean isDataEntryIDsEmpty() 104 { 105 return dataEntryIDs.isEmpty(); 106 } 107 108 public boolean addDataEntryID(long dataEntryID) 109 { 110 return dataEntryIDs.add(dataEntryID); 111 } 112 113 public boolean removeDataEntryID(long dataEntryID) 114 { 115 return dataEntryIDs.remove(dataEntryID); 116 } 117 118 @Override 119 public int hashCode() { 120 return dataEntryIDs.hashCode(); 121 } 122 123 @Override 124 public boolean equals(Object obj) { 125 if (this == obj) return true; 126 if (obj == null) return false; 127 if (getClass() != obj.getClass()) return false; 128 IndexValue other = (IndexValue) obj; 129 return this.dataEntryIDs.equals(other.dataEntryIDs); 130 } 131 132 // public static void main(String[] args) { 133 // Random random = new Random(); 134 // IndexValue indexValue1 = new IndexValue(); 135 // for (int i = 0; i < 100; ++i) { 136 // long dataEntryID = random.nextLong(); 137 // indexValue1.addDataEntryID(dataEntryID); 138 // } 139 // 140 // for (Long dataEntryID : indexValue1.getDataEntryIDs()) { 141 // System.out.println(dataEntryID); 142 // } 143 // 144 // System.out.println(); 145 // System.out.println(); 146 // System.out.println(); 147 // 148 // byte[] byteArray = indexValue1.toByteArray(); 149 // 150 // IndexValue indexValue2 = new IndexValue(byteArray); 151 // for (Long dataEntryID : indexValue2.getDataEntryIDs()) { 152 // System.out.println(dataEntryID); 153 // } 154 // 155 // System.out.println(); 156 // System.out.println(); 157 // System.out.println(); 158 // 159 // System.out.println(indexValue1.equals(indexValue2)); 160 // } 161 162 }