mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged HEAD-BUG-FIX (5.0/Cloud) to HEAD (5.0/Cloud)
84811: Merged PLATFORM1 (5.0/Cloud) to HEAD-BUG-FIX (5.0/Cloud) 82464: ACE-1246 "Allow the customer to change the document encryption key" Encrypting content store git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@85170 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -1120,7 +1120,7 @@ abstract public class AbstractMappingMetadataExtracter implements MetadataExtrac
|
||||
if (!isSupported(mimetype))
|
||||
{
|
||||
throw new AlfrescoRuntimeException(
|
||||
"Metadata extracter does not support mimetype: \n" +
|
||||
"Metadata extracter does not support mimetype: " + mimetype + "\n" +
|
||||
" reader: " + reader + "\n" +
|
||||
" supported: " + supportedMimetypes + "\n" +
|
||||
" extracter: " + this);
|
||||
|
@@ -19,7 +19,6 @@
|
||||
package org.alfresco.repo.domain.contentdata;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Savepoint;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -29,7 +28,6 @@ import org.alfresco.repo.cache.SimpleCache;
|
||||
import org.alfresco.repo.cache.lookup.EntityLookupCache;
|
||||
import org.alfresco.repo.cache.lookup.EntityLookupCache.EntityLookupCallbackDAOAdaptor;
|
||||
import org.alfresco.repo.content.cleanup.EagerContentStoreCleaner;
|
||||
import org.alfresco.repo.domain.control.ControlDAO;
|
||||
import org.alfresco.repo.domain.encoding.EncodingDAO;
|
||||
import org.alfresco.repo.domain.locale.LocaleDAO;
|
||||
import org.alfresco.repo.domain.mimetype.MimetypeDAO;
|
||||
@@ -54,11 +52,14 @@ import org.springframework.dao.DataIntegrityViolationException;
|
||||
* IDs into <code>ContentData</code> instances.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @author sglover
|
||||
* @since 3.2
|
||||
*/
|
||||
public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
{
|
||||
private static final String CACHE_REGION_CONTENT_DATA = "ContentData";
|
||||
private static final String CACHE_REGION_CONTENT_URL = "ContentUrl";
|
||||
|
||||
/**
|
||||
* Content URL IDs to delete before final commit.
|
||||
*/
|
||||
@@ -67,10 +68,10 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
private static Log logger = LogFactory.getLog(AbstractContentDataDAOImpl.class);
|
||||
|
||||
private final ContentDataCallbackDAO contentDataCallbackDAO;
|
||||
private ControlDAO controlDAO;
|
||||
private MimetypeDAO mimetypeDAO;
|
||||
private EncodingDAO encodingDAO;
|
||||
private LocaleDAO localeDAO;
|
||||
private final ContentUrlCallbackDAO contentUrlCallbackDAO;
|
||||
protected MimetypeDAO mimetypeDAO;
|
||||
protected EncodingDAO encodingDAO;
|
||||
protected LocaleDAO localeDAO;
|
||||
private EagerContentStoreCleaner contentStoreCleaner;
|
||||
|
||||
/**
|
||||
@@ -80,24 +81,20 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
* VALUE KEY: NONE<br/>
|
||||
*/
|
||||
private EntityLookupCache<Long, ContentData, Serializable> contentDataCache;
|
||||
|
||||
|
||||
private EntityLookupCache<Long, ContentUrlEntity, String> contentUrlCache;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public AbstractContentDataDAOImpl()
|
||||
{
|
||||
this.contentDataCallbackDAO = new ContentDataCallbackDAO();
|
||||
this.contentUrlCallbackDAO = new ContentUrlCallbackDAO();
|
||||
this.contentDataCache = new EntityLookupCache<Long, ContentData, Serializable>(contentDataCallbackDAO);
|
||||
this.contentUrlCache = new EntityLookupCache<Long, ContentUrlEntity, String>(contentUrlCallbackDAO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param controlDAO create Savepoints
|
||||
*/
|
||||
public void setControlDAO(ControlDAO controlDAO)
|
||||
{
|
||||
this.controlDAO = controlDAO;
|
||||
}
|
||||
|
||||
public void setMimetypeDAO(MimetypeDAO mimetypeDAO)
|
||||
{
|
||||
this.mimetypeDAO = mimetypeDAO;
|
||||
@@ -133,7 +130,15 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
CACHE_REGION_CONTENT_DATA,
|
||||
contentDataCallbackDAO);
|
||||
}
|
||||
|
||||
|
||||
public void setContentUrlCache(SimpleCache<Long, ContentUrlEntity> contentUrlCache)
|
||||
{
|
||||
this.contentUrlCache = new EntityLookupCache<Long, ContentUrlEntity, String>(
|
||||
contentUrlCache,
|
||||
CACHE_REGION_CONTENT_URL,
|
||||
contentUrlCallbackDAO);
|
||||
}
|
||||
|
||||
/**
|
||||
* A <b>content_url</b> entity was dereferenced. This makes no assumptions about the
|
||||
* current references - dereference deletion is handled in the commit phase.
|
||||
@@ -179,6 +184,49 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
return entityPair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContentUrl(ContentUrlEntity contentUrl)
|
||||
{
|
||||
if (contentUrl == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot look up ContentData by null ID.");
|
||||
}
|
||||
Pair<Long, ContentUrlEntity> pair = contentUrlCache.getByValue(contentUrl);
|
||||
if(pair != null)
|
||||
{
|
||||
contentUrlCache.updateValue(pair.getFirst(), contentUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = contentUrlCache.getOrCreateByValue(contentUrl);
|
||||
contentUrlCache.updateValue(pair.getFirst(), contentUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentUrlEntity getContentUrl(String contentUrl)
|
||||
{
|
||||
if (contentUrl == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot look up ContentData by null ID.");
|
||||
}
|
||||
ContentUrlEntity entity = new ContentUrlEntity();
|
||||
entity.setContentUrl(contentUrl);
|
||||
Pair<Long, ContentUrlEntity> pair = contentUrlCache.getByValue(entity);
|
||||
return (pair == null ? null : pair.getSecond());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentUrlEntity getContentUrl(Long contentUrlId)
|
||||
{
|
||||
if (contentUrlId == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot look up ContentData by null ID.");
|
||||
}
|
||||
Pair<Long, ContentUrlEntity> pair = contentUrlCache.getByKey(contentUrlId);
|
||||
return (pair == null ? null : pair.getSecond());
|
||||
}
|
||||
|
||||
public void cacheContentDataForNodes(Set<Long> nodeIds)
|
||||
{
|
||||
for (ContentDataEntity entity : getContentDataEntitiesForNodes(nodeIds))
|
||||
@@ -245,7 +293,7 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
}
|
||||
ContentData contentData = makeContentData(contentDataEntity);
|
||||
// Done
|
||||
return new Pair<Long, ContentData>(key, contentData);
|
||||
return new Pair<Long, ContentData>(key, contentData);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,15 +313,89 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
return deleteContentDataEntity(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback for <b>alf_content_url</b> DAO.
|
||||
*/
|
||||
private class ContentUrlCallbackDAO extends EntityLookupCallbackDAOAdaptor<Long, ContentUrlEntity, String>
|
||||
{
|
||||
/**
|
||||
* @return Returns the Node's NodeRef
|
||||
*/
|
||||
@Override
|
||||
public String getValueKey(ContentUrlEntity value)
|
||||
{
|
||||
return value.getContentUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks the node up based on the NodeRef of the given node
|
||||
*/
|
||||
@Override
|
||||
public Pair<Long, ContentUrlEntity> findByValue(ContentUrlEntity entity)
|
||||
{
|
||||
String contentUrl = entity.getContentUrl();
|
||||
ContentUrlEntity ret = getContentUrlEntity(contentUrl);
|
||||
return (ret != null ? new Pair<Long, ContentUrlEntity>(ret.getId(), ret) : null);
|
||||
}
|
||||
|
||||
public Pair<Long, ContentUrlEntity> createValue(ContentUrlEntity value)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = createContentUrlEntity(value.getContentUrl(), value.getSize(), value.getContentUrlKey());
|
||||
// Done
|
||||
return new Pair<Long, ContentUrlEntity>(contentUrlEntity.getId(), contentUrlEntity);
|
||||
}
|
||||
|
||||
public Pair<Long, ContentUrlEntity> findByKey(Long id)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = getContentUrlEntity(id);
|
||||
if (contentUrlEntity == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Done
|
||||
return new Pair<Long, ContentUrlEntity>(contentUrlEntity.getId(), contentUrlEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateValue(Long id, ContentUrlEntity value)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = getContentUrlEntity(id);
|
||||
if (contentUrlEntity == null)
|
||||
{
|
||||
return 0; // The client (outer-level code) will decide if this is an error
|
||||
}
|
||||
return updateContentUrlEntity(contentUrlEntity, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteByKey(Long id)
|
||||
{
|
||||
return deleteContentUrlEntity(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates this instance into an externally-usable <code>ContentData</code> instance.
|
||||
*/
|
||||
private ContentData makeContentData(ContentDataEntity contentDataEntity)
|
||||
{
|
||||
// Decode content URL
|
||||
String contentUrl = contentDataEntity.getContentUrl();
|
||||
Long contentUrlId = contentDataEntity.getContentUrlId();
|
||||
String contentUrl = null;
|
||||
if(contentUrlId != null)
|
||||
{
|
||||
Pair<Long, ContentUrlEntity> entityPair = contentUrlCache.getByKey(contentUrlId);
|
||||
if (entityPair == null)
|
||||
{
|
||||
throw new DataIntegrityViolationException("No ContentUrl value exists for ID " + contentUrlId);
|
||||
}
|
||||
ContentUrlEntity contentUrlEntity = entityPair.getSecond();
|
||||
contentUrl = contentUrlEntity.getContentUrl();
|
||||
}
|
||||
|
||||
long size = contentDataEntity.getSize() == null ? 0L : contentDataEntity.getSize().longValue();
|
||||
|
||||
// Decode mimetype
|
||||
Long mimetypeId = contentDataEntity.getMimetypeId();
|
||||
String mimetype = null;
|
||||
@@ -281,6 +403,7 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
{
|
||||
mimetype = mimetypeDAO.getMimetype(mimetypeId).getSecond();
|
||||
}
|
||||
|
||||
// Decode encoding
|
||||
Long encodingId = contentDataEntity.getEncodingId();
|
||||
String encoding = null;
|
||||
@@ -288,6 +411,7 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
{
|
||||
encoding = encodingDAO.getEncoding(encodingId).getSecond();
|
||||
}
|
||||
|
||||
// Decode locale
|
||||
Long localeId = contentDataEntity.getLocaleId();
|
||||
Locale locale = null;
|
||||
@@ -295,16 +419,17 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
{
|
||||
locale = localeDAO.getLocalePair(localeId).getSecond();
|
||||
}
|
||||
|
||||
// Build the ContentData
|
||||
ContentData contentData = new ContentData(contentUrl, mimetype, size, encoding, locale);
|
||||
// Done
|
||||
return contentData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translates the {@link ContentData} into persistable values using the helper DAOs
|
||||
*/
|
||||
private ContentDataEntity createContentDataEntity(ContentData contentData)
|
||||
protected ContentDataEntity createContentDataEntity(ContentData contentData)
|
||||
{
|
||||
// Resolve the content URL
|
||||
Long contentUrlId = null;
|
||||
@@ -312,9 +437,13 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
long size = contentData.getSize();
|
||||
if (contentUrl != null)
|
||||
{
|
||||
// We must find or create the ContentUrlEntity
|
||||
contentUrlId = getOrCreateContentUrlEntity(contentUrl, size).getId();
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setContentUrl(contentUrl);
|
||||
contentUrlEntity.setSize(size);
|
||||
Pair<Long, ContentUrlEntity> pair = contentUrlCache.getOrCreateByValue(contentUrlEntity);
|
||||
contentUrlId = pair.getFirst();
|
||||
}
|
||||
|
||||
// Resolve the mimetype
|
||||
Long mimetypeId = null;
|
||||
String mimetype = contentData.getMimetype();
|
||||
@@ -346,10 +475,22 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
/**
|
||||
* Translates the {@link ContentData} into persistable values using the helper DAOs
|
||||
*/
|
||||
private int updateContentDataEntity(ContentDataEntity contentDataEntity, ContentData contentData)
|
||||
protected int updateContentDataEntity(ContentDataEntity contentDataEntity, ContentData contentData)
|
||||
{
|
||||
// Resolve the content URL
|
||||
String oldContentUrl = contentDataEntity.getContentUrl();
|
||||
Long oldContentUrlId = contentDataEntity.getContentUrlId();
|
||||
ContentUrlEntity contentUrlEntity = null;
|
||||
if(oldContentUrlId != null)
|
||||
{
|
||||
Pair<Long, ContentUrlEntity> entityPair = contentUrlCache.getByKey(oldContentUrlId);
|
||||
if (entityPair == null)
|
||||
{
|
||||
throw new DataIntegrityViolationException("No ContentUrl value exists for ID " + oldContentUrlId);
|
||||
}
|
||||
contentUrlEntity = entityPair.getSecond();
|
||||
}
|
||||
|
||||
String oldContentUrl = (contentUrlEntity != null ? contentUrlEntity.getContentUrl() : null);
|
||||
String newContentUrl = contentData.getContentUrl();
|
||||
if (!EqualsHelper.nullSafeEquals(oldContentUrl, newContentUrl))
|
||||
{
|
||||
@@ -360,16 +501,23 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
}
|
||||
if (newContentUrl != null)
|
||||
{
|
||||
Long contentUrlId = getOrCreateContentUrlEntity(newContentUrl, contentData.getSize()).getId();
|
||||
contentDataEntity.setContentUrlId(contentUrlId);
|
||||
contentDataEntity.setContentUrl(newContentUrl);
|
||||
if(contentUrlEntity == null)
|
||||
{
|
||||
contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setContentUrl(newContentUrl);
|
||||
}
|
||||
Pair<Long, ContentUrlEntity> pair = contentUrlCache.getOrCreateByValue(contentUrlEntity);
|
||||
Long newContentUrlId = pair.getFirst();
|
||||
contentUrlEntity.setId(newContentUrlId);
|
||||
contentDataEntity.setContentUrlId(newContentUrlId);
|
||||
}
|
||||
else
|
||||
{
|
||||
contentDataEntity.setId(null);
|
||||
contentDataEntity.setContentUrlId(null);
|
||||
contentDataEntity.setContentUrl(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve the mimetype
|
||||
Long mimetypeId = null;
|
||||
String mimetype = contentData.getMimetype();
|
||||
@@ -391,84 +539,27 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
{
|
||||
localeId = localeDAO.getOrCreateLocalePair(locale).getFirst();
|
||||
}
|
||||
|
||||
|
||||
contentDataEntity.setMimetypeId(mimetypeId);
|
||||
contentDataEntity.setEncodingId(encodingId);
|
||||
contentDataEntity.setLocaleId(localeId);
|
||||
|
||||
return updateContentDataEntity(contentDataEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create (or get an existing) content URL. The URL will be unorphaned
|
||||
* whether it has been created or is being re-used.
|
||||
* @param isReferenced if <code>true</code> we won't worry about eagerly deleting the content on transaction rollback
|
||||
*/
|
||||
private ContentUrlEntity getOrCreateContentUrlEntity(String contentUrl, long size)
|
||||
{
|
||||
// Try to insert the content first. Usually, the insert will not clash with anything
|
||||
// as content URL re-use is far less frequent than new content creation.
|
||||
ContentUrlEntity contentUrlEntity = null;
|
||||
Savepoint savepoint = controlDAO.createSavepoint("getOrCreateContentUrlEntity");
|
||||
try
|
||||
{
|
||||
contentUrlEntity = createContentUrlEntity(contentUrl, size);
|
||||
controlDAO.releaseSavepoint(savepoint);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
controlDAO.rollbackToSavepoint(savepoint);
|
||||
// See if this was caused by an existing URL
|
||||
contentUrlEntity = getContentUrlEntity(contentUrl);
|
||||
// If it exists, then we can just re-use it, but check that the size is consistent
|
||||
if (contentUrlEntity == null)
|
||||
{
|
||||
// The error was caused by something else. Perhaps another, as-yet-unseen
|
||||
// row clashes with this. Just propagate the exception and let retrying
|
||||
// happen as required.
|
||||
throw e;
|
||||
}
|
||||
// Reuse it
|
||||
long existingSize = contentUrlEntity.getSize();
|
||||
if (size != existingSize)
|
||||
{
|
||||
logger.warn(
|
||||
"Re-using Content URL, but size is mismatched: \n" +
|
||||
" Inbound: " + contentUrl + "\n" +
|
||||
" Existing: " + contentUrlEntity);
|
||||
}
|
||||
// Check orphan state
|
||||
Long oldOrphanTime = contentUrlEntity.getOrphanTime();
|
||||
if (oldOrphanTime != null)
|
||||
{
|
||||
Long id = contentUrlEntity.getId();
|
||||
int updated = updateContentUrlOrphanTime(id, null, oldOrphanTime);
|
||||
if (updated == 0)
|
||||
{
|
||||
throw new ConcurrencyFailureException("Failed to remove orphan time: " + contentUrlEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Done
|
||||
return contentUrlEntity;
|
||||
return updateContentDataEntity(contentDataEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentUrl the content URL to create or search for
|
||||
*/
|
||||
protected abstract ContentUrlEntity createContentUrlEntity(String contentUrl, long size);
|
||||
|
||||
protected abstract ContentUrlEntity createContentUrlEntity(String contentUrl, long size, ContentUrlKeyEntity contentUrlKey);
|
||||
|
||||
/**
|
||||
* @param id the ID of the <b>content url</b> entity
|
||||
* @return Return the entity or <tt>null</tt> if it doesn't exist
|
||||
*/
|
||||
protected abstract ContentUrlEntity getContentUrlEntity(Long id);
|
||||
|
||||
/**
|
||||
* @param contentUrl the URL of the <b>content url</b> entity
|
||||
* @return Return the entity or <tt>null</tt> if it doesn't exist
|
||||
*/
|
||||
|
||||
protected abstract ContentUrlEntity getContentUrlEntity(String contentUrl);
|
||||
|
||||
|
||||
/**
|
||||
* @param contentUrl the URL of the <b>content url</b> entity
|
||||
@@ -501,7 +592,7 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
* @return Returns the entity or <tt>null</tt> if it doesn't exist
|
||||
*/
|
||||
protected abstract ContentDataEntity getContentDataEntity(Long id);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param nodeIds the node ID
|
||||
@@ -516,14 +607,16 @@ public abstract class AbstractContentDataDAOImpl implements ContentDataDAO
|
||||
* @return Returns the number of rows updated (should be 1)
|
||||
*/
|
||||
protected abstract int updateContentDataEntity(ContentDataEntity entity);
|
||||
|
||||
|
||||
/**
|
||||
* Delete the entity with the given ID
|
||||
*
|
||||
* @return Returns the number of rows deleted
|
||||
*/
|
||||
protected abstract int deleteContentDataEntity(Long id);
|
||||
|
||||
protected abstract int deleteContentUrlEntity(long id);
|
||||
protected abstract int updateContentUrlEntity(ContentUrlEntity existing, ContentUrlEntity entity);
|
||||
|
||||
/**
|
||||
* Transactional listener that deletes unreferenced <b>content_url</b> entities.
|
||||
*
|
||||
|
@@ -118,4 +118,51 @@ public interface ContentDataDAO
|
||||
* Delete a batch of content URL entities.
|
||||
*/
|
||||
int deleteContentUrls(List<Long> ids);
|
||||
|
||||
/**
|
||||
* Get a content url entity by contentUrl
|
||||
*
|
||||
* @since 5.0
|
||||
* @param contentUrl
|
||||
* @return
|
||||
*/
|
||||
ContentUrlEntity getContentUrl(String contentUrl);
|
||||
|
||||
/**
|
||||
* Get a content url entity by contentUrlId
|
||||
*
|
||||
* @since 5.0
|
||||
* @param contentUrlId
|
||||
* @return
|
||||
*/
|
||||
ContentUrlEntity getContentUrl(Long contentUrlId);
|
||||
|
||||
/**
|
||||
* Update a content url
|
||||
*
|
||||
* @since 5.0
|
||||
* @param contentUrlEntity
|
||||
* @return
|
||||
*/
|
||||
void updateContentUrl(ContentUrlEntity contentUrlEntity);
|
||||
|
||||
/**
|
||||
* Get symmetric keys entities for symmetric keys that have been encrypted using the given
|
||||
* master key, starting from 'fromId' and returning at most 'maxResults' entities.
|
||||
*
|
||||
* @since 5.0
|
||||
* @param contentUrlEntity
|
||||
* @return
|
||||
*/
|
||||
List<ContentUrlKeyEntity> getSymmetricKeysByMasterKeyAlias(String masterKeyAlias, long fromId, int maxResults);
|
||||
|
||||
/**
|
||||
* Count symmetric keys entities for symmetric keys that have been encrypted using the given
|
||||
* master key
|
||||
*
|
||||
* @since 5.0
|
||||
* @param masterKeyAlias
|
||||
* @return
|
||||
*/
|
||||
int countSymmetricKeysForMasterKeyAlias(String masterKeyAlias);
|
||||
}
|
||||
|
@@ -36,7 +36,6 @@ public class ContentDataEntity
|
||||
private Long id;
|
||||
private Long version;
|
||||
private Long contentUrlId;
|
||||
private String contentUrl;
|
||||
private Long size;
|
||||
private Long mimetypeId;
|
||||
private Long encodingId;
|
||||
@@ -45,8 +44,8 @@ public class ContentDataEntity
|
||||
public ContentDataEntity()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return (id == null ? 0 : id.hashCode());
|
||||
@@ -69,15 +68,14 @@ public class ContentDataEntity
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("ContentDataEntity")
|
||||
.append("[ ID=").append(id)
|
||||
.append(", contentUrlId=").append(contentUrlId)
|
||||
.append(", contentUrl=").append(contentUrl)
|
||||
.append(", size=").append(size)
|
||||
.append(", mimetype=").append(mimetypeId)
|
||||
.append(", encoding=").append(encodingId)
|
||||
@@ -128,16 +126,6 @@ public class ContentDataEntity
|
||||
this.contentUrlId = contentUrlId;
|
||||
}
|
||||
|
||||
public String getContentUrl()
|
||||
{
|
||||
return contentUrl;
|
||||
}
|
||||
|
||||
public void setContentUrl(String contentUrl)
|
||||
{
|
||||
this.contentUrl = contentUrl;
|
||||
}
|
||||
|
||||
public Long getSize()
|
||||
{
|
||||
return size;
|
||||
|
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.alfresco.repo.domain.contentdata;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.alfresco.repo.domain.CrcHelper;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
@@ -31,9 +33,13 @@ import org.alfresco.util.Pair;
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class ContentUrlEntity
|
||||
public class ContentUrlEntity implements Serializable
|
||||
{
|
||||
public static final Long CONST_LONG_ZERO = new Long(0L);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -7697859151521433536L;
|
||||
public static final Long CONST_LONG_ZERO = new Long(0L);
|
||||
public static final String EMPTY_URL = "empty";
|
||||
|
||||
private Long id;
|
||||
@@ -42,7 +48,9 @@ public class ContentUrlEntity
|
||||
private long contentUrlCrc;
|
||||
private long size;
|
||||
private Long orphanTime;
|
||||
|
||||
|
||||
private ContentUrlKeyEntity contentUrlKey;
|
||||
|
||||
public ContentUrlEntity()
|
||||
{
|
||||
this.size = 0L;
|
||||
@@ -114,7 +122,31 @@ public class ContentUrlEntity
|
||||
}
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
public ContentUrlKeyEntity getContentUrlKey()
|
||||
{
|
||||
return contentUrlKey;
|
||||
}
|
||||
|
||||
public static ContentUrlEntity setContentUrlKey(ContentUrlEntity existing, ContentUrlKeyEntity contentUrlKey)
|
||||
{
|
||||
ContentUrlEntity ret = new ContentUrlEntity();
|
||||
ret.setContentUrl(existing == null ? null : existing.getContentUrl());
|
||||
ret.setContentUrlShort(existing == null ? null : existing.getContentUrlShort());
|
||||
ret.setContentUrlCrc(existing == null ? null : existing.getContentUrlCrc());
|
||||
ret.setContentUrlKey(contentUrlKey);
|
||||
ret.setOrphanTime(existing == null ? null : existing.getOrphanTime());
|
||||
ret.setSize(existing == null ? null : existing.getSize());
|
||||
ret.setId(existing == null ? null : existing.getId());
|
||||
// done
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setContentUrlKey(ContentUrlKeyEntity contentUrlKey)
|
||||
{
|
||||
this.contentUrlKey = contentUrlKey;
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
@@ -0,0 +1,150 @@
|
||||
package org.alfresco.repo.domain.contentdata;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.alfresco.service.cmr.repository.ContentUrlKey;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sglover
|
||||
*
|
||||
*/
|
||||
public class ContentUrlKeyEntity implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = -6594309522849585169L;
|
||||
|
||||
private Long id;
|
||||
private Long contentUrlId;
|
||||
private byte[] encryptedKeyAsBytes;
|
||||
private Integer keySize;
|
||||
private String algorithm;
|
||||
private String masterKeystoreId;
|
||||
private String masterKeyAlias;
|
||||
private Long unencryptedFileSize;
|
||||
|
||||
public ContentUrlKeyEntity()
|
||||
{
|
||||
}
|
||||
|
||||
public ContentUrlKey getContentUrlKey() throws DecoderException
|
||||
{
|
||||
ContentUrlKey contentUrlKey = new ContentUrlKey();
|
||||
contentUrlKey.setAlgorithm(algorithm);
|
||||
contentUrlKey.setKeySize(keySize);
|
||||
contentUrlKey.setEncryptedKeyBytes(ByteBuffer.wrap(encryptedKeyAsBytes));
|
||||
contentUrlKey.setMasterKeyAlias(masterKeyAlias);
|
||||
contentUrlKey.setMasterKeystoreId(masterKeystoreId);
|
||||
contentUrlKey.setUnencryptedFileSize(unencryptedFileSize);
|
||||
return contentUrlKey;
|
||||
}
|
||||
|
||||
public Long getContentUrlId()
|
||||
{
|
||||
return contentUrlId;
|
||||
}
|
||||
|
||||
public void setContentUrlId(Long contentUrlId)
|
||||
{
|
||||
this.contentUrlId = contentUrlId;
|
||||
}
|
||||
|
||||
public void setEncryptedKeyAsBytes(byte[] encryptedKeyAsBytes)
|
||||
{
|
||||
this.encryptedKeyAsBytes = encryptedKeyAsBytes;
|
||||
}
|
||||
|
||||
public byte[] getEncryptedKeyAsBytes()
|
||||
{
|
||||
return encryptedKeyAsBytes;
|
||||
}
|
||||
|
||||
public void updateEncryptedKey(EncryptedKey encryptedKey)
|
||||
{
|
||||
byte[] encryptedKeyAsBytes = new byte[encryptedKey.getByteBuffer().remaining()];
|
||||
encryptedKey.getByteBuffer().get(encryptedKeyAsBytes);
|
||||
this.encryptedKeyAsBytes = encryptedKeyAsBytes;
|
||||
setKeySize(encryptedKeyAsBytes.length*8);
|
||||
setAlgorithm(encryptedKey.getAlgorithm());
|
||||
setMasterKeyAlias(encryptedKey.getMasterKeyAlias());
|
||||
setMasterKeystoreId(encryptedKey.getMasterKeystoreId());
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public EncryptedKey getEncryptedKey() throws DecoderException
|
||||
{
|
||||
EncryptedKey encryptedKey = new EncryptedKey(getMasterKeystoreId(), getMasterKeyAlias(),
|
||||
getAlgorithm(), ByteBuffer.wrap(this.encryptedKeyAsBytes));
|
||||
return encryptedKey;
|
||||
}
|
||||
|
||||
public Long getUnencryptedFileSize()
|
||||
{
|
||||
return unencryptedFileSize;
|
||||
}
|
||||
|
||||
public void setUnencryptedFileSize(Long unencryptedFileSize)
|
||||
{
|
||||
this.unencryptedFileSize = unencryptedFileSize;
|
||||
}
|
||||
|
||||
public void setKeySize(Integer keySize)
|
||||
{
|
||||
this.keySize = keySize;
|
||||
}
|
||||
|
||||
public Integer getKeySize()
|
||||
{
|
||||
return keySize;
|
||||
}
|
||||
|
||||
public String getAlgorithm()
|
||||
{
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public void setAlgorithm(String algorithm)
|
||||
{
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public String getMasterKeystoreId()
|
||||
{
|
||||
return masterKeystoreId;
|
||||
}
|
||||
|
||||
public void setMasterKeystoreId(String masterKeystoreId)
|
||||
{
|
||||
this.masterKeystoreId = masterKeystoreId;
|
||||
}
|
||||
|
||||
public String getMasterKeyAlias()
|
||||
{
|
||||
return masterKeyAlias;
|
||||
}
|
||||
|
||||
public void setMasterKeyAlias(String masterKeyAlias)
|
||||
{
|
||||
this.masterKeyAlias = masterKeyAlias;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ContentUrlKeyEntity [id=" + id + ", encryptedKeyAsBytes="
|
||||
+ encryptedKeyAsBytes+ ", keySize=" + keySize + ", algorithm="
|
||||
+ algorithm + ", masterKeystoreId=" + masterKeystoreId
|
||||
+ ", masterKeyAlias=" + masterKeyAlias
|
||||
+ ", unencryptedFileSize=" + unencryptedFileSize + "]";
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package org.alfresco.repo.domain.contentdata;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class EncryptedKey implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String masterKeystoreId;
|
||||
private String masterKeyAlias;
|
||||
private final String algorithm;
|
||||
private final ByteBuffer encryptedKeyBytes;
|
||||
|
||||
public EncryptedKey(String masterKeystoreId, String masterKeyAlias, String algorithm, ByteBuffer encryptedKeyBytes)
|
||||
{
|
||||
this.masterKeyAlias = masterKeyAlias;
|
||||
this.masterKeystoreId = masterKeystoreId;
|
||||
this.algorithm = algorithm;
|
||||
this.encryptedKeyBytes = encryptedKeyBytes.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
public String getMasterKeystoreId()
|
||||
{
|
||||
return masterKeystoreId;
|
||||
}
|
||||
|
||||
public String getMasterKeyAlias()
|
||||
{
|
||||
return masterKeyAlias;
|
||||
}
|
||||
|
||||
public ByteBuffer getEncryptedKeyBytes()
|
||||
{
|
||||
return encryptedKeyBytes;
|
||||
}
|
||||
|
||||
public String getAlgorithm()
|
||||
{
|
||||
return this.algorithm;
|
||||
}
|
||||
|
||||
public ByteBuffer getByteBuffer()
|
||||
{
|
||||
return this.encryptedKeyBytes.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
public int keySize()
|
||||
{
|
||||
byte[] eKey = new byte[getByteBuffer().remaining()];
|
||||
getByteBuffer().get(eKey);
|
||||
return eKey.length * 8;
|
||||
}
|
||||
|
||||
}
|
@@ -31,9 +31,11 @@ import org.alfresco.ibatis.IdsEntity;
|
||||
import org.alfresco.repo.domain.contentdata.AbstractContentDataDAOImpl;
|
||||
import org.alfresco.repo.domain.contentdata.ContentDataEntity;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlEntity;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlKeyEntity;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlOrphanQuery;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlUpdateEntity;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.apache.ibatis.session.RowBounds;
|
||||
@@ -45,6 +47,7 @@ import org.springframework.dao.DataIntegrityViolationException;
|
||||
* iBatis-specific implementation of the ContentData DAO.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @author sglover
|
||||
* @since 3.2
|
||||
*/
|
||||
public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
@@ -62,16 +65,20 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
private static final String UPDATE_CONTENT_DATA = "alfresco.content.update_ContentData";
|
||||
private static final String DELETE_CONTENT_DATA = "alfresco.content.delete_ContentData";
|
||||
private static final String DELETE_CONTENT_URLS = "alfresco.content.delete_ContentUrls";
|
||||
|
||||
|
||||
private SqlSessionTemplate template;
|
||||
private static final String DELETE_CONTENT_URL_KEYS = "alfresco.content.delete_ContentUrlKeys";
|
||||
private static final String DELETE_SYMMETRIC_KEY = "alfresco.content.delete_KeyData";
|
||||
private static final String UPDATE_SYMMETRIC_KEY = "alfresco.content.update_KeyData";
|
||||
private static final String INSERT_SYMMETRIC_KEY = "alfresco.content.insert.insert_KeyData";
|
||||
private static final String SELECT_SYMMETRIC_KEYS_BY_MASTER_KEY = "alfresco.content.select_SymmetricKeysByMasterKey";
|
||||
private static final String COUNT_SYMMETRIC_KEYS_BY_MASTER_KEY = "alfresco.content.select_CountSymmetricKeysByMasterKey";
|
||||
|
||||
protected SqlSessionTemplate template;
|
||||
|
||||
public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)
|
||||
{
|
||||
this.template = sqlSessionTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Pair<Long, String> createContentUrlOrphaned(String contentUrl, Date orphanTime)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
@@ -85,7 +92,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentUrlEntity createContentUrlEntity(String contentUrl, long size)
|
||||
protected ContentUrlEntity createContentUrlEntity(String contentUrl, long size, ContentUrlKeyEntity contentUrlKeyEntity)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setContentUrl(contentUrl);
|
||||
@@ -93,7 +100,14 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
contentUrlEntity.setOrphanTime(null);
|
||||
/* Long id = (Long) */ template.insert(INSERT_CONTENT_URL, contentUrlEntity);
|
||||
/*contentUrlEntity.setId(id);*/
|
||||
|
||||
|
||||
if(contentUrlKeyEntity != null)
|
||||
{
|
||||
template.insert(INSERT_SYMMETRIC_KEY, contentUrlKeyEntity);
|
||||
|
||||
// contentUrlEntity.setContentUrlKey(contentUrlKeyEntity);
|
||||
}
|
||||
|
||||
// Done
|
||||
return contentUrlEntity;
|
||||
}
|
||||
@@ -103,13 +117,13 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setId(id);
|
||||
contentUrlEntity = template.selectOne(SELECT_CONTENT_URL_BY_ID, contentUrlEntity);
|
||||
contentUrlEntity = (ContentUrlEntity) template.selectOne(SELECT_CONTENT_URL_BY_ID, contentUrlEntity);
|
||||
// Done
|
||||
return contentUrlEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentUrlEntity getContentUrlEntity(String contentUrl)
|
||||
public ContentUrlEntity getContentUrlEntity(String contentUrl)
|
||||
{
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setContentUrl(contentUrl);
|
||||
@@ -122,7 +136,6 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
return contentUrlEntity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getContentUrlsOrphaned(
|
||||
final ContentUrlHandler contentUrlHandler,
|
||||
final Long maxOrphanTimeExclusive,
|
||||
@@ -132,7 +145,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
|
||||
ContentUrlOrphanQuery query = new ContentUrlOrphanQuery();
|
||||
query.setMaxOrphanTimeExclusive(maxOrphanTimeExclusive);
|
||||
List<ContentUrlEntity> results = template.selectList(SELECT_CONTENT_URLS_ORPHANED,
|
||||
List<ContentUrlEntity> results = template.selectList(SELECT_CONTENT_URLS_ORPHANED,
|
||||
query,
|
||||
new RowBounds(0, maxResults));
|
||||
// Pass the result to the callback
|
||||
@@ -159,6 +172,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
*/
|
||||
public int deleteContentUrls(List<Long> ids)
|
||||
{
|
||||
template.delete(DELETE_CONTENT_URL_KEYS, ids);
|
||||
return template.delete(DELETE_CONTENT_URLS, ids);
|
||||
}
|
||||
|
||||
@@ -171,7 +185,7 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
{
|
||||
contentUrlEntity.setContentUrlShort(contentUrlEntity.getContentUrlShort().toLowerCase());
|
||||
}
|
||||
contentUrlEntity = template.selectOne(SELECT_CONTENT_URL_BY_KEY_UNREFERENCED, contentUrlEntity);
|
||||
contentUrlEntity = (ContentUrlEntity) template.selectOne(SELECT_CONTENT_URL_BY_KEY_UNREFERENCED, contentUrlEntity);
|
||||
// Done
|
||||
return contentUrlEntity;
|
||||
}
|
||||
@@ -206,12 +220,11 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>(11);
|
||||
params.put("id", id);
|
||||
ContentDataEntity contentDataEntity = template.selectOne(SELECT_CONTENT_DATA_BY_ID, params);
|
||||
ContentDataEntity contentDataEntity = (ContentDataEntity) template.selectOne(SELECT_CONTENT_DATA_BY_ID, params);
|
||||
// Done
|
||||
return contentDataEntity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected List<ContentDataEntity> getContentDataEntitiesForNodes(Set<Long> nodeIds)
|
||||
{
|
||||
@@ -266,7 +279,6 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
IdsEntity idsEntity = new IdsEntity();
|
||||
idsEntity.setIdOne(nodeId);
|
||||
idsEntity.setIds(new ArrayList<Long>(qnameIds));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Long> ids = template.selectList(SELECT_CONTENT_DATA_BY_NODE_AND_QNAME, idsEntity);
|
||||
// Delete each one
|
||||
for (Long id : ids)
|
||||
@@ -284,4 +296,49 @@ public class ContentDataDAOImpl extends AbstractContentDataDAOImpl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int updateContentUrlEntity(ContentUrlEntity existing, ContentUrlEntity entity)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ContentUrlKeyEntity existingContentUrlKey = existing.getContentUrlKey();
|
||||
ContentUrlKeyEntity contentUrlKey = entity.getContentUrlKey();
|
||||
contentUrlKey.setContentUrlId(existing.getId());
|
||||
if(existingContentUrlKey == null)
|
||||
{
|
||||
ret = template.insert(INSERT_SYMMETRIC_KEY, contentUrlKey);
|
||||
}
|
||||
else if (!EqualsHelper.nullSafeEquals(existingContentUrlKey, contentUrlKey))
|
||||
{
|
||||
ret = template.update(UPDATE_SYMMETRIC_KEY, contentUrlKey);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int deleteContentUrlEntity(long id)
|
||||
{
|
||||
Map<String, Object> params = new HashMap<String, Object>(11);
|
||||
params.put("id", id);
|
||||
return template.delete(DELETE_SYMMETRIC_KEY, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ContentUrlKeyEntity> getSymmetricKeysByMasterKeyAlias(String masterKeyAlias, long fromId, int maxResults)
|
||||
{
|
||||
ContentUrlKeyEntity entity = new ContentUrlKeyEntity();
|
||||
entity.setMasterKeyAlias(masterKeyAlias);
|
||||
entity.setId(fromId);
|
||||
List<ContentUrlKeyEntity> results = template.selectList(SELECT_SYMMETRIC_KEYS_BY_MASTER_KEY,
|
||||
entity, new RowBounds(0, maxResults));
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countSymmetricKeysForMasterKeyAlias(String masterKeyAlias)
|
||||
{
|
||||
return (Integer)template.selectOne(COUNT_SYMMETRIC_KEYS_BY_MASTER_KEY, masterKeyAlias);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user