// Path: tftp-protocol/src/main/java/org/anarres/tftp/protocol/engine/TftpTransfer.java
// public interface TftpTransfer<TftpTransferContext> {
// 
//     /**
//      * Opens this TftpTransfer and sends the initial packets.
//      *
//      * Implemented by the transfer.
//      */
//     public void open(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /**
//      * Responds to an incoming packet on this transfer.
//      *
//      * Implemented by the transfer.
//      */
//     public void handle(@Nonnull TftpTransferContext context, @Nonnull TftpPacket packet) throws Exception;
// 
//     /** Implemented by the transfer. */
//     public void timeout(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void send(@Nonnull TftpTransferContext context, @Nonnull TftpPacket packet) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void flush(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void close(@Nonnull TftpTransferContext context) throws Exception;
// }
// 
// Path: tftp-protocol/src/main/java/org/anarres/tftp/protocol/packet/TftpPacket.java
// public abstract class TftpPacket {
// 
//     // Substitute for netascii in the RFC. ISO_8859_1 is 8-bit transparent.
//     public static final Charset CHARSET = Charsets.ISO_8859_1;
//     private SocketAddress remoteAddress;
// 
//     @Nonnull
//     public SocketAddress getRemoteAddress() {
//         return remoteAddress;
//     }
// 
//     public void setRemoteAddress(@Nonnull SocketAddress remoteAddress) {
//         this.remoteAddress = Preconditions.checkNotNull(remoteAddress, "Remote address was null.");
//     }
// 
//     /** At most this long, possibly less. */
//     @Nonnegative
//     public int getWireLength() {
//         return 256;
//     }
// 
//     @Nonnull
//     public abstract TftpOpcode getOpcode();
// 
//     @Nonnull
//     protected Objects.ToStringHelper toStringHelper() {
//         return Objects.toStringHelper(this).add("opcode", getOpcode());
//     }
// 
//     public void toWire(@Nonnull ByteBuffer buffer) {
//         buffer.putShort(getOpcode().getCode());
//     }
// 
//     /** This is called after the opcode has already been read. */
//     public abstract void fromWire(@Nonnull ByteBuffer buffer);
// 
//     protected static void putString(@Nonnull ByteBuffer buffer, @Nonnull String text) {
//         buffer.put(text.getBytes(CHARSET));
//         buffer.put((byte) 0);
//     }
// 
//     @Nonnull
//     protected static String getString(@Nonnull ByteBuffer buffer) {
//         int start = buffer.position();
//         int finish;
//         int end = -1;
//         for (finish = start; finish < buffer.limit(); finish++) {
//             if (buffer.get(finish) == 0) {
//                 end = finish;
//                 finish++;
//                 break;
//             }
//         }
//         // We didn't find a zero byte.
//         if (end == -1)
//             end = buffer.limit();
// 
//         byte[] bytes = new byte[end - start];
//         buffer.get(bytes);
//         buffer.position(finish);
//         return new String(bytes, CHARSET);
//     }
// 
//     @Override
//     public String toString() {
//         return toStringHelper().toString();
//     }
// }


import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
import java.io.IOException;
import javax.annotation.Nonnull;
import org.anarres.tftp.protocol.engine.TftpTransfer;
import org.anarres.tftp.protocol.packet.TftpPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.anarres.tftp.server.netty;


/**
 *
 * @author shevek
 */
public class TftpTransferHandler extends ChannelDuplexHandler {

    private static final Logger LOG = LoggerFactory.getLogger(TftpTransferHandler.class);
    private final TftpTransfer<Channel> transfer;

    public TftpTransferHandler(@Nonnull TftpTransfer<Channel> transfer) throws IOException {
        this.transfer = transfer;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        transfer.open(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
// Path: tftp-protocol/src/main/java/org/anarres/tftp/protocol/engine/TftpTransfer.java
// public interface TftpTransfer<TftpTransferContext> {
// 
//     /**
//      * Opens this TftpTransfer and sends the initial packets.
//      *
//      * Implemented by the transfer.
//      */
//     public void open(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /**
//      * Responds to an incoming packet on this transfer.
//      *
//      * Implemented by the transfer.
//      */
//     public void handle(@Nonnull TftpTransferContext context, @Nonnull TftpPacket packet) throws Exception;
// 
//     /** Implemented by the transfer. */
//     public void timeout(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void send(@Nonnull TftpTransferContext context, @Nonnull TftpPacket packet) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void flush(@Nonnull TftpTransferContext context) throws Exception;
// 
//     /** Implemented by the channel. */
//     public void close(@Nonnull TftpTransferContext context) throws Exception;
// }
// 
// Path: tftp-protocol/src/main/java/org/anarres/tftp/protocol/packet/TftpPacket.java
// public abstract class TftpPacket {
// 
//     // Substitute for netascii in the RFC. ISO_8859_1 is 8-bit transparent.
//     public static final Charset CHARSET = Charsets.ISO_8859_1;
//     private SocketAddress remoteAddress;
// 
//     @Nonnull
//     public SocketAddress getRemoteAddress() {
//         return remoteAddress;
//     }
// 
//     public void setRemoteAddress(@Nonnull SocketAddress remoteAddress) {
//         this.remoteAddress = Preconditions.checkNotNull(remoteAddress, "Remote address was null.");
//     }
// 
//     /** At most this long, possibly less. */
//     @Nonnegative
//     public int getWireLength() {
//         return 256;
//     }
// 
//     @Nonnull
//     public abstract TftpOpcode getOpcode();
// 
//     @Nonnull
//     protected Objects.ToStringHelper toStringHelper() {
//         return Objects.toStringHelper(this).add("opcode", getOpcode());
//     }
// 
//     public void toWire(@Nonnull ByteBuffer buffer) {
//         buffer.putShort(getOpcode().getCode());
//     }
// 
//     /** This is called after the opcode has already been read. */
//     public abstract void fromWire(@Nonnull ByteBuffer buffer);
// 
//     protected static void putString(@Nonnull ByteBuffer buffer, @Nonnull String text) {
//         buffer.put(text.getBytes(CHARSET));
//         buffer.put((byte) 0);
//     }
// 
//     @Nonnull
//     protected static String getString(@Nonnull ByteBuffer buffer) {
//         int start = buffer.position();
//         int finish;
//         int end = -1;
//         for (finish = start; finish < buffer.limit(); finish++) {
//             if (buffer.get(finish) == 0) {
//                 end = finish;
//                 finish++;
//                 break;
//             }
//         }
//         // We didn't find a zero byte.
//         if (end == -1)
//             end = buffer.limit();
// 
//         byte[] bytes = new byte[end - start];
//         buffer.get(bytes);
//         buffer.position(finish);
//         return new String(bytes, CHARSET);
//     }
// 
//     @Override
//     public String toString() {
//         return toStringHelper().toString();
//     }
// }


// Path: tftp-server-netty/src/main/java/org/anarres/tftp/server/netty/TftpTransferHandler.java
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil;
import java.io.IOException;
import javax.annotation.Nonnull;
import org.anarres.tftp.protocol.engine.TftpTransfer;
import org.anarres.tftp.protocol.packet.TftpPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.anarres.tftp.server.netty;


/**
 *
 * @author shevek
 */
public class TftpTransferHandler extends ChannelDuplexHandler {

    private static final Logger LOG = LoggerFactory.getLogger(TftpTransferHandler.class);
    private final TftpTransfer<Channel> transfer;

    public TftpTransferHandler(@Nonnull TftpTransfer<Channel> transfer) throws IOException {
        this.transfer = transfer;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        transfer.open(ctx.channel());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            transfer.handle(ctx.channel(), (TftpPacket) msg);