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.CmsResourceFilter;
032import org.opencms.file.CmsVfsException;
033import org.opencms.file.CmsVfsResourceAlreadyExistsException;
034import org.opencms.file.CmsVfsResourceNotFoundException;
035import org.opencms.jsp.CmsJspActionElement;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.security.CmsPermissionSet;
040import org.opencms.staticexport.CmsLinkManager;
041import org.opencms.workplace.CmsMultiDialog;
042import org.opencms.workplace.CmsWorkplaceSettings;
043
044import java.util.ArrayList;
045import java.util.Iterator;
046import java.util.List;
047
048import javax.servlet.http.HttpServletRequest;
049import javax.servlet.http.HttpServletResponse;
050import javax.servlet.jsp.JspException;
051import javax.servlet.jsp.PageContext;
052
053import org.apache.commons.logging.Log;
054
055/**
056 * Provides methods for the move resources dialog.<p>
057 *
058 * The following files use this class:
059 * <ul>
060 * <li>/commons/move.jsp
061 * </ul>
062 * <p>
063 *
064 * @since 6.0.0
065 */
066public class CmsMove extends CmsMultiDialog {
067
068    /** Value for the action: move resource. */
069    public static final int ACTION_MOVE = 100;
070
071    /** The dialog type. */
072    public static final String DIALOG_TYPE = "move";
073
074    /** The log object for this class. */
075    private static final Log LOG = CmsLog.getLog(CmsMove.class);
076
077    /** The value for the 'target' parameter. */
078    private String m_paramTarget;
079
080    /**
081     * Public constructor with JSP action element.<p>
082     *
083     * @param jsp an initialized JSP action element
084     */
085    public CmsMove(CmsJspActionElement jsp) {
086
087        super(jsp);
088    }
089
090    /**
091     * Public constructor with JSP variables.<p>
092     *
093     * @param context the JSP page context
094     * @param req the JSP request
095     * @param res the JSP response
096     */
097    public CmsMove(PageContext context, HttpServletRequest req, HttpServletResponse res) {
098
099        this(new CmsJspActionElement(context, req, res));
100    }
101
102    /**
103     * Performs the move action, will be called by the JSP page.<p>
104     *
105     * @throws JspException if problems including sub-elements occur
106     */
107    public void actionMove() throws JspException {
108
109        // save initialized instance of this class in request attribute for included sub-elements
110        getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
111        try {
112            boolean isFolder = false;
113            String source = getResourceList().get(0);
114            String target = CmsLinkManager.getAbsoluteUri(getParamTarget(), CmsResource.getParentFolder(source));
115            if (!isMultiOperation()) {
116                CmsResource resource = getCms().readResource(source, CmsResourceFilter.ALL);
117                isFolder = resource.isFolder();
118            } else {
119                String siteRootFolder = null;
120                CmsResource resource;
121                try {
122                    // check if a site root was added to the target name
123                    if (OpenCms.getSiteManager().getSiteRoot(target) != null) {
124                        siteRootFolder = getCms().getRequestContext().getSiteRoot();
125                        if (siteRootFolder.endsWith("/")) {
126                            siteRootFolder = siteRootFolder.substring(0, siteRootFolder.length() - 1);
127                        }
128                        getCms().getRequestContext().setSiteRoot("/");
129                    }
130                    resource = getCms().readResource(target, CmsResourceFilter.ALL);
131                } finally {
132                    if (siteRootFolder != null) {
133                        getCms().getRequestContext().setSiteRoot(siteRootFolder);
134                    }
135                }
136                if (!resource.isFolder()) {
137                    // no folder selected for multi operation, throw exception
138                    throw new CmsVfsException(
139                        Messages.get().container(Messages.ERR_MOVE_MULTI_TARGET_NOFOLDER_1, target));
140                }
141            }
142            if (performDialogOperation()) {
143                // if no exception is caused and "true" is returned move operation was successful
144                if (isMultiOperation() || isFolder) {
145                    // set request attribute to reload the explorer tree view
146                    List<String> folderList = new ArrayList<String>(2);
147                    String sourceParent = CmsResource.getParentFolder(source);
148                    folderList.add(sourceParent);
149                    try {
150                        String targetParent = CmsResource.getParentFolder(target);
151                        if (!targetParent.equals(sourceParent)) {
152                            // update target folder if its not the same as the source folder
153                            folderList.add(targetParent);
154                        }
155                    } catch (Exception e) {
156                        if (LOG.isInfoEnabled()) {
157                            LOG.info(e.getLocalizedMessage(), e);
158                        }
159                    }
160                    getJsp().getRequest().setAttribute(REQUEST_ATTRIBUTE_RELOADTREE, folderList);
161                }
162                actionCloseDialog();
163            } else {
164                // "false" returned, display "please wait" screen
165                getJsp().include(FILE_DIALOG_SCREEN_WAIT);
166            }
167        } catch (Throwable e) {
168            // error during move, show error dialog
169            includeErrorpage(this, e);
170        }
171    }
172
173    /**
174     * Returns the current name of the resource without path information.<p>
175     *
176     * This is used to preset the input text field with the current resource name for single resource operations.<p>
177     *
178     * @return the current name of the resource without path information
179     */
180    public String getCurrentResourceName() {
181
182        if (isMultiOperation()) {
183            return "";
184        }
185        String resourceName = CmsResource.getName(getParamResource());
186        if (resourceName.endsWith("/")) {
187            resourceName = resourceName.substring(0, resourceName.length() - 1);
188        }
189        return resourceName;
190    }
191
192    /**
193     * Returns the value of the target parameter,
194     * or null if this parameter was not provided.<p>
195     *
196     * The target parameter selects the target name
197     * of the operation.<p>
198     *
199     * @return the value of the target parameter
200     */
201    public String getParamTarget() {
202
203        return m_paramTarget;
204    }
205
206    /**
207     * Sets the value of the target parameter.<p>
208     *
209     * @param value the value to set
210     */
211    public void setParamTarget(String value) {
212
213        m_paramTarget = value;
214    }
215
216    /**
217     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
218     */
219    @Override
220    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
221
222        // fill the parameter values in the get/set methods
223        fillParamValues(request);
224
225        // check the required permissions to rename/move the resource
226        if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) {
227            // no write permissions for the resource, set cancel action to close dialog
228            setParamAction(DIALOG_CANCEL);
229        }
230
231        // set the dialog type
232        setParamDialogtype(DIALOG_TYPE);
233        // set the action for the JSP switch
234        if (DIALOG_TYPE.equals(getParamAction())) {
235            setAction(ACTION_MOVE);
236        } else if (DIALOG_CONFIRMED.equals(getParamAction())) {
237            setAction(ACTION_CONFIRMED);
238        } else if (DIALOG_WAIT.equals(getParamAction())) {
239            setAction(ACTION_WAIT);
240        } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) {
241            setAction(ACTION_LOCKS_CONFIRMED);
242        } else if (DIALOG_CANCEL.equals(getParamAction())) {
243            setAction(ACTION_CANCEL);
244        } else {
245            setAction(ACTION_DEFAULT);
246            // build title for move dialog
247            setDialogTitle(Messages.GUI_MOVE_RESOURCE_1, Messages.GUI_MOVE_MULTI_2);
248        }
249    }
250
251    /**
252     * Performs the resource moving.<p>
253     *
254     * @return true, if the resource was successfully moved, otherwise false
255     * @throws CmsException if moving is not successful
256     */
257    @Override
258    protected boolean performDialogOperation() throws CmsException {
259
260        // check if the current resource is a folder for single operation
261        boolean isFolder = isOperationOnFolder();
262        // on folder move operation display "please wait" screen, not for simple file move operation
263        if ((isMultiOperation() || isFolder) && !DIALOG_WAIT.equals(getParamAction())) {
264            // return false, this will trigger the "please wait" screen
265            return false;
266        }
267
268        // get the target name
269        String target = getParamTarget();
270        if (target == null) {
271            target = "";
272        }
273
274        String siteRootFolder = null;
275        try {
276            // check if a site root was added to the target name
277            String sitePrefix = "";
278            if (OpenCms.getSiteManager().getSiteRoot(target) != null) {
279                siteRootFolder = getCms().getRequestContext().getSiteRoot();
280                if (siteRootFolder.endsWith("/")) {
281                    siteRootFolder = siteRootFolder.substring(0, siteRootFolder.length() - 1);
282                }
283                sitePrefix = siteRootFolder;
284                getCms().getRequestContext().setSiteRoot("/");
285            }
286
287            Iterator<String> i = getResourceList().iterator();
288            // iterate the resources to move
289            while (i.hasNext()) {
290                String resName = i.next();
291                try {
292                    performSingleMoveOperation(resName, target, sitePrefix);
293                } catch (CmsException e) {
294                    if (isMultiOperation()) {
295                        // collect exceptions to create a detailed output
296                        addMultiOperationException(e);
297                    } else {
298                        // for single operation, throw the exception immediately
299                        throw e;
300                    }
301                }
302            }
303            // check if exceptions occurred
304            checkMultiOperationException(Messages.get(), Messages.ERR_MOVE_MULTI_0);
305        } finally {
306            if (siteRootFolder != null) {
307                getCms().getRequestContext().setSiteRoot(siteRootFolder);
308            }
309        }
310        return true;
311    }
312
313    /**
314     * Performs the move operation for a single VFS resource.<p>
315     *
316     * @param source the source VFS path
317     * @param target the target VFS path
318     * @param sitePrefix the site prefix
319     *
320     * @throws CmsException if moving the resource fails
321     */
322    protected void performSingleMoveOperation(String source, String target, String sitePrefix) throws CmsException {
323
324        // calculate the target name
325        String finalTarget = getCms().getRequestContext().getFileTranslator().translateResource(target);
326        finalTarget = CmsLinkManager.getAbsoluteUri(finalTarget, CmsResource.getParentFolder(source));
327
328        if (finalTarget.equals(source) || (isMultiOperation() && finalTarget.startsWith(source))) {
329            throw new CmsVfsException(Messages.get().container(Messages.ERR_MOVE_ONTO_ITSELF_1, finalTarget));
330        }
331
332        try {
333            CmsResource res = getCms().readResource(finalTarget, CmsResourceFilter.ALL);
334            if (res.isFolder()) {
335                // target folder already exists, so we add the current folder name
336                if (!finalTarget.endsWith("/")) {
337                    finalTarget += "/";
338                }
339                finalTarget = finalTarget + CmsResource.getName(source);
340                if (finalTarget.endsWith("/")) {
341                    finalTarget = finalTarget.substring(0, finalTarget.length() - 1);
342                }
343            }
344        } catch (CmsVfsResourceNotFoundException e) {
345            // target folder does not already exist, so target name is o.k.
346            if (LOG.isInfoEnabled()) {
347                LOG.info(e.getLocalizedMessage());
348            }
349        }
350
351        // set the target parameter value
352        setParamTarget(finalTarget);
353
354        // could not overwrite a resource in a move operation
355        if (getCms().existsResource(finalTarget, CmsResourceFilter.ALL)) {
356            // throw exception to indicate that the target exists
357            throw new CmsVfsResourceAlreadyExistsException(
358                Messages.get().container(
359                    Messages.ERR_MOVE_FAILED_TARGET_EXISTS_2,
360                    source,
361                    getJsp().getRequestContext().removeSiteRoot(finalTarget)));
362        }
363
364        // lock resource if autolock is enabled
365        checkLock(sitePrefix + source);
366        // move the resource
367        getCms().moveResource(sitePrefix + source, finalTarget);
368    }
369}