| Feedback from Standalone Client Implementation [message #1116016] |
Tue, 24 September 2013 18:24  |
Chris Monty Messages: 18 Registered: July 2013 |
Junior Member |
|
|
I just completed a small standalone project which in essence, runs as a desktop application. Jeramie mentioned that feedback would be welcome, so here it is.
Features:- Single user, no authentication, no server (offline implementation)
Since this is a desktop application, a server is unnecessary.
- Custom DB driver (Derby v 10.10.1.1)
I chose Derby because it's portable and stand-alone (no db installation required). I chose version 10.10.1.1 because it supports sequences. I bundled the derby database folder in with the client .zip. Installation is as simple as download, unzip and run.
- Jasper Reports integration
Because the ReportingService shares its connection with the Jasper reporting engine, it's possible to create reports from a database (like Derby) which only supports a single connection.
- Docx4j integration
Just for 'screen scraping' tables into an Excel document.
I had some trouble creating my own derby jdbc connector bundle, even with the help of the tutorial. Most of my time was spent here resolving package import problems. I think that for making your own jdbc bundle you a) have to be well versed with eclipse plugin project architecture, or b) will be by the time you get it working.
Once the whole thing compiled, I faced some issues with the new Sql Style. I had copied the old DerbySqlStyle.java and AbstractDerbySqlService.java, but was having problems with decimals. It seems in Derby, decimal values are typed as java.sql.Types.DOUBLE. The default implementation of org.eclipse.scout.rt.server.services.common.jdbc.style.AbstractSqlStyle.writeBind() supports only DECIMAL and NUMERIC, and refers DOUBLE types to writeDefaultBind() which truncates decimals.
My ugly-but-functional fix is to subclass AbstractSqlStyle and override writeBind() as so:
@Override
public void writeBind(PreparedStatement ps, int jdbcBindIndex, SqlBind bind)
throws SQLException {
switch (bind.getSqlType()) {
case Types.DOUBLE:
// explicit handling for DOUBLE types. The default DOUBLE handling from AbstractSQLService
// does not explicitly specify a scale.
if (bind.getValue() instanceof Double) {
Double value = ((Double)bind.getValue());
// figure out the scale by counting the number of digits after the decimal point
String strVal = value.toString();
int decimalIndex = strVal.indexOf('.');
int scale = (decimalIndex > 0)?(strVal.length() - decimalIndex - 1):0;
// I never need more than 3 decimal places.
if (scale > 3) {
scale = 3;
}
ps.setObject(jdbcBindIndex, value, bind.getSqlType(), scale);
}
break;
default:
super.writeBind(ps, jdbcBindIndex, bind);
}
}
I realised at installation test that my application runs only on 64-bit Windows (not 32-bit). This surprised me, being Java and all. My development environment is 64-bit, as is my version of Java 7. Does anyone know how to remove this constraint?
One final snag I hit was with my Jasper report, which I implemented according to this tutorial. I have a report which has a sub-report. I'm able to load the report as a ByteArrayInputStream, but the report then tries to load the sub-report itself, which it can't find of course. To make matters worse, the report location in my deployment build is inside the plugins folder, which takes on a dynamic name. I've worked around this by making a configuration key with a value like.\\plugins\\<packagename>_<version>.<timestamp>\\reports\\ which gets passed into the report as a parameter (I have to manually update this after each deploy) but it's hardly elegant. Does anyone know how I might find the reports folder at runtime?
But otherwise it's a nice little desktop app.
|
|
|
| Re: Feedback from Standalone Client Implementation [message #1116479 is a reply to message #1116016] |
Wed, 25 September 2013 10:01   |
Nils Israel Messages: 23 Registered: May 2010 |
Junior Member |
|
|
Hi Chris,
it is possible to load the subreport the same way as the master report and add the compiled subreport as a parameter:
@Override
public byte[] createCompanyReport(Long companyID) throws ProcessingException {
JasperPrint jasperPrint;
// create a map to pass parameters to the report
HashMap<String, Object> parameter = new HashMap<String, Object>();
parameter.put("COMPANY_NR", companyID);
try {
// load the report from the reports plugin
URL url = new URL("platform:/plugin/org.eclipse.scout.minicrm.reports/reports/company.jrxml");
InputStream inputStream = url.openConnection().getInputStream();
// compile the report
JasperReport report = JasperCompileManager.compileReport(inputStream);
// load the subreport from the reports plugin
URL urlSubreport = new URL("platform:/plugin/org.eclipse.scout.minicrm.reports/reports/subreport.jrxml");
InputStream inputStreamSubreport = urlSubreport.openConnection().getInputStream();
// compile the subreport
JasperReport subreport = JasperCompileManager.compileReport(inputStreamSubreport);
parameter.put("mySubreport", subreport);
// let Jasper Reports use our already defined SQL Connection
jasperPrint = JasperFillManager.fillReport(report, parameter, SQL.getConnection());
// don't create a file but let jasper put the contents in an byte array
ByteArrayOutputStream ba = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint, ba);
// return the contents to the caller
return ba.toByteArray();
}
catch (JRException e) {
throw new ProcessingException("An error occured during the creation of the report.", e);
}
catch (MalformedURLException e) {
throw new ProcessingException("Can't load the report file.", e);
}
catch (IOException e) {
throw new ProcessingException("An IO-error occured while reading the report file.", e);
}
}
To use the subreport you have to add the parameter
<parameter name="mySubreport" class="net.sf.jasperreports.engine.JasperReport"/>
to the master report and and replace the subreportExpression
<subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{mySubreport}]]></subreportExpression>
Kind regards,
Nils
|
|
|
|
|
| Re: Feedback from Standalone Client Implementation [message #1119365 is a reply to message #1117095] |
Sat, 28 September 2013 07:07  |
Chris Monty Messages: 18 Registered: July 2013 |
Junior Member |
|
|
Hi Jeremie, thanks for the response.
Until now I was using the Scout export wizard which automagically does everything. But now that you've asked, I also discovered the Eclipse product export wizard and tried it. I found a tutorial about Products and Deployment, which was helpful.
I tried rewinding the jre from JavaSE-1.7 to JavaSE-1.6 - just in case it was my x64 installation Java 7. I found that when exporting a jre with the application, java rejects all but 64-bit versions with an error message on startup: Quote:Failed to load the JNI shared Library (...JDK)
Searches on stackoverflow indicate this might lie with the version of eclipse I'm using. Is there a way to generate a 32-bit compatible application, or should I try installing a 32-bit of Eclipse? Or should I look to Maven or PDE for a solution?
|
|
|
Powered by
FUDForum. Page generated in 0.01854 seconds