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