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.updatexml;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.types.CmsResourceTypeXmlContent;
035import org.opencms.file.types.CmsResourceTypeXmlPage;
036import org.opencms.lock.CmsLock;
037import org.opencms.main.CmsException;
038import org.opencms.main.CmsLog;
039import org.opencms.report.A_CmsReportThread;
040import org.opencms.report.I_CmsReport;
041import org.opencms.util.CmsStringUtil;
042
043import java.util.ArrayList;
044import java.util.Iterator;
045import java.util.List;
046
047import org.apache.commons.logging.Log;
048
049/**
050 * Converting xml contents according to new schema.
051 * <p>
052 *
053 * @since 7.0.5
054 */
055public class CmsUpdateXmlThread extends A_CmsReportThread {
056
057    /** The log object for this class. */
058    private static final Log LOG = CmsLog.getLog(CmsUpdateXmlThread.class);
059
060    /** Current CmsObject. */
061    private CmsObject m_cmsObject;
062
063    /** Number of errors while updating. */
064    private int m_errorUpdate;
065
066    /** Number of locked files during updating. */
067    private int m_lockedFiles;
068
069    /** Settings. */
070    private CmsUpdateXmlSettings m_settings;
071
072    /**
073     * Creates a replace html tag Thread.<p>
074     *
075     * @param cms the current cms context.
076     *
077     * @param settings the settings needed to perform the operation.
078     */
079    public CmsUpdateXmlThread(CmsObject cms, CmsUpdateXmlSettings settings) {
080
081        super(cms, Messages.get().getBundle().key(Messages.GUI_UPDATEXML_THREAD_NAME_0));
082        initHtmlReport(cms.getRequestContext().getLocale());
083        m_cmsObject = cms;
084        m_settings = settings;
085    }
086
087    /**
088     * @see org.opencms.report.A_CmsReportThread#getReportUpdate()
089     */
090    @Override
091    public String getReportUpdate() {
092
093        return getReport().getReportUpdate();
094    }
095
096    /**
097     * @see java.lang.Runnable#run()
098     */
099    @Override
100    public void run() {
101
102        I_CmsReport report = getReport();
103        report.println(
104            Messages.get().container(Messages.RPT_UPDATEXML_BEGIN_UPDATE_THREAD_0),
105            I_CmsReport.FORMAT_HEADLINE);
106        try {
107            // update xml contents
108            updateXmlContents(report, m_settings.getVfsFolder(), m_settings.getIncludeSubFolders(), m_cmsObject);
109        } catch (Throwable f) {
110            m_errorUpdate += 1;
111            report.println(Messages.get().container(Messages.RPT_UPDATETXML_UPDATE_ERROR_0));
112            if (LOG.isErrorEnabled()) {
113                LOG.error(f.toString());
114            }
115        }
116
117        // append runtime statistics to report
118        getReport().print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_STAT_0));
119        getReport().println(
120            org.opencms.report.Messages.get().container(
121                org.opencms.report.Messages.RPT_STAT_DURATION_1,
122                getReport().formatRuntime()));
123        getReport().println(
124            Messages.get().container(Messages.RPT_UPDATEXML_END_UPDATE_THREAD_0),
125            I_CmsReport.FORMAT_HEADLINE);
126    }
127
128    /**
129     * Locks the current resource.<p>
130     *
131     * @param cms the current CmsObject
132     * @param cmsResource the resource to lock
133     * @param report the report
134     *
135     * @throws CmsException if some goes wrong
136     */
137    private boolean lockResource(CmsObject cms, CmsResource cmsResource, I_CmsReport report) throws CmsException {
138
139        CmsLock lock = cms.getLock(getCms().getSitePath(cmsResource));
140        // check the lock
141        if ((lock != null)
142            && lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())
143            && lock.isOwnedInProjectBy(
144                getCms().getRequestContext().getCurrentUser(),
145                getCms().getRequestContext().getCurrentProject())) {
146            // prove is current lock from current user in current project
147            return true;
148        } else if ((lock != null)
149            && !lock.isUnlocked()
150            && !lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())) {
151            // the resource is not locked by the current user, so can not lock it
152            m_lockedFiles += 1;
153            return false;
154        } else if ((lock != null)
155            && !lock.isUnlocked()
156            && lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())
157            && !lock.isOwnedInProjectBy(
158                getCms().getRequestContext().getCurrentUser(),
159                getCms().getRequestContext().getCurrentProject())) {
160            // prove is current lock from current user but not in current project
161            // file is locked by current user but not in current project
162            // change the lock
163            cms.changeLock(getCms().getSitePath(cmsResource));
164        } else if ((lock != null) && lock.isUnlocked()) {
165            // lock resource from current user in current project
166            cms.lockResource(getCms().getSitePath(cmsResource));
167        }
168        lock = cms.getLock(getCms().getSitePath(cmsResource));
169        if ((lock != null)
170            && lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())
171            && !lock.isOwnedInProjectBy(
172                getCms().getRequestContext().getCurrentUser(),
173                getCms().getRequestContext().getCurrentProject())) {
174            // resource could not be locked
175            m_lockedFiles += 1;
176
177            return false;
178        }
179        // resource is locked successfully
180        return true;
181    }
182
183    /**
184     * The method to update xml contents.<p>
185     *
186     * @param report I_CmsReport
187     * @param resourcePath Path to update xml contents in
188     * @param inclSubFolder true, if also resources in subfolders in the vfs folder shall be updated, otherwise false
189     * @param cmsObject Current CmsObject
190     */
191    @SuppressWarnings("unchecked")
192    private void updateXmlContents(
193        I_CmsReport report,
194        String resourcePath,
195        boolean inclSubFolder,
196        CmsObject cmsObject) {
197
198        // write parameters to report
199        report.println(Messages.get().container(Messages.RPT_UPDATEXML_BEGIN_UPDATE_0), I_CmsReport.FORMAT_NOTE);
200        report.println(Messages.get().container(Messages.RPT_UPDATEXML_PARAMETERS_0), I_CmsReport.FORMAT_HEADLINE);
201        report.println(
202            Messages.get().container(Messages.RPT_UPDATEXML_PARAMETERS_RESOURCE_PATH_1, resourcePath),
203            I_CmsReport.FORMAT_NOTE);
204        report.println(
205            Messages.get().container(
206                Messages.RPT_UPDATEXML_PARAMETERS_INC_SUBFOLDERS_1,
207                Boolean.valueOf(inclSubFolder).toString()),
208            I_CmsReport.FORMAT_NOTE);
209
210        // check for valid parameters (vfs folder)
211        if (CmsStringUtil.isEmpty(resourcePath)) {
212            report.println(Messages.get().container(Messages.RPT_UPDATEXML_NO_VFS_FOLDER_0), I_CmsReport.FORMAT_ERROR);
213            return;
214        }
215
216        // read all files in the vfs folder
217        report.println(Messages.get().container(Messages.RPT_UPDATEXML_START_SEARCHING_0), I_CmsReport.FORMAT_HEADLINE);
218        List<CmsResource> allFiles = null;
219        try {
220            allFiles = cmsObject.readResources(resourcePath, CmsResourceFilter.DEFAULT, inclSubFolder);
221        } catch (CmsException e) {
222            m_errorUpdate += 1;
223            report.println(Messages.get().container(Messages.RPT_UPDATEXML_SEARCH_ERROR_0), I_CmsReport.FORMAT_ERROR);
224            if (LOG.isErrorEnabled()) {
225                LOG.error(e.getMessageContainer(), e);
226            }
227            report.println(Messages.get().container(Messages.RPT_UPDATEXML_END_UPDATE_0), I_CmsReport.FORMAT_NOTE);
228            return;
229        }
230
231        // get the files to update
232        List<CmsResource> files2Update = new ArrayList<CmsResource>();
233        Iterator<CmsResource> iter = allFiles.iterator();
234        while (iter.hasNext()) {
235            CmsResource cmsResource = iter.next();
236            // only update Xml contents
237            if (cmsResource.isFile()
238                && (CmsResourceTypeXmlContent.isXmlContent(cmsResource)
239                    || CmsResourceTypeXmlPage.isXmlPage(cmsResource))) {
240                files2Update.add(cmsResource);
241            }
242        }
243
244        // number of files to update
245        int nrOfFiles = files2Update.size();
246        report.println(
247            Messages.get().container(Messages.RPT_UPDATEXML_FILES_TO_UPDATE_1, Integer.valueOf(nrOfFiles).toString()),
248            I_CmsReport.FORMAT_NOTE);
249        // the file counter
250        int fileCounter = 0;
251        // update the files
252        if (nrOfFiles > 0) {
253            // report entry
254            report.println(
255                Messages.get().container(Messages.RPT_UPDATEXML_START_UPDATING_0),
256                I_CmsReport.FORMAT_HEADLINE);
257            // loop over all files
258            iter = files2Update.iterator();
259            while (iter.hasNext()) {
260                CmsResource cmsResource = iter.next();
261                fileCounter += 1;
262                // report entries
263                report.print(
264                    org.opencms.report.Messages.get().container(
265                        org.opencms.report.Messages.RPT_SUCCESSION_2,
266                        String.valueOf(fileCounter),
267                        String.valueOf(nrOfFiles)),
268                    I_CmsReport.FORMAT_NOTE);
269                report.print(Messages.get().container(Messages.RPT_UPDATEXML_CURRENT_FILE_0), I_CmsReport.FORMAT_NOTE);
270                report.print(
271                    org.opencms.report.Messages.get().container(
272                        org.opencms.report.Messages.RPT_ARGUMENT_1,
273                        report.removeSiteRoot(cmsResource.getRootPath())));
274                report.print(
275                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0),
276                    I_CmsReport.FORMAT_DEFAULT);
277
278                // get current lock from file
279                try {
280                    // try to lock the resource
281                    if (!lockResource(cmsObject, cmsResource, report)) {
282                        report.println(
283                            Messages.get().container(
284                                Messages.RPT_UPDATEXML_LOCKED_FILE_0,
285                                cmsObject.getSitePath(cmsResource)),
286                            I_CmsReport.FORMAT_ERROR);
287                        continue;
288                    }
289                } catch (CmsException e) {
290                    report.println(
291                        Messages.get().container(
292                            Messages.RPT_UPDATEXML_LOCKED_FILE_0,
293                            cmsObject.getSitePath(cmsResource)),
294                        I_CmsReport.FORMAT_ERROR);
295                    if (LOG.isErrorEnabled()) {
296                        LOG.error(e.getMessageContainer(), e);
297                    }
298                    continue;
299                }
300
301                // write the resource
302                try {
303                    // do not change the date last modified
304                    long lastModified = cmsResource.getDateLastModified();
305                    CmsFile cmsFile = cmsObject.readFile(cmsResource);
306                    cmsFile.setDateLastModified(lastModified);
307                    cmsObject.writeFile(cmsFile);
308                } catch (Exception e) {
309                    m_errorUpdate += 1;
310                    report.println(
311                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0),
312                        I_CmsReport.FORMAT_ERROR);
313                    if (LOG.isErrorEnabled()) {
314                        LOG.error(e.toString());
315                    }
316                    continue;
317                }
318
319                // unlock the resource
320                try {
321                    cmsObject.unlockResource(cmsObject.getSitePath(cmsResource));
322                } catch (CmsException e) {
323                    m_errorUpdate += 1;
324                    report.println(
325                        Messages.get().container(Messages.RPT_UPDATEXML_UNLOCK_FILE_0),
326                        I_CmsReport.FORMAT_WARNING);
327                    if (LOG.isErrorEnabled()) {
328                        LOG.error(e.getMessageContainer(), e);
329                    }
330                    continue;
331                }
332                // successfully updated
333                report.println(
334                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
335                    I_CmsReport.FORMAT_OK);
336            }
337        } else {
338            // no files to update
339            report.println(Messages.get().container(Messages.RPT_UPDATEXML_NO_FILES_FOUND_0), I_CmsReport.FORMAT_NOTE);
340        }
341
342        // the results are written in the report
343        report.println(Messages.get().container(Messages.RPT_UPDATEXML_RESULT_0), I_CmsReport.FORMAT_HEADLINE);
344        report.println(
345            Messages.get().container(Messages.RPT_UPDATEXML_FILES_TO_UPDATE_1, Integer.valueOf(nrOfFiles).toString()),
346            I_CmsReport.FORMAT_NOTE);
347        report.println(
348            Messages.get().container(
349                Messages.RPT_UPDATEXML_UPDATE_NUMBER_ERRORS_1,
350                Integer.valueOf(m_errorUpdate).toString()),
351            I_CmsReport.FORMAT_NOTE);
352        report.println(
353            Messages.get().container(Messages.RPT_UPDATEXML_LOCKED_FILES_1, Integer.valueOf(m_lockedFiles).toString()),
354            I_CmsReport.FORMAT_NOTE);
355        if (m_lockedFiles > 0) {
356            report.println(Messages.get().container(Messages.RPT_UPDATEXML_UPDATE_FAILED_0), I_CmsReport.FORMAT_ERROR);
357        } else {
358            report.println(Messages.get().container(Messages.RPT_UPDATEXML_UPDATE_SUCCESS_0), I_CmsReport.FORMAT_OK);
359        }
360        report.println(Messages.get().container(Messages.RPT_UPDATEXML_END_UPDATE_0), I_CmsReport.FORMAT_NOTE);
361    }
362}