Embedded (Inline) Excel Workbook Generation from DataModel of a Page-Scoped Seam Component
sgurevich Jul 14, 2009 5:39 PMI'm trying to conditionally generate a workbook from a results section, Richfaces tab panel really, of a search page. Seam's excel library examples provide clearly documented use of generating a workbook from either a standalone page or invoking Javascript that converts
an existing data table. In this case, the table of results, a Richfaces data table, contains a summarized set of data. The full data set must be exported to the spreadsheet. The same data model that is used to build the web-based table is also used to generate the workbook. The component that contains the data model is of page scope.
Code Snippets
Seam component:
@Name("search") @Scope(ScopeType.PAGE) @AutoCreate public class searchAction { ... @DataModel private List<Result> results; private boolean excelExport; ... public List<Result> getResults () { return results; } public void setResults (List<Result> results) { this.results = results; } public boolean isExcelExport () { return excelExport; } public void setExcelExport (boolean excelExport) { this.excelExport = excelExport; } }
JSF Page:
<rich:dataTable id="resultsTable" value="#{search.results}" var="result" width="100%"> <rich:column sortBy="#{result.meId}"> <f:facet name="header"> <h:outputText value="#{messages['results.column.me_id']}" /> </f:facet> <h:outputText value="#{result.meId}" /> </rich:column> ... </rich:dataTable> ... <a4j:commandLink value="Export to Excel" action="#{search.setExcelExport(true)}" reRender="excelExportRegion" ajaxSingle="true" status="doNothingStatus" /> <a4j:region id="excelExportRegion" renderRegionOnly="true" rendered="#{search.excelExport}"> <a4j:status id="doNothingStatus" /> <e:workbook> <e:worksheet value="#{search.results}" var="result"> <e:column> <f:facet name="header"> <e:cell value="#{messages['results.column.me_id']}" /> </f:facet> <e:cell value="#{result.meId}" /> </e:column> </e:worksheet> </e:workbook> </a4j:region> </h:form> </rich:tab> </rich:tabPanel> </ui:define> </ui:composition>
You can imagine the hierarchy of the page from the terminating tags. The page is a part of a JSF template. The region isolates the rerender to activate the workbook construction and download. The status that does nothing is there to avoid leaving the top-level status from spinning indefinitely once the download begins. The result of this code produces an Excel file that contains only the (correct) header value. The single data row that is present in the web-based data table is not being rendered on the worksheet. I have used a debugger to verify that the list identified as a DataModel (results), which is used to satisfy the ajax call to rerender the workbook region, does contain the single result element, as expected, since we are still on the same page.
Environment
Jetty (Maven Plugin) 6.1.10 running on JDK 1.6.0_13
Library Dependencies
<dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-el</artifactId> <version>2.0.0.GA</version> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam</artifactId> <version>2.1.1.GA</version> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam-ui</artifactId> <version>2.1.1.GA</version> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam-ioc</artifactId> <version>2.1.1.GA</version> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam-debug</artifactId> <version>2.1.1.GA</version> </dependency> <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-seam-excel</artifactId> <version>2.1.1.GA</version> </dependency> <dependency> <groupId>jboss</groupId> <artifactId>jboss-common</artifactId> <version>4.2.2.GA</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>1.2_12</version> </dependency> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-impl</artifactId> <version>1.2_12</version> </dependency> <dependency> <groupId>com.sun.facelets</groupId> <artifactId>jsf-facelets</artifactId> <version>1.1.14</version> </dependency> <dependency> <groupId>org.richfaces.framework</groupId> <artifactId>richfaces-api</artifactId> <version>3.3.1.BETA3</version> </dependency> <dependency> <groupId>org.richfaces.framework</groupId> <artifactId>richfaces-impl</artifactId> <version>3.3.1.BETA3</version> </dependency> <dependency> <groupId>org.richfaces.ui</groupId> <artifactId>richfaces-ui</artifactId> <version>3.3.1.BETA3</version> </dependency> <dependency> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency>
Side Notes
- I can access the results DataModel directly, since results becomes a named component by virtue of the DataModel annotation, but I'd rather not have component names just popping up in the XHTML without a context. Seam's proxy still wraps the DataModelList around my list successful when called this way and I've confirmed the outcome with the workbook is the same when using just results in place of search.results.
- I realize that once the excelExport flag turns to true, it will always be true, but that's not a problem in this case as the tab panel is client-side rendered and the excelExportRegion is only rerendered when the Export to Excel link is clicked. BTW, yes the link is just temporary and its text will come from a resource bundle as everything else on the page. ;-)
Hopefully, I've provided enough detail while at the same time pruning and abbreviating the excess to convey my problem. I have tried upgrading to Seam version 2.1.2 for all Seam libraries, but ran into the java.lang.IllegalAccessError: tried to access class javassist.bytecode.StackMapTable$Writer from class org.jboss.seam.util.ProxyFactory
problem. I have found some suggestions to avoid this problem by declaring an explicit javaassist dependency version, but decided to revert to the working version and tackle the non-trivial upgrade at a different time. I would certainly upgrade, if that is the solution to this problem; however, there is no documentation that would suggest so at this time and I would rather not get side-tracked by an upgrading discussion.
Greatly appreciate suggestions toward a solution for the problem of generating an inline workbook by simply rerendering a portion of the page.
Sean