
rapture.kernel.DocApiImpl Maven / Gradle / Ivy
The newest version!
/**
* 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.kernel;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.log4j.Logger;
import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import rapture.common.CallingContext;
import rapture.common.ContentEnvelope;
import rapture.common.DocUpdateObject;
import rapture.common.DocumentAttributeFactory;
import rapture.common.EntitlementSet;
import rapture.common.Messages;
import rapture.common.RaptureFolderInfo;
import rapture.common.RaptureIdGenConfig;
import rapture.common.RaptureScript;
import rapture.common.RaptureURI;
import rapture.common.Scheme;
import rapture.common.XferDocumentAttribute;
import rapture.common.api.DocApi;
import rapture.common.event.DocEventConstants;
import rapture.common.exception.RaptureException;
import rapture.common.exception.RaptureExceptionFactory;
import rapture.common.impl.jackson.JacksonUtil;
import rapture.common.model.DocWriteHandle;
import rapture.common.model.DocumentAttribute;
import rapture.common.model.DocumentMetadata;
import rapture.common.model.DocumentRepoConfig;
import rapture.common.model.DocumentRepoConfigStorage;
import rapture.common.model.DocumentWithMeta;
import rapture.common.model.IndexScriptPair;
import rapture.common.model.RaptureDocConfig;
import rapture.common.model.RunEventHandle;
import rapture.common.shared.doc.DeleteDocPayload;
import rapture.common.shared.doc.GetDocPayload;
import rapture.dsl.dparse.AbsoluteVersion;
import rapture.dsl.dparse.AsOfTimeDirective;
import rapture.dsl.dparse.BaseDirective;
import rapture.index.IndexHandler;
import rapture.kernel.context.ContextValidator;
import rapture.kernel.pipeline.SearchPublisher;
import rapture.kernel.schemes.RaptureScheme;
import rapture.repo.NVersionedRepo;
import rapture.repo.Repository;
import rapture.repo.VersionedRepo;
import rapture.script.reflex.ReflexHandler;
import rapture.script.reflex.ReflexRaptureScript;
import rapture.table.TableScriptCache;
import reflex.IReflexHandler;
import reflex.ReflexTreeWalker;
import reflex.value.ReflexValue;
public class DocApiImpl extends KernelBase implements DocApi, RaptureScheme {
private static Logger log = Logger.getLogger(DocApiImpl.class);
private static final String NAME = "Name"; //$NON-NLS-1$
private static final String IDGEN_AUTHORITY = "documentRepo";
private TableScriptCache indexScriptCache = new TableScriptCache();
public DocApiImpl(Kernel raptureKernel) {
super(raptureKernel);
}
@Override
public void createDocRepo(CallingContext context, String docRepoUri, String config) {
checkParameter("Repository URI", docRepoUri);
checkParameter("Config", config); //$NON-NLS-1$
RaptureURI internalUri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
String authority = internalUri.getAuthority();
if ((authority == null) || authority.isEmpty()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoAuthority")); //$NON-NLS-1$
}
if (internalUri.hasDocPath()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoDocPath", docRepoUri)); //$NON-NLS-1$
}
if (docRepoExists(context, docRepoUri)) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("Exists", internalUri.toShortString())); //$NON-NLS-1$
}
// save repo config
RaptureDocConfig dc = new RaptureDocConfig();
dc.setConfig(config);
dc.setAuthority(authority);
DocumentRepoConfig documentRepo = new DocumentRepoConfig();
documentRepo.setAuthority(authority);
documentRepo.setDocumentRepo(dc);
DocumentRepoConfigStorage.add(documentRepo, context.getUser(),
apiMessageCatalog.getMessage("CreatedType", new String[] { internalUri.getDocPath(), authority }).format()); //$NON-NLS-1$
// The repo will be created as needed in the cache when accessed the first time
log.info("Creating Repository " + docRepoUri + " with config " + config);
}
@Override
public Boolean validateDocRepo(CallingContext context, String docRepoUri) {
RaptureURI internalUri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
if (internalUri.hasDocPath()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoDocPath", docRepoUri)); //$NON-NLS-1$
}
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
return repository.validate();
}
// @Override
public Boolean removeDocumentRepo(CallingContext context, String docRepoUri, Boolean destroy) {
if (destroy) deleteDocRepo(context, docRepoUri);
return true;
}
@Override
public void archiveRepoDocs(CallingContext context, String docRepoUri, int versionLimit, long timeLimit, Boolean ensureVersionLimit) {
RaptureURI internalUri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
checkParameter(NAME, internalUri.getAuthority());
log.info("Archive versions " + internalUri.getFullPath());
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
} else if (repository instanceof VersionedRepo) {
archiveVersionedRepo(context, repository, internalUri, versionLimit, timeLimit, ensureVersionLimit);
} else if (repository instanceof NVersionedRepo) {
archiveNVersionedRepo(context, repository, internalUri, versionLimit, timeLimit, ensureVersionLimit);
} else {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST,
apiMessageCatalog.getMessage("ArchiveUnsupported", repository.getClass().getSimpleName())); //$NON-NLS-1$
}
}
private void archiveVersionedRepo(CallingContext context, Repository repo, RaptureURI internalUri, int versionLimit, long timeLimit,
Boolean ensureVersionLimit) {
try {
((VersionedRepo) repo).archiveRepoVersions(versionLimit, timeLimit, ensureVersionLimit, ContextFactory.getKernelUser().getUser());
} catch (RaptureException e) {
if (e.getMessage().contains("no version left")) {
deleteDocRepo(context, internalUri.getAuthority());
}
}
}
private boolean archiveNVersionedRepo(CallingContext context, Repository repo, RaptureURI internalUri, int versionLimit, long timeLimit,
Boolean ensureVersionLimit) {
if (internalUri.hasDocPath()) {
return ((NVersionedRepo) repo).archiveDocumentVersions(internalUri.getDocPath(), versionLimit, timeLimit, ensureVersionLimit,
ContextFactory.getKernelUser().getUser());
} else {
return ((NVersionedRepo) repo).archiveRepoVersions(internalUri.getAuthority(), versionLimit, timeLimit, ensureVersionLimit,
ContextFactory.getKernelUser().getUser());
}
}
@Override
public void deleteDocRepo(CallingContext context, String docRepoUri) {
RaptureURI internalUri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
if (internalUri.hasDocPath()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoDocPath", docRepoUri)); //$NON-NLS-1$
}
checkParameter(NAME, internalUri.getAuthority());
// First drop the data, then drop the repo config
Repository repository = getRepoFromCache(internalUri.getAuthority());
log.info(Messages.getString("Admin.DropRepo") + internalUri.getAuthority()); //$NON-NLS-1$
if (repository != null) {
repository.drop();
}
// Remove jobs associated with this authority.
for (String jobUri : Kernel.getSchedule().getTrusted().getJobs(context)) {
RaptureURI uri = new RaptureURI(Kernel.getSchedule().getTrusted().retrieveJob(context, jobUri).getJobURI());
if (uri.getAuthority().equals(internalUri.getAuthority())) {
Kernel.getSchedule().getTrusted().deleteJob(context, jobUri);
}
}
// Yeah this is like "delete everything that is prefixed by //docRepoUri
SearchPublisher.publishDropMessage(context, internalUri.toString());
// We can't just delete the repo. If we do then
// DocRepoCache.reloadConfig will just create it.
// So mark the config as having been deleted.
// DocumentRepoConfigStorage.deleteByAddress(internalUri,
// context.getUser(), "Drop document repo");
DocumentRepoConfig drc = DocumentRepoConfigStorage.readByAddress(internalUri);
drc.setDeleted(true);
DocumentRepoConfigStorage.add(internalUri, drc, context.getUser(), "Mark config as deleted");
log.info("Config for " + internalUri.toString() + " marked as deleted ");
removeRepoFromCache(internalUri.getAuthority());
}
public void updateDocumentRepo(CallingContext context, DocumentRepoConfig data) {
DocumentRepoConfigStorage.add(data, context.getUser(), "updated");
removeRepoFromCache(data.getAuthority());
}
@Override
public Boolean docRepoExists(CallingContext context, String docRepoUri) {
DocumentRepoConfig documentRepo = getDocRepoConfig(context, docRepoUri);
return documentRepo != null;
}
@Override
public DocumentRepoConfig getDocRepoConfig(CallingContext context, String docRepoUri) {
RaptureURI uri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
if (uri.hasDocPath()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoDocPath", docRepoUri)); //$NON-NLS-1$
}
DocumentRepoConfig documentRepo = DocumentRepoConfigStorage.readByAddress(uri);
if ((documentRepo != null) && documentRepo.getDeleted()) return null;
return documentRepo;
}
@Override
public List getDocRepoConfigs(CallingContext context) {
List configs = DocumentRepoConfigStorage.readAll();
if ((configs == null) || configs.isEmpty()) return configs;
int i = configs.size();
do {
i--;
DocumentRepoConfig drc = configs.get(i);
if (drc.getDeleted()) configs.remove(i);
} while (i > 0);
return configs;
}
@Override
/**
* Note: We no longer remove duplicates or modify the docUris list
*/
public List docsExist(CallingContext context, List docUris) {
List retVal = new ArrayList(docUris.size());
for (String uri : docUris) {
try {
GetDocPayload requestObj = new GetDocPayload();
requestObj.setContext(context);
requestObj.setDocUri(uri);
ContextValidator.validateContext(context, EntitlementSet.Doc_docExists, requestObj);
retVal.add(exists(context, uri));
} catch (RaptureException e) {
retVal.add(false);
}
}
return retVal;
}
public Boolean exists(CallingContext context, String docUri) {
// Slow - it gets the whole doc just to verify existence
return getDoc(context, docUri) != null;
}
@Override
public Map getDocs(CallingContext context, List docUris) {
if (docUris == null) {
return null;
} else if (docUris.isEmpty()) {
return new HashMap<>();
}
Map ret = new LinkedHashMap();
Map result = getDocsInternal(context, docUris);
for (String uri : docUris) {
try {
// Not so fast. Need to check your entitlement first
GetDocPayload requestObj = new GetDocPayload();
requestObj.setContext(context);
requestObj.setDocUri(uri);
ContextValidator.validateContext(context, EntitlementSet.Doc_getDoc, requestObj);
String toAdd = result.get(uri);
if (toAdd == null) {
ret.put(uri, result.get(new RaptureURI(uri, Scheme.DOCUMENT).toString()));
} else {
ret.put(uri, toAdd);
}
} catch (RaptureException e) {
log.error("Unable to access " + uri, e);
}
}
return ret;
}
public Map getDocsInternal(CallingContext context, List docUris) {
Map ret = new LinkedHashMap<>();
ListMultimap repoToUriMap = ArrayListMultimap.create();
// Group all the documents by the correct repo
for (String docUri : docUris) {
if (StringUtils.isBlank(docUri)) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NullOrEmpty"));
}
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
repoToUriMap.put(internalUri.getAuthority(), internalUri);
}
// Request each set of the documents from the repo at once
for (final String authority : repoToUriMap.keySet()) {
Repository repository = getRepoFromCache(authority);
if (repository != null) {
List uris = repoToUriMap.get(authority);
List docs = repository.getDocuments(Lists.transform(uris, new Function() {
@Override
public String apply(RaptureURI uri) {
return uri.getDocPath();
}
}));
for (int i = 0; i < docs.size(); i++) {
ret.put(uris.get(i).toString(), docs.get(i));
}
}
}
return ret;
}
@Override
public List getDocAndMetas(CallingContext context, List docUris) {
ListMultimap repoToUriMap = ArrayListMultimap.create();
List documents = new ArrayList();
if (docUris == null) {
return null;
} else if (docUris.isEmpty()) {
return new ArrayList();
}
for (String docUri : docUris) {
try {
GetDocPayload requestObj = new GetDocPayload();
requestObj.setContext(context);
requestObj.setDocUri(docUri);
ContextValidator.validateContext(context, EntitlementSet.Doc_getDoc, requestObj);
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
repoToUriMap.put(internalUri.getAuthority(), internalUri);
} catch (RaptureException e) {
log.error("Unable to access " + docUri, e);
}
}
for (String typePath : repoToUriMap.keySet()) {
Repository repository = getRepoFromCache(typePath);
if (repository != null && repository.hasMetaContent()) {
documents.addAll(repository.getDocAndMetas(repoToUriMap.get(typePath)));
} else if (repository != null) {
List contents = repository.getDocuments(Lists.transform(repoToUriMap.get(typePath), new Function() {
@Override
public String apply(RaptureURI input) {
return input.toString();
}
}));
for (int i = 0; i < contents.size(); i++) {
documents.add(constructDefaultDocumentWithMeta(contents.get(i), repoToUriMap.get(typePath).get(i).getDocPath()));
}
} else {
log.error("repository is null for " + typePath);
}
}
return documents;
}
private DocumentWithMeta constructDefaultDocumentWithMeta(String content, String displayName) {
DocumentWithMeta ret = new DocumentWithMeta();
ret.setContent(content);
ret.setDisplayName(displayName);
ret.setMetaData(new DocumentMetadata());
ret.getMetaData().setComment("Repo does not support metadata");
ret.getMetaData().setUser("unknown");
ret.getMetaData().setVersion(-1);
long now = System.currentTimeMillis();
ret.getMetaData().setCreatedTimestamp(now);
ret.getMetaData().setModifiedTimestamp(now);
ret.getMetaData().setWriteTime(new Date(now));
return ret;
}
@Override
public Boolean deleteDoc(CallingContext context, String docUri) {
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
DocumentRepoConfig type = getConfigFromCache(internalUri.getAuthority());
boolean ret = repository.removeDocument(internalUri.getDocPath(), context.getUser(), "");
if (ret) {
SearchPublisher.publishDeleteMessage(context, type, internalUri);
}
return ret;
}
@Override
public String getDoc(CallingContext context, String docUri) {
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
// check if they specified an attribute in the display name e.g.
// order/1/$link/linkeddoc
if (internalUri.hasAttribute()) {
DocumentAttribute att = repository.getDocAttribute(internalUri);
return (att == null) ? null : att.getValue();
}
BaseDirective baseDirective = getDirective(internalUri, repository);
return repository.getDocument(internalUri.getDocPath(), baseDirective);
}
@Override
public DocumentWithMeta getDocAndMeta(CallingContext context, String docUri) {
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
if (repository.hasMetaContent()) {
BaseDirective directive = getDirective(internalUri, repository);
return repository.getDocAndMeta(internalUri.getDocPath(), directive);
} else {
return constructDefaultDocumentWithMeta(getDoc(context, docUri), internalUri.getDocPath());
}
}
@Override
public DocumentMetadata getDocMeta(CallingContext context, String docUri) {
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
BaseDirective directive = getDirective(internalUri, repository);
return repository.getMeta(internalUri.getDocPath(), directive);
}
private BaseDirective getDirective(RaptureURI internalUri, Repository repository) {
BaseDirective directive = null;
if ((internalUri.hasVersion() || internalUri.hasAsOfTime()) && !repository.isVersioned()) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("InvalidVersionURI", internalUri.toString())); //$NON-NLS-1$
}
if (internalUri.hasVersion()) {
AbsoluteVersion av = new AbsoluteVersion();
av.setVersion(internalUri.getVersion());
directive = av;
} else if (internalUri.hasAsOfTime()) {
AsOfTimeDirective asOfTimeDirective = new AsOfTimeDirective();
asOfTimeDirective.setAsOfTime(internalUri.getAsOfTime());
directive = asOfTimeDirective;
}
return directive;
}
@Override
public DocumentWithMeta revertDoc(CallingContext context, String docUri) {
RaptureURI internalUri = new RaptureURI(docUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
return repository.revertDoc(internalUri.getDocPath(), null);
}
@Override
public Map getDocRepoStatus(CallingContext context, String docRepoUri) {
RaptureURI internalUri = new RaptureURI(docRepoUri, Scheme.DOCUMENT);
Repository repository = getRepoFromCache(internalUri.getAuthority());
if (repository == null) {
throw RaptureExceptionFactory.create(HttpURLConnection.HTTP_BAD_REQUEST, apiMessageCatalog.getMessage("NoSuchRepo", internalUri.toAuthString())); //$NON-NLS-1$
}
return repository.getStatus();
}
@Override
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy