~ubuntu-branches/ubuntu/saucy/apache-mime4j/saucy

« back to all changes in this revision

Viewing changes to src/main/java/org/apache/james/mime4j/storage/ThresholdStorageProvider.java

  • Committer: Bazaar Package Importer
  • Author(s): David Paleino
  • Date: 2010-07-13 09:28:28 UTC
  • Revision ID: james.westby@ubuntu.com-20100713092828-g6wafdtidgmtx7su
Tags: upstream-0.6
ImportĀ upstreamĀ versionĀ 0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.james.mime4j.storage;
 
21
 
 
22
import java.io.ByteArrayInputStream;
 
23
import java.io.IOException;
 
24
import java.io.InputStream;
 
25
import java.io.SequenceInputStream;
 
26
 
 
27
import org.apache.james.mime4j.util.ByteArrayBuffer;
 
28
 
 
29
/**
 
30
 * A {@link StorageProvider} that keeps small amounts of data in memory and
 
31
 * writes the remainder to another <code>StorageProvider</code> (the back-end)
 
32
 * if a certain threshold size gets exceeded.
 
33
 * <p>
 
34
 * Example usage:
 
35
 *
 
36
 * <pre>
 
37
 * StorageProvider tempStore = new TempFileStorageProvider();
 
38
 * StorageProvider provider = new ThresholdStorageProvider(tempStore, 4096);
 
39
 * DefaultStorageProvider.setInstance(provider);
 
40
 * </pre>
 
41
 */
 
42
public class ThresholdStorageProvider extends AbstractStorageProvider {
 
43
 
 
44
    private final StorageProvider backend;
 
45
    private final int thresholdSize;
 
46
 
 
47
    /**
 
48
     * Creates a new <code>ThresholdStorageProvider</code> for the given
 
49
     * back-end using a threshold size of 2048 bytes.
 
50
     */
 
51
    public ThresholdStorageProvider(StorageProvider backend) {
 
52
        this(backend, 2048);
 
53
    }
 
54
 
 
55
    /**
 
56
     * Creates a new <code>ThresholdStorageProvider</code> for the given
 
57
     * back-end and threshold size.
 
58
     *
 
59
     * @param backend
 
60
     *            used to store the remainder of the data if the threshold size
 
61
     *            gets exceeded.
 
62
     * @param thresholdSize
 
63
     *            determines how much bytes are kept in memory before that
 
64
     *            back-end storage provider is used to store the remainder of
 
65
     *            the data.
 
66
     */
 
67
    public ThresholdStorageProvider(StorageProvider backend, int thresholdSize) {
 
68
        if (backend == null)
 
69
            throw new IllegalArgumentException();
 
70
        if (thresholdSize < 1)
 
71
            throw new IllegalArgumentException();
 
72
 
 
73
        this.backend = backend;
 
74
        this.thresholdSize = thresholdSize;
 
75
    }
 
76
 
 
77
    public StorageOutputStream createStorageOutputStream() {
 
78
        return new ThresholdStorageOutputStream();
 
79
    }
 
80
 
 
81
    private final class ThresholdStorageOutputStream extends
 
82
            StorageOutputStream {
 
83
 
 
84
        private final ByteArrayBuffer head;
 
85
        private StorageOutputStream tail;
 
86
 
 
87
        public ThresholdStorageOutputStream() {
 
88
            final int bufferSize = Math.min(thresholdSize, 1024);
 
89
            head = new ByteArrayBuffer(bufferSize);
 
90
        }
 
91
 
 
92
        @Override
 
93
        public void close() throws IOException {
 
94
            super.close();
 
95
 
 
96
            if (tail != null)
 
97
                tail.close();
 
98
        }
 
99
 
 
100
        @Override
 
101
        protected void write0(byte[] buffer, int offset, int length)
 
102
                throws IOException {
 
103
            int remainingHeadSize = thresholdSize - head.length();
 
104
            if (remainingHeadSize > 0) {
 
105
                int n = Math.min(remainingHeadSize, length);
 
106
                head.append(buffer, offset, n);
 
107
                offset += n;
 
108
                length -= n;
 
109
            }
 
110
 
 
111
            if (length > 0) {
 
112
                if (tail == null)
 
113
                    tail = backend.createStorageOutputStream();
 
114
 
 
115
                tail.write(buffer, offset, length);
 
116
            }
 
117
        }
 
118
 
 
119
        @Override
 
120
        protected Storage toStorage0() throws IOException {
 
121
            if (tail == null)
 
122
                return new MemoryStorageProvider.MemoryStorage(head.buffer(),
 
123
                        head.length());
 
124
 
 
125
            return new ThresholdStorage(head.buffer(), head.length(), tail
 
126
                    .toStorage());
 
127
        }
 
128
 
 
129
    }
 
130
 
 
131
    private static final class ThresholdStorage implements Storage {
 
132
 
 
133
        private byte[] head;
 
134
        private final int headLen;
 
135
        private Storage tail;
 
136
 
 
137
        public ThresholdStorage(byte[] head, int headLen, Storage tail) {
 
138
            this.head = head;
 
139
            this.headLen = headLen;
 
140
            this.tail = tail;
 
141
        }
 
142
 
 
143
        public void delete() {
 
144
            if (head != null) {
 
145
                head = null;
 
146
                tail.delete();
 
147
                tail = null;
 
148
            }
 
149
        }
 
150
 
 
151
        public InputStream getInputStream() throws IOException {
 
152
            if (head == null)
 
153
                throw new IllegalStateException("storage has been deleted");
 
154
 
 
155
            InputStream headStream = new ByteArrayInputStream(head, 0, headLen);
 
156
            InputStream tailStream = tail.getInputStream();
 
157
            return new SequenceInputStream(headStream, tailStream);
 
158
        }
 
159
 
 
160
    }
 
161
}