001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.workplace;
029
030import org.opencms.file.CmsObject;
031import org.opencms.i18n.CmsMessageContainer;
032import org.opencms.jsp.CmsJspActionElement;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.report.A_CmsReportThread;
037import org.opencms.report.I_CmsReport;
038import org.opencms.util.CmsStringUtil;
039import org.opencms.util.CmsUUID;
040
041import javax.servlet.http.HttpServletRequest;
042import javax.servlet.http.HttpServletResponse;
043import javax.servlet.jsp.PageContext;
044
045import org.apache.commons.logging.Log;
046
047/**
048 * Provides an output window for a CmsReport.<p>
049 *
050 * @since 6.0.0
051 */
052public class CmsReport extends CmsMultiDialog {
053
054    /** Request parameter key for the type of the report. */
055    public static final String PARAM_REPORT_CONTINUEKEY = "reportcontinuekey";
056
057    /** Request parameter key for the type of the report. */
058    public static final String PARAM_REPORT_TYPE = "reporttype";
059
060    /** Max. byte size of report output on client. */
061    public static final int REPORT_UPDATE_SIZE = 512000;
062
063    /** Update time for report reloading. */
064    public static final int REPORT_UPDATE_TIME = 2000;
065
066    /** The log object for this class. */
067    private static final Log LOG = CmsLog.getLog(CmsReport.class);
068
069    /** Flag for refreching workplace .*/
070    private String m_paramRefreshWorkplace;
071
072    /** The key name which contains the localized message for the continue checkbox. */
073    private String m_paramReportContinueKey;
074
075    /** The type of this report. */
076    private String m_paramReportType;
077
078    /** The thread to display in this report. */
079    private CmsUUID m_paramThread;
080
081    /** The next thread to display after this report. */
082    private String m_paramThreadHasNext;
083
084    /**
085     * Public constructor.<p>
086     *
087     * @param jsp an initialized JSP action element
088     */
089    public CmsReport(CmsJspActionElement jsp) {
090
091        super(jsp);
092    }
093
094    /**
095     * Public constructor with JSP variables.<p>
096     *
097     * @param context the JSP page context
098     * @param req the JSP request
099     * @param res the JSP response
100     */
101    public CmsReport(PageContext context, HttpServletRequest req, HttpServletResponse res) {
102
103        this(new CmsJspActionElement(context, req, res));
104    }
105
106    /**
107     * Returns the style sheets for the report.<p>
108     *
109     * @param cms the current users context
110     * @return the style sheets for the report
111     */
112    public static String generateCssStyle(CmsObject cms) {
113
114        StringBuffer result = new StringBuffer(128);
115        result.append("<style type='text/css'>\n");
116        String contents = "";
117        try {
118            contents = new String(
119                cms.readFile(CmsWorkplace.VFS_PATH_COMMONS + "style/report.css").getContents(),
120                OpenCms.getSystemInfo().getDefaultEncoding());
121        } catch (Exception e) {
122            // ignore
123        }
124        if (CmsStringUtil.isEmpty(contents)) {
125            // css file not found, create default styles
126            result.append(
127                "body       { box-sizing: border-box; -moz-box-sizing: border-box; padding: 2px; margin: 0; color: /*begin-color WindowText*/#000000/*end-color*/; background-color: /*begin-color Window*/#ffffff/*end-color*/; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 11px; }\n");
128            result.append(
129                "div.main   { box-sizing: border-box; -moz-box-sizing: border-box; color: /*begin-color WindowText*/#000000/*end-color*/; white-space: nowrap; }\n");
130            result.append("span.head  { color: #000099; font-weight: bold; }\n");
131            result.append("span.note  { color: #666666; }\n");
132            result.append("span.ok    { color: #009900; }\n");
133            result.append("span.warn  { color: #990000; padding-left: 40px; }\n");
134            result.append("span.err   { color: #990000; font-weight: bold; padding-left: 40px; }\n");
135            result.append("span.throw { color: #990000; font-weight: bold; }\n");
136            result.append("span.link1 { color: #666666; }\n");
137            result.append("span.link2 { color: #666666; padding-left: 40px; }\n");
138            result.append("span.link2 { color: #990000; }\n");
139        } else {
140            result.append(contents);
141        }
142        result.append("</style>\n");
143        return result.toString();
144    }
145
146    /**
147     * Generates the footer for the extended report view.<p>
148     *
149     * @return html code
150     */
151    public static String generatePageEndExtended() {
152
153        StringBuffer result = new StringBuffer(128);
154        result.append("</div>\n");
155        result.append("</body>\n");
156        result.append("</html>\n");
157        return result.toString();
158    }
159
160    /**
161     * Generates the footer for the simple report view.<p>
162     *
163     * @return html code
164     */
165    public static String generatePageEndSimple() {
166
167        StringBuffer result = new StringBuffer(128);
168        result.append("</td></tr>\n");
169        result.append("</table></div>\n");
170        result.append("</body>\n</html>");
171        return result.toString();
172    }
173
174    /**
175     * Generates the header for the extended report view.<p>
176     *
177     * @param cms the current users context
178     * @param encoding the encoding string
179     *
180     * @return html code
181     */
182    public static String generatePageStartExtended(CmsObject cms, String encoding) {
183
184        StringBuffer result = new StringBuffer(128);
185        result.append("<html>\n<head>\n");
186        result.append("<meta HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=");
187        result.append(encoding);
188        result.append("'>\n");
189        result.append(generateCssStyle(cms));
190        result.append("</head>\n");
191        result.append("<body style='overflow: auto;'>\n");
192        result.append("<div class='main'>\n");
193        return result.toString();
194    }
195
196    /**
197     * Generates the header for the simple report view.<p>
198     *
199     * @param wp the workplace instance
200     *
201     * @return html code
202     */
203    public static String generatePageStartSimple(CmsWorkplace wp) {
204
205        StringBuffer result = new StringBuffer(128);
206        result.append("<html>\n<head>\n");
207        result.append("<meta HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=");
208        result.append(wp.getEncoding());
209        result.append("'>\n");
210        result.append("<link rel='stylesheet' type='text/css' href='");
211        result.append(wp.getStyleUri("workplace.css"));
212        result.append("'>\n");
213        result.append(generateCssStyle(wp.getCms()));
214        result.append("</head>\n");
215        result.append("<body style='background-color:/*begin-color Menu*/#f0f0f0/*end-color*/;'>\n");
216        result.append("<div style='vertical-align:middle; height: 100%;'>\n");
217        result.append("<table border='0' style='vertical-align:middle; height: 100%;'>\n");
218        result.append("<tr><td width='40' align='center' valign='middle'><img name='report_img' src='");
219        result.append(CmsWorkplace.getSkinUri());
220        result.append("commons/wait.gif' width='32' height='32' alt=''></td>\n");
221        result.append("<td valign='middle'>");
222        return result.toString();
223    }
224
225    /**
226     * Returns an initialized CmsReport instance that is read from the request attributes.<p>
227     *
228     * This method is used by dialog elements.
229     * The dialog elements do not initialize their own workplace class,
230     * but use the initialized instance of the "master" class.
231     * This is required to ensure that parameters of the "master" class
232     * can properly be kept on the dialog elements.<p>
233     *
234     * To prevent null pointer exceptions, an empty dialog is returned if
235     * nothing is found in the request attributes.<p>
236     *
237     * @param context the JSP page context
238     * @param req the JSP request
239     * @param res the JSP response
240     * @return an initialized CmsDialog instance that is read from the request attributes
241     */
242    public static CmsReport initCmsReport(PageContext context, HttpServletRequest req, HttpServletResponse res) {
243
244        CmsReport wp = (CmsReport)req.getAttribute(CmsWorkplace.SESSION_WORKPLACE_CLASS);
245        if (wp == null) {
246            // ensure that we don't get null pointers if the page is directly called
247            wp = new CmsReport(new CmsJspActionElement(context, req, res));
248        }
249        return wp;
250    }
251
252    /**
253     * Builds a button row with an "Ok", a "Cancel" and a "Details" button.<p>
254     *
255     * This row is displayed when the first report is running.<p>
256     *
257     * @param okAttrs optional attributes for the ok button
258     * @param cancelAttrs optional attributes for the cancel button
259     * @param detailsAttrs optional attributes for the details button
260     * @return the button row
261     */
262    public String dialogButtonsContinue(String okAttrs, String cancelAttrs, String detailsAttrs) {
263
264        if (CmsStringUtil.isEmptyOrWhitespaceOnly(detailsAttrs)) {
265            detailsAttrs = "";
266        } else {
267            detailsAttrs += " ";
268        }
269        return dialogButtons(
270            new int[] {BUTTON_OK, BUTTON_CANCEL, BUTTON_DETAILS},
271            new String[] {okAttrs, cancelAttrs, detailsAttrs + "onclick=\"switchOutputFormat();\""});
272    }
273
274    /**
275     * Builds a button row with an "Ok", a "Cancel" and a "Details" button.<p>
276     *
277     * This row is used when a single report is running or after the first report has finished.<p>
278     *
279     * @param okAttrs optional attributes for the ok button
280     * @param cancelAttrs optional attributes for the cancel button
281     * @param detailsAttrs optional attributes for the details button
282     * @return the button row
283     */
284    public String dialogButtonsOkCancelDetails(String okAttrs, String cancelAttrs, String detailsAttrs) {
285
286        if (CmsStringUtil.isEmptyOrWhitespaceOnly(detailsAttrs)) {
287            detailsAttrs = "";
288        } else {
289            detailsAttrs += " ";
290        }
291
292        if (Boolean.valueOf(getParamThreadHasNext()).booleanValue()
293            && CmsStringUtil.isNotEmpty(getParamReportContinueKey())) {
294            return dialogButtons(
295                new int[] {BUTTON_OK, BUTTON_CANCEL, BUTTON_DETAILS},
296                new String[] {okAttrs, cancelAttrs, detailsAttrs + "onclick=\"switchOutputFormat();\""});
297        }
298        return dialogButtons(
299            new int[] {BUTTON_OK, BUTTON_DETAILS},
300            new String[] {okAttrs, detailsAttrs + "onclick=\"switchOutputFormat();\""});
301    }
302
303    /**
304     * Returns if the workplace must be refreshed.<p>
305     *
306     * @return <code>"true"</code> if the workplace must be refreshed.
307     */
308    public String getParamRefreshWorkplace() {
309
310        return m_paramRefreshWorkplace;
311    }
312
313    /**
314     * Returns the key name which contains the localized message for the continue checkbox.<p>
315     *
316     * @return the key name which contains the localized message for the continue checkbox
317     */
318    public String getParamReportContinueKey() {
319
320        if (m_paramReportContinueKey == null) {
321            m_paramReportContinueKey = "";
322        }
323        return m_paramReportContinueKey;
324    }
325
326    /**
327     * Returns the type of this report.<p>
328     *
329     * @return the type of this report
330     */
331    public String getParamReportType() {
332
333        if (m_paramReportType == null) {
334            // the default report type is the simple report
335            setParamReportType(getSettings().getUserSettings().getWorkplaceReportType());
336        }
337
338        return m_paramReportType;
339    }
340
341    /**
342     * Returns the Thread id to display in this report.<p>
343     *
344     * @return the Thread id to display in this report
345     */
346    public String getParamThread() {
347
348        if ((m_paramThread != null) && (!m_paramThread.equals(CmsUUID.getNullUUID()))) {
349            return m_paramThread.toString();
350        } else {
351            return null;
352        }
353    }
354
355    /**
356     * Returns if another report is following this report.<p>
357     *
358     * @return <code>"true"</code> if another report is following this report
359     */
360    public String getParamThreadHasNext() {
361
362        if (m_paramThreadHasNext == null) {
363            m_paramThreadHasNext = "";
364        }
365        return m_paramThreadHasNext;
366    }
367
368    /**
369     * Returns the part of the report that is ready for output.<p>
370     *
371     * @return the part of the report that is ready for output
372     */
373    public String getReportUpdate() {
374
375        A_CmsReportThread thread = OpenCms.getThreadStore().retrieveThread(m_paramThread);
376        if (thread != null) {
377            return thread.getReportUpdate();
378        } else {
379            return "";
380        }
381    }
382
383    /**
384     * Returns if the report generated an error output.<p>
385     *
386     * @return true if the report generated an error, otherwise false
387     */
388    public boolean hasError() {
389
390        A_CmsReportThread thread = OpenCms.getThreadStore().retrieveThread(m_paramThread);
391        if (thread != null) {
392            return thread.hasError();
393        } else {
394            return false;
395        }
396    }
397
398    /**
399     * Builds the start html of the page, including setting of DOCTYPE and
400     * inserting a header with the content-type.<p>
401     *
402     * This overloads the default method of the parent class.<p>
403     *
404     * @return the start html of the page
405     */
406    @Override
407    public String htmlStart() {
408
409        return pageHtml(HTML_START, true);
410    }
411
412    /**
413     * Builds the start html of the page, including setting of DOCTYPE and
414     * inserting a header with the content-type.<p>
415     *
416     * This overloads the default method of the parent class.<p>
417     *
418     * @param loadStyles if true, the defaul style sheet will be loaded
419     * @return the start html of the page
420     */
421    public String htmlStart(boolean loadStyles) {
422
423        return pageHtml(HTML_START, loadStyles);
424    }
425
426    /**
427     * Returns true if the report Thread is still alive (i.e. running), false otherwise.<p>
428     *
429     * @return true if the report Thread is still alive
430     */
431    public boolean isAlive() {
432
433        A_CmsReportThread thread = OpenCms.getThreadStore().retrieveThread(m_paramThread);
434        if (thread != null) {
435            return thread.isAlive();
436        } else {
437            return false;
438        }
439    }
440
441    /**
442     * Checks whether this is a simple report.<p>
443     *
444     * @return true, if the type of this report is a "simple"
445     */
446    public boolean isSimpleReport() {
447
448        return getParamReportType().equalsIgnoreCase(I_CmsReport.REPORT_TYPE_SIMPLE);
449    }
450
451    /**
452     * Builds the start html of the page, including setting of DOCTYPE and
453     * inserting a header with the content-type.<p>
454     *
455     * This overloads the default method of the parent class.<p>
456     *
457     * @param segment the HTML segment (START / END)
458     * @param loadStyles if true, the defaul style sheet will be loaded
459     * @return the start html of the page
460     */
461    public String pageHtml(int segment, boolean loadStyles) {
462
463        if (useNewStyle()) {
464            return super.pageHtml(segment, null, getParamTitle());
465        }
466        if (segment == HTML_START) {
467            StringBuffer result = new StringBuffer(512);
468            result.append("<!DOCTYPE html>\n");
469            result.append("<html>\n<head>\n");
470            result.append("<meta HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=");
471            result.append(getEncoding());
472            result.append("\">\n");
473            if (loadStyles) {
474                result.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"");
475                result.append(getStyleUri(getJsp(), "workplace.css"));
476                result.append("\">\n");
477                result.append("<script >\n");
478                result.append(dialogScriptSubmit());
479                result.append("</script>\n");
480            }
481            return result.toString();
482        } else {
483            return "</html>";
484        }
485
486    }
487
488    /**
489     * Returns an optional conclusion text to be displayed below the report output.<p>
490     *
491     * @return an optional conclusion text
492     */
493    public String reportConclusionText() {
494
495        return "";
496    }
497
498    /**
499     * Returns an optional introduction text to be displayed above the report output.<p>
500     *
501     * @return an optional introduction text
502     */
503    public String reportIntroductionText() {
504
505        return "";
506    }
507
508    /**
509     * Sets  if the workplace must be refreshed.<p>
510     *
511     * @param value <code>"true"</code> (String) if the workplace must be refreshed.
512     */
513    public void setParamRefreshWorkplace(String value) {
514
515        m_paramRefreshWorkplace = value;
516    }
517
518    /**
519     * Sets the key name which contains the localized message for the continue checkbox.<p>
520     *
521     * @param key the key name which contains the localized message for the continue checkbox
522     */
523    public void setParamReportContinueKey(String key) {
524
525        m_paramReportContinueKey = key;
526    }
527
528    /**
529     * Sets the type of this report.<p>
530     *
531     * @param value the type of this report
532     */
533    public void setParamReportType(String value) {
534
535        m_paramReportType = value;
536    }
537
538    /**
539     * Sets the Thread id to display in this report.<p>
540     *
541     * @param value the Thread id to display in this report
542     */
543    public void setParamThread(String value) {
544
545        m_paramThread = CmsUUID.getNullUUID();
546        if (value != null) {
547            try {
548                m_paramThread = new CmsUUID(value);
549            } catch (Exception e) {
550                // can usually be ignored
551                if (LOG.isInfoEnabled()) {
552                    LOG.info(
553                        Messages.get().getBundle().key(Messages.LOG_THREAD_CREATION_FAILED_1, Integer.valueOf(value)),
554                        e);
555                }
556            }
557        }
558    }
559
560    /**
561     * Sets if another report is following this report.<p>
562     *
563     * @param value <code>"true"</code> if another report is following this report
564     */
565    public void setParamThreadHasNext(String value) {
566
567        m_paramThreadHasNext = value;
568    }
569
570    /**
571     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, javax.servlet.http.HttpServletRequest)
572     */
573    @Override
574    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
575
576        // fill the parameter values in the get/set methods
577        fillParamValues(request);
578        // set the action for the JSP switch
579        if (REPORT_UPDATE.equals(getParamAction())) {
580            setAction(ACTION_REPORT_UPDATE);
581        } else {
582            setAction(ACTION_REPORT_BEGIN);
583        }
584    }
585
586    /**
587     * Returns always true and does nothing else, has to be implemented.<p>
588     *
589     * @see org.opencms.workplace.CmsMultiDialog#performDialogOperation()
590     */
591    @Override
592    protected boolean performDialogOperation() throws CmsException {
593
594        throw new CmsException(new CmsMessageContainer(null, ""));
595    }
596}