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.workplace.threads; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.lock.CmsLock; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsLog; 037import org.opencms.report.A_CmsReportThread; 038import org.opencms.report.I_CmsReport; 039import org.opencms.xml.CmsXmlEntityResolver; 040import org.opencms.xml.CmsXmlException; 041import org.opencms.xml.content.CmsXmlContent; 042import org.opencms.xml.content.CmsXmlContentFactory; 043 044import java.util.Iterator; 045import java.util.List; 046 047import org.apache.commons.logging.Log; 048 049/** 050 * Repairs XML content resources according to their XSD using the corresponding settings object.<p> 051 * 052 */ 053public class CmsXmlContentRepairThread extends A_CmsReportThread { 054 055 /** The log object for this class. */ 056 private static final Log LOG = CmsLog.getLog(CmsXmlContentRepairThread.class); 057 058 /** The dialog settings used to configure the repair thread. */ 059 private CmsXmlContentRepairSettings m_settings; 060 061 /** 062 * Creates a repair XML content resources thread.<p> 063 * 064 * @param cms the current cms context 065 * @param settings the settings needed to perform the repair operation 066 */ 067 public CmsXmlContentRepairThread(CmsObject cms, CmsXmlContentRepairSettings settings) { 068 069 super(cms, Messages.get().getBundle().key(Messages.GUI_XMLCONTENTREPAIR_THREAD_NAME_0)); 070 initHtmlReport(cms.getRequestContext().getLocale()); 071 m_settings = settings; 072 } 073 074 /** 075 * @see org.opencms.report.A_CmsReportThread#getReportUpdate() 076 */ 077 @Override 078 public String getReportUpdate() { 079 080 return getReport().getReportUpdate(); 081 } 082 083 /** 084 * @see java.lang.Runnable#run() 085 */ 086 @Override 087 public void run() { 088 089 getReport().println( 090 Messages.get().container( 091 Messages.RPT_XMLCONTENTREPAIR_BEGIN_2, 092 m_settings.getResourceType(), 093 m_settings.getVfsFolder()), 094 I_CmsReport.FORMAT_HEADLINE); 095 try { 096 // repair the XML content resources 097 repairXmlContents(); 098 } catch (Throwable f) { 099 getReport().println( 100 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0), 101 I_CmsReport.FORMAT_ERROR); 102 getReport().println(f); 103 if (LOG.isErrorEnabled()) { 104 LOG.error(f); 105 } 106 } 107 108 // append runtime statistics to the report output 109 getReport().print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_STAT_0)); 110 getReport().println( 111 org.opencms.report.Messages.get().container( 112 org.opencms.report.Messages.RPT_STAT_DURATION_1, 113 getReport().formatRuntime())); 114 getReport().println(Messages.get().container(Messages.RPT_XMLCONTENTREPAIR_END_0), I_CmsReport.FORMAT_HEADLINE); 115 } 116 117 /** 118 * Performs the correction of the XML content resources according to their XML schema definition.<p> 119 * 120 * @throws CmsException if reading the list of resources to repair fails 121 */ 122 private void repairXmlContents() throws CmsException { 123 124 // set the resource filter to filter XML contents of the selected type 125 CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(m_settings.getResourceTypeId()); 126 String path = CmsResource.getFolderPath(m_settings.getVfsFolder()); 127 // get the list of resources to check 128 List<CmsResource> resources = getCms().readResources(path, filter, m_settings.isIncludeSubFolders()); 129 130 // set the report counters 131 int count = 0; 132 int resSize = resources.size(); 133 134 // create an entity resolver to use 135 CmsXmlEntityResolver resolver = new CmsXmlEntityResolver(getCms()); 136 137 // iterate the resources 138 Iterator<CmsResource> i = resources.iterator(); 139 while (i.hasNext()) { 140 141 count++; 142 CmsResource res = i.next(); 143 144 // generate report output 145 getReport().print( 146 org.opencms.report.Messages.get().container( 147 org.opencms.report.Messages.RPT_SUCCESSION_2, 148 String.valueOf(count), 149 String.valueOf(resSize)), 150 I_CmsReport.FORMAT_NOTE); 151 getReport().print(Messages.get().container(Messages.RPT_PROCESSING_XMLCONTENT_0), I_CmsReport.FORMAT_NOTE); 152 getReport().print( 153 org.opencms.report.Messages.get().container( 154 org.opencms.report.Messages.RPT_ARGUMENT_1, 155 getCms().getSitePath(res))); 156 getReport().print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 157 158 try { 159 160 // get the file contents 161 CmsFile file = getCms().readFile(res); 162 // get the XML content 163 CmsXmlContent xmlContent = CmsXmlContentFactory.unmarshal(getCms(), file); 164 165 // check the XML structure 166 boolean fixFile = m_settings.isForce(); 167 if (!fixFile) { 168 try { 169 xmlContent.validateXmlStructure(resolver); 170 } catch (CmsXmlException e) { 171 // XML structure is not valid, this file has to be fixed 172 fixFile = true; 173 } 174 } 175 if (fixFile) { 176 177 // check the lock state of the file to repair 178 CmsLock lock = getCms().getLock(res); 179 boolean isLocked = false; 180 boolean canWrite = false; 181 if (lock.isNullLock()) { 182 // file is not locked, lock it 183 getCms().lockResource(getCms().getSitePath(res)); 184 isLocked = true; 185 canWrite = true; 186 } else if (lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())) { 187 // file is locked by current user 188 canWrite = true; 189 } 190 191 if (canWrite) { 192 // enable "auto correction mode" - this is required or the XML structure will not be fully corrected 193 xmlContent.setAutoCorrectionEnabled(true); 194 // now correct the XML 195 xmlContent.correctXmlStructure(getCms()); 196 file.setContents(xmlContent.marshal()); 197 // write the corrected file 198 getCms().writeFile(file); 199 } else { 200 // no write operation possible 201 getReport().println( 202 Messages.get().container(Messages.RPT_XMLCONTENTREPAIR_NOTLOCKED_0), 203 I_CmsReport.FORMAT_NOTE); 204 } 205 206 if (isLocked) { 207 // unlock previously locked resource 208 getCms().unlockResource(getCms().getSitePath(res)); 209 } 210 211 if (canWrite) { 212 // successfully repaired XML content, report it 213 getReport().println( 214 Messages.get().container(Messages.RPT_XMLCONTENTREPAIR_REPAIRED_0), 215 I_CmsReport.FORMAT_OK); 216 } 217 218 } else { 219 // nothing to fix, skip this file 220 getReport().println( 221 Messages.get().container(Messages.RPT_XMLCONTENTREPAIR_SKIPFILE_0), 222 I_CmsReport.FORMAT_NOTE); 223 } 224 225 } catch (CmsException e) { 226 // an error occurred, show exception on report output 227 getReport().println(e); 228 } 229 } 230 } 231 232}