/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.core.command.binary;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.xmind.core.internal.command.BinaryUtil;
import org.xmind.core.internal.command.XMindCommandPlugin;
public class BinaryStore implements IBinaryStore {
private Map<String, IBinaryEntry> entries = new HashMap<String, IBinaryEntry>();
private List<String> entryNames = new ArrayList<String>();
private File root;
private byte[] buffer = new byte[4096];
private int randomIndex = 1;
public BinaryStore(File root) {
this.root = root;
}
public BinaryStore(boolean useLocalFileCache) {
if (useLocalFileCache) {
File cacheDir = XMindCommandPlugin.getDefault()
.getBinaryCacheLocation();
String rootName = String.format("%s-%s", //$NON-NLS-1$
String.valueOf(System.currentTimeMillis()), String
.valueOf(new Random(System.currentTimeMillis())
.nextInt()));
this.root = new File(cacheDir, rootName);
} else {
this.root = null;
}
}
public BinaryStore() {
this(true);
}
public synchronized Iterator<String> entryNames() {
return this.entryNames.iterator();
}
public synchronized boolean isEmpty() {
return this.entries.isEmpty();
}
public synchronized int size() {
return this.entries.size();
}
public synchronized IBinaryEntry getEntry(String entryName) {
return this.entries.get(entryName);
}
public synchronized boolean hasEntry(String entryName) {
return this.entries.containsKey(entryName);
}
public synchronized void clear() {
Object[] oldEntries = this.entries.values().toArray();
this.entries.clear();
this.entryNames.clear();
for (int i = 0; i < oldEntries.length; i++) {
((IBinaryEntry) oldEntries[i]).dispose();
}
if (this.root != null) {
BinaryUtil.delete(this.root);
}
}
public synchronized boolean removeEntry(String entryName) {
IBinaryEntry entry = this.entries.remove(entryName);
if (entry != null) {
this.entryNames.remove(entryName);
entry.dispose();
}
return entry != null;
}
public synchronized INamedEntry addEntry(IProgressMonitor monitor,
InputStream source) throws IOException, InterruptedException {
String entryName = generateRandomEntryName();
IBinaryEntry realEntry = createEntry(monitor, entryName, source);
NamedEntry entry = new NamedEntry(entryName, realEntry);
addEntry(entryName, entry);
return entry;
}
protected String generateRandomEntryName() {
String entryName = Long.toHexString(System.currentTimeMillis()) + "-" //$NON-NLS-1$
+ (randomIndex++) + "-" //$NON-NLS-1$
+ Integer.toHexString(new Random().nextInt()) + ".tmp"; //$NON-NLS-1$
return entryName;
}
public synchronized IBinaryEntry addEntry(IProgressMonitor monitor,
String entryName, InputStream source) throws IOException,
InterruptedException {
IBinaryEntry entry = createEntry(monitor, entryName, source);
addEntry(entryName, entry);
return entry;
}
public synchronized void addEntry(String entryName, IBinaryEntry entry) {
removeEntry(entryName);
this.entries.put(entryName, entry);
this.entryNames.add(entryName);
}
protected IBinaryEntry createEntry(IProgressMonitor monitor,
String entryName, InputStream source) throws IOException,
InterruptedException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
if (monitor.isCanceled())
throw new InterruptedException();
if (this.root != null) {
this.root.mkdirs();
}
if (monitor.isCanceled())
throw new InterruptedException();
if (this.root != null && this.root.isDirectory()) {
if (entryName.endsWith("/")) { //$NON-NLS-1$
File file = new File(this.root, entryName.substring(0,
entryName.length() - 1));
if (monitor.isCanceled())
throw new InterruptedException();
file.mkdirs();
return IBinaryEntry.NULL;
} else {
File file = new File(this.root, entryName);
file.getParentFile().mkdirs();
if (monitor.isCanceled())
throw new InterruptedException();
try {
OutputStream fout = new FileOutputStream(file);
try {
int read;
while ((read = source.read(buffer)) > 0) {
if (monitor.isCanceled())
throw new InterruptedException();
fout.write(buffer, 0, read);
}
} finally {
fout.close();
}
} finally {
source.close();
}
if (monitor.isCanceled())
throw new InterruptedException();
return new FileEntry(file);
}
} else {
if (entryName.endsWith("/")) { //$NON-NLS-1$
return IBinaryEntry.NULL;
} else {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
try {
int read;
while ((read = source.read(buffer)) > 0) {
if (monitor.isCanceled())
throw new InterruptedException();
out.write(buffer, 0, read);
}
if (monitor.isCanceled())
throw new InterruptedException();
return new ByteArrayEntry(out.toByteArray());
} finally {
out.close();
}
} finally {
source.close();
}
}
}
}
@Override
public String toString() {
return entries.toString();
}
}