Merged V3.1 to HEAD

13853: Merged V3.0 to V3.1
      13008: Merged V2.2 to V3.0
         12824: (record only) Change admin access to the web project staging store to be read-only in the virtualization view - ETWOTWO-933
      13031: (Record only) AMP fix for ETWOTWO-968: Space rules are not run when saving from MS Word
      13040: Merged V2.2 to V3.0
         12824: (record-only) - already done via r13005 (ETWOTWO-933)
      13145: Merged V2.2 to V3.0:
         13089: (record-only) Fix "Read-Write transaction started within read-only transaction" exception. ETWOTWO-1055.
         13091: (record-only) Fix for NFS server "Read-Write transaction started within read-only transaction" exception. ETWOTWO-1054.
      13508: ETHREEOH-1548 - allow config to reset (even if null/cache)
      13514: ETHREEOH-1548 (follow-on fix) - to allow config to reset (even if null/cache) and also reduce 5 caches to 1
      13848: Merged V2.2 to V3.0
         13188: *RECORD ONLY* Using correct ooo startup context - does not work for *nix.  Fixed in 3.0sp1
         13212: *RECORD ONLY* AMP for ETWOTWO-984
         13342: *RECORD ONLY* Merge info stuff
         13435: Merged V2.1 to V2.2
            12307: Merged DEV/V2.1SP7 to 2.1
               11927: ETWOONE-396
               12112: ETWOONE-396
         13442: *RECORD ONLY* Updated version to 2.2.4dev
         13468: *RECORD ONLY* Removed svn:mergeinfo crud
         13470: I18NUtil doesn't cause NPE if message key doesn't exist
         13471: Fixed ETWOTWO-1133: Incorrect CRC32 Values for non-ASCII names
         13475: Test fix: I18NUtil.getMessage() no longer returns null, leading to NPEs if message bundle is missing
         13476: Reverted back to null return values.  Will save for fixing on HEAD.
         13749: Fixed ALFCOM-2655: MLTranslationInterceptor doesn't handle getType method
         13803: ETWOTWO-710
         13819: *RECORD ONLY* ACT-6420 - Office 2003 "Install for all users" - DO NOT MERGE
         13827: ETWOTWO-1172 - authority exists now checks nodeRef result
   ___________________________________________________________________
   Modified: svn:mergeinfo
      Merged /alfresco/BRANCHES/V3.0:r12824,13008,13031,13040,13089,13091,13145,13848
      Merged /alfresco/BRANCHES/V2.2:r12824,13188,13212,13342,13442,13468,13470-13471,13475-13476,13749,13803,13827
      Merged /alfresco/BRANCHES/V3.1:r13853


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14763 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-06-17 12:28:56 +00:00
parent e3df62325d
commit 3a5c120bbe
19 changed files with 608 additions and 30 deletions

View File

@@ -0,0 +1,293 @@
/*
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.repo.admin.patch.impl;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.CRC32;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.QNameDAO;
import org.alfresco.repo.domain.hibernate.ChildAssocImpl;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.service.cmr.admin.PatchException;
import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* Fixes <a href=https://issues.alfresco.com/jira/browse/ETWOTWO-1133>ETWOTWO-1133</a>.
* Checks all CRC values for <b>alf_child_assoc.child_node_name_crc</b>.
*
* @author Derek Hulley
* @since V2.2SP4
*/
public class FixNameCrcValuesPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.fixNameCrcValues.result";
private static final String MSG_REWRITTEN = "patch.fixNameCrcValues.fixed";
private SessionFactory sessionFactory;
private NodeDaoService nodeDaoService;
private QNameDAO qnameDAO;
public FixNameCrcValuesPatch()
{
}
public void setSessionFactory(SessionFactory sessionFactory)
{
this.sessionFactory = sessionFactory;
}
/**
* @param nodeDaoService The service that generates the CRC values
*/
public void setNodeDaoService(NodeDaoService nodeDaoService)
{
this.nodeDaoService = nodeDaoService;
}
/**
* @param qnameDAO resolved QNames
*/
public void setQnameDAO(QNameDAO qnameDAO)
{
this.qnameDAO = qnameDAO;
}
@Override
protected void checkProperties()
{
super.checkProperties();
checkPropertyNotNull(sessionFactory, "sessionFactory");
checkPropertyNotNull(nodeDaoService, "nodeDaoService");
checkPropertyNotNull(qnameDAO, "qnameDAO");
}
@Override
protected String applyInternal() throws Exception
{
// initialise the helper
HibernateHelper helper = new HibernateHelper();
helper.setSessionFactory(sessionFactory);
try
{
String msg = helper.fixCrcValues();
// done
return msg;
}
finally
{
helper.closeWriter();
}
}
private class HibernateHelper extends HibernateDaoSupport
{
private File logFile;
private FileChannel channel;
private HibernateHelper() throws IOException
{
logFile = new File("./FixNameCrcValuesPatch.log");
// open the file for appending
RandomAccessFile outputFile = new RandomAccessFile(logFile, "rw");
channel = outputFile.getChannel();
// move to the end of the file
channel.position(channel.size());
// add a newline and it's ready
writeLine("").writeLine("");
writeLine("FixNameCrcValuesPatch executing on " + new Date());
}
private HibernateHelper write(Object obj) throws IOException
{
channel.write(ByteBuffer.wrap(obj.toString().getBytes("UTF-8")));
return this;
}
private HibernateHelper writeLine(Object obj) throws IOException
{
write(obj);
write("\n");
return this;
}
private void closeWriter()
{
try { channel.close(); } catch (Throwable e) {}
}
public String fixCrcValues() throws Exception
{
// get the association types to check
@SuppressWarnings("unused")
List<Long> childAssocIds = findMismatchedCrcs();
int updated = 0;
for (Long childAssocId : childAssocIds)
{
ChildAssoc assoc = (ChildAssoc) getHibernateTemplate().get(ChildAssocImpl.class, childAssocId);
if (assoc == null)
{
// Missing now ...
continue;
}
// Get the old CRC
long oldCrc = assoc.getChildNodeNameCrc();
// Get the child node
Node childNode = assoc.getChild();
// Get the name
String childName = (String) nodeDaoService.getNodeProperty(childNode.getId(), ContentModel.PROP_NAME);
if (childName == null)
{
childName = childNode.getUuid();
}
// Update the CRC
long crc = getCrc(childName);
// Update the assoc
assoc.setChildNodeNameCrc(crc);
// Persist
updated++;
getSession().flush();
getSession().clear();
// Record
writeLine(I18NUtil.getMessage(MSG_REWRITTEN, childNode.getId(), childName, oldCrc, crc));
}
String msg = I18NUtil.getMessage(MSG_SUCCESS, updated, logFile);
return msg;
}
@SuppressWarnings("unchecked")
private List<Long> findMismatchedCrcs() throws Exception
{
final Long qnameId = qnameDAO.getOrCreateQName(ContentModel.PROP_NAME).getFirst();
final List<Long> childAssocIds = new ArrayList<Long>(1000);
HibernateCallback callback = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
SQLQuery query = session
.createSQLQuery(
" SELECT " +
" ca.id AS child_assoc_id," +
" ca.child_node_name_crc AS child_assoc_crc," +
" np.string_value AS node_name," +
" n.uuid as node_uuid" +
" FROM" +
" alf_child_assoc ca" +
" JOIN alf_node n ON (ca.child_node_id = n.id AND ca.child_node_name_crc > 0)" +
" JOIN alf_node_properties np on (np.node_id = n.id AND np.qname_id = :qnameId)" +
"");
query.setLong("qnameId", qnameId);
query.addScalar("child_assoc_id", new LongType());
query.addScalar("child_assoc_crc", new LongType());
query.addScalar("node_name", new StringType());
query.addScalar("node_uuid", new StringType());
return query.scroll(ScrollMode.FORWARD_ONLY);
}
};
ScrollableResults rs = null;
try
{
rs = (ScrollableResults) getHibernateTemplate().execute(callback);
while (rs.next())
{
Long assocId = (Long) rs.get(0);
Long dbCrc = (Long) rs.get(1);
String name = (String) rs.get(2);
String uuid = (String) rs.get(3);
long utf8Crc = -1L;
if (name != null)
{
utf8Crc = getCrc(name);
}
else
{
utf8Crc = getCrc(uuid);
}
// Check
if (dbCrc != null && utf8Crc == dbCrc.longValue())
{
// It is a match, so ignore
continue;
}
childAssocIds.add(assocId);
}
}
catch (Throwable e)
{
logger.error("Failed to query for child name CRCs", e);
writeLine("Failed to query for child name CRCs: " + e.getMessage());
throw new PatchException("Failed to query for child name CRCs", e);
}
finally
{
if (rs != null)
{
try { rs.close(); } catch (Throwable e) { writeLine("Failed to close resultset: " + e.getMessage()); }
}
}
return childAssocIds;
}
/**
* @param str the name that will be converted to lowercase
* @return the CRC32 calcualted on the lowercase version of the string
*/
private long getCrc(String str)
{
CRC32 crc = new CRC32();
try
{
crc.update(str.toLowerCase().getBytes("UTF-8")); // https://issues.alfresco.com/jira/browse/ALFCOM-1335
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException("UTF-8 encoding is not supported");
}
return crc.getValue();
}
}
}