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, 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.ui.report;
029
030import org.opencms.i18n.CmsEncoder;
031import org.opencms.ui.shared.rpc.I_CmsReportClientRpc;
032
033import java.io.ByteArrayOutputStream;
034import java.io.IOException;
035import java.io.OutputStream;
036import java.io.PrintStream;
037import java.io.UnsupportedEncodingException;
038
039/**
040 * Widget that can be used to view a running report that is not generated specifically by an OpenCms report thread,
041 * but from the text written to the stream provided by this widget.
042 */
043public class CmsStreamReportWidget extends CmsReportWidget {
044
045    /**
046     * Helper class which transfers the written data to the buffer of the report widget.
047     */
048    public class ReportStream extends ByteArrayOutputStream {
049
050        /**
051         * @see java.io.OutputStream#flush()
052         */
053        @SuppressWarnings("synthetic-access")
054        @Override
055        public void flush() {
056
057            // since we wrap a PrintStream with autoflush around this,
058            // flush is called after every line
059            synchronized (m_buffer) {
060                String content = "";
061                byte[] data = toByteArray();
062                try {
063                    content = new String(data, "UTF-8");
064                } catch (UnsupportedEncodingException e) {
065                    // ignore
066                }
067                m_buffer.append(content);
068                reset();
069                writeToDelegate(data);
070            }
071
072        }
073    }
074
075    /** Serial version id. */
076    private static final long serialVersionUID = 1L;
077
078    /** A second stream to write the data to. */
079    private OutputStream m_delegateStream;
080
081    /** Flag which signals that no further output will be written to the stream and that the report is finished. */
082    private boolean m_finish;
083
084    /** The buffer for the text which has been written to the stream, but not yet sent to the client. */
085    private StringBuilder m_buffer = new StringBuilder();
086
087    /** The stream whose input is written to the report. */
088    private PrintStream m_out;
089
090    /**
091     * Creates a new instance.
092     */
093    public CmsStreamReportWidget() {
094
095        super();
096
097        try {
098            m_out = new PrintStream(new ReportStream(), true, "UTF-8");
099        } catch (UnsupportedEncodingException e) {
100            // ignore
101        }
102    }
103
104    /**
105     * Call this after all output has been written to the stream.<p>
106     *
107     * This does not directly call the 'report finished' handlers, they will be only
108     * called after the next RPC call from the client which fetches the report updates.
109     */
110    public void finish() {
111
112        m_finish = true;
113    }
114
115    /**
116     * Gets the stream.
117     *
118     * @return the stream
119     */
120    public PrintStream getStream() {
121
122        return m_out;
123    }
124
125    /**
126     * @see org.opencms.ui.report.CmsReportWidget#requestReportUpdate()
127     */
128    @Override
129    public void requestReportUpdate() {
130
131        String content = "";
132        synchronized (m_buffer) {
133            content = m_buffer.toString();
134            m_buffer.setLength(0);
135        }
136        String html;
137        if ((content.length() == 0) && m_finish) {
138            html = null;
139            try {
140                runReportFinishedHandlers();
141            } catch (Exception e) {
142                // ignore
143            }
144        } else {
145            html = convertOutputToHtml(content);
146        }
147        getRpcProxy(I_CmsReportClientRpc.class).handleReportUpdate(html);
148    }
149
150    /**
151     * Sets a second stream to write the report output to (usually a log file).
152     *
153     * @param stream the second stream to write the data to
154     */
155    public void setDelegateStream(OutputStream stream) {
156
157        m_delegateStream = stream;
158    }
159
160    /**
161     * Converts the text stream data to HTML form.
162     *
163     * @param content the content to convert
164     * @return the HTML version of the content
165     */
166    private String convertOutputToHtml(String content) {
167
168        if (content.length() == 0) {
169            return "";
170        }
171        StringBuilder buffer = new StringBuilder();
172        for (String line : content.split("\n")) {
173            buffer.append(CmsEncoder.escapeXml(line) + "<br>");
174        }
175        return buffer.toString();
176    }
177
178    /**
179     * Writes data to delegate stream if it has been set.
180     *
181     * @param data the data to write
182     */
183    private void writeToDelegate(byte[] data) {
184
185        if (m_delegateStream != null) {
186            try {
187                m_delegateStream.write(data);
188            } catch (IOException e) {
189                throw new RuntimeException(e);
190            }
191        }
192    }
193
194}