RSS

Monthly Archives: February 2012

Integrate zxing barcode scanner into your Android app natively using Eclipse

June 13, 2011

Edit: Sean Owen, one of the developers for ZXing has posted a comment to this blog warning of the pitfalls of integrating ZXing into your own app; doing so just to avoid having your users take that extra step of installing from the market is not a good reason. I completely agree with this. There are many advantages to using the intent based approach as outlined in his comments. My motivation is for an enterprise app that does not have access to the Android market and involves my client installing zxing manually on thousands of devices before they are able to distribute to its business customers.

So to be clear, do not use this method unless it is absolutely necessary, and if you do have to – make sure that override your intent filters so that other apps that want to use zxing do not end up calling your modified version. Also, if zxing is already installed, then you should use that by default instead of your modified version.

ZXing is one of the most popular barcode scanning applications on the market. They make it very easy for you to integrate into your application via an intent but this means that your users must manually install the application from the market.

Fortunately, the app is also open source so I will show you how to cleanly build this capability into your project.

Please note that the awesome developers of this product have released the src under the Apache v2.o license so please be sure to adhere to the terms of this license and give them full credit for their work. http://www.apache.org/licenses/LICENSE-2.0

Step One: Obtain the zxing src code
The src can be found at http://code.google.com/p/zxing/source/browse/trunk. Specifically you only need the android/ and the core/ projects. Use svn to checkout these to your local hard-drive.

Step Two: Build zxing core using Apache Ant
You will need to build the core project into a jar file using apache ant (download from herehttp://ant.apache.org/ivy/download.cgi). Using a shell or cmd prompt navigate to the root directory of the downloaded zxing src and execute ”ant -f core/build.xml”. This will produce a file core/core.jar which we will use in the next step.

Step Three: Build ZXing Android using Eclipse
Create a New Android Project (File –> New –> Android Project).
Set the project name to ZXing (or similar).
Select the “Create project from existing source” radio button
Click “Browse” and navigate to the android project that you downloaded from zxing and click “OK”
Select “Finish”

The project will not currently build. We need to add the core.jar file (that we produced in the previous step) into our project. Right-click on ZXing project –> properties –> Java Build Path –> Add External Jars –> Navigate to and select core.jar –> Open –> OK.

Actually, while we’re here we should do one more very important thing! Right-click on ZXing project –> properties –> Android –> Scroll down and check/tick the “Is Library” checkbox –> OK.

Step 4: Include ZXing Android into your project.
Within Eclipse,  Right-click on YOURPROJECTNAMEHERE project –> properties –>Android –> Scroll down to Libraries section –> Click Add –> Select ZXing (which should appear as an option as a result of completing previous step).

Next, in some trigger function e.g. button press within your code you should add:

 

1 Intent intent = new Intent("com.google.zxing.client.android.SCAN");
2 intent.putExtra("SCAN_MODE""QR_CODE_MODE");
3 startActivityForResult(intent, 0);

 

In the same activity you’ll need the following to retrieve the results:

 

01 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
02    if (requestCode == 0) {
03       if (resultCode == RESULT_OK) {
04          String contents = intent.getStringExtra("SCAN_RESULT");
05          String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
06          // Handle successful scan
07       else if (resultCode == RESULT_CANCELED) {
08          // Handle cancel
09       }
10    }
11 }

 

Almost there! One of the current limitations of Android Library projects is that it will not pull anything from AndroidManifest.xml into your project.
So if we try to invoke the above code we will receive a runtime exception because your Android app has no idea how to handle the scan intent.
To fix this you just need to copy the following into your AndroidManifest.xml:

 

01 <activity android:name="com.google.zxing.client.android.CaptureActivity"
02    android:screenOrientation="landscape"
03    android:configChanges="orientation|keyboardHidden"
04    android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
05    android:windowSoftInputMode="stateAlwaysHidden">
06    <intent-filter>
07       <action android:name="android.intent.action.MAIN"/>
08       <category android:name="android.intent.category.DEFAULT"/>
09    </intent-filter>
10    <intent-filter>
11       <action android:name="com.google.zxing.client.android.SCAN"/>
12       <category android:name="android.intent.category.DEFAULT"/>
13     </intent-filter>
14 </activity>

 

And as Columbo would say, “Just one more thing!”. Add this permission to the top of your AndroidManifest.xml:

 

1 <uses-permission android:name="android.permission.CAMERA"/>

 

EDIT: You need to do yet one more thing! You need to add the core.jar (produced in Step two) to your new project (Right-click your project –> Properties –> Java Build Path –> Add External JARS… –> Select core.jar –> OK). Thanks to Marco and Markosys in the comments for spotting and pointing out the omission!

 

Referenced by: http://damianflannery.wordpress.com/2011/06/13/integrate-zxing-barcode-scanner-into-your-android-app-natively-using-eclipse/#comment-298

http://as400samplecode.blogspot.com/2011/09/android-barcode-scanner-using-zxing.html

Advertisements
 
12 Comments

Posted by on February 29, 2012 in Android, Mobile Development

 

Java : BIRT Report Printing Without User Interaction (Background Printing)

May 18, 2009 by laukik81

During one of my projects , I needed server side printing of BIRT report in which User Interaction was not required ie Background Printing. By the term “No User Interaction” , Print Dialog is not involved anywhere. It could be used for batch printing.
Or A copy of viewed report is printed on the server without letting the user to know it.

BIRT provides server side printing but again it comes to User Interaction.Here BIRT’s ReportEngine API Plays a important role.

Steps :

(1). Create a servlet which can be invoked from a simple Java Program or any stored procedure.

(2).In this servlet, run the report through ReportEngine API and generate a temp pdf of report

(3). Print this generated pdf through Java and delete it.

ReportPrintingServlet.java


import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.PrinterJob;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Properties;

import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.birt.core.framework.IPlatformContext;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.core.framework.PlatformFileContext;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.PDFRenderOption;

import com.sun.pdfview.PDFFile;

public class ReportPrintingServlet extends HttpServlet{

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

System.out.println("Came for printing");
ServletContext servletContext = getServletConfig().getServletContext();
Object attribute = servletContext.getAttribute("reportprintproperties");
Properties properties = (Properties) attribute;
try
{
generatePDFFile(properties, request);
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void generatePDFFile(Properties properties,HttpServletRequest request) throws Exception
{
final String REPORT_ENGINE = Path of your ReportEngine
final String REPORTS_PATH = Path where .rptdesign files are kept
final String OUTPUT_LOCATION = Location where pdf is to be generated

PDFRenderOption options = new PDFRenderOption();
EngineConfig config = new EngineConfig();
config.setEngineHome(REPORT_ENGINE);
IPlatformContext context = new PlatformFileContext();
config.setEngineContext(context);
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);

IReportEngine engine = factory.createReportEngine(config);
IReportRunnable runnable = null;
try {
runnable = engine.openReportDesign(REPORTS_PATH);
} catch (EngineException e) {
System.err.println("Design " + REPORTS_PATH + " not found!");
e.printStackTrace();
engine.destroy();
}

IRunAndRenderTask task = engine.createRunAndRenderTask(runnable);

ByteArrayOutputStream fso = new ByteArrayOutputStream();
options.setOutputStream(fso);
options.setOutputFormat(PDFRenderOption.OUTPUT_FORMAT_PDF);
options.setSupportedImageFormats("PNG");
options.setOutputFileName(OUTPUT_LOCATION); //
task.setRenderOption(options);

Enumeration names = request.getParameterNames();

while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = request.getParameter(name);
task.setParameterValue(name, value);
}

task.getAppContext().put(EngineConstants.APPCONTEXT_CLASSLOADER_KEY,Thread.currentThread().getContextClassLoader());
task.run();
System.out.println("Created Report " + OUTPUT_LOCATION + ".");
engine.destroy();

String printerName = request.getParameter("printer");
if(printPDF(OUTPUT_LOCATION,printerName))
{
deletePDFFile(OUTPUT_LOCATION);

}
}

private boolean printPDF(String filename,String printerName) throws Exception{

FileInputStream fis = null;
BufferedInputStream bufferedInputStream = null;
ByteBuffer bb = null;

try {
File f = new File(filename);
fis = new FileInputStream(f);
//FileChannel fc = fis.getChannel();
//ByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size());
bufferedInputStream = new BufferedInputStream(fis);
byte bytes[] = new byte[fis.available()];
bufferedInputStream.read(bytes);
bb = ByteBuffer.wrap(bytes);
PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page
PDFPrintPage pages = new PDFPrintPage(pdfFile);

// Create Print Job
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat pf = PrinterJob.getPrinterJob().defaultPage();
pjob.setJobName(f.getName());

/**
* Use the printer which comes as parameter from URL.
* So that we can redirect the print at runtime to any of the printer.
*/
PrintService selectedPrinter = null;
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService printService : services) {

System.out.println(printService.getName()+" = "+printerName);
if(printService.getName().equalsIgnoreCase(printerName))
{
selectedPrinter = printService;

break;
}

}
pjob.setPrintService(selectedPrinter);

Book book = new Book();
book.append(pages, pf, pdfFile.getNumPages());
pjob.setPageable(book);
System.out.println("Printer : " + pjob.getPrintService().getName());
// Send print job to default printer

pjob.print();
System.out.println("Sent for Printing : ....");

return true;

} catch (Exception e) {
e.printStackTrace();
return false;
}
finally{

bb.clear();
try
{
fis.close();
bufferedInputStream.close();
}
catch(Exception e)
{
throw new Exception(e);
}
finally
{
fis = null;
bufferedInputStream = null;
}

}

}

private void deletePDFFile(String OUTPUT_LOCATION) throws Exception
{

File file = new File(OUTPUT_LOCATION);
boolean deleted = false;
if(file != null &amp;&amp; file.exists())
{
// file.renameTo(new File(OUTPUT_LOCATION.replace(".", "_")));
deleted = file.delete();
}
System.out.println(" Generated PDF Deleted "+deleted);
}

}

Sample URL :

http://infotraksrv:8080/BirtReportPrinting/print?__report=reports/myreport.rptdesign&printer=printserverprinter_name

In above URL,

print : Is the ReportPrintingServet
printer : Parameter specifies the printer location.
__report : Parameter specifies which report is to be printed

PDFRenderer needs to be in your classpath for printing PDF files.
You can download it from here

Note

Loading Report Engine is costly task so it is recommended to have it one time only.

Referenced by: http://laukik.wordpress.com/2009/05/18/java-birt-report-printing-without-user-interaction/

 
1 Comment

Posted by on February 29, 2012 in Birt Report

 

Show a context menu for long-clicks in an Android ListView

Source code for this blog post is available as a complete Eclipse project athttp://github.com/mikeplate/ListViewDemo (zip download link in upper right corner).

An Activity with an expanding ListView and a docked TextView

If you have an activity that will only contain a single ListView control, you can derive your activity from the ListActivity instead of Activity. However, I think I might like to show some extra info below my ListView so I chose to have a separate ListView object. My activity layout looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  >
  <ListView
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="0px"
    android:layout_weight="1"
    />
  <TextView
    android:id="@+id/footer"
    android:layout_width="fill_parent"
    android:layout_height="60dip"
    android:text="@string/footer"
    android:padding="4dip"
    android:background="#FF666666"
    />
</LinearLayout>

And I need the layout for items in the ListView (listitem.xml):

<?xml version="1.0" encoding="utf-8"?>
<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textSize="24dip"
  android:padding="8dip"
  />

Note a nice trick that I’ve used to get the TextView to “dock” at the bottom with a definied height, and have the ListView automatically fill out the rest of the height. This kind of thinking is important since Android devices can have different resolutions. The trick is to set the layout_height to zero pixels and the layout_weight to one (default is zero). Not sure about the logic behind that, but it works!

Screen capture of a selected=

In order to have something to put into my ListView, I created a few country names in a string array as a resource and I sort that array before adding it to the ListView with the ArrayAdapter object. (Check out source code link above for this content.)

public class ListViewDemoActivity extends Activity {
  private String[] Countries;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Countries = getResources().getStringArray(R.array.countries);
    Arrays.sort(Countries);

    ListView list = (ListView)findViewById(R.id.list);
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.listitem, Countries);
    list.setAdapter(adapter);
    registerForContextMenu(list);
  }
}

Creating a ContextMenu in Android

When the user long-clicks, the event onCreateContextMenu is fired for the control that the user is clicking. For me, that is the ListView control. But since I don’t want to write a custom ListView-derived class, I want to catch that event in my activity. There does not seem to be any bubbling going on. Events fired in a child control does not bubble up to the parent if they are unhandled.

But obviously, the api designers have thought of this since there is a special method for this situation. Call the registerForContextMenu in your activity for this! This will actually make sure your overridden methods for both onCreateContextMenu and onContextItemSelected is called for the ListView-events as we’ll see soon.

Next, we’ll provide the implementation of onCreateContextMenu. Here I want to ensure that the event comes from the ListView and if so, I want to determine on which item in the ListView the user long-clicked.

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
    ContextMenuInfo menuInfo) {
  if (v.getId()==R.id.list) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
    menu.setHeaderTitle(Countries[info.position]);
    String[] menuItems = getResources().getStringArray(R.array.menu);
    for (int i = 0; i<menuItems.length; i++) {
      menu.add(Menu.NONE, i, i, menuItems[i]);
    }
  }
}

As you can see, the argument of type ContextMenuInfo can actually change depending on what type of control is sending the event. For ListViews, the class you need to type cast into is AdapterView.AdapterContextMenuInfo. From there I used the position, which in my case corresponds to the index into the string-array. From the array I retrieve the string for that particular item and use as title for the menu. Then you can of course add all the menu commands you like. For the demo, I defined another string array as a resource with the commands I want to add.

When creating the menu items with the add-call, I specify that I don’t want any grouping of the items (Menu.NONE) and that the order and id of the item is the same (i). The last argument to add is the text to display for the item.

Screen capture of the context menu with commands

Responding to selected MenuItem

If the user dismisses the context menu (for instance, by back button) you don’t need to do anything. But for catching the actual selection of one of the items, you need to override onContextItemSelected.

@Override
public boolean onContextItemSelected(MenuItem item) {
  AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
  int menuItemIndex = item.getItemId();
  String[] menuItems = getResources().getStringArray(R.array.menu);
  String menuItemName = menuItems[menuItemIndex];
  String listItemName = Countries[info.position];

  TextView text = (TextView)findViewById(R.id.footer);
  text.setText(String.format("Selected %s for item %s", menuItemName, listItemName));
  return true;
}

The MenuItem argument holds all information that you need. The ContextMenuInfo object that got sent to onCreateContextMenu is still there and still needs type casting. Or I guess you could have saved that info in the activity between the calls, but I didn’t.

The id of the menu item selected is the same as the index into the string array of menu item texts for me. Instead of just outputting the menu command name and the list item text in a TextView, you would most likely have a big switch statement on menuItemIndex.

This was my first blog post and code demo for the Android platform. I hope it won’t be the last! The goal is to build upon this demo and/or other demos in my investigations of the Android platform. Please let me know in the comments if you have even better methods or code patterns that solves problems like this.

 

Referenced by: http://www.mikeplate.com/2010/01/21/show-a-context-menu-for-long-clicks-in-an-android-listview/

 
Leave a comment

Posted by on February 23, 2012 in Android

 

Android Format Currency Input editText

I have an editText, starting value is $0.00. When you press 1, it changes to $0.01. Press 4, it goes to $0.14. Press 8, $1.48. Press backspace, $0.14, etc.

That works, the problem is, if somebody manually positions the cursor, problems occur in the formatting. If they were to delete the decimal, it won’t come back. If they put the cursor in front of the decimal and type 2, it will display $02.00 instead of $2.00. If they try to delete the $ it will delete a digit instead, for example.

<code> mEditPrice.setRawInputType(Configuration.KEYBOARD_12KEY);
public void priceClick(View view) {
mEditPrice.addTextChangedListener(new TextWatcher(){
DecimalFormat dec = new DecimalFormat("0.00");
@Override
public void afterTextChanged(Editable arg0) {
}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
</code>
<code> if(!s.toString().equals(current)){
mEditPrice.removeTextChangedListener(this);

String cleanString = s.toString().replaceAll("[$,.]", "");
</code>
<code> BigDecimal parsed = new BigDecimal(cleanString).setScale(2,BigDecimal.ROUND_FLOOR).divide(new BigDecimal(100),BigDecimal.ROUND_FLOOR);
 String formated = NumberFormat.getCurrencyInstance().format(parsed);</code>
<code>        current = formated;       </code>
<code> mEditPrice</code>.setText(formated);       
<code> mEditPrice</code>.setSelection(formated.length());
<code>mEditPrice</code>.addTextChangedListener(this);
<code>    }</code>
<code>
}
});</code>

Referenced by: http://stackoverflow.com/questions/5107901/better-way-to-format-currency-input-edittext

 
Leave a comment

Posted by on February 21, 2012 in Android

 

Whats the Difference Between dataSetRow[“FIELD”] and row[“FIELD”]

Posted by Scott Rosenbaum

One of the most common questions for people that are new to BIRT is about how to ask data from the DataSet in the report.  The question is when building expressions should I use dataSetRow[“FIELD”] or row[“FIELD”]?

So let me see if I can set the record straight.  When data is acquired, it is acquired by a DataSet, so the following query in a JDBC DataSet will create a three field resultset:

select CITY, STATE, COUNTRY from CUSTOMERS 

Any script or expressions written on the DataSet will be written to use the format

row[“FIELD_NAME”];

So if we add a computed column to the DataSet called compCityState, the expression would look like this.

Once a computed column is created, you can reference that computed column using the same row syntax.  So in the OnFetch method you could add this message to log the value of the computed column.

Packages.java.lang.System.out.println(row["compCityState"]); 

The other place that you can access variable on the DataSet is through ReportItem binding.  In most cases, this means Table Binding where you have attached a table to a DataSet.  In general, when you use BIRT you associate a Table with a DataSet.  We say that the Table is bound to the DataSet.

When a DataSet is dragged to the Layout editor, BIRT automatically does the data binding and creates a bound column for each field and computed column in the DataSet.  The following shows a table and its Binding.

You will notice that all of the expressions use the term dataSetRow, which means this value is pulled from the DataSet.  Now for the tricky bit, any field that is bound to a Table can be used in another table binding.  So if we wanted to create a field that has City, State and Country, we could either:
a) go back to the DataSet
b) add a new table binding

When you add a binding to a table you are brought to the expression builder.  In this first example, I am creating a table binding that gathers data straight from the DataSet.

Because I am referencing the DataSet directly the expression uses the dataSetRow syntax.
In the next example, I will use the previously established bindings to build the expression.  In the expression builder I will select Available Column Bindings and the Table and then select the fields.  You will also notice that the Table Binding has access to any of the previously bound fields and a special RowNumber field.
The important thing is that the syntax to access those values is to use row[“FIELD_NAME”]

So the short answer is, dataSetRow syntax references the original values from the DataSet, whereas the row syntax references the bound column values.

Now for a quick test, this should be easy.

Imagine that I change the expression of the CITY expression to look like this, and all else remains the same.

If the values for the row are:
City: Kalamazoo
State: MI
Country: USA

What will a DataItem that is showing rowCityStateZip display?
What will a DataItem that is showing tablCityStateCountry display?

The answers will be after a short shameless promotion of my companies BIRT training program.  We have designed a modular training program that is focused on teaching you how BIRT works.  You can take one module or all of them.  The focus of our training is on how BIRT works, so that when you finish you really understand what is going on in the product.

Our training can be taken on-site, or through remote sessions of between two and four hours each.  We are also happy to work with your team to customize the training to match your companies needs.   If you are interested, please visit our web site and have a look.

Answers:
rowCityStateZip:        { Kalamazoo }, MI USA
tablCityStateCountry:  Kalamazoo, MI USA

Remember, dataSetRow syntax (as used in tablCityStateCountry) goes back to the original data.  Row syntax use the table binding.

Referenced by: http://birtworld.blogspot.com/2010/07/whats-difference-between.html

 
Leave a comment

Posted by on February 20, 2012 in Birt Report, Eclipse

 

BIRT: Connecting to MS Sql Server Database

POSTED BY 
  1. Download the Microsoft JDBC driver fromhttp://msdn.microsoft.com/en-us/sqlserver/aa937724
  2. Note: If youre using Java 1.5, you will use sqljdbc.jar, if your using Java 1.6, you will use sqljdbc4.jar.
  3. Open Eclipse
  4. Create a new Report or open an existing report
  5. Open the Data Explorer Tab
  6. If this is an existing report, Double Click on an existing Data Source, otherwise create a new Data Source. Call it whatever.
  7. From the Data Source editor, click on the Manage Drivers button.

 

  1. In the Manage JDBC Drivers Dialog, click on Add…

 

  1. Navigate to where you have either the sqljdbc.jar or sqljdbc4.jar file, and click Open. This will add the driver to the BIRT Designer.
  2. Now, click on the Drivers Tab.
  3. Double click on the SqlServerDriver entry to edit it. Put in a name, and a URL template that will prompt you on the correct URL pattern to use.

 

  1. Click on OK, and OK, until you get to the Data Source Editor Dialog.
  2. Select the SQL Server driver from the drop down list. It will automatically put in the template. Replace the IP Address, and Database name with the ip of your Sql Server Database, and the name of the database.

 

  1. Enter the correct User Name and Password.

 

That’s it, your done. Test Connection to make sure the information is correct, and hit OK.

Referenced by: http://digiassn.blogspot.com/2011/03/birt-connecting-to-ms-sql-server.html

 
Leave a comment

Posted by on February 17, 2012 in Birt Report

 

Reporting with Eclipse BIRT and Java Objects (POJO’s) – Tutorial

Tutorial

by Lars Vogel

Reporting with Eclipse BIRT and Java Objects (POJO’s) – Tutorial

Lars Vogel Hendrik Still

Version 1.2

Copyright © 2008 – 2011 Lars Vogel

26.06.2011

Revision History
Revision 0.1 – 0.2 07.03.2008 Hendrik Still, Lars Vogel
Created Article
Revision 0.3 – 1.2 07.03.2009 – 26.06.2011 Lars
Vogel
bug fixes and enhancements
Eclipse BirtThis tutorial describes how to use Eclipse BIRT for reporting on simple Java Objects (POJO’s). The tutorial explains also how to deploy the resulting BIRT report into a webcontainer (Tomcat) and how to use it in an Eclipse RCP application. Eclipse 3.7 (Indigo) is used for this tutorial.

1. Eclipse BIRT

1.1. Overview

Eclipse BIRT allows the creation of reports based on data from different data sources. Data sources define where the data is stored.

BIRT provides for example the following data sources:

  • Databases (via JDBC)
  • Text Files (cvs, XML)
  • WebServices (via WSDL-Files)
  • Scripting Data sources

You use in BIRT “Data sets” to defines queries on data source. These data sets can be used in a report.

In a Java program it is often convenient to use Java objects as a data source for reports. This article will focus on the usage of plain old Java objects (POJO) as data sources for BIRT reports.

1.2. Example

In this tutorial we will build a report which will show us information about the stock market. We get the information from a Java Object. The data will be displayed in a chart and in a table with detailed information. The result should look like this:

2. Installation

Use the Eclipse Update Manager to install “Business Intelligence, Reporting and Charting” -> BIRT Framework.

3. Create Project and REport

Create a new Java Project with the name “de.vogella.birt.stocks”.

Create a new report “stock_report.rptdesign” via File -> New -> Other -> Business Intelligence and Reporting -> Report.

The new report is displayed in the “Report Design” perspective. Delete everything in the example report except the report header. The result should look like the following.

4. Java classes

The report will display stock data. To demonstrate BIRT we use a Mock object for providing the data.

Create package “de.vogella.birt.stocks.model” and then the following class. This class will represent the domain model.

package de.vogella.birt.stocks.model;

import java.util.Date;
/** * Domain model for stock data * @author Lars Vogel */
public class StockData {
	private Date date;
	private double open;
	private double high;
	private double low;
	private double close;
	private long volume;

	public double getClose() {
		return close;
	}

	public void setClose(double close) {
		this.close = close;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public double getHigh() {
		return high;
	}

	public void setHigh(double high) {
		this.high = high;
	}

	public double getLow() {
		return low;
	}

	public void setLow(double low) {
		this.low = low;
	}

	public double getOpen() {
		return open;
	}

	public void setOpen(double open) {
		this.open = open;
	}

	public long getVolume() {
		return volume;
	}

	public void setVolume(long volume) {
		this.volume = volume;
	}

}

Create the package “de.vogella.birt.stocks.daomock” and then the following class “StockDaoMock”. This will only mock / fake the data and not really get it from the Internet. As we want to learn BIRT here this should be fine.

package de.vogella.birt.stocks.daomock;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import de.vogella.birt.stocks.model.StockData;

public class StockDaoMock {

	public List<StockData> getStockValues(String company) {
		// Ignore the company and always return the data
		// A real implementation would of course use the company string
		List<StockData> history = new ArrayList<StockData>();
		// We fake the values, we will return fake value for 01.01.2009 -
		// 31.01.2009
		double begin = 2.5;
		for (int i = 1; i <= 31; i++) {
			Calendar day = Calendar.getInstance();
			day.set(Calendar.HOUR, 0);
			day.set(Calendar.MINUTE, 0);
			day.set(Calendar.SECOND, 0);
			day.set(Calendar.MILLISECOND, 0);
			day.set(Calendar.YEAR, 2009);
			day.set(Calendar.MONTH, 0);
			day.set(Calendar.DAY_OF_MONTH, i);
			StockData data = new StockData();
			data.setOpen(begin);
			double close = Math.round(begin + Math.random() * begin * 0.1);
			data.setClose(close);
			data.setLow(Math.round(Math.min(begin, begin - Math.random() * begin * 0.1)));
			data.setHigh(Math.round(Math.max(begin, close) + Math.random() * 2));
			data.setVolume(1000 + (int) (Math.random() * 500));
			begin = close;
			data.setDate(day.getTime());
			history.add(data);
		}
		return history;
	}
}

5. Datasource and Dataset

To use Java Objects (POJO’s) as datasource in Eclipse BIRT you have to map the fields of your Java classes to JavaScript. This JavaScript is used in your report and will access the Java Object.

5.1. Create Data Source

The data source connects your data with your report. BIRT provides different types of data sources, we use the “Scripted Data Source”. Go back to your stocks_report, use the “Report Design” perspective and select the “Data Explorer” View.

Tip

You have to select your report to display the content of the datasource view.

Create a new datasource, named “srcStocks” in your report.

5.2. The Dataset

The dataset defines the mapping for the datasource data and the BIRT data. Create a new dataset named “dataSetSocks”.

Press next and define the columns for your report.

5.3. JavaScript

Now we have to write the JavaScript for our dataset. Select the dataset and choose “open” as script. The open script is called before the first access to the dataset. We use this to load our List with the stock objects. To access a Java class you only have to use the following syntax: Packages.myJavaClass where myJavaClass is the full qualified Java class name.

Tip

In case you don’t see the script please node that the editor for the report has several tab. One of it is labeled “source”.

count = 0;

// Create instance of
// the GetStockHistory class
gsh = new Packages.de.vogella.birt.stocks.daomock.StockDaoMock(); 

//Load the List

stock = gsh.getStockValues("Java");

Place the following coding in the fetch script.

if(count < stock.size()){
       row["columnDate"] = stock.get(count).getDate();
       row["columnOpen"] = stock.get(count).getOpen();
       row["columnHigh"] = stock.get(count).getHigh();
       row["columnLow"] = stock.get(count).getLow();
       row["columnClose"] = stock.get(count).getClose();
       row["columnVolume"] = stock.get(count).getVolume();
       count++;
       return true;
}

return false;

Check if your Script works by doubleclicking on the dataset -> Preview Result.

6. Display the data in a table

6.1. Overview

We will now display the data in a table.

6.2. Create a table

Switch from “Data Explorer” to the “Palette”. Select the tab “Layout”.

Drag and drop the table element on the report.

Define the following settings for the table.

Change back to the “Data Explorer”. And drag and drop the dataset columns into the “Details row” of the table.

The result should look like the following.

Done. You can see a preview of the report if you click on the “Review” Tab. The result should look like the following:

7. Chart

7.1. Create a Chart

Switch back to the Palette, select a chart and drag and drop it on your report.

Choose the Line Chart with the standard settings.

Press Next and select your data set.

At the next step we have to assign the columns to the axis. We assign the date to the x axis and the open value to the y axis via drag and drop.

Define 5 series in total. Assign the columns to these series by dragging the column to the Sum sign.

Currently the x axis shows first the newest date. Reverse the x axis by you have to sort the data ascending. Press the highlighted button.

Go to the next tab and give titles to your columns. Hide the last one.

The display of the dates use a long format, we would like to change this. Perform the following and choose “short” as date type of the x axis

Change the display of the lines via the following.

Press finish to include your chart into your report.

8. Deploying in Tomcat

8.1. Overview

The following explains how to use BIRT reports in Tomcat. In general you have to:

  • Install the BIRT webviewer in Tomcat
  • Export your BIRT project into a .jar file
  • Move the .jar file to the birt-install-directory/WEB-INF/lib directory
  • Move the report design file into the root directory of birt in tomcat
  • Restart Tomcat

8.2. Install BIRT in Tomcat

We will use a standalone Tomcat 6.0 which we assume is already installed. See Apache Tomcat Tutorial for details.

You need the “Deployment components of BIRT” http://download.eclipse.org/birt/downloads/.

Copy the birt.war of this download into the Tomcat webappsfolder.

Tip

Currently you have to install org.eclipse.commons.logging separately into Tomcat. Download this lib from http://commons.apache.org/logging/ and put the jars into the lib folder of Tomcat.

The Birt example should be available under http://localhost:8080/birt/.If you see something like this, your Tomcat an your Web Viewer should work correct.

8.3. Install your BIRT reports in Tomcat

To run your own reports you have to copy the .rptdesign file in the root of the birt folder in Tomcat. To make your Java classes available export your project into a jar file.

After that the jar file has to be copied to the Tomcat webapps/birt/WEB-INF/lib/ directory. Restart the Tomcat and navigate to your report.

Your report should be found under http://localhost:8080/birt/frameset?__report=stock_report.rptdesign

Tip

If you want to export your report to PDF you also need the library iText from (http://prdownloads.sourceforge.net/itext/itext-1.3.jar ) . Copy the iText.jar in “/birt-viewer/WEB-INF/platform/plugins/com.lowagie.itext/lib”. Now restart the Tomcat.

9. Deploying in Eclipse RCP application

9.1. BIRT deploying to an RCP Application

We can use the Birtviewer also in a local RCP Application, it isn’t more than an browser view which shows a HTML Page generated by an integrated Webserver.

The following assumes that you are already familiar with Eclipse RCP development. See Eclipse RCP Tutorial in case you need an introduction.

Convert “de.vogella.birt.stocks” to a plugin project, via right mouse click -> Configure -> “Convert to plug-in project”.

Create an new plugin project “de.vogella.birt.stocks.rcp”. Select the template “RCP Application with a view”.

Add the following plugins as dependendies to “de.vogella.birt.stocks.rcp”.

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Rcp
Bundle-SymbolicName: de.vogella.birt.stocks.rcp; singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: de.vogella.birt.stocks.rcp.Activator
Require-Bundle: org.eclipse.ui,
 org.eclipse.core.runtime,
 org.eclipse.birt.report.viewer,
 org.eclipse.birt.report.engine.emitter.html,
 de.vogella.birt.stocks,
 org.eclipse.birt,
 org.eclipse.birt.chart.ui,
 org.eclipse.birt.chart.device.extension,
 org.eclipse.birt.chart.device.pdf,
 org.eclipse.birt.chart.device.svg,
 org.eclipse.birt.chart.device.swt,
 org.eclipse.birt.chart.engine.extension,
 org.eclipse.birt.chart.reportitem,
 org.eclipse.birt.chart.reportitem.ui,
 org.eclipse.birt.chart.ui.extension,
 org.eclipse.birt.core.script.function,
 org.eclipse.birt.report.engine.script.javascript
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Copy your report to “stock_report_rcp.rptdesign” into this new project. Open this report and change the “open” JavaScript to the following.

count = 0;
/* * load and init data reader * import Platform from org.eclipse.core.runtime */
importPackage(Packages.org.eclipse.core.runtime);

/* load bundle with POJOs and data loading class */

myBundle = Platform.getBundle("de.vogella.birt.stocks");

/* load data reader class */
readerClass = myBundle.loadClass("de.vogella.birt.stocks.daomock.StockDaoMock");

/* create new instance of DataReader */
readerInstance = readerClass.newInstance();

/* read data */
stock = readerInstance.getStockValues("Java");

Use this code as View.java.

package de.vogella.birt.stocks.rcp;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.eclipse.birt.report.viewer.utilities.WebViewer;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import org.osgi.framework.Bundle;

public class View extends ViewPart {
	public static final String ID = "de.vogella.birt.stocks.rcp.view";

	public void createPartControl(Composite parent) {
		String path = "";
		try {
			Bundle bundle = Platform.getBundle("de.vogella.birt.stocks.rcp");
			URL url = FileLocator.find(bundle, new Path(
					"stock_report_rcp.rptdesign"), null);
			path = FileLocator.toFileURL(url).getPath();
		} catch (MalformedURLException me) {
			System.out.println("Fehler bei URL " + me.getStackTrace());
		} catch (IOException e) {
			e.printStackTrace();
		}

		Browser browser = new Browser(parent, SWT.NONE);
		// Use the filename of your reportWebViewer.display(path, WebViewer.HTML, browser, "frameset");
	}
/** * Passing the focus request to the viewer’s control. */
	public void setFocus() {
	}
}

10. Thank you

Please help me to support this article:

Flattr this  

11. Questions and Discussion

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.de Google Group. I have created a short list how to create good questions which might also help you.

12. Links and Literature

12.1. Source Code

Source Code of Examples

12.2.  Eclipse BIRT resources

http://wiki.eclipse.org/index.php/BIRT_Project

Eclipse BIRT Wiki

12.3. vogella Resources

Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java and compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put everything you have under distributed version control system

Referenced from: http://www.vogella.de/articles/EclipseBIRT/article.html

 
Leave a comment

Posted by on February 14, 2012 in Android, Birt Report, Eclipse, Java Pro