/******************************************************************************* * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek * * 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 de.mxro.thrd.jdbm2V22.helper; import java.io.IOError; import java.io.IOException; import java.util.AbstractSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import de.mxro.thrd.jdbm2V22.PrimaryMap; import de.mxro.thrd.jdbm2V22.PrimaryStoreMap; import de.mxro.thrd.jdbm2V22.RecordListener; import de.mxro.thrd.jdbm2V22.RecordManager; import de.mxro.thrd.jdbm2V22.Serializer; public class PrimaryStoreMapImpl<K extends Long, V> extends AbstractPrimaryMap<Long, V> implements PrimaryStoreMap<K, V>{ final protected PrimaryMap<Long,String> map; final protected Serializer<V> valueSerializer; final protected List<RecordListener<Long,V>> listeners = new CopyOnWriteArrayList<RecordListener<Long,V>>(); public PrimaryStoreMapImpl(PrimaryMap<Long, String> map,Serializer<V> valueSerializer2) { this.map = map; this.valueSerializer = valueSerializer2; map.addRecordListener(new RecordListener<Long,String>(){ public void recordInserted(Long key,String value) throws IOException { V v = (V) getRecordManager().fetch(key,valueSerializer); for(RecordListener<Long,V> l:listeners) l.recordInserted(key, v); } public void recordRemoved(Long key, String value) throws IOException { //store reference to value, it is needed to notify listeners V deletedValue = (V) getRecordManager().fetch(key,valueSerializer); for(RecordListener<Long,V> l:listeners) l.recordRemoved(key, deletedValue); //dispose old reference getRecordManager().delete(key); } public void recordUpdated(Long key, String oldValue, String newValue) throws IOException { throw new InternalError("should not be here"); }}); } public Long putValue(V v) { try { Long recid = getRecordManager().insert(v,valueSerializer); map.put(recid, ""); return recid; } catch (IOException e) { throw new IOError(e); } } public void addRecordListener(final RecordListener<Long, V> listener) { listeners.add((RecordListener<Long, V>) listener); } public RecordManager getRecordManager() { return map.getRecordManager(); } public void removeRecordListener(RecordListener<Long, V> listener) { listeners.remove(listener); } public void clear() { map.clear(); } public boolean containsKey(Object key) { return map.containsKey(key); } public Set<java.util.Map.Entry<Long, V>> entrySet() { return new AbstractSet<java.util.Map.Entry<Long,V>>(){ protected java.util.Map.Entry<Long,V> newEntry(Long k,V v){ return new SimpleEntry<Long,V>(k,v){ public V setValue(V arg0) { throw new UnsupportedOperationException(); }; }; } public boolean add(java.util.Map.Entry<Long, V> e) { throw new UnsupportedOperationException(); } @SuppressWarnings("unchecked") public boolean contains(Object o) { if(o instanceof Entry){ Entry<Long,V> e = (java.util.Map.Entry<Long, V>) o; if(e.getKey()!=null && get(e.getKey())!=null) return true; } return false; } public Iterator<java.util.Map.Entry<Long, V>> iterator() { return new Iterator<Entry<Long,V>>(){ final Iterator<Long> keyIter = keySet().iterator(); public boolean hasNext() { return keyIter.hasNext(); } public Entry<Long, V> next() { Long k = keyIter.next(); return newEntry(k, get(k)); } public void remove() { keyIter.remove(); } }; } @SuppressWarnings("unchecked") public boolean remove(Object o) { if(o instanceof Entry){ Entry<Long,V> e = (java.util.Map.Entry<Long, V>) o; //check for nulls if(e.getKey() == null || e.getValue() == null) return false; //find old value, must be same as item in entry V v = get(e.getKey()); if(v == null || !e.getValue().equals(v)) return false; return PrimaryStoreMapImpl.this.remove(e.getKey())!=null; } return false; } public int size() { return PrimaryStoreMapImpl.this.size(); } }; } public V get(Object key) { if(!map.containsKey(key)) return null; try { return getRecordManager().fetch((Long)key,valueSerializer); } catch (IOException e) { throw new IOError(e); } } public Set<Long> keySet() { return map.keySet(); } public V put(Long key, V value) { if(containsKey(key)){ try { V oldVal= getRecordManager().fetch(key,valueSerializer,true); getRecordManager().update(key, value,valueSerializer); //fire listeners, recid tree map did not change, so they would not be notified for(RecordListener<Long, V> listener: listeners) listener.recordUpdated(key, oldVal, value); return oldVal; } catch (IOException e) { throw new IOError(e); } }else{ throw new UnsupportedOperationException("Can not update, key not found, use putValue(val) instead."); } } public V remove(Object key) { if(!map.containsKey(key)) return null; try{ V v = getRecordManager().fetch((Long)key,valueSerializer); map.remove(key); return v; }catch (IOException e){ throw new IOError(e); } } public int size() { return map.size(); } }