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.CmsProperty;
033import org.opencms.file.CmsPropertyDefinition;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.types.CmsResourceTypeXmlPage;
037import org.opencms.i18n.CmsLocaleManager;
038import org.opencms.i18n.CmsMessages;
039import org.opencms.jsp.CmsJspActionElement;
040import org.opencms.loader.CmsLoaderException;
041import org.opencms.lock.CmsLock;
042import org.opencms.main.CmsException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.report.I_CmsReport;
046import org.opencms.util.CmsStringUtil;
047import org.opencms.workplace.CmsReport;
048import org.opencms.workplace.CmsWorkplace;
049import org.opencms.workplace.CmsWorkplaceSettings;
050import org.opencms.workplace.editors.CmsDialogElement;
051import org.opencms.workplace.explorer.CmsNewResourceXmlPage;
052import org.opencms.xml.CmsXmlException;
053import org.opencms.xml.page.CmsXmlPage;
054import org.opencms.xml.page.CmsXmlPageFactory;
055import org.opencms.xml.types.CmsXmlHtmlValue;
056
057import java.util.ArrayList;
058import java.util.HashSet;
059import java.util.Iterator;
060import java.util.List;
061import java.util.Locale;
062import java.util.Map;
063import java.util.Set;
064import java.util.StringTokenizer;
065import java.util.TreeMap;
066
067import javax.servlet.http.HttpServletRequest;
068import javax.servlet.http.HttpServletResponse;
069import javax.servlet.jsp.JspException;
070import javax.servlet.jsp.PageContext;
071
072import org.apache.commons.logging.Log;
073
074/**
075 * Provides methods for the change page element name dialog.<p>
076 *
077 * @since 6.0.0
078 */
079public class CmsElementRename extends CmsReport {
080
081    /** A constant representing the select option all templates. */
082    public static final String ALL = "ALL";
083
084    /** The dialog type. */
085    public static final String DIALOG_TYPE = "renameelement";
086
087    /** Request parameter name for the locale. */
088    public static final String PARAM_LOCALE = "locale";
089
090    /** Request parameter name for the new element name. */
091    public static final String PARAM_NEW_ELEMENT = "newelement";
092
093    /** Request parameter name for the old element name. */
094    public static final String PARAM_OLD_ELEMENT = "oldelement";
095
096    /** Request parameter name for the recursive search. */
097    public static final String PARAM_RECURSIVE = "recursive";
098
099    /** Request parameter name for the remove empty elements. */
100    public static final String PARAM_REMOVE_EMPTYELEMENTS = "removeemptyelements";
101
102    /** Request parameter name for the template. */
103    public static final String PARAM_TEMPLATE = "template";
104
105    /** Request parameter name for the validate new element. */
106    public static final String PARAM_VALIDATE_NEW_ELEMENT = "validatenewelement";
107
108    /** The log object for this class. */
109    private static final Log LOG = CmsLog.getLog(CmsElementRename.class);
110
111    /** the cms object. */
112    private CmsObject m_cms;
113    /** the error message. */
114    private String m_errorMessage;
115    /** the locale use for content definition. */
116    private String m_paramLocale;
117    /** The new page element name. */
118    private String m_paramNewElement;
119    /** The old page element name. */
120    private String m_paramOldElement;
121    /** The recursive parameter. */
122    private String m_paramRecursive;
123    /** the flag indicating to remove empty elements. */
124    private String m_paramRemoveEmptyElements;
125    /** the template use for all pages (optional). */
126    private String m_paramTemplate;
127    /** the flag indicating to remove empty elements. */
128    private String m_paramValidateNewElement;
129    /** the report for the output. */
130    private I_CmsReport m_report;
131
132    /**
133     * Public constructor with JSP action element.<p>
134     *
135     * @param jsp an initialized JSP action element
136     */
137    public CmsElementRename(CmsJspActionElement jsp) {
138
139        super(jsp);
140    }
141
142    /**
143     * Public constructor for testcase using.<p>
144     *
145     * @param jsp an initialized JSP action element
146     * @param cms the cms object
147     * @param resource the resource path
148     * @param recursive if true then do read recursive from the folder
149     * @param template the template
150     * @param locale the locale
151     * @param oldElement the old element name
152     * @param newElement the new element name
153     * @param removeEmptyElements if true then remove all invalid elements with no content
154     * @param validateNewElement if true then validate the new element before renaming
155     */
156    public CmsElementRename(
157        CmsJspActionElement jsp,
158        CmsObject cms,
159        String resource,
160        String recursive,
161        String template,
162        String locale,
163        String oldElement,
164        String newElement,
165        String removeEmptyElements,
166        String validateNewElement) {
167
168        super(jsp);
169        m_cms = cms;
170        setParamResource(resource);
171        setParamRecursive(recursive);
172        setParamTemplate(template);
173        setParamLocale(locale);
174        setParamOldElement(oldElement);
175        setParamNewElement(newElement);
176        setParamRemoveEmptyElements(removeEmptyElements);
177        setParamValidateNewElement(validateNewElement);
178    }
179
180    /**
181     * Public constructor with JSP variables.<p>
182     *
183     * @param context the JSP page context
184     * @param req the JSP request
185     * @param res the JSP response
186     */
187    public CmsElementRename(PageContext context, HttpServletRequest req, HttpServletResponse res) {
188
189        this(new CmsJspActionElement(context, req, res));
190    }
191
192    /**
193     * Renames the element name on the specified resources.<p>
194     *
195     * @param report the cms report
196     */
197    public void actionRename(I_CmsReport report) {
198
199        m_report = report;
200        List locales = OpenCms.getLocaleManager().getAvailableLocales();
201        List xmlPages = getXmlPages();
202        if (ALL.equals(getParamLocale())) {
203            Iterator i = locales.iterator();
204            while (i.hasNext()) {
205                Locale locale = (Locale)i.next();
206                performRenameOperation(xmlPages, locale);
207            }
208        } else {
209            performRenameOperation(xmlPages, CmsLocaleManager.getLocale(getParamLocale()));
210        }
211    }
212
213    /**
214     * Performs the move report, will be called by the JSP page.<p>
215     *
216     * @throws JspException if problems including sub-elements occur
217     */
218    public void actionReport() throws JspException {
219
220        // save initialized instance of this class in request attribute for included sub-elements
221        getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
222        switch (getAction()) {
223            case ACTION_REPORT_END:
224                actionCloseDialog();
225                break;
226            case ACTION_REPORT_UPDATE:
227                setParamAction(REPORT_UPDATE);
228                getJsp().include(FILE_REPORT_OUTPUT);
229                break;
230            case ACTION_REPORT_BEGIN:
231            case ACTION_CONFIRMED:
232            default:
233                CmsElementRenameThread thread = new CmsElementRenameThread(getCms(), this);
234                thread.start();
235                setParamAction(REPORT_BEGIN);
236                setParamThread(thread.getUUID().toString());
237                getJsp().include(FILE_REPORT_OUTPUT);
238                break;
239        }
240    }
241
242    /**
243     * Builds the html for the available locales select box.<p>
244     *
245     * @param attributes optional attributes for the &lt;select&gt; tag
246     *
247     * @return the html for the available locales select box
248     */
249    public String buildSelectLocales(String attributes) {
250
251        List options = new ArrayList();
252        List values = new ArrayList();
253        List locales = OpenCms.getLocaleManager().getAvailableLocales();
254        int selectedIndex = -1;
255        if (locales == null) {
256            // no locales found, return empty String
257            return "";
258        } else {
259            // locales found, create option and value lists
260            CmsMessages messages = Messages.get().getBundle(getLocale());
261            options.add(messages.key(Messages.GUI_PLEASE_SELECT_0));
262            values.add("");
263            options.add(messages.key(Messages.GUI_BUTTON_ALL_0));
264            values.add(ALL);
265            if (ALL.equals(getParamLocale())) {
266                selectedIndex = 1;
267            }
268            Iterator i = locales.iterator();
269            int counter = 2;
270            while (i.hasNext()) {
271                Locale locale = (Locale)i.next();
272                String language = locale.getLanguage();
273                String displayLanguage = locale.getDisplayLanguage();
274                if (language.equals(getParamLocale())) {
275                    selectedIndex = counter;
276                }
277                options.add(displayLanguage);
278                values.add(language);
279                counter++;
280            }
281        }
282
283        return CmsWorkplace.buildSelect(attributes, options, values, selectedIndex, false);
284    }
285
286    /**
287     * Builds the html for the template select box.<p>
288     *
289     * @param attributes optional attributes for the &lt;select&gt; tag
290     * @return the html for the template select box
291     */
292    public String buildSelectTemplates(String attributes) {
293
294        List options = new ArrayList();
295        List values = new ArrayList();
296        TreeMap templates = null;
297        int selectedIndex = -1;
298        try {
299            // get all available templates
300            templates = CmsNewResourceXmlPage.getTemplates(getCms(), null);
301        } catch (CmsException e) {
302            // can usually be ignored
303            if (LOG.isInfoEnabled()) {
304                LOG.info(e.getLocalizedMessage(), e);
305            }
306        }
307        if (templates == null) {
308            // no templates found, return empty String
309            return "";
310        } else {
311            // templates found, create option and value lists
312            CmsMessages messages = Messages.get().getBundle(getLocale());
313            options.add(messages.key(Messages.GUI_PLEASE_SELECT_0));
314            values.add("");
315            options.add(messages.key(Messages.GUI_BUTTON_ALL_0));
316            values.add(ALL);
317            if (ALL.equals(getParamTemplate())) {
318                selectedIndex = 1;
319            }
320            Iterator i = templates.entrySet().iterator();
321            int counter = 2;
322            while (i.hasNext()) {
323                Map.Entry entry = (Map.Entry)i.next();
324                String key = (String)entry.getKey();
325                String path = (String)entry.getValue();
326                if (path.equals(getParamTemplate())) {
327                    selectedIndex = counter;
328                }
329                options.add(key);
330                values.add(path);
331                counter++;
332            }
333        }
334        return buildSelect(attributes, options, values, selectedIndex, false);
335    }
336
337    /**
338     * @see org.opencms.workplace.CmsWorkplace#getCms()
339     */
340    @Override
341    public CmsObject getCms() {
342
343        if (m_cms == null) {
344            return super.getCms();
345        }
346
347        return m_cms;
348    }
349
350    /**
351     * Returns the errorMessage.<p>
352     *
353     * @return the errorMessage
354     */
355    public String getErrorMessage() {
356
357        if (CmsStringUtil.isEmpty(m_errorMessage)) {
358            return "";
359        }
360
361        return m_errorMessage;
362    }
363
364    /**
365     * Returns the paramLocale.<p>
366     *
367     * @return the paramLocale
368     */
369    public String getParamLocale() {
370
371        return m_paramLocale;
372    }
373
374    /**
375     * Returns the value of the newvalue parameter.<p>
376     *
377     * @return the value of the newvalue parameter
378     */
379    public String getParamNewElement() {
380
381        return m_paramNewElement;
382    }
383
384    /**
385     * Returns the value of the oldvalue parametere.<p>
386     *
387     * @return the value of the oldvalue parameter
388     */
389    public String getParamOldElement() {
390
391        return m_paramOldElement;
392    }
393
394    /**
395     * Returns the value of the recursive parameter.<p>
396     *
397     * @return the value of the recursive parameter
398     */
399    public String getParamRecursive() {
400
401        return m_paramRecursive;
402    }
403
404    /**
405     * Returns true if the user has set remove empty elements parameter; otherwise false.<p>
406     *
407     * @return true if the user has set remove empty elements parameter; otherwise false
408     */
409    public String getParamRemoveEmptyElements() {
410
411        return m_paramRemoveEmptyElements;
412    }
413
414    /**
415     * Returns the template.<p>
416     *
417     * @return the template
418     */
419    public String getParamTemplate() {
420
421        return m_paramTemplate;
422    }
423
424    /**
425     * Returns true if the user has set validate new element parameter; otherwise false.<p>.<p>
426     *
427     * @return true if the user has set validate new element parameter; otherwise false
428     */
429    public String getParamValidateNewElement() {
430
431        return m_paramValidateNewElement;
432    }
433
434    /**
435     * Sets the errorMessage.<p>
436     *
437     * @param errorMessage the errorMessage to set
438     */
439    public void setErrorMessage(String errorMessage) {
440
441        m_errorMessage = errorMessage;
442    }
443
444    /**
445     * Sets the locale.<p>
446     *
447     * @param paramLocale the locale to set
448     */
449    public void setParamLocale(String paramLocale) {
450
451        m_paramLocale = paramLocale;
452    }
453
454    /**
455     * Sets the value of the newvalue parameter.<p>
456     *
457     * @param paramNewValue the value of the newvalue parameter
458     */
459    public void setParamNewElement(String paramNewValue) {
460
461        m_paramNewElement = paramNewValue;
462    }
463
464    /**
465     * Sets the value of the oldvalue parameter.<p>
466     *
467     * @param paramOldValue the value of the oldvalue parameter
468     */
469    public void setParamOldElement(String paramOldValue) {
470
471        m_paramOldElement = paramOldValue;
472    }
473
474    /**
475     * Sets the value of the recursive parameter.<p>
476     *
477     * @param paramRecursive the value of the recursive parameter
478     */
479    public void setParamRecursive(String paramRecursive) {
480
481        m_paramRecursive = paramRecursive;
482    }
483
484    /**
485     * Sets the remove empty elements parameter to true or false.<p>
486     *
487     * @param paramRemoveEmptyElements the remove empty elements parameter to set
488     */
489    public void setParamRemoveEmptyElements(String paramRemoveEmptyElements) {
490
491        m_paramRemoveEmptyElements = paramRemoveEmptyElements;
492    }
493
494    /**
495     * Sets the param Template.<p>
496     *
497     * @param paramTemplate the template name to set
498     */
499    public void setParamTemplate(String paramTemplate) {
500
501        m_paramTemplate = paramTemplate;
502    }
503
504    /**
505     * Sets the paramValidateNewElement.<p>
506     *
507     * @param paramValidateNewElement the validate new element parameter to set
508     */
509    public void setParamValidateNewElement(String paramValidateNewElement) {
510
511        m_paramValidateNewElement = paramValidateNewElement;
512    }
513
514    /**
515     * Does validate the request parameters and returns a buffer with error messages.<p>
516     *
517     * If there were no error messages, the buffer is empty.<p>
518     */
519    public void validateParameters() {
520
521        // localisation
522        CmsMessages messages = Messages.get().getBundle(getLocale());
523
524        StringBuffer validationErrors = new StringBuffer();
525        if (CmsStringUtil.isEmpty(getParamResource())) {
526            validationErrors.append(messages.key(Messages.GUI_ELEM_RENAME_VALIDATE_RESOURCE_FOLDER_0)).append("<br>");
527        }
528        if (CmsStringUtil.isEmpty(getParamTemplate())) {
529            validationErrors.append(messages.key(Messages.GUI_ELEM_RENAME_VALIDATE_SELECT_TEMPLATE_0)).append("<br>");
530        }
531        if (CmsStringUtil.isEmpty(getParamLocale())) {
532            validationErrors.append(messages.key(Messages.GUI_ELEM_RENAME_VALIDATE_SELECT_LANGUAGE_0)).append("<br>");
533        }
534        if (CmsStringUtil.isEmpty(getParamOldElement())) {
535            validationErrors.append(messages.key(Messages.GUI_ELEM_RENAME_VALIDATE_ENTER_OLD_ELEM_0)).append("<br>");
536        }
537        if (CmsStringUtil.isEmpty(getParamNewElement())) {
538            validationErrors.append(messages.key(Messages.GUI_ELEM_RENAME_VALIDATE_ENTER_NEW_ELEM_0)).append("<br>");
539        }
540        if (!isValidElement(getParamNewElement())) {
541            validationErrors.append(
542                messages.key(
543                    Messages.GUI_ELEM_RENAME_VALIDATE_INVALID_NEW_ELEM_2,
544                    getParamNewElement(),
545                    getParamTemplate())).append("<br>");
546        }
547
548        setErrorMessage(validationErrors.toString());
549    }
550
551    /**
552     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
553     */
554    @Override
555    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
556
557        // fill the parameter values in the get/set methods
558        fillParamValues(request);
559        // set the dialog type
560        setParamDialogtype(DIALOG_TYPE);
561        // set the action for the JSP switch
562        // set the action for the JSP switch
563        if (DIALOG_CONFIRMED.equals(getParamAction())) {
564            setAction(ACTION_CONFIRMED);
565        } else if (DIALOG_OK.equals(getParamAction())) {
566            setAction(ACTION_OK);
567        } else if (DIALOG_CANCEL.equals(getParamAction())) {
568            setAction(ACTION_CANCEL);
569        } else if (REPORT_UPDATE.equals(getParamAction())) {
570            setAction(ACTION_REPORT_UPDATE);
571        } else if (REPORT_BEGIN.equals(getParamAction())) {
572            setAction(ACTION_REPORT_BEGIN);
573        } else if (REPORT_END.equals(getParamAction())) {
574            setAction(ACTION_REPORT_END);
575        } else {
576            setAction(ACTION_DEFAULT);
577            // add the title for the dialog
578            setParamTitle(key("title.renameelement"));
579        }
580    }
581
582    /**
583     * Returns a retained list of xml pages that belongs to the specified template.<p>
584     *
585     * @param xmlPages a list of all xml pages
586     * @return a retained list of xml pages that belongs to the specified template
587     */
588    private List getRetainedPagesWithTemplate(List xmlPages) {
589
590        // list of resources belongs to the selected template
591        List resourcesWithTemplate = new ArrayList();
592        TreeMap templates = null;
593        try {
594            templates = CmsNewResourceXmlPage.getTemplates(getCms(), null);
595        } catch (CmsException e) {
596            if (LOG.isErrorEnabled()) {
597                LOG.error(e.getLocalizedMessage(), e);
598            }
599        }
600        // check if the users selected template is valid.
601        if ((templates != null) && templates.containsValue(getParamTemplate())) {
602            // iterate the xmlPages list and add all resources with the specified template to the resourcesWithTemplate list
603            Iterator i = xmlPages.iterator();
604            while (i.hasNext()) {
605                CmsResource currentPage = (CmsResource)i.next();
606                // read the template property
607                CmsProperty templateProperty;
608                try {
609                    templateProperty = getCms().readPropertyObject(
610                        getCms().getSitePath(currentPage),
611                        CmsPropertyDefinition.PROPERTY_TEMPLATE,
612                        false);
613                } catch (CmsException e2) {
614                    if (LOG.isErrorEnabled()) {
615                        LOG.error(e2);
616                    }
617                    continue;
618                }
619                // add currentResource if the template property value is the same as the given template
620                if (getParamTemplate().equals(templateProperty.getValue())) {
621                    resourcesWithTemplate.add(currentPage);
622                }
623            }
624            // retain the list of pages against the list with template
625            xmlPages.retainAll(resourcesWithTemplate);
626        }
627
628        return xmlPages;
629    }
630
631    /**
632     * Returns a set of elements stored in the given template property.<p>
633     *
634     * The elements are stored in the property I_CmsConstants.C_PROPERTY_TEMPLATE_ELEMENTS.<p>
635     *
636     * @param currentTemplate the path of the template to look in
637     * @return a set of elements stored in the given template path
638     */
639    private Set getTemplateElements(String currentTemplate) {
640
641        Set templateElements = new HashSet();
642
643        if ((currentTemplate != null) && (currentTemplate.length() > 0)) {
644            // template found, check template-elements property
645            String elements = null;
646            try {
647                // read the property from the template file
648                elements = getCms().readPropertyObject(
649                    currentTemplate,
650                    CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
651                    false).getValue(null);
652            } catch (CmsException e) {
653                if (LOG.isWarnEnabled()) {
654                    LOG.warn(e.getLocalizedMessage());
655                }
656            }
657            if (elements != null) {
658                // elements are defined on template file, merge with available elements
659                StringTokenizer T = new StringTokenizer(elements, ",");
660                while (T.hasMoreTokens()) {
661                    String currentElement = T.nextToken();
662                    String niceName = null;
663                    boolean mandatory = false;
664                    int sepIndex = currentElement.indexOf("|");
665                    if (sepIndex != -1) {
666                        // nice name found for current element, extract it
667                        niceName = currentElement.substring(sepIndex + 1);
668                        currentElement = currentElement.substring(0, sepIndex);
669                    }
670                    if (currentElement.endsWith("*")) {
671                        // element is mandatory
672                        mandatory = true;
673                        currentElement = currentElement.substring(0, currentElement.length() - 1);
674                    }
675
676                    CmsDialogElement element = new CmsDialogElement(currentElement, niceName, mandatory, true, false);
677                    templateElements.add(element);
678                }
679            }
680        }
681
682        return templateElements;
683    }
684
685    /**
686     * Returns a list of xml pages from the specified folder.<p>
687     *
688     * @return a list of xml pages from the specified folder
689     */
690    private List getXmlPages() {
691
692        boolean isRecursive = Boolean.valueOf(getParamRecursive()).booleanValue();
693        // filter definition to read only the required resources
694        int xmlPageId;
695        try {
696            xmlPageId = OpenCms.getResourceManager().getResourceType(
697                CmsResourceTypeXmlPage.getStaticTypeName()).getTypeId();
698        } catch (CmsLoaderException e1) {
699            xmlPageId = CmsResourceTypeXmlPage.getStaticTypeId();
700        }
701        CmsResourceFilter filter = CmsResourceFilter.IGNORE_EXPIRATION.addRequireType(xmlPageId);
702        // trying to read the resources
703        List xmlPages = null;
704
705        try {
706            xmlPages = getCms().readResources(getParamResource(), filter, isRecursive);
707        } catch (CmsException e) {
708            if (LOG.isErrorEnabled()) {
709                LOG.error(e.getLocalizedMessage(), e);
710            }
711        }
712
713        return xmlPages;
714    }
715
716    /**
717     * Checks if the specified element/locale of the given page has a content.<p>
718     *
719     * @param page the xml page
720     * @param element the element name
721     * @param locale the locale
722     * @return false if the specified element/locale of the given page has a content; otherwise true
723     */
724    private boolean isEmptyElement(CmsXmlPage page, String element, Locale locale) {
725
726        CmsXmlHtmlValue xmlHtmlValue = (CmsXmlHtmlValue)page.getValue(element, locale);
727        if (CmsStringUtil.isNotEmpty(xmlHtmlValue.getPlainText(getCms()))) {
728            return false;
729        }
730
731        return true;
732    }
733
734    /**
735     * Checks if the selected new element is valid for the selected template.<p>
736     *
737     * @param page the xml page
738     * @param element the element name
739     *
740     * @return true if ALL_TEMPLATES selected or the element is valid for the selected template; otherwise false
741     */
742    private boolean isValidElement(CmsXmlPage page, String element) {
743
744        CmsFile file = page.getFile();
745        String template;
746        try {
747            template = getCms().readPropertyObject(
748                getCms().getSitePath(file),
749                CmsPropertyDefinition.PROPERTY_TEMPLATE,
750                true).getValue(null);
751        } catch (CmsException e) {
752            return false;
753        }
754
755        return isValidTemplateElement(template, element);
756    }
757
758    /**
759     * Checks if the selected new element is valid for the selected template.<p>
760     *
761     * @param element the element name
762     *
763     * @return true if ALL_TEMPLATES selected or the element is valid for the selected template; otherwise false
764     */
765    private boolean isValidElement(String element) {
766
767        boolean validateNewElement = Boolean.valueOf(getParamValidateNewElement()).booleanValue();
768        if (ALL.equals(getParamTemplate()) || !validateNewElement) {
769            return true;
770        }
771
772        return isValidTemplateElement(getParamTemplate(), element);
773    }
774
775    /**
776     * Check if the given template includes the specified element.<p>
777     *
778     * @param template the template
779     * @param element the element name
780     * @return true if the template includes the given element
781     */
782    private boolean isValidTemplateElement(String template, String element) {
783
784        List elements = new ArrayList(getTemplateElements(template));
785        Iterator i = elements.iterator();
786        while (i.hasNext()) {
787            CmsDialogElement currElement = (CmsDialogElement)i.next();
788            if (element.equals(currElement.getName())) {
789                return true;
790            }
791        }
792
793        return false;
794    }
795
796    /**
797     * Performs the main element rename operation on the filtered resources.<p>
798     *
799     * @param xmlPages the list of xml pages
800     * @param locale the locale specifying the xmlpage node to perform the operation on
801     */
802    private void performRenameOperation(List xmlPages, Locale locale) {
803
804        // partial localized (stopped due to low prio).
805        boolean removeEmptyElements = Boolean.valueOf(getParamRemoveEmptyElements()).booleanValue();
806        boolean validateNewElement = Boolean.valueOf(getParamValidateNewElement()).booleanValue();
807        // the list including at least one resource
808        if ((xmlPages != null) && (xmlPages.size() > 0)) {
809            m_report.println(
810                Messages.get().container(Messages.RPT_RENAME_LANG_1, locale.getLanguage()),
811                I_CmsReport.FORMAT_HEADLINE);
812            // if user has not selected ALL templates, then retain pages with specified template
813            if (!ALL.equals(getParamTemplate())) {
814                xmlPages = getRetainedPagesWithTemplate(xmlPages);
815            }
816            int m = 0;
817            int n = xmlPages.size();
818            // loop over remained pages
819            Iterator i = xmlPages.iterator();
820            while (i.hasNext()) {
821                m++;
822                CmsXmlPage page = null;
823                try {
824                    // next file from the list
825                    CmsResource res = (CmsResource)i.next();
826                    CmsFile file;
827
828                    m_report.print(
829                        org.opencms.report.Messages.get().container(
830                            org.opencms.report.Messages.RPT_SUCCESSION_2,
831                            String.valueOf(m),
832                            String.valueOf(n)),
833                        I_CmsReport.FORMAT_NOTE);
834                    m_report.print(Messages.get().container(Messages.RPT_PROCESSING_PAGE_0), I_CmsReport.FORMAT_NOTE);
835                    m_report.print(
836                        org.opencms.report.Messages.get().container(
837                            org.opencms.report.Messages.RPT_ARGUMENT_1,
838                            getCms().getSitePath(res)));
839                    m_report.println(
840                        org.opencms.report.Messages.get().container(org.opencms.report.Messages.RPT_DOTS_0));
841
842                    try {
843                        file = getCms().readFile(getCms().getSitePath(res), CmsResourceFilter.IGNORE_EXPIRATION);
844                    } catch (CmsException e2) {
845                        if (LOG.isErrorEnabled()) {
846                            LOG.error(e2);
847                        }
848                        m_report.println(e2);
849                        continue;
850                    }
851                    // try unmarshaling to xml page
852                    try {
853                        page = CmsXmlPageFactory.unmarshal(getCms(), file);
854                    } catch (CmsXmlException e) {
855                        m_report.println(e);
856                        continue;
857                    }
858
859                    // check if the source element exists in the page
860                    if (!page.hasValue(getParamOldElement(), locale)) {
861                        m_report.println(
862                            Messages.get().container(Messages.RPT_NONEXISTANT_ELEM_1, getParamOldElement()),
863                            I_CmsReport.FORMAT_NOTE);
864                        continue;
865                    }
866
867                    // check if the target element already exists in the page
868                    if (page.hasValue(getParamNewElement(), locale)) {
869                        // the page contains already the new element with speicific content.
870                        // renaming the old will invalid the xml page
871                        m_report.println(
872                            Messages.get().container(Messages.RPT_NEW_ELEM_EXISTS_0),
873                            I_CmsReport.FORMAT_NOTE);
874                        continue;
875                    }
876
877                    if (validateNewElement) {
878                        // check if the target element is valid for the template
879                        if (!isValidElement(page, getParamNewElement())) {
880                            m_report.println(
881                                Messages.get().container(Messages.RPT_INVALID_ARGUMENT_1, getParamNewElement()),
882                                I_CmsReport.FORMAT_NOTE);
883                            continue;
884                        }
885                    }
886
887                    try {
888                        // rename the element from the old value to the new
889                        page.renameValue(getParamOldElement(), getParamNewElement(), locale);
890                        // write the page with the new content
891                        writePageAndReport(page, true);
892                    } catch (Throwable t) {
893                        LOG.error(t);
894                        m_report.println(t);
895                        continue;
896                    }
897
898                } catch (Throwable t) {
899                    LOG.error(t);
900                    m_report.println(t);
901                } finally {
902                    // finally do remove empty elements of the page
903                    // the remove operation is executed if the user has checked the specified checkbox and selected a template (NOT ALL)
904                    if (removeEmptyElements) {
905                        removeInValidElements(page, locale);
906                    }
907                }
908            }
909        }
910    }
911
912    /**
913     * Analyzes xml page and removes any element if this is not valid for the specified template and has no content.<p>
914     *
915     * @param page a xml page
916     * @param locale the locale
917     */
918    private void removeInValidElements(CmsXmlPage page, Locale locale) {
919
920        if (page == null) {
921            return;
922        }
923
924        if (ALL.equals(getParamTemplate())) {
925            return;
926        }
927
928        // get all elements of this page
929        List pageElements = page.getNames(locale);
930        if (pageElements != null) {
931            Iterator i = pageElements.iterator();
932            while (i.hasNext()) {
933                String currElement = (String)i.next();
934                // remove current element only is invalid and has no content
935                if (!isValidElement(currElement) && isEmptyElement(page, currElement, locale)) {
936                    page.removeValue(currElement, locale);
937                    try {
938                        writePageAndReport(page, false);
939                        m_report.println(
940                            Messages.get().container(Messages.RPT_REMOVE_INVALID_EMPTY_ELEM_1, currElement),
941                            I_CmsReport.FORMAT_NOTE);
942                    } catch (CmsException e) {
943                        // ignore
944                    }
945                }
946            }
947        }
948    }
949
950    /**
951     * Writes the given xml page by reporting the result.<p>
952     *
953     * @param page the xml page
954     * @param report if true then some output will be written to the report
955     * @throws CmsException if operation failed
956     */
957    private void writePageAndReport(CmsXmlPage page, boolean report) throws CmsException {
958
959        CmsFile file = page.getFile();
960        byte[] content = page.marshal();
961        file.setContents(content);
962        // check lock
963        CmsLock lock = getCms().getLock(file);
964        if (lock.isNullLock() || lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())) {
965            // lock the page
966            checkLock(getCms().getSitePath(file));
967            // write the file with the new content
968            getCms().writeFile(file);
969            // unlock the page
970            getCms().unlockResource(getCms().getSitePath(file));
971            if (report) {
972                m_report.println(
973                    Messages.get().container(Messages.RPT_ELEM_RENAME_2, getParamOldElement(), getParamNewElement()),
974                    I_CmsReport.FORMAT_OK);
975            }
976        }
977    }
978}