package de.hub.emffrag.datastore; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import org.eclipse.emf.common.util.URI; public class DataMap<KT> implements IDataMap<KT> { protected final IBaseDataStore store; private final byte[] fullPrefix; private final byte[] fullPrefixNext; protected final KeyType<KT> keyType; private final URI dataStoreUri; public DataMap(IBaseDataStore store, URI dataStoreURI, byte[] prefix, KeyType<KT> keyType) { super(); this.store = store; this.fullPrefix = (new String(prefix) + "_").getBytes(); this.fullPrefixNext = (new String(prefix) + (char) ('_' + 1)).getBytes(); this.keyType = keyType; this.dataStoreUri = dataStoreURI; } @Override public byte[] getStoreKey(KT key) { byte[] serialize = keyType.serialize(key); return ByteBuffer.allocate(fullPrefix.length + serialize.length).put(fullPrefix).put(serialize).array(); } @Override public URI getURI(KT key) { return dataStoreUri.appendSegment(URIUtils.encode(getStoreKey(key))); } @Override public KT add() { KT last = last(); KT key = null; if (last == null) { key = keyType.nullKey(); } else { key = keyType.next(last); } if (add(key)) { return key; } else { // TODO error handling: retry for a couple of times and then fail? throw new RuntimeException("Could not add key " + new String(keyType.serialize(key))); } } @Override public KT first() { byte[] lastStoreKeyInIndex = store.ceiling(fullPrefix); if (lastStoreKeyInIndex == null) { return null; } if (prefixMatches(lastStoreKeyInIndex)) { return keyType.deserialize(lastStoreKeyInIndex, fullPrefix.length); } else { return null; } } private boolean prefixMatches(byte[] lastStoreKeyInIndex) { boolean prefixMatches = true; for (int i = 0; i < fullPrefix.length; i++) { prefixMatches &= fullPrefix[i] == lastStoreKeyInIndex[i]; } return prefixMatches; } @Override public KT last() { byte[] lastStoreKeyInIndex = store.floor(fullPrefixNext); if (lastStoreKeyInIndex == null) { return null; } if (prefixMatches(lastStoreKeyInIndex)) { return keyType.deserialize(lastStoreKeyInIndex, fullPrefix.length); } else { return null; } } @Override public KT exactOrNext(KT key) { byte[] ceiling = store.ceiling(getStoreKey(key)); return ceiling == null ? null : keyType.deserialize(ceiling, fullPrefix.length); } @Override public boolean exists(KT key) { return !store.check(getStoreKey(key)); } @Override public KT next(KT key) { byte[] ceiling = store.ceiling(getStoreKey(keyType.next(key))); return ceiling == null ? null : keyType.deserialize(ceiling, fullPrefix.length); } @Override public boolean add(KT key) { byte[] storeKey = getStoreKey(key); return store.checkAndCreate(storeKey); } @Override public void set(KT key, String value) { PrintWriter printWriter = new PrintWriter(openOutputStream(key)); printWriter.print(value); printWriter.close(); } @Override public String get(KT key) { InputStream openInputStream = openInputStream(key); return openInputStream == null ? null : slurp(openInputStream, 1024); } @Override public String remove(KT key) { byte[] storeKey = getStoreKey(key); InputStream openInputStream = store.openInputStream(storeKey); if (openInputStream == null) { return null; } else { String result = slurp(openInputStream, 1024); store.delete(storeKey); return result; } } @Override public OutputStream openOutputStream(KT key) { return store.openOutputStream(getStoreKey(key)); } @Override public InputStream openInputStream(KT key) { return store.openInputStream(getStoreKey(key)); } private static String slurp(final InputStream is, final int bufferSize) { final char[] buffer = new char[bufferSize]; final StringBuilder out = new StringBuilder(); try { final Reader in = new InputStreamReader(is, "UTF-8"); try { for (;;) { int rsz = in.read(buffer, 0, buffer.length); if (rsz < 0) break; out.append(buffer, 0, rsz); } } finally { in.close(); } } catch (UnsupportedEncodingException ex) { /* ... */ } catch (IOException ex) { /* ... */ } return out.toString(); } @Override public KT getKeyFromURI(URI crossReferenceURI) { byte[] key = URIUtils.decode(crossReferenceURI.segment(1)); return keyType.deserialize(key, fullPrefix.length); } @Override public void close() { } }