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.searchindex.sourcesearch;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProject;
033import org.opencms.file.CmsResource;
034import org.opencms.file.CmsResourceFilter;
035import org.opencms.file.types.CmsResourceTypeXmlContent;
036import org.opencms.file.types.I_CmsResourceType;
037import org.opencms.i18n.CmsLocaleManager;
038import org.opencms.loader.CmsLoaderException;
039import org.opencms.lock.CmsLock;
040import org.opencms.main.CmsException;
041import org.opencms.main.CmsLog;
042import org.opencms.main.OpenCms;
043import org.opencms.report.A_CmsReportThread;
044import org.opencms.report.I_CmsReport;
045import org.opencms.search.CmsSearchException;
046import org.opencms.search.solr.CmsSolrIndex;
047import org.opencms.search.solr.CmsSolrQuery;
048import org.opencms.util.CmsRequestUtil;
049import org.opencms.util.CmsStringUtil;
050import org.opencms.xml.CmsXmlUtils;
051import org.opencms.xml.content.CmsXmlContent;
052import org.opencms.xml.content.CmsXmlContentFactory;
053import org.opencms.xml.types.I_CmsXmlContentValue;
054
055import java.util.ArrayList;
056import java.util.HashSet;
057import java.util.Iterator;
058import java.util.List;
059import java.util.Locale;
060import java.util.Set;
061import java.util.regex.Matcher;
062import java.util.regex.Pattern;
063
064import javax.servlet.http.HttpSession;
065
066import org.apache.commons.logging.Log;
067
068/**
069 * Searches in sources.
070 * <p>
071 *
072 * @since 7.5.3
073 */
074public class CmsSearchReplaceThread extends A_CmsReportThread {
075
076    /** The log object for this class. */
077    private static final Log LOG = CmsLog.getLog(CmsSearchReplaceThread.class);
078
079    /** The number of Solr search results to be processed at maximum. */
080    private static final int MAX_PROCESSED_SOLR_RESULTS = 10000;
081
082    /** Number of errors while searching. */
083    private int m_errorSearch;
084
085    /** Number of errors while updating. */
086    private int m_errorUpdate;
087
088    /** Number of locked files during updating. */
089    private int m_lockedFiles;
090
091    /** The found resources. */
092    private Set<CmsResource> m_matchedResources = new HashSet<CmsResource>();
093
094    /** The current session. */
095    private HttpSession m_session;
096
097    /** Settings. */
098    private CmsSearchReplaceSettings m_settings;
099
100    /**
101     * Creates a replace html tag Thread.<p>
102     *
103     * @param session the current session
104     * @param cms the current cms object
105     * @param settings the settings needed to perform the operation.
106     */
107    public CmsSearchReplaceThread(HttpSession session, CmsObject cms, CmsSearchReplaceSettings settings) {
108
109        super(cms, "searchAndReplace");
110        initHtmlReport(cms.getRequestContext().getLocale());
111        m_session = session;
112        m_settings = settings;
113    }
114
115    /**
116     * @see org.opencms.report.A_CmsReportThread#getReportUpdate()
117     */
118    @Override
119    public String getReportUpdate() {
120
121        return getReport().getReportUpdate();
122    }
123
124    /**
125     * @see java.lang.Runnable#run()
126     */
127    @Override
128    public void run() {
129
130        // get the report
131        I_CmsReport report = getReport();
132        boolean isError = false;
133        report.println(
134            Messages.get().container(Messages.RPT_SOURCESEARCH_BEGIN_SEARCH_THREAD_0),
135            I_CmsReport.FORMAT_HEADLINE);
136        // write parameters to report
137        report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_0), I_CmsReport.FORMAT_HEADLINE);
138        // the paths
139        if (!m_settings.getPaths().isEmpty()) {
140            // iterate over the paths
141            Iterator<String> iter = m_settings.getPaths().iterator();
142            while (iter.hasNext()) {
143                String path = iter.next();
144                report.println(
145                    Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_RESOURCE_PATH_1, path),
146                    I_CmsReport.FORMAT_NOTE);
147            }
148        } else {
149            // no paths selected
150            isError = true;
151            report.println(
152                Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_EMPTY_RESOURCE_PATHS_0),
153                I_CmsReport.FORMAT_ERROR);
154        }
155        // the search pattern
156        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_settings.getSearchpattern())) {
157            // there is a search pattern
158            report.println(
159                Messages.get().container(
160                    Messages.RPT_SOURCESEARCH_PARAMETERS_SEARCHPATTERN_1,
161                    CmsStringUtil.escapeHtml(m_settings.getSearchpattern())),
162                I_CmsReport.FORMAT_NOTE);
163        } else {
164            // empty search pattern
165            isError = true;
166            report.println(
167                Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_EMPTY_SEARCHPATTERN_0),
168                I_CmsReport.FORMAT_ERROR);
169        }
170        // the replace pattern
171        report.println(
172            Messages.get().container(
173                Messages.RPT_SOURCESEARCH_PARAMETERS_REPLACEPATTERN_1,
174                CmsStringUtil.escapeHtml(m_settings.getReplacepattern())),
175            I_CmsReport.FORMAT_NOTE);
176        // the project
177        report.println(
178            Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_PROJECT_1, m_settings.getProject()),
179            I_CmsReport.FORMAT_NOTE);
180        // remarks for search/replace dependent od the replace pattern and the selected project
181        // in the online project search is possible only
182        // in other projects there is replaced, if the replace pattern is not empty
183        boolean replace = false;
184        if (CmsStringUtil.isEmpty(m_settings.getReplacepattern()) && !m_settings.isForceReplace()) {
185            // empty replace pattern, search only
186            report.println(
187                Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_EMPTY_REPLACEPATTERN_0),
188                I_CmsReport.FORMAT_NOTE);
189        } else {
190            // not empty replace pattern, search and replace
191            replace = true;
192            report.println(
193                Messages.get().container(Messages.RPT_SOURCESEARCH_PARAMETERS_NOTEMPTY_REPLACEPATTERN_0),
194                I_CmsReport.FORMAT_NOTE);
195        }
196
197        // make an OpenCms object copy if replace is active
198        CmsObject cmsObject = getCms();
199        if (replace && !m_settings.getProject().equals(cmsObject.getRequestContext().getCurrentProject().getName())) {
200            try {
201                cmsObject = OpenCms.initCmsObject(getCms());
202                CmsProject cmsProject = getCms().readProject(m_settings.getProject());
203                cmsObject.getRequestContext().setCurrentProject(cmsProject);
204            } catch (CmsException e) {
205                report.println(
206                    Messages.get().container(Messages.RPT_SOURCESEARCH_INIT_CMS_OBJECT_FAILED_0),
207                    I_CmsReport.FORMAT_NOTE);
208                replace = false;
209            }
210        }
211
212        // search the resources and replace the patterns
213        if (!isError) {
214            List<CmsResource> resources = searchResources(report, cmsObject);
215
216            if (resources.isEmpty()) {
217                // no resources found, so search is not possible
218                report.println(
219                    Messages.get().container(Messages.RPT_SOURCESEARCH_NO_FILES_TO_SEARCH_IN_0),
220                    I_CmsReport.FORMAT_NOTE);
221            } else {
222
223                report.println(
224                    Messages.get().container(
225                        Messages.RPT_SOURCESEARCH_NR_OF_FILES_TO_SEARCH_IN_1,
226                        new Integer(resources.size())),
227                    I_CmsReport.FORMAT_NOTE);
228                if (replace) {
229                    // start searching and replacing
230                    report.println(
231                        Messages.get().container(Messages.RPT_SOURCESEARCH_START_SEARCHING_REPLACING_0),
232                        I_CmsReport.FORMAT_HEADLINE);
233                } else {
234                    // start searching
235                    report.println(
236                        Messages.get().container(Messages.RPT_SOURCESEARCH_START_SEARCHING_0),
237                        I_CmsReport.FORMAT_HEADLINE);
238                }
239
240                searchAndReplace(cmsObject, resources, replace, report);
241            }
242
243            // show the resources
244            // save the matched file list in the session
245            m_session.setAttribute(
246                CmsSearchReplaceSettings.ATTRIBUTE_NAME_SOURCESEARCH_RESULT_LIST,
247                m_matchedResources);
248        } else {
249            // do not show the resources, because there were errors while searching
250        }
251
252        report.println(
253            Messages.get().container(Messages.RPT_SOURCESEARCH_END_SEARCH_THREAD_0),
254            I_CmsReport.FORMAT_HEADLINE);
255    }
256
257    /**
258     * Search the resources.<p>
259     *
260     * @param cmsObject the CmsObject using to write files
261     * @param resources the relevant resources
262     * @param replace true, if search and replace. False is search only.
263     * @param report the report.
264     */
265    protected void searchAndReplace(
266        CmsObject cmsObject,
267        List<CmsResource> resources,
268        boolean replace,
269        I_CmsReport report) {
270
271        // the file counter
272        int counter = 0;
273        int resCount = resources.size();
274
275        // iterate over the files in the selected path
276        for (CmsResource resource : resources) {
277
278            try {
279
280                // get the content
281                CmsFile file = getCms().readFile(resource);
282                byte[] contents = file.getContents();
283
284                // report the current resource
285                ++counter;
286                report(report, counter, resCount, resource);
287
288                // search and replace
289                byte[] result = null;
290                boolean xpath = false;
291                if ((CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_settings.getXpath())
292                    || m_settings.isOnlyContentValues()) && CmsResourceTypeXmlContent.isXmlContent(resource)) {
293                    xpath = true;
294                }
295                if (!xpath) {
296                    result = replaceInContent(cmsObject, report, file, contents, replace);
297                } else {
298                    result = replaceInXml(cmsObject, file, replace, report);
299                }
300
301                if ((result != null) && (contents != null) && !contents.equals(result)) {
302                    // rewrite the content
303                    writeContent(cmsObject, report, file, result);
304                }
305
306            } catch (Exception e) {
307                report.print(
308                    org.opencms.report.Messages.get().container(Messages.RPT_SOURCESEARCH_COULD_NOT_READ_FILE_0),
309                    I_CmsReport.FORMAT_ERROR);
310                report.addError(e);
311                report.println(
312                    org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0),
313                    I_CmsReport.FORMAT_ERROR);
314                m_errorSearch += 1;
315                LOG.error(
316                    org.opencms.report.Messages.get().container(Messages.RPT_SOURCESEARCH_COULD_NOT_READ_FILE_0),
317                    e);
318                continue;
319            }
320        }
321
322        // report results
323        reportResults(replace, report, resources.size());
324    }
325
326    /**
327     * Locks the current resource.<p>
328     *
329     * @param cms the current CmsObject
330     * @param cmsResource the resource to lock
331     * @param report the report
332     *
333     * @return <code>true</code> if the given resource was locked was successfully
334     *
335     * @throws CmsException if some goes wrong
336     */
337    private boolean lockResource(CmsObject cms, CmsResource cmsResource, I_CmsReport report) throws CmsException {
338
339        CmsLock lock = cms.getLock(cms.getSitePath(cmsResource));
340        // check the lock
341        if ((lock != null)
342            && lock.isOwnedBy(cms.getRequestContext().getCurrentUser())
343            && lock.isOwnedInProjectBy(
344                cms.getRequestContext().getCurrentUser(),
345                cms.getRequestContext().getCurrentProject())) {
346            // prove is current lock from current user in current project
347            return true;
348        } else if ((lock != null) && !lock.isUnlocked() && !lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) {
349            // the resource is not locked by the current user, so can not lock it
350            m_lockedFiles += 1;
351            return false;
352        } else if ((lock != null)
353            && !lock.isUnlocked()
354            && lock.isOwnedBy(cms.getRequestContext().getCurrentUser())
355            && !lock.isOwnedInProjectBy(
356                cms.getRequestContext().getCurrentUser(),
357                cms.getRequestContext().getCurrentProject())) {
358            // prove is current lock from current user but not in current project
359            // file is locked by current user but not in current project
360            // change the lock
361            cms.changeLock(cms.getSitePath(cmsResource));
362        } else if ((lock != null) && lock.isUnlocked()) {
363            // lock resource from current user in current project
364            cms.lockResource(cms.getSitePath(cmsResource));
365        }
366        lock = cms.getLock(cms.getSitePath(cmsResource));
367        if ((lock != null)
368            && lock.isOwnedBy(cms.getRequestContext().getCurrentUser())
369            && !lock.isOwnedInProjectBy(
370                cms.getRequestContext().getCurrentUser(),
371                cms.getRequestContext().getCurrentProject())) {
372            // resource could not be locked
373            m_lockedFiles += 1;
374
375            return false;
376        }
377        // resource is locked successfully
378        return true;
379    }
380
381    /**
382     * Performs the replacement in content.<p>
383     *
384     * @param cmsObject the cms context
385     * @param report the report to print messages to
386     * @param file the file object
387     * @param contents the byte content
388     * @param replace signals whether to execute a replacement or not
389     *
390     * @return the new content if a replacement has been performed
391     *
392     * @throws Exception if something goes wrong
393     */
394    private byte[] replaceInContent(
395        CmsObject cmsObject,
396        I_CmsReport report,
397        CmsFile file,
398        byte[] contents,
399        boolean replace)
400    throws Exception {
401
402        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_settings.getLocale())) {
403            Locale contentLocale = CmsLocaleManager.getMainLocale(cmsObject, file);
404            if (!contentLocale.toString().equalsIgnoreCase(m_settings.getLocale())) {
405                // content does not match the requested locale, skip it
406                report.println(
407                    Messages.get().container(Messages.RPT_SOURCESEARCH_NOT_MATCHED_0),
408                    I_CmsReport.FORMAT_NOTE);
409                return null;
410            }
411        }
412
413        String encoding = CmsLocaleManager.getResourceEncoding(cmsObject, file);
414        String content = new String(contents, encoding);
415
416        Matcher matcher;
417        matcher = Pattern.compile(m_settings.getSearchpattern()).matcher(content);
418        if (matcher.find()) {
419            // search pattern did match here, so take this file in the list with matches resources
420            m_matchedResources.add(file);
421            report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_MATCHED_0), I_CmsReport.FORMAT_OK);
422            if (replace) {
423                return matcher.replaceAll(m_settings.getReplacepattern()).getBytes(encoding);
424            }
425        } else {
426            // search pattern did not match
427            report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_NOT_MATCHED_0), I_CmsReport.FORMAT_NOTE);
428        }
429        return null;
430    }
431
432    /**
433     * Performs a replacement for XML contents.<p>
434     *
435     * @param cmsObject the cms object to perform the actio with
436     * @param cmsFile the file to operate on
437     * @param replace <code>true</code> if a replacement should be performed
438     * @param report the report to print messages to
439     *
440     * @return the marshaled content
441     * @throws Exception if something goes wrong
442     */
443    private byte[] replaceInXml(CmsObject cmsObject, CmsFile cmsFile, boolean replace, I_CmsReport report)
444    throws Exception {
445
446        Exception e = null;
447        CmsXmlContent xmlContent = CmsXmlContentFactory.unmarshal(cmsObject, cmsFile);
448        Pattern pattern = Pattern.compile(m_settings.getSearchpattern());
449        // loop over the locales of the content
450        boolean modified = false;
451        boolean matched = false;
452        String requestedLocale = m_settings.getLocale();
453        for (Locale locale : xmlContent.getLocales()) {
454            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(requestedLocale)
455                && !locale.toString().equalsIgnoreCase(requestedLocale)) {
456                // does not match the requested locale, skip it
457                continue;
458            }
459            // loop over the available element paths of the current content locale
460            List<String> paths = xmlContent.getNames(locale);
461            for (String xpath : paths) {
462                // try to get the value extraction for the current element path
463                I_CmsXmlContentValue value = xmlContent.getValue(xpath, locale);
464                if (value.isSimpleType()) {
465                    try {
466                        String currPath = value.getPath();
467                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_settings.getXpath())
468                            || currPath.equals(m_settings.getXpath())
469                            || (CmsXmlUtils.removeXpath(currPath).equals(m_settings.getXpath()))) {
470                            // xpath match
471                            String oldVal = value.getStringValue(cmsObject);
472                            Matcher matcher = pattern.matcher(oldVal);
473                            matcher = Pattern.compile(m_settings.getSearchpattern()).matcher(oldVal);
474                            if (matcher.find()) {
475                                matched = true;
476                                m_matchedResources.add(cmsFile);
477                                if (replace) {
478                                    String newVal = matcher.replaceAll(m_settings.getReplacepattern());
479                                    if (!oldVal.equals(newVal)) {
480                                        value.setStringValue(cmsObject, newVal);
481                                        modified = true;
482                                    }
483                                }
484                            }
485                        }
486                    } catch (Exception ex) {
487                        // log and go on
488                        LOG.error(ex.getMessage(), ex);
489                        e = ex;
490                    }
491                }
492            }
493        }
494        if (e != null) {
495            throw e;
496        }
497        if (matched) {
498            report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_MATCHED_0), I_CmsReport.FORMAT_OK);
499        } else {
500            report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_NOT_MATCHED_0), I_CmsReport.FORMAT_NOTE);
501        }
502        if (modified) {
503            return xmlContent.marshal();
504        }
505        return null;
506    }
507
508    /**
509     * Reads the content as byte array of the given resource and prints a message to the report.<p>
510     *
511     * @param report the report
512     * @param counter the counter
513     * @param resCount the total resource count
514     * @param resource the file to get the content for
515     */
516    private void report(I_CmsReport report, int counter, int resCount, CmsResource resource) {
517
518        // report entries
519        report.print(
520            org.opencms.report.Messages.get().container(
521                org.opencms.report.Messages.RPT_SUCCESSION_2,
522                String.valueOf(counter),
523                String.valueOf(resCount)),
524            I_CmsReport.FORMAT_NOTE);
525        report.print(
526            org.opencms.report.Messages.get().container(
527                org.opencms.report.Messages.RPT_ARGUMENT_1,
528                report.removeSiteRoot(resource.getRootPath())));
529        report.print(
530            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0),
531            I_CmsReport.FORMAT_DEFAULT);
532    }
533
534    /**
535     * Prints the result messages into the report.<p>
536     *
537     * @param replace if replacement has to be executed
538     * @param report the report to use
539     * @param nrOfFiles the total number of files
540     */
541    private void reportResults(boolean replace, I_CmsReport report, int nrOfFiles) {
542
543        // report entries
544        if (replace) {
545            // finish searching and replacing
546            report.println(
547                Messages.get().container(Messages.RPT_SOURCESEARCH_END_SEARCHING_REPLACING_0),
548                I_CmsReport.FORMAT_HEADLINE);
549        } else {
550            // finish searching
551            report.println(
552                Messages.get().container(Messages.RPT_SOURCESEARCH_END_SEARCHING_0),
553                I_CmsReport.FORMAT_HEADLINE);
554        }
555        // the results are written in the report
556        report.println(Messages.get().container(Messages.RPT_SOURCESEARCH_RESULT_0), I_CmsReport.FORMAT_HEADLINE);
557        report.println(
558            Messages.get().container(
559                Messages.RPT_SOURCESEARCH_NR_OF_FILES_TO_SEARCH_IN_1,
560                new Integer(nrOfFiles).toString()),
561            I_CmsReport.FORMAT_NOTE);
562        report.println(
563            Messages.get().container(
564                Messages.RPT_SOURCESEARCH_NR_OF_FILES_MATCHED_1,
565                new Integer(m_matchedResources.size()).toString()),
566            I_CmsReport.FORMAT_NOTE);
567        report.println(
568            Messages.get().container(
569                Messages.RPT_SOURCESEARCH_SEARCH_ERROR_COUNT_1,
570                new Integer(m_errorSearch).toString()),
571            I_CmsReport.FORMAT_NOTE);
572        if (replace) {
573            // replace report entries
574            report.println(
575                Messages.get().container(
576                    Messages.RPT_SOURCESEARCH_REPLACE_ERROR_COUNT_1,
577                    new Integer(m_errorUpdate).toString()),
578                I_CmsReport.FORMAT_NOTE);
579            report.println(
580                Messages.get().container(
581                    Messages.RPT_SOURCESEARCH_LOCKED_FILES_1,
582                    new Integer(m_lockedFiles).toString()),
583                I_CmsReport.FORMAT_NOTE);
584            if (m_matchedResources.size() == 0) {
585                report.println(
586                    Messages.get().container(Messages.RPT_SOURCESEARCH_NO_FILES_FOUND_0),
587                    I_CmsReport.FORMAT_OK);
588            } else {
589                report.println(
590                    Messages.get().container(Messages.RPT_SOURCESEARCH_CLICK_OK_TO_GET_LIST_0),
591                    I_CmsReport.FORMAT_OK);
592            }
593            if (m_lockedFiles > 0) {
594                report.println(
595                    Messages.get().container(Messages.RPT_SOURCESEARCH_REPLACE_FAILED_0),
596                    I_CmsReport.FORMAT_ERROR);
597            } else {
598                report.println(
599                    Messages.get().container(Messages.RPT_SOURCESEARCH_REPLACE_SUCCESS_0),
600                    I_CmsReport.FORMAT_OK);
601            }
602        } else {
603            // search report entries
604            if (m_matchedResources.size() == 0) {
605                report.println(
606                    Messages.get().container(Messages.RPT_SOURCESEARCH_NO_FILES_FOUND_0),
607                    I_CmsReport.FORMAT_OK);
608            } else {
609                report.println(
610                    Messages.get().container(Messages.RPT_SOURCESEARCH_CLICK_OK_TO_GET_LIST_0),
611                    I_CmsReport.FORMAT_OK);
612            }
613            if (m_errorSearch > 0) {
614                // only searching failed
615                report.println(
616                    Messages.get().container(Messages.RPT_SOURCESEARCH_SEARCH_FAILED_0),
617                    I_CmsReport.FORMAT_ERROR);
618            } else {
619                // only searching was successful
620                report.println(
621                    Messages.get().container(Messages.RPT_SOURCESEARCH_SEARCH_SUCCESS_0),
622                    I_CmsReport.FORMAT_OK);
623            }
624        }
625    }
626
627    /**
628     * Searches/reads all resources that are relevant.<p>
629     *
630     * @param report the report
631     * @param cmsObject the cms Object to use
632     *
633     * @return the relevant resources
634     */
635    private List<CmsResource> searchResources(I_CmsReport report, CmsObject cmsObject) {
636
637        report.println(
638            Messages.get().container(Messages.RPT_SOURCESEARCH_START_COLLECTING_FILES_TO_SEARCH_IN_0),
639            I_CmsReport.FORMAT_HEADLINE);
640
641        List<CmsResource> resources = new ArrayList<CmsResource>();
642        if (m_settings.isSolrSearch()) {
643            CmsSolrIndex index = OpenCms.getSearchManager().getIndexSolr(m_settings.getSource());
644            if (index != null) {
645                CmsSolrQuery query = new CmsSolrQuery(
646                    null,
647                    CmsRequestUtil.createParameterMap(m_settings.getQuery() + "&fl=path,type"));
648                query.setSearchRoots(m_settings.getPaths());
649                if ((m_settings.getTypesArray() != null) && (m_settings.getTypesArray().length > 0)) {
650                    query.setResourceTypes(m_settings.getTypesArray());
651                }
652                query.setRows(new Integer(MAX_PROCESSED_SOLR_RESULTS));
653                query.ensureParameters();
654                try {
655                    resources.addAll(
656                        index.search(cmsObject, query, true, null, false, null, MAX_PROCESSED_SOLR_RESULTS));
657                } catch (CmsSearchException e) {
658                    LOG.error(e.getMessage(), e);
659                }
660            }
661        } else {
662            CmsResourceFilter filter = CmsResourceFilter.ALL.addRequireFile().addExcludeState(
663                CmsResource.STATE_DELETED).addRequireTimerange().addRequireVisible();
664            if ((m_settings.getTypesArray() != null) && (m_settings.getTypesArray().length > 0)) {
665                for (String resTypeName : m_settings.getTypesArray()) {
666                    try {
667                        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resTypeName);
668                        filter = filter.addRequireType(type);
669                    } catch (CmsLoaderException e) {
670                        // noop
671                    } catch (NullPointerException e) {
672                        // noop
673                    }
674                }
675            }
676
677            // iterate over all selected paths
678            Iterator<String> iterPaths = m_settings.getPaths().iterator();
679            while (iterPaths.hasNext()) {
680                String path = iterPaths.next();
681                try {
682                    // only read resources which are files and not deleted, which are in the current time range window and where the current
683                    // user has the sufficient permissions to read them
684                    List<CmsResource> tmpResources = getCms().readResources(path, filter);
685                    if ((tmpResources != null) && !tmpResources.isEmpty()) {
686                        resources.addAll(tmpResources);
687                    }
688                } catch (CmsException e) {
689                    // an error occured
690                    LOG.error(Messages.get().container(Messages.RPT_SOURCESEARCH_ERROR_READING_RESOURCES_1, path), e);
691                    report.println(
692                        Messages.get().container(Messages.RPT_SOURCESEARCH_ERROR_READING_RESOURCES_1, path),
693                        I_CmsReport.FORMAT_ERROR);
694                }
695            }
696        }
697        return resources;
698    }
699
700    /**
701     * Writes the file contents.<p>
702     *
703     * @param cmsObject the cms context
704     * @param report the report
705     * @param file the file to write
706     * @param content the file content
707     *
708     * @return success flag
709     */
710    private boolean writeContent(CmsObject cmsObject, I_CmsReport report, CmsFile file, byte[] content) {
711
712        boolean success = true;
713
714        // get current lock from file
715        try {
716            // try to lock the resource
717            if (!lockResource(cmsObject, file, report)) {
718                report.println(
719                    Messages.get().container(Messages.RPT_SOURCESEARCH_LOCKED_FILE_0, cmsObject.getSitePath(file)),
720                    I_CmsReport.FORMAT_ERROR);
721                success = false;
722            }
723        } catch (CmsException e) {
724            report.println(
725                Messages.get().container(Messages.RPT_SOURCESEARCH_LOCKED_FILE_0, cmsObject.getSitePath(file)),
726                I_CmsReport.FORMAT_ERROR);
727            if (LOG.isErrorEnabled()) {
728                LOG.error(e.getMessageContainer(), e);
729            }
730            success = false;
731        }
732
733        // write the file content
734        try {
735            file.setContents(content);
736            cmsObject.writeFile(file);
737        } catch (Exception e) {
738            m_errorUpdate += 1;
739            report.println(
740                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_FAILED_0),
741                I_CmsReport.FORMAT_ERROR);
742            if (LOG.isErrorEnabled()) {
743                LOG.error(e.toString());
744            }
745            success = false;
746        }
747
748        // unlock the resource
749        try {
750            cmsObject.unlockResource(cmsObject.getSitePath(file));
751        } catch (CmsException e) {
752            m_errorUpdate += 1;
753            report.println(
754                Messages.get().container(Messages.RPT_SOURCESEARCH_UNLOCK_FILE_0),
755                I_CmsReport.FORMAT_WARNING);
756            if (LOG.isErrorEnabled()) {
757                LOG.error(e.getMessageContainer(), e);
758            }
759            success = false;
760        }
761
762        if (success) {
763            // successfully updated
764            report.println(
765                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
766                I_CmsReport.FORMAT_OK);
767        }
768
769        return success;
770    }
771}