Saturday, November 06, 2010

Finally we've got Base64 in Java...

It was always a pain and we used those strange Sun packages (crossing fingers, of course). But now Java 6 has a little thing, that is a standard package and won't collide, at least:

public static byte[] decodeFromBase64(String encoded) {
return javax.xml.bind.DatatypeConverter
.parseBase64Binary(encoded);
}

public static String encodeToBase64(byte[] binary) {
return javax.xml.bind.DatatypeConverter
.printBase64Binary(binary);
}

Nothing special. Just nice to know. :-)

Thursday, October 28, 2010

VMWare and Spring

VMWare bangs their bells for Spring framework, trying to tell it is best choice. Lots of people excited etc.

Now (*cracks my fingers*) questions and doubts:
  1. Spring's arguments are valid. Yes, they are. With one little note: they are valid on EJB2 and JEE5, where first one has incredibly bad design, another is bulky and not really convenient. Wait a second... but we are not talking for old projects future, but for new! So, when you going to choose framework for plain new project, the we do have EJB3 and JEE6 today.
  2. RedHat (also known as a leader at Enterprises in Linux world, by the way) and Snorcle (also know as Oracle, also known as benevolent dictator, also known as Sun Microsystems eater) — both of them completely don't really like Spring. In fact, they think it is a bullshit and they think JEE6 would fit to your datacenter much better.
  3. Do you really like that XML thing? I think this is all like back to a stone-age, instead have just everything minimalistic and cute (means: modern).
  4. Template classes as intrusive as it turns your code to a bullshit. Yes, you can have a workaround for this, but the keywords here are still stays to "bad" and "design".
  5. Tell me, you configuring or you coding?.. In Spring you will code^H^H^H^Hconfigure your project in XML. Well, no, you're literally coding. You are freakin' coding in XML, don't get fooled and mislead.

    Let me explain here a bit: a configuration file is something like you can find in Unix /etc directory. It is a small, simple ASCII text file, you can put comments in there and you can parse it with your Perl/Python/Ruby or just AWK/Sed. This is what is called: configuration file and was more than 30 years around. Now what Spring brings you into? A pile of XML, that are actually built into your WAR file. They do believe you have to change XML, so no need to change source code of Java.

    But this is utterly misleading: you intrude to a deployed application anyway (sane companies will put it through a "Change Request" procedure that involves also testing and quality assurance sometimes), while configuring application means you change only that little cute file in /etc directory (or click few checkboxes in admin UI) and thus your buddy sysadmin can do that with a cigarette in his teeth with a little effort (change request still required, but a consequences are significantly smaller).
  6. Spring adds complexity, it does not removes it. Don't be fooled: you will need to have a serious and difficult learning curve as well as you will need to spend weeks to configure your XML (see above).
  7. Bugs in framework itself will cost you a lot. So make sure your framework is extensively supported, reviewed and updated. Who you will trust more: giants like Oracle and RedHat that has tons of very fat customers, or just a little VMWare — yet another player in virtual world with not the best business model? You choose.
  8. OK, you can dismiss my XML rants by changing from XML to annotations. Great point! Because here is another problem: different ways to do the same thing. Java coders chronically away from Unix, but we already been there and we know it is called as "Tim Toady" or TMTOWTDI or "There's More Than One Way To Do It" or, simply Perl. It results to things like this or like this. In contrast, the beauty of Python language lays in its great philosophy: "There should be only one — and preferably only one — obvious way to do it".
    Little note to above: I was not talking about code obfuscation.
  9. We already learned that doing often casting is a bad idea. So that's why we do have Generics for this and why we are trying to go away from casting operations as much as far as possible. However, Spring is pushing you back to a mesozoic era to fight java.lang.ClassCastException dinosaurs each next step. Stupid.
  10. \u3042\u306a\u305f\u306f\u99ac\u9e7f\u3067\u3059 — this is how to say "Good morning" to your boss in Japanese (anata ha baka desu), or exactly what you will get, once you open your ResourceBundle in VIM editor.
  11. It is going up to eleven... You normally should keep SQL separate from the code. Try it with Spring and see how it works (or not) for you.
Of course, the main question still around: Why bother with Spring, if JEE6:
  • Is getting to be more and more lightweight than Spring 3
  • Is less complicated (recently) than Spring 3
  • Is well designed
  • Is well documented
  • Is well supported
  • Is an industry standard and chosen by industry leaders (sure).
  • Has more features
  • Is easier to learn (because it is less complicated)
  • Is not proprietary, versus Spring which is proprietary container.
I certainly don't have an answer on above. Maybe you have?

Feel free to explain. :-)

Tuesday, October 19, 2010

JSR 286 and crying developers

JSR 286 is probably a primary way of how any web-related stuff should be done. Definitely. However, it has some nasty limitations, that would lead novice to hit the wall, step on rake, step on rake again etc. One of such limitations (well, not really, but still) is to return a file. Normally, JSR286 wants you to return HTML. But what if you want to click on some button and get a PDF file or TIFF or DOC or MP3 and so on? Usually, developers are setting content type, putting some content disposition to define filename etc, put some headers to flush cache, write to the output stream, recompile and deploy.

Problem solved.
No, not really: once they call their portlet, entire application disappears and log is filled with devil's 666 lines of Java traceback from Hell. So, random desperate rants over forums begins usually with "me too!" or "pass me some code!" messages.
The real thing is: you need to read JSR286 properly. See, the JSR 168 does not allows us to use something else than just HTML. Pretty much silly. But JSR 286 allows. How? Easy: serve it as a resource. Hence the recipe:
  1. Implement/override method in GenericPortlet:
    serveResource(ResourceRequest request, ResourceResponse response)
  2. In your JSP (or whatever you use) refer to it with Resource URL. In JSP you do it like this (use it on your own way):
    renderResponse.createResourceURL().toString()
  3. In that "serveResource" thing check your request parameters and then return your content into an InputStream.
Keep in mind, that normally you're dealing with ResourceResponse, which is different than HTTP response in a servlet. So after you've put content type in usual way, "setHeader" method is actually not available. But you can always use "setProperty" instead.
Now, if you are smart enough and using Liferay :-) instead of something else, then you simply could use one-liner PortletResponseUtil class, wher you can find a bunch of "sendFile" or "write" methods. They are just for your convenience: get from byte array, InputStream etc. As an example how it works, watch:
PortletResponseUtil.sendFile(response,
"test.pdf",
new FileInputStream(new File("/tmp/test.pdf")),
"application/pdf");
Now use your own imagination how to make it actually right (by replacing FileInputStream with something more valuable, as a starter).
This is it. Enjoy. :-)

Tuesday, October 12, 2010

Thursday, October 07, 2010

Jasper Reports: gone!

OK, this is it. I fed up fighting Jasper Reports and simply ditched it. BIRT (or "dirt" — you call it) although has interesting things, still is even worse than the Jasper Reports. There is also Pentaho Reports available. They are actually nice, but buggy as hell, crashes and has no much features. Embedding is odd.
At first, I don't need that fancy GUI editor. I simply don't. Do you need? No, you don't either. Here is why: it requires programming anyway. So if you think you will get this sexy full-screen editor with mousedraggable objects and will pass you your girls at operations department — you're wrong, wrong and once again wrong. They won't use that. Because if boss will ask you to make red color some figures that are greater than 1000 — what you will do? It is not anymore mousedraggable and clicketyclickdroppable.
At second, I had a trouble with Japanese, but that's font package installation. Why do they do it this way — their problem. I don't like their (Jasper Report's) way to distribute fonts either.
Therefore I decided to make my own parser of my own markup, that is very similar to RML, but is more looks like just a regular HTML. Basically a 50/50 mix of them.
So far, I achieved (in compare to Jasper Reports):
  • Something like 40 times faster PDF compilation. Yes, up to forty times.
  • A very simple way to embed it to your servlet. The keyword here: "very". It is mostly a re-entrant one-liner, something like this:
    new PDFRender(OutputStream, InputStream);
  • Very small footprint.
  • Resulting PDF simply crashes my Preview.app ... BWAHAHAHAHAHAHA!
It renders still bit ugly sometimes and I still working on styles, but I have fully controlled by styles headers, footers, pagination, page layout, text body, paragraphs, True Type fonts, embedded images and a simple grid-like tables.

Soon table spanning and styling is still coming (probably right tomorrow). Later I will add SVG support for native charts (still don't know how what way to do it is the best), barcodes and lovely Japanese QRCode that is required just everywhere through.

Friday, September 17, 2010

Custom TTF Fonts in JasperReports

You hit this wall too, aren't ya? At first I was truly pissed off by the overall design of Jasper Reports (entire suite in general). At second, I am even more pissed off how fonts are handled in PDFs.

First what you do, is you're trying to install some TTF fonts into your JVM, somewhere in $JRE/lib/fonts, map them and hope things will fly. Then you probably specify that your new font in Jasper Report XML file, something like:
<font fontName="Great Font" />
...and you finding it not working: in your PDF you see Helvetica. If you expect some Asian support (Japanese, e.g.), then you will find blank space there. Familiar, eh? Of course, you go around the XML Schema and finding that Jasper Reports actually has some more arguments to the "font" aggregate, so you adding it:
<font fontName="Great Font" ispdfembedded="true"/>
...and you finding it not working: in your PDF you see Helvetica. Then you, puzzled, finding out that there is also some more attributes (although they are quite odd anyway), so you use them too:
<font fontName="Great Font" ispdfembedded="true"
pdffontname="/madly/hardcoded/path/on/the/system/to/your/greatfont.ttf"/>
...and you still finding it not working: in your PDF you see Helvetica. Then you, angry, yelling "WTF!!!", googling around and you finding a lots of people, suffering from the same problem.

The key to solve this puzzle is to deal with completely stupid implementation of Jasper Reports engine: you have to package these fonts into JAR file and embed into your application. They (developers) think that since it is Java, so "run everywhere", therefore you take your .WAR or .JAR or .EAR file and put on any possible container and it will just work, so no need to setup the environment. In reality, however, when you deploy 1000 applications like this, you also have 1000 duplications of the same stuff. It results to a horrible mess and very very VERY angry sysadmins that literally hates all the guts of Java. Moral: keep it simple, stupid.

So anyways, how to use own TTFs or at least find Japanese visible? JaperReport's answer is: put this stuff into JAR and toss in into the classpath. Here is how to do it:
  1. In the default, root package, create a property file with a magic name: jasperreports_extension.properties
    Developers could not name it more elegant, like fonts.properties or, perfectly elegant, having none of it at all.
  2. Create a package for your fonts. Let's say it is foo.bar.fonts
  3. In this strange properties file we've made above, you have to put two things at least. One is very magical static property that normally can be hardcoded once and forever somewhere deep in the guts of JasperReports and never ever remembered anymore:
    net.sf.jasperreports.extension.registry.factory.simple.font.families
    =net.sf.jasperreports.engine.fonts.SimpleFontExtensionsRegistryFactory
    Can you read that wide?
  4. Another property is to reference the reference to the reference of the actual files, embedded into the JAR:
    net.sf.jasperreports.extension.simple.font.families.somebullshit
    =foo/bar/fonts/fonts.xml
    That's how to let finally Jasper find the fonts.xml file. Please not one very nasty and ugly thing: there is no leading slash prior to "foo". Noticed? If you put it (as it should be), then forget it working.
  5. Now, in the foo.bar.fonts package create "fonts.xml". You can change its name in step #4.
  6. Map your fonts there as it is in examples of JasperReports (demo/fonts).
  7. Compile all this assembly into a JAR file and toss in somewhere in your app $CLASSPATH. Now your PDF should pick up the font finally.
  8. Phew!
If you still find this idiotic (like I do), you'd better try Dynamic Jasper http://http://dynamicjasper.sourceforge.net/ and it suppose to help you.

You might ask: how it should be better implemented? OK, you ever heard about X11 and how fonts are mapped there? In the same fashion. Why not use just fontmap.properties file in the JAR and just simply drop fonts there and have zero XML? Yes, it is magic name, but it is the only magic name. And then stick to something like one line per font, e.g.:
family=weight,encoding,embedded,file.ttf
Said that, it might look this way:
greatfamily=n,UTF-8,t,greatfont-nnormal.ttf
greatfamily=i,UTF-8,t,greatfont-italic.ttf
greatfamily=b,UTF-8,t,greatfont-bold.ttf
greatfamily=bi,UTF-8,t,greatfont-bold-italic.ttf
Then, you run something like $JASPER_REPORTS/bin/fontpack ...and it would create such a JAR right away for you. How that sounds? That sounds just greatly simplified yet idiotism. What it actually should be: you specify font name "Great Font" (not path to actual TTF!) in the XML and it picks up automatically from the JVM right away. If font is not installed, then it has to fall-back to the default (Helvetica, in this case) by warning the user to the log file (instead of crashing, by the way).

Still, I suffer from its performance, if this is the word. Generating PDFs are still hell very slow for my requirements. My next step will be ditching JasperReports and go OpenOffice.org as template editor and renderer iText based engine. Well, if company will pay for that. :-)

Wednesday, September 01, 2010

Nexenta 3.0 Zones: Fixing Broken Bones

As a rule of thumbs, when things installs very smoothly, I always suspect something wrong, because there is an old Ukrainian saying: "Devil lives in a silent lake". This time same thing happened to newly installed Nexenta Core 3.0 Release. Installation went just as sweet and smooth.

But when it comes to zones... :-(

Long story short: Zones are just totally broken in Nexenta Core 3.0 Release, end of story. SSH won't work, you won't login, no passwords asked, nothing. And I am quite surprised it was never fixed (probably nobody took a chance to test it). Now is the way how I fixed, grepping over bugs database:

First, before you install a zone, you have to fix broken /usr/bin/createzone Perl script. This should be done in two steps:
  1. Replace elatte-unstable with hardy-unstable on a line #41.

  2. Throw away @source_files with all its guts and replace with the following:
    my @source_files = qw(
    /lib/svc/method/nexenta-sysidtool-system
    /var/svc/manifest/system/nexenta-sysidtool.xml
    /lib/svc/method/nexenta-sysidtool-net
    );
Second, fix broken /lib/svc/method/svc-syseventd script. This is done in quite dirty way, but at least works fine:
  1. In the global zone edit the script above. Find this line (below the CDDL header):
    . /lib/svc/share/smf_include.sh
    ...and add this:
    [ `zonename` = global ] || sleep 3600 & exit 0
    ...so in result you will get this:
    . /lib/svc/share/smf_include.sh
    [ `zonename` = global ] || sleep 3600 & exit 0

This will allow required services finally start.

Now you can install your zone (zoneadm -z yourzonename install).

Third, fix shadow and passwd. Boot your zone and zlogin to it in a single mode (-S), then issue pwconv command and exit.

Finally, after you anyhow login to that thing, reconfigure broken system service once again, like this:

dpkg-reconfigure sunwcsd
svccfg import /var/svc/manifest/system/sysevent.xml

And yes, this is Unix. You should reboot your zone in order it getting working right. :-)