001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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 org.apache.commons.logging.Log; 061 062import jakarta.servlet.ServletException; 063import jakarta.servlet.http.HttpServletRequest; 064import jakarta.servlet.http.HttpServletResponse; 065import jakarta.servlet.jsp.PageContext; 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( 425 Messages.get().container( 426 Messages.GUI_COMPARE_VERSION_1, 427 CmsHistoryListUtil.getDisplayVersion(getParamVersion2(), getLocale()))); 428 return result; 429 } 430 431 /** 432 * @see org.opencms.workplace.list.A_CmsListDialog#setColumns(org.opencms.workplace.list.CmsListMetadata) 433 */ 434 @Override 435 protected void setColumns(CmsListMetadata metadata) { 436 437 // create column for icon 438 CmsListColumnDefinition iconCol = new CmsListColumnDefinition(LIST_COLUMN_ICON); 439 iconCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_ICON_0)); 440 iconCol.setWidth("20"); 441 iconCol.setAlign(CmsListColumnAlignEnum.ALIGN_CENTER); 442 iconCol.setSorteable(true); 443 444 // add state error action 445 CmsListDirectAction addedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_ADDED) { 446 447 @Override 448 public boolean isVisible() { 449 450 String type = getItem().get(LIST_COLUMN_STATUS).toString(); 451 return key(Messages.GUI_COMPARE_ADDED_0).equals(type); 452 } 453 }; 454 addedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_ADDED_0)); 455 addedAction.setIconPath("tools/ex_history/buttons/added.png"); 456 addedAction.setEnabled(true); 457 iconCol.addDirectAction(addedAction); 458 459 // add state error action 460 CmsListDirectAction removedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_REMOVED) { 461 462 @Override 463 public boolean isVisible() { 464 465 String type = getItem().get(LIST_COLUMN_STATUS).toString(); 466 return key(Messages.GUI_COMPARE_REMOVED_0).equals(type); 467 } 468 }; 469 removedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_REMOVED_0)); 470 removedAction.setIconPath("tools/ex_history/buttons/removed.png"); 471 removedAction.setEnabled(true); 472 iconCol.addDirectAction(removedAction); 473 474 // add state error action 475 CmsListDirectAction changedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_CHANGED) { 476 477 @Override 478 public boolean isVisible() { 479 480 String type = getItem().get(LIST_COLUMN_STATUS).toString(); 481 return key(Messages.GUI_COMPARE_CHANGED_0).equals(type); 482 } 483 }; 484 changedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_CHANGED_0)); 485 changedAction.setIconPath("tools/ex_history/buttons/changed.png"); 486 changedAction.setEnabled(true); 487 iconCol.addDirectAction(changedAction); 488 489 // add state error action 490 CmsListDirectAction unchangedAction = new CmsListDirectAction(CmsResourceComparison.TYPE_UNCHANGED) { 491 492 @Override 493 public boolean isVisible() { 494 495 String type = getItem().get(LIST_COLUMN_STATUS).toString(); 496 return key(Messages.GUI_COMPARE_UNCHANGED_0).equals(type); 497 } 498 }; 499 unchangedAction.setName(Messages.get().container(Messages.GUI_COMPARE_ELEM_UNCHANGED_0)); 500 unchangedAction.setIconPath("tools/ex_history/buttons/unchanged.png"); 501 unchangedAction.setEnabled(true); 502 iconCol.addDirectAction(unchangedAction); 503 metadata.addColumn(iconCol); 504 iconCol.setPrintable(false); 505 506 // add column for type 507 CmsListColumnDefinition statusCol = new CmsListColumnDefinition(LIST_COLUMN_STATUS); 508 statusCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_STATUS_0)); 509 statusCol.setWidth("10%"); 510 511 CmsListDefaultAction statusColAction = new CmsListDefaultAction(LIST_ACTION_STATUS); 512 statusColAction.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_STATUS_0)); 513 statusColAction.setEnabled(true); 514 statusCol.addDefaultAction(statusColAction); 515 metadata.addColumn(statusCol); 516 statusCol.setPrintable(true); 517 518 // add column for locale 519 CmsListColumnDefinition localeCol = new CmsListColumnDefinition(LIST_COLUMN_LOCALE); 520 localeCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_LOCALE_0)); 521 localeCol.setWidth("10%"); 522 metadata.addColumn(localeCol); 523 localeCol.setPrintable(true); 524 525 // add column for element name 526 CmsListColumnDefinition attCol = new CmsListColumnDefinition(LIST_COLUMN_ATTRIBUTE); 527 attCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_NAME_0)); 528 attCol.setWidth("10%"); 529 metadata.addColumn(attCol); 530 attCol.setPrintable(true); 531 532 CmsListColumnDefinition typeCol = new CmsListColumnDefinition(LIST_COLUMN_TYPE); 533 typeCol.setName(Messages.get().container(Messages.GUI_COMPARE_COLS_TYPE_0)); 534 typeCol.setWidth("10%"); 535 // display column only if xml content is compared 536 typeCol.setVisible(m_xmlContentComparisonMode); 537 metadata.addColumn(typeCol); 538 typeCol.setPrintable(true); 539 540 // add column for first value 541 CmsListColumnDefinition version1Col = new CmsListColumnDefinition(LIST_COLUMN_VERSION_1); 542 version1Col.setName( 543 Messages.get().container( 544 Messages.GUI_COMPARE_VERSION_1, 545 CmsHistoryListUtil.getDisplayVersion(getParamVersion1(), getLocale()))); 546 version1Col.setWidth("35%"); 547 version1Col.setSorteable(false); 548 metadata.addColumn(version1Col); 549 version1Col.setPrintable(true); 550 551 // add column for second value 552 CmsListColumnDefinition version2Col = new CmsListColumnDefinition(LIST_COLUMN_VERSION_2); 553 version2Col.setName( 554 Messages.get().container( 555 Messages.GUI_COMPARE_VERSION_1, 556 CmsHistoryListUtil.getDisplayVersion(getParamVersion2(), getLocale()))); 557 version2Col.setWidth("35%"); 558 version2Col.setSorteable(false); 559 metadata.addColumn(version2Col); 560 version2Col.setPrintable(true); 561 } 562 563 /** 564 * @see org.opencms.workplace.list.A_CmsListDialog#setIndependentActions(org.opencms.workplace.list.CmsListMetadata) 565 */ 566 @Override 567 protected void setIndependentActions(CmsListMetadata metadata) { 568 569 CmsListIndependentAction compare = new CmsListIndependentAction(LIST_IACTION_COMPARE_ALL); 570 compare.setName(Messages.get().container(Messages.GUI_COMPARE_COMPARE_ALL_0)); 571 compare.setIconPath("tools/ex_history/buttons/compare.png"); 572 compare.setEnabled(true); 573 metadata.addIndependentAction(compare); 574 575 // add event details 576 CmsListItemDetails eventDetails = new CmsListItemDetails(LIST_IACTION_SHOW); 577 eventDetails.setVisible(false); 578 eventDetails.setShowActionName(Messages.get().container(Messages.GUI_COMPARE_SHOW_ALL_ELEMENTS_0)); 579 eventDetails.setHideActionName(Messages.get().container(Messages.GUI_COMPARE_HIDE_IDENTICAL_ELEMENTS_0)); 580 metadata.addItemDetails(eventDetails); 581 } 582 583 /** 584 * @see org.opencms.workplace.list.A_CmsListDialog#setMultiActions(org.opencms.workplace.list.CmsListMetadata) 585 */ 586 @Override 587 protected void setMultiActions(CmsListMetadata metadata) { 588 589 // no-op 590 } 591}