/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.internal; import java.io.*; import com.db4o.*; import com.db4o.ext.*; import com.db4o.foundation.io.*; import com.db4o.internal.activation.*; import com.db4o.types.*; /** * Transfer of blobs to and from the db4o system, * if users use the Blob Db4oType. * * @moveto com.db4o.internal.blobs * @exclude * * @sharpen.if !SILVERLIGHT */ public class BlobImpl implements Blob, Cloneable, Db4oTypeImpl { public final static int COPYBUFFER_LENGTH=4096; public String fileName; public String i_ext; private transient File i_file; private transient BlobStatus i_getStatusFrom; public int i_length; private transient double i_status = Status.UNUSED; private transient ObjectContainerBase i_stream; private transient Transaction i_trans; /** * @param depth */ public int adjustReadDepth(int depth) { return 1; } private String checkExt(File file) { String name = file.getName(); int pos = name.lastIndexOf("."); if (pos > 0) { i_ext = name.substring(pos); return name.substring(0, pos); } i_ext = ""; return name; } private static void copy(File from, File to) throws IOException { File4.copyFile(from, to); } public Object createDefault(Transaction a_trans) { BlobImpl bi = null; try { bi = (BlobImpl) this.clone(); bi.setTrans(a_trans); } catch (CloneNotSupportedException e) { return null; } return bi; } public FileInputStream getClientInputStream() throws Exception { return new FileInputStream(i_file); } public FileOutputStream getClientOutputStream() throws Exception { return new FileOutputStream(i_file); } public String getFileName() { return fileName; } public int getLength() { return i_length; } public double getStatus() { if (i_status == Status.PROCESSING && i_getStatusFrom != null) { return i_getStatusFrom.getStatus(); } if (i_status == Status.UNUSED) { if (i_length > 0) { i_status = Status.AVAILABLE; } } return i_status; } public void getStatusFrom(BlobStatus from) { i_getStatusFrom = from; } public boolean hasClassIndex() { return false; } public void readFrom(File file) throws IOException { if (!file.exists()) { throw new IOException(Messages.get(41, file.getAbsolutePath())); } i_length = (int) file.length(); checkExt(file); if (i_stream.isClient()) { i_file = file; ((BlobTransport)i_stream).readBlobFrom(i_trans, this); } else { readLocal(file); } } public void readLocal(File file) throws IOException { boolean copied = false; if (fileName == null) { File newFile = new File(serverPath(), file.getName()); if (!newFile.exists()) { copy(file, newFile); copied = true; fileName = newFile.getName(); } } if (!copied) { copy(file, serverFile(checkExt(file), true)); } synchronized (i_stream.lock()) { i_stream.storeInternal(i_trans, this, false); } i_status = Status.COMPLETED; } public File serverFile(String promptName, boolean writeToServer) throws IOException { synchronized (i_stream.lock()) { i_stream.activate(i_trans, this, new FixedActivationDepth(2)); } String path = serverPath(); i_stream.configImpl().ensureDirExists(path); if (writeToServer) { if (fileName == null) { if (promptName != null) { fileName = promptName; } else { fileName = "b_" + System.currentTimeMillis(); } String tryPath = fileName + i_ext; int i = 0; while (new File(path, tryPath).exists()) { tryPath = fileName + "_" + i++ +i_ext; if (i == 99) { // should never happen i_status = Status.ERROR; throw new IOException(Messages.get(40)); } } fileName = tryPath; synchronized (i_stream.lock()) { i_stream.storeInternal(i_trans, this, false); } } } else { if (fileName == null) { throw new IOException(Messages.get(38)); } } String lastTryPath = path + File.separator + fileName; if (!writeToServer) { if (!(new File(lastTryPath).exists())) { throw new IOException(Messages.get(39)); } } return new File(lastTryPath); } private String serverPath() throws IOException { String path = i_stream.configImpl().blobPath(); if (path == null) { path = "blobs"; } i_stream.configImpl().ensureDirExists(path); return path; } public void setStatus(double status) { i_status = status; } public void setTrans(Transaction a_trans) { i_trans = a_trans; i_stream = a_trans.container(); } public void writeLocal(File file) throws IOException { copy(serverFile(null, false), file); i_status = Status.COMPLETED; } public void writeTo(File file) throws IOException { if (getStatus() == Status.UNUSED) { throw new IOException(Messages.get(43)); } if (i_stream.isClient()) { i_file = file; i_status = Status.QUEUED; ((BlobTransport)i_stream).writeBlobTo(i_trans, this); } else { writeLocal(file); } } public void setObjectReference(ObjectReference objectReference) { // not necessary } public void deleteFile() throws IOException { if (getStatus() == Status.UNUSED) { throw new IOException(Messages.get(43)); } if (i_stream.isClient()) { ((BlobTransport)i_stream).deleteBlobFile(i_trans, this); } else { serverFile(null, false).delete(); } fileName = null; i_ext = null; i_length = 0; setStatus(Status.UNUSED); synchronized (i_stream.lock()) { i_stream.storeInternal(i_trans, this, false); } } }