001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.search; 033 034import org.opencms.db.CmsPublishedResource; 035import org.opencms.file.CmsProject; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.report.I_CmsReport; 041import org.opencms.search.documents.CmsDocumentDependency; 042 043import java.util.ArrayList; 044import java.util.HashMap; 045import java.util.Iterator; 046import java.util.List; 047import java.util.Map; 048 049import org.apache.commons.logging.Log; 050 051/** 052 * A VFS indexer that resolves locale dependent documents.<p> 053 * 054 * @since 8.5.0 055 */ 056public class CmsDependencyIndexer extends CmsVfsIndexer { 057 058 /** The log object for this class. */ 059 private static final Log LOG = CmsLog.getLog(CmsDependencyIndexer.class); 060 061 /** 062 * @see org.opencms.search.CmsVfsIndexer#getUpdateData(org.opencms.search.CmsSearchIndexSource, java.util.List) 063 */ 064 @Override 065 public CmsSearchIndexUpdateData getUpdateData( 066 CmsSearchIndexSource source, 067 List<CmsPublishedResource> publishedResources) { 068 069 try { 070 // create a new update collection from this indexer and the given index source 071 CmsSearchIndexUpdateData result = new CmsSearchIndexUpdateData(source, this); 072 Iterator<CmsPublishedResource> i = publishedResources.iterator(); 073 while (i.hasNext()) { 074 // check all published resources if they match this indexer / source 075 CmsPublishedResource pubRes = i.next(); 076 // VFS resources will always have a structure id 077 if (!pubRes.getStructureId().isNullUUID()) { 078 // use utility method from CmsProject to check if published resource is "inside" this index source 079 if (CmsProject.isInsideProject(source.getResourcesNames(), pubRes.getRootPath())) { 080 // the resource is "inside" this index source 081 CmsPublishedResource pub = pubRes; 082 // grab the dependencies of this resource 083 CmsDocumentDependency dep = CmsDocumentDependency.load(m_cms, pub); 084 List<CmsDocumentDependency> depsAvailable = dep.getDependencies(); 085 Iterator<CmsDocumentDependency> depIt = depsAvailable.iterator(); 086 do { 087 // add the document to the search index update data 088 addResourceToUpdateData(pub, result); 089 if (!pub.getState().isDeleted()) { 090 // don't need to store dependency info for deleted resources 091 dep.storeInContext(m_cms); 092 } 093 if (depIt.hasNext()) { 094 // add all dependent documents that are not already included in the original publish list 095 pub = depIt.next().getResource(); 096 } else { 097 dep = null; 098 } 099 } while (dep != null); 100 } 101 } 102 } 103 return result; 104 } catch (Exception e) { 105 LOG.error(e.getLocalizedMessage(), e); 106 } 107 return null; 108 } 109 110 /** 111 * @see org.opencms.search.CmsVfsIndexer#isLocaleDependenciesEnable() 112 */ 113 @Override 114 public boolean isLocaleDependenciesEnable() { 115 116 return true; 117 } 118 119 /** 120 * @see org.opencms.search.I_CmsIndexer#rebuildIndex(org.opencms.search.I_CmsIndexWriter, org.opencms.search.CmsIndexingThreadManager, org.opencms.search.CmsSearchIndexSource) 121 */ 122 @Override 123 public void rebuildIndex( 124 I_CmsIndexWriter writer, 125 CmsIndexingThreadManager threadManager, 126 CmsSearchIndexSource source) { 127 128 List<String> resourceNames = source.getResourcesNames(); 129 Iterator<String> i = resourceNames.iterator(); 130 while (i.hasNext()) { 131 // read the resources from all configured source folders 132 String resourceName = i.next(); 133 List<CmsResource> resources = null; 134 try { 135 // read all resources (only files) below the given path 136 resources = m_cms.readResources(resourceName, CmsResourceFilter.IGNORE_EXPIRATION.addRequireFile()); 137 } catch (CmsException e) { 138 if (m_report != null) { 139 m_report.println( 140 Messages.get().container( 141 Messages.RPT_UNABLE_TO_READ_SOURCE_2, 142 resourceName, 143 e.getLocalizedMessage()), 144 I_CmsReport.FORMAT_WARNING); 145 } 146 if (LOG.isWarnEnabled()) { 147 LOG.warn( 148 Messages.get().getBundle().key( 149 Messages.LOG_UNABLE_TO_READ_SOURCE_2, 150 resourceName, 151 m_index.getName()), 152 e); 153 } 154 } 155 if (resources != null) { 156 Map<String, List<CmsResource>> folderLookupMap = createFolderLookupMap(resources); 157 // iterate all resources found in the folder 158 for (CmsResource resource : resources) { 159 List<CmsResource> folderContent = folderLookupMap.get( 160 CmsResource.getFolderPath(resource.getRootPath())); 161 CmsDocumentDependency dep = CmsDocumentDependency.load(m_cms, resource, folderContent); 162 dep.storeInContext(m_cms); 163 // now update all the resources individually 164 updateResource(writer, threadManager, resource); 165 } 166 } 167 } 168 } 169 170 /** 171 * Creates a folder based lookup map for the given resource list.<p> 172 * 173 * @param resources the list of resource to build the lookup map for 174 * 175 * @return a folder based lookup map for the given resource list 176 */ 177 protected Map<String, List<CmsResource>> createFolderLookupMap(List<CmsResource> resources) { 178 179 Map<String, List<CmsResource>> result = new HashMap<String, List<CmsResource>>(128); 180 Iterator<CmsResource> i = resources.iterator(); 181 while (i.hasNext()) { 182 CmsResource res = i.next(); 183 String folderPath = CmsResource.getFolderPath(res.getRootPath()); 184 List<CmsResource> folderContent = result.get(folderPath); 185 if (folderContent == null) { 186 folderContent = new ArrayList<CmsResource>(32); 187 result.put(folderPath, folderContent); 188 } 189 folderContent.add(res); 190 } 191 192 return result; 193 } 194}