package com.intrbiz.bergamot.accounting.io;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Supplier;
import com.intrbiz.Util;
import com.intrbiz.bergamot.accounting.model.BergamotAccountingEvent;
import com.intrbiz.bergamot.accounting.model.ExecuteCheckAccountingEvent;
import com.intrbiz.bergamot.accounting.model.LoginAccountingEvent;
import com.intrbiz.bergamot.accounting.model.ProcessResultAccountingEvent;
import com.intrbiz.bergamot.accounting.model.SendNotificationAccountingEvent;
import com.intrbiz.bergamot.accounting.model.SendNotificationToContactAccountingEvent;
import com.intrbiz.bergamot.accounting.model.SignAgentAccountingEvent;
public class BergamotAccountingTranscoder
{
private static final BergamotAccountingTranscoder DEFAULT = new BergamotAccountingTranscoder();
public static final BergamotAccountingTranscoder getDefault()
{
return DEFAULT;
}
private ConcurrentMap<UUID, Supplier<? extends BergamotAccountingEvent>> eventTypes = new ConcurrentHashMap<UUID, Supplier<? extends BergamotAccountingEvent>>();
public BergamotAccountingTranscoder()
{
super();
// register default types
this.registerType(ExecuteCheckAccountingEvent.TYPE_ID, ExecuteCheckAccountingEvent::new);
this.registerType(ProcessResultAccountingEvent.TYPE_ID, ProcessResultAccountingEvent::new);
this.registerType(SendNotificationAccountingEvent.TYPE_ID, SendNotificationAccountingEvent::new);
this.registerType(LoginAccountingEvent.TYPE_ID, LoginAccountingEvent::new);
this.registerType(SignAgentAccountingEvent.TYPE_ID, SignAgentAccountingEvent::new);
this.registerType(SendNotificationToContactAccountingEvent.TYPE_ID, SendNotificationToContactAccountingEvent::new);
}
public void registerType(UUID id, Supplier<? extends BergamotAccountingEvent> factory)
{
this.eventTypes.putIfAbsent(id, factory);
}
@SuppressWarnings("unchecked")
public <T extends BergamotAccountingEvent> T create(UUID id)
{
Supplier<? extends BergamotAccountingEvent> supplier = this.eventTypes.get(id);
return supplier == null ? null : (T) supplier.get();
}
public void encode(BergamotAccountingEvent event, ByteBuffer into)
{
Objects.requireNonNull(event);
Objects.requireNonNull(event.getTypeId());
into.putLong(event.getTypeId().getMostSignificantBits());
into.putLong(event.getTypeId().getLeastSignificantBits());
event.pack(into);
}
public <T extends BergamotAccountingEvent> T decode(ByteBuffer from)
{
UUID typeId = new UUID(from.getLong(), from.getLong());
T event = this.create(typeId);
if (event == null) throw new RuntimeException("Failed to decode type " + typeId);
event.unpack(from);
return event;
}
public String encodeToString(BergamotAccountingEvent event)
{
ByteBuffer buffer = ByteBuffer.allocate(8192);
this.encode(event, buffer);
buffer.flip();
ByteBuffer encoded = Base64.getUrlEncoder().withoutPadding().encode(buffer);
return new String(encoded.array(), encoded.arrayOffset(), encoded.remaining(), Util.UTF8);
}
public <T extends BergamotAccountingEvent> T decodeFromString(String event)
{
byte[] decoded = Base64.getUrlDecoder().decode(event);
return this.decode(ByteBuffer.wrap(decoded));
}
}