Merged V4.0-BUG-FIX to HEAD

33836: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock
   33842: Fixes ALF-12797: i18n strings in activiti-admin login-screen escaped properly
   33844: Fix for ALF-10651 Fix patches that trigger reindexing and ALF-10656 SOLR: Patches execute search during bootstrap causing deadlock
   - batch touch to limit the in clause size generated
   33845: Manually added extra core Share extensions needed for the V4.0 Records Management module from the development branch.
   - Refactored JSON property decorators for the Document Library data webscripts
   - Document List banners (e.g. working copy) moved into metadata template config
   - Ability to override default document/folder title within Document Library (<title> element in metadata template - unused in core code)
   - Additional extension point in surf-doclist to override remote data URL
   - Better handling for missing content property
   33852: ALF-12725: Merged V3.4-BUG-FIX (3.4.9) to V4.0-BUG-FIX (4.0.1)
      33849: Merged V3 (3.4.8) to V3.4-BUG-FIX (3.4.9)
         33848: ALF-10976 (relates to ALF-10412)
            Fixed bug to do with preview being stuck as always being 'Content cannot be previewed.
            Do you wish to download?' or a 'blank preview after a transformer is not found' for all
            content with the same mimetype. Cache in ThumbnailRegistory.getThumbnailDefinitions()
            now understands that transformers may have an upper content size limit. The choice between
            the two options was based on the size of the first file previewed of each mimetype.
            Needed to add getMaxSourceSizeBytes() to support this (see below).
            - refactored (previous refactor was incomplete) ContentTransformer so that
              the two halfs of isTransformable is now split into sub methods
              isTransformableMimetypes and isTransformableSize.
              This is why there are so many files changed.
            - Moved getMaxSourceSizeBytes() from AbstractContentTransformerLimits to ContentTransformer as
              there were becomming too many places in the code that needed needed to check if the ContentTransformer
              was an instanceof AbstractContentTransformerLimits before calling this method.
            - TransformerDebug now uses KB MB GB values in output to make it simpler to read.
            - TransformerDebug now uses thousand separaters in millisecond values to make it simpler to read.
            - TransformerDebug now reports the 'parent' transformer name rather than the sub-transformer name 
              when an unavailable transformer is found. Makes it simpler to tie up with the 'available transformer'
              list with the new pushIsTransformableSize() calls.
            - TransformerDebug now uses trace logging for calls from ThumbnailRegistory.isThumbnailDefinitionAvailable()
              as it is normally followed by a ContentService.transform() which is logged at debug level anyway.
            - TransformerDebug now turns logging level to trace if the file size is 0 bytes. Request from Jan.
              Not sure how one uploads such a file!
            - Modified ComplexContentTransformer.isTransformable() so that it checks the mimetypes before the sizes
              so that TransformerDebug does not report 'unavailable transformers' that don't support the
              mimetype conversion.
            - Modified ComplexContentTransformer.getLimits and ComplexContentTransformer.isPageLimitSupported()
              to include the limits from the first sub transformer.
              Was not an issue until ContentTransformer.getMaxSourceSizeBytes() was introduced.
            - Added logger to RhinoScriptProcessor to debug requests run javascript on the server.
            - Dropped the sourceUrl parameter from ThumbnailRegistry.getThumbnailDefinitions() which was
              introduced with limits as it is logicall not needed.
   33853: DiskInterface.renameFile() can now throw PermissionDeniedException to return a different status to the client. Part of ALF-12717.
   33856: Merged V3.4-BUG-FIX to V4.0-BUG-FIX
      33835: ALF-12546: Remove references to retired RegPaths.exe from installed apply_amps.bat script
      33843: Fix for ALF-12775
      33855: Merged V3.4 to V3.4-BUG-FIX
         33851: ALF-12588: Documents Intermittently Do Not Appear in Share
            - Fix by Alex Busel for regression I accidentally caused in 3.4.6
            - Simple typo in mergeDeletions() caused path deletions to sometimes not get applied or get processed twice
            - Yikes!


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@33857 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-02-13 12:24:24 +00:00
parent ac387f5f7b
commit c3a622e3c4
50 changed files with 1916 additions and 801 deletions

View File

@@ -19,91 +19,134 @@
package org.alfresco.repo.admin.patch.impl;
import java.util.List;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.util.Pair;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Patch usr:user and cm:person objects so that the user name properties are in the
* index in untokenized form. If not authentication may fail in mixed language use.
* Patch usr:user and cm:person objects so that the user name properties are in the index in untokenized form. If not
* authentication may fail in mixed language use.
*
* @author andyh
*
*/
public class CalendarModelUriPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.calendarModelNamespacePatch.result";
private static final String URI_BEFORE = "com.infoaxon.alfresco.calendar";
private static final String URI_AFTER = "http://www.alfresco.org/model/calendar";
private ImporterBootstrap importerBootstrap;
private IndexerAndSearcher indexerAndSearcher;
private static final String URI_AFTER = "http://www.alfresco.org/model/calendar";
private QNameDAO qnameDAO;
private PatchDAO patchDAO;
private NodeDAO nodeDAO;
private RetryingTransactionHelper retryingTransactionHelper;
private static long BATCH_SIZE = 100000L;
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
{
this.importerBootstrap = importerBootstrap;
}
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
{
this.indexerAndSearcher = indexerAndSearcher;
}
/**
* @param qnameDAO the qnameDAO to set
*/
public void setQnameDAO(QNameDAO qnameDAO)
{
this.qnameDAO = qnameDAO;
}
/**
* @param patchDAO the patchDAO to set
*/
public void setPatchDAO(PatchDAO patchDAO)
{
this.patchDAO = patchDAO;
}
/**
* @param nodeDAO the nodeDAO to set
*/
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
/**
* @param retryingTransactionHelper the retryingTransactionHelper to set
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(patchDAO, "patchDAO");
checkPropertyNotNull(qnameDAO, "qnameDAO");
checkPropertyNotNull(nodeDAO, "nodeDAO");
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
}
@Override
protected String applyInternal() throws Exception
{
Long maxNodeId = patchDAO.getMaxAdmNodeID();
long count = 0L;
// Make sure the old name spaces exists before we update it ...
qnameDAO.getOrCreateNamespace(URI_BEFORE);
Pair<Long, String> before = qnameDAO.getOrCreateNamespace(URI_BEFORE);
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
{
Work work = new Work(before.getFirst(), i);
count += retryingTransactionHelper.doInTransaction(work, false, true);
}
// modify namespace for all calendar entries
qnameDAO.updateNamespace(URI_BEFORE, URI_AFTER);
// reindex the calendar entries
int count = reindex("TYPE:\\{" + AbstractLuceneQueryParser.escape(URI_BEFORE) + "\\}*", importerBootstrap.getStoreRef());
return I18NUtil.getMessage(MSG_SUCCESS, count);
}
private int reindex(String query, StoreRef store)
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
{
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
sp.addStore(store);
Indexer indexer = indexerAndSearcher.getIndexer(store);
ResultSet rs = null;
int count = 0;
try
long nsId;
long lower;
Work(long nsId, long lower)
{
rs = searchService.query(sp);
count = rs.length();
for (ResultSetRow row : rs)
{
indexer.updateNode(row.getNodeRef());
}
this.nsId = nsId;
this.lower = lower;
}
finally
/*
* (non-Javadoc)
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
*/
@Override
public Integer execute() throws Throwable
{
if (rs != null)
{
rs.close();
}
List<Long> nodeIds = patchDAO.getNodesByTypeUriId(nsId, lower, lower + BATCH_SIZE);
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
return nodeIds.size();
}
return count;
}
}

View File

@@ -18,23 +18,15 @@
*/
package org.alfresco.repo.admin.patch.impl;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.domain.mimetype.MimetypeDAO;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.util.Pair;
import org.springframework.extensions.surf.util.I18NUtil;
@@ -57,18 +49,21 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
private static final String MSG_DONE_REINDEX = "patch.genericMimetypeUpdate.doneReindex";
/* Helper DAOs */
private IndexerAndSearcher indexerAndSearcher;
private MimetypeDAO mimetypeDAO;
private PatchDAO patchDAO;
private NodeDAO nodeDAO;
private RetryingTransactionHelper retryingTransactionHelper;
private static long BATCH_SIZE = 100000L;
/** Mimetype mappings */
private Map<String, String> mimetypeMappings;
private boolean reindex;
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
{
this.indexerAndSearcher = indexerAndSearcher;
}
public void setMimetypeDAO(MimetypeDAO mimetypeDAO)
{
@@ -90,36 +85,46 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
this.reindex = reindex;
}
/**
* @param nodeDAO the nodeDAO to set
*/
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
/**
* @param retryingTransactionHelper the retryingTransactionHelper to set
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(indexerAndSearcher, "indexerAndSearcher");
checkPropertyNotNull(mimetypeDAO, "mimetypeDAO");
checkPropertyNotNull(patchDAO, "patchDAO");
checkPropertyNotNull(mimetypeMappings, "mimetypeMappings");
checkPropertyNotNull(nodeDAO, "nodeDAO");
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
}
@Override
protected String applyInternal() throws Exception
{
// First get all the available stores that we might want to reindex
List<StoreRef> storeRefsList = nodeService.getStores();
Set<StoreRef> storeRefs = new HashSet<StoreRef>();
for (StoreRef storeRef : storeRefsList)
{
// We want workspace://SpacesStore or related MT stores
if (storeRef.getIdentifier().endsWith("SpacesStore"))
{
storeRefs.add(storeRef);
}
}
StringBuilder result = new StringBuilder(I18NUtil.getMessage(MSG_START));
Long maxNodeId = patchDAO.getMaxAdmNodeID();
for (Map.Entry<String, String> element : mimetypeMappings.entrySet())
{
String oldMimetype = element.getKey();
String newMimetype = element.getValue();
// First check if the mimetype is used at all
Pair<Long, String> oldMimetypePair = mimetypeDAO.getMimetype(oldMimetype);
if (oldMimetypePair == null)
@@ -127,7 +132,20 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
// Not used
continue;
}
// pull all affectsed nodes into a new transaction id indexed
if(reindex)
{
long count = 0L;
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
{
Work work = new Work(oldMimetypePair.getFirst(), i);
count += retryingTransactionHelper.doInTransaction(work, false, true);
}
result.append(I18NUtil.getMessage(MSG_INDEXED, count, "(All stores)"));
}
// Check if the new mimetype exists
Pair<Long, String> newMimetypePair = mimetypeDAO.getMimetype(newMimetype);
int updateCount = 0;
@@ -144,16 +162,6 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
updateCount = patchDAO.updateContentMimetypeIds(oldMimetypeId, newMimetypeId);
}
result.append(I18NUtil.getMessage(MSG_UPDATED, updateCount, oldMimetype, newMimetype));
if (reindex)
{
// Update Lucene
int reindexCount = 0;
for (StoreRef storeRef : storeRefs)
{
reindexCount += reindex(oldMimetype, storeRef);
result.append(I18NUtil.getMessage(MSG_INDEXED, reindexCount, storeRef));
}
}
}
// Done
if (reindex)
@@ -167,33 +175,30 @@ public class GenericMimetypeRenamePatch extends AbstractPatch
return result.toString();
}
private int reindex(String oldMimetype, StoreRef store)
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
{
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery("@" + AbstractLuceneQueryParser.escape(ContentModel.PROP_CONTENT.toString()) +
".mimetype:\"" + oldMimetype + "\"");
sp.addStore(store);
Indexer indexer = indexerAndSearcher.getIndexer(store);
ResultSet rs = null;
int count = 0;
try
long mimetypeId;
long lower;
Work(long mimetypeId, long lower)
{
rs = searchService.query(sp);
count = rs.length();
for (ResultSetRow row : rs)
{
indexer.updateNode(row.getNodeRef());
}
this.mimetypeId = mimetypeId;
this.lower = lower;
}
finally
/*
* (non-Javadoc)
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
*/
@Override
public Integer execute() throws Throwable
{
if (rs != null)
{
rs.close();
}
List<Long> nodeIds = patchDAO.getNodesByContentPropertyMimetypeId(mimetypeId, lower, lower + BATCH_SIZE);
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
return nodeIds.size();
}
return count;
}
}

View File

@@ -19,18 +19,15 @@
package org.alfresco.repo.admin.patch.impl;
import java.util.List;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.patch.PatchDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.importer.ImporterBootstrap;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.IndexerAndSearcher;
import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.ResultSetRow;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.springframework.extensions.surf.util.I18NUtil;
/**
@@ -56,38 +53,50 @@ public class QNamePatch extends AbstractPatch
private String qnameStringAfter;
private String reindexClass;
/* Injected services */
private ImporterBootstrap importerBootstrap;
private IndexerAndSearcher indexerAndSearcher;
private QNameDAO qnameDAO;
/**
* Sets the importerBootstrap.
* @param importerBootstrap.
*/
public void setImporterBootstrap(ImporterBootstrap importerBootstrap)
{
this.importerBootstrap = importerBootstrap;
}
private PatchDAO patchDAO;
private NodeDAO nodeDAO;
private RetryingTransactionHelper retryingTransactionHelper;
private static long BATCH_SIZE = 100000L;
/**
* Sets the IndexerAndSearcher.
* @param indexerAndSearcher
*/
public void setIndexerAndSearcher(IndexerAndSearcher indexerAndSearcher)
{
this.indexerAndSearcher = indexerAndSearcher;
}
/**
* Sets the QNameDAO.
* @param qnameDAO
* @param qnameDAO the qnameDAO to set
*/
public void setQnameDAO(QNameDAO qnameDAO)
{
this.qnameDAO = qnameDAO;
}
/**
* @param patchDAO the patchDAO to set
*/
public void setPatchDAO(PatchDAO patchDAO)
{
this.patchDAO = patchDAO;
}
/**
* @param nodeDAO the nodeDAO to set
*/
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
/**
* @param retryingTransactionHelper the retryingTransactionHelper to set
*/
public void setRetryingTransactionHelper(RetryingTransactionHelper retryingTransactionHelper)
{
this.retryingTransactionHelper = retryingTransactionHelper;
}
/**
* Sets the QName to be patched.
* @param qnameStringBefore the long-form QName to be patched from. {namespaceURI}localName
@@ -116,6 +125,17 @@ public class QNamePatch extends AbstractPatch
this.reindexClass = reindexClass;
}
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(patchDAO, "patchDAO");
checkPropertyNotNull(qnameDAO, "qnameDAO");
checkPropertyNotNull(nodeDAO, "nodeDAO");
checkPropertyNotNull(retryingTransactionHelper, "retryingTransactionHelper");
checkPropertyNotNull(qnameStringAfter, "qnameStringAfter");
checkPropertyNotNull(qnameStringBefore, "qnameStringBefore");
}
@Override
protected String applyInternal() throws Exception
{
@@ -124,46 +144,61 @@ public class QNamePatch extends AbstractPatch
QName qnameBefore = QName.createQName(this.qnameStringBefore);
QName qnameAfter = QName.createQName(this.qnameStringAfter);
if (qnameDAO.getQName(qnameBefore) != null)
Long maxNodeId = patchDAO.getMaxAdmNodeID();
Pair<Long, QName> before = qnameDAO.getQName(qnameBefore);
for (Long i = 0L; i < maxNodeId; i+=BATCH_SIZE)
{
Work work = new Work(before.getFirst(), i);
retryingTransactionHelper.doInTransaction(work, false, true);
}
if (before != null)
{
qnameDAO.updateQName(qnameBefore, qnameAfter);
}
// Optionally perform a focussed reindexing of the removed QName.
if ("TYPE".equals(reindexClass) ||
"ASPECT".equals(reindexClass))
{
reindex(reindexClass + ":" + AbstractLuceneQueryParser.escape(qnameStringBefore), importerBootstrap.getStoreRef());
}
return I18NUtil.getMessage(MSG_SUCCESS, qnameBefore, qnameAfter);
}
private int reindex(String query, StoreRef store)
private class Work implements RetryingTransactionHelper.RetryingTransactionCallback<Integer>
{
SearchParameters sp = new SearchParameters();
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
sp.setQuery(query);
sp.addStore(store);
Indexer indexer = indexerAndSearcher.getIndexer(store);
ResultSet rs = null;
int count = 0;
try
long qnameId;
long lower;
Work(long qnameId, long lower)
{
rs = searchService.query(sp);
count = rs.length();
for (ResultSetRow row : rs)
{
indexer.updateNode(row.getNodeRef());
}
this.qnameId = qnameId;
this.lower = lower;
}
finally
/*
* (non-Javadoc)
* @see org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback#execute()
*/
@Override
public Integer execute() throws Throwable
{
if (rs != null)
if ("TYPE".equals(reindexClass))
{
rs.close();
List<Long> nodeIds = patchDAO.getNodesByTypeQNameId(qnameId, lower, lower + BATCH_SIZE);
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
return nodeIds.size();
}
else if ("ASPECT".equals(reindexClass))
{
List<Long> nodeIds = patchDAO.getNodesByAspectQNameId(qnameId, lower, lower + BATCH_SIZE);
nodeDAO.touchNodes(nodeDAO.getCurrentTransactionId(true), nodeIds);
return nodeIds.size();
}
else
{
// nothing to do
return 0;
}
}
return count;
}
}