/* * Copyright 2016 higherfrequencytrading.com * * 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 net.openhft.chronicle.engine.collection; /** * Created by Rob Austin */ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.network.connection.CoreFields; import net.openhft.chronicle.wire.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Supplier; /** * @author Rob Austin. */ public class CollectionWireHandler<U, C extends Collection<U>> { private static final int SIZE_OF_SIZE = 4; private static final Logger LOG = LoggerFactory.getLogger(CollectionWireHandler.class); private Function<ValueIn, U> fromWire; private BiConsumer<ValueOut, U> toWire; @Nullable private WireIn inWire = null; @Nullable private WireOut outWire = null; private C underlyingCollection; private long tid; private Supplier<C> factory; private final ReadMarshallable dataConsumer = new ReadMarshallable() { @Override public void readMarshallable(WireIn wire) throws IllegalStateException { try { final StringBuilder eventName = Wires.acquireStringBuilder(); @NotNull @SuppressWarnings("ConstantConditions") final ValueIn valueIn = inWire.readEventName(eventName); outWire.writeDocument(true, w -> w.writeEventName(CoreFields.tid).int64 (CollectionWireHandler.this.tid)); outWire.writeDocument(false, out -> { // note : remove on the key-set returns a boolean and on the map returns the // old value if (EventId.remove.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool(underlyingCollection.remove(fromWire.apply(valueIn))); return; } // note : remove on the key-set returns a boolean and on the map returns the // old value if (EventId.iterator.contentEquals(eventName)) { @NotNull final ValueOut valueOut = out.writeEventName(CoreFields.reply); valueOut.sequence(v -> underlyingCollection.forEach(e -> toWire.accept(v, e))); return; } if (EventId.numberOfSegments.contentEquals(eventName)) { outWire.write(CoreFields.reply).int32(1); return; } if (EventId.isEmpty.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool(underlyingCollection.isEmpty()); return; } if (EventId.size.contentEquals(eventName)) { outWire.write(CoreFields.reply).int32(underlyingCollection.size()); return; } if (EventId.clear.contentEquals(eventName)) { underlyingCollection.clear(); return; } if (EventId.contains.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.contains(fromWire.apply(valueIn))); return; } if (EventId.add.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.add(fromWire.apply(valueIn))); return; } if (EventId.remove.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.remove(fromWire.apply(valueIn))); return; } if (EventId.containsAll.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.remove(collectionFromWire())); return; } if (EventId.addAll.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.addAll(collectionFromWire())); return; } if (EventId.removeAll.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.removeAll(collectionFromWire())); return; } if (EventId.retainAll.contentEquals(eventName)) { outWire.write(CoreFields.reply).bool( underlyingCollection.retainAll(collectionFromWire())); return; } throw new IllegalStateException("unsupported event=" + eventName); }); } catch (Exception e) { Jvm.warn().on(getClass(), e); } finally { if (YamlLogging.showServerWrites()) { assert outWire.startUse(); try { @NotNull final Bytes<?> outBytes = outWire.bytes(); long len = outBytes.writePosition(); if (len >= SIZE_OF_SIZE) { String s = Wires.fromSizePrefixedBlobs((Wire) outWire); LOG.info("server writes:\n\n" + s); } }finally { assert outWire.endUse(); } } } } }; private C collectionFromWire() { C c = factory.get(); @NotNull @SuppressWarnings("ConstantConditions") final ValueIn valueIn = ((Wire) outWire).getValueIn(); while (valueIn.hasNextSequenceItem()) { c.add(fromWire.apply(valueIn)); } return c; } @SuppressWarnings("unchecked") public void process(@NotNull WireIn in, @NotNull WireOut out, @NotNull C collection, @NotNull BiConsumer toWire, @NotNull Function fromWire, @NotNull Supplier factory, long tid) { this.fromWire = fromWire; this.toWire = toWire; this.underlyingCollection = collection; this.factory = factory; try { this.inWire = in; this.outWire = out; this.tid = tid; assert in.startUse(); dataConsumer.readMarshallable(in); } catch (RuntimeException e) { Jvm.warn().on(getClass(), e); }finally { assert in.endUse(); } } enum Params implements WireKey { key, segment, } enum EventId implements ParameterizeWireKey { size, isEmpty, add, addAll, retainAll, containsAll, removeAll, clear, remove(CollectionWireHandler.Params.key), numberOfSegments, contains(CollectionWireHandler.Params.key), identifier, iterator(CollectionWireHandler.Params.segment); private final WireKey[] params; <P extends WireKey> EventId(P... params) { this.params = params; } @NotNull public <P extends WireKey> P[] params() { return (P[]) this.params; } } }