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.tools.scheduler;
029
030import org.opencms.configuration.CmsSchedulerConfiguration;
031import org.opencms.jsp.CmsJspActionElement;
032import org.opencms.main.CmsContextInfo;
033import org.opencms.main.OpenCms;
034import org.opencms.monitor.CmsMemoryMonitor;
035import org.opencms.notification.CmsContentNotificationJob;
036import org.opencms.relations.CmsExternalLinksValidator;
037import org.opencms.relations.CmsInternalRelationsValidationJob;
038import org.opencms.scheduler.CmsScheduledJobInfo;
039import org.opencms.scheduler.jobs.CmsCreateImageSizeJob;
040import org.opencms.scheduler.jobs.CmsDeleteExpiredResourcesJob;
041import org.opencms.scheduler.jobs.CmsHistoryClearJob;
042import org.opencms.scheduler.jobs.CmsImageCacheCleanupJob;
043import org.opencms.scheduler.jobs.CmsPublishJob;
044import org.opencms.scheduler.jobs.CmsStaticExportJob;
045import org.opencms.scheduler.jobs.CmsUnsubscribeDeletedResourcesJob;
046import org.opencms.search.CmsSearchManager;
047import org.opencms.util.CmsDateUtil;
048import org.opencms.util.CmsStringUtil;
049import org.opencms.widgets.CmsCheckboxWidget;
050import org.opencms.widgets.CmsComboWidget;
051import org.opencms.widgets.CmsDisplayWidget;
052import org.opencms.widgets.CmsInputWidget;
053import org.opencms.widgets.CmsSelectWidgetOption;
054import org.opencms.widgets.CmsUserWidget;
055import org.opencms.widgets.CmsVfsFileWidget;
056import org.opencms.workplace.CmsDialog;
057import org.opencms.workplace.CmsWidgetDialog;
058import org.opencms.workplace.CmsWidgetDialogParameter;
059import org.opencms.workplace.CmsWorkplaceSettings;
060
061import java.text.DateFormat;
062import java.util.ArrayList;
063import java.util.Date;
064import java.util.List;
065import java.util.Map;
066
067import javax.servlet.http.HttpServletRequest;
068import javax.servlet.http.HttpServletResponse;
069import javax.servlet.jsp.PageContext;
070
071/**
072 * Dialog to edit new and existing scheduled jobs in the administration view.<p>
073 *
074 * @since 6.0.0
075 */
076public class CmsEditScheduledJobInfoDialog extends CmsWidgetDialog {
077
078    /** The action to copy a job to edit. */
079    public static final String DIALOG_COPYJOB = "copyjob";
080
081    /** Defines which pages are valid for this dialog. */
082    public static final String[] PAGES = {"page1", "page2"};
083
084    /** Request parameter name for the job id. */
085    public static final String PARAM_JOBID = "jobid";
086
087    /** The job info object that is edited on this dialog. */
088    protected CmsScheduledJobInfo m_jobInfo;
089
090    /** Stores the value of the request parameter for the job id. */
091    protected String m_paramJobid;
092
093    /** formatted current server time. */
094    protected String m_serverTime;
095
096    /**
097     * Public constructor with JSP action element.<p>
098     *
099     * @param jsp an initialized JSP action element
100     */
101    public CmsEditScheduledJobInfoDialog(CmsJspActionElement jsp) {
102
103        super(jsp);
104    }
105
106    /**
107     * Public constructor with JSP variables.<p>
108     *
109     * @param context the JSP page context
110     * @param req the JSP request
111     * @param res the JSP response
112     */
113    public CmsEditScheduledJobInfoDialog(PageContext context, HttpServletRequest req, HttpServletResponse res) {
114
115        this(new CmsJspActionElement(context, req, res));
116    }
117
118    /**
119     * Commits the edited scheduled job to the scheduler.<p>
120     */
121    @Override
122    public void actionCommit() {
123
124        List<Throwable> errors = new ArrayList<Throwable>();
125
126        try {
127            // schedule the edited job
128            OpenCms.getScheduleManager().scheduleJob(getCms(), m_jobInfo);
129            // update the XML configuration
130            OpenCms.writeConfiguration(CmsSchedulerConfiguration.class);
131            // refresh the list
132            Map<?, ?> objects = (Map<?, ?>)getSettings().getListObject();
133            if (objects != null) {
134                objects.remove(CmsSchedulerList.class.getName());
135            }
136        } catch (Throwable t) {
137            errors.add(t);
138        }
139        // set the list of errors to display when saving failed
140        setCommitErrors(errors);
141    }
142
143    /**
144     * Returns the job id parameter value.<p>
145     *
146     * @return the job id parameter value
147     */
148    public String getParamJobid() {
149
150        return m_paramJobid;
151    }
152
153    /**
154     * Returns the server Time.<p>
155     *
156     * @return the server Time
157     */
158    public String getServerTime() {
159
160        if (m_serverTime == null) {
161            m_serverTime = CmsDateUtil.getDateTime(new Date(), DateFormat.LONG, getLocale());
162        }
163        return m_serverTime;
164    }
165
166    /**
167     * Sets the job id parameter value.<p>
168     *
169     * @param jobid the job id parameter value
170     */
171    public void setParamJobid(String jobid) {
172
173        m_paramJobid = jobid;
174    }
175
176    /**
177     * Sets the server Time.<p>
178     *
179     * @param serverTime the server Time to set
180     */
181    public void setServerTime(String serverTime) {
182
183        m_serverTime = serverTime;
184    }
185
186    /**
187     * Creates the dialog HTML for all defined widgets of the named dialog (page).<p>
188     *
189     * This overwrites the method from the super class to create a layout variation for the widgets.<p>
190     *
191     * @param dialog the dialog (page) to get the HTML for
192     * @return the dialog HTML for all defined widgets of the named dialog (page)
193     */
194    @Override
195    protected String createDialogHtml(String dialog) {
196
197        StringBuffer result = new StringBuffer(1024);
198
199        // create widget table
200        result.append(createWidgetTableStart());
201
202        // show error header once if there were validation errors
203        result.append(createWidgetErrorHeader());
204
205        if (dialog.equals(PAGES[0])) {
206            // create the widgets for the first dialog page
207            result.append(createWidgetBlockStart(key(Messages.GUI_EDITOR_LABEL_SERVERTIME_BLOCK_0)));
208            result.append(createDialogRowsHtml(0, 0));
209            result.append(createWidgetBlockEnd());
210            result.append(createWidgetBlockStart(key(Messages.GUI_EDITOR_LABEL_JOBSETTINGS_BLOCK_0)));
211            result.append(createDialogRowsHtml(1, 5));
212            result.append(createWidgetBlockEnd());
213            result.append(createWidgetBlockStart(key(Messages.GUI_EDITOR_LABEL_CONTEXTINFO_BLOCK_0)));
214            result.append(createDialogRowsHtml(6, 12));
215            result.append(createWidgetBlockEnd());
216        } else if (dialog.equals(PAGES[1])) {
217            // create the widget for the second dialog page
218            result.append(createWidgetBlockStart(key(Messages.GUI_EDITOR_LABEL_PARAMETERS_BLOCK_0)));
219            result.append(createDialogRowsHtml(13, 13));
220            result.append(createWidgetBlockEnd());
221        }
222
223        // close widget table
224        result.append(createWidgetTableEnd());
225
226        return result.toString();
227    }
228
229    /**
230     * Creates the list of widgets for this dialog.<p>
231     */
232    @Override
233    protected void defineWidgets() {
234
235        // initialize the scheduled job object to use for the dialog
236        initScheduledJobObject();
237
238        // required to read the default values for the optional context parameters for the widgets
239        CmsContextInfo dC = new CmsContextInfo();
240
241        // add current server time
242        addWidget(new CmsWidgetDialogParameter(this, "serverTime", PAGES[0], new CmsDisplayWidget()));
243        // widgets to display on the first dialog page
244        addWidget(new CmsWidgetDialogParameter(m_jobInfo, "jobName", PAGES[0], new CmsInputWidget()));
245        addWidget(
246            new CmsWidgetDialogParameter(m_jobInfo, "className", PAGES[0], new CmsComboWidget(getComboClasses())));
247        addWidget(
248            new CmsWidgetDialogParameter(
249                m_jobInfo,
250                "cronExpression",
251                PAGES[0],
252                new CmsComboWidget(getComboCronExpressions())));
253        addWidget(new CmsWidgetDialogParameter(m_jobInfo, "reuseInstance", PAGES[0], new CmsCheckboxWidget()));
254        addWidget(new CmsWidgetDialogParameter(m_jobInfo, "active", PAGES[0], new CmsCheckboxWidget()));
255        addWidget(
256            new CmsWidgetDialogParameter(m_jobInfo, "contextInfo.userName", PAGES[0], new CmsUserWidget(null, null)));
257        addWidget(new CmsWidgetDialogParameter(m_jobInfo, "contextInfo.projectName", PAGES[0], new CmsInputWidget()));
258        addWidget(
259            new CmsWidgetDialogParameter(
260                m_jobInfo,
261                "contextInfo.siteRoot",
262                dC.getSiteRoot(),
263                PAGES[0],
264                new CmsVfsFileWidget(),
265                0,
266                1));
267        addWidget(
268            new CmsWidgetDialogParameter(
269                m_jobInfo,
270                "contextInfo.requestedUri",
271                dC.getRequestedUri(),
272                PAGES[0],
273                new CmsVfsFileWidget(),
274                0,
275                1));
276        addWidget(
277            new CmsWidgetDialogParameter(
278                m_jobInfo,
279                "contextInfo.localeName",
280                dC.getLocaleName(),
281                PAGES[0],
282                new CmsInputWidget(),
283                0,
284                1));
285        addWidget(
286            new CmsWidgetDialogParameter(
287                m_jobInfo,
288                "contextInfo.encoding",
289                dC.getEncoding(),
290                PAGES[0],
291                new CmsInputWidget(),
292                0,
293                1));
294        addWidget(
295            new CmsWidgetDialogParameter(
296                m_jobInfo,
297                "contextInfo.remoteAddr",
298                dC.getRemoteAddr(),
299                PAGES[0],
300                new CmsInputWidget(),
301                0,
302                1));
303
304        // widget to display on the second dialog page
305        addWidget(new CmsWidgetDialogParameter(m_jobInfo, "parameters", PAGES[1], new CmsInputWidget()));
306    }
307
308    /**
309     * Returns the example cron class names to show in the combo box.<p>
310     *
311     * The result list elements are of type <code>{@link org.opencms.widgets.CmsSelectWidgetOption}</code>.<p>
312     *
313     * @return the example cron class names to show in the combo box
314     */
315    protected List<CmsSelectWidgetOption> getComboClasses() {
316
317        List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>(16);
318        result.add(
319            new CmsSelectWidgetOption(
320                CmsInternalRelationsValidationJob.class.getName(),
321                false,
322                null,
323                key(Messages.GUI_EDITOR_CRONCLASS_INTERNALVALIDATION_0)));
324        result.add(
325            new CmsSelectWidgetOption(
326                CmsPublishJob.class.getName(),
327                false,
328                null,
329                key(Messages.GUI_EDITOR_CRONCLASS_PUBLISH_0)));
330        result.add(
331            new CmsSelectWidgetOption(
332                CmsStaticExportJob.class.getName(),
333                false,
334                null,
335                key(Messages.GUI_EDITOR_CRONCLASS_STATICEXPORT_0)));
336        result.add(
337            new CmsSelectWidgetOption(
338                CmsExternalLinksValidator.class.getName(),
339                false,
340                null,
341                key(Messages.GUI_EDITOR_CRONCLASS_POINTERVALIDATION_0)));
342        result.add(
343            new CmsSelectWidgetOption(
344                CmsMemoryMonitor.class.getName(),
345                false,
346                null,
347                key(Messages.GUI_EDITOR_CRONCLASS_MEMORYMONITOR_0)));
348        result.add(
349            new CmsSelectWidgetOption(
350                CmsSearchManager.class.getName(),
351                false,
352                null,
353                key(Messages.GUI_EDITOR_CRONCLASS_SEARCHINDEX_0)));
354        result.add(
355            new CmsSelectWidgetOption(
356                CmsContentNotificationJob.class.getName(),
357                false,
358                null,
359                key(Messages.GUI_EDITOR_CRONCLASS_CONTENTNOTIFICATION_0)));
360        result.add(
361            new CmsSelectWidgetOption(
362                CmsCreateImageSizeJob.class.getName(),
363                false,
364                null,
365                key(Messages.GUI_EDITOR_CRONCLASS_IMAGESIZE_0)));
366        result.add(
367            new CmsSelectWidgetOption(
368                CmsImageCacheCleanupJob.class.getName(),
369                false,
370                null,
371                key(Messages.GUI_EDITOR_CRONCLASS_IMAGE_CACHECLEAN_0)));
372        result.add(
373            new CmsSelectWidgetOption(
374                CmsHistoryClearJob.class.getName(),
375                false,
376                null,
377                key(Messages.GUI_EDITOR_CRONCLASS_CLEARHISTORY_0)));
378        result.add(
379            new CmsSelectWidgetOption(
380                CmsDeleteExpiredResourcesJob.class.getName(),
381                false,
382                null,
383                key(Messages.GUI_EDITOR_CRONCLASS_DELETEEXPIRED_0)));
384        result.add(
385            new CmsSelectWidgetOption(
386                CmsUnsubscribeDeletedResourcesJob.class.getName(),
387                false,
388                null,
389                key(Messages.GUI_EDITOR_CRONCLASS_UNSUBSCRIBEDELETED_0)));
390        return result;
391    }
392
393    /**
394     * Returns the example cron expressions to show in the combo box.<p>
395     *
396     * The result list elements are of type <code>{@link org.opencms.widgets.CmsSelectWidgetOption}</code>.<p>
397     *
398     * @return the example cron expressions to show in the combo box
399     */
400    protected List<CmsSelectWidgetOption> getComboCronExpressions() {
401
402        List<CmsSelectWidgetOption> result = new ArrayList<CmsSelectWidgetOption>();
403
404        // 0 0 3 * * ? (daily at 3 am)
405        result.add(new CmsSelectWidgetOption("0 0 3 * * ?", false, null, key(Messages.GUI_EDITOR_CRONJOB_EXAMPLE1_0)));
406        // 0 0/30 * * * ? (daily every thirty minutes)
407        result.add(
408            new CmsSelectWidgetOption("0 0/30 * * * ?", false, null, key(Messages.GUI_EDITOR_CRONJOB_EXAMPLE2_0)));
409        // 0 30 8 ? * 4 (every Wednesday at 8:30 am)
410        result.add(new CmsSelectWidgetOption("0 30 8 ? * 4", false, null, key(Messages.GUI_EDITOR_CRONJOB_EXAMPLE3_0)));
411        // 0 15 18 15 * ? (on the 20th day of the month at 6:15 pm)
412        result.add(
413            new CmsSelectWidgetOption("0 15 18 20 * ?", false, null, key(Messages.GUI_EDITOR_CRONJOB_EXAMPLE4_0)));
414        // 0 45 15 ? * 1 2007-2009 (every Sunday from the year 2007 to 2009 at 3:45 pm)
415        result.add(
416            new CmsSelectWidgetOption(
417                "0 45 15 ? * 1 2007-2009",
418                false,
419                null,
420                key(Messages.GUI_EDITOR_CRONJOB_EXAMPLE5_0)));
421        return result;
422    }
423
424    /**
425     * @see org.opencms.workplace.CmsWidgetDialog#getPageArray()
426     */
427    @Override
428    protected String[] getPageArray() {
429
430        return PAGES;
431    }
432
433    /**
434     * @see org.opencms.workplace.CmsWorkplace#initMessages()
435     */
436    @Override
437    protected void initMessages() {
438
439        // add specific dialog resource bundle
440        addMessages(Messages.get().getBundleName());
441        // add default resource bundles
442        super.initMessages();
443    }
444
445    /**
446     * Initializes the scheduled job object to work with depending on the dialog state and request parameters.<p>
447     *
448     * Three initializations of the scheduled job object on first dialog call are possible:
449     * <ul>
450     * <li>edit an existing scheduled job</li>
451     * <li>create a new scheduled job</li>
452     * <li>copy an existing scheduled job and edit it</li>
453     * </ul>
454     */
455    protected void initScheduledJobObject() {
456
457        Object o;
458
459        boolean setActive = false;
460
461        if (CmsStringUtil.isEmpty(getParamAction())
462            || CmsDialog.DIALOG_INITIAL.equals(getParamAction())
463            || DIALOG_COPYJOB.equals(getParamAction())) {
464            // this is the initial dialog call
465            if (CmsStringUtil.isNotEmpty(getParamJobid())) {
466                // edit or copy an existing job, get the job object from manager
467                CmsScheduledJobInfo job = OpenCms.getScheduleManager().getJob(getParamJobid());
468                // clone resets the active flag!
469                o = job.clone();
470                setActive = job.isActive();
471            } else {
472                // create a new job for the new job dialog
473                o = null;
474            }
475        } else {
476            // this is not the initial call, get the job object from session
477            o = getDialogObject();
478        }
479
480        if (!(o instanceof CmsScheduledJobInfo)) {
481            // create a new job info object
482            m_jobInfo = new CmsScheduledJobInfo();
483            m_jobInfo.setContextInfo(new CmsContextInfo());
484        } else {
485            // reuse job info object stored in session
486            m_jobInfo = (CmsScheduledJobInfo)o;
487        }
488
489        if (setActive) {
490            // initial call of edit an existing job, set active state of cloned job
491            m_jobInfo.setActive(true);
492        }
493
494        if (DIALOG_COPYJOB.equals(getParamAction())) {
495            // initial call of copy job action, clear the job id of the cloned job
496            m_jobInfo.clearId();
497        }
498    }
499
500    /**
501     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
502     */
503    @Override
504    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
505
506        // initialize parameters and dialog actions in super implementation
507        super.initWorkplaceRequestValues(settings, request);
508
509        // save the current state of the job (may be changed because of the widget values)
510        setDialogObject(m_jobInfo);
511    }
512
513    /**
514     * Checks if the new job dialog has to be displayed.<p>
515     *
516     * @return <code>true</code> if the new job dialog has to be displayed
517     */
518    protected boolean isNewJob() {
519
520        return getCurrentToolPath().equals("/scheduler/new");
521    }
522
523    /**
524     * @see org.opencms.workplace.CmsWidgetDialog#validateParamaters()
525     */
526    @Override
527    protected void validateParamaters() throws Exception {
528
529        if (!isNewJob()) {
530            // test if params are available
531            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(getParamJobid())) {
532                // validate the params
533                if (OpenCms.getScheduleManager().getJob(getParamJobid()) != null) {
534                    // params are ok!
535                    return;
536                }
537            }
538            // params are no valid
539            throw new Exception();
540        }
541    }
542}