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;
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.CmsResourceTypeXmlPage;
035import org.opencms.i18n.CmsLocaleManager;
036import org.opencms.i18n.CmsMessages;
037import org.opencms.jsp.CmsJspActionElement;
038import org.opencms.main.CmsException;
039import org.opencms.main.OpenCms;
040import org.opencms.report.I_CmsReport;
041import org.opencms.util.CmsStringUtil;
042import org.opencms.workplace.CmsReport;
043import org.opencms.workplace.CmsWorkplaceSettings;
044import org.opencms.xml.page.CmsXmlPage;
045import org.opencms.xml.page.CmsXmlPageFactory;
046
047import java.util.ArrayList;
048import java.util.Iterator;
049import java.util.List;
050import java.util.Locale;
051
052import javax.servlet.http.HttpServletRequest;
053import javax.servlet.http.HttpServletResponse;
054import javax.servlet.jsp.JspException;
055import javax.servlet.jsp.PageContext;
056
057/**
058 * Provides methods for the merge pages dialog.<p>
059 *
060 * @since 6.0.0
061 */
062public class CmsMergePages extends CmsReport {
063
064    /** A constant representing the select option all templates. */
065    public static final String ALL = "ALL";
066
067    /** Key for pages found in folder 1 exclusivly. */
068    public static final int FOLDER1_EXCLUSIVE = 0;
069
070    /** Key for pages found in folder 2 exclusivly. */
071    public static final int FOLDER2_EXCLUSIVE = 1;
072
073    /** Key for pages found in both folders but as different types. */
074    public static final int FOLDERS_DIFFERENTTYPES = 4;
075
076    /** Key for pages found in both folders as individual resources. */
077    public static final int FOLDERS_EQUALNAMES = 3;
078
079    /** Key for pages found in both folders as siblings. */
080    public static final int FOLDERS_SIBLING = 2;
081
082    /** The dialog type. */
083    public static final String DIALOG_TYPE = "mergepages";
084
085    /** Request parameter name for the first folder to merge. */
086    public static final String PARAM_FOLDER1 = "folder1";
087
088    /** Request parameter name for the second folder to merge. */
089    public static final String PARAM_FOLDER2 = "folder2";
090
091    /** the cms object. */
092    private CmsObject m_cms;
093
094    /** the error message. */
095    private String m_errorMessage;
096
097    /** List of pages found in folder 1 exclusivly. */
098    private List m_folder1Exclusive;
099
100    /** List of pages found in folder 2 exclusivly. */
101    private List m_folder2Exclusive;
102
103    /** List of pages found in  both folders but as different types. */
104    private List m_foldersDifferenttypes;
105
106    /** List of pages found in both folders as individual resources. */
107    private List m_foldersEqualnames;
108
109    /** List of pages found in both folders as siblings. */
110    private List m_foldersSibling;
111
112    /** The first folder to merge. */
113    private String m_paramFolder1;
114
115    /** The second folder to merge. */
116    private String m_paramFolder2;
117
118    /** the report for the output. */
119    private I_CmsReport m_report;
120
121    /**
122     * Public constructor with JSP action element.<p>
123     *
124     * @param jsp an initialized JSP action element
125     */
126    public CmsMergePages(CmsJspActionElement jsp) {
127
128        super(jsp);
129        m_folder1Exclusive = new ArrayList();
130        m_folder2Exclusive = new ArrayList();
131        m_foldersSibling = new ArrayList();
132        m_foldersEqualnames = new ArrayList();
133        m_foldersDifferenttypes = new ArrayList();
134    }
135
136    /**
137     * Public constructor with JSP variables.<p>
138     *
139     * @param cms the current CmsObject
140     * @param context the JSP page context
141     * @param req the JSP request
142     * @param res the JSP response
143     */
144    public CmsMergePages(CmsObject cms, PageContext context, HttpServletRequest req, HttpServletResponse res) {
145
146        this(new CmsJspActionElement(context, req, res));
147        m_cms = cms;
148    }
149
150    /**
151     * Merges the specified resources.<p>
152     *
153     * @param report the cms report
154     */
155    public void actionMerge(I_CmsReport report) {
156
157        m_report = report;
158        m_report.println(Messages.get().container(Messages.RPT_MERGE_PAGES_BEGIN_0), I_CmsReport.FORMAT_HEADLINE);
159
160        try {
161            // collect all pages and sort them depending on their state
162            collectResources();
163            // merge all pages that can be merged
164            mergePages();
165            // cleanup
166            cleanup();
167        } catch (CmsException e) {
168            m_report.println(e);
169        }
170
171    }
172
173    /**
174     * Performs the move report, will be called by the JSP page.<p>
175     *
176     * @throws JspException if problems including sub-elements occur
177     */
178    public void actionReport() throws JspException {
179
180        // save initialized instance of this class in request attribute for included sub-elements
181        getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
182        switch (getAction()) {
183            case ACTION_REPORT_END:
184                actionCloseDialog();
185                break;
186            case ACTION_REPORT_UPDATE:
187                setParamAction(REPORT_UPDATE);
188                getJsp().include(FILE_REPORT_OUTPUT);
189                break;
190            case ACTION_REPORT_BEGIN:
191            case ACTION_CONFIRMED:
192            default:
193                CmsMergePagesThread thread = new CmsMergePagesThread(getCms(), this);
194                thread.start();
195                setParamAction(REPORT_BEGIN);
196                setParamThread(thread.getUUID().toString());
197                getJsp().include(FILE_REPORT_OUTPUT);
198                break;
199        }
200    }
201
202    /**
203     * @see org.opencms.workplace.CmsWorkplace#getCms()
204     */
205    @Override
206    public CmsObject getCms() {
207
208        if (m_cms == null) {
209            return super.getCms();
210        }
211
212        return m_cms;
213    }
214
215    /**
216     * Returns the errorMessage.<p>
217     *
218     * @return the errorMessage
219     */
220    public String getErrorMessage() {
221
222        if (CmsStringUtil.isEmpty(m_errorMessage)) {
223            return "";
224        }
225
226        return m_errorMessage;
227    }
228
229    /**
230     * Returns the first folder.<p>
231     *
232     * @return the folder
233     */
234    public String getParamFolder1() {
235
236        return m_paramFolder1;
237    }
238
239    /**
240     * Returns the second folder.<p>
241     *
242     * @return the folder
243     */
244    public String getParamFolder2() {
245
246        return m_paramFolder2;
247    }
248
249    /**
250     * Sets the errorMessage.<p>
251     *
252     * @param errorMessage the errorMessage to set
253     */
254    public void setErrorMessage(String errorMessage) {
255
256        m_errorMessage = errorMessage;
257    }
258
259    /**
260     * Sets the first folder to merge.<p>
261     *
262     * @param folder1 the first folder name to set
263     */
264    public void setParamFolder1(String folder1) {
265
266        m_paramFolder1 = folder1;
267    }
268
269    /**
270     * Sets the second folder to merge.<p>
271     *
272     * @param folder2 the second folder name to set
273     */
274    public void setParamFolder2(String folder2) {
275
276        m_paramFolder2 = folder2;
277    }
278
279    /**
280     * Does validate the request parameters and returns a buffer with error messages.<p>
281     * @param cms the current cms object
282     * If there were no error messages, the buffer is empty.<p>
283     */
284    public void validateParameters(CmsObject cms) {
285
286        CmsMessages messages = Messages.get().getBundle(getLocale());
287        StringBuffer validationErrors = new StringBuffer();
288        if (CmsStringUtil.isEmpty(getParamFolder1())) {
289            validationErrors.append(messages.key(Messages.GUI_MERGE_PAGES_VALIDATE_FIRST_FOLDER_0)).append("<br>");
290        } else {
291            try {
292                cms.readResource(getParamFolder1());
293            } catch (CmsException e) {
294                validationErrors.append(
295                    messages.key(Messages.GUI_MERGE_PAGES_VALIDATE_FIRST_FOLDER_1, getParamFolder1())).append("<br>");
296            }
297        }
298        if (CmsStringUtil.isEmpty(getParamFolder2())) {
299            validationErrors.append(messages.key(Messages.GUI_MERGE_PAGES_VALIDATE_SECOND_FOLDER_0)).append("<br>");
300        } else {
301            try {
302                cms.readResource(getParamFolder2());
303            } catch (CmsException e) {
304                validationErrors.append(
305                    messages.key(Messages.GUI_MERGE_PAGES_VALIDATE_SECOND_FOLDER_1, getParamFolder2())).append("<br>");
306            }
307        }
308        if (getParamFolder1().equals(getParamFolder2())) {
309            validationErrors.append(messages.key(Messages.GUI_MERGE_PAGES_VALIDATE_SAME_FOLDER_0)).append("<br>");
310        }
311
312        setErrorMessage(validationErrors.toString());
313    }
314
315    /**
316     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
317     */
318    @Override
319    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
320
321        // fill the parameter values in the get/set methods
322        fillParamValues(request);
323        // set the dialog type
324        setParamDialogtype(DIALOG_TYPE);
325        // set the action for the JSP switch
326        // set the action for the JSP switch
327        if (DIALOG_CONFIRMED.equals(getParamAction())) {
328            setAction(ACTION_CONFIRMED);
329        } else if (DIALOG_OK.equals(getParamAction())) {
330            setAction(ACTION_OK);
331        } else if (DIALOG_CANCEL.equals(getParamAction())) {
332            setAction(ACTION_CANCEL);
333        } else if (REPORT_UPDATE.equals(getParamAction())) {
334            setAction(ACTION_REPORT_UPDATE);
335        } else if (REPORT_BEGIN.equals(getParamAction())) {
336            setAction(ACTION_REPORT_BEGIN);
337        } else if (REPORT_END.equals(getParamAction())) {
338            setAction(ACTION_REPORT_END);
339        } else {
340            setAction(ACTION_DEFAULT);
341            // add the title for the dialog
342            setParamTitle(Messages.get().getBundle(getLocale()).key(Messages.GUI_TITLE_MERGEPAGES_0));
343        }
344    }
345
346    /**
347     * Analyses a page in the source morge folder and tests if a resouce with the same name exists in the target merge folder.<p>
348     *
349     * The method then calcualtes a action for further processing of this page, possible values are:
350     * <ul>
351     * <li>C_FOLDER1_EXCLUSIVE: exclusivly found in folder 1</li>
352     * <li>C_FOLDER2_EXCLUSIVE: exclusivly found in folder 2</li>
353     * <li>C_FOLDERS_SIBLING: found in both folders as siblings of each other </li>
354     * <li>C_FOLDERS_EQUALNAMES: found in both folders as individual resources</li>
355     * <li>C_FOLDERS_DIFFERENTTYPES: found in both folders as different types</li>
356     * </ul>
357     * @param res the resource to test
358     * @param sourceMergeFolder the path to the source merge folder
359     * @param targetMergefolder the path to the target merge folder
360     * @param currentFolder integer value (1 or 2) showing if the source folder is folder 1 or folder 2
361     * @return value of the action to do with this page
362     */
363    private int analyse(CmsResource res, String sourceMergeFolder, String targetMergefolder, int currentFolder) {
364
365        int retValue = -1;
366        String resourcenameOther = getResourceNameInOtherFolder(
367            m_cms.getSitePath(res),
368            sourceMergeFolder,
369            targetMergefolder);
370        try {
371            CmsResource otherRes = m_cms.readResource(resourcenameOther, CmsResourceFilter.IGNORE_EXPIRATION);
372            // there was a resource with the same name in the other merge folder
373            // now check if it is already a sibling of the current resource
374            if (res.getResourceId().equals(otherRes.getResourceId())) {
375                // it is a sibling, so set the action to "sibling already";
376                retValue = FOLDERS_SIBLING;
377            } else {
378                // it is no sibling, now test if it has the same resource type than the oringinal resource
379                if (res.getTypeId() == otherRes.getTypeId()) {
380                    // both resources have the same type, so set the action to  "same name". Only those resources can be merged
381                    retValue = FOLDERS_EQUALNAMES;
382                } else {
383                    // both resources have different types, so set the action to "different types"
384                    retValue = FOLDERS_DIFFERENTTYPES;
385                }
386            }
387        } catch (CmsException e) {
388            // the resource was not found, so set the action mode to "found only in the source folder"
389            if (currentFolder == 1) {
390                retValue = FOLDER1_EXCLUSIVE;
391            } else {
392                retValue = FOLDER2_EXCLUSIVE;
393            }
394        }
395
396        return retValue;
397    }
398
399    /**
400     * Cleanup all internal storages.<p>    *
401     */
402    private void cleanup() {
403
404        m_folder1Exclusive = null;
405        m_folder2Exclusive = null;
406        m_foldersSibling = null;
407        m_foldersEqualnames = null;
408        m_foldersDifferenttypes = null;
409    }
410
411    /**
412     * Collect all pages in a folders and sort them depending on the required action to do.<p>
413     *
414     * @param sourceMergeFolder the source merge folder to collect all pages from
415     * @param targetMergefolder the target merge folder to compare to
416     * @param currentFolder integer value (1 or 2) showing if the source folder is folder 1 or folder 2
417     * @throws CmsException if something goes wrong
418     */
419    private void collectFolder(String sourceMergeFolder, String targetMergefolder, int currentFolder)
420    throws CmsException {
421
422        //get the list of all resources in the source merge folder
423        int xmlPageId = OpenCms.getResourceManager().getResourceType(
424            CmsResourceTypeXmlPage.getStaticTypeName()).getTypeId();
425        CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(xmlPageId);
426        List folderResources = m_cms.readResources(sourceMergeFolder, filter, true);
427        Iterator i = folderResources.iterator();
428        int size = folderResources.size();
429        // now loop through all resources and check them against those in the target merge folder
430        m_report.println(
431            Messages.get().container(Messages.RPT_SCAN_PAGES_IN_FOLDER_BEGIN_2, sourceMergeFolder, Integer.valueOf(size)),
432            I_CmsReport.FORMAT_HEADLINE);
433        int count = 1;
434        while (i.hasNext()) {
435            CmsResource res = (CmsResource)i.next();
436            String resName = m_cms.getSitePath(res);
437
438            m_report.print(
439                org.opencms.report.Messages.get().container(
440                    org.opencms.report.Messages.RPT_SUCCESSION_2,
441                    String.valueOf(count++),
442                    String.valueOf(size)),
443                I_CmsReport.FORMAT_NOTE);
444            m_report.println(Messages.get().container(Messages.RPT_PROCESS_1, resName), I_CmsReport.FORMAT_NOTE);
445
446            // now analyse the page and calculate the action to do
447            int action = analyse(res, sourceMergeFolder, targetMergefolder, currentFolder);
448            // add the name of the resource to the correct list
449            switch (action) {
450                case FOLDER1_EXCLUSIVE:
451                    m_folder1Exclusive.add(resName);
452                    m_report.println(Messages.get().container(Messages.RPT_FOLDER1_EXCLUSIVE_0), I_CmsReport.FORMAT_OK);
453                    break;
454                case FOLDER2_EXCLUSIVE:
455                    m_folder2Exclusive.add(resName);
456                    m_report.println(Messages.get().container(Messages.RPT_FOLDER2_EXCLUSIVE_0), I_CmsReport.FORMAT_OK);
457                    break;
458                case FOLDERS_SIBLING:
459                    if (!m_foldersSibling.contains(
460                        getResourceNameInOtherFolder(resName, sourceMergeFolder, targetMergefolder))) {
461                        m_foldersSibling.add(resName);
462                    }
463                    m_report.println(Messages.get().container(Messages.RPT_FOLDERS_SIBLING_0), I_CmsReport.FORMAT_OK);
464                    break;
465                case FOLDERS_EQUALNAMES:
466                    if (!m_foldersEqualnames.contains(
467                        getResourceNameInOtherFolder(resName, sourceMergeFolder, targetMergefolder))) {
468                        m_foldersEqualnames.add(resName);
469                    }
470                    m_report.println(
471                        Messages.get().container(Messages.RPT_FOLDERS_EQUALNAMES_0),
472                        I_CmsReport.FORMAT_OK);
473                    break;
474                case FOLDERS_DIFFERENTTYPES:
475                    if (!m_foldersDifferenttypes.contains(
476                        getResourceNameInOtherFolder(resName, sourceMergeFolder, targetMergefolder))) {
477                        m_foldersDifferenttypes.add(resName);
478                    }
479                    m_report.println(
480                        Messages.get().container(Messages.RPT_FOLDERS_DIFFERENTTYPES_0),
481                        I_CmsReport.FORMAT_OK);
482                    break;
483                default:
484                    break;
485            }
486            res = null;
487        }
488        folderResources = null;
489        m_report.println(
490            Messages.get().container(Messages.RPT_SCAN_PAGES_IN_FOLDER_END_0),
491            I_CmsReport.FORMAT_HEADLINE);
492
493    }
494
495    /**
496     * Collect all pages in the folders to merge and sort them depending on the required action to do.<p>
497     *
498     * The method will create several lists. Each list contains the resource names of pages
499     * and will be used in further steps of the merging process.
500     * <ul>
501     * <li>List m_folder1Exclusive: contains all pages which are exclusivly found in folder 1</li>
502     * <li>List m_folder2Exclusive: contains all pages which are exclusivly found in folder 2</li>
503     * <li>List m_foldersSibling: contains all pages which can be found in both folders and are siblings of each other </li>
504     * <li>List m_foldersEqualnames: contains all pages which can be found in both folders and are no siblings of each other</li>
505     * <li>List m_foldersDifferenttypes: contains all pages which can be found in both folders but are of different types</li>
506     * </ul>
507     *
508     * @throws CmsException if something goes wrong
509     */
510    private void collectResources() throws CmsException {
511
512        String defaultLocale = CmsLocaleManager.getDefaultLocale().toString();
513        String locale1 = m_cms.readPropertyObject(getParamFolder1(), "locale", true).getValue(defaultLocale);
514        String locale2 = m_cms.readPropertyObject(getParamFolder2(), "locale", true).getValue(defaultLocale);
515        m_report.println(
516            Messages.get().container(Messages.RPT_CREATE_EXTERNAL_LINK_0, getParamFolder1(), locale1),
517            I_CmsReport.FORMAT_NOTE);
518        m_report.println(
519            Messages.get().container(Messages.RPT_CREATE_EXTERNAL_LINK_0, getParamFolder2(), locale2),
520            I_CmsReport.FORMAT_NOTE);
521
522        // collect all resources in folder 1
523        collectFolder(getParamFolder1(), getParamFolder2(), 1);
524        // collect all resources in folder 2
525        collectFolder(getParamFolder2(), getParamFolder1(), 2);
526
527        // report the results of the collection
528        m_report.println(Messages.get().container(Messages.RPT_SCANNING_RESULTS_0), I_CmsReport.FORMAT_HEADLINE);
529
530        m_report.println(Messages.get().container(Messages.RPT_FOLDER1_EXCLUSIVE_0), I_CmsReport.FORMAT_HEADLINE);
531        reportList(m_folder1Exclusive, false);
532        m_report.println(Messages.get().container(Messages.RPT_FOLDER2_EXCLUSIVE_0), I_CmsReport.FORMAT_HEADLINE);
533        reportList(m_folder2Exclusive, false);
534        m_report.println(Messages.get().container(Messages.RPT_FOLDERS_SIBLING_0), I_CmsReport.FORMAT_HEADLINE);
535        reportList(m_foldersSibling, false);
536        m_report.println(Messages.get().container(Messages.RPT_FOLDERS_EQUALNAMES_0), I_CmsReport.FORMAT_HEADLINE);
537        reportList(m_foldersEqualnames, true);
538        m_report.println(Messages.get().container(Messages.RPT_FOLDERS_DIFFERENTTYPES_0), I_CmsReport.FORMAT_HEADLINE);
539        reportList(m_foldersDifferenttypes, false);
540
541    }
542
543    /**
544     * Gets the name of a resource in the other merge folder.<p>
545     *
546     * @param resName the complete path of a resource
547     * @param sourceMergeFolder the path to the source merge folder
548     * @param targetMergefolder the path to the target merge folder
549     * @return the name of a resource in the other merge folder
550     */
551    private String getResourceNameInOtherFolder(String resName, String sourceMergeFolder, String targetMergefolder) {
552
553        // get the resourcename of the resouce to test without the source merge folder
554        String resourcename = resName.substring(sourceMergeFolder.length());
555        // get the complete path of the resource in the other merge folder
556        return targetMergefolder + resourcename;
557    }
558
559    /**
560     * Merges those pages in the two merge folders that have the same name and are no siblings of each other yet.<p>
561     * @throws CmsException if something goes wrong
562     */
563    private void mergePages() throws CmsException {
564
565        int size = m_foldersEqualnames.size();
566        if (size > 0) {
567
568            m_report.println(
569                Messages.get().container(Messages.RPT_MERGE_PAGES_BEGIN_1, String.valueOf(size)),
570                I_CmsReport.FORMAT_HEADLINE);
571            String defaultLocale = CmsLocaleManager.getDefaultLocale().toString();
572            String locale2 = m_cms.readPropertyObject(getParamFolder2(), "locale", true).getValue(defaultLocale);
573
574            // lock the source and the target folder
575            m_report.print(Messages.get().container(Messages.RPT_LOCK_FOLDER_0), I_CmsReport.FORMAT_NOTE);
576            m_report.print(
577                org.opencms.report.Messages.get().container(
578                    org.opencms.report.Messages.RPT_ARGUMENT_1,
579                    getParamFolder1()));
580            m_report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
581            m_cms.lockResource(getParamFolder1());
582            m_report.println(
583                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
584                I_CmsReport.FORMAT_OK);
585
586            m_report.print(Messages.get().container(Messages.RPT_LOCK_FOLDER_0), I_CmsReport.FORMAT_NOTE);
587            m_report.print(
588                org.opencms.report.Messages.get().container(
589                    org.opencms.report.Messages.RPT_ARGUMENT_1,
590                    getParamFolder2()));
591            m_report.print(org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
592            m_cms.lockResource(getParamFolder2());
593            m_report.println(
594                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
595                I_CmsReport.FORMAT_OK);
596
597            // now loop through all collected resources
598            int count = 1;
599            Iterator i = m_foldersEqualnames.iterator();
600            while (i.hasNext()) {
601                String resFolder1Name = (String)i.next();
602                try {
603                    String resFolder2Name = getResourceNameInOtherFolder(
604                        resFolder1Name,
605                        getParamFolder1(),
606                        getParamFolder2());
607                    m_report.print(org.opencms.report.Messages.get().container(
608                        org.opencms.report.Messages.RPT_SUCCESSION_2,
609                        String.valueOf(count++),
610                        String.valueOf(size)), I_CmsReport.FORMAT_NOTE);
611                    m_report.print(Messages.get().container(Messages.RPT_PROCESS_0), I_CmsReport.FORMAT_NOTE);
612                    m_report.print(
613                        org.opencms.report.Messages.get().container(
614                            org.opencms.report.Messages.RPT_ARGUMENT_1,
615                            resFolder1Name));
616                    m_report.print(Messages.get().container(Messages.RPT_DOUBLE_ARROW_0), I_CmsReport.FORMAT_NOTE);
617                    m_report.print(
618                        org.opencms.report.Messages.get().container(
619                            org.opencms.report.Messages.RPT_ARGUMENT_1,
620                            resFolder2Name));
621                    m_report.println(
622                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
623
624                    // get the content of the resource in folder1
625                    String locale = m_cms.readPropertyObject(resFolder1Name, "locale", true).getValue(defaultLocale);
626                    m_report.print(
627                        Messages.get().container(Messages.RPT_READ_CONTENT_2, resFolder1Name, locale),
628                        I_CmsReport.FORMAT_NOTE);
629                    CmsResource resFolder1 = m_cms.readResource(resFolder1Name, CmsResourceFilter.IGNORE_EXPIRATION);
630                    CmsFile fileFolder1 = m_cms.readFile(resFolder1);
631                    CmsXmlPage pageFolder1 = CmsXmlPageFactory.unmarshal(m_cms, fileFolder1);
632                    m_report.println(
633                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
634                        I_CmsReport.FORMAT_OK);
635
636                    // get the content of the resource in folder2
637                    locale = m_cms.readPropertyObject(resFolder2Name, "locale", true).getValue(defaultLocale);
638                    m_report.print(
639                        Messages.get().container(Messages.RPT_READ_CONTENT_2, resFolder2Name, locale),
640                        I_CmsReport.FORMAT_NOTE);
641                    CmsResource resFolder2 = m_cms.readResource(resFolder2Name, CmsResourceFilter.IGNORE_EXPIRATION);
642                    CmsFile fileFolder2 = m_cms.readFile(resFolder2);
643                    CmsXmlPage pageFolder2 = CmsXmlPageFactory.unmarshal(m_cms, fileFolder2);
644                    m_report.println(
645                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
646                        I_CmsReport.FORMAT_OK);
647
648                    // now get all the text elements from the resource in folder 2 which match the the locale of folder 2
649                    Locale loc = CmsLocaleManager.getLocale(locale2);
650                    List textElements2 = pageFolder2.getNames(loc);
651                    Iterator j = textElements2.iterator();
652                    while (j.hasNext()) {
653                        String textElementName = (String)j.next();
654                        m_report.print(
655                            Messages.get().container(Messages.RPT_PROCESS_TEXT_ELEM_1, textElementName),
656                            I_CmsReport.FORMAT_NOTE);
657                        // get the text element from the resource in folder 2...
658                        String textElement = pageFolder2.getValue(textElementName, loc).getStringValue(m_cms);
659                        // and set it in the resource in folder 1...
660                        // WARNING: An existing content will be overwritten!
661                        if (!pageFolder1.hasValue(textElementName, loc)) {
662                            pageFolder1.addValue(textElementName, loc);
663                        }
664                        pageFolder1.setStringValue(m_cms, textElementName, loc, textElement);
665                        m_report.println(
666                            org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
667                            I_CmsReport.FORMAT_OK);
668                    }
669                    // the resource in folder 1 now has all text elements in both locales, so update it in the vfs
670
671                    m_report.print(
672                        Messages.get().container(Messages.RPT_WRITE_CONTENT_1, resFolder1Name),
673                        I_CmsReport.FORMAT_NOTE);
674                    fileFolder1.setContents(pageFolder1.marshal());
675                    m_cms.writeFile(fileFolder1);
676                    m_report.println(
677                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
678                        I_CmsReport.FORMAT_OK);
679
680                    // save all properties from the resource in folder2
681                    m_report.print(
682                        Messages.get().container(Messages.RPT_READ_PROPERTIES_1, resFolder2Name),
683                        I_CmsReport.FORMAT_NOTE);
684                    List properties = m_cms.readPropertyObjects(resFolder2Name, false);
685                    m_report.println(
686                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
687                        I_CmsReport.FORMAT_OK);
688
689                    // the next thing to do is to delete the old resource in folder 2
690                    m_report.print(
691                        Messages.get().container(Messages.RPT_DELETE_PAGE_1, resFolder2Name),
692                        I_CmsReport.FORMAT_NOTE);
693                    m_cms.deleteResource(resFolder2Name, CmsResource.DELETE_PRESERVE_SIBLINGS);
694                    m_report.println(
695                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
696                        I_CmsReport.FORMAT_OK);
697
698                    // copy a sibling of the resource from folder 1 to folder 2
699                    m_report.print(
700                        Messages.get().container(Messages.RPT_COPY_2, resFolder1Name, resFolder2Name),
701                        I_CmsReport.FORMAT_NOTE);
702                    m_cms.copyResource(resFolder1Name, resFolder2Name, CmsResource.COPY_AS_SIBLING);
703                    m_report.println(
704                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
705                        I_CmsReport.FORMAT_OK);
706
707                    // restore the properties at the sibling in folder 2
708                    m_report.print(
709                        Messages.get().container(Messages.RPT_RESORE_PROPERTIES_1, resFolder2Name),
710                        I_CmsReport.FORMAT_NOTE);
711                    m_cms.writePropertyObjects(resFolder2Name, properties);
712                    m_report.println(
713                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
714                        I_CmsReport.FORMAT_OK);
715
716                    resFolder1 = null;
717                    resFolder2 = null;
718                    fileFolder1 = null;
719                    fileFolder2 = null;
720                    pageFolder1 = null;
721                    pageFolder2 = null;
722
723                } catch (CmsException e) {
724                    m_report.println(e);
725                }
726
727            }
728            // lock the source and the target folder
729            m_report.print(Messages.get().container(Messages.RPT_UNLOCK_1, getParamFolder1()), I_CmsReport.FORMAT_NOTE);
730            m_cms.unlockResource(getParamFolder1());
731            m_report.println(
732                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
733                I_CmsReport.FORMAT_OK);
734
735            m_report.print(Messages.get().container(Messages.RPT_UNLOCK_1, getParamFolder2()), I_CmsReport.FORMAT_NOTE);
736            m_cms.unlockResource(getParamFolder2());
737            m_report.println(
738                org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_OK_0),
739                I_CmsReport.FORMAT_OK);
740
741            m_report.println(Messages.get().container(Messages.RPT_MERGE_PAGES_END_0), I_CmsReport.FORMAT_HEADLINE);
742        }
743    }
744
745    /**
746     * Creates a report list of all resources in one of the collected lists.<p>
747     *
748     * @param collected the list to create the output from
749     * @param doReport flag to enable detailed report
750     */
751    private void reportList(List collected, boolean doReport) {
752
753        int size = collected.size();
754        // now loop through all collected resources
755        m_report.println(
756            Messages.get().container(Messages.RPT_NUM_PAGES_1, Integer.valueOf(size)),
757            I_CmsReport.FORMAT_HEADLINE);
758        if (doReport) {
759            int count = 1;
760
761            Iterator i = collected.iterator();
762            while (i.hasNext()) {
763                String resName = (String)i.next();
764                m_report.print(
765                    org.opencms.report.Messages.get().container(
766                        org.opencms.report.Messages.RPT_SUCCESSION_2,
767                        String.valueOf(count++),
768                        String.valueOf(size)),
769                    I_CmsReport.FORMAT_NOTE);
770                m_report.println(Messages.get().container(Messages.RPT_PROCESS_1, resName), I_CmsReport.FORMAT_NOTE);
771            }
772        }
773        m_report.println(Messages.get().container(Messages.RPT_MERGE_PAGES_END_0), I_CmsReport.FORMAT_HEADLINE);
774    }
775}