Wednesday, November 17, 2010

Caveats of converting images from GIF to JPG using Java

Java has come so far that we expect it to be mature enough and handle any possible use-cases such as a simple GIF to JPG image conversion without any hiccups. But when converting GIFs which happen to have an alpha (transparency) property about them, the results of the conversion seem less than appealing.

To the layman (myself included) who knows nothing of alpha or transparencies, the impression the resulting image leaves is often described as:
  1. some how the colors have been inverted or reversed
  2. feels like you are looking at an image in a film roll
  3. everything seems to have had its black & white colors somehow switched about
These impressions make for a very difficult google search but when you do get the search words right (transparent gif jpeg alpha convert) you should hopefully end up at a post similar to this one which educates us about what is really going on and that there is much more to still look forward to from Java.

Saturday, November 6, 2010

Send different logs to separate files in Tomcat with log4j

Everyone who works with web applications must have at least once wished for separating out his/her log files. It is painful to scan for infomation when multiple threads are dumping information from all over. I'm sure that all the great admins who watch over production or staging systems must quickly learn to use tools that allow them to set up rules and get a clean view of what they need but developers tend to be a more lethargic breed.

I finally decided to dig though the web and put this extremely basic skill into my bag of known tricks.
  1. If you use log4j, do not waste your time reading the instructions for JULI when you land on the page in Tomcat's documentation which talks about logging.properties file etc.
  2. Everything that you need to do in order to send the logs to a separate file can be done in log4j.properties.
    • Unless you are looking to do something really advanced, in which case you should use log4j.xml file.
    • You can read more about that in this Log4j tutorial with Tomcat examples.
  3. Here's the basic blurb (+/-) that you can throw in with minimal edits to get the job done.
    ##
    # Name your appender whatever you want, and choose whatever
    # implementation makes most sense for you.
    ##
    log4j.appender.yourAppenderNameGoesHere=org.apache.log4j.RollingFileAppender
    ##
    # You will most likely want to place the log file in a known location.
    # Leverage ${catalina.base}/logs/yourFilename.log to accomplish this.
    ##
    log4j.appender.yourAppenderNameGoesHere.File=${catalina.base}/logs/yourFileName.log
    ##
    # The rest is generic stuff which you can tweak as you please.
    ##
    log4j.appender.yourAppenderNameGoesHere.MaxFileSize=2MB
    log4j.appender.yourAppenderNameGoesHere.MaxBackupIndex=10
    log4j.appender.yourAppenderNameGoesHere.layout=org.apache.log4j.PatternLayout
    log4j.appender.yourAppenderNameGoesHere.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss,SSS} %5p [%t] (%F:%L) - %m%n
  4. Use this blurb to direct the output from a particular package or a class to the appender you have created for the new separate file.
    # Redirect the logs from an entire package
    log4j.logger.com.my.packageName=ERROR, yourAppenderNameGoesHere
    # Redirect logs from only a specific class
    log4j.logger.com.my.packageName.MyClass=DEBUG, yourAppenderNameGoesHere
    # Set the additivity flag to false if you do NOT want the logs to show up redundantly in log files that the parent loggers point to
    log4j.additivity.com.my.packageName=false
    log4j.additivity.com.my.packageName.MyClass=false
  5. By the way, do NOT make the mistake of putting the name of your appender as one of the values in the following line of your log4j.properties file.
    # don't change this
    log4j.rootLogger=INFO, blah, blah, yourAppenderNameGoesHere

Using Blogging as a fundamental career tool

When I first joined the workforce, blogging was the last thing on my mind. But over the years I have realized that each and every one of us gains expertise at our jobs or on pet projects that doesn't always stay with us. The knowledge we gather in our day to day activities might not seem all that innovative or hard to come by, but as it builds over the years we start wishing that we had kept track what we did in the past.

Blogging allows me to appreciate the value of the challenges I've faced, solutions I've researched, hacks I've invented, plus the pros & cons ... all put down into words that seem like a godsend later on.

Blogging also serves as an excellent resource when you finally decide to move on with your career but quickly find yourself scratching your head as to how to update your resume. This is when you can take a look back at your blogs and remember all the wonderful technologies you've worked with and challenges you've tackled.

Of course there is a huge liability/responsibility that comes with blogging for a working professional which can always be summed up in one sentence: don't ever write about anything that will let your company wring your neck for it!

The basic etiquette that can perhaps keep you safe is simply writing about technologies and challenges in as generic a manner as possible. Focus on the true challenge and nothing else. Of course sometimes if folks in the industry can figure out who you are, who you work for and what you are working on currently then its best to write your piece and delay publishing it online until the information does not leak anything to the competition or is not time-sensitive anymore. And the ultimate "DUH" point is not to write about stuff so smart that it could be considered your companies Intellectual Property ;)

If you start small and cover yourself by not getting too ambitious as to what you write about, you'll gain immense satisfaction by going over the challenges both when you write them and when you review them later. It will give your self-confidence and career a boost as it will allow the online community to get to know how you think and how your abilities may be extremely specialized or widely varied.

So what are you waiting for? Take control of your career and start blogging!

Thursday, November 4, 2010

Understanding text encoding for Properties Files: Latin1 vs. UTF-8

Folks often want to have readable properties files that look like:
textInEng=this a sample of the japanese language's character set
textInJap=日本語の文字は、このサンプルでは、設定
But anyone who actually tries to use a human-readable file (like the one above) via Java will be surprised to see corrupted string values being loaded. The reason behind this is that by default Java's Properties class uses an input stream that has Latin-1 encoding. Also known as ISO-8859-1 encoding. So, reading UTF-8 as Latin-1 yields seemingly corrupted text as the boundaries for bytes that make upa character are all wrong and when Java once again converts it to UTF-8 (which is how the String class stores its data internally), instead of having access to the raw bytes, the boundaries set by Latin-1 characters are honored and that doesn't help us see any meaningful data either. This is why most properties files end up looking more like this:
textInEng=this a sample of the japanese language's character set
textInJap=\u65E5\u672C\u8A9E\u306E\u6587\u5B57\u306F\u3001\u3053\u306E\u30B5\u30F3\u30D7\u30EB\u3067\u306F\u3001\u8A2D\u5B9A
The patterns you see above (\uXXXX)are called unicode-escapes and allow a Latin-1 stream to properly convert each character into its UTF-8 equivalent and hand it off to Java whose internal storage encoding for the String class happens to be UTF-8 already.

But what if you wanted more? What if you absolutely must have human-readable properties files and they must be loaded into Java correctly?
  • Well if you are using Spring, there is an easy way out: just have a look at ReloadableResourceBundleMessageSource and use it to your advantage, problem solved!
  • Otherwise here's how you can get the best of both worlds yourself:
    1. Let Java's Properties class read in the UTF-8 values incorrectly with the Latin-1 encoding.
    2. Then go over each value and convert it back into bytes by telling the code to pass it through Latin-1 for the reverse transformation.
    3. Now that you have the raw-bytes again, you can read them in properly with the appropriate UTF-8 encoding!
    4. Set them back into your Properties object and you are good to go!
    5. See the code (+/-).
          private static void FourthTry() throws IOException {
              FileInputStream inputStream = null;
              try {
                  inputStream = new FileInputStream("utf8.properties");
                  Properties defaultProperties = new PrettyPrintProperties();
                  defaultProperties.load(inputStream);
                  for(Entry keyValuePair : defaultProperties.entrySet()) {
                      byte[] rawBytes = ((String)keyValuePair.getValue()).getBytes("ISO-8859-1");
                      String recoveredString = new String(rawBytes,"UTF-8");
                      keyValuePair.setValue(recoveredString);
                  }
                  PrintStream customConsoleOuput = new PrintStream(System.out, true, "UTF-8");
                  customConsoleOuput.println(defaultProperties.toString());
              } finally {
                  if (inputStream!= null) inputStream.close();
              }
          }
    6. If you want to test it in Eclipse, make sure to: Open Run Dialog > "your application" > Common Tab > Encoding > Other dropdown > set it to UTF-8
    But keep in mind, you cannot be inconsistent. You must pick choose to have the key-value pairs in your properties files be either utf8 or latin1, do NOT mix them like this:
    textInEng=this a sample of the japanese language's character set
    textInJap=日本語の文字は、このサンプルでは、設定
    escapedJp=\u65E5\u672C\u8A9E\u306E\u6587\u5B57\u306F\u3001\u3053\u306E\u30B5\u30F3\u30D7\u30EB\u3067\u306F\u3001\u8A2D\u5B9A
    Happy Coding!