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.comparison;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.jsp.CmsJspActionElement;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.util.CmsDateUtil;
036import org.opencms.util.CmsStringUtil;
037import org.opencms.util.CmsUUID;
038import org.opencms.workplace.commons.CmsHistoryList;
039import org.opencms.workplace.list.A_CmsListDialog;
040import org.opencms.workplace.list.CmsListColumnAlignEnum;
041import org.opencms.workplace.list.CmsListColumnDefinition;
042import org.opencms.workplace.list.CmsListDefaultAction;
043import org.opencms.workplace.list.CmsListDirectAction;
044import org.opencms.workplace.list.CmsListIndependentAction;
045import org.opencms.workplace.list.CmsListItem;
046import org.opencms.workplace.list.CmsListItemDetails;
047import org.opencms.workplace.list.CmsListMetadata;
048import org.opencms.workplace.list.CmsListOrderEnum;
049import org.opencms.xml.types.CmsXmlDateTimeValue;
050
051import java.io.IOException;
052import java.text.DateFormat;
053import java.util.ArrayList;
054import java.util.Date;
055import java.util.HashMap;
056import java.util.Iterator;
057import java.util.List;
058import java.util.Map;
059
060import javax.servlet.ServletException;
061import javax.servlet.http.HttpServletRequest;
062import javax.servlet.http.HttpServletResponse;
063import javax.servlet.jsp.PageContext;
064
065import org.apache.commons.logging.Log;
066
067/**
068 * Element comparison list view. <p>
069 *
070 * @since 6.0.0
071 */
072public class CmsElementComparisonList extends A_CmsListDialog {
073
074    /** list action id constant. */
075    public static final String LIST_ACTION_ICON = "ai";
076
077    /** list action id constant. */
078    public static final String LIST_ACTION_STATUS = "at";
079
080    /** list column id constant. */
081    public static final String LIST_COLUMN_ATTRIBUTE = "ca";
082
083    /** list column id constant. */
084    public static final String LIST_COLUMN_ICON = "ci";
085
086    /** list column id constant. */
087    public static final String LIST_COLUMN_LOCALE = "cl";
088
089    /** list column id constant. */
090    public static final String LIST_COLUMN_STATUS = "cs";
091
092    /** list column id constant. */
093    public static final String LIST_COLUMN_TYPE = "cy";
094
095    /** list column id constant. */
096    public static final String LIST_COLUMN_VERSION_1 = "cv";
097
098    /** list column id constant. */
099    public static final String LIST_COLUMN_VERSION_2 = "cw";
100
101    /** list default action id constant. */
102    public static final String LIST_DEFACTION_VIEW = "dv";
103
104    /** list independent action id constant. */
105    public static final String LIST_DETAIL_TYPE = "dt";
106
107    /** list independent action id constant. */
108    public static final String LIST_IACTION_COMPARE_ALL = "ava";
109
110    /** list independent action id constant. */
111    public static final String LIST_IACTION_SHOW = "isy";
112
113    /** List id constant. */
114    public static final String LIST_ID = "hiecl";
115
116    /** Request parameter name for the element. */
117    public static final String PARAM_ELEMENT = "element";
118
119    /** Request parameter name for the locale. */
120    public static final String PARAM_LOCALE = "locale";
121
122    /** The log object for this class. */
123    private static final Log LOG = CmsLog.getLog(CmsElementComparisonList.class);
124
125    /** Parameter value for the structure id of the first file. */
126    private String m_paramId1;
127
128    /** Parameter value for the structure id of the second file. */
129    private String m_paramId2;
130
131    /** Parameter value for the version of the first file. */
132    private String m_paramVersion1;
133
134    /** Parameter value for the version of the second file. */
135    private String m_paramVersion2;
136
137    /** flag indicating whether xml contents are compared.<p> */
138    private boolean m_xmlContentComparisonMode;
139
140    /**
141     * Public constructor.<p>
142     *
143     * @param jsp an initialized JSP action element
144     */
145    public CmsElementComparisonList(CmsJspActionElement jsp) {
146
147        this(LIST_ID, jsp);
148    }
149
150    /**
151     * Public constructor with JSP variables.<p>
152     *
153     * @param context the JSP page context
154     * @param req the JSP request
155     * @param res the JSP response
156     */
157    public CmsElementComparisonList(PageContext context, HttpServletRequest req, HttpServletResponse res) {
158
159        this(new CmsJspActionElement(context, req, res));
160    }
161
162    /**
163     * Protected constructor.<p>
164     *
165     * @param listId the id of the specialized list
166     * @param jsp an initialized JSP action element
167     */
168    protected CmsElementComparisonList(String listId, CmsJspActionElement jsp) {
169
170        super(
171            jsp,
172            listId,
173            Messages.get().container(Messages.GUI_COMPARE_CONTENT_0),
174            LIST_COLUMN_LOCALE,
175            CmsListOrderEnum.ORDER_ASCENDING,
176            null);
177    }
178
179    public static String formatContentValueForDiffTable(
180        CmsObject cms,
181        CmsElementComparison comparison,
182        String origValue) {
183
184        String result = CmsStringUtil.escapeHtml(
185            CmsStringUtil.substitute(
186                CmsStringUtil.trimToSize(origValue, CmsPropertyComparisonList.TRIM_AT_LENGTH),
187                "\n",
188                ""));
189
190        // formatting DateTime
191        if (comparison instanceof CmsXmlContentElementComparison) {
192            if (((CmsXmlContentElementComparison)comparison).getType().equals(CmsXmlDateTimeValue.TYPE_NAME)) {
193                if (CmsStringUtil.isNotEmpty(result)) {
194
195                    result = CmsDateUtil.getDateTime(
196                        new Date(Long.parseLong(result)),
197                        DateFormat.SHORT,
198                        cms.getRequestContext().getLocale());
199                }
200            }
201        }
202        return result;
203    }
204
205    /**
206     *
207     * @see org.opencms.workplace.list.A_CmsListDialog#executeListIndepActions()
208     */
209    @Override
210    public void executeListIndepActions() {
211
212        if (getParamListAction().equals(LIST_IACTION_COMPARE_ALL)) {
213            // called if all elements are to be compared
214            Map<String, String[]> params = new HashMap<String, String[]>();
215            params.put(CmsHistoryList.PARAM_VERSION_1, new String[] {getParamVersion1()});
216            params.put(CmsHistoryList.PARAM_VERSION_2, new String[] {getParamVersion2()});
217            params.put(CmsHistoryList.PARAM_ID_1, new String[] {getParamId1()});
218            params.put(CmsHistoryList.PARAM_ID_2, new String[] {getParamId2()});
219            params.put(
220                CmsPropertyComparisonList.PARAM_COMPARE,
221                new String[] {CmsResourceComparisonDialog.COMPARE_ALL_ELEMENTS});
222            params.put(PARAM_RESOURCE, new String[] {getParamResource()});
223            // forward to the element difference screen
224            try {
225                getToolManager().jspForwardTool(this, "/history/comparison/difference", params);
226            } catch (Exception e) {
227                LOG.debug(e.getMessage(), e);
228            }
229
230        }
231        super.executeListIndepActions();
232    }
233
234    /**
235     * @see org.opencms.workplace.list.A_CmsListDialog#executeListMultiActions()
236     */
237    @Override
238    public void executeListMultiActions() {
239
240        throwListUnsupportedActionException();
241    }
242
243    /**
244     * @see org.opencms.workplace.list.A_CmsListDialog#executeListSingleActions()
245     */
246    @Override
247    public void executeListSingleActions() throws IOException, ServletException {
248
249        Map<String, String[]> params = new HashMap<String, String[]>();
250        params.put(CmsHistoryList.PARAM_VERSION_1, new String[] {getParamVersion1()});
251        params.put(CmsHistoryList.PARAM_VERSION_2, new String[] {getParamVersion2()});
252        params.put(CmsHistoryList.PARAM_ID_1, new String[] {getParamId1()});
253        params.put(CmsHistoryList.PARAM_ID_2, new String[] {getParamId2()});
254        params.put(PARAM_LOCALE, new String[] {getSelectedItem().get(LIST_COLUMN_LOCALE).toString()});
255        params.put(PARAM_ELEMENT, new String[] {getSelectedItem().get(LIST_COLUMN_ATTRIBUTE).toString()});
256        params.put(PARAM_RESOURCE, new String[] {getParamResource()});
257        // forward to the element difference screen
258        getToolManager().jspForwardTool(this, "/history/comparison/difference", params);
259
260    }
261
262    /**
263     * Returns the paramId1.<p>
264     *
265     * @return the paramId1
266     */
267    public String getParamId1() {
268
269        return m_paramId1;
270    }
271
272    /**
273     * Returns the paramId2.<p>
274     *
275     * @return the paramId2
276     */
277    public String getParamId2() {
278
279        return m_paramId2;
280    }
281
282    /**
283     * Returns the paramNewversionid.<p>
284     *
285     * @return the paramNewversionid
286     */
287    public String getParamVersion1() {
288
289        return m_paramVersion1;
290    }
291
292    /**
293     * Returns the paramOldversionid.<p>
294     *
295     * @return the paramOldversionid
296     */
297    public String getParamVersion2() {
298
299        return m_paramVersion2;
300    }
301
302    /**
303     * Sets the paramId1.<p>
304     *
305     * @param paramId1 the paramId1 to set
306     */
307    public void setParamId1(String paramId1) {
308
309        m_paramId1 = paramId1;
310    }
311
312    /**
313     * Sets the paramId2.<p>
314     *
315     * @param paramId2 the paramId2 to set
316     */
317    public void setParamId2(String paramId2) {
318
319        m_paramId2 = paramId2;
320    }
321
322    /**
323     * Sets the paramNewversionid.<p>
324     *
325     * @param paramNewversionid the paramNewversionid to set
326     */
327    public void setParamVersion1(String paramNewversionid) {
328
329        m_paramVersion1 = paramNewversionid;
330    }
331
332    /**
333     * Sets the paramOldversionid.<p>
334     *
335     * @param paramOldversionid the paramOldversionid to set
336     */
337    public void setParamVersion2(String paramOldversionid) {
338
339        m_paramVersion2 = paramOldversionid;
340    }
341
342    /**
343     * @see org.opencms.workplace.list.A_CmsListDialog#fillDetails(java.lang.String)
344     */
345    @Override
346    protected void fillDetails(String detailId) {
347
348        // no-op
349    }
350
351    /**
352     * @see org.opencms.workplace.list.A_CmsListDialog#getListItems()
353     */
354    @Override
355    protected List<CmsListItem> getListItems() throws CmsException {
356
357        List<CmsListItem> result = new ArrayList<CmsListItem>();
358        CmsFile resource1 = CmsResourceComparisonDialog.readFile(
359            getCms(),
360            new CmsUUID(getParamId1()),
361            getParamVersion1());
362        CmsFile resource2 = CmsResourceComparisonDialog.readFile(
363            getCms(),
364            new CmsUUID(getParamId2()),
365            getParamVersion2());
366        Iterator<CmsElementComparison> diffs = new CmsXmlDocumentComparison(
367            getCms(),
368            resource1,
369            resource2).getElements().iterator();
370        while (diffs.hasNext()) {
371            CmsElementComparison comparison = diffs.next();
372            String locale = comparison.getLocale().toString();
373            String attribute = comparison.getName();
374            CmsListItem item = getList().newItem(locale + attribute);
375            item.set(LIST_COLUMN_LOCALE, locale);
376            item.set(LIST_COLUMN_ATTRIBUTE, attribute);
377            if (comparison instanceof CmsXmlContentElementComparison) {
378                m_xmlContentComparisonMode = true;
379                item.set(LIST_COLUMN_TYPE, ((CmsXmlContentElementComparison)comparison).getType());
380            }
381            if (CmsResourceComparison.TYPE_ADDED.equals(comparison.getStatus())) {
382                item.set(LIST_COLUMN_STATUS, key(Messages.GUI_COMPARE_ADDED_0));
383            } else if (CmsResourceComparison.TYPE_REMOVED.equals(comparison.getStatus())) {
384                item.set(LIST_COLUMN_STATUS, key(Messages.GUI_COMPARE_REMOVED_0));
385            } else if (CmsResourceComparison.TYPE_CHANGED.equals(comparison.getStatus())) {
386                item.set(LIST_COLUMN_STATUS, key(Messages.GUI_COMPARE_CHANGED_0));
387            } else {
388                if (!getList().getMetadata().getItemDetailDefinition(LIST_IACTION_SHOW).isVisible()) {
389                    // do not display entry
390                    continue;
391                } else {
392                    item.set(LIST_COLUMN_STATUS, key(Messages.GUI_COMPARE_UNCHANGED_0));
393                }
394            }
395            String value1 = CmsStringUtil.escapeHtml(
396                CmsStringUtil.substitute(
397                    CmsStringUtil.trimToSize(comparison.getVersion1(), CmsPropertyComparisonList.TRIM_AT_LENGTH),
398                    "\n",
399                    ""));
400
401            // formatting DateTime
402            if (comparison instanceof CmsXmlContentElementComparison) {
403                if (((CmsXmlContentElementComparison)comparison).getType().equals(CmsXmlDateTimeValue.TYPE_NAME)) {
404                    if (CmsStringUtil.isNotEmpty(value1)) {
405                        value1 = CmsDateUtil.getDateTime(
406                            new Date(Long.parseLong(value1)),
407                            DateFormat.SHORT,
408                            getCms().getRequestContext().getLocale());
409                    }
410                }
411            }
412            item.set(LIST_COLUMN_VERSION_1, value1);
413
414            String origValue = comparison.getVersion2();
415            String value2 = formatContentValueForDiffTable(getCms(), comparison, origValue);
416            item.set(LIST_COLUMN_VERSION_2, value2);
417            result.add(item);
418        }
419
420        getList().getMetadata().getColumnDefinition(LIST_COLUMN_VERSION_1).setName(
421            Messages.get().container(
422                Messages.GUI_COMPARE_VERSION_1,
423                CmsHistoryListUtil.getDisplayVersion(getParamVersion1(), getLocale())));
424        getList().getMetadata().getColumnDefinition(LIST_COLUMN_VERSION_2).setName(Messages.get().container(
425            Messages.GUI_COMPARE_VERSION_1,
426            CmsHistoryListUtil.getDisplayVersion(getParamVersion2(), getLocale())));
427        return result;
428    }
429
430    /**
431     * @see org.opencms.workplace.list.A_CmsListDialog#setColumns(org.opencms.workplace.list.CmsListMetadata)
432     */
433    @Override
434    protected void setColumns(CmsListMetadata metadata) {
435
436        // create column for icon
437        CmsListColumnDefinition iconCol = new CmsListColumnDefinition(LIST_COLUMN_ICON);
438        iconCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_ICON_0));
439        iconCol.setWidth("20");
440        iconCol.setAlign(CmsListColumnAlignEnum.ALIGN_CENTER);
441        iconCol.setSorteable(true);
442
443        // add state error action
444        CmsListDirectAction addedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_ADDED) {
445
446            @Override
447            public boolean isVisible() {
448
449                String type = getItem().get(LIST_COLUMN_STATUS).toString();
450                return key(Messages.GUI_COMPARE_ADDED_0).equals(type);
451            }
452        };
453        addedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_ADDED_0));
454        addedAction.setIconPath("tools/ex_history/buttons/added.png");
455        addedAction.setEnabled(true);
456        iconCol.addDirectAction(addedAction);
457
458        // add state error action
459        CmsListDirectAction removedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_REMOVED) {
460
461            @Override
462            public boolean isVisible() {
463
464                String type = getItem().get(LIST_COLUMN_STATUS).toString();
465                return key(Messages.GUI_COMPARE_REMOVED_0).equals(type);
466            }
467        };
468        removedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_REMOVED_0));
469        removedAction.setIconPath("tools/ex_history/buttons/removed.png");
470        removedAction.setEnabled(true);
471        iconCol.addDirectAction(removedAction);
472
473        // add state error action
474        CmsListDirectAction changedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_CHANGED) {
475
476            @Override
477            public boolean isVisible() {
478
479                String type = getItem().get(LIST_COLUMN_STATUS).toString();
480                return key(Messages.GUI_COMPARE_CHANGED_0).equals(type);
481            }
482        };
483        changedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_CHANGED_0));
484        changedAction.setIconPath("tools/ex_history/buttons/changed.png");
485        changedAction.setEnabled(true);
486        iconCol.addDirectAction(changedAction);
487
488        // add state error action
489        CmsListDirectAction unchangedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_UNCHANGED) {
490
491            @Override
492            public boolean isVisible() {
493
494                String type = getItem().get(LIST_COLUMN_STATUS).toString();
495                return key(Messages.GUI_COMPARE_UNCHANGED_0).equals(type);
496            }
497        };
498        unchangedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_UNCHANGED_0));
499        unchangedAction.setIconPath("tools/ex_history/buttons/unchanged.png");
500        unchangedAction.setEnabled(true);
501        iconCol.addDirectAction(unchangedAction);
502        metadata.addColumn(iconCol);
503        iconCol.setPrintable(false);
504
505        // add column for type
506        CmsListColumnDefinition statusCol = new CmsListColumnDefinition(LIST_COLUMN_STATUS);
507        statusCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_STATUS_0));
508        statusCol.setWidth("10%");
509
510        CmsListDefaultAction statusColAction = new CmsListDefaultAction(LIST_ACTION_STATUS);
511        statusColAction.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_STATUS_0));
512        statusColAction.setEnabled(true);
513        statusCol.addDefaultAction(statusColAction);
514        metadata.addColumn(statusCol);
515        statusCol.setPrintable(true);
516
517        // add column for locale
518        CmsListColumnDefinition localeCol = new CmsListColumnDefinition(LIST_COLUMN_LOCALE);
519        localeCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_LOCALE_0));
520        localeCol.setWidth("10%");
521        metadata.addColumn(localeCol);
522        localeCol.setPrintable(true);
523
524        // add column for element name
525        CmsListColumnDefinition attCol = new CmsListColumnDefinition(LIST_COLUMN_ATTRIBUTE);
526        attCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_NAME_0));
527        attCol.setWidth("10%");
528        metadata.addColumn(attCol);
529        attCol.setPrintable(true);
530
531        CmsListColumnDefinition typeCol = new CmsListColumnDefinition(LIST_COLUMN_TYPE);
532        typeCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_TYPE_0));
533        typeCol.setWidth("10%");
534        // display column only if xml content is compared
535        typeCol.setVisible(m_xmlContentComparisonMode);
536        metadata.addColumn(typeCol);
537        typeCol.setPrintable(true);
538
539        // add column for first value
540        CmsListColumnDefinition version1Col = new CmsListColumnDefinition(LIST_COLUMN_VERSION_1);
541        version1Col.setName(
542            Messages.get().container(
543                Messages.GUI_COMPARE_VERSION_1,
544                CmsHistoryListUtil.getDisplayVersion(getParamVersion1(), getLocale())));
545        version1Col.setWidth("35%");
546        version1Col.setSorteable(false);
547        metadata.addColumn(version1Col);
548        version1Col.setPrintable(true);
549
550        // add column for second value
551        CmsListColumnDefinition version2Col = new CmsListColumnDefinition(LIST_COLUMN_VERSION_2);
552        version2Col.setName(
553            Messages.get().container(
554                Messages.GUI_COMPARE_VERSION_1,
555                CmsHistoryListUtil.getDisplayVersion(getParamVersion2(), getLocale())));
556        version2Col.setWidth("35%");
557        version2Col.setSorteable(false);
558        metadata.addColumn(version2Col);
559        version2Col.setPrintable(true);
560    }
561
562    /**
563     * @see org.opencms.workplace.list.A_CmsListDialog#setIndependentActions(org.opencms.workplace.list.CmsListMetadata)
564     */
565    @Override
566    protected void setIndependentActions(CmsListMetadata metadata) {
567
568        CmsListIndependentAction compare = new CmsListIndependentAction(LIST_IACTION_COMPARE_ALL);
569        compare.setName(Messages.get().container(Messages.GUI_COMPARE_COMPARE_ALL_0));
570        compare.setIconPath("tools/ex_history/buttons/compare.png");
571        compare.setEnabled(true);
572        metadata.addIndependentAction(compare);
573
574        // add event details
575        CmsListItemDetails eventDetails = new CmsListItemDetails(LIST_IACTION_SHOW);
576        eventDetails.setVisible(false);
577        eventDetails.setShowActionName(Messages.get().container(Messages.GUI_COMPARE_SHOW_ALL_ELEMENTS_0));
578        eventDetails.setHideActionName(Messages.get().container(Messages.GUI_COMPARE_HIDE_IDENTICAL_ELEMENTS_0));
579        metadata.addItemDetails(eventDetails);
580    }
581
582    /**
583     * @see org.opencms.workplace.list.A_CmsListDialog#setMultiActions(org.opencms.workplace.list.CmsListMetadata)
584     */
585    @Override
586    protected void setMultiActions(CmsListMetadata metadata) {
587
588        // no-op
589    }
590}