Source code: org/activemq/io/util/DataContainer.java
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.activemq.io.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.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.deactivate();
115 writeBlock = createDataBlock(sequence++);
116 dataBlocks.add(writeBlock);
117 }
118 length += data.length;
119 size++;
120 writeBlock.write(data);
121 }
122
123 /**
124 * read a block of data from the container
125 *
126 * @return next data entry to read
127 * @throws IOException
128 */
129 public byte[] read() throws IOException {
130 byte[] result = null;
131 if (readBlock != null) {
132 result = readBlock.read();
133 if (result == null) {
134 if (readBlock != writeBlock) {
135 readBlock.close();
136 dataBlocks.remove(readBlock);
137 readBlock = (FileDataBlock) dataBlocks.get(0);
138 readBlock.activate();
139 }
140 }
141 else {
142 length -= result.length;
143 size--;
144 }
145 }
146 return result;
147 }
148
149 /**
150 * close the DataContainer and corresponding FileDataBlocks
151 *
152 * @throws IOException
153 */
154 public void close() throws IOException {
155 for (int i = 0;i < dataBlocks.size();i++) {
156 FileDataBlock db = (FileDataBlock) dataBlocks.get(i);
157 db.close();
158 }
159 dataBlocks.clear();
160 readBlock = null;
161 writeBlock = null;
162 size = 0;
163 length = 0l;
164 }
165
166 /**
167 * create a FileDataBlock
168 *
169 * @param sequence
170 * @return a new FileDataBlock
171 * @throws IOException
172 */
173 private FileDataBlock createDataBlock(int sequence) throws IOException {
174 String fileName = name + "_" + sequence + SUFFIX;
175 if (!dir.exists()){
176 log.info("making directory for temporary spooled data: " + dir);
177 dir.mkdirs();
178 }
179 File file = File.createTempFile(name, SUFFIX, dir);
180 file.deleteOnExit();
181 return new FileDataBlock(file, maxBlockSize);
182 }
183 }