001/* 002 * Copyright 2010 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.cms.content.consistency; 017 018import java.io.IOException; 019import java.util.Date; 020import java.util.HashMap; 021import java.util.Map; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.generation.ServiceableGenerator; 027import org.apache.cocoon.xml.AttributesImpl; 028import org.apache.cocoon.xml.XMLUtils; 029import org.xml.sax.SAXException; 030 031import org.ametys.cms.content.references.OutgoingReferences; 032import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 033import org.ametys.cms.contenttype.ContentTypesHelper; 034import org.ametys.cms.repository.Content; 035import org.ametys.cms.repository.ContentQueryHelper; 036import org.ametys.cms.repository.DefaultContent; 037import org.ametys.cms.transformation.ConsistencyChecker; 038import org.ametys.cms.transformation.ConsistencyChecker.CHECK; 039import org.ametys.core.user.User; 040import org.ametys.core.user.UserIdentity; 041import org.ametys.core.user.UserManager; 042import org.ametys.core.util.DateUtils; 043import org.ametys.plugins.repository.AmetysObjectIterable; 044import org.ametys.plugins.repository.AmetysObjectResolver; 045import org.ametys.plugins.repository.RepositoryConstants; 046import org.ametys.plugins.repository.query.expression.Expression; 047 048/** 049 * Generate content with consistency information.<br> 050 * Parameters: 051 * <ul> 052 * <li>short-test: set to true to make a short test, false to make a full one (default false).</li> 053 * <li>omit-consistent: set to true to omit consistent contents and generate only contents with unknown or failed consistency information (default false).</li> 054 * </ul> 055 */ 056public class GlobalContentConsistencyGenerator extends ServiceableGenerator 057{ 058 /** The ametys object resolver. */ 059 protected AmetysObjectResolver _resolver; 060 061 /** The consistency checker */ 062 protected ConsistencyChecker _consistencyChecker; 063 064 /** The user manager */ 065 protected UserManager _userManager; 066 /** The content type extension point */ 067 protected ContentTypeExtensionPoint _cTypeExtPt; 068 /** Helper for content types */ 069 protected ContentTypesHelper _cTypesHelper; 070 071 /** The name cache */ 072 protected Map<UserIdentity, String> _nameCache; 073 074 075 @Override 076 public void service(ServiceManager serviceManager) throws ServiceException 077 { 078 super.service(serviceManager); 079 _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 080 _consistencyChecker = (ConsistencyChecker) serviceManager.lookup(ConsistencyChecker.ROLE); 081 _cTypeExtPt = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE); 082 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 083 _cTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE); 084 } 085 086 @Override 087 public void generate() throws IOException, SAXException, ProcessingException 088 { 089 _nameCache = new HashMap<>(); 090 091 boolean shortTest = parameters.getParameterAsBoolean("short-test", false); 092 boolean omitConsistent = parameters.getParameterAsBoolean("omit-consistent", false); 093 094 contentHandler.startDocument(); 095 096 AttributesImpl atts = new AttributesImpl(); 097 098 atts.addCDATAAttribute("date", DateUtils.dateToString(new Date())); 099 XMLUtils.startElement(contentHandler, "contents", atts); 100 101 try (AmetysObjectIterable<Content> contents = _getContents()) 102 { 103 for (Content content : contents) 104 { 105 int successCount = 0; 106 int unknownCount = 0; 107 int unauthorizedCount = 0; 108 int notFoundCount = 0; 109 int serverErrorCount = 0; 110 111 Map<String, OutgoingReferences> referencesByPath = content.getOutgoingReferences(); 112 113 for (OutgoingReferences references : referencesByPath.values()) 114 { 115 for (String referenceType : references.keySet()) 116 { 117 for (String referenceValue : references.get(referenceType)) 118 { 119 CHECK check = CHECK.SERVER_ERROR; 120 try 121 { 122 check = _consistencyChecker.checkConsistency(referenceType, referenceValue, shortTest); 123 } 124 catch (Exception e) 125 { 126 // Ignore, consider it a failure. 127 } 128 129 switch (check) 130 { 131 case SUCCESS: 132 successCount++; 133 break; 134 case UNKNOWN: 135 unknownCount++; 136 break; 137 case UNAUTHORIZED: 138 unauthorizedCount++; 139 break; 140 case NOT_FOUND: 141 notFoundCount++; 142 break; 143 case SERVER_ERROR: 144 default: 145 serverErrorCount++; 146 break; 147 } 148 } 149 } 150 } 151 152 if (!omitConsistent || unauthorizedCount > 0 || notFoundCount > 0 || serverErrorCount > 0 || unknownCount > 0) 153 { 154 _saxContentConsistency(content, successCount, unknownCount, unauthorizedCount, notFoundCount, serverErrorCount); 155 } 156 } 157 } 158 159 XMLUtils.endElement(contentHandler, "contents"); 160 contentHandler.endDocument(); 161 } 162 163 /** 164 * Get the contents with inconsistency information. 165 * @return an iterator on contents. 166 */ 167 protected AmetysObjectIterable<Content> _getContents() 168 { 169 Expression expression = new ConsistencyExpression(); 170 171 String query = ContentQueryHelper.getContentXPathQuery(expression); 172 173 return _resolver.query(query); 174 } 175 176 /** 177 * Generate information on content consistency. 178 * @param content the content. 179 * @param successCount the count of consistent information. 180 * @param unknownCount the count of information of unknown consistency. 181 * @param unauthorizedCount the count of unauthorized links. 182 * @param notFoundCount the count of not found links. 183 * @param serverErrorCount the count of inconsistent information. 184 * @throws SAXException if an errors occurs generating the data. 185 */ 186 protected void _saxContentConsistency(Content content, int successCount, int unknownCount, int unauthorizedCount, int notFoundCount, int serverErrorCount) throws SAXException 187 { 188 AttributesImpl atts = new AttributesImpl(); 189 atts.addCDATAAttribute("id", content.getId()); 190 atts.addCDATAAttribute("title", content.getTitle(null)); 191 atts.addCDATAAttribute("smallIcon", _cTypesHelper.getSmallIcon(content)); 192 193 atts.addCDATAAttribute("unauthorized-count", Integer.toString(unauthorizedCount)); 194 atts.addCDATAAttribute("not-found-count", Integer.toString(notFoundCount)); 195 atts.addCDATAAttribute("server-error-count", Integer.toString(serverErrorCount)); 196 atts.addCDATAAttribute("unknown-count", Integer.toString(unknownCount)); 197 atts.addCDATAAttribute("success-count", Integer.toString(successCount)); 198 199 _saxAdditionalContentAttributes(content, atts); 200 201 XMLUtils.startElement(contentHandler, "content", atts); 202 203 XMLUtils.createElement(contentHandler, "lastModified", DateUtils.dateToString(content.getLastModified())); 204 205 UserIdentity user = content.getLastContributor(); 206 AttributesImpl attr = new AttributesImpl(); 207 attr.addAttribute("", "login", "login", "CDATA", user.getLogin()); 208 attr.addAttribute("", "populationId", "populationId", "CDATA", user.getPopulationId()); 209 XMLUtils.createElement(contentHandler, "contributor", attr, getName(user)); 210 211 XMLUtils.endElement(contentHandler, "content"); 212 } 213 214 /** 215 * Sax additional data on the content 216 * @param content the content. 217 * @param atts the attributes the will be saxed? 218 */ 219 protected void _saxAdditionalContentAttributes (Content content, AttributesImpl atts) 220 { 221 // Nothing to do 222 } 223 224 /** 225 * Get the user name 226 * @param userIdentity the user 227 * @return the user name 228 */ 229 protected String getName(UserIdentity userIdentity) 230 { 231 String name = _nameCache.get(userIdentity); 232 if (name != null) 233 { 234 return name; 235 } 236 237 User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin()); 238 if (user == null) 239 { 240 return ""; 241 } 242 243 name = user.getFullName(); 244 _nameCache.put(userIdentity, name); 245 return name; 246 } 247 248 /** 249 * Expression which tests if contents have consistency informations. 250 */ 251 public class ConsistencyExpression implements Expression 252 { 253 @Override 254 public String build() 255 { 256 StringBuilder sb = new StringBuilder(); 257 sb.append(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL).append(':').append(DefaultContent.METADATA_ROOT_OUTGOING_REFERENCES); 258 sb.append('/').append(RepositoryConstants.NAMESPACE_PREFIX_INTERNAL).append(':').append(DefaultContent.METADATA_OUTGOING_REFERENCES); 259 sb.append("/*"); 260 sb.append("/@").append(RepositoryConstants.NAMESPACE_PREFIX).append(':').append(DefaultContent.METADATA_OUTGOING_REFERENCE_PROPERTY); 261 262 return sb.toString(); 263 } 264 } 265 266}