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; 029 030import org.opencms.file.CmsPropertyDefinition; 031import org.opencms.file.CmsResource; 032import org.opencms.file.CmsResourceFilter; 033import org.opencms.i18n.CmsMessageContainer; 034import org.opencms.i18n.I_CmsMessageBundle; 035import org.opencms.jsp.CmsJspActionElement; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.CmsMultiException; 039import org.opencms.security.CmsPermissionSet; 040import org.opencms.util.CmsStringUtil; 041 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.Iterator; 045import java.util.List; 046 047import javax.servlet.http.HttpServletRequest; 048import javax.servlet.http.HttpServletResponse; 049import javax.servlet.jsp.PageContext; 050 051import org.apache.commons.logging.Log; 052 053/** 054 * The base class to build a dialog capable of multiple file operations.<p> 055 * 056 * Extend this class for workplace dialogs that can perform operations on more than one 057 * VFS resource like copy, move, touch etc.<p> 058 * 059 * Provides methods to determine if a multi-resource operation has to be done and helper methods, 060 * e.g. to get the list of resources to work with.<p> 061 * 062 * @since 6.2.0 063 */ 064public abstract class CmsMultiDialog extends CmsDialog { 065 066 /** The delimiter that is used in the resource list request parameter. */ 067 public static final String DELIMITER_RESOURCES = "|"; 068 069 /** The log object for this class. */ 070 private static final Log LOG = CmsLog.getLog(CmsMultiDialog.class); 071 072 /** Collects all eventually thrown exceptions during a multi operation. */ 073 private CmsMultiException m_multiOperationException; 074 075 /** The resource list parameter value. */ 076 private String m_paramResourcelist; 077 078 /** The list of resource names for the multi operation. */ 079 private List<String> m_resourceList; 080 081 /** 082 * Public constructor.<p> 083 * 084 * @param jsp an initialized JSP action element 085 */ 086 public CmsMultiDialog(CmsJspActionElement jsp) { 087 088 super(jsp); 089 m_multiOperationException = new CmsMultiException(); 090 } 091 092 /** 093 * Public constructor with JSP variables.<p> 094 * 095 * @param context the JSP page context 096 * @param req the JSP request 097 * @param res the JSP response 098 */ 099 public CmsMultiDialog(PageContext context, HttpServletRequest req, HttpServletResponse res) { 100 101 this(new CmsJspActionElement(context, req, res)); 102 } 103 104 /** 105 * Adds an exception thrown during a multi resource operation to the multi exception.<p> 106 * 107 * After iterating the dialog resources, use {@link #checkMultiOperationException(I_CmsMessageBundle, String)} to 108 * display the multi exception depending on collected exceptions.<p> 109 * 110 * @param exc the exception that was thrown 111 */ 112 public void addMultiOperationException(CmsException exc) { 113 114 m_multiOperationException.addException(exc); 115 } 116 117 /** 118 * @see org.opencms.workplace.CmsDialog#buildLockHeaderBox() 119 */ 120 @Override 121 public String buildLockHeaderBox() throws CmsException { 122 123 if (!isMultiOperation()) { 124 return super.buildLockHeaderBox(); 125 } 126 StringBuffer html = new StringBuffer(1024); 127 // include multi resource list 128 html.append(dialogBlockStart(key(org.opencms.workplace.commons.Messages.GUI_MULTI_RESOURCELIST_TITLE_0))); 129 html.append(buildResourceList()); 130 html.append(dialogBlockEnd()); 131 return html.toString(); 132 } 133 134 /** 135 * Builds the HTML for the resource list that is affected by the multi operation.<p> 136 * 137 * @return the HTML for the resource list that is affected by the multi operation 138 */ 139 public String buildResourceList() { 140 141 // check how many resources are selected to decide using a div or not 142 boolean scroll = (getResourceList().size() > 6); 143 144 StringBuffer result = new StringBuffer(1024); 145 146 result.append(dialogWhiteBoxStart()); 147 148 // if the output to long, wrap it in a div 149 if (scroll) { 150 result.append("<div style='width: 100%; height:100px; overflow: auto;'>\n"); 151 } 152 153 result.append("<table border=\"0\">\n"); 154 Iterator<String> i = getResourceList().iterator(); 155 while (i.hasNext()) { 156 String resName = i.next(); 157 result.append("\t<tr>\n"); 158 result.append("\t\t<td class='textbold' style=\"vertical-align:top;\">"); 159 result.append(CmsResource.getName(resName)); 160 result.append(" </td>\n\t\t<td style=\"vertical-align:top;\">"); 161 String title = null; 162 try { 163 // get the title property value 164 title = getCms().readPropertyObject(resName, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue( 165 null); 166 } catch (CmsException e) { 167 // ignore this exception, title not found 168 } 169 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) { 170 // show the title information 171 result.append(title); 172 } 173 result.append("</td>\n\t</tr>\n"); 174 } 175 result.append("</table>"); 176 177 // close the div if needed 178 if (scroll) { 179 result.append("</div>\n"); 180 } 181 result.append(dialogWhiteBoxEnd()); 182 return result.toString(); 183 } 184 185 /** 186 * Checks if an exception occurred during a multi resource operation, and throws a new exception if necessary.<p> 187 * 188 * @param messages the message bundle to use for the exception message generation 189 * @param key the key for the exception to throw with one parameter 190 * @throws CmsException the exception that is thrown when the multi operation was not successful 191 */ 192 public void checkMultiOperationException(I_CmsMessageBundle messages, String key) throws CmsException { 193 194 if (m_multiOperationException.hasExceptions()) { 195 m_multiOperationException.setMessage( 196 new CmsMessageContainer(messages, key, new Object[] {m_multiOperationException})); 197 throw m_multiOperationException; 198 } 199 } 200 201 /** 202 * Returns the value of the resource list parameter, or null if the parameter is not provided.<p> 203 * 204 * This parameter selects the resources to perform operations on.<p> 205 * 206 * @return the value of the resource list parameter or null, if the parameter is not provided 207 */ 208 public String getParamResourcelist() { 209 210 if (CmsStringUtil.isNotEmpty(m_paramResourcelist) && !"null".equals(m_paramResourcelist)) { 211 return m_paramResourcelist; 212 } else { 213 return null; 214 } 215 } 216 217 /** 218 * Returns the resources that are defined for the dialog operation.<p> 219 * 220 * For single resource operations, the list contains one item: the resource name found 221 * in the request parameter value of the "resource" parameter.<p> 222 * 223 * @return the resources that are defined for the dialog operation 224 */ 225 public List<String> getResourceList() { 226 227 if (m_resourceList == null) { 228 // use lazy initializing 229 if (getParamResourcelist() != null) { 230 // found the resourcelist parameter 231 m_resourceList = CmsStringUtil.splitAsList(getParamResourcelist(), DELIMITER_RESOURCES, true); 232 Collections.sort(m_resourceList); 233 } else { 234 // this is a single resource operation, create list containing the resource name 235 m_resourceList = new ArrayList<String>(1); 236 m_resourceList.add(getParamResource()); 237 } 238 } 239 return m_resourceList; 240 } 241 242 /** 243 * Returns the value of the resourcelist parameter in form of a String separated 244 * with {@link #DELIMITER_RESOURCES}, or the value of the resource parameter if the 245 * first parameter is not provided (no multiple choice has been done.<p> 246 * 247 * This may be used for jsps as value for the parameter for resources {@link #PARAM_RESOURCELIST}.<p> 248 * 249 * @return the value of the resourcelist parameter or null, if the parameter is not provided 250 */ 251 public String getResourceListAsParam() { 252 253 String result = getParamResourcelist(); 254 if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) { 255 result = getParamResource(); 256 } 257 return result; 258 } 259 260 /** 261 * Returns true if the dialog operation has to be performed on multiple resources.<p> 262 * 263 * @return true if the dialog operation has to be performed on multiple resources, otherwise false 264 */ 265 public boolean isMultiOperation() { 266 267 return (getResourceList().size() > 1); 268 } 269 270 /** 271 * Sets the title of the dialog depending on the operation type, multiple or single operation.<p> 272 * 273 * @param singleKey the key for the single operation 274 * @param multiKey the key for the multiple operation 275 */ 276 public void setDialogTitle(String singleKey, String multiKey) { 277 278 if (isMultiOperation()) { 279 // generate title with number of selected resources and parent folder parameters 280 String resCount = String.valueOf(getResourceList().size()); 281 String currentFolder = CmsResource.getFolderPath(getSettings().getExplorerResource()); 282 currentFolder = CmsStringUtil.formatResourceName(currentFolder, 40); 283 Object[] params = new Object[] {resCount, currentFolder}; 284 setParamTitle(key(multiKey, params)); 285 } else { 286 // generate title using the resource name as parameter for the key 287 String resourceName = CmsStringUtil.formatResourceName(getParamResource(), 50); 288 setParamTitle(key(singleKey, new Object[] {resourceName})); 289 } 290 } 291 292 /** 293 * @see org.opencms.workplace.CmsDialog#setParamResource(java.lang.String) 294 */ 295 @Override 296 public void setParamResource(String value) { 297 298 super.setParamResource(value); 299 m_resourceList = null; 300 } 301 302 /** 303 * Sets the value of the resourcelist parameter.<p> 304 * 305 * @param paramResourcelist the value of the resourcelist parameter 306 */ 307 public void setParamResourcelist(String paramResourcelist) { 308 309 m_paramResourcelist = paramResourcelist; 310 m_resourceList = null; 311 } 312 313 /** 314 * Checks if the permissions of the current user on the single resource to use in the dialog are sufficient.<p> 315 * 316 * For a multi resource operation, this returns always true, checks only for single resource operations.<p> 317 * 318 * @see CmsDialog#checkResourcePermissions(CmsPermissionSet, boolean) 319 * 320 * @param required the required permissions for the dialog 321 * @param neededForFolder if true, the permissions are required for the parent folder of the resource (e.g. for editors) 322 * @return true if the permissions are sufficient, otherwise false 323 */ 324 @Override 325 protected boolean checkResourcePermissions(CmsPermissionSet required, boolean neededForFolder) { 326 327 if (isMultiOperation()) { 328 // for multi resource operation, return always true 329 return true; 330 } else { 331 // check for single resource operation 332 return super.checkResourcePermissions(required, neededForFolder); 333 } 334 } 335 336 /** 337 * Checks if the resource operation is an operation on at least one folder.<p> 338 * 339 * @return true if the operation an operation on at least one folder, otherwise false 340 */ 341 protected boolean isOperationOnFolder() { 342 343 Iterator<String> i = getResourceList().iterator(); 344 while (i.hasNext()) { 345 String resName = i.next(); 346 try { 347 CmsResource curRes = getCms().readResource(resName, CmsResourceFilter.ALL); 348 if (curRes.isFolder()) { 349 // found a folder 350 return true; 351 } 352 } catch (CmsException e) { 353 // can usually be ignored 354 if (LOG.isInfoEnabled()) { 355 LOG.info(e.getLocalizedMessage()); 356 } 357 } 358 } 359 return false; 360 } 361 362 /** 363 * Performs the dialog operation for the selected resources.<p> 364 * 365 * @return true, if the operation was successful, otherwise false 366 * 367 * @throws CmsException if operation was not successful 368 */ 369 protected abstract boolean performDialogOperation() throws CmsException; 370 371}