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.commons; 029 030import org.opencms.configuration.CmsParameterConfiguration; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.jsp.CmsJspActionElement; 035import org.opencms.lock.CmsLockFilter; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.relations.CmsRelation; 039import org.opencms.relations.CmsRelationFilter; 040import org.opencms.security.CmsPermissionSet; 041import org.opencms.util.CmsStringUtil; 042import org.opencms.workplace.CmsDialog; 043import org.opencms.workplace.CmsDialogSelector; 044import org.opencms.workplace.CmsMultiDialog; 045import org.opencms.workplace.CmsWorkplace; 046import org.opencms.workplace.CmsWorkplaceSettings; 047import org.opencms.workplace.I_CmsDialogHandler; 048import org.opencms.workplace.list.CmsListExplorerColumn; 049 050import java.io.IOException; 051import java.util.ArrayList; 052import java.util.Collections; 053import java.util.HashMap; 054import java.util.HashSet; 055import java.util.Iterator; 056import java.util.List; 057import java.util.Map; 058import java.util.Set; 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.JspException; 066import jakarta.servlet.jsp.PageContext; 067 068/** 069 * Creates the dialogs for locking, unlocking or steal lock operations on a resource.<p> 070 * 071 * The following files use this class: 072 * <ul> 073 * <li>/commons/lock_standard.jsp 074 * <li>/commons/lockchange_standard.jsp 075 * <li>/commons/unlock_standard.jsp 076 * <li>/commons/locks.jsp 077 * </ul> 078 * <p> 079 * 080 * @since 6.0.0 081 */ 082public class CmsLock extends CmsMultiDialog implements I_CmsDialogHandler { 083 084 /** Value for the action: confirmed. */ 085 public static final int ACTION_SUBMIT_NOCONFIRMATION = 200; 086 087 /** Request parameter value for the action: submit form without user interaction. */ 088 public static final String DIALOG_SUBMIT_NOCONFIRMATION = "submitnoconfirmation"; 089 090 /** The dialog type: lock a resource. */ 091 public static final String DIALOG_TYPE_LOCK = "lock"; 092 093 /** The dialog type: Steal a lock. */ 094 public static final String DIALOG_TYPE_LOCKCHANGE = "lockchange"; 095 096 /** The dialog type: locked subresources. */ 097 public static final String DIALOG_TYPE_LOCKS = "locks"; 098 099 /** The dialog type: unlock a resource. */ 100 public static final String DIALOG_TYPE_UNLOCK = "unlock"; 101 102 /** Request parameter name for the 'include unpublished related resources' flag. */ 103 public static final String PARAM_INCLUDERELATED = "includerelated"; 104 105 /** Request parameter name for the project id. */ 106 public static final String PARAM_PROJECT_ID = "projectid"; 107 108 /** Request parameter name for the publishsiblings parameter. */ 109 public static final String PARAM_PUBLISHSIBLINGS = "publishsiblings"; 110 111 /** Request parameter name for the 'show own locked resources' flag. */ 112 public static final String PARAM_SHOWOWNLOCKS = "showownlocks"; 113 114 /** Request parameter name for the source dialog uri. */ 115 public static final String PARAM_SOURCE_DIALOG = "sourcedialog"; 116 117 /** Request parameter name for the subresources parameter. */ 118 public static final String PARAM_SUBRESOURCES = "subresources"; 119 120 /** Type of the operation which is performed: lock resource. */ 121 public static final int TYPE_LOCK = 1; 122 123 /** Type of the operation which is performed: steal a lock. */ 124 public static final int TYPE_LOCKCHANGE = 2; 125 126 /** Type of the operation which is performed: locked subresources. */ 127 public static final int TYPE_LOCKS = 4; 128 129 /** Type of the operation which is performed: unlock resource. */ 130 public static final int TYPE_UNLOCK = 3; 131 132 /** The lock dialog URI. */ 133 public static final String URI_LOCK_DIALOG = PATH_DIALOGS + "lock_standard.jsp"; 134 135 /** The steal lock dialog URI. */ 136 public static final String URI_LOCKCHANGE_DIALOG = PATH_DIALOGS + "lockchange_standard.jsp"; 137 138 /** The locks dialog URI. */ 139 public static final String URI_LOCKS_DIALOG = PATH_DIALOGS + "locks.jsp"; 140 141 /** The unlock dialog URI. */ 142 public static final String URI_UNLOCK_DIALOG = PATH_DIALOGS + "unlock_standard.jsp"; 143 144 /** The log object for this class. */ 145 private static final Log LOG = CmsLog.getLog(CmsLock.class); 146 147 /** the filter to get all blocking locks. */ 148 private CmsLockFilter m_blockingFilter; 149 150 /** the nunmber of blocking locked resources. */ 151 private int m_blockingLocks = -1; 152 153 /** The list of locked resources. */ 154 private List<String> m_lockedResources; 155 156 /** the filter to get all non blocking locks. */ 157 private CmsLockFilter m_nonBlockingFilter; 158 159 /** The 'include unpublished related resources' parameter value. */ 160 private String m_paramIncluderelated; 161 162 /** The project id parameter value. */ 163 private String m_paramProjectid; 164 165 /** The 'show own locked resources' parameter value. */ 166 private String m_paramShowownlocks; 167 168 /** 169 * Default constructor needed for dialog handler implementation.<p> 170 */ 171 public CmsLock() { 172 173 super(null); 174 } 175 176 /** 177 * Public constructor.<p> 178 * 179 * @param jsp an initialized JSP action element 180 */ 181 public CmsLock(CmsJspActionElement jsp) { 182 183 super(jsp); 184 } 185 186 /** 187 * Public constructor with JSP variables.<p> 188 * 189 * @param context the JSP page context 190 * @param req the JSP request 191 * @param res the JSP response 192 */ 193 public CmsLock(PageContext context, HttpServletRequest req, HttpServletResponse res) { 194 195 this(new CmsJspActionElement(context, req, res)); 196 } 197 198 /** 199 * Returns the html code to build the lock dialog.<p> 200 * 201 * @return html code 202 * 203 * @throws CmsException if something goes wrong 204 */ 205 public static String buildLockDialog(CmsDialog dialog) throws CmsException { 206 207 return buildLockDialog(dialog, null, null, 2000, false); 208 } 209 210 /** 211 * Returns the html code to build the lock dialog.<p> 212 * 213 * @param nonBlockingFilter the filter to get all non blocking locks 214 * @param blockingFilter the filter to get all blocking locks 215 * @param hiddenTimeout the maximal number of milliseconds the dialog will be hidden 216 * @param includeRelated indicates if the report should include related resources 217 * 218 * @return html code 219 * 220 * @throws CmsException if something goes wrong 221 */ 222 public static String buildLockDialog( 223 CmsDialog dialog, 224 CmsLockFilter nonBlockingFilter, 225 CmsLockFilter blockingFilter, 226 int hiddenTimeout, 227 boolean includeRelated) 228 throws CmsException { 229 230 dialog.setParamAction(CmsDialog.DIALOG_LOCKS_CONFIRMED); 231 CmsLock lockwp = new CmsLock(dialog.getJsp()); 232 lockwp.setBlockingFilter(blockingFilter); 233 lockwp.setNonBlockingFilter(nonBlockingFilter); 234 235 StringBuffer html = new StringBuffer(512); 236 html.append(dialog.htmlStart("help.explorer.contextmenu.lock")); 237 html.append(lockwp.buildIncludeJs()); 238 html.append(dialog.buildLockConfirmationMessageJS()); 239 html.append(dialog.bodyStart("dialog")); 240 html.append("<div id='lock-body-id' class='hide'>\n"); 241 html.append(dialog.dialogStart()); 242 html.append(dialog.dialogContentStart(dialog.getParamTitle())); 243 html.append(dialog.buildLockHeaderBox()); 244 html.append(dialog.dialogSpacer()); 245 html.append("<form name='main' action='"); 246 html.append(dialog.getDialogUri()); 247 html.append("' method='post' class='nomargin' onsubmit=\"return submitAction('"); 248 html.append(CmsDialog.DIALOG_OK); 249 html.append("', null, 'main');\">\n"); 250 html.append(dialog.paramsAsHidden()); 251 html.append("<input type='hidden' name='"); 252 html.append(CmsDialog.PARAM_FRAMENAME); 253 html.append("' value=''>\n"); 254 html.append( 255 dialog.buildAjaxResultContainer( 256 dialog.key(org.opencms.workplace.commons.Messages.GUI_LOCK_RESOURCES_TITLE_0))); 257 html.append("<div id='conf-msg'></div>\n"); 258 html.append(dialog.buildLockAdditionalOptions()); 259 html.append(dialog.dialogContentEnd()); 260 html.append(dialog.dialogLockButtons()); 261 html.append("</form>\n"); 262 html.append(dialog.dialogEnd()); 263 html.append("</div>\n"); 264 html.append(dialog.bodyEnd()); 265 html.append(lockwp.buildLockRequest(hiddenTimeout, includeRelated)); 266 html.append(dialog.htmlEnd()); 267 return html.toString(); 268 } 269 270 /** 271 * Determines if the resource should be locked, unlocked or if the lock should be stolen.<p> 272 * 273 * @param cms the CmsObject 274 * @return the dialog action: lock, change lock (steal) or unlock 275 */ 276 public static int getDialogAction(CmsObject cms) { 277 278 String fileName = CmsResource.getName(cms.getRequestContext().getUri()); 279 if (fileName == null) { 280 // file name could not be determined, return "see locked subresources" action 281 return TYPE_LOCKS; 282 } else if (fileName.equalsIgnoreCase("lock.jsp")) { 283 // a "lock" action is requested 284 return TYPE_LOCK; 285 } else if (fileName.indexOf("change") != -1) { 286 // a "steal lock" action is requested 287 return TYPE_LOCKCHANGE; 288 } else if (fileName.indexOf("unlock") != -1) { 289 // an "unlock" action is requested 290 return TYPE_UNLOCK; 291 } else { 292 // an "see locked subresources" action is requested 293 return TYPE_LOCKS; 294 } 295 } 296 297 /** 298 * Performs the lock/unlock operation, will be called by the JSP page.<p> 299 * 300 * @throws JspException if problems including sub-elements occur 301 */ 302 public void actionToggleLock() throws JspException { 303 304 // save initialized instance of this class in request attribute for included sub-elements 305 getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this); 306 307 try { 308 if (performDialogOperation()) { 309 // if no exception is caused and "true" is returned the lock/unlock operation was successful 310 actionCloseDialog(); 311 } else { 312 // "false" returned, display "please wait" screen 313 getJsp().include(FILE_DIALOG_SCREEN_WAIT); 314 } 315 } catch (Throwable e) { 316 // exception occurred, show error dialog 317 includeErrorpage(this, e); 318 } 319 } 320 321 /** 322 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String) 323 */ 324 @Override 325 public void addConfigurationParameter(String paramName, String paramValue) { 326 327 // not implemented yet 328 329 } 330 331 /** 332 * Returns the html code to build the dialogs default confirmation message js.<p> 333 * 334 * @return html code 335 */ 336 public String buildDefaultConfirmationJS() { 337 338 StringBuffer html = new StringBuffer(512); 339 html.append("<script ><!--\n"); 340 html.append("function setConfirmationMessage(locks, blockinglocks) {\n"); 341 html.append("\tvar confMsg = document.getElementById('conf-msg');\n"); 342 html.append("\tif (locks > -1) {\n"); 343 if (!getSettings().getUserSettings().getDialogShowLock() 344 && (CmsLock.getDialogAction(getCms()) != CmsLock.TYPE_LOCKS)) { 345 // auto commit if lock dialog disabled 346 html.append("\t\tif (blockinglocks == 0) {\n"); 347 html.append("\t\t\tsubmitAction('"); 348 html.append(CmsDialog.DIALOG_OK); 349 html.append("', null, 'main');\n"); 350 html.append("\t\t\tdocument.forms['main'].submit();\n"); 351 html.append("\t\t\treturn;\n"); 352 html.append("\t\t}\n"); 353 } 354 html.append("\t\tdocument.getElementById('lock-body-id').className = '';\n"); 355 html.append("\t\tif (locks > '0') {\n"); 356 html.append("\t\t\tshowAjaxReportContent();\n"); 357 html.append("\t\t\tconfMsg.innerHTML = '"); 358 html.append(getConfirmationMessage(false)); 359 html.append("';\n"); 360 html.append("\t\t} else {\n"); 361 html.append("\t\t\tshowAjaxOk();\n"); 362 html.append("\t\t\tconfMsg.innerHTML = '"); 363 html.append(getConfirmationMessage(true)); 364 html.append("';\n"); 365 html.append("\t\t}\n"); 366 html.append("\t} else {\n"); 367 html.append("\t\tconfMsg.innerHTML = '"); 368 html.append(key(org.opencms.workplace.Messages.GUI_AJAX_REPORT_WAIT_0)); 369 html.append("';\n"); 370 html.append("\t}\n"); 371 html.append("}\n"); 372 html.append("// -->\n"); 373 html.append("</script>\n"); 374 return html.toString(); 375 } 376 377 /** 378 * Returns the html code to include the needed js code.<p> 379 * 380 * @return html code 381 */ 382 public String buildIncludeJs() { 383 384 StringBuffer html = new StringBuffer(512); 385 html.append("<script src='"); 386 html.append(CmsWorkplace.getSkinUri()); 387 html.append("commons/ajax.js'></script>\n"); 388 html.append("<script src='"); 389 html.append(CmsWorkplace.getSkinUri()); 390 html.append("editors/xmlcontent/help.js'></script>\n"); 391 html.append("<script src='"); 392 html.append(CmsWorkplace.getSkinUri()); 393 html.append("admin/javascript/general.js'></script>\n"); 394 html.append("<script src='"); 395 html.append(CmsWorkplace.getSkinUri()); 396 html.append("admin/javascript/list.js'></script>\n"); 397 html.append("<script ><!--\n"); 398 html.append("function showAjaxOk() {\n"); 399 html.append("\tdocument.getElementById('ajaxreport-img').src = '"); 400 html.append(CmsWorkplace.getSkinUri()); 401 html.append("commons/ok.png';\n"); 402 html.append("\tdocument.getElementById('ajaxreport-txt').innerHTML = '"); 403 html.append(key(Messages.GUI_OPERATION_NO_LOCKS_0)); 404 html.append("';\n"); 405 html.append("}\n"); 406 html.append("var ajaxReportContent = '';\n"); 407 html.append("var ajaxWaitMessage = '"); 408 html.append(CmsStringUtil.escapeJavaScript(buildAjaxWaitMessage())); 409 html.append("';\n"); 410 html.append("function showAjaxReportContent() {\n"); 411 html.append("\tif (ajaxReportContent != '') {\n"); 412 html.append("\t\tdocument.getElementById('ajaxreport').innerHTML = ajaxReportContent;\n"); 413 html.append("\t}\n"); 414 html.append("}\n"); 415 html.append("function doReportUpdate(msg, state) {\n"); 416 html.append("\tvar img = state + '.png';\n"); 417 html.append("\tvar txt = '';\n"); 418 html.append("\tvar locks = -1;\n"); 419 html.append("\tvar blockinglocks = -1;\n"); 420 html.append("\tvar elem = document.getElementById('ajaxreport');\n"); 421 html.append("\tif (state != 'ok') {\n"); 422 html.append("\t\tif (state != 'wait') {\n"); 423 html.append("\t\t\tdocument.getElementById('lock-body-id').className = '';\n"); 424 html.append("\t\t}\n"); 425 html.append("\t\tvar img = state + '.png';\n"); 426 html.append("\t\tvar txt = msg;\n"); 427 html.append("\t\tif (state == 'fatal') {\n"); 428 html.append("\t\t\timg = 'error.png';\n"); 429 html.append("\t\t\ttxt = '"); 430 html.append(key(org.opencms.workplace.Messages.GUI_AJAX_REPORT_GIVEUP_0)); 431 html.append("';\n"); 432 html.append("\t\t} else if (state == 'wait') {\n"); 433 html.append("\t\t\timg = 'wait.gif';\n"); 434 html.append("\t\t\ttxt = '"); 435 html.append(key(org.opencms.workplace.Messages.GUI_AJAX_REPORT_WAIT_0)); 436 html.append("'\n"); 437 html.append("\t\t} else if (state == 'error') {\n"); 438 html.append("\t\t\ttxt = '"); 439 html.append(key(org.opencms.workplace.Messages.GUI_AJAX_REPORT_ERROR_0)); 440 html.append("' + msg;\n"); 441 html.append("\t\t}\n"); 442 html.append("\t\tdocument.getElementById('ajaxreport-img').src = '"); 443 html.append(CmsWorkplace.getSkinUri()); 444 html.append("commons/' + img;\n"); 445 html.append("\t\tdocument.getElementById('ajaxreport-txt').innerHTML = txt;\n"); 446 html.append("\t} else {\n"); 447 html.append("\t\telem.innerHTML = elem.innerHTML + msg.substring(0, 120);\n"); 448 html.append("\t\tajaxReportContent = msg;\n"); 449 html.append("\t}\n"); 450 html.append("\tif (txt != '') {\n"); 451 html.append("\t}\n"); 452 html.append("\tif (state == 'ok') {\n"); 453 html.append("\t\tlocks = document.forms['main'].locks.value;\n"); 454 html.append("\t\tblockinglocks = document.forms['main'].blockinglocks.value;\n"); 455 html.append("\t}\n"); 456 html.append("\tsetConfirmationMessage(locks, blockinglocks);\n"); 457 html.append("}\n"); 458 html.append("// -->\n"); 459 html.append("</script>\n"); 460 return html.toString(); 461 } 462 463 /** 464 * Returns the html code to build the lock request.<p> 465 * 466 * @return html code 467 */ 468 public String buildLockRequest() { 469 470 return buildLockRequest(0, false); 471 } 472 473 /** 474 * Returns the html code to build the lock request.<p> 475 * 476 * @param hiddenTimeout the maximal number of millis the dialog will be hidden 477 * @param includeRelated indicates if the report should include related resources 478 * 479 * @return html code 480 */ 481 public String buildLockRequest(int hiddenTimeout, boolean includeRelated) { 482 483 StringBuffer html = new StringBuffer(512); 484 html.append("<script ><!--\n"); 485 html.append("makeRequest('"); 486 html.append(getJsp().link("/system/workplace/commons/report-locks.jsp")); 487 html.append("', '"); 488 html.append(CmsWorkplace.PARAM_RESOURCELIST); 489 html.append("="); 490 html.append(getParamResourcelist()); 491 html.append("&"); 492 html.append(CmsDialog.PARAM_RESOURCE); 493 html.append("="); 494 html.append(getParamResource()); 495 html.append("&"); 496 html.append(CmsLock.PARAM_INCLUDERELATED); 497 html.append("="); 498 html.append(includeRelated); 499 html.append("', 'doReportUpdate');\n"); 500 html.append("function showLockDialog() {\n"); 501 html.append("\tdocument.getElementById('lock-body-id').className = '';\n"); 502 html.append("}\n"); 503 html.append("setTimeout('showLockDialog()', " + hiddenTimeout + ");\n"); 504 html.append("// -->\n"); 505 html.append("</script>\n"); 506 return html.toString(); 507 } 508 509 /** 510 * Returns the report of all locked subresources.<p> 511 * 512 * @return the report of all locked subresources 513 * 514 * @throws JspException if dialog actions fail 515 * @throws IOException in case of errros forwarding to the required result page 516 * @throws ServletException in case of errros forwarding to the required result page 517 */ 518 public String buildReport() throws JspException, ServletException, IOException { 519 520 List<String> lockedResources; 521 if (Boolean.valueOf(getParamShowownlocks()).booleanValue()) { 522 lockedResources = getLockedResources(); 523 } else { 524 lockedResources = new ArrayList<String>(getBlockingLockedResources()); 525 } 526 Collections.sort(lockedResources); 527 Map<String, String> lockParams = new HashMap<String, String>(); 528 if (getParamResource() != null) { 529 lockParams.put(PARAM_RESOURCE, getParamResource()); 530 } 531 if (getParamResourcelist() != null) { 532 lockParams.put(PARAM_RESOURCELIST, getParamResourcelist()); 533 } 534 if (getParamShowownlocks() != null) { 535 lockParams.put(PARAM_SHOWOWNLOCKS, getParamShowownlocks()); 536 } 537 if (getParamIncluderelated() != null) { 538 lockParams.put(PARAM_INCLUDERELATED, getParamIncluderelated()); 539 } 540 541 CmsLockedResourcesList list = new CmsLockedResourcesList( 542 getJsp(), 543 lockedResources, 544 CmsResource.getParentFolder(getResourceList().get(0)), 545 lockParams); 546 list.actionDialog(); 547 list.getList().setBoxed(false); 548 549 StringBuffer result = new StringBuffer(512); 550 result.append("<input type='hidden' name='locks' value='"); 551 result.append(getLockedResources().size()).append("'>\n"); 552 result.append("<input type='hidden' name='blockinglocks' value='"); 553 result.append(getBlockingLockedResources().size()).append("'>\n"); 554 result.append(CmsStringUtil.padLeft("", 120 - result.length())); 555 result.append(CmsListExplorerColumn.getExplorerStyleDef()); 556 result.append("<div style='height:150px; overflow: auto;'>\n"); 557 result.append(list.getList().listHtml()); 558 result.append("</div>\n"); 559 return result.toString(); 560 } 561 562 /** 563 * Builds the necessary button row.<p> 564 * 565 * @return the button row 566 */ 567 public String dialogButtons() { 568 569 if (CmsLock.getDialogAction(getCms()) != CmsLock.TYPE_LOCKS) { 570 return dialogButtonsOkCancel(); 571 } else { 572 return dialogButtonsClose(); 573 } 574 } 575 576 /** 577 * Returns the filter to get all blocking locks.<p> 578 * 579 * @return the filter to get all blocking locks 580 */ 581 public CmsLockFilter getBlockingFilter() { 582 583 if (m_blockingFilter == null) { 584 m_blockingFilter = CmsLockFilter.FILTER_ALL; 585 m_blockingFilter = m_blockingFilter.filterNotLockableByUser(getCms().getRequestContext().getCurrentUser()); 586 } 587 return m_blockingFilter; 588 } 589 590 /** 591 * Returns locked resources that do not belong to the current user.<p> 592 * 593 * @return the locked Resources 594 */ 595 public Set<String> getBlockingLockedResources() { 596 597 Set<String> blockingResources = new HashSet<String>(); 598 Iterator<String> i = getResourceList().iterator(); 599 while (i.hasNext()) { 600 String resName = i.next(); 601 try { 602 blockingResources.addAll(getCms().getLockedResources(resName, getBlockingFilter())); 603 } catch (CmsException e) { 604 // error reading a resource, should usually never happen 605 if (LOG.isErrorEnabled()) { 606 LOG.error(e.getLocalizedMessage(), e); 607 } 608 } 609 if (Boolean.valueOf(getParamIncluderelated()).booleanValue()) { 610 addLockedRelatedResources(resName, getBlockingFilter(), blockingResources); 611 } 612 } 613 m_blockingLocks = blockingResources.size(); 614 return blockingResources; 615 } 616 617 /** 618 * Returns the number of blocking locks.<p> 619 * 620 * @return the number of blocking locks 621 */ 622 public int getBlockingLocks() { 623 624 if (m_blockingLocks == -1) { 625 // to initialize the blocking locks flag 626 getLockedResources(); 627 } 628 return m_blockingLocks; 629 } 630 631 /** 632 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration() 633 */ 634 @Override 635 public CmsParameterConfiguration getConfiguration() { 636 637 return CmsParameterConfiguration.EMPTY_PARAMETERS; 638 } 639 640 /** 641 * Returns the confirmation message.<p> 642 * 643 * @param state if <code>true</code> everything is ok 644 * 645 * @return the confirmation message 646 */ 647 public String getConfirmationMessage(boolean state) { 648 649 if (getDialogAction(getCms()) == TYPE_LOCKS) { 650 return ""; 651 } 652 if (state) { 653 if (isMultiOperation()) { 654 return key(Messages.GUI_LOCK_MULTI_LOCK_CONFIRMATION_0); 655 } else { 656 return key(Messages.GUI_LOCK_CONFIRMATION_0); 657 } 658 } 659 switch (getDialogAction(getCms())) { 660 case TYPE_LOCK: 661 if (isMultiOperation()) { 662 return key(Messages.GUI_LOCK_MULTI_INFO_LOCKEDSUBRESOURCES_0); 663 } else { 664 return key(Messages.GUI_LOCK_INFO_LOCKEDSUBRESOURCES_0); 665 } 666 case TYPE_LOCKCHANGE: 667 return key(Messages.GUI_LOCK_CHANGE_CONFIRMATION_0); 668 case TYPE_UNLOCK: 669 if (isMultiOperation()) { 670 return key(Messages.GUI_LOCK_MULTI_UNLOCK_CONFIRMATION_0); 671 } else { 672 return key(Messages.GUI_LOCK_UNLOCK_CONFIRMATION_0); 673 } 674 case TYPE_LOCKS: 675 default: 676 return ""; 677 } 678 } 679 680 /** 681 * @see org.opencms.workplace.I_CmsDialogHandler#getDialogHandler() 682 */ 683 @Override 684 public String getDialogHandler() { 685 686 return CmsDialogSelector.DIALOG_LOCK; 687 } 688 689 /** 690 * @see org.opencms.workplace.I_CmsDialogHandler#getDialogUri(java.lang.String, CmsJspActionElement) 691 */ 692 @Override 693 public String getDialogUri(String resource, CmsJspActionElement jsp) { 694 695 switch (getDialogAction(jsp.getCmsObject())) { 696 case TYPE_LOCK: 697 return URI_LOCK_DIALOG; 698 case TYPE_LOCKCHANGE: 699 return URI_LOCKCHANGE_DIALOG; 700 case TYPE_UNLOCK: 701 return URI_UNLOCK_DIALOG; 702 case TYPE_LOCKS: 703 default: 704 return URI_LOCKS_DIALOG; 705 } 706 } 707 708 /** 709 * Returns all the locked Resources.<p> 710 * 711 * @return all the locked Resources 712 */ 713 public List<String> getLockedResources() { 714 715 if (m_lockedResources == null) { 716 // collect my locked resources 717 Set<String> lockedResources = new HashSet<String>(); 718 Iterator<String> i = getResourceList().iterator(); 719 while (i.hasNext()) { 720 String resName = i.next(); 721 try { 722 lockedResources.addAll(getCms().getLockedResources(resName, getNonBlockingFilter())); 723 } catch (CmsException e) { 724 // error reading a resource, should usually never happen 725 if (LOG.isErrorEnabled()) { 726 LOG.error(e.getLocalizedMessage(getLocale()), e); 727 } 728 } 729 if (Boolean.valueOf(getParamIncluderelated()).booleanValue()) { 730 addLockedRelatedResources(resName, getNonBlockingFilter(), lockedResources); 731 } 732 } 733 // get blocking resources needs the locked resources 734 m_lockedResources = new ArrayList<String>(lockedResources); 735 lockedResources.addAll(getBlockingLockedResources()); 736 // create the locked resources list again, with the blocking locked resources 737 m_lockedResources = new ArrayList<String>(lockedResources); 738 Collections.sort(m_lockedResources); 739 } 740 return m_lockedResources; 741 } 742 743 /** 744 * Returns the filter to get all non blocking locks.<p> 745 * 746 * @return the filter to get all non blocking locks 747 */ 748 public CmsLockFilter getNonBlockingFilter() { 749 750 if (m_nonBlockingFilter == null) { 751 m_nonBlockingFilter = CmsLockFilter.FILTER_ALL; 752 m_nonBlockingFilter = m_nonBlockingFilter.filterLockableByUser( 753 getCms().getRequestContext().getCurrentUser()); 754 m_nonBlockingFilter = m_nonBlockingFilter.filterSharedExclusive(); 755 } 756 return m_nonBlockingFilter; 757 } 758 759 /** 760 * Returns the 'include unpublished related resources' parameter value.<p> 761 * 762 * @return the 'include unpublished related resources' parameter value 763 */ 764 public String getParamIncluderelated() { 765 766 return m_paramIncluderelated; 767 } 768 769 /** 770 * Returns the project id parameter value.<p> 771 * 772 * @return the project id parameter value 773 */ 774 public String getParamProjectid() { 775 776 return m_paramProjectid; 777 } 778 779 /** 780 * Returns the 'show own locked resources' parameter value.<p> 781 * 782 * @return the 'show own locked resources' parameter value 783 */ 784 public String getParamShowownlocks() { 785 786 return m_paramShowownlocks; 787 } 788 789 /** 790 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 791 */ 792 @Override 793 public void initConfiguration() { 794 795 // not implemented yet 796 797 } 798 799 /** 800 * Sets the filter to get all blocking locks.<p> 801 * 802 * @param blockingFilter the filter to set 803 */ 804 public void setBlockingFilter(CmsLockFilter blockingFilter) { 805 806 m_blockingFilter = blockingFilter; 807 // reset blocking locks count 808 m_blockingLocks = -1; 809 // reset locked resources 810 m_lockedResources = null; 811 } 812 813 /** 814 * Sets the filter to get all non blocking locks.<p> 815 * 816 * @param nonBlockingFilter the filter to set 817 */ 818 public void setNonBlockingFilter(CmsLockFilter nonBlockingFilter) { 819 820 m_nonBlockingFilter = nonBlockingFilter; 821 // reset locked resources 822 m_lockedResources = null; 823 } 824 825 /** 826 * Sets the 'include unpublished related resources' parameter value.<p> 827 * 828 * @param paramIncluderelated the 'include unpublished related resources' parameter value to set 829 */ 830 public void setParamIncluderelated(String paramIncluderelated) { 831 832 m_paramIncluderelated = paramIncluderelated; 833 } 834 835 /** 836 * Sets the project id parameter value.<p> 837 * 838 * @param projectid the project id parameter value to set 839 */ 840 public void setParamProjectid(String projectid) { 841 842 m_paramProjectid = projectid; 843 } 844 845 /** 846 * Sets the 'show own locked resources' parameter value.<p> 847 * 848 * @param paramShowownlocks the 'show own locked resources' parameter value to set 849 */ 850 public void setParamShowownlocks(String paramShowownlocks) { 851 852 m_paramShowownlocks = paramShowownlocks; 853 } 854 855 /** 856 * Determines whether to show the lock dialog depending on the users settings and the dilaog type.<p> 857 * 858 * In case of locking a folder, a confirmation dialog is needed if any sub resources are already locked.<p> 859 * 860 * @return true if dialogs should be shown, otherwise false 861 */ 862 public boolean showConfirmation() { 863 864 boolean showConfirmation = getSettings().getUserSettings().getDialogShowLock(); 865 if (DIALOG_TYPE_LOCK.equals(getParamDialogtype())) { 866 // in case of locking resources, check if there are locked sub resources in the selected folder(s) 867 showConfirmation = showConfirmation || (getLockedResources().size() > 0); 868 } 869 return showConfirmation; 870 } 871 872 /** 873 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, jakarta.servlet.http.HttpServletRequest) 874 */ 875 @Override 876 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 877 878 // fill the parameter values in the get/set methods 879 fillParamValues(request); 880 881 // set the action for the JSP switch 882 if (DIALOG_CONFIRMED.equals(getParamAction())) { 883 setAction(ACTION_CONFIRMED); 884 } else if (DIALOG_CANCEL.equals(getParamAction())) { 885 setAction(ACTION_CANCEL); 886 } else if (DIALOG_WAIT.equals(getParamAction())) { 887 setAction(ACTION_WAIT); 888 } else { 889 switch (getDialogAction(getCms())) { 890 case TYPE_LOCK: 891 setDialogTitle(Messages.GUI_LOCK_RESOURCE_1, Messages.GUI_LOCK_MULTI_LOCK_2); 892 setParamDialogtype(DIALOG_TYPE_LOCK); 893 // check the required permissions to lock/unlock 894 if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) { 895 // no write permissions for the resource, set cancel action to close dialog 896 setAction(ACTION_CANCEL); 897 return; 898 } 899 break; 900 case TYPE_LOCKCHANGE: 901 setDialogTitle(Messages.GUI_LOCK_STEAL_1, Messages.GUI_LOCK_MULTI_STEAL_2); 902 setParamDialogtype(DIALOG_TYPE_UNLOCK); 903 break; 904 case TYPE_UNLOCK: 905 setDialogTitle(Messages.GUI_LOCK_UNLOCK_1, Messages.GUI_LOCK_MULTI_UNLOCK_2); 906 setParamDialogtype(DIALOG_TYPE_UNLOCK); 907 break; 908 case TYPE_LOCKS: 909 default: 910 setDialogTitle(Messages.GUI_LOCK_LOCKS_1, Messages.GUI_LOCK_MULTI_LOCKS_2); 911 setParamDialogtype(DIALOG_TYPE_LOCKS); 912 } 913 // set action depending on user settings 914 if ((getDialogAction(getCms()) == TYPE_LOCKS) || showConfirmation()) { 915 // show confirmation dialog 916 setAction(ACTION_DEFAULT); 917 } else { 918 // lock/unlock resource without confirmation 919 setAction(ACTION_SUBMIT_NOCONFIRMATION); 920 } 921 } 922 923 if ((getParamResource() == null) && (getParamResourcelist() == null)) { 924 // this if in case of publish project 925 setParamResource("/"); 926 } 927 928 } 929 930 /** 931 * Performs the lock/unlock/steal lock operation.<p> 932 * 933 * @return true, if the operation was performed, otherwise false 934 * @throws CmsException if operation is not successful 935 */ 936 @Override 937 protected boolean performDialogOperation() throws CmsException { 938 939 //on multi resource operation display "please wait" screen 940 if (isMultiOperation() && !DIALOG_WAIT.equals(getParamAction())) { 941 return false; 942 } 943 // determine action to perform (lock, unlock, change lock) 944 int dialogAction = getDialogAction(getCms()); 945 946 // now perform the operation on the resource(s) 947 Iterator<String> i = getResourceList().iterator(); 948 while (i.hasNext()) { 949 String resName = i.next(); 950 try { 951 performSingleResourceOperation(resName, dialogAction); 952 } catch (CmsException e) { 953 // collect exceptions to create a detailed output 954 addMultiOperationException(e); 955 } 956 } 957 // generate the error message for exception 958 String message; 959 if (dialogAction == TYPE_LOCK) { 960 message = Messages.ERR_LOCK_MULTI_0; 961 } else { 962 message = Messages.ERR_UNLOCK_MULTI_0; 963 } 964 checkMultiOperationException(Messages.get(), message); 965 966 return true; 967 } 968 969 /** 970 * Performs the lock state operation on a single resource.<p> 971 * 972 * @param resourceName the resource name to perform the operation on 973 * @param dialogAction the lock action: lock, unlock or change lock 974 * @throws CmsException if the operation fails 975 */ 976 protected void performSingleResourceOperation(String resourceName, int dialogAction) throws CmsException { 977 978 // store original name to use for lock action 979 String originalResourceName = resourceName; 980 CmsResource res = getCms().readResource(resourceName, CmsResourceFilter.ALL); 981 if (res.isFolder() && !resourceName.endsWith("/")) { 982 resourceName += "/"; 983 } 984 org.opencms.lock.CmsLock lock = getCms().getLock(res); 985 // perform action depending on dialog uri 986 switch (dialogAction) { 987 case TYPE_LOCKCHANGE: 988 case TYPE_LOCK: 989 if (lock.isNullLock()) { 990 getCms().lockResource(originalResourceName); 991 } else if (!lock.isDirectlyOwnedInProjectBy(getCms())) { 992 getCms().changeLock(resourceName); 993 } 994 break; 995 case TYPE_UNLOCK: 996 default: 997 if (lock.isNullLock()) { 998 break; 999 } 1000 if (lock.isOwnedBy(getCms().getRequestContext().getCurrentUser())) { 1001 getCms().unlockResource(resourceName); 1002 } 1003 } 1004 } 1005 1006 /** 1007 * Returns a set of locked unpublished related resources.<p> 1008 * 1009 * @param resName the resource to check the related resources for 1010 * @param filter the lock filter to use 1011 * @param lockedResources a set of site relative paths, of locked resources to exclude 1012 */ 1013 private void addLockedRelatedResources(String resName, CmsLockFilter filter, Set<String> lockedResources) { 1014 1015 try { 1016 // get and iterate over all related resources 1017 Iterator<CmsRelation> itRelations = getCms().getRelationsForResource( 1018 resName, 1019 CmsRelationFilter.TARGETS.filterStrong().filterIncludeChildren()).iterator(); 1020 while (itRelations.hasNext()) { 1021 CmsRelation relation = itRelations.next(); 1022 CmsResource target = null; 1023 try { 1024 target = relation.getTarget(getCms(), CmsResourceFilter.ALL); 1025 } catch (CmsException e) { 1026 // error reading a resource, should usually never happen 1027 if (LOG.isDebugEnabled()) { 1028 LOG.debug(e.getLocalizedMessage(getLocale()), e); 1029 } 1030 continue; 1031 } 1032 // we are interested just in unpublished resources 1033 if (target.getState().isUnchanged()) { 1034 continue; 1035 } 1036 String targetName = getCms().getSitePath(target); 1037 // if already selected 1038 if (lockedResources.contains(targetName) || lockedResources.contains(targetName + "*")) { 1039 continue; 1040 } 1041 if (m_lockedResources != null) { 1042 if (m_lockedResources.contains(targetName) || m_lockedResources.contains(targetName + "*")) { 1043 continue; 1044 } 1045 } 1046 try { 1047 org.opencms.lock.CmsLock lock = getCms().getLock(targetName); 1048 if (!lock.isUnlocked() && filter.match("/", lock)) { 1049 // just add resources that may come in question 1050 lockedResources.add(targetName + "*"); 1051 } 1052 } catch (CmsException e) { 1053 // error reading a lock, should usually never happen 1054 if (LOG.isErrorEnabled()) { 1055 LOG.error(e.getLocalizedMessage(getLocale()), e); 1056 } 1057 continue; 1058 } 1059 } 1060 } catch (CmsException e) { 1061 // error reading the relations, should usually never happen 1062 if (LOG.isErrorEnabled()) { 1063 LOG.error(e.getLocalizedMessage(getLocale()), e); 1064 } 1065 } 1066 } 1067}