Java tutorial
// Copyright (c) 2016 Natalia Dymnikova // Available via the MIT license // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated // documentation files (the "Software"), to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE // OR OTHER DEALINGS IN THE SOFTWARE. package natalia.dymnikova.cluster.scheduler.impl; import com.google.protobuf.ByteString; import natalia.dymnikova.cluster.scheduler.Remote; import natalia.dymnikova.cluster.scheduler.RemoteFunction; import natalia.dymnikova.cluster.scheduler.RemoteOperator; import natalia.dymnikova.cluster.scheduler.RemoteSubscriber; import natalia.dymnikova.cluster.scheduler.RemoteSupplier; import natalia.dymnikova.cluster.scheduler.impl.AkkaBackedRemoteObservable.RemoteOperatorImpl; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import rx.Observable; import rx.Observable.Operator; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.util.function.Supplier; import static java.lang.reflect.Modifier.isStatic; import static natalia.dymnikova.util.MoreThrowables.propagateUnchecked; import static natalia.dymnikova.util.MoreThrowables.unchecked; /** * */ @Lazy @Component public class Codec { public <T extends Serializable> byte[] pack(final RemoteSupplier<T> f) { return pack((Remote) f); } public <T extends Serializable> byte[] pack(final Remote f) { return packObject(sanitize(f)); } public <T extends Serializable> Supplier<Observable<T>> unpackSupplier(final byte[] b) { return (Supplier<Observable<T>>) unpack(b); } public Serializable unpack(final byte[] b) { return unpack(new ByteArrayInputStream(b)); } public Serializable unpack(final InputStream inputStream) { try { try (final ObjectInputStream in = new ObjectInputStream(inputStream)) { return (Serializable) in.readObject(); } } catch (final IOException e) { throw propagateUnchecked(e); } catch (final ClassNotFoundException e) { throw unchecked(e); } } public <I extends Serializable, O extends Serializable> byte[] pack(final RemoteFunction<I, O> f) { return pack((Remote) f); } public <I extends Serializable, O extends Serializable> byte[] pack(final RemoteOperator<I, O> f) { return pack((Remote) f); } public <I extends Serializable, O extends Serializable> Operator<I, O> unpackOperator(final byte[] b) { return (Operator<I, O>) unpack(b); } public Remote unpackRemote(final byte[] b) { return (Remote) unpack(b); } public Remote unpackRemote(final ByteString b) { return (Remote) unpack(b.newInput()); } public byte[] packObject(final Object funct) { try { // TODO make sense to reuse Codec and inner ObjectOutputStream at least for a single RemoteObservable final ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream(); final ObjectOutputStream os = new ObjectOutputStream(arrayOutputStream); os.writeObject(funct); os.close(); return arrayOutputStream.toByteArray(); } catch (final IOException e) { throw propagateUnchecked(e); } } private static Object sanitize(final Object f) { if (f instanceof RemoteOperatorImpl) { doSanitize(((RemoteOperatorImpl) f).delegate); return f; } else { return doSanitize(f); } } private static Object doSanitize(final Object f) { final Class<?> aClass = f.getClass(); if (!isStatic(aClass.getModifiers())) { final Class<?> enclosingClass = aClass.getEnclosingClass(); if (enclosingClass != null) { for (final Field field : aClass.getDeclaredFields()) { if (enclosingClass.equals(field.getType())) { field.setAccessible(true); try { field.set(f, null); } catch (final IllegalAccessException e) { throw unchecked(e); } } } } } return f; } public <T extends Serializable> RemoteSubscriber<T> unpackSubscriber(final byte[] b) { return (RemoteSubscriber<T>) unpack(b); } }