KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > tigris > scarab > screens > DataExport


1 package org.tigris.scarab.screens;
2
3 /* ================================================================
4  * Copyright (c) 2003 CollabNet. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowlegement: "This product includes
19  * software developed by CollabNet <http://www.collab.net/>."
20  * Alternately, this acknowlegement may appear in the software itself, if
21  * and wherever such third-party acknowlegements normally appear.
22  *
23  * 4. The hosted project names must not be used to endorse or promote
24  * products derived from this software without prior written
25  * permission. For written permission, please contact info@collab.net.
26  *
27  * 5. Products derived from this software may not use the "Tigris" or
28  * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
29  * prior written permission of CollabNet.
30  *
31  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34  * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
35  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
39  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
40  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  *
43  * ====================================================================
44  *
45  * This software consists of voluntary contributions made by many
46  * individuals on behalf of CollabNet.
47  */

48
49 import java.io.Writer JavaDoc;
50 import java.io.IOException JavaDoc;
51 import java.io.PrintWriter JavaDoc;
52 import java.io.OutputStreamWriter JavaDoc;
53 import java.util.List JavaDoc;
54
55 import org.apache.commons.lang.StringUtils;
56
57 import org.apache.turbine.Turbine;
58 import org.apache.turbine.RunData;
59 import org.apache.turbine.TemplateContext;
60
61 import org.tigris.scarab.util.ScarabUtil;
62 import org.tigris.scarab.util.export.ExportFormat;
63
64
65 /**
66  * <p>Sends file contents directly to the output stream, setting the
67  * <code>Content-Type</code> and writing back to the browser a
68  * tab-delimited file (Excel digests this fine). We used to use <a
69  * HREF="http://jakarta.apache.org/poi/">POI</a> to compose an Excel
70  * binary data file, but its outrageous memory consumption didn't
71  * scale for large result sets. POI assembles the its output in
72  * memory. After study of the native OLE2 Excel file format, it
73  * appears very difficult to generate the file in another fashion.</p>
74  *
75  * <p>Regards output encoding, for now we're assuming the response
76  * stream is appropriately set upon fetching. Also, we're assuming
77  * that Excel will do the right thing on receipt of our TSV file with
78  * Japanese or other multibyte characters (we're not setting an
79  * encoding on the <code>Content-Type</code> we return). Both of the
80  * above to be verified.</p>
81  *
82  * @author <a HREF="mailto:jmcnally@collab.net">John McNally</a>
83  * @author <a HREF="mailto:stack@collab.net">St.Ack</a>
84  * @author <a HREF="mailto:dlr@collab.net">Daniel Rall</a>
85  * @since Scarab 1.0
86  */

87 class DataExport extends Default
88 {
89     /**
90      * What to show if a cell is empty. The empty string is dealt
91      * with best by spreadsheet applications.
92      */

93     protected static final String JavaDoc NO_CONTENT = "";
94
95     /**
96      * Sets the <code>Content-Type</code> header for the response.
97      * Since this assumes we're writing the reponse ourself, indicates
98      * no target to render by setting it to <code>null</code>.
99      */

100     public void doBuildTemplate(RunData data, TemplateContext context)
101         throws Exception JavaDoc
102     {
103         super.doBuildTemplate(data, context);
104         String JavaDoc format = ScarabUtil.findValue(data, ExportFormat.KEY_NAME);
105
106         // look for a configuration toggle for the encoding to which to
107
// export. TODO : make this per request configurable (with a per-
108
// language default) to allow use of scarab in a multilingual
109
// environment.
110
if (ExportFormat.EXCEL_FORMAT.equalsIgnoreCase(format))
111         {
112             data.getResponse().setContentType("application/vnd.ms-excel");
113         }
114         else
115         {
116             // we want to set a charset on the response -- so clients
117
// can detect it properly -- if we have a known encoding
118
String JavaDoc encoding = getEncodingForExport(data);
119             String JavaDoc contentType = "text/plain";
120             if (encoding != null && !encoding.equals(""))
121             {
122                 contentType = contentType + "; charset=" + encoding;
123             }
124             data.getResponse().setContentType(contentType);
125         }
126         // Since we're streaming the TSV content directly from our
127
// data source, we don't know its length ahead of time.
128
//data.getResponse().setContentLength(?);
129

130         // FIXME: Provide work hooks here...
131
//TSVPrinter printer = new TSVPrinter(data.getResponse().getWriter());
132
//writeHeading(printer, mitlist, l10n, rmuas);
133
//writeRows(printer, mitlist, l10n, scarabR, rmuas);
134

135         // Above we sent the response, so no target to render
136
data.setTarget(null);
137     }
138
139     /**
140      * This function encapsulates the logic of determining which encoding
141      * to use. Right now, the encoding isn't per-request, but that should
142      * be changed.
143      */

144     protected String JavaDoc getEncodingForExport(RunData data)
145     {
146         String JavaDoc encoding = Turbine.getConfiguration()
147             .getString("scarab.dataexport.encoding");
148         return encoding;
149     }
150
151     /**
152      * This function is available to subclasses -- it is used to provide
153      * a Writer based on the current request and the site configuration,
154      * taking encoding issues into consideration.
155      */

156     protected Writer JavaDoc getWriter(RunData data)
157         throws IOException JavaDoc
158     {
159         Writer JavaDoc writer = null;
160         String JavaDoc encoding = getEncodingForExport(data);
161         if (encoding != null && !encoding.equals(""))
162         {
163             writer =
164                 new OutputStreamWriter JavaDoc(data.getResponse().getOutputStream(),
165                                        encoding);
166         }
167         else
168         {
169             writer = data.getResponse().getWriter();
170         }
171         return writer;
172     }
173
174     /**
175      * Escape any commas in passed string.
176      *
177      * @param s String to check.
178      * @return Passed string with commas escaped.
179      */

180     protected String JavaDoc escapeCommas(String JavaDoc s)
181     {
182         // Not sure how to escape commas. What to use instead? Quote
183
// for now.
184
return quote(s);
185     }
186
187     protected final boolean containsElements(List JavaDoc l)
188     {
189         return l != null && !l.isEmpty();
190     }
191
192     /**
193      * Quote the string argument.
194      *
195      * @param s Text to quote.
196      * @return Passed string, quoted.
197      */

198     private static String JavaDoc quote(String JavaDoc s)
199     {
200         return '"' + StringUtils.replace(s, "\"", "\"\"") + '"';
201     }
202
203     /**
204      * Uses a <code>PrintWriter</code> internally to do actual
205      * writing. If content with tabs and newlines in it is
206      * double-quoted, Excel does the Right Thing when parsing.
207      *
208      * @see <a HREF="http://ostermiller.org/utils/ExcelCSVPrinter.java.htm">ExcelCSVPrinter.java</a>
209      */

210     protected class TSVPrinter
211     {
212         /**
213          * Flag indicating start of a new line.
214          */

215         private boolean lineStart = true;
216
217         /**
218          * Printer write on.
219          */

220         private PrintWriter JavaDoc printer = null;
221
222         /**
223          * Creates a new instance.
224          *
225          * @param writer Writer to output to.
226          * @throws IllegalArgumentException If <code>writer</code> is
227          * <code>null</code>.
228          */

229         public TSVPrinter(Writer JavaDoc writer)
230         {
231             if (writer == null)
232             {
233                 //TODO [HD] Shouldn't this be better a NPE ?
234
// That better hits the truth...
235
throw new IllegalArgumentException JavaDoc
236                     ("TSVPrinter constructor requires a non-null writer"); //EXCEPTION
237
}
238             
239             if (writer instanceof PrintWriter JavaDoc)
240             {
241                 this.printer = (PrintWriter JavaDoc) writer;
242             }
243             else
244             {
245                 this.printer = new PrintWriter JavaDoc(writer);
246             }
247         }
248
249         /**
250          * Prints one field at a time.
251          */

252         public void print(String JavaDoc s)
253         {
254             if (!lineStart)
255             {
256                 // Print a tab seperator before we print our field content.
257
printer.print('\t');
258             }
259             lineStart = false;
260
261             if (StringUtils.isNotEmpty(s))
262             {
263                 printer.print(escape(s));
264             }
265         }
266
267         /**
268          * Must be called when done writing a line -- this prints a newline
269          * and flushes the printer.
270          */

271         public void println()
272         {
273             printer.println();
274             printer.flush();
275             lineStart = true;
276         }
277
278         /**
279          * Quote the string argument.
280          *
281          * @param s Text to quote.
282          * @return Passed string, quoted.
283          */

284         protected String JavaDoc quote(String JavaDoc s)
285         {
286             return DataExport.quote(s);
287         }
288
289         /**
290          * If the passed string has any problematic characters, quote the
291          * whole thing after escaping any quotes already present. Excel
292          * does the right thing parsing if it gets quoted content.
293          *
294          * @param s String to escape.
295          * @return An escaped version of the passed string.
296          */

297         private String JavaDoc escape(String JavaDoc s)
298         {
299             if (StringUtils.isNotEmpty(s))
300             {
301                 for (int i = 0; i < s.length(); i++)
302                 {
303                     char c = s.charAt(i);
304                     if (c == '"' || c == '\t' || c == '\n' || c == '\r')
305                     {
306                         s = quote(s);
307                         break;
308                     }
309                 }
310             }
311
312             return s;
313         }
314     }
315 }
316
Popular Tags