/** * Copyright (c) 2011-2012, Thilo Planz. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package v7db.files.mongodb; import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.List; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.ArrayUtils; import org.bson.BSONObject; import org.bson.types.ObjectId; import v7db.files.spi.Content; import v7db.files.spi.ContentPointer; import v7db.files.spi.ContentSHA; import v7db.files.spi.InlineContent; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; public class V7File { // lazy-loaded private Content gridFile; private final V7GridFS gridFS; private final DBObject metaData; private final V7File parent; V7File(V7GridFS gridFS, DBObject metaData, V7File parent) { this.gridFS = gridFS; this.metaData = metaData; this.parent = parent; } static V7File lazy(V7GridFS gridFS, Object id, V7File parent) { return new V7File(gridFS, new BasicDBObject("_id", id), parent); } private void loadGridFile() throws IOException { if (gridFile == null) gridFile = gridFS.getContent(metaData); } public String getContentType() { Object x = metaData.get("contentType"); if (x instanceof String) return (String) x; return null; } public Object getId() { return metaData.get("_id"); } public Object getParentId() { if (parent != null) return parent.getId(); return metaData.get("parent"); } public int getVersion() { return BSONUtils.getRequiredInt(metaData, "_version"); } public V7File getParent() { return parent; } public String getName() { Object o = metaData.get("filename"); if (o instanceof String) return (String) o; return null; } /** * useful to send gzipped contents directly to a client that supports it, * without having to uncompress it first. * * @return the _compressed_ data (using gzip), if present, null if not (no * on-the-fly compression is done) * */ public InputStream getInputStreamWithGzipContents() throws IOException { // loadGridFile(); // String store = (String) gridFile.get("store"); // if ("gz".equals(store)) // return gridFile.getInputStream(); return null; } /** * * @return null, if the file is not stored using gzip */ public Long getGZipLength() { // loadGridFile(); // String store = (String) gridFile.get("store"); // if ("gz".equals(store)) // return gridFile.getLength(); return null; } /** * takes care of de-compression * * @return an InputStream to _uncompressed_ data * @throws IOException */ public InputStream getInputStream() throws IOException { loadGridFile(); if (gridFile == null) return null; try { return gridFile.getInputStream(); } catch (IllegalArgumentException e) { throw new IOException(e.getMessage() + " on file " + getName()); } } public ContentPointer getContentPointer() { return gridFS.getContentPointer(metaData); } public boolean hasContent() { return getContentPointer() != null; } public Long getLength() { ContentPointer p = getContentPointer(); if (p == null) return null; return p.getLength(); } public String getDigest() { ContentPointer contentPointer = getContentPointer(); if (contentPointer instanceof ContentSHA) { return ((ContentSHA) contentPointer).getDigest(); } if (contentPointer instanceof InlineContent) { try { return DigestUtils.shaHex(((InlineContent) contentPointer) .getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } } if (contentPointer.getLength() == 0) return ContentSHA.calculate(ArrayUtils.EMPTY_BYTE_ARRAY) .getDigest(); // TODO: System.err.println("NO DIGEST!"); return null; } public List<V7File> getChildren() { return gridFS.getChildren(this); } public V7File getChild(String childName) { return gridFS.getChild(this, childName); } public V7File createChild(byte[] data, String filename, String contentType) throws IOException { Object childId = gridFS.addFile(data, getId(), filename, contentType); return lazy(gridFS, childId, this); } public V7File createChild(ContentPointer data, String filename, String contentType) throws IOException { Object childId = gridFS.addFile(data, getId(), filename, contentType); return lazy(gridFS, childId, this); } public V7File createChild(byte[] data, int offset, int len, String filename, String contentType) throws IOException { Object childId = gridFS.addFile(data, offset, len, getId(), filename, contentType); return lazy(gridFS, childId, this); }; public V7File createChild(InputStream data, String filename, String contentType) throws IOException { if (data == null) return createChild(null, 0, 0, filename, contentType); Object childId = gridFS.addFile(data, getId(), filename, contentType); return lazy(gridFS, childId, this); } public void rename(String newName) throws IOException { metaData.put("filename", newName); gridFS.updateMetaData(metaData); } public void moveTo(Object newParentId, String newName) throws IOException { metaData.put("parent", newParentId); rename(newName); } public void copyTo(Object newParentId, String newName) throws IOException { BasicDBObject newMetaData = new BasicDBObject(); ObjectId myNewId = new ObjectId(); newMetaData.put("_id", myNewId); newMetaData.put("filename", newName); newMetaData.put("parent", newParentId); newMetaData.put("contentType", getContentType()); for (V7File child : getChildren()) { child.copyTo(myNewId, child.getName()); } gridFS.insertContents(newMetaData, getContentPointer()); } public void setContent(ContentPointer data, String contentType) throws IOException { metaData.put("contentType", contentType); gridFS.updateContents(metaData, data); } public void setContent(byte[] data, String contentType) throws IOException { metaData.put("contentType", contentType); gridFS.updateContents(metaData, data); } public void setContent(InputStream data, String contentType) throws IOException { metaData.put("contentType", contentType); gridFS.updateContents(metaData, data, null); } public void setContent(InputStream data, long size, String contentType) throws IOException { metaData.put("contentType", contentType); gridFS.updateContents(metaData, data, size); } public Date getModifiedDate() { return (Date) metaData.get("updated_at"); } public Date getCreateDate() { return (Date) metaData.get("created_at"); } public void delete() throws IOException { gridFS.delete(this); } /** * @param permission * "read", "write", or "open" * @return the ACL for this permission, if not set, inherited from parents * null if not set (not even at parents), empty if set but empty */ public Object[] getEffectiveAcl(String permission) { BSONObject acls = (BSONObject) metaData.get("acl"); if (acls == null) if (parent != null) return parent.getEffectiveAcl(permission); else return null; List<?> acl = (List<?>) acls.get(permission); if (acl == null) return ArrayUtils.EMPTY_OBJECT_ARRAY; return acl.toArray(); } public Object[] getAcl(String permission) { BSONObject acls = (BSONObject) metaData.get("acl"); if (acls == null) return null; List<?> acl = (List<?>) acls.get(permission); if (acl == null) return ArrayUtils.EMPTY_OBJECT_ARRAY; return acl.toArray(); } }