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.tools.content.languagecopy; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.i18n.CmsLocaleManager; 033import org.opencms.i18n.CmsMessageContainer; 034import org.opencms.lock.CmsLock; 035import org.opencms.main.CmsException; 036import org.opencms.main.CmsLog; 037import org.opencms.main.OpenCms; 038import org.opencms.report.A_CmsReportThread; 039import org.opencms.report.CmsHtmlReport; 040import org.opencms.report.CmsLogReport; 041import org.opencms.report.CmsMultiplexReport; 042import org.opencms.report.I_CmsReport; 043import org.opencms.xml.content.CmsXmlContent; 044import org.opencms.xml.content.CmsXmlContentFactory; 045 046import java.util.Iterator; 047import java.util.List; 048import java.util.Locale; 049 050import org.apache.commons.logging.Log; 051 052/** 053 * Copies language nodes in XML contents.<p> 054 * 055 * @since 7.5.1 056 */ 057public class CmsLanguageCopyThread extends A_CmsReportThread { 058 059 /** The log object for this class. */ 060 private static final Log LOG = CmsLog.getLog(CmsLanguageCopyThread.class); 061 062 /** The resources to copy. */ 063 private String[] m_copyresources; 064 065 /** The delete flag. */ 066 private boolean m_delete; 067 068 /** The special multiplex report. */ 069 private I_CmsReport m_report; 070 071 /** The source language. */ 072 private String m_sourceLanguage; 073 074 /** The source language. */ 075 private String m_targetLanguage; 076 077 /** 078 * Copies language nodes in XML contents.<p> 079 * 080 * @param cms the current cms context 081 * @param copyResources the resources to copy 082 * @param delete the delete flag 083 * @param sourceLanguage the source language 084 * @param targetLanguage the target language 085 */ 086 public CmsLanguageCopyThread( 087 final CmsObject cms, 088 String[] copyResources, 089 boolean delete, 090 String sourceLanguage, 091 String targetLanguage) { 092 093 super(cms, Messages.get().getBundle().key(Messages.GUI_REPORT_LANGUAGECOPY_NAME_0)); 094 m_copyresources = copyResources; 095 m_sourceLanguage = sourceLanguage; 096 m_targetLanguage = targetLanguage; 097 m_delete = delete; 098 initHtmlReport(cms.getRequestContext().getLocale()); 099 CmsMultiplexReport report = new CmsMultiplexReport(); 100 Locale locale = cms.getRequestContext().getLocale(); 101 report.addReport(new CmsHtmlReport(locale, cms.getRequestContext().getSiteRoot())); 102 report.addReport(new CmsLogReport(locale, CmsLanguageCopyThread.class)); 103 m_report = report; 104 } 105 106 /** 107 * @see org.opencms.report.A_CmsReportThread#getReportUpdate() 108 */ 109 @Override 110 public String getReportUpdate() { 111 112 return getReport().getReportUpdate(); 113 } 114 115 /** 116 * @see java.lang.Runnable#run() 117 */ 118 @Override 119 public void run() { 120 121 CmsMultiplexReport report = (CmsMultiplexReport)getReport(); 122 int totalFiles = m_copyresources.length; 123 Locale sourceLocale = CmsLocaleManager.getLocale(m_sourceLanguage); 124 Locale targetLocale = CmsLocaleManager.getLocale(m_targetLanguage); 125 report.println( 126 Messages.get().container( 127 Messages.GUI_REPORT_LANGUAGEC0PY_START_3, 128 new Object[] {Integer.valueOf(totalFiles), sourceLocale, targetLocale}), 129 I_CmsReport.FORMAT_HEADLINE); 130 131 try { 132 copyLanguageNodes(); 133 } catch (Throwable e) { 134 report.println(e); 135 if (LOG.isErrorEnabled()) { 136 LOG.error(Messages.get().getBundle().key(Messages.ERR_REPORT_LANGUAGEC0PY_0), e); 137 } 138 } 139 // List the errors: 140 List<Object> errors = report.getErrors(); 141 List<Object> warnings = report.getWarnings(); 142 143 report.println( 144 Messages.get().container( 145 Messages.GUI_REPORT_LANGUAGEC0PY_END_2, 146 new Object[] {Integer.valueOf(warnings.size()), Integer.valueOf(errors.size())}), 147 I_CmsReport.FORMAT_HEADLINE); 148 for (Object f : warnings) { 149 if (f instanceof CmsMessageContainer) { 150 report.println((CmsMessageContainer)f, I_CmsReport.FORMAT_WARNING); 151 } 152 } 153 for (Object f : errors) { 154 if (f instanceof CmsMessageContainer) { 155 report.println((CmsMessageContainer)f, I_CmsReport.FORMAT_ERROR); 156 } 157 } 158 } 159 160 /** 161 * @see org.opencms.report.A_CmsReportThread#getReport() 162 */ 163 @Override 164 protected I_CmsReport getReport() { 165 166 return m_report; 167 } 168 169 /** 170 * Does the job.<p> 171 */ 172 private void copyLanguageNodes() { 173 174 CmsObject cms = getCms(); 175 CmsMultiplexReport report = (CmsMultiplexReport)getReport(); 176 CmsFile file; 177 CmsXmlContent content; 178 int totalFiles = m_copyresources.length; 179 int processedFiles = 0; 180 Locale sourceLocale = CmsLocaleManager.getLocale(m_sourceLanguage); 181 Locale targetLocale = CmsLocaleManager.getLocale(m_targetLanguage); 182 183 for (int i = 0; i < m_copyresources.length; i++) { 184 processedFiles++; 185 report.print( 186 org.opencms.report.Messages.get().container( 187 org.opencms.report.Messages.RPT_SUCCESSION_2, 188 new Object[] {String.valueOf(processedFiles), String.valueOf(totalFiles)}), 189 I_CmsReport.FORMAT_NOTE); 190 191 report.print( 192 Messages.get().container(Messages.RPT_LOCALIZATION_BYPASS_1, new Object[] {m_copyresources[i]})); 193 report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0)); 194 195 try { 196 file = cms.readFile(m_copyresources[i]); 197 content = CmsXmlContentFactory.unmarshal(cms, file); 198 199 if (!content.hasLocale(sourceLocale)) { 200 report.println( 201 Messages.get().container( 202 Messages.GUI_REPORT_LANGUAGEC0PY_WARN_SOURCELOCALE_MISSING_1, 203 new Object[] {sourceLocale}), 204 I_CmsReport.FORMAT_WARNING); 205 CmsMessageContainer container = Messages.get().container( 206 Messages.GUI_REPORT_LANGUAGEC0PY_WARN_SOURCELOCALE_MISSING_2, 207 new Object[] {m_copyresources[i], sourceLocale}); 208 report.addWarning(container); 209 } else if (content.hasLocale(targetLocale)) { 210 report.println( 211 Messages.get().container( 212 Messages.GUI_REPORT_LANGUAGEC0PY_WARN_TARGETLOCALE_EXISTS_1, 213 new Object[] {targetLocale}), 214 I_CmsReport.FORMAT_WARNING); 215 CmsMessageContainer container = Messages.get().container( 216 Messages.GUI_REPORT_LANGUAGEC0PY_WARN_TARGETLOCALE_EXISTS_2, 217 new Object[] {m_copyresources[i], targetLocale}); 218 report.addWarning(container); 219 } else { 220 content.copyLocale(sourceLocale, targetLocale); 221 if (m_delete) { 222 content.removeLocale(sourceLocale); 223 } 224 file.setContents(content.marshal()); 225 CmsLock lock = cms.getLock(file); 226 if (lock.isInherited()) { 227 unlockInherited(file.getRootPath()); 228 cms.lockResource(m_copyresources[i]); 229 } else { 230 if (lock.isNullLock()) { 231 cms.lockResource(m_copyresources[i]); 232 } else { 233 if (!lock.isLockableBy(cms.getRequestContext().getCurrentUser())) { 234 cms.changeLock(m_copyresources[i]); 235 } 236 } 237 } 238 cms.writeFile(file); 239 cms.unlockResource(m_copyresources[i]); 240 report.println( 241 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0), 242 I_CmsReport.FORMAT_OK); 243 } 244 245 } catch (Throwable f) { 246 CmsMessageContainer error = Messages.get().container( 247 Messages.GUI_REPORT_LANGUAGEC0PY_ERROR_2, 248 new String[] {m_copyresources[i], CmsException.getStackTraceAsString(f)}); 249 250 report.println( 251 org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0), 252 I_CmsReport.FORMAT_ERROR); 253 // report.println(f); 254 report.addError(error); 255 256 } 257 } 258 } 259 260 /** 261 * Returns the lock of a possible locked parent folder of a resource, system locks are ignored.<p> 262 * 263 * @param absoluteResourceName the name of the resource 264 * 265 * @return the lock of a parent folder, or {@link CmsLock#getNullLock()} 266 * if no parent folders are locked by a non system lock 267 */ 268 private CmsLock getParentFolderLock(final String absoluteResourceName) { 269 270 Iterator<CmsLock> itLocks = OpenCms.getMemoryMonitor().getAllCachedLocks().iterator(); 271 while (itLocks.hasNext()) { 272 CmsLock lock = itLocks.next(); 273 if (lock.getResourceName().endsWith("/") 274 && absoluteResourceName.startsWith(lock.getResourceName()) 275 && !absoluteResourceName.equals(lock.getResourceName())) { 276 // system locks does not get inherited 277 lock = lock.getEditionLock(); 278 // check the lock 279 if (!lock.isUnlocked()) { 280 return lock; 281 } 282 } 283 } 284 return CmsLock.getNullLock(); 285 } 286 287 /** 288 * Returns the inherited lock of a resource.<p> 289 * 290 * @param absoluteResourcename the absolute path of the resource 291 * 292 * @return the inherited lock or the null lock 293 */ 294 private CmsLock getParentLock(final String absoluteResourcename) { 295 296 CmsLock parentFolderLock = getParentFolderLock(absoluteResourcename); 297 if (!parentFolderLock.isNullLock()) { 298 return parentFolderLock; 299 } 300 return CmsLock.getNullLock(); 301 } 302 303 /** 304 * Recursively steps up to the resource that is the originator of the given 305 * resource which has an inherited lock.<p> 306 * 307 * @param absoluteResourcename the absolute resource with the inherited lock 308 * 309 * @throws CmsException if something goes wrong 310 */ 311 private void unlockInherited(final String absoluteResourcename) throws CmsException { 312 313 CmsObject cms = getCms(); 314 CmsLock parentLock = getParentLock(absoluteResourcename); 315 if (!parentLock.isNullLock()) { 316 if (parentLock.isInherited()) { 317 unlockInherited(parentLock.getResourceName()); 318 } else { 319 if (!parentLock.isLockableBy(cms.getRequestContext().getCurrentUser())) { 320 cms.changeLock(cms.getRequestContext().removeSiteRoot(parentLock.getResourceName())); 321 } 322 cms.unlockResource(cms.getRequestContext().removeSiteRoot(parentLock.getResourceName())); 323 } 324 } 325 326 } 327}