Package net.sf.cindy.filter

Source Code of net.sf.cindy.filter.PacketDecoderFilter$LinkPacketDecoderFilter

/*
* Copyright 2004-2006 the original author or authors.
*
* 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.sf.cindy.filter;

import java.net.SocketAddress;

import net.sf.cindy.Buffer;
import net.sf.cindy.Packet;
import net.sf.cindy.Session;
import net.sf.cindy.SessionFilterAdapter;
import net.sf.cindy.SessionFilterChain;
import net.sf.cindy.SessionType;
import net.sf.cindy.buffer.BufferFactory;
import net.sf.cindy.buffer.LinkedBuffer;
import net.sf.cindy.packet.DefaultPacket;
import net.sf.cindy.util.Configuration;

/**
* Decode <code>Packet</code> to object. Inner filter before
* <code>SessionHandlerFilter</code>.
*
* @author <a href="chenrui@gmail.com">Roger Chen</a>
* @version $id$
*/
public class PacketDecoderFilter extends SessionFilterAdapter {

    private static final boolean USE_LINKED_BUFFER = Configuration
            .isUseLinkedBuffer();

    public static PacketDecoderFilter getInstance(Session session) {
        if (session.getSessionType() == SessionType.UDP)
            return new DiscardPacketDecoderFilter(session);
        if (USE_LINKED_BUFFER)
            return new LinkPacketDecoderFilter(session);
        return new CopyPacketDecoderFilter(session);
    }

    protected final Session session;

    protected PacketDecoderFilter(Session session) {
        this.session = session;
    }

    protected void recognize(Buffer content, SocketAddress address)
            throws Exception {
        while (content.hasRemaining()) {
            Buffer slice = content.asReadOnlyBuffer().slice();
            Object obj = session.getPacketDecoder().decode(session,
                    new DefaultPacket(slice, address));
            if (obj == null)
                break;
            content.skip(slice.position());
            session.getSessionFilterChain(false).objectReceived(obj);
        }
    }

    /**
     * Datagram session should discard previous received packet.
     *
     * @author <a href="chenrui@gmail.com">Roger Chen</a>
     * @version $id$
     */
    private static class DiscardPacketDecoderFilter extends PacketDecoderFilter {

        public DiscardPacketDecoderFilter(Session session) {
            super(session);
        }

        public void packetReceived(SessionFilterChain filterChain, Packet packet)
                throws Exception {
            if (packet == null || filterChain.getSession() != session)
                super.packetReceived(filterChain, packet);
            else {
                Buffer content = packet.getContent();
                if (content != null)
                    try {
                        recognize(content, packet.getAddress());
                    } finally {
                        content.release();
                    }
            }
        }

    }

    /**
     * Copy received content as a single content.
     *
     * @author <a href="chenrui@gmail.com">Roger Chen</a>
     * @version $id$
     */
    private static class CopyPacketDecoderFilter extends PacketDecoderFilter {

        private Buffer content;
        private SocketAddress address;

        public CopyPacketDecoderFilter(Session session) {
            super(session);
        }

        public void sessionClosed(SessionFilterChain filterChain)
                throws Exception {
            if (filterChain.getSession() == session) {
                synchronized (this) {
                    if (content != null) {
                        content.release();
                        content = null;
                    }
                    address = null;
                }
            }
            super.sessionClosed(filterChain);
        }

        public void packetReceived(SessionFilterChain filterChain, Packet packet)
                throws Exception {
            if (packet == null || filterChain.getSession() != session) {
                super.packetReceived(filterChain, packet);
                return;
            }

            synchronized (this) {
                if (content == null) {
                    content = packet.getContent();
                    address = packet.getAddress();
                } else {
                    Buffer recvContent = packet.getContent();
                    if (content.remaining() < recvContent.remaining()) {
                        Buffer newContent = BufferFactory.allocate(
                                content.position() + recvContent.remaining())
                                .put(content.flip());
                        content.release();
                        content = newContent;
                    }
                    content.put(recvContent);
                    content.flip();
                }

                if (content != null)
                    try {
                        recognize(content, address);
                    } finally {
                        if (content.hasRemaining())
                            content.compact();
                        else {
                            content.release();
                            content = null;
                            address = null;
                        }
                    }
            }
        }
    }

    /**
     * Link received contents as a single content. Experimental.
     *
     * @author <a href="chenrui@gmail.com">Roger Chen</a>
     * @version $id$
     */
    private static class LinkPacketDecoderFilter extends PacketDecoderFilter {

        private LinkedPacketDecoderBuffer content;
        private SocketAddress address;

        public LinkPacketDecoderFilter(Session session) {
            super(session);
        }

        public void sessionClosed(SessionFilterChain filterChain)
                throws Exception {
            if (filterChain.getSession() == session) {
                synchronized (this) {
                    if (content != null) {
                        content.release();
                        content = null;
                    }
                    address = null;
                }
            }
            super.sessionClosed(filterChain);
        }

        public void packetReceived(SessionFilterChain filterChain, Packet packet)
                throws Exception {
            if (packet == null || filterChain.getSession() != session) {
                super.packetReceived(filterChain, packet);
                return;
            }

            synchronized (this) {
                if (content == null) {
                    content = new LinkedPacketDecoderBuffer();
                    address = packet.getAddress();
                }
                content.append(packet.getContent());
                try {
                    recognize(content, address);
                } finally {
                    content.releaseNoUseBuffer();
                }
            }

        }

        /**
         * Link several buffers as a single buffer.
         *
         * @author <a href="chenrui@gmail.com">Roger Chen</a>
         * @version $id$
         */
        private static class LinkedPacketDecoderBuffer extends LinkedBuffer {

            private static final Buffer[] EMPTY_BUFFER = new Buffer[0];

            public LinkedPacketDecoderBuffer() {
                super(EMPTY_BUFFER);
            }

            protected void append(Buffer buffer) {
                super.append(buffer);
                limit(capacity());
            }

            private void releaseNoUseBuffer() {
                int position = position();
                int releasedLen = 0;

                for (Entry e = header.next; e != header;) {
                    int length = e.buffer.remaining();
                    if (e.position + length <= position) {
                        Entry next = e.next;
                        e.previous.next = next;
                        next.previous = e.previous;

                        releasedLen += length;
                        e.buffer.release();
                        e.buffer = null;
                        e.next = null;
                        e.previous = null;
                        e = next;
                    } else
                        e = e.next;
                }

                if (releasedLen > 0) {
                    for (Entry e = header.next; e != header; e = e.next) {
                        e.position -= releasedLen;
                    }
                    position(position() - releasedLen);
                    limit(limit() - releasedLen);
                    capacity(capacity() - releasedLen);
                }
            }
        }
    }

}
TOP

Related Classes of net.sf.cindy.filter.PacketDecoderFilter$LinkPacketDecoderFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.