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