package sk.stuba.fiit.perconik.core.resources;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import javax.annotation.Nullable;
import sk.stuba.fiit.perconik.core.Listener;
import sk.stuba.fiit.perconik.core.Registrable;
import sk.stuba.fiit.perconik.core.Resource;
import static com.google.common.base.Preconditions.checkNotNull;
final class Synchronized {
private Synchronized() {}
private static class SynchronizedObject<T> implements Serializable {
private static final long serialVersionUID = 0L;
final T delegate;
final Object mutex;
SynchronizedObject(final T delegate, final Object mutex) {
this.delegate = checkNotNull(delegate);
this.mutex = (mutex == null) ? this : mutex;
}
@Override
public final String toString() {
synchronized (this.mutex) {
return this.delegate.toString();
}
}
private final void writeObject(final ObjectOutputStream stream) throws IOException {
synchronized (this.mutex) {
stream.defaultWriteObject();
}
}
}
private static class SynchronizedRegistrable<R extends Registrable> extends SynchronizedObject<R> implements Registrable {
private static final long serialVersionUID = 0L;
SynchronizedRegistrable(final R registrable, final Object mutex) {
super(registrable, mutex);
}
public final void preRegister() {
synchronized (this.mutex) {
this.delegate.preRegister();
}
}
public final void postRegister() {
synchronized (this.mutex) {
this.delegate.postRegister();
}
}
public final void preUnregister() {
synchronized (this.mutex) {
this.delegate.preUnregister();
}
}
public final void postUnregister() {
synchronized (this.mutex) {
this.delegate.preUnregister();
}
}
}
private static final class SynchronizedResource<L extends Listener> extends SynchronizedRegistrable<Resource<L>> implements Resource<L> {
private static final long serialVersionUID = 0L;
SynchronizedResource(final Resource<L> resource, final Object mutex) {
super(resource, mutex);
}
@Override
public boolean equals(@Nullable final Object object) {
if (object == this) {
return true;
}
synchronized (this.mutex) {
return this.delegate.equals(object);
}
}
@Override
public int hashCode() {
synchronized (this.mutex) {
return this.delegate.hashCode();
}
}
public void register(final L listener) {
synchronized (this.mutex) {
this.delegate.register(listener);
}
}
public void unregister(final L listener) {
synchronized (this.mutex) {
this.delegate.register(listener);
}
}
public <U extends Listener> Collection<U> registered(final Class<U> type) {
synchronized (this.mutex) {
return this.delegate.registered(type);
}
}
public boolean registered(final Listener listener) {
synchronized (this.mutex) {
return this.delegate.registered(listener);
}
}
public String getName() {
synchronized (this.mutex) {
return this.delegate.getName();
}
}
}
private static final class SynchronizedPool<T> extends SynchronizedObject<Pool<T>> implements Pool<T> {
private static final long serialVersionUID = 0L;
SynchronizedPool(final Pool<T> pool, final Object mutex) {
super(pool, mutex);
}
@Override
public boolean equals(@Nullable final Object object) {
if (object == this) {
return true;
}
synchronized (this.mutex) {
return this.delegate.equals(object);
}
}
@Override
public int hashCode() {
synchronized (this.mutex) {
return this.delegate.hashCode();
}
}
public boolean contains(final Object object) {
synchronized (this.mutex) {
return this.delegate.contains(object);
}
}
public void add(final T object) {
synchronized (this.mutex) {
this.delegate.add(object);
}
}
public void remove(final T object) {
synchronized (this.mutex) {
this.delegate.remove(object);
}
}
public Collection<T> toCollection() {
synchronized (this.mutex) {
return this.delegate.toCollection();
}
}
}
private static final class SynchronizedHandler<T> extends SynchronizedObject<Handler<T>> implements Handler<T> {
private static final long serialVersionUID = 0L;
SynchronizedHandler(final Handler<T> handler, final Object mutex) {
super(handler, mutex);
}
@Override
public boolean equals(@Nullable final Object object) {
if (object == this) {
return true;
}
synchronized (this.mutex) {
return this.delegate.equals(object);
}
}
@Override
public int hashCode() {
synchronized (this.mutex) {
return this.delegate.hashCode();
}
}
public void register(final T object) {
synchronized (this.mutex) {
this.delegate.register(object);
}
}
public void unregister(final T object) {
synchronized (this.mutex) {
this.delegate.unregister(object);
}
}
}
private static final class SynchronizedHook<T, L extends Listener> extends SynchronizedRegistrable<Hook<T, L>> implements Hook<T, L> {
private static final long serialVersionUID = 0L;
SynchronizedHook(final Hook<T, L> handler, final Object mutex) {
super(handler, mutex);
}
@Override
public boolean equals(@Nullable final Object object) {
if (object == this) {
return true;
}
synchronized (this.mutex) {
return this.delegate.equals(object);
}
}
@Override
public int hashCode() {
synchronized (this.mutex) {
return this.delegate.hashCode();
}
}
public void add(final T object) {
synchronized (this.mutex) {
this.delegate.add(object);
}
}
public void remove(final T object) {
synchronized (this.mutex) {
this.delegate.remove(object);
}
}
public Collection<T> toCollection() {
synchronized (this.mutex) {
return this.delegate.toCollection();
}
}
public L forListener() {
synchronized (this.mutex) {
return this.delegate.forListener();
}
}
}
static <L extends Listener> Resource<L> resource(final Resource<L> resource) {
return new SynchronizedResource<>(resource, new Object());
}
static <T> Pool<T> pool(final Pool<T> pool) {
return new SynchronizedPool<>(pool, new Object());
}
static <T> Handler<T> handler(final Handler<T> handler) {
return new SynchronizedHandler<>(handler, new Object());
}
static <T, L extends Listener> Hook<T, L> hook(final Hook<T, L> hook) {
return new SynchronizedHook<>(hook, new Object());
}
}