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.commons; 029 030import org.opencms.file.CmsResource; 031import org.opencms.file.CmsResource.CmsResourceCopyMode; 032import org.opencms.file.CmsResourceFilter; 033import org.opencms.file.CmsVfsException; 034import org.opencms.file.CmsVfsResourceAlreadyExistsException; 035import org.opencms.file.CmsVfsResourceNotFoundException; 036import org.opencms.jsp.CmsJspActionElement; 037import org.opencms.lock.CmsLockException; 038import org.opencms.main.CmsException; 039import org.opencms.main.CmsLog; 040import org.opencms.main.OpenCms; 041import org.opencms.security.CmsPermissionSet; 042import org.opencms.staticexport.CmsLinkManager; 043import org.opencms.util.CmsStringUtil; 044import org.opencms.workplace.CmsMultiDialog; 045import org.opencms.workplace.CmsWorkplaceSettings; 046 047import java.util.ArrayList; 048import java.util.Iterator; 049import java.util.List; 050 051import javax.servlet.http.HttpServletRequest; 052import javax.servlet.http.HttpServletResponse; 053import javax.servlet.jsp.JspException; 054import javax.servlet.jsp.PageContext; 055 056import org.apache.commons.logging.Log; 057 058/** 059 * Provides methods for the copy resources dialog.<p> 060 * 061 * The following files use this class: 062 * <ul> 063 * <li>/commons/copy.jsp 064 * </ul> 065 * <p> 066 * 067 * @since 6.0.0 068 */ 069public class CmsCopy extends CmsMultiDialog { 070 071 /** Value for the action: copy the resource. */ 072 public static final int ACTION_COPY = 100; 073 074 /** The dialog type. */ 075 public static final String DIALOG_TYPE = "copy"; 076 077 /** Request parameter name for the keep rights flag. */ 078 public static final String PARAM_KEEPRIGHTS = "keeprights"; 079 080 /** Request parameter name for the overwrite flag. */ 081 public static final String PARAM_OVERWRITE = "overwrite"; 082 083 /** The log object for this class. */ 084 private static final Log LOG = CmsLog.getLog(CmsCopy.class); 085 086 /** A parameter of this dialog. */ 087 private String m_paramCopymode; 088 089 /** A parameter of this dialog. */ 090 private String m_paramKeeprights; 091 092 /** A parameter of this dialog. */ 093 private String m_paramOverwrite; 094 095 /** A parameter of this dialog. */ 096 private String m_paramTarget; 097 098 /** 099 * Public constructor with JSP action element.<p> 100 * 101 * @param jsp an initialized JSP action element 102 */ 103 public CmsCopy(CmsJspActionElement jsp) { 104 105 super(jsp); 106 } 107 108 /** 109 * Public constructor with JSP variables.<p> 110 * 111 * @param context the JSP page context 112 * @param req the JSP request 113 * @param res the JSP response 114 */ 115 public CmsCopy(PageContext context, HttpServletRequest req, HttpServletResponse res) { 116 117 this(new CmsJspActionElement(context, req, res)); 118 } 119 120 /** 121 * Performs the copy action, will be called by the JSP page.<p> 122 * 123 * @throws JspException if problems including sub-elements occur 124 */ 125 public void actionCopy() throws JspException { 126 127 // save initialized instance of this class in request attribute for included sub-elements 128 getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this); 129 CmsResource resource = null; 130 try { 131 boolean isFolder = false; 132 String source = getResourceList().get(0); 133 String target = CmsLinkManager.getAbsoluteUri(getParamTarget(), CmsResource.getParentFolder(source)); 134 if (!isMultiOperation()) { 135 resource = getCms().readResource(source, CmsResourceFilter.ALL); 136 isFolder = resource.isFolder(); 137 } else { 138 String siteRootFolder = null; 139 try { 140 // check if a site root was added to the target name 141 if (OpenCms.getSiteManager().getSiteRoot(target) != null) { 142 siteRootFolder = getCms().getRequestContext().getSiteRoot(); 143 if (siteRootFolder.endsWith("/")) { 144 siteRootFolder = siteRootFolder.substring(0, siteRootFolder.length() - 1); 145 } 146 getCms().getRequestContext().setSiteRoot("/"); 147 } 148 resource = getCms().readResource(target, CmsResourceFilter.ALL); 149 } finally { 150 if (siteRootFolder != null) { 151 getCms().getRequestContext().setSiteRoot(siteRootFolder); 152 } 153 } 154 if (!resource.isFolder()) { 155 // no folder selected for multi operation, throw exception 156 throw new CmsVfsException( 157 Messages.get().container(Messages.ERR_COPY_MULTI_TARGET_NOFOLDER_1, target)); 158 } 159 } 160 if (performDialogOperation()) { 161 // if no exception is caused and "true" is returned copy operation was successful 162 if (isMultiOperation() || isFolder) { 163 // set request attribute to reload the explorer tree view 164 List<String> folderList = new ArrayList<String>(1); 165 String targetParent = CmsResource.getParentFolder(target); 166 folderList.add(targetParent); 167 getJsp().getRequest().setAttribute(REQUEST_ATTRIBUTE_RELOADTREE, folderList); 168 } 169 actionCloseDialog(); 170 } else { 171 // "false" returned, display "please wait" screen 172 getJsp().include(FILE_DIALOG_SCREEN_WAIT); 173 } 174 } catch (Throwable e) { 175 // check if this exception requires a confirmation or error screen for single resource operations 176 if (!isMultiOperation() 177 && ((e instanceof CmsVfsResourceAlreadyExistsException) || (e instanceof CmsLockException)) 178 && (resource != null) 179 && !(resource.isFolder())) { 180 // file copy but file already exists, now check target file type 181 int targetType = -1; 182 String storedSiteRoot = null; 183 try { 184 if (OpenCms.getSiteManager().getSiteRoot(getParamTarget()) != null) { 185 storedSiteRoot = getCms().getRequestContext().getSiteRoot(); 186 getCms().getRequestContext().setSiteRoot("/"); 187 } 188 CmsResource targetRes = getCms().readResource(getParamTarget()); 189 targetType = targetRes.getTypeId(); 190 } catch (CmsException e2) { 191 // can usually be ignored 192 if (LOG.isInfoEnabled()) { 193 LOG.info(e2.getLocalizedMessage()); 194 } 195 } finally { 196 if (storedSiteRoot != null) { 197 getCms().getRequestContext().setSiteRoot(storedSiteRoot); 198 } 199 } 200 if (resource.getTypeId() == targetType) { 201 // file type of target is the same as source, show confirmation dialog 202 setParamMessage( 203 CmsStringUtil.escapeHtml(key( 204 Messages.GUI_COPY_CONFIRM_OVERWRITE_2, 205 new Object[] {getParamResource(), getParamTarget()}))); 206 getJsp().include(FILE_DIALOG_SCREEN_CONFIRM); 207 } else { 208 // file type is different, create error message 209 includeErrorpage(this, e); 210 } 211 } else { 212 // error during copy, show error dialog 213 includeErrorpage(this, e); 214 } 215 } 216 } 217 218 /** 219 * Builds the input radio buttons to select between preserving links or creating new resources when copying.<p> 220 * 221 * @return the HTML code for the radio buttons 222 */ 223 public String buildRadioCopyMode() { 224 225 StringBuffer retValue = new StringBuffer(256); 226 227 // check if the current resource is a folder for single operation 228 boolean isFolder = isOperationOnFolder(); 229 String checkedAttr = " checked=\"checked\""; 230 231 if (isMultiOperation() || isFolder) { 232 // for multi resource operations or folders, show an additional option "preserve links" 233 CmsResourceCopyMode defaultMode = getSettings().getUserSettings().getDialogCopyFolderMode(); 234 retValue.append("<input type=\"radio\" name=\"copymode\" value=\""); 235 retValue.append(CmsResource.COPY_AS_SIBLING.getMode()); 236 retValue.append("\""); 237 if (defaultMode == CmsResource.COPY_AS_SIBLING) { 238 retValue.append(checkedAttr); 239 } 240 retValue.append("> "); 241 String msgKey; 242 if (isMultiOperation()) { 243 msgKey = Messages.GUI_COPY_MULTI_CREATE_SIBLINGS_0; 244 } else { 245 msgKey = Messages.GUI_COPY_CREATE_SIBLINGS_0; 246 } 247 retValue.append(key(msgKey)); 248 retValue.append("<br>\n"); 249 retValue.append("<input type=\"radio\" name=\"copymode\" value=\""); 250 retValue.append(CmsResource.COPY_PRESERVE_SIBLING.getMode()); 251 retValue.append("\""); 252 if (defaultMode == CmsResource.COPY_PRESERVE_SIBLING) { 253 retValue.append(checkedAttr); 254 } 255 retValue.append("> "); 256 retValue.append(key(Messages.GUI_COPY_ALL_NO_SIBLINGS_0)); 257 retValue.append("<br>\n"); 258 retValue.append("<input type=\"radio\" name=\"copymode\" value=\""); 259 retValue.append(CmsResource.COPY_AS_NEW.getMode()); 260 retValue.append("\""); 261 if (defaultMode == CmsResource.COPY_AS_NEW) { 262 retValue.append(checkedAttr); 263 } 264 retValue.append("> "); 265 retValue.append(key(Messages.GUI_COPY_ALL_0)); 266 retValue.append("<br>\n"); 267 268 if (isMultiOperation()) { 269 // show overwrite option for multi resource copy 270 retValue.append(dialogSpacer()); 271 retValue.append("<input type=\"checkbox\" name=\""); 272 retValue.append(PARAM_OVERWRITE); 273 retValue.append("\" value=\"true\"> "); 274 retValue.append(key(Messages.GUI_COPY_MULTI_OVERWRITE_0)); 275 retValue.append("<br>\n"); 276 } 277 } else { 278 // for files, show copy option "copy as sibling" and "copy as new resource" 279 CmsResourceCopyMode defaultMode = getSettings().getUserSettings().getDialogCopyFileMode(); 280 retValue.append("<input type=\"radio\" name=\"copymode\" value=\""); 281 retValue.append(CmsResource.COPY_AS_SIBLING.getMode()); 282 retValue.append("\""); 283 if (defaultMode == CmsResource.COPY_AS_SIBLING) { 284 retValue.append(checkedAttr); 285 } 286 retValue.append("> "); 287 retValue.append(key(Messages.GUI_CREATE_SIBLING_0)); 288 retValue.append("<br>\n"); 289 retValue.append("<input type=\"radio\" name=\"copymode\" value=\""); 290 retValue.append(CmsResource.COPY_AS_NEW.getMode()); 291 retValue.append("\""); 292 if (defaultMode == CmsResource.COPY_AS_NEW) { 293 retValue.append(checkedAttr); 294 } 295 retValue.append("> "); 296 retValue.append(key(Messages.GUI_COPY_AS_NEW_0)); 297 retValue.append("<br>\n"); 298 } 299 300 return retValue.toString(); 301 } 302 303 /** 304 * Returns the value of the copymode parameter.<p> 305 * 306 * @return the value of the copymode parameter 307 */ 308 public String getParamCopymode() { 309 310 return m_paramCopymode; 311 } 312 313 /** 314 * Returns the value of the keeprights parameter.<p> 315 * 316 * @return the value of the keeprights parameter 317 */ 318 public String getParamKeeprights() { 319 320 return m_paramKeeprights; 321 } 322 323 /** 324 * Returns the value of the overwrite parameter.<p> 325 * 326 * @return the value of the overwrite parameter 327 */ 328 public String getParamOverwrite() { 329 330 return m_paramOverwrite; 331 } 332 333 /** 334 * Returns the value of the target parameter, 335 * or null if this parameter was not provided.<p> 336 * 337 * The target parameter selects the target name 338 * of the operation.<p> 339 * 340 * @return the value of the target parameter 341 */ 342 public String getParamTarget() { 343 344 return m_paramTarget; 345 } 346 347 /** 348 * Sets the value of the copymode parameter.<p> 349 * 350 * @param value the value of the copymode parameter 351 */ 352 public void setParamCopymode(String value) { 353 354 m_paramCopymode = value; 355 } 356 357 /** 358 * Sets the value of the "keeprights" parameter.<p> 359 * 360 * @param value the value of the "keeprights" parameter 361 */ 362 public void setParamKeeprights(String value) { 363 364 m_paramKeeprights = value; 365 } 366 367 /** 368 * Sets the value of the overwrite parameter.<p> 369 * 370 * @param paramOverwrite the value of the overwrite parameter 371 */ 372 public void setParamOverwrite(String paramOverwrite) { 373 374 m_paramOverwrite = paramOverwrite; 375 } 376 377 /** 378 * Sets the value of the target parameter.<p> 379 * 380 * @param value the value to set 381 */ 382 public void setParamTarget(String value) { 383 384 m_paramTarget = value; 385 } 386 387 /** 388 * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest) 389 */ 390 @Override 391 protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) { 392 393 // fill the parameter values in the get/set methods 394 fillParamValues(request); 395 396 // check the required permissions to copy the resource 397 if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) { 398 // no write permissions for the resource, set cancel action to close dialog 399 setParamAction(DIALOG_CANCEL); 400 } 401 402 // set the dialog type 403 setParamDialogtype(DIALOG_TYPE); 404 // set the action for the JSP switch 405 if (DIALOG_TYPE.equals(getParamAction())) { 406 setAction(ACTION_COPY); 407 } else if (DIALOG_CONFIRMED.equals(getParamAction())) { 408 setAction(ACTION_CONFIRMED); 409 } else if (DIALOG_WAIT.equals(getParamAction())) { 410 setAction(ACTION_WAIT); 411 } else if (DIALOG_CANCEL.equals(getParamAction())) { 412 setAction(ACTION_CANCEL); 413 } else { 414 setAction(ACTION_DEFAULT); 415 // build title for copy dialog 416 setDialogTitle(Messages.GUI_COPY_RESOURCE_1, Messages.GUI_COPY_MULTI_2); 417 } 418 } 419 420 /** 421 * Performs the resource copying.<p> 422 * 423 * @return true, if the resource was copied, otherwise false 424 * @throws CmsException if copying is not successful 425 */ 426 @Override 427 protected boolean performDialogOperation() throws CmsException { 428 429 // check if the current resource is a folder for single operation 430 boolean isFolder = isOperationOnFolder(); 431 432 // on folder copy display "please wait" screen, not for simple file copy 433 if ((isMultiOperation() || isFolder) && !DIALOG_WAIT.equals(getParamAction())) { 434 // return false, this will trigger the "please wait" screen 435 return false; 436 } 437 438 // get the copy mode from request parameter value 439 CmsResourceCopyMode copyMode = CmsResource.COPY_PRESERVE_SIBLING; 440 try { 441 copyMode = CmsResourceCopyMode.valueOf(Integer.parseInt(getParamCopymode())); 442 } catch (Exception e) { 443 // can usually be ignored 444 if (LOG.isInfoEnabled()) { 445 LOG.info(e.getLocalizedMessage()); 446 } 447 } 448 449 // check the overwrite options 450 boolean overwrite = Boolean.valueOf(getParamOverwrite()).booleanValue(); 451 overwrite = ((isMultiOperation() && overwrite) || DIALOG_CONFIRMED.equals(getParamAction())); 452 453 // calculate the target name 454 String target = getParamTarget(); 455 if (target == null) { 456 target = ""; 457 } 458 459 String storedSiteRoot = null; 460 try { 461 // check if a site root was added to the target name 462 String sitePrefix = ""; 463 if (OpenCms.getSiteManager().getSiteRoot(target) != null) { 464 String siteRootFolder = getCms().getRequestContext().getSiteRoot(); 465 if (siteRootFolder.endsWith("/")) { 466 siteRootFolder = siteRootFolder.substring(0, siteRootFolder.length() - 1); 467 } 468 sitePrefix = siteRootFolder; 469 storedSiteRoot = getCms().getRequestContext().getSiteRoot(); 470 getCms().getRequestContext().setSiteRoot("/"); 471 } 472 473 Iterator<String> i = getResourceList().iterator(); 474 // iterate the resources to copy 475 while (i.hasNext()) { 476 String resName = i.next(); 477 try { 478 performSingleCopyOperation(resName, target, sitePrefix, copyMode, overwrite); 479 } catch (CmsException e) { 480 if (isMultiOperation()) { 481 // collect exceptions to create a detailed output 482 addMultiOperationException(e); 483 } else { 484 // for single operation, throw the exception immediately 485 throw e; 486 } 487 } 488 } 489 // check if exceptions occurred 490 checkMultiOperationException(Messages.get(), Messages.ERR_COPY_MULTI_0); 491 } finally { 492 // restore the site root 493 if (storedSiteRoot != null) { 494 getCms().getRequestContext().setSiteRoot(storedSiteRoot); 495 } 496 } 497 return true; 498 } 499 500 /** 501 * Performs the copy operation for a single VFS resource.<p> 502 * 503 * @param source the source VFS path 504 * @param target the target VFS path 505 * @param sitePrefix the site prefix 506 * @param copyMode the copy mode for siblings 507 * @param overwrite the overwrite flag 508 * 509 * @throws CmsException if copying the resource fails 510 */ 511 protected void performSingleCopyOperation( 512 String source, 513 String target, 514 String sitePrefix, 515 CmsResourceCopyMode copyMode, 516 boolean overwrite) throws CmsException { 517 518 // calculate the target name 519 String finalTarget = CmsLinkManager.getAbsoluteUri(target, CmsResource.getParentFolder(source)); 520 521 if (finalTarget.equals(source) || (isMultiOperation() && finalTarget.startsWith(source))) { 522 throw new CmsVfsException(Messages.get().container(Messages.ERR_COPY_ONTO_ITSELF_1, finalTarget)); 523 } 524 525 try { 526 CmsResource res = getCms().readResource(finalTarget, CmsResourceFilter.ALL); 527 if (res.isFolder()) { 528 // target folder already exists, so we add the current folder name 529 if (!finalTarget.endsWith("/")) { 530 finalTarget += "/"; 531 } 532 finalTarget = finalTarget + CmsResource.getName(source); 533 } 534 } catch (CmsVfsResourceNotFoundException e) { 535 // target folder does not already exist, so target name is o.k. 536 if (LOG.isInfoEnabled()) { 537 LOG.info(e.getLocalizedMessage()); 538 } 539 } 540 541 // set the target parameter value 542 setParamTarget(finalTarget); 543 544 // delete existing target resource if selected or confirmed by the user 545 if (overwrite && getCms().existsResource(finalTarget)) { 546 checkLock(finalTarget); 547 getCms().deleteResource(finalTarget, CmsResource.DELETE_PRESERVE_SIBLINGS); 548 } 549 // copy the resource 550 getCms().copyResource(sitePrefix + source, finalTarget, copyMode); 551 } 552}