001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.internal;
022:
023: import java.io.*;
024:
025: import com.db4o.*;
026: import com.db4o.ext.*;
027: import com.db4o.types.*;
028:
029: /**
030: * Transfer of blobs to and from the db4o system,
031: * if users use the Blob Db4oType.
032: *
033: * @moveto com.db4o.internal.blobs
034: * @exclude
035: */
036: public class BlobImpl implements Blob, Cloneable, Db4oTypeImpl {
037:
038: public final static int COPYBUFFER_LENGTH = 4096;
039:
040: public String fileName;
041: public String i_ext;
042: private transient File i_file;
043: private transient BlobStatus i_getStatusFrom;
044: public int i_length;
045: private transient double i_status = Status.UNUSED;
046: private transient ObjectContainerBase i_stream;
047: private transient Transaction i_trans;
048:
049: public int adjustReadDepth(int a_depth) {
050: return 1;
051: }
052:
053: public boolean canBind() {
054: return true;
055: }
056:
057: private String checkExt(File file) {
058: String name = file.getName();
059: int pos = name.lastIndexOf(".");
060: if (pos > 0) {
061: i_ext = name.substring(pos);
062: return name.substring(0, pos);
063: }
064:
065: i_ext = "";
066: return name;
067:
068: }
069:
070: private void copy(File from, File to) throws IOException {
071: to.delete();
072: BufferedInputStream in = new BufferedInputStream(
073: new FileInputStream(from));
074: try {
075: BufferedOutputStream out = new BufferedOutputStream(
076: new FileOutputStream(to));
077: try {
078: byte[] buffer = new byte[COPYBUFFER_LENGTH];
079: int bytesread = -1;
080: while ((bytesread = in.read(buffer)) >= 0) {
081: out.write(buffer, 0, bytesread);
082: }
083: out.flush();
084: } finally {
085: out.close();
086: }
087: } finally {
088: in.close();
089: }
090: }
091:
092: public Object createDefault(Transaction a_trans) {
093: BlobImpl bi = null;
094: try {
095: bi = (BlobImpl) this .clone();
096: bi.setTrans(a_trans);
097: } catch (CloneNotSupportedException e) {
098: return null;
099: }
100: return bi;
101: }
102:
103: public FileInputStream getClientInputStream() throws Exception {
104: return new FileInputStream(i_file);
105: }
106:
107: public FileOutputStream getClientOutputStream() throws Exception {
108: return new FileOutputStream(i_file);
109: }
110:
111: public String getFileName() {
112: return fileName;
113: }
114:
115: public int getLength() {
116: return i_length;
117: }
118:
119: public double getStatus() {
120: if (i_status == Status.PROCESSING && i_getStatusFrom != null) {
121: return i_getStatusFrom.getStatus();
122: }
123: if (i_status == Status.UNUSED) {
124: if (i_length > 0) {
125: i_status = Status.AVAILABLE;
126: }
127: }
128: return i_status;
129: }
130:
131: public void getStatusFrom(BlobStatus from) {
132: i_getStatusFrom = from;
133: }
134:
135: public boolean hasClassIndex() {
136: return false;
137: }
138:
139: public void readFrom(File file) throws IOException {
140: if (!file.exists()) {
141: throw new IOException(Messages.get(41, file
142: .getAbsolutePath()));
143: }
144: i_length = (int) file.length();
145: checkExt(file);
146: if (i_stream.isClient()) {
147: i_file = file;
148: ((BlobTransport) i_stream)
149: .readBlobFrom(i_trans, this , file);
150: } else {
151: readLocal(file);
152: }
153: }
154:
155: public void readLocal(File file) throws IOException {
156: boolean copied = false;
157: if (fileName == null) {
158: File newFile = new File(serverPath(), file.getName());
159: if (!newFile.exists()) {
160: copy(file, newFile);
161: copied = true;
162: fileName = newFile.getName();
163: }
164: }
165: if (!copied) {
166: copy(file, serverFile(checkExt(file), true));
167: }
168: synchronized (i_stream._lock) {
169: i_stream.setInternal(i_trans, this , false);
170: }
171: i_status = Status.COMPLETED;
172: }
173:
174: public void preDeactivate() {
175: // do nothing
176: }
177:
178: public File serverFile(String promptName, boolean writeToServer)
179: throws IOException {
180: synchronized (i_stream._lock) {
181: i_stream.activate(i_trans, this , 2);
182: }
183: String path = serverPath();
184: i_stream.configImpl().ensureDirExists(path);
185: if (writeToServer) {
186: if (fileName == null) {
187: if (promptName != null) {
188: fileName = promptName;
189: } else {
190: fileName = "b_" + System.currentTimeMillis();
191: }
192: String tryPath = fileName + i_ext;
193: int i = 0;
194: while (new File(path, tryPath).exists()) {
195: tryPath = fileName + "_" + i++ + i_ext;
196: if (i == 99) {
197: // should never happen
198: i_status = Status.ERROR;
199: throw new IOException(Messages.get(40));
200: }
201: }
202: fileName = tryPath;
203: synchronized (i_stream._lock) {
204: i_stream.setInternal(i_trans, this , false);
205: }
206: }
207: } else {
208: if (fileName == null) {
209: throw new IOException(Messages.get(38));
210: }
211: }
212: String lastTryPath = path + File.separator + fileName;
213: if (!writeToServer) {
214: if (!(new File(lastTryPath).exists())) {
215: throw new IOException(Messages.get(39));
216: }
217: }
218: return new File(lastTryPath);
219: }
220:
221: private String serverPath() throws IOException {
222: String path = i_stream.configImpl().blobPath();
223: if (path == null) {
224: path = "blobs";
225: }
226: i_stream.configImpl().ensureDirExists(path);
227: return path;
228: }
229:
230: public void setStatus(double status) {
231: i_status = status;
232: }
233:
234: public void setTrans(Transaction a_trans) {
235: i_trans = a_trans;
236: i_stream = a_trans.container();
237: }
238:
239: public void writeLocal(File file) throws IOException {
240: copy(serverFile(null, false), file);
241: i_status = Status.COMPLETED;
242: }
243:
244: public void writeTo(File file) throws IOException {
245: if (getStatus() == Status.UNUSED) {
246: throw new IOException(Messages.get(43));
247: }
248: if (i_stream.isClient()) {
249: i_file = file;
250: i_status = Status.QUEUED;
251: ((BlobTransport) i_stream).writeBlobTo(i_trans, this , file);
252: } else {
253: writeLocal(file);
254: }
255: }
256:
257: public void replicateFrom(Object obj) {
258: // do nothing
259: }
260:
261: public Object storedTo(Transaction a_trans) {
262: return this ;
263: }
264:
265: public void setObjectReference(ObjectReference a_yapObject) {
266: // not necessary
267: }
268:
269: public void deleteFile() throws IOException {
270: if (getStatus() == Status.UNUSED) {
271: throw new IOException(Messages.get(43));
272: }
273: if (i_stream.isClient()) {
274: ((BlobTransport) i_stream).deleteBlobFile(i_trans, this );
275: } else {
276: serverFile(null, false).delete();
277: }
278: fileName = null;
279: i_ext = null;
280: i_length = 0;
281: setStatus(Status.UNUSED);
282: synchronized (i_stream._lock) {
283: i_stream.setInternal(i_trans, this , false);
284: }
285: }
286:
287: }
|