mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@21892 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
346 lines
12 KiB
Java
346 lines
12 KiB
Java
/*
|
|
* Copyright (C) 2005-2010 Alfresco Software Limited.
|
|
*
|
|
* This file is part of Alfresco
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package org.alfresco.cmis.changelog;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Date;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
|
|
import org.alfresco.cmis.CMISBaseObjectTypeIds;
|
|
import org.alfresco.cmis.CMISCapabilityChanges;
|
|
import org.alfresco.cmis.CMISChangeEvent;
|
|
import org.alfresco.cmis.CMISChangeLog;
|
|
import org.alfresco.cmis.CMISChangeLogService;
|
|
import org.alfresco.cmis.CMISChangeType;
|
|
import org.alfresco.cmis.CMISInvalidArgumentException;
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.service.cmr.audit.AuditQueryParameters;
|
|
import org.alfresco.service.cmr.audit.AuditService;
|
|
import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
|
|
/**
|
|
* ChangeLog Service Implementation
|
|
*
|
|
* @author Dmitry Velichkevich
|
|
*/
|
|
public class CMISChangeLogServiceImpl implements CMISChangeLogService
|
|
{
|
|
private static final String PATH_DELIMITER = "/";
|
|
private static final int DEFAULT_RETURN_SIZE = 100;
|
|
|
|
private AuditService auditService;
|
|
private String cmisAuditApplicationName;
|
|
private List<CMISBaseObjectTypeIds> changesOnTypeCapability;
|
|
|
|
/**
|
|
* Set the AuditService.
|
|
*
|
|
* @param auditService AuditService
|
|
*/
|
|
public void setAuditService(AuditService auditService)
|
|
{
|
|
this.auditService = auditService;
|
|
}
|
|
|
|
/**
|
|
* Set the Audit Application Name.
|
|
*
|
|
* @param cmisAuditApplicationName Audit Application Name
|
|
*/
|
|
public void setCmisAuditApplicationName(String cmisAuditApplicationName)
|
|
{
|
|
this.cmisAuditApplicationName = cmisAuditApplicationName;
|
|
}
|
|
|
|
/**
|
|
* Set the ChangesOnTypeCapability.
|
|
*
|
|
* @param changesOnTypeCapability list of CMISBaseObjectTypeIds
|
|
*/
|
|
public void setChangesOnTypeCapability(List<CMISBaseObjectTypeIds> changesOnTypeCapability)
|
|
{
|
|
this.changesOnTypeCapability = changesOnTypeCapability;
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getCapability()
|
|
*/
|
|
public CMISCapabilityChanges getCapability()
|
|
{
|
|
return (auditService.isAuditEnabled(cmisAuditApplicationName, PATH_DELIMITER + cmisAuditApplicationName)) ? (CMISCapabilityChanges.OBJECTIDSONLY)
|
|
: (CMISCapabilityChanges.NONE);
|
|
}
|
|
|
|
/**
|
|
* @throws CMISInvalidArgumentException
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getChangeLogEvents(java.lang.String, java.lang.Integer)
|
|
*/
|
|
public CMISChangeLog getChangeLogEvents(String changeLogToken, Integer maxItems) throws CMISInvalidArgumentException
|
|
{
|
|
if (!auditService.isAuditEnabled(cmisAuditApplicationName, ("/" + cmisAuditApplicationName)))
|
|
{
|
|
throw new AlfrescoRuntimeException("Auditing for " + cmisAuditApplicationName + " is disabled!");
|
|
}
|
|
CMISChangeLogImpl result = new CMISChangeLogImpl();
|
|
final List<CMISChangeEvent> changeEvents = result.getChangeEvents();
|
|
EntryIdCallback changeLogCollectingCallback = new EntryIdCallback(true)
|
|
{
|
|
@Override
|
|
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
|
{
|
|
List<CMISChangeEvent> changeLogEvents = convertValuesMapToChangeLogEvents(values, time);
|
|
changeEvents.addAll(changeLogEvents);
|
|
return super.handleAuditEntry(entryId, user, time, values);
|
|
}
|
|
};
|
|
Long from;
|
|
try
|
|
{
|
|
from = changeLogToken != null ? Long.parseLong(changeLogToken) : null;
|
|
}
|
|
catch (NumberFormatException e)
|
|
{
|
|
throw new CMISInvalidArgumentException("Invalid change log token " + changeLogToken);
|
|
}
|
|
AuditQueryParameters params = new AuditQueryParameters();
|
|
params.setApplicationName(cmisAuditApplicationName);
|
|
params.setForward(true);
|
|
params.setFromId(from);
|
|
|
|
// Query one past the last item, so that we know what the next ID is
|
|
int maxAmount = ((null == maxItems) || (0 == maxItems)) ? (0) : (maxItems + 1);
|
|
auditService.auditQuery(changeLogCollectingCallback, params, maxAmount);
|
|
|
|
if ((0 != maxAmount) && (changeEvents.size() > maxItems))
|
|
{
|
|
changeEvents.remove(changeEvents.size() - 1);
|
|
result.setNextChangeToken(changeLogCollectingCallback.getEntryId().toString());
|
|
result.setHasMoreItems(true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getChangesIncomplete()
|
|
*/
|
|
public boolean getChangesIncomplete()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getLastChangeLogToken()
|
|
*/
|
|
public String getLastChangeLogToken()
|
|
{
|
|
EntryIdCallback auditQueryCallback = new EntryIdCallback(false);
|
|
AuditQueryParameters params = new AuditQueryParameters();
|
|
params.setApplicationName(cmisAuditApplicationName);
|
|
params.setForward(false);
|
|
auditService.auditQuery(auditQueryCallback, params, 1);
|
|
return auditQueryCallback.getEntryId();
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getPreviousPageChangeLogToken(java.lang.String, java.lang.Integer)
|
|
*/
|
|
public String getPreviousPageChangeLogToken(String currentPageToken, Integer maxItems)
|
|
{
|
|
if (currentPageToken == null)
|
|
{
|
|
return null;
|
|
}
|
|
maxItems = maxItems == null ? DEFAULT_RETURN_SIZE : maxItems;
|
|
EntryIdCallback auditQueryCallback = new EntryIdCallback(false);
|
|
AuditQueryParameters params = new AuditQueryParameters();
|
|
params.setApplicationName(cmisAuditApplicationName);
|
|
params.setForward(false);
|
|
params.setToId(Long.parseLong(currentPageToken));
|
|
auditService.auditQuery(auditQueryCallback, params, maxItems);
|
|
return auditQueryCallback.getEntryId();
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getLastPageChangeLogToken(java.lang.String, java.lang.Integer)
|
|
*/
|
|
public String getLastPageChangeLogToken(String currentPageToken, Integer maxItems)
|
|
{
|
|
maxItems = maxItems == null ? DEFAULT_RETURN_SIZE : maxItems;
|
|
EntryIdCallback auditQueryCallback = new PageStartEntryIdCallback(maxItems);
|
|
AuditQueryParameters params = new AuditQueryParameters();
|
|
params.setApplicationName(cmisAuditApplicationName);
|
|
if (currentPageToken != null)
|
|
{
|
|
params.setFromId(Long.parseLong(currentPageToken));
|
|
}
|
|
auditService.auditQuery(auditQueryCallback, params, -1);
|
|
return auditQueryCallback.getEntryId();
|
|
}
|
|
|
|
/**
|
|
* @see org.alfresco.cmis.CMISChangeLogService#getChangesOnTypeCapability()
|
|
*/
|
|
public List<CMISBaseObjectTypeIds> getChangesOnTypeCapability()
|
|
{
|
|
if (null == changesOnTypeCapability)
|
|
{
|
|
changesOnTypeCapability = new LinkedList<CMISBaseObjectTypeIds>();
|
|
}
|
|
return changesOnTypeCapability;
|
|
}
|
|
|
|
/**
|
|
* Converts audit values map to list of CMISChangeEvents.
|
|
*
|
|
* @param values audit values map
|
|
* @param time audit event time
|
|
* @return list of CMISChangeEvent
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
private List<CMISChangeEvent> convertValuesMapToChangeLogEvents(Map<String, Serializable> values, long time)
|
|
{
|
|
List<CMISChangeEvent> result = new ArrayList<CMISChangeEvent>();
|
|
if (values != null && values.size() > 0)
|
|
{
|
|
for (Entry<String, Serializable> entry : values.entrySet())
|
|
{
|
|
if (entry.getKey() != null && entry.getValue() != null)
|
|
{
|
|
String path = entry.getKey();
|
|
CMISChangeType changeType = getCMISChangeType(path);
|
|
if (changeType != null && entry.getValue() instanceof Map)
|
|
{
|
|
Map<String, Serializable> valueMap = (Map<String, Serializable>)entry.getValue();
|
|
result.add(new CMISChangeEventImpl(changeType, new Date(time), (NodeRef) valueMap
|
|
.get(CMISChangeLogDataExtractor.KEY_NODE_REF), (String) valueMap
|
|
.get(CMISChangeLogDataExtractor.KEY_OBJECT_ID)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets CMISChangeType by audit path.
|
|
*
|
|
* @param auditPath audit path
|
|
* @return CMISChangeType
|
|
*/
|
|
private CMISChangeType getCMISChangeType(String auditPath)
|
|
{
|
|
CMISChangeType result = null;
|
|
if (auditPath != null)
|
|
{
|
|
if (auditPath.startsWith(PATH_DELIMITER))
|
|
{
|
|
auditPath = auditPath.substring(PATH_DELIMITER.length());
|
|
}
|
|
if (auditPath.startsWith(cmisAuditApplicationName))
|
|
{
|
|
auditPath = auditPath.substring(cmisAuditApplicationName.length());
|
|
}
|
|
if (auditPath.startsWith(PATH_DELIMITER))
|
|
{
|
|
auditPath = auditPath.substring(PATH_DELIMITER.length());
|
|
}
|
|
auditPath = auditPath.toLowerCase();
|
|
for (CMISChangeType changeType : CMISChangeType.values())
|
|
{
|
|
if (auditPath.startsWith(changeType.getLabel()))
|
|
{
|
|
result = changeType;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private class EntryIdCallback implements AuditQueryCallback
|
|
{
|
|
private final boolean valuesRequired;
|
|
private Long entryId;
|
|
|
|
public EntryIdCallback(boolean valuesRequired)
|
|
{
|
|
this.valuesRequired = valuesRequired;
|
|
}
|
|
|
|
public String getEntryId()
|
|
{
|
|
return entryId == null ? null : entryId.toString();
|
|
}
|
|
|
|
public boolean valuesRequired()
|
|
{
|
|
return this.valuesRequired;
|
|
}
|
|
|
|
public final boolean handleAuditEntry(Long entryId, String applicationName, String user, long time, Map<String, Serializable> values)
|
|
{
|
|
if (applicationName.equals(CMISChangeLogServiceImpl.this.cmisAuditApplicationName))
|
|
{
|
|
return handleAuditEntry(entryId, user, time, values);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
|
{
|
|
this.entryId = entryId;
|
|
return true;
|
|
}
|
|
|
|
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
|
|
{
|
|
throw new AlfrescoRuntimeException(errorMsg, error);
|
|
}
|
|
};
|
|
|
|
private class PageStartEntryIdCallback extends EntryIdCallback
|
|
{
|
|
private final int pageSize;
|
|
private int indexWithinPage;
|
|
|
|
public PageStartEntryIdCallback(int pageSize)
|
|
{
|
|
super(false);
|
|
this.pageSize = pageSize;
|
|
this.indexWithinPage = -1;
|
|
}
|
|
|
|
@Override
|
|
public boolean handleAuditEntry(Long entryId, String user, long time, Map<String, Serializable> values)
|
|
{
|
|
if (++this.indexWithinPage == this.pageSize)
|
|
{
|
|
this.indexWithinPage = 0;
|
|
return super.handleAuditEntry(entryId, user, time, values);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|