/* Index ECM Engine - A system for managing the capture (when created
* or received), classification (cataloguing), storage, retrieval,
* revision, sharing, reuse and disposition of documents.
*
* Copyright (C) 2008 Regione Piemonte
* Copyright (C) 2008 Provincia di Torino
* Copyright (C) 2008 Comune di Torino
*
* 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,
* 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package it.doqui.index.ecmengine.business.personalization.security.permissions;
import it.doqui.index.ecmengine.util.EcmEngineConstants;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeStatus;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.security.permissions.NodePermissionEntry;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.impl.PermissionServiceImpl;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Interceptor che pilota l'aggiornamento degli indici a seguito di modifiche
* alle ACL associate ad un nodo.
*
* @author Doqui
*/
public class ReindexingPermissionServiceInterceptor implements MethodInterceptor {
private static Log logger = LogFactory.getLog(EcmEngineConstants.ECMENGINE_ROOT_LOG_CATEGORY + ".business.personalization.permissions");
private Indexer indexer;
private NodeDaoService nodeDaoService;
/** Costruttore vuoto. */
public ReindexingPermissionServiceInterceptor() {}
public Object invoke(MethodInvocation invocation) throws Throwable {
logger.debug("[ReindexingPermissionServiceInterceptor::invoke] BEGIN");
try {
final Object retValue = invocation.proceed();
final String methodName = invocation.getMethod().getName();
final Object[] args = invocation.getArguments();
logger.debug("[ReindexingPermissionServiceInterceptor::invoke] " +
"Intercepting method \"" + methodName + "\": " + args.length + " arguments.");
final Object target = invocation.getThis();
PermissionServiceImpl permissionService = null;
logger.debug("[ReindexingPermissionServiceInterceptor::invoke] Target: " + target);
if (target instanceof PermissionServiceImpl) {
permissionService = (PermissionServiceImpl) target;
} else {
throw new IllegalStateException("Wrong target!");
}
if (methodName.equals("deletePermissions")) {
if (args[0] instanceof NodeRef) {
updateIndex((NodeRef) args[0], permissionService);
} else if (args[0] instanceof NodePermissionEntry) {
NodeRef nodeRef = ((NodePermissionEntry) args[0]).getNodeRef();
updateIndex(nodeRef, permissionService);
} else if (args[0] instanceof String) {
Map<NodeRef, Set<AccessPermission>> permissions =
permissionService.getAllSetPermissionsForAuthority((String) args[0]);
for (NodeRef nodeRef : permissions.keySet()) {
updateIndex(nodeRef, permissionService);
}
}
} else if (methodName.equals("deletePermission")) {
if (args.length == 1) {
NodeRef nodeRef = ((PermissionEntry) args[0]).getNodeRef();
updateIndex(nodeRef, permissionService);
} else if (args.length == 3) {
updateIndex((NodeRef) args[0], permissionService);
}
} else if (methodName.equals("clearPermission")
|| methodName.equals("setInheritParentPermissions")) {
updateIndex((NodeRef) args[0], permissionService);
} else if (methodName.equals("setPermission")) {
if (args.length == 1) {
if (args[0] instanceof NodePermissionEntry) {
NodeRef nodeRef = ((NodePermissionEntry) args[0]).getNodeRef();
updateIndex(nodeRef, permissionService);
} else if (args[0] instanceof PermissionEntry) {
NodeRef nodeRef = ((PermissionEntry) args[0]).getNodeRef();
updateIndex(nodeRef, permissionService);
}
} else if (args.length == 4) {
updateIndex((NodeRef) args[0], permissionService);
}
}
return retValue;
} finally {
logger.debug("[ReindexingPermissionServiceInterceptor::invoke] END");
}
}
private void updateIndex(NodeRef nodeRef, PermissionServiceImpl permissionService) {
logger.debug("[ReindexingPermissionServiceInterceptor::updateIndex] BEGIN");
try {
logger.debug("[ReindexingPermissionServiceInterceptor::updateIndex] Requesting reindex of node: " + nodeRef);
final String protocol = nodeRef.getStoreRef().getProtocol();
if (protocol.equals("workspace") || protocol.equals("archive")) {
// XXX: workaround per forzare la ri-indicizzazione dei figli in cascata
Map<Long, NodeRef> toReindex = getNodeHierarchyToReindex(
nodeDaoService.getNodeStatus(nodeRef, false), null, permissionService);
for (NodeRef ref : toReindex.values()) {
indexer.updateChildRelationship(new ChildAssociationRef(null, null, null, ref), null);
// indexer.updateNode(nodeRef);
// Registra la transazione sul DB per l'index tracking in ambiente cluster
nodeDaoService.recordChangeId(nodeRef);
}
}
} finally {
logger.debug("[ReindexingPermissionServiceInterceptor::updateIndex] END");
}
}
private Map<Long, NodeRef> getNodeHierarchyToReindex(NodeStatus nodeStatus, Map<Long, NodeRef> nodesById, PermissionServiceImpl permissionService) {
logger.debug("[ReindexingPermissionServiceInterceptor::getNodeHierarchyToReindex] BEGIN");
try {
// XXX: ispirato a DbNodeServiceImpl.getNodeHierarchy()
if (nodesById == null) {
nodesById = new HashMap<Long, NodeRef>(23);
// Inizio della gerarchia
nodeDaoService.flush();
}
final Node node = nodeStatus.getNode();
if (node == null) {
// Il nodo e` stato eliminato
return nodesById;
}
Long nodeId = node.getId();
if (nodesById.containsKey(nodeId)) {
// ID gia` aggiunto... dipendenza circolare
logger
.warn("Circular hierarchy found including node "
+ nodeId);
return nodesById;
}
final NodeRef nodeRef = node.getNodeRef();
// Ottimizzabile con: nodeStatus.getKey().getGuid(); ???
// Se il nodo non eredita ACL dal padre blocco la navigazione dell'albero
if (!permissionService.getInheritParentPermissions(nodeRef)) {
return nodesById;
}
nodesById.put(nodeId, nodeRef);
// Ricorsione
Collection<NodeStatus> primaryChildNodeStatuses = nodeDaoService
.getPrimaryChildNodeStatuses(node);
for (NodeStatus primaryChildNodeStatus : primaryChildNodeStatuses) {
nodesById = getNodeHierarchyToReindex(primaryChildNodeStatus,
nodesById, permissionService);
}
return nodesById;
} finally {
logger.debug("[ReindexingPermissionServiceInterceptor::getNodeHierarchyToReindex] END");
}
}
public void setIndexer(Indexer indexer) {
this.indexer = indexer;
}
public void setNodeDaoService(NodeDaoService nodeDaoService) {
this.nodeDaoService = nodeDaoService;
}
}