001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdo;
012:
013: import java.io.IOException;
014: import java.io.File;
015: import java.io.FileOutputStream;
016: import java.io.OutputStream;
017:
018: /**
019: * File that rolls over to backups at a configurable max size. Parts of this
020: * file have been cut and pasted from org.apache.log4j.RollingFileAppender.
021: * @keep-all
022: */
023: public class RollingFile {
024:
025: private String filename;
026: private long maxSize = 1024 * 1024;
027: private int maxBackupIndex = 1;
028: private boolean append;
029: private CountingOutputStream out;
030: private boolean firstOpen = true;
031:
032: public RollingFile(String filename) {
033: this .filename = filename;
034: }
035:
036: public String getFilename() {
037: return filename;
038: }
039:
040: public void setFilename(String filename) {
041: this .filename = filename;
042: }
043:
044: public long getMaxSize() {
045: return maxSize;
046: }
047:
048: public void setMaxSize(long maxSize) {
049: this .maxSize = maxSize;
050: }
051:
052: public int getMaxBackupIndex() {
053: return maxBackupIndex;
054: }
055:
056: public void setMaxBackupIndex(int maxBackupIndex) {
057: this .maxBackupIndex = maxBackupIndex;
058: }
059:
060: public boolean isAppend() {
061: return append;
062: }
063:
064: public void setAppend(boolean append) {
065: this .append = append;
066: }
067:
068: /**
069: * Open our file. This will close any existing file.
070: */
071: public void open() throws IOException {
072: close();
073: if (firstOpen) {
074: firstOpen = false;
075: if (!append) { // nuke old backups
076: for (int i = 1; i <= maxBackupIndex; i++) {
077: File file = new File(filename + "." + i);
078: if (file.exists())
079: file.delete();
080: }
081: }
082: }
083: out = new CountingOutputStream(new FileOutputStream(filename,
084: append));
085: if (append)
086: out.setCount(new File(filename).length());
087: }
088:
089: /**
090: * Close our file.
091: */
092: public void close() throws IOException {
093: if (out != null)
094: out.close();
095: }
096:
097: /**
098: * Get the stream that writes to our file.
099: */
100: public OutputStream getOut() throws IOException {
101: if (out == null)
102: open();
103: return out;
104: }
105:
106: /**
107: * Is a rollover required? This should be called after writes to out. We
108: * cannot rollover automatically as out will typically be wrapped by
109: * other streams.
110: */
111: public boolean isRolloverRequired() {
112: return out.getCount() > maxSize;
113: }
114:
115: /**
116: * Perform a rollover to a new file.
117: */
118: public void rollover() throws IOException {
119: File target, file;
120:
121: // If maxBackups <= 0, then there is no file renaming to be done.
122: if (maxBackupIndex > 0) {
123: // Delete the oldest file, to keep Windows happy.
124: file = new File(filename + '.' + maxBackupIndex);
125: if (file.exists())
126: file.delete();
127:
128: // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
129: for (int i = maxBackupIndex - 1; i >= 1; i--) {
130: file = new File(filename + "." + i);
131: if (file.exists()) {
132: target = new File(filename + '.' + (i + 1));
133: file.renameTo(target);
134: }
135: }
136:
137: // Rename filename to filename.1
138: target = new File(filename + "." + 1);
139:
140: out.close();
141:
142: file = new File(filename);
143: file.renameTo(target);
144: }
145: open();
146: }
147:
148: /**
149: * OutputStream that counts bytes written to another stream.
150: */
151: public static class CountingOutputStream extends OutputStream {
152:
153: private OutputStream out;
154: private long count;
155:
156: public CountingOutputStream(OutputStream out) {
157: this .out = out;
158: }
159:
160: /**
161: * Get number of bytes written so far.
162: */
163: public long getCount() {
164: return count;
165: }
166:
167: public void setCount(long count) {
168: this .count = count;
169: }
170:
171: public void write(int b) throws IOException {
172: ++count;
173: out.write(b);
174: }
175:
176: public void write(byte b[]) throws IOException {
177: count += b.length;
178: out.write(b);
179: }
180:
181: public void write(byte b[], int off, int len)
182: throws IOException {
183: count += len;
184: out.write(b, off, len);
185: }
186:
187: public void flush() throws IOException {
188: out.flush();
189: }
190:
191: public void close() throws IOException {
192: out.close();
193: }
194: }
195:
196: }
|