package org.terracotta.offheapstore.disk.storage.portability;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.util.Map.Entry;
import org.terracotta.offheapstore.disk.persistent.PersistentPortability;
import org.terracotta.offheapstore.storage.portability.SerializablePortability;
import org.terracotta.offheapstore.util.FindbugsSuppressWarnings;
public class PersistentSerializablePortability extends SerializablePortability implements PersistentPortability<Serializable> {
private static final int MAGIC = 0xfeedbeef;
public PersistentSerializablePortability() {
super();
}
public PersistentSerializablePortability(ClassLoader classLoader) {
super(classLoader);
}
@Override
public void flush() throws IOException {
}
@Override
public void close() throws IOException {
}
@Override
@FindbugsSuppressWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
public void persist(ObjectOutput output) throws IOException {
output.writeInt(MAGIC);
synchronized (lookup) {
for (Entry<Object, Object> e : lookup.entrySet()) {
if (e.getKey() instanceof Integer) {
output.writeInt(((Integer) e.getKey()));
output.writeObject(e.getValue());
}
}
output.writeInt(-1);
}
}
@Override
@FindbugsSuppressWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
public void bootstrap(ObjectInput input) throws IOException {
if (input.readInt() != MAGIC) {
throw new IOException("Wrong magic number");
}
synchronized (lookup) {
int nextIndex = 0;
while (true) {
int representation = input.readInt();
if (representation == -1) {
if (nextStreamIndex == 0) {
nextStreamIndex = nextIndex;
} else if (nextStreamIndex != nextIndex) {
throw new IOException("Cannot bootstrap already used instance");
}
break;
} else {
ObjectStreamClass osc;
try {
osc = (ObjectStreamClass) input.readObject();
} catch (ClassNotFoundException e) {
throw new IOException(e);
}
SerializableDataKey key = new SerializableDataKey(disconnect(osc), true);
ObjectStreamClass oldOsc = (ObjectStreamClass) lookup.putIfAbsent(representation, osc);
Integer oldRep = (Integer) lookup.putIfAbsent(key, representation);
if (oldRep != null && !oldRep.equals(representation)) {
throw new IOException("Existing colliding class mapping detected");
} else if (oldOsc != null && !oldOsc.getName().equals(osc.getName())) {
throw new IOException("Existing colliding class mapping detected");
} else {
nextIndex = Math.max(nextIndex, representation + 1);
}
}
}
}
}
}