001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.relations; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsResource; 032import org.opencms.file.CmsResourceFilter; 033import org.opencms.main.CmsException; 034import org.opencms.main.CmsLog; 035import org.opencms.util.CmsUUID; 036 037import java.util.ArrayList; 038import java.util.Collections; 039import java.util.HashMap; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Map; 043 044import org.apache.commons.logging.Log; 045 046/** 047 * Util class to find broken links in a bundle of resources.<p> 048 * 049 * @since 6.5.3 050 */ 051public class CmsInternalLinksValidator { 052 053 /** The log object for this class. */ 054 private static final Log LOG = CmsLog.getLog(CmsInternalLinksValidator.class); 055 056 /** The internal computed broken relations map. */ 057 protected Map<String, List<CmsRelation>> m_brokenRelations; 058 059 /** The cms context object. */ 060 private CmsObject m_cms; 061 062 /** The number of not visible resources with broken links. */ 063 private int m_notVisibleResourcesCount; 064 065 /** All resources with broken links. */ 066 private List<CmsResource> m_resourcesWithBrokenLinks; 067 068 /** 069 * Creates a new helper object.<p> 070 * 071 * @param cms the cms object 072 * @param resourceNames a list of resource names to be deleted 073 */ 074 public CmsInternalLinksValidator(CmsObject cms, List<String> resourceNames) { 075 076 m_cms = cms; 077 m_brokenRelations = getBrokenRelations(resourceNames); 078 } 079 080 /** 081 * Returns all broken links for the given resource.<p> 082 * 083 * @param resourceName the resource to get the broken link 084 * 085 * @return a list of {@link CmsRelation} objects 086 */ 087 public List<CmsRelation> getBrokenLinksForResource(String resourceName) { 088 089 return m_brokenRelations.get(resourceName); 090 } 091 092 /** 093 * Returns the number of not visible resources with broken links.<p> 094 * 095 * @return the number of not visible resources with broken links 096 */ 097 public int getNotVisibleResourcesCount() { 098 099 if (m_resourcesWithBrokenLinks == null) { 100 // compute it if needed 101 getResourcesWithBrokenLinks(); 102 } 103 return m_notVisibleResourcesCount; 104 } 105 106 /** 107 * Returns all resources with broken links.<p> 108 * 109 * @return a list of {@link org.opencms.file.CmsResource} objects 110 */ 111 public List<CmsResource> getResourcesWithBrokenLinks() { 112 113 if (m_resourcesWithBrokenLinks == null) { 114 // sort the resulting hash map 115 List<String> resources = new ArrayList<String>(m_brokenRelations.keySet()); 116 Collections.sort(resources); 117 118 m_resourcesWithBrokenLinks = new ArrayList<CmsResource>(resources.size()); 119 m_notVisibleResourcesCount = 0; 120 // remove not visible resources 121 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireVisible(); 122 String storedSiteRoot = m_cms.getRequestContext().getSiteRoot(); 123 try { 124 m_cms.getRequestContext().setSiteRoot("/"); 125 Iterator<String> itResources = resources.iterator(); 126 while (itResources.hasNext()) { 127 String resourceName = itResources.next(); 128 try { 129 m_resourcesWithBrokenLinks.add(m_cms.readResource(resourceName, filter)); 130 } catch (Exception e) { 131 // resource is not visible, increase count 132 m_notVisibleResourcesCount++; 133 } 134 } 135 } finally { 136 m_cms.getRequestContext().setSiteRoot(storedSiteRoot); 137 } 138 } 139 return m_resourcesWithBrokenLinks; 140 } 141 142 /** 143 * If no relation would be broken deleting the given resources.<p> 144 * 145 * @return <code>true</code> if no relation would be broken deleting the given resources 146 */ 147 public boolean isEmpty() { 148 149 return m_brokenRelations.isEmpty(); 150 } 151 152 /** 153 * Returns a map of where each entry has as key a name of a resource to be validated, 154 * and value a list of relations that are broken.<p> 155 * 156 * @param resourceNames a list of resource names to be validated 157 * 158 * @return a map of broken relations 159 */ 160 private Map<String, List<CmsRelation>> getBrokenRelations(List<String> resourceNames) { 161 162 Map<String, List<CmsRelation>> brokenRelations = new HashMap<String, List<CmsRelation>>(); 163 164 CmsRelationFilter filter = CmsRelationFilter.TARGETS.filterIncludeChildren().filterStructureId( 165 CmsUUID.getNullUUID()); 166 167 Iterator<String> itFolders = resourceNames.iterator(); 168 while (itFolders.hasNext()) { 169 String folderName = itFolders.next(); 170 List<CmsRelation> relations; 171 try { 172 relations = m_cms.getRelationsForResource(folderName, filter); 173 } catch (CmsException e) { 174 LOG.error(Messages.get().getBundle().key(Messages.LOG_LINK_SEARCH_1, folderName), e); 175 continue; 176 } 177 Iterator<CmsRelation> itRelations = relations.iterator(); 178 while (itRelations.hasNext()) { 179 CmsRelation relation = itRelations.next(); 180 // target is broken 181 String resourceName = relation.getSourcePath(); 182 List<CmsRelation> broken = brokenRelations.get(resourceName); 183 if (broken == null) { 184 broken = new ArrayList<CmsRelation>(); 185 brokenRelations.put(resourceName, broken); 186 } 187 broken.add(relation); 188 } 189 } 190 return brokenRelations; 191 } 192}