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.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.jsp.CmsJspActionElement;
035import org.opencms.main.CmsException;
036import org.opencms.security.CmsPermissionSet;
037import org.opencms.util.CmsStringUtil;
038import org.opencms.widgets.CmsCalendarWidget;
039import org.opencms.workplace.CmsMultiDialog;
040import org.opencms.workplace.CmsWorkplaceSettings;
041
042import java.text.ParseException;
043import java.util.Iterator;
044
045import javax.servlet.http.HttpServletRequest;
046import javax.servlet.http.HttpServletResponse;
047import javax.servlet.jsp.JspException;
048import javax.servlet.jsp.PageContext;
049
050/**
051 * Provides methods for the touch resource(s) dialog.<p>
052 *
053 * The following files use this class:
054 * <ul>
055 * <li>/commons/touch.jsp
056 * </ul>
057 * <p>
058 *
059 * @since 6.0.0
060 */
061public class CmsTouch extends CmsMultiDialog {
062
063    /** Value for the action: touch. */
064    public static final int ACTION_TOUCH = 100;
065
066    /** Default value for date last modified, the release and expire date. */
067    public static final String DEFAULT_DATE_STRING = "-";
068
069    /** The dialog type. */
070    public static final String DIALOG_TYPE = "touch";
071
072    /** Request parameter name for the content flag. */
073    public static final String PARAM_CONTENT = "content";
074
075    /** Request parameter name for timestamp. */
076    public static final String PARAM_NEWTIMESTAMP = "newtimestamp";
077
078    /** Request parameter name for the recursive flag. */
079    public static final String PARAM_RECURSIVE = "recursive";
080
081    /** Content parameter. */
082    private String m_paramContent;
083
084    /** Timestamp parameter. */
085    private String m_paramNewtimestamp;
086
087    /** Recursive parameter. */
088    private String m_paramRecursive;
089
090    /**
091     * Public constructor.<p>
092     *
093     * @param jsp an initialized JSP action element
094     */
095    public CmsTouch(CmsJspActionElement jsp) {
096
097        super(jsp);
098    }
099
100    /**
101     * Public constructor with JSP variables.<p>
102     *
103     * @param context the JSP page context
104     * @param req the JSP request
105     * @param res the JSP response
106     */
107    public CmsTouch(PageContext context, HttpServletRequest req, HttpServletResponse res) {
108
109        this(new CmsJspActionElement(context, req, res));
110    }
111
112    /**
113     * Performs a touch operation for a single resource.<p>
114     *
115     * @param resourceName the resource name of the resource to touch
116     * @param timeStamp the new time stamp
117     * @param recursive the flag if the touch operation is recursive
118     * @param correctDate the flag if the new time stamp is a correct date
119     * @param touchContent if the content has to be rewritten
120     *
121     * @throws CmsException if touching the resource fails
122     */
123    public static void touchSingleResource(
124        CmsObject cms,
125        String resourceName,
126        long timeStamp,
127        boolean recursive,
128        boolean correctDate,
129        boolean touchContent) throws CmsException {
130
131        CmsResource sourceRes = cms.readResource(resourceName, CmsResourceFilter.ALL);
132        if (!correctDate) {
133            // no date value entered, use current resource modification date
134            timeStamp = sourceRes.getDateLastModified();
135        }
136        cms.setDateLastModified(resourceName, timeStamp, recursive);
137
138        if (touchContent) {
139            if (sourceRes.isFile()) {
140                hardTouch(cms, sourceRes);
141            } else if (recursive) {
142                Iterator<CmsResource> it = cms.readResources(resourceName, CmsResourceFilter.ALL, true).iterator();
143                while (it.hasNext()) {
144                    CmsResource subRes = it.next();
145                    if (subRes.isFile()) {
146                        hardTouch(cms, subRes);
147                    }
148                }
149            }
150        }
151    }
152
153    /**
154     * Rewrites the content of the given file.<p>
155     *
156     * @param resource the resource to rewrite the content for
157     *
158     * @throws CmsException if something goes wrong
159     */
160    private static void hardTouch(CmsObject cms, CmsResource resource) throws CmsException {
161
162        CmsFile file = cms.readFile(resource);
163        file.setContents(file.getContents());
164        cms.writeFile(file);
165    }
166
167    /**
168     * Performs the resource touching, will be called by the JSP page.<p>
169     *
170     * @throws JspException if problems including sub-elements occur
171     */
172    public void actionTouch() throws JspException {
173
174        // save initialized instance of this class in request attribute for included sub-elements
175        getJsp().getRequest().setAttribute(SESSION_WORKPLACE_CLASS, this);
176        try {
177            if (performDialogOperation()) {
178                // if no exception is caused and "true" is returned the touch operation was successful
179                actionCloseDialog();
180            } else {
181                // "false" returned, display "please wait" screen
182                getJsp().include(FILE_DIALOG_SCREEN_WAIT);
183            }
184        } catch (Throwable e) {
185            includeErrorpage(this, e);
186        }
187    }
188
189    /**
190     * Creates the "rewrite content" checkbox.<p>
191     *
192     * @return the String with the checkbox input field
193     */
194    public String buildCheckContent() {
195
196        StringBuffer retValue = new StringBuffer(256);
197
198        retValue.append("<tr>\n\t<td colspan=\"3\" style=\"white-space: nowrap;\" unselectable=\"on\">");
199        retValue.append("<input type=\"checkbox\" name=\"");
200        retValue.append(PARAM_CONTENT);
201        retValue.append("\" value=\"true\">&nbsp;");
202        retValue.append(key(Messages.GUI_TOUCH_MODIFY_CONTENT_0));
203        retValue.append("</td>\n</tr>\n");
204        return retValue.toString();
205    }
206
207    /**
208     * Creates the "recursive" checkbox for touching subresources of folders.<p>
209     *
210     * @return the String with the checkbox input field or an empty String for folders.
211     */
212    public String buildCheckRecursive() {
213
214        StringBuffer retValue = new StringBuffer(256);
215
216        // show the checkbox only for folders
217        if (isOperationOnFolder()) {
218            retValue.append("<tr>\n\t<td colspan=\"3\" style=\"white-space: nowrap;\" unselectable=\"on\">");
219            retValue.append("<input type=\"checkbox\" name=\"");
220            retValue.append(PARAM_RECURSIVE);
221            retValue.append("\" value=\"true\">&nbsp;");
222            retValue.append(key(Messages.GUI_TOUCH_MODIFY_SUBRESOURCES_0));
223            retValue.append("</td>\n</tr>\n");
224        }
225        return retValue.toString();
226    }
227
228    /**
229     * Creates the HTML JavaScript and stylesheet includes required by the calendar for the head of the page.<p>
230     *
231     * @return the necessary HTML code for the js and stylesheet includes
232     *
233     * @deprecated use {@link CmsCalendarWidget#calendarIncludes(java.util.Locale)}, this is just here so that old JSP still work
234     */
235    @Deprecated
236    public String calendarIncludes() {
237
238        return CmsCalendarWidget.calendarIncludes(getLocale());
239    }
240
241    /**
242     * Generates the HTML to initialize the JavaScript calendar element on the end of a page.<p>
243     *
244     * @param inputFieldId the ID of the input field where the date is pasted to
245     * @param triggerButtonId the ID of the button which triggers the calendar
246     * @param align initial position of the calendar popup element
247     * @param singleClick if true, a single click selects a date and closes the calendar, otherwise calendar is closed by doubleclick
248     * @param weekNumbers show the week numbers in the calendar or not
249     * @param mondayFirst show monday as first day of week
250     * @param dateStatusFunc name of the function which determines if/how a date should be disabled
251     * @param showTime true if the time selector should be shown, otherwise false
252     * @return the HTML code to initialize a calendar poup element
253     *
254     * @deprecated use {@link CmsCalendarWidget#calendarInit(org.opencms.i18n.CmsMessages, String, String, String, boolean, boolean, boolean, String, boolean)}, this is just here so that old JSP still work
255     */
256    @Deprecated
257    public String calendarInit(
258        String inputFieldId,
259        String triggerButtonId,
260        String align,
261        boolean singleClick,
262        boolean weekNumbers,
263        boolean mondayFirst,
264        String dateStatusFunc,
265        boolean showTime) {
266
267        return CmsCalendarWidget.calendarInit(
268            getMessages(),
269            inputFieldId,
270            triggerButtonId,
271            align,
272            singleClick,
273            weekNumbers,
274            mondayFirst,
275            dateStatusFunc,
276            showTime);
277    }
278
279    /**
280     * Returns the current date and time as String formatted in localized pattern.<p>
281     *
282     * @return the current date and time as String formatted in localized pattern
283     */
284    public String getCurrentDateTime() {
285
286        // get the current date & time
287        return CmsCalendarWidget.getCalendarLocalizedTime(getLocale(), getMessages(), System.currentTimeMillis());
288    }
289
290    /**
291     * Returns the value of the content parameter,
292     * or null if this parameter was not provided.<p>
293     *
294     * The content parameter on files decides if also the content is rewritten.<p>
295     *
296     * @return the value of the content parameter
297     */
298    public String getParamContent() {
299
300        return m_paramContent;
301    }
302
303    /**
304     * Returns the value of the new timestamp parameter,
305     * or null if this parameter was not provided.<p>
306     *
307     * The timestamp parameter stores the new timestamp as String.<p>
308     *
309     * @return the value of the new timestamp parameter
310     */
311    public String getParamNewtimestamp() {
312
313        return m_paramNewtimestamp;
314    }
315
316    /**
317     * Returns the value of the recursive parameter,
318     * or null if this parameter was not provided.<p>
319     *
320     * The recursive parameter on folders decides if all subresources
321     * of the folder should be touched, too.<p>
322     *
323     * @return the value of the recursive parameter
324     */
325    public String getParamRecursive() {
326
327        return m_paramRecursive;
328    }
329
330    /**
331     * Sets the value of the content parameter.<p>
332     *
333     * @param value the value to set
334     */
335    public void setParamContent(String value) {
336
337        m_paramContent = value;
338    }
339
340    /**
341     * Sets the value of the new timestamp parameter.<p>
342     *
343     * @param value the value to set
344     */
345    public void setParamNewtimestamp(String value) {
346
347        m_paramNewtimestamp = value;
348    }
349
350    /**
351     * Sets the value of the recursive parameter.<p>
352     *
353     * @param value the value to set
354     */
355    public void setParamRecursive(String value) {
356
357        m_paramRecursive = value;
358    }
359
360    /**
361     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
362     */
363    @Override
364    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
365
366        // fill the parameter values in the get/set methods
367        fillParamValues(request);
368
369        // check the required permissions to touch the resource
370        if (!checkResourcePermissions(CmsPermissionSet.ACCESS_WRITE, false)) {
371            // no write permissions for the resource, set cancel action to close dialog
372            setParamAction(DIALOG_CANCEL);
373        }
374
375        // set the dialog type
376        setParamDialogtype(DIALOG_TYPE);
377
378        // set the action for the JSP switch
379        if (DIALOG_TYPE.equals(getParamAction())) {
380            setAction(ACTION_TOUCH);
381        } else if (DIALOG_WAIT.equals(getParamAction())) {
382            setAction(ACTION_WAIT);
383        } else if (DIALOG_CANCEL.equals(getParamAction())) {
384            setAction(ACTION_CANCEL);
385        } else if (DIALOG_LOCKS_CONFIRMED.equals(getParamAction())) {
386            setAction(ACTION_LOCKS_CONFIRMED);
387        } else {
388            setAction(ACTION_DEFAULT);
389            // build title for touch dialog
390            setDialogTitle(Messages.GUI_TOUCH_RESOURCE_1, Messages.GUI_TOUCH_MULTI_2);
391        }
392    }
393
394    /**
395     * Performs the resource touching.<p>
396     *
397     * @return true, if the resource was touched, otherwise false
398     * @throws CmsException if touching is not successful
399     */
400    @Override
401    protected boolean performDialogOperation() throws CmsException {
402
403        // on folder touch or multi resource operation display "please wait" screen, not for simple file copy
404        if (!DIALOG_WAIT.equals(getParamAction())) {
405            // check if the "please wait" screen has to be shown
406            if (isMultiOperation()) {
407                // show please wait for every multi resource operation
408                return false;
409            } else {
410                // check if the single resource is a folder
411                CmsResource sourceRes = getCms().readResource(getParamResource(), CmsResourceFilter.ALL);
412                if (sourceRes.isFolder()) {
413                    return false;
414                }
415            }
416        }
417
418        // get the new timestamp for the resource(s) from request parameter
419        long timeStamp = 0;
420        boolean correctDate = false;
421        try {
422            if (CmsStringUtil.isNotEmpty(getParamNewtimestamp())) {
423                timeStamp = CmsCalendarWidget.getCalendarDate(getMessages(), getParamNewtimestamp(), true);
424                correctDate = true;
425            }
426        } catch (ParseException e) {
427            throw new CmsException(Messages.get().container(Messages.ERR_PARSE_TIMESTAMP_1, getParamNewtimestamp()), e);
428        }
429
430        // get the flag if the touch is recursive from request parameter
431        boolean touchRecursive = Boolean.valueOf(getParamRecursive()).booleanValue();
432        // get the flag to the touch the content from request parameter
433        boolean touchContent = Boolean.valueOf(getParamContent()).booleanValue();
434
435        // now touch the resource(s)
436        Iterator<String> i = getResourceList().iterator();
437        while (i.hasNext()) {
438            String resName = i.next();
439            try {
440                // lock resource if autolock is enabled
441                checkLock(resName);
442                touchSingleResource(getCms(), resName, timeStamp, touchRecursive, correctDate, touchContent);
443            } catch (CmsException e) {
444                // collect exceptions to create a detailed output
445                addMultiOperationException(e);
446            }
447        }
448        checkMultiOperationException(Messages.get(), Messages.ERR_TOUCH_MULTI_0);
449
450        return true;
451    }
452}