1 /***
2 *
3 * Copyright 2004 Protique Ltd
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of 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,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18
19 package org.codehaus.activemq.message.util;
20 import java.io.File;
21 import java.io.FileFilter;
22 import java.io.IOException;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;
26
27 /***
28 * A DataContainer handles file persistence for a DiskBoundedQueue
29 * The DataContainer is a temporary data structure, that is only
30 * designed to exist for the lifetime of the application
31 *
32 * @version $Revision: 1.1 $
33 */
34 class DataContainer {
35 private CopyOnWriteArrayList dataBlocks = new CopyOnWriteArrayList();
36 private FileDataBlock writeBlock;
37 private FileDataBlock readBlock;
38 private File dir;
39 private long length;
40 private int size;
41 private String name;
42 private int maxBlockSize;
43 private int sequence;
44 private static final String SUFFIX = ".fdb";
45 private static final Log log = LogFactory.getLog(DataContainer.class);
46
47 /***
48 * Constructor for the data container
49 *
50 * @param dir directory where to create the data blocks
51 * @param name for the data block names
52 * @param maxBlockSize maximum size (in bytes) of the data blocks
53 * @throws IOException
54 */
55 DataContainer(File dir, String name, int maxBlockSize) throws IOException {
56 this.dir = dir;
57 this.name = name;
58 this.maxBlockSize = maxBlockSize;
59 }
60
61 /***
62 * Delete all previous files of the same suffix in the directory
63 */
64 void deleteAll() {
65 FileFilter filter = new FileFilter() {
66 public boolean accept(File file) {
67 return (file.getName().endsWith(SUFFIX) && file.getName().startsWith(name));
68 }
69 };
70 File[] files = dir.listFiles(filter);
71 if (files != null) {
72 for (int i = 0;i < files.length;i++) {
73 files[i].delete();
74 }
75 }
76 }
77
78
79
80 /***
81 * @return true if this DataContainer is empty
82 */
83 public synchronized boolean isEmpty() {
84 return size == 0;
85 }
86
87 /***
88 * @return the length (in bytes) of unread data in the DataContainer
89 */
90 public long length() {
91 return length;
92 }
93
94 /***
95 * @return the number of data entries unread
96 */
97 public int size() {
98 return size;
99 }
100
101 /***
102 * write a block of data into the Container
103 *
104 * @param data
105 * @throws IOException
106 */
107 public synchronized void write(byte[] data) throws IOException {
108 if (writeBlock == null) {
109 writeBlock = createDataBlock(sequence++);
110 dataBlocks.add(writeBlock);
111 readBlock = writeBlock;
112 }
113 else if (!writeBlock.isEnoughSpace(data)) {
114 writeBlock = createDataBlock(sequence++);
115 dataBlocks.add(writeBlock);
116 }
117 length += data.length;
118 size++;
119 writeBlock.write(data);
120 }
121
122 /***
123 * read a block of data from the container
124 *
125 * @return next data entry to read
126 * @throws IOException
127 */
128 public byte[] read() throws IOException {
129 byte[] result = null;
130 if (readBlock != null) {
131 result = readBlock.read();
132 if (result == null) {
133 if (readBlock != writeBlock) {
134 readBlock.close();
135 dataBlocks.remove(readBlock);
136 readBlock = (FileDataBlock) dataBlocks.get(0);
137 }
138 }
139 else {
140 length -= result.length;
141 size--;
142 }
143 }
144 return result;
145 }
146
147 /***
148 * close the DataContainer and corresponding FileDataBlocks
149 *
150 * @throws IOException
151 */
152 public void close() throws IOException {
153 for (int i = 0;i < dataBlocks.size();i++) {
154 FileDataBlock db = (FileDataBlock) dataBlocks.get(i);
155 db.close();
156 }
157 dataBlocks.clear();
158 readBlock = null;
159 writeBlock = null;
160 size = 0;
161 length = 0l;
162 }
163
164 /***
165 * create a FileDataBlock
166 *
167 * @param sequence
168 * @return a new FileDataBlock
169 * @throws IOException
170 */
171 private FileDataBlock createDataBlock(int sequence) throws IOException {
172 String fileName = name + "_" + sequence + SUFFIX;
173
174 File file = File.createTempFile(name, SUFFIX, dir);
175 file.deleteOnExit();
176 return new FileDataBlock(file, maxBlockSize);
177 }
178 }