diff --git a/config/alfresco/bootstrap/system.xml b/config/alfresco/bootstrap/system.xml index 95a9200224..fc618e8a1b 100644 --- a/config/alfresco/bootstrap/system.xml +++ b/config/alfresco/bootstrap/system.xml @@ -53,6 +53,7 @@ /${spaces.company_home.childname} bootstrapHomeFolderProvider + 0 @@ -69,6 +70,7 @@ /${spaces.company_home.childname}/${spaces.guest_home.childname} bootstrapHomeFolderProvider + 0 diff --git a/config/alfresco/messages/patch-service.properties b/config/alfresco/messages/patch-service.properties index e150722ae5..a478b89547 100644 --- a/config/alfresco/messages/patch-service.properties +++ b/config/alfresco/messages/patch-service.properties @@ -280,3 +280,7 @@ patch.fixNameCrcValues.description=Fixes name CRC32 values to match UTF-8 encodi patch.fixNameCrcValues.result=Fixed {0} name CRC32 values for UTF-8 encoding. See file {1} for details. patch.fixNameCrcValues.fixed=Updated CRC32 value for node ID {0}, name ''{1}'': {2} -> {3}. patch.fixNameCrcValues.unableToChange=Failed to update the CRC32 value for node ID {0}: \n Node name: {1} \n CRC old: {2} \n CRC new: {3} \n Error: {4} + +patch.personUsagePatch.description=Add person 'cm:sizeCurrent' property (if missing). +patch.personUsagePatch.result1=Added 'cm:sizeCurrent' property to {0} people that were missing this property. +patch.personUsagePatch.result2=No people were missing the 'cm:sizeCurrent' property. diff --git a/config/alfresco/model/contentModel.xml b/config/alfresco/model/contentModel.xml index c77f28a7a3..670d0ce538 100644 --- a/config/alfresco/model/contentModel.xml +++ b/config/alfresco/model/contentModel.xml @@ -250,6 +250,7 @@ d:long true + true d:long diff --git a/config/alfresco/patch/patch-services-context.xml b/config/alfresco/patch/patch-services-context.xml index 29bf95fe9d..f8b3ed1a7d 100644 --- a/config/alfresco/patch/patch-services-context.xml +++ b/config/alfresco/patch/patch-services-context.xml @@ -1933,4 +1933,22 @@ + + patch.personUsagePatch + patch.personUsagePatch.description + 0 + 3004 + 3005 + + + + + + ${spaces.store} + + + + + + diff --git a/config/alfresco/version.properties b/config/alfresco/version.properties index ccf92d5bb2..5d2443fa8a 100644 --- a/config/alfresco/version.properties +++ b/config/alfresco/version.properties @@ -19,4 +19,4 @@ version.build=@build-number@ # Schema number -version.schema=3004 +version.schema=3005 diff --git a/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java b/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java new file mode 100644 index 0000000000..720f824763 --- /dev/null +++ b/source/java/org/alfresco/repo/admin/patch/impl/PersonUsagePatch.java @@ -0,0 +1,130 @@ +/* + * 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 received 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 org.alfresco.i18n.I18NUtil; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.admin.patch.AbstractPatch; +import org.alfresco.repo.node.db.NodeDaoService; +import org.alfresco.repo.node.db.NodeDaoService.ObjectArrayQueryCallback; +import org.alfresco.repo.tenant.TenantService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Patch to add person usage ('cm:sizeCurrent') property to person (if missing) + * + * @author janv + */ +public class PersonUsagePatch extends AbstractPatch +{ + private static Log logger = LogFactory.getLog(PersonUsagePatch.class); + + /** Success messages. */ + private static final String MSG_SUCCESS1 = "patch.personUsagePatch.result1"; + private static final String MSG_SUCCESS2 = "patch.personUsagePatch.result2"; + + private NodeDaoService nodeDaoService; + private StoreRef personStoreRef; + private TenantService tenantService; + + + public void setNodeDaoService(NodeDaoService nodeDaoService) + { + this.nodeDaoService = nodeDaoService; + } + + public void setPersonStoreUrl(String storeUrl) + { + this.personStoreRef = new StoreRef(storeUrl); + } + + public void setTenantService(TenantService tenantService) + { + this.tenantService = tenantService; + } + + + @Override + protected String applyInternal() throws Exception + { + logger.info("Checking for people with missing 'cm:sizeCurrent' property ..."); + + int count = addPersonSizeCurrentProperty(); + + String msg = null; + if (count > 0) + { + logger.info("... missing 'cm:sizeCurrent' property added to "+count+" people"); + msg = I18NUtil.getMessage(MSG_SUCCESS1, count); + } + else + { + logger.info("... no people were missing the 'cm:sizeCurrent' property"); + msg = I18NUtil.getMessage(MSG_SUCCESS2); + } + + return msg; + } + + private int addPersonSizeCurrentProperty() + { + // get people (users) with missing 'cm:sizeCurrent' property + + CountObjectArrayQueryCallback userHandler = new CountObjectArrayQueryCallback(); + + nodeDaoService.getUsersWithoutUsageProp(tenantService.getName(personStoreRef), userHandler); + + return userHandler.getCount(); + } + + private class CountObjectArrayQueryCallback implements ObjectArrayQueryCallback + { + private int count; + + public CountObjectArrayQueryCallback() + { + count = 0; + } + + public boolean handle(Object[] arr) + { + String uuid = (String)arr[0]; + + nodeService.setProperty(new NodeRef(personStoreRef, uuid), ContentModel.PROP_SIZE_CURRENT, null); + + count++; + + return true; // continue to next node (more required) + } + + public int getCount() + { + return count; + } + }; +} diff --git a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml index b73246e627..90796facd1 100644 --- a/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml +++ b/source/java/org/alfresco/repo/domain/hibernate/Node.hbm.xml @@ -716,6 +716,22 @@ (p1.string_value != 'System' OR (p1.string_value IS NULL AND n.audit_creator != 'System')) + + + + SELECT + n.uuid AS uuid + FROM + alf_node n + JOIN alf_store s ON (s.id = n.store_id AND n.type_qname_id = :personTypeQNameID) + LEFT JOIN alf_node_properties p1 ON (p1.node_id = n.id AND p1.qname_id = :sizeCurrentPropQNameID) + WHERE + s.protocol = :storeProtocol AND + s.identifier = :storeIdentifier AND + n.node_deleted = :isDeleted AND + p1.persisted_type_n IS NULL + + diff --git a/source/java/org/alfresco/repo/node/db/NodeDaoService.java b/source/java/org/alfresco/repo/node/db/NodeDaoService.java index 23d9b8a6e0..612104add0 100644 --- a/source/java/org/alfresco/repo/node/db/NodeDaoService.java +++ b/source/java/org/alfresco/repo/node/db/NodeDaoService.java @@ -503,6 +503,19 @@ public interface NodeDaoService StoreRef storeRef, ObjectArrayQueryCallback resultsCallback); + /** + * Iterate over all person nodes with missing usage property (for one-off patch) + * + * @param storeRef the store to search in + * @param handler the callback to use while iterating over the people + * @return Returns the values for person node uuid + */ + @DirtySessionAnnotation(markDirty=true) + public void getUsersWithoutUsageProp( + StoreRef storeRef, + ObjectArrayQueryCallback resultsCallback); + + /** * Iterate over all person nodes to get users without a calculated usage * diff --git a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java index 13256e4604..56b435dfe8 100644 --- a/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java +++ b/source/java/org/alfresco/repo/node/db/hibernate/HibernateNodeDaoServiceImpl.java @@ -163,6 +163,7 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_STRING_AND_STORE = "node.GetNodesWithPropertyValuesByStringAndStore"; private static final String QUERY_GET_CONTENT_URLS_FOR_STORE_OLD = "node.GetContentUrlsForStoreOld"; private static final String QUERY_GET_CONTENT_URLS_FOR_STORE_NEW = "node.GetContentUrlsForStoreNew"; + private static final String QUERY_GET_USERS_WITHOUT_USAGE_PROP = "node.GetUsersWithoutUsageProp"; private static final String QUERY_GET_USERS_WITHOUT_USAGE = "node.GetUsersWithoutUsage"; private static final String QUERY_GET_USERS_WITH_USAGE = "node.GetUsersWithUsage"; private static final String QUERY_GET_NODES_WITH_PROPERTY_VALUES_BY_ACTUAL_TYPE = "node.GetNodesWithPropertyValuesByActualType"; @@ -3649,6 +3650,59 @@ public class HibernateNodeDaoServiceImpl extends HibernateDaoSupport implements // Done } + public void getUsersWithoutUsageProp( + final StoreRef storeRef, + final ObjectArrayQueryCallback resultsCallback) + { + final Pair sizeCurrentPropQNamePair = qnameDAO.getQName(ContentModel.PROP_SIZE_CURRENT); + final Pair personTypeQNamePair = qnameDAO.getQName(ContentModel.TYPE_PERSON); + + // Shortcut the query if the QNames don't exist + if (sizeCurrentPropQNamePair == null || personTypeQNamePair == null) + { + return; + } + + HibernateCallback callback = new HibernateCallback() + { + public Object doInHibernate(Session session) + { + Query query = session + .getNamedQuery(HibernateNodeDaoServiceImpl.QUERY_GET_USERS_WITHOUT_USAGE_PROP) + .setString("storeProtocol", storeRef.getProtocol()) + .setString("storeIdentifier", storeRef.getIdentifier()) + .setParameter("sizeCurrentPropQNameID", sizeCurrentPropQNamePair.getFirst()) // cm:sizeCurrent + .setParameter("personTypeQNameID", personTypeQNamePair.getFirst()) // cm:person + .setParameter("isDeleted", false); + ; + DirtySessionMethodInterceptor.setQueryFlushMode(session, query); + return query.scroll(ScrollMode.FORWARD_ONLY); + } + }; + ScrollableResults results = null; + try + { + results = (ScrollableResults) getHibernateTemplate().execute(callback); + // Callback with the results + Session session = getSession(); + while (results.next()) + { + Object[] arr = new Object[1]; + arr[0] = (String)results.get(0); // node uuid + resultsCallback.handle(arr); + // Flush if required + DirtySessionMethodInterceptor.flushSession(session); + } + } + finally + { + if (results != null) + { + results.close(); + } + } + } + public void getUsersWithoutUsage( final StoreRef storeRef, final ObjectArrayQueryCallback resultsCallback) diff --git a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java index 68d60d463f..84a70f65e2 100644 --- a/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java +++ b/source/java/org/alfresco/repo/security/authentication/AuthenticationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Alfresco Software Limited. + * 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 @@ -24,8 +24,8 @@ */ package org.alfresco.repo.security.authentication; -import java.util.Stack; - +import java.util.Stack; + import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; @@ -37,10 +37,10 @@ import net.sf.acegisecurity.providers.dao.User; import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.security.PermissionService; -import org.alfresco.util.EqualsHelper; +import org.alfresco.util.EqualsHelper; import org.alfresco.util.log.NDC; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; /** @@ -508,6 +508,7 @@ public class AuthenticationUtil implements InitializingBean } AuthenticationUtil.setRunAsUser(uid); } + logNDC(uid); result = runAsWork.doWork(); return result; } @@ -528,12 +529,15 @@ public class AuthenticationUtil implements InitializingBean if (originalFullAuthentication == null) { AuthenticationUtil.clearCurrentSecurityContext(); + logNDC(null); } else { AuthenticationUtil.setFullAuthentication(originalFullAuthentication); AuthenticationUtil.setRunAsAuthentication(originalRunAsAuthentication); - } + + logNDC(getUserName(originalFullAuthentication)); + } } } @@ -599,22 +603,25 @@ public class AuthenticationUtil implements InitializingBean { NDC.remove(); - if (isMtEnabled()) + if (userName != null) { - String[] parts = splitUserTenant(userName); - if (parts.length == 2) + if (isMtEnabled()) { - NDC.push("Tenant:" + parts[1] + " User:" + parts[0]); + String[] parts = splitUserTenant(userName); + if (parts.length == 2) + { + NDC.push("Tenant:" + parts[1] + " User:" + parts[0]); + } + else + { + NDC.push("User:" + userName); + } } else { NDC.push("User:" + userName); } } - else - { - NDC.push("User:" + userName); - } } private static String[] splitUserTenant(String userName)