View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.io;
15  
16  import java.io.IOException;
17  import java.io.InputStream;
18  import java.io.OutputStream;
19  
20  import org.eclipse.jetty.util.TypeUtil;
21  import org.eclipse.jetty.util.log.Log;
22  import org.eclipse.jetty.util.log.Logger;
23  
24  /**
25   * 
26   *  
27   */
28  public abstract class AbstractBuffer implements Buffer
29  {
30      private static final Logger LOG = Log.getLogger(AbstractBuffer.class);
31  
32      private final static boolean __boundsChecking = Boolean.getBoolean("org.eclipse.jetty.io.AbstractBuffer.boundsChecking");
33      
34      protected final static String 
35      __IMMUTABLE = "IMMUTABLE", 
36      __READONLY = "READONLY",
37      __READWRITE = "READWRITE", 
38      __VOLATILE = "VOLATILE";
39      
40      protected int _access;
41      protected boolean _volatile;
42  
43      protected int _get;
44      protected int _put;
45      protected int _hash;
46      protected int _hashGet;
47      protected int _hashPut;
48      protected int _mark;
49      protected String _string;
50      protected View _view;
51  
52      /**
53       * Constructor for BufferView
54       * 
55       * @param access 0==IMMUTABLE, 1==READONLY, 2==READWRITE
56       */
57      public AbstractBuffer(int access, boolean isVolatile)
58      {
59          if (access == IMMUTABLE && isVolatile)
60                  throw new IllegalArgumentException("IMMUTABLE && VOLATILE");
61          setMarkIndex(-1);
62          _access = access;
63          _volatile = isVolatile;
64      }
65  
66      /*
67       * @see org.eclipse.io.Buffer#toArray()
68       */
69      public byte[] asArray()
70      {
71          byte[] bytes = new byte[length()];
72          byte[] array = array();
73          if (array != null)
74              System.arraycopy(array, getIndex(), bytes, 0, bytes.length);
75          else
76              peek(getIndex(), bytes, 0, length());
77          return bytes;
78      }
79  
80      public ByteArrayBuffer duplicate(int access)
81      {
82          Buffer b=this.buffer();
83          if (this instanceof Buffer.CaseInsensitve || b instanceof Buffer.CaseInsensitve)
84              return new ByteArrayBuffer.CaseInsensitive(asArray(), 0, length(),access);
85          else
86              return new ByteArrayBuffer(asArray(), 0, length(), access);
87      }
88      
89      /*
90       * @see org.eclipse.io.Buffer#asNonVolatile()
91       */
92      public Buffer asNonVolatileBuffer()
93      {
94          if (!isVolatile()) return this;
95          return duplicate(_access);
96      }
97  
98      public Buffer asImmutableBuffer()
99      {
100         if (isImmutable()) return this;
101         return duplicate(IMMUTABLE);
102     }
103 
104     /*
105      * @see org.eclipse.util.Buffer#asReadOnlyBuffer()
106      */
107     public Buffer asReadOnlyBuffer()
108     {
109         if (isReadOnly()) return this;
110         return new View(this, markIndex(), getIndex(), putIndex(), READONLY);
111     }
112 
113     public Buffer asMutableBuffer()
114     {
115         if (!isImmutable()) return this;
116         
117         Buffer b=this.buffer();
118         if (b.isReadOnly())
119         {
120             return duplicate(READWRITE);
121         }
122         return new View(b, markIndex(), getIndex(), putIndex(), _access);
123     }
124 
125     public Buffer buffer()
126     {
127         return this;
128     }
129 
130     public void clear()
131     {
132         setMarkIndex(-1);
133         setGetIndex(0);
134         setPutIndex(0);
135     }
136 
137     public void compact()
138     {
139         if (isReadOnly()) throw new IllegalStateException(__READONLY);
140         int s = markIndex() >= 0 ? markIndex() : getIndex();
141         if (s > 0)
142         {
143             byte array[] = array();
144             int length = putIndex() - s;
145             if (length > 0)
146             {
147                 if (array != null)
148                     System.arraycopy(array(), s, array(), 0, length);
149                 else
150                     poke(0, peek(s, length));
151             }
152             if (markIndex() > 0) setMarkIndex(markIndex() - s);
153             setGetIndex(getIndex() - s);
154             setPutIndex(putIndex() - s);
155         }
156     }
157 
158     @Override
159     public boolean equals(Object obj)
160     {
161         if (obj==this)
162             return true;
163         
164         // reject non buffers;
165         if (obj == null || !(obj instanceof Buffer)) return false;
166         Buffer b = (Buffer) obj;
167 
168         if (this instanceof Buffer.CaseInsensitve ||  b instanceof Buffer.CaseInsensitve)
169             return equalsIgnoreCase(b);
170         
171         // reject different lengths
172         if (b.length() != length()) return false;
173 
174         // reject AbstractBuffer with different hash value
175         if (_hash != 0 && obj instanceof AbstractBuffer)
176         {
177             AbstractBuffer ab = (AbstractBuffer) obj;
178             if (ab._hash != 0 && _hash != ab._hash) return false;
179         }
180 
181         // Nothing for it but to do the hard grind.
182         int get=getIndex();
183         int bi=b.putIndex();
184         for (int i = putIndex(); i-->get;)
185         {
186             byte b1 = peek(i);
187             byte b2 = b.peek(--bi);
188             if (b1 != b2) return false;
189         }
190         return true;
191     }
192 
193     public boolean equalsIgnoreCase(Buffer b)
194     {
195         if (b==this)
196             return true;
197         
198         // reject different lengths
199         if (b.length() != length()) return false;
200 
201         // reject AbstractBuffer with different hash value
202         if (_hash != 0 && b instanceof AbstractBuffer)
203         {
204             AbstractBuffer ab = (AbstractBuffer) b;
205             if (ab._hash != 0 && _hash != ab._hash) return false;
206         }
207 
208         // Nothing for it but to do the hard grind.
209         int get=getIndex();
210         int bi=b.putIndex();
211         
212         byte[] array = array();
213         byte[] barray= b.array();
214         if (array!=null && barray!=null)
215         {
216             for (int i = putIndex(); i-->get;)
217             {
218                 byte b1 = array[i];
219                 byte b2 = barray[--bi];
220                 if (b1 != b2)
221                 {
222                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
223                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
224                     if (b1 != b2) return false;
225                 }
226             }
227         }
228         else
229         {
230             for (int i = putIndex(); i-->get;)
231             {
232                 byte b1 = peek(i);
233                 byte b2 = b.peek(--bi);
234                 if (b1 != b2)
235                 {
236                     if ('a' <= b1 && b1 <= 'z') b1 = (byte) (b1 - 'a' + 'A');
237                     if ('a' <= b2 && b2 <= 'z') b2 = (byte) (b2 - 'a' + 'A');
238                     if (b1 != b2) return false;
239                 }
240             }
241         }
242         return true;
243     }
244 
245     public byte get()
246     {
247         return peek(_get++);
248     }
249 
250     public int get(byte[] b, int offset, int length)
251     {
252         int gi = getIndex();
253         int l=length();
254         if (l==0)
255             return -1;
256         
257         if (length>l)
258             length=l;
259         
260         length = peek(gi, b, offset, length);
261         if (length>0)
262             setGetIndex(gi + length);
263         return length;
264     }
265 
266     public Buffer get(int length)
267     {
268         int gi = getIndex();
269         Buffer view = peek(gi, length);
270         setGetIndex(gi + length);
271         return view;
272     }
273 
274     public final int getIndex()
275     {
276         return _get;
277     }
278 
279     public boolean hasContent()
280     {
281         return _put > _get;
282     }
283     
284     @Override
285     public int hashCode()
286     {
287         if (_hash == 0 || _hashGet!=_get || _hashPut!=_put) 
288         {
289             int get=getIndex();
290             byte[] array = array();
291             if (array==null)
292             {
293                 for (int i = putIndex(); i-- >get;)
294                 {
295                     byte b = peek(i);
296                     if ('a' <= b && b <= 'z') 
297                         b = (byte) (b - 'a' + 'A');
298                     _hash = 31 * _hash + b;
299                 }
300             }
301             else
302             {
303                 for (int i = putIndex(); i-- >get;)
304                 {
305                     byte b = array[i];
306                     if ('a' <= b && b <= 'z') 
307                         b = (byte) (b - 'a' + 'A');
308                     _hash = 31 * _hash + b;
309                 }
310             }
311             if (_hash == 0) 
312                 _hash = -1;
313             _hashGet=_get;
314             _hashPut=_put;
315             
316         }
317         return _hash;
318     }
319 
320     public boolean isImmutable()
321     {
322         return _access <= IMMUTABLE;
323     }
324 
325     public boolean isReadOnly()
326     {
327         return _access <= READONLY;
328     }
329 
330     public boolean isVolatile()
331     {
332         return _volatile;
333     }
334 
335     public int length()
336     {
337         return _put - _get;
338     }
339 
340     public void mark()
341     {
342         setMarkIndex(_get - 1);
343     }
344 
345     public void mark(int offset)
346     {
347         setMarkIndex(_get + offset);
348     }
349 
350     public int markIndex()
351     {
352         return _mark;
353     }
354 
355     public byte peek()
356     {
357         return peek(_get);
358     }
359 
360     public Buffer peek(int index, int length)
361     {
362         if (_view == null)
363         {
364             _view = new View(this, -1, index, index + length, isReadOnly() ? READONLY : READWRITE);
365         }
366         else
367         {
368             _view.update(this.buffer());
369             _view.setMarkIndex(-1);
370             _view.setGetIndex(0);
371             _view.setPutIndex(index + length);
372             _view.setGetIndex(index);
373             
374         }
375         return _view;
376     }
377 
378     public int poke(int index, Buffer src)
379     {
380         _hash=0;
381         /* 
382         if (isReadOnly()) 
383             throw new IllegalStateException(__READONLY);
384         if (index < 0) 
385             throw new IllegalArgumentException("index<0: " + index + "<0");
386         */
387         
388         int length=src.length();
389         if (index + length > capacity())
390         {
391             length=capacity()-index;
392             /*
393             if (length<0)
394                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
395             */
396         }
397         
398         byte[] src_array = src.array();
399         byte[] dst_array = array();
400         if (src_array != null && dst_array != null)
401             System.arraycopy(src_array, src.getIndex(), dst_array, index, length);
402         else if (src_array != null)
403         {
404             int s=src.getIndex();
405             for (int i=0;i<length;i++)
406                 poke(index++,src_array[s++]);
407         }
408         else if (dst_array != null)
409         {
410             int s=src.getIndex();
411             for (int i=0;i<length;i++)
412                 dst_array[index++]=src.peek(s++);
413         }
414         else
415         {
416             int s=src.getIndex();
417             for (int i=0;i<length;i++)
418                 poke(index++,src.peek(s++));
419         }
420         
421         return length;
422     }
423     
424 
425     public int poke(int index, byte[] b, int offset, int length)
426     {
427         _hash=0;
428         /*
429         if (isReadOnly()) 
430             throw new IllegalStateException(__READONLY);
431         if (index < 0) 
432             throw new IllegalArgumentException("index<0: " + index + "<0");
433         */
434         if (index + length > capacity())
435         {
436             length=capacity()-index;
437             /* if (length<0)
438                 throw new IllegalArgumentException("index>capacity(): " + index + ">" + capacity());
439             */
440         }
441         
442         byte[] dst_array = array();
443         if (dst_array != null)
444             System.arraycopy(b, offset, dst_array, index, length);
445         else
446         {
447             int s=offset;
448             for (int i=0;i<length;i++)
449                 poke(index++,b[s++]);
450         }
451         return length;
452     }
453 
454     public int put(Buffer src)
455     {
456         int pi = putIndex();
457         int l=poke(pi, src);
458         setPutIndex(pi + l);
459         return l;
460     }
461 
462     public void put(byte b)
463     {
464         int pi = putIndex();
465         poke(pi, b);
466         setPutIndex(pi + 1);
467     }
468 
469     public int put(byte[] b, int offset, int length)
470     {
471         int pi = putIndex();
472         int l = poke(pi, b, offset, length);
473         setPutIndex(pi + l);
474         return l;
475     }
476     
477     public int put(byte[] b)
478     {
479         int pi = putIndex();
480         int l = poke(pi, b, 0, b.length);
481         setPutIndex(pi + l);
482         return l;
483     }
484 
485     public final int putIndex()
486     {
487         return _put;
488     }
489 
490     public void reset()
491     {
492         if (markIndex() >= 0) setGetIndex(markIndex());
493     }
494 
495     public void rewind()
496     {
497         setGetIndex(0);
498         setMarkIndex(-1);
499     }
500 
501     public void setGetIndex(int getIndex)
502     {
503         /* bounds checking
504         if (isImmutable()) 
505             throw new IllegalStateException(__IMMUTABLE);
506         if (getIndex < 0)
507             throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0");
508         if (getIndex > putIndex())
509             throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex());
510          */
511         _get = getIndex;
512         _hash=0;
513     }
514 
515     public void setMarkIndex(int index)
516     {
517         /*
518         if (index>=0 && isImmutable()) 
519             throw new IllegalStateException(__IMMUTABLE);
520         */
521         _mark = index;
522     }
523 
524     public void setPutIndex(int putIndex)
525     {
526         /* bounds checking
527         if (isImmutable()) 
528             throw new IllegalStateException(__IMMUTABLE);
529         if (putIndex > capacity())
530                 throw new IllegalArgumentException("putIndex>capacity: " + putIndex + ">" + capacity());
531         if (getIndex() > putIndex)
532                 throw new IllegalArgumentException("getIndex>putIndex: " + getIndex() + ">" + putIndex);
533          */
534         _put = putIndex;
535         _hash=0;
536     }
537 
538     public int skip(int n)
539     {
540         if (length() < n) n = length();
541         setGetIndex(getIndex() + n);
542         return n;
543     }
544 
545     public Buffer slice()
546     {
547         return peek(getIndex(), length());
548     }
549 
550     public Buffer sliceFromMark()
551     {
552         return sliceFromMark(getIndex() - markIndex() - 1);
553     }
554 
555     public Buffer sliceFromMark(int length)
556     {
557         if (markIndex() < 0) return null;
558         Buffer view = peek(markIndex(), length);
559         setMarkIndex(-1);
560         return view;
561     }
562 
563     public int space()
564     {
565         return capacity() - _put;
566     }
567 
568     public String toDetailString()
569     {
570         StringBuilder buf = new StringBuilder();
571         buf.append("[");
572         buf.append(super.hashCode());
573         buf.append(",");
574         buf.append(this.buffer().hashCode());
575         buf.append(",m=");
576         buf.append(markIndex());
577         buf.append(",g=");
578         buf.append(getIndex());
579         buf.append(",p=");
580         buf.append(putIndex());
581         buf.append(",c=");
582         buf.append(capacity());
583         buf.append("]={");
584         if (markIndex() >= 0)
585         {
586             for (int i = markIndex(); i < getIndex(); i++)
587             {
588                 byte b =  peek(i);
589                 TypeUtil.toHex(b,buf);
590             }
591             buf.append("}{");
592         }
593         int count = 0;
594         for (int i = getIndex(); i < putIndex(); i++)
595         {
596             byte b =  peek(i);
597             TypeUtil.toHex(b,buf);
598             if (count++ == 50)
599             {
600                 if (putIndex() - i > 20)
601                 {
602                     buf.append(" ... ");
603                     i = putIndex() - 20;
604                 }
605             }
606         }
607         buf.append('}');
608         return buf.toString();
609     }
610 
611     /* ------------------------------------------------------------ */
612     @Override
613     public String toString()
614     {
615         if (isImmutable())
616         {
617             if (_string == null) 
618                 _string = new String(asArray(), 0, length());
619             return _string;
620         }
621         return new String(asArray(), 0, length());
622     }
623 
624     /* ------------------------------------------------------------ */
625     public String toString(String charset)
626     {
627         try
628         {
629             byte[] bytes=array();
630             if (bytes!=null)
631                 return new String(bytes,getIndex(),length(),charset);
632             return new String(asArray(), 0, length(),charset);
633             
634         }
635         catch(Exception e)
636         {
637             LOG.warn(e);
638             return new String(asArray(), 0, length());
639         }
640     }
641 
642     /* ------------------------------------------------------------ */
643     public String toDebugString()
644     {
645         return getClass()+"@"+super.hashCode();
646     }
647 
648     /* ------------------------------------------------------------ */
649     public void writeTo(OutputStream out)
650     	throws IOException
651     {
652         byte[] array = array();
653         
654         if (array!=null)
655         {
656             out.write(array,getIndex(),length());
657         }
658         else
659         {
660             int len = this.length();
661             byte[] buf=new byte[len>1024?1024:len];
662             int offset=_get;
663             while (len>0)
664             {
665                 int l=peek(offset,buf,0,len>buf.length?buf.length:len);
666                 out.write(buf,0,l);
667                 offset+=l;
668                 len-=l;
669             }
670         } 
671         clear();
672     }
673     
674     /* ------------------------------------------------------------ */
675     public int readFrom(InputStream in,int max) throws IOException
676     {
677         byte[] array = array();
678         int s=space();
679         if (s>max)
680             s=max;
681 
682         if (array!=null)
683         {
684             int l=in.read(array,_put,s);
685             if (l>0)
686                 _put+=l;
687             return l;
688         }
689         else
690         {
691             byte[] buf=new byte[s>1024?1024:s];
692             int total=0;
693             while (s>0)
694             {
695                 int l=in.read(buf,0,buf.length);
696                 if (l<0)
697                     return total>0?total:-1;
698                 int p=put(buf,0,l);
699                 assert l==p;
700                 s-=l;
701             }
702             return total; 
703         }
704     }
705 }