View Javadoc

1   /***
2    * 
3    * Copyright 2004 Hiram Chirino
4    * 
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License. You may obtain a copy of
7    * the License at
8    * 
9    * http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package org.activeio.packet;
18  
19  import java.io.DataOutput;
20  import java.io.IOException;
21  import java.io.OutputStream;
22  import java.lang.reflect.Constructor;
23  
24  import org.activeio.Packet;
25  
26  /***
27   * Appends two packets together.
28   * 
29   * @version $Revision$
30   */
31  final public class AppendedPacket implements Packet {
32  
33      private final Packet first;
34      private final Packet last;
35  
36      private final int capacity;
37      private final int firstCapacity;
38  
39      static public Packet join(Packet first, Packet last) {
40          if( first.hasRemaining() ) {
41              if( last.hasRemaining() ) {
42                  
43                  //TODO: this might even be a rejoin of the same continous buffer.
44                  //It would be good if we detected that and avoided just returned the buffer.
45                  
46                  return new AppendedPacket(first.slice(), last.slice());               
47              } else {
48                  return first.slice();
49              }
50          } else {
51              if( last.hasRemaining() ) {
52                  return last.slice();                
53              } else {
54                  return EmptyPacket.EMPTY_PACKET;
55              }            
56          }
57      }
58      
59      /***
60       * @deprecated use {@see #join(Packet, Packet)} instead.
61       */
62      public AppendedPacket(Packet first, Packet second) {
63          this.first = first;
64          this.last = second;
65          this.firstCapacity = first.capacity();
66          this.capacity = first.capacity()+last.capacity();
67          clear();        
68      }
69          
70      public void position(int position) {
71          if( position <= firstCapacity ) {
72              last.position(0);
73              first.position(position);
74          } else {
75              last.position(position-firstCapacity);
76              first.position(firstCapacity);
77          }
78      }
79      
80      public void limit(int limit) {
81          if( limit <= firstCapacity ) {
82              last.limit(0);
83              first.limit(limit);
84          } else {
85              last.limit(limit-firstCapacity);
86              first.limit(firstCapacity);
87          }
88      }
89  
90      public Packet slice() {
91          return join(first,last);
92      }
93  
94      public Packet duplicate() {
95          return new AppendedPacket(first.duplicate(), last.duplicate());               
96      }
97  
98      public Object duplicate(ClassLoader cl) throws IOException {
99          try {
100             Class pclazz = cl.loadClass(Packet.class.getName());
101             Class clazz = cl.loadClass(AppendedPacket.class.getName());
102             Constructor constructor = clazz.getConstructor(new Class[]{pclazz, pclazz});
103             return constructor.newInstance(new Object[]{first.duplicate(cl), last.duplicate(cl)});
104         } catch (Throwable e) {
105             throw (IOException)new IOException("Could not duplicate packet in a different classloader: "+e).initCause(e);
106         }
107     }
108     
109     public void flip() {
110         limit(position());
111         position(0);
112     }
113 
114     public int position() {
115         return first.position()+last.position();
116     }
117     
118     public int limit() {
119         return first.limit()+last.limit();
120     }    
121 
122     public int remaining() {
123         return first.remaining()+last.remaining();
124     }
125 
126     public void rewind() {
127         first.rewind();
128         last.rewind();
129     }
130 
131     public boolean hasRemaining() {
132         return first.hasRemaining()||last.hasRemaining();
133     }
134 
135     public void clear() {
136         first.clear();
137         last.clear();        
138     }
139 
140     public int capacity() {
141         return capacity;
142     }
143 
144     public void writeTo(OutputStream out) throws IOException {
145         first.writeTo(out);
146         last.writeTo(out);
147     }
148     
149     public void writeTo(DataOutput out) throws IOException {
150         first.writeTo(out);
151         last.writeTo(out);
152     }
153 
154 
155     /***
156      * @see org.activeio.Packet#read()
157      */
158     public int read() {
159         if( first.hasRemaining() ) {
160             return first.read();
161         } else if( last.hasRemaining() ) {
162             return last.read();
163         } else {
164             return -1;
165         }
166     }
167 
168     /***
169      * @see org.activeio.Packet#read(byte[], int, int)
170      */
171     public int read(byte[] data, int offset, int length) {        
172         
173         int rc1 = first.read(data, offset, length);        
174         if( rc1==-1 ) {
175             int rc2 = last.read(data, offset, length);
176             return ( rc2==-1 ) ? -1 : rc2;
177         } else {
178             int rc2 = last.read(data, offset+rc1, length-rc1);
179             return ( rc2==-1 ) ? rc1 : rc1+rc2;
180         }
181 
182     }
183 
184     /***
185      * @see org.activeio.Packet#write(int)
186      */
187     public boolean write(int data) {
188         if( first.hasRemaining() ) {
189             return first.write(data);
190         } else if( last.hasRemaining() ) {
191             return last.write(data);
192         } else {
193             return false;
194         }
195     }
196 
197     /***
198      * @see org.activeio.Packet#write(byte[], int, int)
199      */
200     public int write(byte[] data, int offset, int length) {
201         int rc1 = first.write(data, offset, length);        
202         if( rc1==-1 ) {
203             int rc2 = last.write(data, offset, length);
204             return ( rc2==-1 ) ? -1 : rc2;
205         } else {
206             int rc2 = last.write(data, offset+rc1, length-rc1);
207             return ( rc2==-1 ) ? rc1 : rc1+rc2;
208         }
209     }
210 
211     public int read(Packet dest) {        
212 	    int rc = first.read(dest);
213 	    rc += last.read(dest);
214 	    return rc;
215     }    
216     
217     public String toString() {
218         return "{position="+position()+",limit="+limit()+",capacity="+capacity()+"}";
219     }
220 
221     public Object narrow(Class target) {
222         if( target.isAssignableFrom(getClass()) ) {
223             return this;
224         }
225         Object object = first.narrow(target);
226         if( object == null )
227             object = last.narrow(target);
228         return object;
229     }
230 
231     public ByteSequence asByteSequence() {      
232         // TODO: implement me
233         return null;
234     }
235 
236     public byte[] sliceAsBytes() {
237         // TODO: implement me
238         return null;
239     }
240 
241     public void dispose() {
242         first.dispose();
243         last.dispose();
244     }
245 
246 }