View Javadoc

1   /* RecyclingSerialBinding
2   *
3   * $Id: RecyclingSerialBinding.java 4667 2006-09-26 20:38:48Z paul_jack $
4   *
5   * Created on May 25, 2005
6   *
7   * Copyright (C) 2005 Internet Archive.
8   *
9   * This file is part of the Heritrix web crawler (crawler.archive.org).
10  *
11  * Heritrix is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * any later version.
15  *
16  * Heritrix is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser Public License
22  * along with Heritrix; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */ 
25  package org.archive.crawler.frontier;
26  
27  import java.io.IOException;
28  
29  import com.sleepycat.bind.serial.ClassCatalog;
30  import com.sleepycat.bind.serial.SerialBinding;
31  import com.sleepycat.bind.serial.SerialOutput;
32  import com.sleepycat.je.DatabaseEntry;
33  import com.sleepycat.util.FastOutputStream;
34  import com.sleepycat.util.RuntimeExceptionWrapper;
35  
36  /***
37   * A SerialBinding that recycles a single FastOutputStream per
38   * thread, avoiding reallocation of the internal buffer for 
39   * either repeated serializations or because of mid-serialization
40   * expansions. (Cached stream's buffer will quickly grow to a size 
41   * sufficient for all serialized instances.)
42   *
43   * @author gojomo
44   */
45  public class RecyclingSerialBinding extends SerialBinding {
46      /***
47       * Thread-local cache of reusable FastOutputStream
48       */
49      ThreadLocal<FastOutputStream> fastOutputStreamHolder
50       = new ThreadLocal<FastOutputStream>();
51      
52      private ClassCatalog classCatalog;
53      private Class baseClass;
54  
55      /***
56       * Constructor. Save parameters locally, as superclass 
57       * fields are private. 
58       * 
59       * @param classCatalog is the catalog to hold shared class information
60       *
61       * @param baseClass is the base class for serialized objects stored using
62       * this binding
63       */
64      public RecyclingSerialBinding(ClassCatalog classCatalog, Class baseClass) {
65          super(classCatalog, baseClass);
66          this.classCatalog = classCatalog;
67          this.baseClass = baseClass;
68      }
69  
70      /***
71       * Copies superclass simply to allow different source for FastOoutputStream.
72       * 
73       * @see com.sleepycat.bind.serial.SerialBinding#entryToObject
74       */
75      public void objectToEntry(Object object, DatabaseEntry entry) {
76  
77          if (baseClass != null && !baseClass.isInstance(object)) {
78              throw new IllegalArgumentException(
79                          "Data object class (" + object.getClass() +
80                          ") not an instance of binding's base class (" +
81                          baseClass + ')');
82          }
83          FastOutputStream fo = getFastOutputStream();
84          try {
85              SerialOutput jos = new SerialOutput(fo, classCatalog);
86              jos.writeObject(object);
87          } catch (IOException e) {
88              throw new RuntimeExceptionWrapper(e);
89          }
90  
91          byte[] hdr = SerialOutput.getStreamHeader();
92          entry.setData(fo.getBufferBytes(), hdr.length,
93                       fo.getBufferLength() - hdr.length);
94      }
95  
96      /***
97       * Get the cached (and likely pre-grown to efficient size) FastOutputStream,
98       * creating it if necessary. 
99       * 
100      * @return FastOutputStream
101      */
102     private FastOutputStream getFastOutputStream() {
103         FastOutputStream fo = (FastOutputStream) fastOutputStreamHolder.get();
104         if (fo == null) {
105             fo = new FastOutputStream();
106             fastOutputStreamHolder.set(fo);
107         }
108         fo.reset();
109         return fo;
110     }
111 }