/**
* Copyright (c) 2015 The original author or authors
*
* 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.reveno.atp.core.serialization;
import org.reveno.atp.api.domain.RepositoryData;
import org.reveno.atp.api.exceptions.BufferOutOfBoundsException;
import org.reveno.atp.api.exceptions.SerializerException;
import org.reveno.atp.api.exceptions.SerializerException.Action;
import org.reveno.atp.core.api.TransactionCommitInfo;
import org.reveno.atp.core.api.TransactionCommitInfo.Builder;
import org.reveno.atp.core.api.channel.Buffer;
import org.reveno.atp.core.api.channel.RevenoBufferInputStream;
import org.reveno.atp.core.api.channel.RevenoBufferOutputStream;
import org.reveno.atp.core.api.serialization.RepositoryDataSerializer;
import org.reveno.atp.core.api.serialization.TransactionInfoSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.List;
public class DefaultJavaSerializer implements RepositoryDataSerializer,
TransactionInfoSerializer {
@Override
public int getSerializerType() {
return DEFAULT_TYPE;
}
@Override
public boolean isRegistered(Class<?> type) {
return true;
}
@Override
public void registerTransactionType(Class<?> txDataType) {
}
@Override
public void serialize(TransactionCommitInfo info, Buffer buffer) {
buffer.writeLong(info.transactionId());
buffer.writeLong(info.time());
try (RevenoBufferOutputStream ba = new RevenoBufferOutputStream(buffer);
ObjectOutputStream os = new ObjectOutputStream(ba)) {
os.writeObject(info.transactionCommits());
} catch (IOException e) {
throw new SerializerException(Action.SERIALIZATION, getClass(), e);
}
}
@SuppressWarnings("unchecked")
@Override
public TransactionCommitInfo deserialize(Builder builder, Buffer buffer) {
long transactionId = buffer.readLong();
long time = buffer.readLong();
if (transactionId == 0 && time == 0) {
throw new BufferOutOfBoundsException();
}
try (RevenoBufferInputStream is = new RevenoBufferInputStream(buffer);
ObjectInputStreamEx os = new ObjectInputStreamEx(is, classLoader)) {
return builder.create().transactionId(transactionId).time(time).transactionCommits((List<Object>)os.readObject());
} catch (IOException | ClassNotFoundException e) {
throw new SerializerException(Action.DESERIALIZATION, getClass(), e);
}
}
@Override
public void serialize(RepositoryData repository, Buffer buffer) {
try (RevenoBufferOutputStream ba = new RevenoBufferOutputStream(buffer);
ObjectOutputStream os = new ObjectOutputStream(ba)) {
os.writeObject(repository);
} catch (IOException e) {
throw new SerializerException(Action.SERIALIZATION, getClass(), e);
}
}
@Override
public RepositoryData deserialize(Buffer buffer) {
try (RevenoBufferInputStream is = new RevenoBufferInputStream(buffer);
ObjectInputStreamEx os = new ObjectInputStreamEx(is,
classLoader)) {
return (RepositoryData) os.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new SerializerException(Action.DESERIALIZATION, getClass(), e);
}
}
@Override
public void serializeCommands(List<Object> commands, Buffer buffer) {
try (RevenoBufferOutputStream ba = new RevenoBufferOutputStream(buffer);
ObjectOutputStream os = new ObjectOutputStream(ba)) {
os.writeObject(commands);
} catch (IOException e) {
throw new SerializerException(Action.SERIALIZATION, getClass(), e);
}
}
@SuppressWarnings("unchecked")
@Override
public List<Object> deserializeCommands(Buffer buffer) {
try (RevenoBufferInputStream is = new RevenoBufferInputStream(buffer);
ObjectInputStreamEx os = new ObjectInputStreamEx(is, classLoader)) {
return (List<Object>) os.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new SerializerException(Action.DESERIALIZATION, getClass(), e);
}
}
@Override
public void serializeObject(Buffer buffer, Object tc) {
try (ByteArrayOutputStream ba = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(ba)) {
os.writeObject(tc);
buffer.writeInt(ba.size());
buffer.writeBytes(ba.toByteArray());
} catch (IOException e) {
throw new SerializerException(Action.SERIALIZATION, getClass(), e);
}
}
@Override
public Object deserializeObject(Buffer buffer) {
try (ByteArrayInputStream is = new ByteArrayInputStream(
buffer.readBytes(buffer.readInt()));
ObjectInputStreamEx os = new ObjectInputStreamEx(is,
classLoader)) {
return os.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new SerializerException(Action.DESERIALIZATION, getClass(), e);
}
}
public DefaultJavaSerializer() {
this(Thread.currentThread().getContextClassLoader());
}
public DefaultJavaSerializer(ClassLoader classLoader) {
this.classLoader = classLoader;
}
private ClassLoader classLoader;
protected static final int DEFAULT_TYPE = 0x111;
/*
* We need OSGi compliancy here
*/
public static class ObjectInputStreamEx extends ObjectInputStream {
private ClassLoader classLoader;
public ObjectInputStreamEx(InputStream input, ClassLoader classLoader)
throws IOException {
super(input);
this.classLoader = classLoader;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
try {
return classLoader.loadClass(desc.getName());
} catch (Throwable t) {
return super.resolveClass(desc);
}
}
}
}