/* * 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.server.internal; import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.engine.api.tree.RequestContext; import net.openhft.chronicle.network.connection.WireOutPublisher; import net.openhft.chronicle.wire.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static net.openhft.chronicle.network.connection.CoreFields.reply; import static net.openhft.chronicle.network.connection.WireOutPublisher.newThrottledWireOutPublisher; import static net.openhft.chronicle.wire.WriteMarshallable.EMPTY; /** * Created by Rob Austin */ abstract class AbstractHandler { private static final Logger LOG = LoggerFactory.getLogger(AbstractHandler.class); @Nullable WireOut outWire = null; volatile boolean connectionClosed = false; RequestContext requestContext; long readPosAfterValueIn = -1; private boolean hasSkipped; boolean startEnforceInValueReadCheck(WireIn w) { assert readPosAfterValueIn == -1; readPosAfterValueIn = w.bytes().readPosition(); hasSkipped = false; return true; } void skipValue(ValueIn valueIn) { assert (hasSkipped = true) == true; valueIn.skipValue(); } boolean endEnforceInValueReadCheck(WireIn w) { try { assert readPosAfterValueIn != -1; if (hasSkipped) return true; return w.bytes().readPosition() > readPosAfterValueIn; } finally { readPosAfterValueIn = -1; } } static void nullCheck(@Nullable Object o) { if (o == null) throw new NullPointerException(); } void setOutWire(@NotNull final WireOut outWire) { this.outWire = outWire; } /** * write and exceptions and rolls back if no data was written */ void writeData(@NotNull WireIn wireIn, @NotNull WriteMarshallable c) { @NotNull Bytes inBytes = wireIn.bytes(); outWire.writeDocument(false, out -> { final long readPosition = inBytes.readPosition(); final long position = outWire.bytes().writePosition(); try { c.writeMarshallable(outWire); } catch (Throwable t) { final String readingYaml = wireIn.readingPeekYaml(); inBytes.readPosition(readPosition); if (LOG.isInfoEnabled()) LOG.info("While readingBytes=" + inBytes.toDebugString() + "\nreadingYaml=" + readingYaml, "\nprocessing wire " + c, t); outWire.bytes().writePosition(position); outWire.writeEventName(() -> "readingYaml").text(readingYaml); outWire.writeEventName(() -> "exception").throwable(t); } // write 'reply : {} ' if no data was sent if (position == outWire.bytes().writePosition()) { outWire.writeEventName(reply).marshallable(EMPTY); } }); logYaml(); } /** * write and exceptions and rolls back if no data was written */ void writeData(boolean isNotComplete, @NotNull Bytes inBytes, @NotNull WriteMarshallable c) { @NotNull final WriteMarshallable marshallable = out -> { final long readPosition = inBytes.readPosition(); final long position = outWire.bytes().writePosition(); try { c.writeMarshallable(outWire); } catch (Throwable t) { inBytes.readPosition(readPosition); if (LOG.isInfoEnabled()) LOG.info("While reading " + inBytes.toDebugString(), " processing wire " + c, t); outWire.bytes().writePosition(position); outWire.writeEventName(() -> "exception").throwable(t); } // write 'reply : {} ' if no data was sent if (position == outWire.bytes().writePosition()) { outWire.writeEventName(reply).marshallable(EMPTY); } }; if (isNotComplete) outWire.writeNotCompleteDocument(false, marshallable); else outWire.writeDocument(false, marshallable); logYaml(); } void logYaml() { if (YamlLogging.showServerWrites()) try { assert outWire.startUse(); LOG.info("\nServer Sends:\n" + Wires.fromSizePrefixedBlobs((Wire) outWire)); } catch (Exception e) { Jvm.warn().on(getClass(), "\nServer Sends ( corrupted ) :\n" + outWire.bytes().toDebugString()); } finally { assert outWire.endUse(); } } /** * called when the connection is closed */ void onEndOfConnection() { connectionClosed = true; unregisterAll(); } /** * called when the connection is closed */ protected void unregisterAll() { } /** * @param publisher * @return If the throttlePeriodMs is set returns a throttled wire out publisher, otherwise the * original */ @NotNull WireOutPublisher publisher(@NotNull final WireOutPublisher publisher) { return requestContext.throttlePeriodMs() == 0 ? publisher : newThrottledWireOutPublisher(requestContext.throttlePeriodMs(), publisher); } }