/* * Copyright 2015-present Open Networking Laboratory * * 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.onosproject.persistence.impl; import com.google.common.collect.Iterators; import org.mapdb.DB; import org.mapdb.Hasher; import org.mapdb.Serializer; import java.util.Collection; import java.util.Iterator; import java.util.Set; import static com.google.common.base.Preconditions.checkNotNull; /** * A set implementation that gets and receives all data from a serialized internal set. */ //TODO add locking for reads and writes public class PersistentSet<E> implements Set<E> { private final org.onosproject.store.service.Serializer serializer; private final org.mapdb.DB database; private final Set<byte[]> items; private final String name; public PersistentSet(org.onosproject.store.service.Serializer serializer, DB database, String name) { this.serializer = checkNotNull(serializer); this.database = checkNotNull(database); this.name = checkNotNull(name); items = database .createHashSet(name) .serializer(Serializer.BYTE_ARRAY) .hasher(Hasher.BYTE_ARRAY) .makeOrGet(); } public void readInto(Set<E> items) { this.items.forEach(item -> items.add(serializer.decode(item))); } @Override public int size() { return items.size(); } @Override public boolean isEmpty() { return items.isEmpty(); } @Override public boolean contains(Object o) { checkNotNull(o, "The argument cannot be null"); return items.contains(serializer.encode(o)); } @Override public Iterator<E> iterator() { return Iterators.transform(items.iterator(), serializer::decode); } @Override public Object[] toArray() { Object[] retArray = new Object[items.size()]; int index = 0; for (byte[] item : items) { retArray[index] = serializer.decode(item); index++; } return retArray; } @Override public <T> T[] toArray(T[] a) { checkNotNull(a, "The passed in array cannot be null."); int index = 0; Iterator<byte[]> iterator = items.iterator(); T[] retArray; if (a.length >= items.size()) { retArray = a; } else { retArray = (T[]) new Object[items.size()]; } while (iterator.hasNext()) { retArray[index++] = serializer.decode(iterator.next()); } if (retArray.length > items.size()) { retArray[index] = null; } return retArray; } @Override public boolean add(E item) { checkNotNull(item, "Item to be added cannot be null."); return items.add(serializer.encode(item)); } @Override public boolean remove(Object o) { checkNotNull(o, "Item to be removed cannot be null."); return items.remove(serializer.encode(o)); } @Override public boolean containsAll(Collection<?> c) { checkNotNull(c, "Collection cannot be internal."); for (Object item : c) { if (!items.contains(serializer.encode(item))) { return false; } } return true; } @Override public boolean addAll(Collection<? extends E> c) { checkNotNull(c, "The collection to be added cannot be null."); boolean changed = false; for (Object item : c) { changed = items.add(serializer.encode(item)) || changed; } return changed; } @Override public boolean retainAll(Collection<?> c) { boolean changed = false; for (byte[] item : items) { E deserialized = serializer.decode(item); if (!c.contains(deserialized)) { changed = items.remove(item) || changed; } } return changed; } @Override public boolean removeAll(Collection<?> c) { boolean changed = false; for (Object item : c) { changed = items.remove(serializer.encode(item)) || changed; } return changed; } @Override public void clear() { items.clear(); } @Override public boolean equals(Object set) { //This is not threadsafe and on larger sets incurs a significant processing cost if (!(set instanceof Set)) { return false; } Set asSet = (Set) set; if (asSet.size() != this.size()) { return false; } for (Object item : this) { if (!asSet.contains(item)) { return false; } } return true; } @Override public int hashCode() { return super.hashCode(); } }