<body><iframe src="http://www.blogger.com/navbar.g?targetBlogID=16506996&amp;blogName=The+Digital+Voice&amp;publishMode=PUBLISH_MODE_BLOGSPOT&amp;navbarType=BLACK&amp;layoutType=CLASSIC&amp;homepageUrl=http%3A%2F%2Fdigiassn.blogspot.com%2F&amp;searchRoot=http%3A%2F%2Fdigiassn.blogspot.com%2Fsearch" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" height="30px" width="100%" id="navbar-iframe" title="Blogger Navigation and Search"></iframe> <div id="space-for-ie"></div>
The Digital Voice

News Relating to Programming, Network Security, and Technology 


Tuesday, April 22, 2008

10:26 PM - BIRT: Another BIRT Book

I was surprised to find this when looking around on Amazon earlier. To join the ranks of my book and the books from AW about BIRT, an author out of Germany is publishing a book called "Eclipse BIRT" from XPert Press. I would like to have an opinion about it, unfortunately the language barrier is a bit of an issue for me since I don't speak German. Regardless, it is good to see another book about BIRT out there, showing the project is growing and demand is out there.

| Permanent Link


Friday, March 28, 2008

4:26 PM - Games: Ninja Gaiden Dragon Sword

I was really skeptical about this game at first. I had read plenty of pre-reviews about this game and using the stylus to "slash" the opponents on the screen. I just imagined some geeky kid on an airplane waving his hands widley, shopping at the tiny DS screen with a katana shapped stylus, poking the passengers around him in the eyes. And given the fact that Ninja Gaiden on the XBox is second only the GTA in the need for an ESRB rating, I was a little worried about the delivery on family friendly Nintendos consoles.

Now that I've gotten a hands on with it, I can say those fears are completely unfounded. NG:DS is a completely engrossing handheld experience right from the get go. Gone are the days and stories of Ryu chasing Jaquio around looking for statues and saving Irine from the clutches of certain death. NG:DS takes up from the original Xbox story line, some 6 months after the "Dark Dragon Blade" incident. While I haven't gotten enough into the story, I did run around quite a bit to make sure the control scheme wasn't nearly as wonky as I had feared. Holding the DS at 90 degrees, book style, is a bit awkward, but only because I've spent the past 20 years of my life holding controllers ALA the original NES control scheme. Moving the character around is done via the stylus, as is the attacks. How is this done? Why, by pointing where you want to move to, writing/slashing the stylus over the opponent to attack, tapping the opponent to throw ninja stars, and slashing up to jump. So the attacks are actually pretty intuitive, despite my original fears.

There are a few hiccups however. There re times where to want to jump, and the chacter runs right into the coming onslaught of enemies instead. Thats kind of annoying, but I can chalk that up to my own ineptness with the control scheme. Blocking is a bit of a pain. Any button will cause you to block. But since I am a righty, I hold the stylus with my right-hand, the DS is in a right-hand orientation, which puts the buttons on the right-screen. So, as you can imagine, having to use my left hand to push a button in a right-handed orientation leaves me a little short-circuited due to my lack of ambidextrous abilities. Fortunately, what I lack in coordination I more than make up for in hand size, so reaching over to push buttons to block isn't as bad as I make it seem.

While I haven't done enough story line to really pass judgment on it, I did find the game bordering on "not able to put down" fun from running around and slashing. While this game isn't quite suitable for my game time during meals while traveling due to it's more interactive nature, it is definitely suitable for the evenings at the hotel while traveling and on long plane rides so that I can be the uncoordinated geeky kid poking peoples eyes out.

| Permanent Link


4:20 PM - Sguil: Sguil 0.7 is out

It's been a while since we've seen an update with Sguil. And although with most Open source projects, that usually an indication that a project is dead. However, frequenters of the Sguil IRC channel #snort-gui on irc.freenode.net know that Sguil is far from being dead. In fact, they just released version 0.7, even though I am about 3 days late in noting it. To be perfectly honest, I haven't messes with Sguil since versions 0.5 - 0.6, however necessity breeds use, and I have need of this awesome tool. And a new release version plus a need REALLY gives me a good excuse to revisit the tool the brought me to working with BIRT.

| Permanent Link


Saturday, March 22, 2008

1:30 AM - BIRT: Building Chart with Chart Engine API based off Report Document

I have been sitting on this example for a few weeks now, and have been waiting to put it out until after EclipseCon so I can absorb any ideas from the Charting API presentation that Jason Weathersby over at BirtWorld did. Now that is done and gone, I have decided to put this one out into the wild.

The original purpose of this was to be able to extract a chart design out of a BIRT report, and render it using the BIRT Chart Engine API’s. What I found out the hard way is that data set and data are not linked to Charts in BIRT outside of the BIRT render engine. The Chart Engine API, as it turns out, is completely decoupled from the BIRT Report Engine API, so axis to data mappings are not accessible in the Chart Engine API and the actual data binding is done through some Java-Fu wizardry at runtime. So, I salvaged what I could of the idea.

The following example will demonstrate a couple of different things. First, it will open a BIRT Report, and pull the Chart definition out of the report. It will then read the XML Representation of the chart to determine what columns in the report are mapped to which Axis. It then runs the report, and uses a Data Extraction task to pull the data and create an appropriate Chart Engine API Series definition. It then renders a chart to a PNG file.

There are a few things to keep in mind in this example. First, it assumes that there is a 2 column data set defined in the report, with column 1 containing what is the X axis definitions, and column 2 containing the values. It then calculates the aggregates based on those. Second, it assumes a chart definition is defined in the report. In a real world scenario, you would NEVER render a chart like this, but I am a glutton for punishment and needed a good way to learn how the Chart Engine API works. You will notice that I commented out a good chunk of code that defines the look and feel of the chart. I kept these commented out as a reference, but they aren’t necessary in this example since the visual attributes for the chart were defined in the source report design.

I did learn one really cool thing about Chart Engine API. There is a whole slew of example Chart Engine API code available in a BIRT install by default, by going to Window/Show View/Other/Report and Chart Design/Chart Examples. This will open a new view, just select any the examples listed and click on the Open button on the right hand side to see example code on how to build those charts.

Anyway, here is my example:


package com.test;

import java.io.File;
import java.io.StringBufferInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.eclipse.birt.chart.api.ChartEngine;
import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.device.image.PngRendererImpl;
import org.eclipse.birt.chart.exception.ChartException;
import org.eclipse.birt.chart.factory.GeneratedChartState;
import org.eclipse.birt.chart.factory.Generator;
import org.eclipse.birt.chart.factory.RunTimeContext;
import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithoutAxes;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.component.Series;
import org.eclipse.birt.chart.model.component.impl.SeriesImpl;
import org.eclipse.birt.chart.model.data.NumberDataSet;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.TextDataSet;
import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl;
import org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl;
import org.eclipse.birt.chart.model.type.PieSeries;
import org.eclipse.birt.chart.model.type.impl.PieSeriesImpl;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.core.framework.PlatformConfig;
import org.eclipse.birt.data.engine.core.DataException;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IDataExtractionTask;
import org.eclipse.birt.report.engine.api.IDataIterator;
import org.eclipse.birt.report.engine.api.IExtractionResults;
import org.eclipse.birt.report.engine.api.IReportDocument;
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.IResultSetItem;
import org.eclipse.birt.report.engine.api.IRunTask;
import org.eclipse.birt.report.model.api.ExtendedItemHandle;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.extension.ExtendedElementException;
import org.w3c.dom.DOMException;
import org.xml.sax.InputSource;

import com.ibm.icu.util.ULocale;
import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList;

public class RenderChart {
private static String BIRT_HOME = "C:/birt-runtime-2_2_1_1/ReportEngine";

/**
* Creates the X series for the Chart
* @param uniqueMap
* @return
*/
public static TextDataSet createCategoriesDataSet(Map uniqueMap)
{
String[] categories = new String[uniqueMap.keySet().size()];
int x = 0;
for (Iterator keyIt = uniqueMap.keySet().iterator(); keyIt.hasNext();)
{
categories[x] = (String)keyIt.next();
x++;
}
return TextDataSetImpl.create(categories);
}

/**
* Creates the Y Series for a chart
* @param uniqueMap
* @return
*/
public static NumberDataSet createValueDataSet(Map uniqueMap)
{
double[] values = new double[uniqueMap.values().size()];
int x = 0;
for (Iterator valIt = uniqueMap.values().iterator(); valIt.hasNext();)
{
values[x] = Math.round(((Double)valIt.next()).doubleValue());
x++;
}

return NumberDataSetImpl.create(values);
}

/**
* Will open a report design and return the Document instance
* @param reportName
* @return
*/
public static IReportDocument executeReport(String reportName) throws EngineException {
// create a new report engine factory
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);

// create a new report engine
EngineConfig engineConfig = new EngineConfig();
engineConfig.setBIRTHome(BIRT_HOME); // will replace with
// configuration file
IReportEngine engine = factory.createReportEngine(engineConfig);

// create the report task and open the report design file
IReportRunnable design = engine.openReportDesign(reportName);
IRunTask runTask = engine.createRunTask(design);

// use the default locale
runTask.setLocale(Locale.getDefault());

// run and close the report run task
File newTempFile = new File("C:/TEMP/birtRenderTemp",
"test.rptDocument");
String tempFileLocation = newTempFile.getAbsolutePath();

// delete the temp file, we just needed the name and path
newTempFile.delete();

runTask.run(tempFileLocation);
runTask.close();

IReportDocument ird = engine
.openReportDocument("C:/TEMP/birtRenderTemp/test.rptDocument");

return ird;
}

/**
* Creates an input source from the XMLProperties string
* @param xmlProperties
* @return
*/
public static InputSource getInputSourceFromString(String xmlProperties)
{
StringBufferInputStream is = new StringBufferInputStream(
xmlProperties);

return new InputSource(is);
}

/**
* Using a data extraction task, this will build a simple Map of columns and rows
* This method assumes a 1-1 relation between what will be the x value and y value
* @param det
* @param ySeries
* @param xSeries
* @return
* @throws BirtException
*/
public static Map getValueMap(IDataExtractionTask det, String ySeries, String xSeries) throws BirtException
{
//extract the results from the task
IExtractionResults iExtractResults = det.extract();
IDataIterator iData = null;

//hashmap to return
Map uniqueMap = new HashMap();

//if we have results, process them, otherwise, don't
if (iExtractResults != null) {
iData = iExtractResults.nextResultIterator();

// iterate through the results
if (iData != null) {
//loop while there is still data in out iterator
while (iData.next()) {
Object objColumn1;
Object objColumn2;
try {
objColumn1 = iData.getValue(ySeries);
} catch (DataException e) {
objColumn1 = new String("");
}
try {
objColumn2 = iData.getValue(xSeries);
} catch (DataException e) {
objColumn2 = new String("");
}

Double newNumber = (Double) objColumn1;
if (uniqueMap.keySet().contains(objColumn2)) {
newNumber += (Double) uniqueMap
.get(objColumn2);
}
uniqueMap.put(objColumn2, newNumber);
}
iData.close();
}
}

//close the data extraction task and return our value map
det.close();
return uniqueMap;
}

/**
* Extract the XML resources from the extended item handle, used to get the XML
* representation of the chart from a report
*
* @param eih
* @return
*/
public static String getXMLResources(ExtendedItemHandle eih)
{
return (String) eih.getProperty("xmlRepresentation");
}

/**
* Retrieves the name of the X Series column from a chart XMLRepresentation
*
* @param xmlProperties
* @return
* @throws XPathExpressionException
* @throws DOMException
*/
public static String getXSeries(String xmlProperties) throws XPathExpressionException, DOMException
{
InputSource inputSource = getInputSourceFromString(xmlProperties);
XPath xpath = XPathFactory.newInstance().newXPath();

DTMNodeList nodeList = (DTMNodeList) xpath
.evaluate(
"//SeriesDefinitions/Series/DataDefinition/Definition",
inputSource, XPathConstants.NODESET);

String xSeries = nodeList.item(1).getTextContent();

//we found the series definitions, now remove the expression and just return
//the key
return xSeries.replace("row[\"", "").replace("\"]", "");
}

/**
* Retrieves the name of the Y Series column from a chart XMLRepresentation
* @param xmlProperties
* @return
* @throws XPathExpressionException
* @throws DOMException
*/
public static String getYSeries(String xmlProperties) throws XPathExpressionException, DOMException
{
InputSource inputSource = getInputSourceFromString(xmlProperties);
XPath xpath = XPathFactory.newInstance().newXPath();

DTMNodeList nodeList = (DTMNodeList) xpath
.evaluate(
"//SeriesDefinitions/Series/DataDefinition/Definition",
inputSource, XPathConstants.NODESET);

String ySeries = nodeList.item(0).getTextContent();

return ySeries.replace("row[\"", "").replace("\"]", "");
}

/**
* Will render a Pie chart with given categories and values. Chart needs to be created beforehand, so pull from document first.
* @param cwa
* @param categories
* @param values
* @throws ChartException
*/
public static void renderPieChart(ChartWithoutAxes cwa, TextDataSet categories, NumberDataSet values) throws ChartException
{
// Create the png renderer
IDeviceRenderer idr = new PngRendererImpl();

//create new run time context
RunTimeContext rtc = new RunTimeContext();
rtc.setULocale(ULocale.getDefault());

//create a new generator
final Generator gr = Generator.instance();
GeneratedChartState gcs = null;

//clear any existing series definitions since we created out own
cwa.getSeriesDefinitions().clear();

// Plot the chart...
/*
* Note: I commented this stuff out since I already designed my chart
* look and feel in the BIRT report designer, and all of that will
* already be set in my chart opened from a BIRT Report
cwa.setSeriesThickness(25);
cwa.getBlock().setBackground(ColorDefinitionImpl.WHITE());
Plot p = cwa.getPlot();
cwa.setDimension(ChartDimension.TWO_DIMENSIONAL_LITERAL);

p.getClientArea().setBackground(null);
p.getClientArea().getOutline().setVisible(true);
p.getOutline().setVisible(true);

Legend lg = cwa.getLegend();
lg.getText().getFont().setSize(16);
lg.setBackground(null);
lg.getOutline().setVisible(true);

// Title
//cwa.getTitle( ).getLabel( ).getCaption( ).setValue( "Pie Chart" );//$NON-NLS-1$
cwa.getTitle( ).getOutline( ).setVisible( true );
*/

//define base series
Series seCategory = SeriesImpl.create();
seCategory.setDataSet(categories);

SeriesDefinition sd = SeriesDefinitionImpl.create();
sd.getSeriesPalette().shift(0);
sd.getSeries().add(seCategory);
cwa.getSeriesDefinitions().add(sd);

//define pie seies
PieSeries categorySeries = (PieSeries) PieSeriesImpl
.create();
categorySeries.setDataSet(values);
categorySeries.setSeriesIdentifier("Territories");

SeriesDefinition sdValues = SeriesDefinitionImpl.create();
sdValues.getQuery().setDefinition("Census.Territories");//$NON-NLS-1$
sdValues.getSeries().add(categorySeries);
sdValues.getSeries().add(categorySeries);
sd.getSeriesDefinitions().add(sdValues);

// Set the chart size
Bounds bo = BoundsImpl.create(0, 0, 350, 275);

//Now build the chart
gcs = gr.build(idr.getDisplayServer(), (Chart)cwa, bo, null, rtc,
null);

// Specify the file to write to.
idr.setProperty(IDeviceRenderer.FILE_IDENTIFIER,
"test.png"); //$NON-NLS-1$

// generate the chart
gr.render(idr, gcs);
}

/**
* Main: The delegator of out program. Starts the BIRT Platform, gets chart, extracts values, and renders chart
* @param args
*/
public static void main(String[] args) {
try {
//start up the platform
//note: needed to add STANDALONE = true, otherwise the chart engine
//would not work.
PlatformConfig platformConfig = new PlatformConfig();
platformConfig.setBIRTHome(BIRT_HOME);
//standalone platform
platformConfig.setProperty("STANDALONE", "true");
ChartEngine.instance(platformConfig);
Platform.startup(platformConfig);

// create a new report engine factory
IReportEngineFactory factory = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);

// create a new report engine
EngineConfig engineConfig = new EngineConfig();
engineConfig.setBIRTHome(BIRT_HOME);
IReportEngine engine = factory.createReportEngine(engineConfig);

//open the given report and create a new Data Extraction task to get data from run report
IReportDocument ird = executeReport("C:/contracts/GWTBirt/BIRTGwt/src/reports/Charts/TerritorySalesPieChart.rptdesign");
IDataExtractionTask det = engine.createDataExtractionTask(ird);

//get the report runnable from the document so we can grab the chart information from the report
IReportRunnable r = ird.getReportRunnable();
ReportDesignHandle rh = (ReportDesignHandle) r.getDesignHandle();

//for each element in the report (assuming only charts), go through and grab info, then render to PNG
for (Iterator i = rh.getBody().getContents().iterator(); i
.hasNext();) {
Object o = i.next();

//make sure this is an extended item handle
if (o instanceof ExtendedItemHandle) {
ExtendedItemHandle eih = (ExtendedItemHandle) o;

// read in the XML Representation for getting the data
// definitions from the chart, get the values of the X and Y
// axis
String xSeries = getXSeries(getXMLResources(eih));
String ySeries = getYSeries(getXMLResources(eih));

//Look into using serializer to grab from a report design.
//alternative of doing this, although a little uglier
//ChartEngine.instance().getSerializer().fromXml(arg0, arg1)

ChartWithoutAxes cwa = (ChartWithoutAxes) eih
.getReportItem().getProperty("chart.instance");

// Get list of result sets
ArrayList resultSetList = (ArrayList) det
.getResultSetList();

//we know out data is in the first result set
IResultSetItem resultItem = (IResultSetItem) resultSetList
.get(0);
String dispName = resultItem.getResultSetName();

//tell the data extraction task to use the first result set
det.selectResultSet(dispName);

// retrieves the dataset with column/values as unique to map
// to Pie Chart
Map uniqueMap = getValueMap(det, ySeries, xSeries);

//crete the category, or X series, and values, or y series
TextDataSet categoryValues = createCategoriesDataSet(uniqueMap);
NumberDataSet seriesOneValues = createValueDataSet(uniqueMap);

//now that we have data and our chart, render to image
renderPieChart(cwa, categoryValues, seriesOneValues);
}
}
} catch (ExtendedElementException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
e.printStackTrace();
} catch (DOMException e) {
e.printStackTrace();
} catch (EngineException e) {
e.printStackTrace();
} catch (ChartException e) {
e.printStackTrace();
} catch (BirtException e) {
e.printStackTrace();
}

//shutdown the platform, we are done
Platform.shutdown();
}
}

| Permanent Link


Thursday, March 20, 2008

12:41 PM - Book: Excerpt Available Online

My Publisher has posted an article with an excerpt from my book on building a simple report. Check it out here: http://www.packtpub.com/article/creating-a-simple-report-using-birt

| Permanent Link


Tuesday, March 18, 2008

8:39 PM - EclipseCon: The BIRT Theme Song

Scott Rosenbaum was nice enough to post Pierre Tessier singing the BIRT theme song and molesting my rubber duck... SFW

http://birtworld.blogspot.com/2008/03/fun-at-eclipsecon.html

| Permanent Link

© John Ward 2005 - Powered for Blogger by Blogger Templates