001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Martin Pernollet 016 */ 017 018package org.nuxeo.ecm.platform.groups.audit.service.acl.data; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.HashSet; 024import java.util.Set; 025import java.util.SortedSet; 026import java.util.TreeSet; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.common.utils.Path; 031import org.nuxeo.ecm.core.api.CoreSession; 032import org.nuxeo.ecm.core.api.DocumentModel; 033import org.nuxeo.ecm.core.api.DocumentModelList; 034import org.nuxeo.ecm.core.api.NuxeoException; 035import org.nuxeo.ecm.platform.groups.audit.service.acl.Pair; 036import org.nuxeo.ecm.platform.groups.audit.service.acl.filter.IContentFilter; 037 038import com.google.common.collect.Multimap; 039 040/** 041 * Gather various data and statistics about a document tree 042 * 043 * @author Martin Pernollet <mpernollet@nuxeo.com> 044 */ 045public class DataProcessor implements IDataProcessor { 046 protected static Log log = LogFactory.getLog(DataProcessor.class); 047 048 protected int documentMinDepth; 049 050 protected int documentTreeDepth; 051 052 protected SortedSet<String> userAndGroups; 053 054 protected SortedSet<String> permissions; 055 056 protected ProcessorStatus status; 057 058 protected String information; 059 060 protected Collection<DocumentSummary> allDocuments; 061 062 protected IContentFilter filter; 063 064 protected AclSummaryExtractor acl; 065 066 public enum ProcessorStatus { 067 SUCCESS, ERROR_TOO_MANY_DOCUMENTS, ERROR_TOO_LONG_PROCESS, ERROR 068 } 069 070 protected int n; 071 072 protected TicToc t = new TicToc(); 073 074 /* */ 075 076 public DataProcessor(IContentFilter filter) { 077 this.filter = filter; 078 this.acl = new AclSummaryExtractor(filter); 079 } 080 081 @Override 082 public void analyze(CoreSession session) { 083 analyze(session, session.getRootDocument(), 0); 084 } 085 086 @Override 087 public void analyze(CoreSession session, DocumentModel doc, int timeout) { 088 init(); 089 doAnalyze(session, doc, timeout); 090 log(); 091 } 092 093 public void init() { 094 userAndGroups = new TreeSet<String>(); 095 permissions = new TreeSet<String>(); 096 documentMinDepth = Integer.MAX_VALUE; 097 documentTreeDepth = 0; 098 } 099 100 // timeout ignored 101 protected void doAnalyze(CoreSession session, DocumentModel root, int timeout) { 102 // get data 103 final DataFetch fetch = new DataFetch(); 104 DocumentModelList list; 105 try { 106 list = fetch.getAllChildren(session, root); 107 } catch (IOException e) { 108 throw new NuxeoException(e); 109 } 110 initSummarySet(); 111 112 processDocument(root); 113 114 n = list.size(); 115 t.tic(); 116 for (DocumentModel d : list) { 117 processDocument(d); 118 } 119 status = ProcessorStatus.SUCCESS; 120 } 121 122 protected void initSummarySet() { 123 allDocuments = new ArrayList<DocumentSummary>(1000); 124 } 125 126 /** 127 * Extract relevant information from document model, to only keep a {@link DocumentSummary} and a few general 128 * informations about the document repository. 129 */ 130 protected void processDocument(DocumentModel doc) { 131 final DocumentSummary da = computeSummary(doc); 132 updateTreeSize(da); 133 computeGlobalAclSummary(doc); 134 allDocuments.add(da); 135 // log.debug(getNumberOfDocuments() + "/" + n + " documents, elapsed " + 136 // t.toc() + "s, docdepth:" + da.getDepth()); 137 } 138 139 /** Extract usefull document information for report rendering */ 140 protected DocumentSummary computeSummary(DocumentModel doc) { 141 String title = doc.getTitle(); 142 String path = doc.getPathAsString(); 143 if (path == null) 144 path = ""; 145 int depth = computeDepth(doc); 146 147 boolean lock = acl.hasLockInheritanceACE(doc); 148 Multimap<String, Pair<String, Boolean>> aclLo = acl.getAclLocalByUser(doc); 149 Multimap<String, Pair<String, Boolean>> aclIn = acl.getAclInheritedByUser(doc); 150 151 DocumentSummary da = new DocumentSummary(title, depth, lock, aclLo, aclIn, path); 152 return da; 153 } 154 155 protected int computeDepth(DocumentModel m) { 156 Path path = m.getPath(); 157 return path.segmentCount(); 158 } 159 160 /** report global tree size */ 161 protected int updateTreeSize(DocumentSummary da) { 162 int depth = da.getDepth(); 163 if (depth > documentTreeDepth) 164 documentTreeDepth = depth; 165 if (depth < documentMinDepth) 166 documentMinDepth = depth; 167 return depth; 168 } 169 170 /** store set of users and set of permission types */ 171 protected void computeGlobalAclSummary(DocumentModel doc) { 172 Pair<HashSet<String>, HashSet<String>> s = acl.getAclSummary(doc); 173 userAndGroups.addAll(s.a); 174 permissions.addAll(s.b); 175 } 176 177 /* RESULTS */ 178 179 /** Ranked so that appear like a tree. */ 180 @Override 181 public Collection<DocumentSummary> getAllDocuments() { 182 return allDocuments; 183 } 184 185 @Override 186 public Set<String> getUserAndGroups() { 187 return userAndGroups; 188 } 189 190 @Override 191 public Set<String> getPermissions() { 192 return permissions; 193 } 194 195 @Override 196 public int getDocumentTreeMaxDepth() { 197 return documentTreeDepth; 198 } 199 200 @Override 201 public int getDocumentTreeMinDepth() { 202 return documentMinDepth; 203 } 204 205 @Override 206 public int getNumberOfDocuments() { 207 return allDocuments.size(); 208 } 209 210 @Override 211 public ProcessorStatus getStatus() { 212 return status; 213 } 214 215 @Override 216 public String getInformation() { 217 return information; 218 } 219 220 /* */ 221 222 public void log() { 223 log.debug("doc tree depth : " + getDocumentTreeMaxDepth()); 224 log.debug("#docs (or folders): " 225 + getNumberOfDocuments() 226 + " (analyzed by processor, may differ from actual number of doc in repo if exceeding timeout or max number of doc)"); 227 log.debug("#users (or groups): " + getUserAndGroups().size() 228 + " (mentionned in ACLs, may differ from actual user directory)"); 229 log.debug("#permissions types: " + getPermissions().size() + " (mentionned in ACLs)"); 230 } 231}