001/* 002* Copyright 2016 Anyware Services 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 */ 016package org.ametys.workspaces.repository.maintenance; 017 018import java.lang.reflect.InvocationTargetException; 019import java.lang.reflect.Method; 020import java.util.ArrayList; 021 022import javax.jcr.RepositoryException; 023import javax.jcr.Session; 024import javax.jcr.SimpleCredentials; 025 026import org.apache.jackrabbit.core.RepositoryContext; 027import org.apache.jackrabbit.core.persistence.IterablePersistenceManager; 028import org.apache.jackrabbit.core.persistence.PersistenceManager; 029import org.apache.jackrabbit.core.persistence.bundle.AbstractBundlePersistenceManager; 030import org.apache.jackrabbit.core.persistence.check.ConsistencyCheckListener; 031import org.apache.jackrabbit.core.persistence.check.ConsistencyReport; 032import org.apache.jackrabbit.core.persistence.check.ReportItem; 033import org.apache.jackrabbit.core.version.InternalVersionManagerImpl; 034import org.slf4j.LoggerFactory; 035 036/** 037 * ConsistencyCheckTask 038 */ 039public class ConsistencyCheckTask extends AbstractMaintenanceTask implements ConsistencyCheckListener 040{ 041 /** The JackRabbit RepositoryImpl Context */ 042 protected RepositoryContext _repositoryContext; 043 044 /** The JCR Session bound to this task. */ 045 protected Session _session; 046 047 private IterablePersistenceManager[] _pmList; 048 049 @Override 050 protected void initialize() throws RepositoryException 051 { 052 // Create the repository and log in the session. 053 _repositoryContext = RepositoryContext.create(_repositoryConfig); 054 _session = _repositoryContext.getRepository().login(new SimpleCredentials("__MAINTENANCE_TASK__", "".toCharArray())); 055 056 // Workaround to get the list of the PersistenceManager 057 ArrayList<PersistenceManager> pmList = new ArrayList<>(); 058 059 // PM of version manager 060 InternalVersionManagerImpl vm = _repositoryContext.getInternalVersionManager(); 061 pmList.add(vm.getPersistenceManager()); 062 063 // PMs of workspaces. 064 String[] wspNames = _repositoryContext.getWorkspaceManager().getWorkspaceNames(); 065 for (int i = 0; i < wspNames.length; i++) 066 { 067 pmList.add(getPM(wspNames[i])); 068 } 069 070 // Filtering on IterablePersistenceManager 071 _pmList = new IterablePersistenceManager[pmList.size()]; 072 for (int i = 0; i < pmList.size(); i++) 073 { 074 PersistenceManager pm = pmList.get(i); 075 if (!(pm instanceof IterablePersistenceManager)) 076 { 077 _pmList = null; 078 break; 079 } 080 _pmList[i] = (IterablePersistenceManager) pm; 081 } 082 083 // Initialize the task progress object. 084 int count = 0; // number of item that will be scanned. 085 086 try 087 { 088 for (IterablePersistenceManager pm : _pmList) 089 { 090 count += pm.getAllNodeIds(null, 0).size(); 091 } 092 _progress = new TaskProgress(count); 093 } 094 catch (Exception e) 095 { 096 _progress = new TaskProgress(0); 097 _progress.setInErrorState(e); 098 _logger.error(e.getLocalizedMessage(), e); 099 } 100 } 101 102 @Override 103 protected void setLogger() 104 { 105 setLogger(LoggerFactory.getLogger(ConsistencyCheckTask.class)); 106 } 107 108 @Override 109 protected void apply() throws RepositoryException 110 { 111 for (PersistenceManager pm : _pmList) 112 { 113 // Do PM consistency check 114 if (pm instanceof AbstractBundlePersistenceManager) 115 { 116 // Perform the check 117 // null -> all uuids, true -> recursive, false -> nofix, null, 118 // lost+found -> null, this -> listener 119 ConsistencyReport report = ((AbstractBundlePersistenceManager) pm).check(null, true, false, null, this); 120 121 _logger.info("Consistency check done for persistence manager : '" + pm.toString() + "' in " + (report.getElapsedTimeMs() / 1000f) + " s."); 122 _logger.info(report.getNodeCount() + " nodes were checked."); 123 _logger.info(report.getItems().isEmpty() ? "No consistency problems were reported." : report.getItems().size() + " consistency problems were reported."); 124 } 125 } 126 } 127 128 @Override 129 protected void close() 130 { 131 if (_session != null) 132 { 133 _session.logout(); 134 } 135 136 if (_repositoryContext != null && _repositoryContext.getRepository() != null) 137 { 138 _repositoryContext.getRepository().shutdown(); 139 } 140 141 if (_progress != null) 142 { 143 _progress.progressRelativePercentage(100); 144 } 145 } 146 147 /** 148 * Retrieves JackRabbit Persistence Manager for currently opened repository. This method uses 149 * Privileged access and will fail with security exception if used in environment with enabled security manager. 150 * @param workspaceName The workspace name 151 * @return Persistence manager used by repository. 152 */ 153 protected PersistenceManager getPM(String workspaceName) 154 { 155 try 156 { 157 Object workspaceInfo = findAndInvokeMethod(_repositoryContext.getRepository(), "getWorkspaceInfo", new Object[] {workspaceName}); 158 return (PersistenceManager) (findAndInvokeMethod(workspaceInfo, "getPersistenceManager", null)); 159 } 160 catch (Exception e) 161 { 162 throw new RuntimeException(e); 163 } 164 } 165 166 private static Object findAndInvokeMethod(Object obj, String name, Object[] parameters) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException 167 { 168 Method m = null; 169 Method[] ms = obj.getClass().getDeclaredMethods(); 170 for (int i = 0; i < ms.length; i++) 171 { 172 final Method x = ms[i]; 173 if (x.getName().equals(name)) 174 { 175 m = x; 176 m.setAccessible(true); 177 return m.invoke(obj, parameters); 178 } 179 } 180 181 return null; 182 } 183 184 // Listener methods 185 186 @Override 187 public void startCheck(String id) 188 { 189 if (_progress != null) 190 { 191 _progress.progress(); 192 } 193 } 194 195 @Override 196 public void report(ReportItem item) 197 { 198 _logger.warn(item.toString()); 199 } 200 201 @Override 202 public void error(String id, String message) 203 { 204 _logger.error("error during the consistency check -> id : [ " + id + "]\n" + message); 205 } 206 207 @Override 208 public void info(String id, String message) 209 { 210 _logger.info("error during the consistency check -> id : [ " + id + "]\n" + message); 211 } 212}