com.addthis.meshy.TargetHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.addthis.meshy.TargetHandler.java

Source

/*
 * 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 com.addthis.meshy;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;

import com.google.common.base.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;

import static com.addthis.meshy.MeshyConstants.KEY_RESPONSE;

public abstract class TargetHandler implements SessionHandler {

    protected static final Logger log = LoggerFactory.getLogger(TargetHandler.class);
    private final AtomicBoolean complete = new AtomicBoolean(false);
    private final AtomicBoolean waited = new AtomicBoolean(false);
    private final CountDownLatch latch = new CountDownLatch(1);

    private MeshyServer master;
    private ChannelState channelState;
    private int session;

    public TargetHandler() {
    }

    public void setContext(MeshyServer master, ChannelState state, int session) {
        this.master = master;
        this.channelState = state;
        this.session = session;
    }

    protected Objects.ToStringHelper toStringHelper() {
        return Objects.toStringHelper(this).add("channelState", channelState.getName()).add("session", session)
                .add("complete", complete).add("waited", waited);
    }

    @Override
    public String toString() {
        return toStringHelper().toString();
    }

    public ChannelState getChannelState() {
        return channelState;
    }

    public MeshyServer getChannelMaster() {
        return master;
    }

    public int getSessionId() {
        return session;
    }

    public boolean send(byte[] data) {
        return send(data, null);
    }

    public void send(ByteBuf from, int length) {
        log.trace("{} send.buf [{}] {}", this, length, from);
        channelState.send(channelState.allocateSendBuffer(KEY_RESPONSE, session, from, length), null, length);
    }

    @Override
    public boolean send(byte[] data, SendWatcher watcher) {
        log.trace("{} send {}", this, data.length);
        return channelState.send(channelState.allocateSendBuffer(KEY_RESPONSE, session, data), watcher,
                data.length);
    }

    public void send(byte[] data, int off, int len, SendWatcher watcher) {
        log.trace("{} send {} o={} l={}", this, data.length, off, len);
        channelState.send(channelState.allocateSendBuffer(KEY_RESPONSE, session, data, off, len), watcher, len);
    }

    public ByteBuf getSendBuffer(int length) {
        return channelState.allocateSendBuffer(KEY_RESPONSE, session, length);
    }

    public int send(ByteBuf buffer, SendWatcher watcher) {
        if (log.isTraceEnabled()) {
            log.trace("{} send b={} l={}", this, buffer, buffer.readableBytes());
        }
        int length = buffer.readableBytes();
        channelState.send(buffer, watcher, length);
        return length;
    }

    @Override
    public boolean sendComplete() {
        return send(MeshyConstants.EMPTY_BYTES, null);
    }

    @Override
    public void receive(ChannelState state, int receivingSession, int length, ByteBuf buffer) throws Exception {
        assert this.channelState == state;
        assert this.session == session;
        log.debug("{} receive [{}] l={}", this, session, length);
        receive(length, buffer);
    }

    @Override
    public void receiveComplete(ChannelState state, int completedSession) throws Exception {
        assert this.channelState == state;
        assert this.session == completedSession;
        log.debug("{} receiveComplete.1 [{}]", this, completedSession);
        if (!state.getChannel().isOpen()) {
            channelClosed();
        }
        receiveComplete(completedSession);
    }

    private void receiveComplete(int completedSession) throws Exception {
        assert this.session == completedSession;
        log.debug("{} receiveComplete.2 [{}]", this, completedSession);
        // ensure this is only called once
        if (complete.compareAndSet(false, true)) {
            receiveComplete();
            latch.countDown();
        }
    }

    protected void autoReceiveComplete() {
        channelState.sessionComplete(this, MeshyConstants.KEY_EXISTING, session);
    }

    @Override
    public void waitComplete() {
        // this is technically incorrect, but prevents lockups
        if (waited.compareAndSet(false, true)) {
            try {
                latch.await();
            } catch (Exception ex) {
                log.error("Swallowing exception while waitComplete() on targetHandler", ex);
            }
        }
    }

    public abstract void channelClosed();

    public abstract void receive(int length, ByteBuf buffer) throws Exception;

    public abstract void receiveComplete() throws Exception;
}