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 }