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