Thursday, May 27, 2010

Working with XSLFO

XSLFO is great.

Create a stand-alone XML file or use XSLT and XML. For testing, the stand-alone file is good. For production, it is better to use XSLT-XML to separate style from data.

Use Apache FOP to access XSLFO. It can be run from the command line or can be used from a Java program.

Download and Verify


Download Apache FOP from the site:
http://xmlgraphics.apache.org/fop/download.html

Use gpg to verify that the file is not corrupt.
Download the KEYS file from the Apache site (not a mirror site).
Import the KEYS into gpg

gpg --import KEYS

Download the file and the associated .asc file. I used the zip version, since I am running on Windows.

gpg --verify fop-xxx.zip.asc fop-xxx.zip

The verification will not be signed, but short of contacting the author, you have done a partial job of verifying the file.

Install


Expand the binary file
The jar file is in the build folder.
The lib file contains additional jars that are needed for embedding into Java.
The fop.bat is the command line front end.

Command line


There are just a few options that are needed.

Data and formatting in one file named file.fo
fop -fo file.fo -pdf file.pdf

Data in xml file, formatting in xslt file.
fop -xml file.xml -xslt file.xslt -pdf file.pdf

For pdf output, the default fop will not recognize all the system fonts. Copy the fop.xconf file into the current folder and modify it to recognize the system fonts.
http://xmlgraphics.apache.org/fop/trunk/fonts.html

<renderers>
<renderer mime="application/pdf">
<fonts>
<!-- automatically detect operating system installed fonts -->
<auto-detect/>
</fonts>
</renderer>
</renderers>

Use the -c option to include the config file

gpg -c fop.xconf -xml name.xml -xslt name2fo.xsl -pdf name.pdf

Embedding in Java


Basic instructions can be found on the Apache FOP site:
http://xmlgraphics.apache.org/fop/0.95/embedding.html

Use a simple transformer if using a stand-alone fo file.

   //without XSLT:
transformer = factory.newTransformer();
...
Source src = new StreamSource(new File("src/currency.fo"));
Add the stylesheet if using XSLT-XML.

   //with XSLT
Source xslt = new StreamSource(new File("src/name2fo.xsl"));
transformer = factory.newTransformer(xslt);
...
Source src = new StreamSource(new File("src/name.xml"));

Main Java method

// Step 1: Construct a FopFactory
// (reuse if you plan to render multiple documents!)
FopFactory fopFactory = FopFactory.newInstance();

// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
OutputStream out = null;
try {
out = new BufferedOutputStream(new FileOutputStream(new File("src/currency.rtf")));
Fop fop;
fop = fopFactory.newFop(MimeConstants.MIME_RTF, out);

// Step 4: Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();

Transformer transformer; // identity transformer

//without XSLT:
transformer = factory.newTransformer();

//with XSLT:
//Source xslt = new StreamSource(new File("src/name2fo.xsl"));
//transformer = factory.newTransformer(xslt);

// Step 5: Setup input and output for XSLT transformation
// Setup input stream
//without XSLT
Source src = new StreamSource(new File("src/currency.fo"));
//with XSLT
//Source src = new StreamSource(new File("src/name.xml"));

// Resulting SAX events (the generated FO) must be piped through to FOP
SAXResult res = new SAXResult(fop.getDefaultHandler());

// Step 6: Start XSLT transformation and FOP processing
transformer.transform(src, res);


} catch (FileNotFoundException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (FOPException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerConfigurationException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} finally {
//Clean-up
if (out != null) {
out.close();
}
}

Saturday, February 27, 2010

Passing by reference in bash

It is possible to mimic pass by reference in a bash shell.

The trick is to pass the name of the variable, not its expanded value.

Use

func out

instead of

func $out


In the function, set the value of the out parameter as

eval "$1=expr"

In the function, copy the value of the parameter to a local variable with

eval "L_VAR=\${$1}"

When using local variables, it is important that the name of the variable from the caller is not the same name as the local variable in the function. The local in the function is deleted when the function ends.

#!/bin/bash

#$1 is name of out param, $2 is name of out param
func () {
  local loc=8
  local diff=9
  local same=10
  eval "$1=$diff"
  eval "$2=$same"
}

loc=7
func out same
echo "loc = $loc"               #loc = 7
echo "out = $out"               #out = 9     
echo "same = $same"             #same = 

Tuesday, December 22, 2009

Jaxer in Aptana

I downloaded version 2.02 of Aptana Studio; it is supposed to have Jaxer in it. I cannot find it.

I have looked at many sites for using Jaxer, I am unable to do step 1 in any of these sites. They all refer to some button or menu in Aptana that is grayed out or that I do not have.

I found a good site at IBM that details how to install Jaxer as a stand-alone server on Windows.

It used a simple example demonstrating how to use a callback; of course, it failed. It turns out that the file that it is trying to access, http://update.aptana.com/update/jaxer/win32/version.txt, cannot be accessed.

I created a file on my own server that will report some number in the correct format: .0.9. Now the example works.

I have found the framework for Jaxer. The query string is in Jaxer.parsedUrl.queryparts.

Functions can be run on the server, client or both. A property of the Function object can be used to allow a server function to be called from the client: functionName.proxy = true. The runat property of the script can also be set to server-proxy, which sets the proxy property to true for all functions in the script block.

I have found an excellent introduction to using Jaxer.

Use Jaxer.request.currentFolder to get the absolute path to the current folder.

Use Jaxer.Dir.resolve to get an absolute path to a relative reference.
Jaxer.Dir.resolve(Jaxer.request.currentFolder + "/posts")

Unobtrusive JavaScript does not set event handlers in the HTML tags. Use JavaScript to set the handlers. If the tag is used, then it removes all other handlers.

form.submit is called when a form is submitted programatically, not by clicking a submit button.
form.addEventListener("submit", handler, bool) is called when a submit button in the form is called. The same effect as using onLoad, but onLoad can only register one event.

When overriding submit, it is good to store the old submit method. The new method will not have the default behavior of submitting the form; call the old method to submit the form. This also has an advantage of allowing the current method to be canceled without canceling the entire event. Once an event is canceled using event.preventDefault, it is not possible to enable it again.


<html>
<head>
<title>Submit Events, Handlers and Prototypes</title>
<script type="text/javascript">

function submitFromScript() {
//There is no event object, but 'this' points to the form.
alert("Submitted by calling submit from a script: this = " + this);
//call the original, if it has been set.
if (this.submitPrototype) this.submitPrototype();
}

function submitFromSubmitButton(event) {
alert("Submitted by clicking a submit button in a form");
}

function submitFromWindowSubmitButton(event) {
alert("Submitted by clicking a submit button in a form, caught by window event");
}

function submitFromHandler(event) {
alert("Submitted by clicking submit button and overriding the submit handler for the form");
if (this.submitHandler) this.submitHandler();
}

// Function to change the content of t2
function modifyText(event) {
var t2 = document.getElementById("t2");
alert("modify t2: " + t2);
t2.firstChild.nodeValue = "three";
}

// Function to add event listener to t
function load() {
alert("load")

HTMLFormElement.prototype.submitPrototype = HTMLFormElement.prototype.submit;
HTMLFormElement.prototype.submit = submitFromScript;

var el = document.getElementById("frmPost");
el.submitHandler = el.submit;
el.submit = submitFromHandler;

el.addEventListener("submit", submitFromSubmitButton, false);
el.addEventListener("submit", modifyText, false);

}

window.addEventListener("load", load, false);

</script>
</head>
<body>
<form id="frmPost">
<input type="button" onClick="document.getElementById('frmPost').submit();" value="Submit by Script">
<input type="submit" value="Submit Button">
</form>
<table id="t">
<tr><td id="t1">one</td></tr>
<tr><td id="t2">two</td></tr>
</table>
</body>
</html>


The event handler code should always be run in the client. If it needs to run server code, then it should call a proxy on the server.

When using jQuery and Prototype, they have a conflict with $(). Use jQuery.noConflict() to allow the Prototype definition to prevail.

$(id) only works on the server. Add a function on the client that does the same thing:
function $(id) {
return window.document.getElementById(id);
}


The blog example from this site has errors when accessing files. Use resolve and combine to translate to a path that can be read by the native file system.
Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));


Here is the modified file that works on a PC.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Write Blog</title>
<script src="lib/prototype/prototype.js" runat="server" type="text/javascript">
</script>
<script src="lib/showdown/showdown.js" runat="server" type="text/javascript">
</script>

<script runat="client" type="text/javascript">

function $(id) {
return window.document.getElementById(id);
}

function onSubmit(evt) {
var newPost = $("txaPostText").value;

if (newPost.length == 0) {
alert("You haven't entered anything.");
}
else {
if (save(newPost)) {
//add the new post
formatPost(newPost);
$("txaPostText").clear();
}
else {
alert("An error occurred. Couldn't save your post.");
}
}
//stop the form from submitting
evt.preventDefault();

$("txaPostText").focus();

}

function onLoad(){
$('frmPost').addEventListener('submit', onSubmit, false);
}

if (window.addEventListener) {
window.addEventListener("load", onLoad, false);
}
</script>
<script runat="server" type="text/javascript">

function serverLoad(){
//create the main posts <DIV>

var posts_div = document.createElement('div');
posts_div.id = 'posts';
document.body.appendChild(posts_div);

var path = Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));
if (!Jaxer.Dir.exists(path)) {
formatPost("Path does not exist: " + path);
return;
}
var dir = new Jaxer.Dir(path);
var files = dir.readDir().map(function(file){
var post = Jaxer.File.read(Jaxer.Dir.combine(dir.path, file.leaf));
formatPost(post);
});
}

window.addEventListener("serverload", serverLoad, false);

var formatPost = (function(showdown){
return function(content){
var post_div = document.createElement('div');
Element.extend(post_div);
post_div.innerHTML = showdown.makeHtml(content);

// insert new post in the main div
$('posts').appendChild(post_div);
}
})(new Showdown.converter());

function save(text){
try {
var path = Jaxer.Dir.resolve(Jaxer.Dir.combine(Jaxer.request.documentRoot, "blog/posts"));
Jaxer.Log.info(path);
var dir = new Jaxer.Dir(path);
//get the last post number
var lastFileNo = (dir.readDir()).length;
path = Jaxer.Dir.resolve(Jaxer.Dir.combine(dir.path, (lastFileNo + 1) + ".txt"));
Jaxer.Log.info(path);
Jaxer.File.write(path, text);

return true;
}
catch (e) {
Jaxer.Log.error(e);

return false;
}
}
save.proxy = true;
</script>
</head>
<body>
<h1>The Blog Page that Writes Files</h1>
<form id="frmPost" action="">
<textarea rows="10" cols="40" id="txaPostText"></textarea>
<input id="btnPost" type="submit" value="Submit Post"/>
</form>
</body>
</html>

While exploring the Aptana resources, I found that there is a new forum site. The old site has a lot of references to Jaxer, but the new site does not. The jaxer.org site references the old forum, but there is link in the old to the new.

The new forum site has a page for forum for App Studio that has an article on manual plugins. On the link for the Jaxer plugin, I followed these instructions and was able to add Jaxer to Aptana Studio 2.0.2.

Installing this Plugin via Aptana or Eclipse

1. From the Help menu, select Install New Software... to open an Install pop-up window.
2. In the Work with: text box of the Install window, type the URL http://update15.aptana.org/jaxer/25739/ for the update site, and hit the Enter key.
3. In the populated table below, check the box next to the name of the plug-in, and click the Next button.
4. Click the Next button to go to the license page.
5. Choose the option to accept the terms of the license agreement, and click the Finish button.

More things are working now. I am writing test code to see if everything works. I now have access to the samples.

The API shows there is a data object in Jaxer, but it is called clientData.
Jaxer.Cache is Jaxer.CacheManager.
Jaxer.SendOptions does not exist.

Friday, October 30, 2009

Outer Join in MS Query

SELECT UffMacBen.`FIRST NAME`, UffMacBen.`LAST NAME`, UffMacBen.MAC_EMPLID, UffMacBen_Original.`FIRST NAME`, UffMacBen_Original.`LAST NAME`, UffMacBen_Original.MAC_EMPLID, UffMacBen.`FIRST NAME` FROM {oj `U:\uweb\members\2009\UFFmacBEN_09032009_copy`.UffMacBen UffMacBen LEFT OUTER JOIN `U:\uweb\members\2009\UFFmacBEN_09032009_copy`.UffMacBen_Original UffMacBen_Original ON UffMacBen.MAC_EMPLID = UffMacBen_Original.MAC_EMPLID} WHERE (UffMacBen_Original.MAC_EMPLID Is Null) UNION SELECT UffMacBen.`FIRST NAME`, UffMacBen.`LAST NAME`, UffMacBen.MAC_EMPLID, UffMacBen_Original.`FIRST NAME`, UffMacBen_Original.`LAST NAME`, UffMacBen_Original.MAC_EMPLID, UffMacBen.`FIRST NAME` FROM {oj `U:\uweb\members\2009\UFFmacBEN_09032009_copy`.UffMacBen_Original UffMacBen_Original LEFT OUTER JOIN `U:\uweb\members\2009\UFFmacBEN_09032009_copy`.UffMacBen UffMacBen ON UffMacBen_Original.MAC_EMPLID = UffMacBen.MAC_EMPLID} WHERE (UffMacBen.MAC_EMPLID Is Null)

Wednesday, October 14, 2009

Reading Excel Files from JDBC

Reading Excel Files from JDBC


I followed this example from JavaWorld and it worked. The instructions were good, except for the explanation of why qas was used as the name of the worksheet. The file was named qa.xls, the connection was qa-list; it took me a few minutes to realize that the name on the worksheet tab was qas.

Next step is to read my own file and do a query. It worked.

Next step is to perform an outer join between two sheets in the same file.

I have created the outer join with the following syntax (from ibm):

query = "SELECT * FROM {oj [09032009$] LEFT OUTER JOIN [09172009$] ON ([09032009$].MAC_EMPLID=[09172009$].MAC_EMPLID)}";

The names of my sheets in the file are 09032009 and 09172009.

I have determined the number of columns in the result set (from devdaily):

    //------------------------------------------------------//
   //  Here's the code to determine the number of columns  //
   //  in the ResultSet.                                   //
   //------------------------------------------------------//
   Statement st = conn.createStatement();
   ResultSet rs = st.executeQuery("SELECT * from Customer");
   ResultSetMetaData rsmd = rs.getMetaData();

   int numCols = rsmd.getColumnCount();
This can also be used to retrieve a column name.

Saturday, September 19, 2009

Replacing the Hard Drive on a Vista Machine

I dropped my HP tx2-1950dx Touchsmart laptop the other day. Since then, the hard drive has been making clicking sounds. After doing a disk check, it seems that the area from 11% to 14% on the hard disk is in bad shape.

I ordered a replacement disk from HP and it arrived the next day.

The first thing that needs to be done is to create a recovery disk that can be used to boot the system from the CD. In Vista, type Recovery in the start box and select Create Recovery Disks. This uses the recovery partition on the hard drive to create disks that will restore the system to its original factory state. Please note, this should have been done BEFORE the drive was damaged!!!

I have also created a current backup of the drive using the Windows Recovery option. I hope that I can use these disks to restore the disk instead of using the original state disks.

I also used DriveImageXML to create a compressed backup of the disk, but I will need to figure out a way to run the software before the main partition is installed.

I will follow the instructions on http://www.bleepingcomputer.com/tutorials/tutorial144.html
, once I have my recovery disks created.

After running the recovery disk, it seems that I will need to reinstall the factory state and then restore the later recovery that was created in Vista.

There is no way to load an image of the disk, except for the original factory state. The HP recovery disk does not allow access to the Repair Computer utility that is normally accessed after pressing F8 during boot. The only way to load another image is to buy a piece of hardware that will add the new drive to the computer through USB. I have ordered such a device.

I borrowed the hardware from a friend, but it didn't work on Vista. I bought the hardware for Vista. It still didn't work. Some of the partitions could be restored but not the boot partition. After several attempts, I surmised that the boot partition was corrupt, since I made it after the crash.

I ran the "restore to factory state" disks and reinstalled additional software and updates. All is well now.

Wednesday, August 26, 2009

Modifying the boot loader in Vista

I miss boot.ini. Why isn't there a GUI version of bcdedit?

I could run bcdedit, but I could not read the boot loader store without admin permission. I found a useful link that had the secret to running cmd with admin permission: type cmd in the search window in the start menu and hit CTRL-SHIFT-ENTER. So obvious.

bcdedit /? will show all the options.

bcdedit /v will show all the boot choices, including the annoying ID.

bcdedit /delete ID /cleanup will delete a choice from the list, as long as you get the ID correct.

If the partition has already been deleted, then this will not work!!!

bcdedit /deletevalue ID type will remove the entry, if you know the type.

bcdedit /? /TYPES will tell you more about the types.

bcdedit /deletevalue ID DESCRIPTION desc should remove the entry, but it doesn't, of course.

The problem that I have is that I have already deleted the Windows 7 partition, so none of the commands work. If I use the current OS, then they work. For instance,

bcdedit /set description "Vista Sucks"

works beautifully. I can even use the ID as

bcdedit /set ID description "Vista Really Sucks"

According to several posts, the /delete command should work but it doesn't.

The solution was to download easybcd

More Blogs

Followers