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