|
|
Hi guys
I am donating a CSV component if anyone wants it... when used, it allows
you to render a link that when clicked will return a CSV
(comma-seperated value) dump of a 2 dimensional array that you pass in.
Interesting sidebar: csv dumps whose first row, and first cell, contain
'ID' (without quotes, in capital letters) will cause Excel on OS X to
freak out and die. 'Id','id', all work fine..
ANYWAY!
I'll post it somewhere like Tacos eventually,but I'm sure it might stand
some improvement/feedback and I'm somewhat pressed for time.
I'm licensing it under the do-whatever-you-want-with-it-but-remember
your-old-pal-Josh-when-you-win-the-lottery-or-make-cool-changes-to-it
license.
Joshua Long
josh@xxxxxxxxxxxx
Code, documentation follow
to get it working int he application, of course, put the following in
the application specification
<service name="com.roartechnologies.ap.view.services.csv-service"
class="com.roartechnologies.ap.view.services.CSVService"/>
Anyway, here are the various cogs of the machine...
/// first the component class....
package com.roartechnologies.ap.view.components.csv;
import com.roartechnologies.ap.view.services.CSVService;
import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;
/**
* @author Joshua Long (josh@xxxxxxxxxxxx)
*
* Builds a request to our CSVService, which in turn
* does the heavy lifting of generating
* the actual dump.
*
* This follows a pretty standard idiom
* as set forth in <i>Tapestry In Action</i>
*
*/
public abstract class CSVComponent extends AbstractComponent {
public abstract Object getMap();
public abstract void setMap(Object mp);
public abstract Boolean getDisabled();
public abstract void setDisabled(Boolean mp);
protected void renderComponent(IMarkupWriter writer,
IRequestCycle cycle) {
if (cycle.isRewinding())
return;
Boolean disabled = getDisabled();
if (disabled != null) {
if (disabled.booleanValue()) {
writer.begin("span");
writer.attribute("class", "csv_disabled");
renderInformalParameters(writer, cycle);
writer.printRaw("CSV");
writer.end();
return ;
}
}
Object map = getMap();
if (null == map)
Tapestry.createRequiredParameterException(this, "map");
String key = Long.toString(System.currentTimeMillis());
cycle.getRequestContext().getSession().setAttribute(key, map);
IEngineService service =
cycle.getEngine().getService(CSVService.SERVICE_NAME);
ILink link = service.getLink(cycle, this, new Object[]{key});
String url = link.getURL();
writer.begin("a");
writer.attribute("class", "csv_enabled");
writer.attribute("href", url);
renderInformalParameters(writer, cycle);
writer.printRaw("CSV");
writer.end();
}
}
// next the backend service
package com.roartechnologies.ap.view.services;
import com.generationjava.io.CsvWriter;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.AbstractService;
import org.apache.tapestry.engine.IEngineServiceView;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.request.RequestContext;
import org.apache.tapestry.request.ResponseOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.MessageFormat;
import java.util.Date;
/**
* @author Joshua Long (josh@xxxxxxxxxxxx)
* <p/>
* The service takes the key passed in from
* the component and uses it to lookup the dump
* in a known place and then it generates the actual dump.
* <p/>
* This component uses the <i>Generation Java CSV </i>
* component to generate the CSV response stream.
* <p/>
* I am not too sure where to find it,
* but it's worked wonders for me and I completely recommend it.
*/
public class CSVService extends AbstractService {
public static final String SERVICE_NAME =
"com.roartechnologies.ap.view.services.csv-service";
public String getName() {
return SERVICE_NAME;
}
public void service(IEngineServiceView service_view,
IRequestCycle cycle,
ResponseOutputStream os) throws
ServletException, IOException {
Object[] params = getParameters(cycle);
String key = (String) params[0];
HttpSession session = cycle.getRequestContext().getSession();
Object mp = session.getAttribute(key);
if (null == mp) {
System.out.println(MessageFormat.format("There is no key
with value {0} exiting @ {1,date,long}", new Object[]{key, new
Date()}));
}
Object[][] rows_array = (Object[][]) mp;
RequestContext context = cycle.getRequestContext();
HttpServletResponse response = context.getResponse();
String dispositionHeader =
MessageFormat.format("attachment;filename=report_{0}.csv",
new
Object[]{Long.toString(System.currentTimeMillis())});
response.setHeader("Content-Disposition", dispositionHeader);
os.setContentType("application/vnd.ms-excel");
/* "text/comma-separated-values");*/
CsvWriter csv_writer = new CsvWriter(new
OutputStreamWriter(os));
for (int i = 0; i < rows_array.length; i++) {
Object row [] = rows_array[i];
String[] string_row = new String[row.length];
for (int a = 0; a < row.length; a++) {
string_row[a] = row[a] == null ? "" : row[a].toString();
}
csv_writer.writeLine(string_row);
}
csv_writer.close();
}
public ILink getLink(IRequestCycle iRequestCycle, IComponent
iComponent, Object[] objects) {
return constructLink(iRequestCycle, SERVICE_NAME, null, objects,
false);
}
}
/// now, finally, the specification..
<!DOCTYPE component-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
<component-specification
class="com.roartechnologies.ap.view.components.csv.CSVComponent"
allow-body="yes"
allow-informal-parameters="yes">
<parameter name="map"
direction="in"
required="yes"
type="java.lang.Object"/>
<parameter name="disabled"
direction="in"
required="no"
type="java.lang.Boolean"/>
<reserved-parameter name="href"/>
</component-specification>
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@xxxxxxxxxxxxxxxxxx
For additional commands, e-mail: tapestry-user-help@xxxxxxxxxxxxxxxxxx
|
|