KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > filter > codec > CumulativeProtocolDecoder


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.filter.codec;
21
22 import org.apache.mina.common.ByteBuffer;
23 import org.apache.mina.common.IoSession;
24
25 /**
26  * A {@link ProtocolDecoder} that cumulates the content of received
27  * buffers to a <em>cumulative buffer</em> to help users implement decoders.
28  * <p>
29  * If the received {@link ByteBuffer} is only a part of a message.
30  * decoders should cumulate received buffers to make a message complete or
31  * to postpone decoding until more buffers arrive.
32  * <p>
33  * Here is an example decoder that decodes CRLF terminated lines into
34  * <code>Command</code> objects:
35  * <pre>
36  * public class CRLFTerminatedCommandLineDecoder
37  * extends CumulativeProtocolDecoder {
38  *
39  * private Command parseCommand(ByteBuffer in) {
40  * // Convert the bytes in the specified buffer to a
41  * // Command object.
42  * ...
43  * }
44  *
45  * protected boolean doDecode(IoSession session, ByteBuffer in,
46  * ProtocolDecoderOutput out)
47  * throws Exception {
48  *
49  * // Remember the initial position.
50  * int start = in.position();
51  *
52  * // Now find the first CRLF in the buffer.
53  * byte previous = 0;
54  * while (in.hasRemaining()) {
55  * byte current = in.get();
56  *
57  * if (previous == '\r' && current == '\n') {
58  * // Remember the current position and limit.
59  * int position = in.position();
60  * int limit = in.limit();
61  * try {
62  * in.position(start);
63  * in.limit(position);
64  * // The bytes between in.position() and in.limit()
65  * // now contain a full CRLF terminated line.
66  * out.write(parseCommand(in.slice()));
67  * } finally {
68  * // Set the position to point right after the
69  * // detected line and set the limit to the old
70  * // one.
71  * in.position(position);
72  * in.limit(limit);
73  * }
74  * // Decoded one line; CumulativeProtocolDecoder will
75  * // call me again until I return false. So just
76  * // return true until there are no more lines in the
77  * // buffer.
78  * return true;
79  * }
80  *
81  * previous = current;
82  * }
83  *
84  * // Could not find CRLF in the buffer. Reset the initial
85  * // position to the one we recorded above.
86  * in.position(start);
87  *
88  * return false;
89  * }
90  * }
91  * </pre>
92  *
93  * @author The Apache Directory Project (mina-dev@directory.apache.org)
94  * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $
95  */

96 public abstract class CumulativeProtocolDecoder extends ProtocolDecoderAdapter {
97
98     private static final String JavaDoc BUFFER = CumulativeProtocolDecoder.class
99             .getName()
100             + ".Buffer";
101
102     /**
103      * Creates a new instance.
104      */

105     protected CumulativeProtocolDecoder() {
106     }
107
108     /**
109      * Cumulates content of <tt>in</tt> into internal buffer and forwards
110      * decoding request to {@link #doDecode(IoSession, ByteBuffer, ProtocolDecoderOutput)}.
111      * <tt>doDecode()</tt> is invoked repeatedly until it returns <tt>false</tt>
112      * and the cumulative buffer is compacted after decoding ends.
113      *
114      * @throws IllegalStateException if your <tt>doDecode()</tt> returned
115      * <tt>true</tt> not consuming the cumulative buffer.
116      */

117     public void decode(IoSession session, ByteBuffer in,
118             ProtocolDecoderOutput out) throws Exception JavaDoc {
119         boolean usingSessionBuffer = true;
120         ByteBuffer buf = (ByteBuffer) session.getAttribute(BUFFER);
121         // If we have a session buffer, append data to that; otherwise
122
// use the buffer read from the network directly.
123
if (buf != null) {
124             buf.put(in);
125             buf.flip();
126         } else {
127             buf = in;
128             usingSessionBuffer = false;
129         }
130
131         for (;;) {
132             int oldPos = buf.position();
133             boolean decoded = doDecode(session, buf, out);
134             if (decoded) {
135                 if (buf.position() == oldPos) {
136                     throw new IllegalStateException JavaDoc(
137                             "doDecode() can't return true when buffer is not consumed.");
138                 }
139
140                 if (!buf.hasRemaining()) {
141                     break;
142                 }
143             } else {
144                 break;
145             }
146         }
147
148         // if there is any data left that cannot be decoded, we store
149
// it in a buffer in the session and next time this decoder is
150
// invoked the session buffer gets appended to
151
if (buf.hasRemaining()) {
152             if (usingSessionBuffer)
153                 buf.compact();
154             else
155                 storeRemainingInSession(buf, session);
156         } else {
157             if (usingSessionBuffer)
158                 removeSessionBuffer(session);
159         }
160     }
161
162     /**
163      * Implement this method to consume the specified cumulative buffer and
164      * decode its content into message(s).
165      *
166      * @param in the cumulative buffer
167      * @return <tt>true</tt> if and only if there's more to decode in the buffer
168      * and you want to have <tt>doDecode</tt> method invoked again.
169      * Return <tt>false</tt> if remaining data is not enough to decode,
170      * then this method will be invoked again when more data is cumulated.
171      * @throws Exception if cannot decode <tt>in</tt>.
172      */

173     protected abstract boolean doDecode(IoSession session, ByteBuffer in,
174             ProtocolDecoderOutput out) throws Exception JavaDoc;
175
176     /**
177      * Releases the cumulative buffer used by the specified <tt>session</tt>.
178      * Please don't forget to call <tt>super.dispose( session )</tt> when
179      * you override this method.
180      */

181     public void dispose(IoSession session) throws Exception JavaDoc {
182         removeSessionBuffer(session);
183     }
184
185     private void removeSessionBuffer(IoSession session) {
186         ByteBuffer buf = (ByteBuffer) session.removeAttribute(BUFFER);
187         if (buf != null) {
188             buf.release();
189         }
190     }
191
192     private void storeRemainingInSession(ByteBuffer buf, IoSession session) {
193         ByteBuffer remainingBuf = ByteBuffer.allocate(buf.capacity());
194         remainingBuf.setAutoExpand(true);
195         remainingBuf.order(buf.order());
196         remainingBuf.put(buf);
197         session.setAttribute(BUFFER, remainingBuf);
198     }
199 }
200
Popular Tags