
rapture.repo.VersionedRepo Maven / Gradle / Ivy
/**
* The MIT License (MIT)
*
* Copyright (c) 2011-2016 Incapture Technologies LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package rapture.repo;
import rapture.common.LockHandle;
import rapture.common.RaptureConstants;
import rapture.common.RaptureDNCursor;
import rapture.common.RaptureFolderInfo;
import rapture.common.RaptureNativeQueryResult;
import rapture.common.RaptureQueryResult;
import rapture.common.RaptureURI;
import rapture.common.exception.RaptNotSupportedException;
import rapture.common.exception.RaptureException;
import rapture.common.exception.RaptureExceptionFactory;
import rapture.common.impl.jackson.JsonContent;
import rapture.common.model.DocumentAttribute;
import rapture.common.model.DocumentVersionInfo;
import rapture.common.model.DocumentWithMeta;
import rapture.common.model.RaptureCommit;
import rapture.common.model.RemoteLink;
import rapture.common.repo.BaseObject;
import rapture.common.repo.CommentaryObject;
import rapture.common.repo.CommitObject;
import rapture.common.repo.DocumentBagObject;
import rapture.common.repo.DocumentBagReference;
import rapture.common.repo.DocumentObject;
import rapture.common.repo.PerspectiveObject;
import rapture.common.repo.TagObject;
import rapture.common.repo.TreeObject;
import rapture.dsl.dparse.BaseDirective;
import rapture.index.IndexHandler;
import rapture.lock.ILockingHandler;
import rapture.repo.db.KeyedDatabase;
import rapture.repo.db.ObjectDatabase;
import rapture.repo.stage.CommitCollector;
import rapture.repo.stage.Stage;
import rapture.repo.stage.StageTree;
import rapture.util.IDGenerator;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.google.common.base.Optional;
/**
* A repo contains an objectdatabase and references to perspectives It is used
* to manage access to typed content in Rapture
*
* @author amkimian
*/
public class VersionedRepo extends BaseRepo implements Repository {
private static Logger log = Logger.getLogger(VersionedRepo.class);
private static final String ERROR_CANNOT_RUN = "Cannot run on versioned repo";
private static final String OFFICIAL = RaptureConstants.OFFICIAL_STAGE;
private static final String DEFAULT_STAGE = RaptureConstants.OFFICIAL_STAGE;
private ObjectDatabase objDb;
private KeyedDatabase keyDb;
private KeyStore cacheKeyStore;
private static String setupKey = "$SETUP";
private Map stages;
private int capacity = 500;
private ILockingHandler lockHandler;
public VersionedRepo(Map config, KeyStore store, KeyStore cacheKeyStore, ILockingHandler lockHandler) {
super(store, config);
this.cacheKeyStore = cacheKeyStore;
this.lockHandler = lockHandler;
if (config != null && config.containsKey("capacity")) {
try {
capacity = Integer.parseInt(config.get("capacity"));
} catch (Exception e) {
log.error("Invalid capacity " + config.get("capacity"));
log.error("Will use default of 500");
}
}
store.resetFolderHandling();
objDb = new ObjectDatabase(store);
keyDb = new KeyedDatabase(store);
stages = new HashMap();
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
if (po == null) {
initBlankEnv();
} else {
if (!cacheKeyStore.containsKey(setupKey)) {
log.info("Initializing vcache");
initCacheStore();
log.info("Initializing vcache - done");
}
}
}
@Override
public void addCommentary(String key, String who, String description, String commentaryKey, String ref) {
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
final CommentaryObject comment = new CommentaryObject();
comment.setCommentaryKey(commentaryKey);
comment.setWho(who);
comment.setWhen(new Date());
comment.setMessage(description);
handleCommentaryFromCommit(cObj, key, new CommentaryHandler() {
@Override
public boolean handleObject(BaseObject b) {
try {
String ref = objDb.writeCommentary(comment);
b.getCommentaryReferences().add(ref);
return true;
} catch (Exception e) {
log.error("Could not handle commentary from commit - " + e.getMessage());
}
return false;
}
});
}
@Override
public long addDocument(String key, String value, String user, String comment, boolean mustBeNew) {
String context = IDGenerator.getUUID();
LockHandle lockHandle = lockHandler.acquireLock(context, DEFAULT_STAGE, 5, 5);
if (lockHandle != null) {
try {
// Create a new stage to be consistent
createStage(DEFAULT_STAGE);
addToStage(DEFAULT_STAGE, key, value, mustBeNew);
commitStage(DEFAULT_STAGE, user, comment);
cacheKeyStore.put(key, value);
} finally {
lockHandler.releaseLock(context, DEFAULT_STAGE, lockHandle);
}
} else {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "Could not get lock for write");
}
return 1L; // Deprecated repository so don't do anything special here.
}
@Override
public void addDocuments(List keys, String value, String user, String comment) {
// We want to add these displayNames, but point them to the same
// document content
String context = IDGenerator.getUUID();
LockHandle lockHandle = lockHandler.acquireLock(context, DEFAULT_STAGE, 5, 5);
if (lockHandle != null) {
try {
// Create a new stage to be consistent
createStage(DEFAULT_STAGE);
addToStage(DEFAULT_STAGE, keys, value, false);
commitStage(DEFAULT_STAGE, user, comment);
for (String x : keys) {
cacheKeyStore.put(x, value);
}
} finally {
lockHandler.releaseLock(context, DEFAULT_STAGE, lockHandle);
}
} else {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "Could not get lock for write");
}
}
private void addToStage(String stage, List keys, String document, boolean mustBeNew) {
Stage st = getStage(stage);
DocumentObject doc = new DocumentObject();
doc.setContent(new JsonContent(document));
for (String path : keys) {
String[] p = path.split("/");
LinkedList parts = new LinkedList();
for (String a : p) {
parts.add(a);
}
st.getStageBase().addDocumentToStage(this, parts, doc, mustBeNew);
}
}
/**
* Add a document to the stage
*
* @throws Exception
*/
public void addToStage(String stage, String path, String document, boolean mustBeNew) {
Stage st = getStage(stage);
DocumentObject doc = new DocumentObject();
doc.setContent(new JsonContent(document));
String[] p = path.split("/");
LinkedList parts = new LinkedList();
for (String a : p) {
parts.add(a);
}
st.getStageBase().addDocumentToStage(this, parts, doc, mustBeNew);
}
@Override
public void clearRemote() {
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
po.setRemoteLink(null);
keyDb.writePerspective(OFFICIAL, po);
}
public void commitStage(String stage, String user, String comment) {
Stage st = getStage(stage);
CommitObject cObj = new CommitObject();
cObj.setUser(user);
cObj.setWhen(new Date());
cObj.setComment(comment);
cObj.setPreviousReference(st.getPerspective().getLatestCommit());
String cRef = objDb.getCommitReference(cObj);
cObj.setCommitRef(cRef);
CommitCollector collector = new CommitCollector();
Map docCollector = new HashMap();
String reference = st.getStageBase().commitStage(this, cRef, collector, docCollector);
collector.addTreeReference(reference);
cObj.setTreeRef(reference);
cObj.setChanges(collector.toString());
cObj.setTreeReferences(collector.getTreeReferences());
cObj.setDocReferences(collector.getDocReferences());
objDb.writeCommit(cObj, cRef);
st.getPerspective().setLatestCommit(cRef);
// Need to write this back... (perhaps checking that the perspective on
// db hasn't changed...!)
keyDb.writePerspective(st.getPerspectiveName(), st.getPerspective());
}
@Override
public long countDocuments() throws RaptNotSupportedException {
throw new RaptNotSupportedException("Count not supported for versioned repo");
}
/**
* Create a new perspective based on the one passed in
*
* @param basePerspective
* @param name
* @throws Exception
*/
public void createPerspective(String basePerspective, String name) {
PerspectiveObject original = keyDb.getPerspective(basePerspective);
PerspectiveObject newP = new PerspectiveObject();
newP.setBaseCommit(original.getLatestCommit());
newP.setLatestCommit(original.getLatestCommit());
newP.setOwner("caller");
keyDb.writePerspective(name, newP);
}
/**
* Create a stage on which to do some changes. A stage is kind of like a
* realised tree with additional "overrides" on some names which reflect new
* concepts created
*
* @throws Exception
*/
@Override
public Stage createStage(String stageName) {
Stage stage = new Stage();
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
stage.setPerspectiveName(OFFICIAL);
stage.setPerspective(po);
CommitObject co = objDb.getCommit(po.getLatestCommit());
TreeObject to = objDb.getTree(co.getTreeRef());
StageTree st = new StageTree(to, capacity);
stage.setStageBase(st);
stages.put(stageName, stage);
return stage;
}
@Override
public void createTag(String user, String tagName) {
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
TagObject to = new TagObject();
to.setCommitRef(po.getLatestCommit());
to.setOwner(user);
to.setWhen(new Date());
keyDb.writeTag(tagName, to);
}
@Override
public void drop() {
if (cacheKeyStore != null) {
cacheKeyStore.dropKeyStore();
}
if (!store.dropKeyStore()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "Could not drop keystore");
}
}
@Override
public List getCommentary(String key) {
// Given a perspective and key, load the associated BasedObject and get
// the list of references. Then load
// each CommentaryObject from those references and return that
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
final List ret = new ArrayList();
handleCommentaryFromCommit(cObj, key, new CommentaryHandler() {
@Override
public boolean handleObject(BaseObject b) {
List commentaryRefs = b.getCommentaryReferences();
for (String c : commentaryRefs) {
CommentaryObject comment;
try {
comment = objDb.getCommentary(c);
if (comment != null) {
ret.add(comment);
}
} catch (RaptureException e) {
log.error("Could not load commentary object " + c);
}
}
return false; // Don't need to save BaseObject back
}
});
return ret;
}
@Override
public List getCommitHistory() {
return getCommitsSince(null);
}
@Override
public CommitObject getCommitObject(String reference) {
return objDb.getCommit(reference);
}
@Override
public List getCommitsSince(String commitReference) {
List commits = new ArrayList();
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
boolean done = false;
while (!done) {
RaptureCommit co = new RaptureCommit();
co.setComment(cObj.getComment());
co.setWhen(cObj.getWhen());
co.setWho(cObj.getUser());
co.setChanges(cObj.getChanges());
co.setReference(cObj.getCommitRef());
co.setDocReferences(cObj.getDocReferences());
co.setTreeReferences(cObj.getTreeReferences());
commits.add(co);
String ref = cObj.getPreviousReference();
if (ref != null && ref.equals(commitReference)) {
done = true;
} else {
if (ref != null) {
cObj = objDb.getCommit(ref);
} else {
cObj = null;
}
if (cObj == null) {
done = true;
}
}
}
return commits;
}
private CommitObject getCommitViaDirective(CommitObject startPoint, String context, BaseDirective directive) {
if (directive == null) {
return startPoint;
}
directive.reset(context);
CommitObject cObj = startPoint;
while (directive.incorrect(cObj)) {
cObj = objDb.getCommit(cObj.getPreviousReference());
if (cObj == null) {
break;
}
}
return directive.retrieveCommit();
}
public String getDocument(String documentName) {
// Retrieve a document from perspective, given its path
String doc = cacheKeyStore.get(documentName);
if (doc != null) {
return doc;
}
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
return getDocumentFromCommit(documentName, cObj);
}
@Override
public String getDocument(String documentName, BaseDirective directive) {
if (directive == null) {
return getDocument(documentName);
}
// In this request we start with the given commit object (the latest in
// the perspective) and
// use the directive to work back until we find the correct commit. Then
// we get the document
// from that commit
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
cObj = getCommitViaDirective(cObj, documentName, directive);
if (cObj != null) {
String ret = getDocumentFromCommit(documentName, cObj);
return ret;
} else {
return null;
}
}
public String getDocumentFromCommit(String documentName, CommitObject cObj) {
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
String[] parts = documentName.split("/");
String ret = null;
for (int i = 0; i < parts.length; i++) {
if (tObj == null) {
break;
}
if (i == parts.length - 1) {
for (DocumentBagReference bagRef : tObj.getDocuments()) {
DocumentBagObject dObj = objDb.getDocumentBag(bagRef.getBagRef());
ret = dObj.getDocRefs().get(parts[i]);
if (ret != null) {
ret = objDb.getDocument(ret).getContent().toString();
break;
}
}
} else {
String treeRef = tObj.getTrees().get(parts[i]);
tObj = objDb.getTree(treeRef);
}
}
return ret;
}
@Override
public DocumentObject getDocumentObject(String reference) {
return objDb.getDocument(reference);
}
@Override
public List getDocuments(List keys) {
// Ideally use the batch method of the cacheStore
List docs = null;
List docsFromCache = cacheKeyStore.getBatch(keys);
docs = new ArrayList();
// Now check for cache misses
for (int i = 0; i < docsFromCache.size(); i++) {
String d = docsFromCache.get(i);
if (d == null) {
d = getDocument(keys.get(i));
if (d != null) {
log.info("Cache miss for " + keys.get(0) + " during batch operation");
cacheKeyStore.put(keys.get(i), d);
}
}
docs.add(d);
}
return docs;
}
@Override
// For each of the displaynames (document names)
// Does that document exist in the perspective point?
public boolean[] getExistence(List displays) {
boolean ret[] = new boolean[displays.size()];
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
List displaysCopy = new ArrayList();
displaysCopy.addAll(displays);
// Try this level
String level = "";
List refs = tObj.getDocuments();
for (DocumentBagReference r : refs) {
DocumentBagObject dObj = objDb.getDocumentBag(r.getBagRef());
for (String key : dObj.getDocRefs().keySet()) {
String testKey = level + key;
if (displaysCopy.contains(testKey)) {
int pos = displays.indexOf(testKey);
ret[pos] = true;
displaysCopy.remove(testKey);
if (displaysCopy.isEmpty()) {
break;
}
}
}
if (displaysCopy.isEmpty()) {
break;
}
}
// And now dive into another level
if (displaysCopy.isEmpty()) {
return ret;
} else {
for (Map.Entry tree : tObj.getTrees().entrySet()) {
String newEntry = level.isEmpty() ? tree.getKey() : level + "/" + tree.getKey();
TreeObject innerObj = objDb.getTree(tree.getValue());
ret = walkInnerExistence(newEntry, innerObj, displaysCopy, displays, ret);
if (displaysCopy.isEmpty()) {
break;
}
}
}
return ret;
}
@Override
public RaptureDNCursor getNextDNCursor(RaptureDNCursor cursor, int count) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "Not yet implemented");
}
public ObjectDatabase getObjectDatabase() {
return objDb;
}
private Stage getStage(String name) {
Stage s = stages.get(name);
if (s == null) {
s = createStage(name);
}
return s;
}
@Override
public String getTagDocument(String tag, String key) {
TagObject to = keyDb.getTag(tag);
CommitObject cObj = objDb.getCommit(to.getCommitRef());
return getDocumentFromCommit(key, cObj);
}
@Override
public List getTags() {
return keyDb.getTags();
}
@Override
public TreeObject getTreeObject(String reference) {
return objDb.getTree(reference);
}
private void handleCommentaryFromCommit(CommitObject cObj, String key, CommentaryHandler handler) {
// Now visit the tree to find the document referenced by key
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
String[] parts = key.split("/");
String ultimateRef = null;
for (int i = 0; i < parts.length; i++) {
if (tObj == null) {
break;
}
if (i == parts.length - 1) {
for (DocumentBagReference bagRef : tObj.getDocuments()) {
DocumentBagObject dObj = objDb.getDocumentBag(bagRef.getBagRef());
ultimateRef = dObj.getDocRefs().get(parts[i]);
if (ultimateRef == null) {
ultimateRef = tObj.getTrees().get(parts[i]);
TreeObject content = objDb.getTree(ultimateRef);
if (content != null) {
if (handler.handleObject(content)) {
objDb.writeTree(content, ultimateRef);
}
}
} else {
DocumentObject content = objDb.getDocument(ultimateRef);
if (handler.handleObject(content)) {
objDb.writeDocument(content, ultimateRef);
}
}
}
} else {
String treeRef = tObj.getTrees().get(parts[i]);
tObj = objDb.getTree(treeRef);
}
}
}
/**
* A test function really to setup a blank environment
*
* @
*/
private void initBlankEnv() {
// Create an initial commit with a null tree
TreeObject tObj = new TreeObject();
String ref = objDb.writeTree(tObj);
CommitObject cObj = new CommitObject();
cObj.setTreeRef(ref);
cObj.setUser("admin");
cObj.setWhen(new Date());
cObj.setComment("Repo creation");
String cRef = objDb.getCommitReference(cObj);
cObj.setCommitRef(cRef);
List refs = new ArrayList();
refs.add(ref);
cObj.setTreeReferences(refs);
cObj.setDocReferences(new ArrayList());
objDb.writeCommit(cObj, cRef);
PerspectiveObject main = new PerspectiveObject();
main.setBaseCommit(cRef);
main.setLatestCommit(cRef);
main.setDescription("Main branch of work");
main.setOwner(OFFICIAL);
main.setWhen(new Date());
keyDb.writePerspective(OFFICIAL, main);
createStage(OFFICIAL);
}
private void initCacheStore() {
// Basically copy the latest keys/values to the cacheKeyStore
visitAll("", null, new RepoVisitor() {
@Override
public boolean visit(String name, JsonContent content, boolean isFolder) {
if (!isFolder) {
System.out.println(name);
if (!cacheKeyStore.containsKey(name)) {
log.info("VCache initialization, writing " + name);
try {
cacheKeyStore.put(name, content.getContent());
} catch (Exception e) {
e.printStackTrace();
}
}
}
return true;
}
});
cacheKeyStore.put(setupKey, "done");
}
public boolean isVersioned() {
return true;
}
/**
* Archives old versions
*
* @param versionLimit number of versions to retain
* @param timeLimit commits older than timeLimit will be archived
* @param ensureVersionLimit ensure number of versions to retain even if commit is older than timeLimit
* @param user
* @return
*/
public boolean archiveRepoVersions(int versionLimit, long timeLimit, boolean ensureVersionLimit, String user) {
if (versionLimit <= 0) {
log.error("versionLimit should > 0");
return false;
}
PerspectiveObject perspective = keyDb.getPerspective(OFFICIAL);
CommitObject commitObj = objDb.getCommit(perspective.getLatestCommit());
if (commitObj.getWhen().getTime() < timeLimit && !ensureVersionLimit) {
throw RaptureExceptionFactory.create("Invalid archive - no version left");
}
List keysToArchive = new ArrayList();
int versionsRemaining = versionLimit;
while (commitObj != null) {
// do not archive the very first commit: repo creation
if (StringUtils.isEmpty(commitObj.getPreviousReference())) {
break;
}
// archive commit if it's older than specified timestamp, and no ensureVersions
boolean isCommitTooOld = commitObj.getWhen().getTime() < timeLimit && !ensureVersionLimit;
if (versionsRemaining <= 0 || isCommitTooOld) {
// archive commit, along with its docref and treerefs
getKeysToArchive(commitObj, keysToArchive);
} else {
versionsRemaining--;
}
// move on to previous commit
commitObj = objDb.getCommit(commitObj.getPreviousReference());
}
return objDb.delete(keysToArchive);
}
private void getKeysToArchive(CommitObject commitObj, List keysToArchive) {
keysToArchive.add(commitObj.getCommitRef());
// add doc refs to archive
keysToArchive.addAll(commitObj.getDocReferences());
// add tree refs to archive
for (String treeRef : commitObj.getTreeReferences()) {
keysToArchive.add(treeRef);
// add document bag ref to archive
TreeObject treeObject = objDb.getTree(treeRef);
List docBagRefs = treeObject.getDocuments();
if (docBagRefs != null) {
for (DocumentBagReference bagRef : docBagRefs) {
keysToArchive.add(bagRef.getBagRef());
}
}
}
}
/**
* Merge one perspective into another
*
* @param targetPerspetive
* @param sourcePerspective
* @throws Exception
*/
public void mergePerspective(String targetPerspetive, String sourcePerspective) {
// We need to look at the target and sourcePerspectives with respect to
// their commits
// We find out a common ancestor commit, and start a Stage from the
// targetPerspective
// We then continuously apply the treeObject from the common ancestor
// point to the commit in the sourcePerspective
// That final stage is the one we commit to move the targetPerspective
// forward.
PerspectiveObject target = keyDb.getPerspective(targetPerspetive);
PerspectiveObject source = keyDb.getPerspective(sourcePerspective);
CommitObject co = objDb.getCommit(target.getLatestCommit());
TreeObject to = objDb.getTree(co.getTreeRef());
StageTree st = new StageTree(to, capacity);
// Now apply each tree object associated with the commits between the
// latest commit in source and the start point
List commitList = new ArrayList();
String commitRef = source.getLatestCommit();
while (!commitRef.equals(source.getBaseCommit())) {
CommitObject cotest = objDb.getCommit(commitRef);
commitList.add(commitRef);
commitRef = cotest.getPreviousReference();
}
// We now have a list of trees to apply (but in the wrong order)
for (int i = commitList.size() - 1; i >= 0; i--) {
CommitObject cob = objDb.getCommit(commitList.get(i));
TreeObject apply = objDb.getTree(cob.getTreeRef());
st.apply(this, apply, commitList.get(i));
}
// And now commit this stage
CommitObject cObj = new CommitObject();
cObj.setUser("merge");
cObj.setWhen(new Date());
cObj.setPreviousReference(target.getLatestCommit());
String cRef = objDb.getCommitReference(cObj);
cObj.setCommitRef(cRef);
CommitCollector collector = new CommitCollector();
String reference = st.commitStage(this, cRef, collector, new HashMap());
cObj.setTreeRef(reference);
cObj.setChanges(collector.toString());
objDb.writeCommit(cObj, cRef);
target.setLatestCommit(cRef);
source.setLatestCommit(cRef);
source.setBaseCommit(cRef);
keyDb.writePerspective(targetPerspetive, target);
keyDb.writePerspective(sourcePerspective, source);
}
private void queryForTree(TreeObject tObj, String indent) {
for (DocumentBagReference bagRef : tObj.getDocuments()) {
DocumentBagObject dObj = objDb.getDocumentBag(bagRef.getBagRef());
for (Map.Entry docEntries : dObj.getDocRefs().entrySet()) {
log.info(indent + docEntries.getKey() + " - " + objDb.getDocument(docEntries.getValue()).getContent().toString());
}
}
for (Map.Entry treeEntries : tObj.getTrees().entrySet()) {
log.info(indent + treeEntries.getKey() + " -V-");
TreeObject inner = objDb.getTree(treeEntries.getValue());
queryForTree(inner, indent + " ");
}
}
/**
* For now this just dumps out the perspective by walking the associated
* tree
*
* @param perspective
* @throws Exception
*/
public void queryPerspective(String perspective) {
PerspectiveObject po = keyDb.getPerspective(perspective);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
queryForTree(tObj, "");
}
@Override
public boolean removeDocument(String key, String user, String comment) {
// Need to reset stage
boolean removed = false;
if (!stages.containsKey(OFFICIAL)) {
createStage(OFFICIAL);
}
removed = removeFromStage(OFFICIAL, key);
if (removed) {
commitStage(OFFICIAL, user, comment);
}
cacheKeyStore.delete(key);
return true;
}
@Override
public boolean removeFromStage(String stage, String path) {
Stage st = getStage(stage);
String[] p = path.split("/");
LinkedList parts = new LinkedList();
for (String a : p) {
parts.add(a);
}
return st.getStageBase().removeFromStage(this, parts);
}
@Override
public void removeTag(String tagName) {
keyDb.deleteTag(tagName);
}
@Override
public RaptureQueryResult runNativeQuery(String repoType, List queryParams) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, ERROR_CANNOT_RUN);
}
@Override
public RaptureNativeQueryResult runNativeQueryWithLimitAndBounds(String repoType, List queryParams, int limit, int offset) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, ERROR_CANNOT_RUN);
}
@Override
public void setRemote(String remote, String remoteAuthority) {
// IF the perspective does not exist, throw, otherwise update the
// perspective and
// save it back
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
RemoteLink rl = new RemoteLink();
rl.setAuthority(remoteAuthority);
rl.setRemoteId(remote);
rl.setPerspective(OFFICIAL);
po.setRemoteLink(rl);
keyDb.writePerspective(OFFICIAL, po);
}
@Override
public void visitAll(String prefix, BaseDirective directive, RepoVisitor visitor) {
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
cObj = getCommitViaDirective(cObj, null, directive);
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
// TODO: optimise this by finding the correct part of the tree based on
// the prefix
visitTree(tObj, prefix, visitor, "");
}
@Override
public List getChildren(String displayNamePart) {
return null;
}
@Override
public List removeChildren(String area, Boolean force) {
return null;
}
@Override
public void visitFolder(String folder, BaseDirective directive, RepoVisitor visitor) {
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
cObj = getCommitViaDirective(cObj, null, directive);
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
visitFolderFromTree(folder, visitor, tObj);
}
public void visitFolderFromTree(String folder, RepoVisitor visitor, TreeObject ptObj) {
TreeObject tObj = ptObj;
if (!folder.isEmpty()) {
String[] parts = folder.split("/");
for (String p : parts) {
if (tObj.getTrees().containsKey(p)) {
tObj = objDb.getTree(tObj.getTrees().get(p));
} else {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, "Not found");
}
}
}
// Now tObj is where we should be
for (DocumentBagReference bagRef : tObj.getDocuments()) {
DocumentBagObject dObj = objDb.getDocumentBag(bagRef.getBagRef());
for (Map.Entry docEntries : dObj.getDocRefs().entrySet()) {
if (!docEntries.getKey().isEmpty()) {
visitor.visit(docEntries.getKey(), objDb.getDocument(docEntries.getValue()).getContent(), false);
}
}
}
for (Map.Entry folderEntries : tObj.getTrees().entrySet()) {
visitor.visit(folderEntries.getKey(), null, true);
}
}
@Override
public void visitFolders(String folderPrefix, BaseDirective directive, final RepoFolderVisitor visitor) {
// Visit just the folders, that match this prefix
if (directive == null) {
cacheKeyStore.visit(folderPrefix, new RepoVisitor() {
@Override
public boolean visit(String name, JsonContent content, boolean isFolder) {
visitor.folder(name);
return true;
}
});
return;
}
PerspectiveObject po = keyDb.getPerspective(OFFICIAL);
CommitObject cObj = objDb.getCommit(po.getLatestCommit());
cObj = getCommitViaDirective(cObj, null, directive);
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
visitFolderFromTree(folderPrefix, new RepoVisitor() {
@Override
public boolean visit(String name, JsonContent content, boolean isFolder) {
visitor.folder(name);
return true;
}
}, tObj);
}
@Override
public void visitTag(String tagName, String prefix, RepoVisitor visitor) {
TagObject to = keyDb.getTag(tagName);
CommitObject cObj = objDb.getCommit(to.getCommitRef());
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
visitTree(tObj, prefix, visitor, "");
}
@Override
public void visitTagFolder(String tagName, String folder, RepoVisitor visitor) {
TagObject to = keyDb.getTag(tagName);
CommitObject cObj = objDb.getCommit(to.getCommitRef());
TreeObject tObj = objDb.getTree(cObj.getTreeRef());
visitFolderFromTree(folder, visitor, tObj);
}
private boolean visitTree(TreeObject tObj, String prefix, RepoVisitor visitor, String treePrefix) {
// Visit docs first
for (DocumentBagReference bagRef : tObj.getDocuments()) {
DocumentBagObject dObj = objDb.getDocumentBag(bagRef.getBagRef());
for (Map.Entry docEntries : dObj.getDocRefs().entrySet()) {
if (treePrefix.startsWith(prefix)) {
// If we cannot visit a document, (i.e. an exception is
// thrown, continue)
try {
if (!visitor.visit(treePrefix + docEntries.getKey(), objDb.getDocument(docEntries.getValue()).getContent(), false)) {
return false;
}
} catch (RaptureException e) {
log.error("Could not decode document " + e.getMessage());
}
}
}
}
for (Map.Entry treeEntries : tObj.getTrees().entrySet()) {
TreeObject inner = objDb.getTree(treeEntries.getValue());
if (!visitTree(inner, prefix, visitor, treePrefix + treeEntries.getKey() + "/")) {
return false;
}
}
return true;
}
private boolean[] walkInnerExistence(String level, TreeObject tObj, List displaysCopy, List displays, boolean[] ret) {
List refs = tObj.getDocuments();
for (DocumentBagReference r : refs) {
DocumentBagObject dObj = objDb.getDocumentBag(r.getBagRef());
for (String key : dObj.getDocRefs().keySet()) {
String testKey = level.isEmpty() ? key : level + "/" + key;
if (displaysCopy.contains(testKey)) {
int pos = displays.indexOf(testKey);
ret[pos] = true;
displaysCopy.remove(testKey);
if (displaysCopy.isEmpty()) {
break;
}
}
}
if (displaysCopy.isEmpty()) {
break;
}
}
// And now dive into another level
if (displaysCopy.isEmpty()) {
return ret;
} else {
for (Map.Entry tree : tObj.getTrees().entrySet()) {
String newEntry = level + "/" + tree.getKey();
TreeObject innerObj = objDb.getTree(tree.getValue());
ret = walkInnerExistence(newEntry, innerObj, displaysCopy, displays, ret);
if (displaysCopy.isEmpty()) {
break;
}
}
}
return ret;
}
@Override
public void writeCommitObject(String reference, CommitObject commit) {
objDb.writeCommit(commit, reference);
}
@Override
public void writeDocumentObject(String reference, DocumentObject docObject) {
objDb.writeDocument(docObject, reference);
}
@Override
public void writeTreeObject(String reference, TreeObject treeObject) {
objDb.writeTree(treeObject, reference);
}
@Override
public boolean addDocumentWithVersion(String disp, String content, String user, String comment, boolean mustBeNew, int expectedVersion) {
addDocument(disp, content, user, comment, mustBeNew);
return true;
}
@Override
public boolean hasMetaContent() {
return false;
}
@Override
public List getVersionHistory(String key) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public List getVersionMeta(String key, List versions) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public List removeVersionMeta(String key, List versions) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public void setDocAttribute(RaptureURI uri, DocumentAttribute attribute) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public DocumentAttribute getDocAttribute(RaptureURI uri) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public List getDocAttributes(RaptureURI uri) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public Boolean deleteDocAttribute(RaptureURI uri) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_INTERNAL_ERROR, Messages.getString("BaseSimpleRepo.notsupp")); //$NON-NLS-1$
}
@Override
public Boolean validate() {
return store.validate();
}
@Override
public Optional getIndexHandler() {
return Optional.absent();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy