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!


Sunday, October 31, 2010

How to list multiple encrypted passwords in properties files

Jasypt is an extremely useful toolkit for encrypting and decrypting passwords. It provides simple instructions for those who want to use Spring and load properties files with encrypted passwords in them.

But, what if you need to provide a whole series of usernames and passwords. How would you accomplish this?
Jasypt's out-of-the-box implementations only read one encrypted value per key=ENC(value) pair in a property file.

Here's a solution:
  1. Override the EncryptablePropertyPlaceholderConfigurer's convertPropertyValue() method. Then you can split a list like the following:
    listOfUsernamePasswords=LIST(username1,ENC(encryptedPassword1),username2,ENC(encryptedPassword2))
    into separate values and only send the encrypted values to the parent convertPropertyValue() implementation to get the decrypted values.
  2. Sew the list back together as a string and return a value that now reads:
    username1,password1,username2,password2
  3. You may be wondering as to who will do the work of breaking up these comma-separated values when they get to your spring bean? The answer is simple: Spring will! For ex: If you had configured you spring bean like so:
    <bean id="someBean" class="com.MyBean">
        <property name="multipleUsernamePasswords" value="${listOfUsernamePasswords}" />
    </bean>
    and the multipleUsernamePasswords property is of type String[] in MyBean class, then StringArrayPropertyEditor will be used implicitly, which will break it up into a string array auto-magically. If you are interested, you can read this blog about how various structures interpret property values for Spring.

  4. Now its up to use that String[] to your advantage in your code.

Generating UML Diagramns with Maven

  1. Install Graphviz. After installation confirm that it is part of your PATH.
  2. Configure your maven pom files to make sure that you can get to the following repository: http://mirrors.ibiblio.org/pub/mirrors/maven2 because it has the second piece of the puzzle, the binaries for UMLGraph. You can see all the options for use in <additionalparam/> here.
  3. To generate UML diagrams as part of the "mvn javadoc:javadoc" command, add the following (+/-) to your pom.xml file's <build/> section.
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-javadoc-plugin</artifactId>
            <configuration>
              <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>
              <docletArtifact>
                <groupId>org.umlgraph</groupId>
                <artifactId>doclet</artifactId>
                <version>5.1</version>
              </docletArtifact>
              <additionalparam>-views</additionalparam>
              <destDir>target/uml</destDir>
              <show>private</show>
            </configuration>
          </plugin>
  4. To generate UML diagrams as part of the "mvn site" command, add the following (+/-) to your pom.xml file's <reporting/> section.
      <reporting>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-javadoc-plugin</artifactId>
            <reportSets>
              <reportSet>
                <id>uml</id>
                <configuration>
                  <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>
                  <docletArtifact>
                    <groupId>org.umlgraph</groupId>
                    <artifactId>doclet</artifactId>
                    <version>5.1</version>
                  </docletArtifact>
                  <additionalparam>-views</additionalparam>
                  <destDir>target/uml</destDir>
                  <show>private</show>
                </configuration>
                <reports>
                  <report>javadoc</report>
                </reports>
              </reportSet>
            </reportSets>
          </plugin>
        </plugins>
      </reporting>
  5. That's it, you should now be reaping the benefits as your javadocs will have UML diagrams inside each class's landing page. I used the following post to put all this info together: http://wiki.wsmoak.net/cgi-bin/wiki.pl?UMLGraph

Friday, October 1, 2010

ResourceManager is only as good as the components you use it with

The flex framework provides many conveniences out-of-the-box, one of them being the ResourceManager. It works wells and until recently I thought one could do no wrong by it.

Yet, as I recently found out, even the most fool-proof components are only as good as the developer using them. Being someone who started working directly with Flex 4, I have had it way too easy. And sometimes I miss out on the bigger picture as I lack the fundamentals that someone who predates the flex 4 framework, would naturally have.

Recently I was faced with a surprising scenario where the ResourceManager had all the translations in various languages for a given key, yet it would always only load one set of translations. After loading the initial translation for a given language, it would simply refuse to update the label, even as I flipped through and tried to change the locales one by one.

The resources for the resource manager were being downloaded from the server side and loaded on the fly into the ResourceManager instance. Adobe has a very nice example of this on their live docs website. But the first translation for the first language to have appeared would stick around and not change!

Another colleague, who was not so naive as to simply take things at face value, pointed out to me that I was trying to use the ResourceManager too soon so perhaps the translation in my label was from a point in time when the rest of the translations had not made it over. But looking at IResourceManager we realized what a well-behaved component it is! As it makes an effort to fire-off change events in order to alert its users that perhaps now there are more exact/locale-specific translations for them to lookup. So what could possibly be wrong?

The AHA moment: my pre-flex-4 colleague noticed that the over-arching component containing the ResourceManager bindings was actually and since it did not implement, extend or mixin the event dispatcher functionality, it would NOT receive property change events! And as soon as I started using something like the problem disappeared.

It just goes to show you that frameworks cannot replace a competent and well-versed developer who excels in his/her area.

Wednesday, September 1, 2010

How to view source for an embedded SWF hosted on a different domain

This is second in a series of blogs that attempt to capture all the aspects of making a good blog even better. The first one covered how to Add SWFs to your blogger posts.

Today we will cover how to allow the SWFs in your blog to provide the users with the option to with the source. You can start by following the instructions provided here, in order to make sure that when users right-click on a SWF file, they would see the "View Source" option.

But this brings up a new challenge if your SWF file itself is embedded in the blog but is actually hosted elsewhere because right-clicking and selecting "view source" results in a URL which is broken because it is generated relative to the blog (http://www.blog.com/article/srcview/index.html) ... instead of the hosting webspace url (https://some.website.com/hosting/srcview/index.html).
  1. You might notice that when you use Flash Builder to publish the code, it adds the viewSourceURL property to your main application file. What you need to do in addition to that is:
    1. Leave the original property in place because setting it later for the first time in an event handler, such as the one for applicationComplete, does not add it to the context-menu so one must still have the original attribute/propety in the application tag.
    2. Set the viewSourceURL again in a handler for the applicationComplete event so that the value is updated correctly.
    3. Build the host URL as shown here in the handler when updating the viewSourceURL value.
    <s:Application
                   ...
                   viewSourceURL="srcview/index.html"
                   applicationComplete="applicationCompleteHandler(event)"
                   >
        <fx:Script>
            <![CDATA[
                protected function applicationCompleteHandler(event:FlexEvent):void
                {
                    var swfURL:String = FlexGlobals.topLevelApplication.loaderInfo.url;
                    swfURL = swfURL.substr(0, swfURL.lastIndexOf("/") + 1)
                    var tempDom:Array = swfURL.split("/");
                    var domURL:String = tempDom.slice(0,3).join("/") + "/";
                    viewSourceURL = domURL+ "srcview/index.html";
                }
            ]]>
        </fx:Script>
        ...
    </s:Application>
  2. A workaround is to use the <iframe/> tag instead of <embed/> tag because that way the url generated to "view source" will be relative to the hosting website and not the embedding website.
  3. Also there is some speculation that if one uses swfobject instead of the embed tag. This blog seems to have a non-standard URL specified for the source versus the SWF but it is relative and not absolute, so again it may or may not work for absolute URLs. Following this example, it could probably be accomplished like so:
    var flashvars = {};
    flashvars.srcUrl = "https://some.website.com/hosting/srcview/index.html";
    ...
    swfobject.embedSWF(arg1,arg2,arg3,arg4,arg5,arg6,flashvars,arg8,arg9);

As a side-note here's an article that makes a very convincing argument for using SWF Object 2.

Flex4: How to build a Stop Watch Timer

Here's a working sample:

The following blog offered a series of very convincing arguments that led me to use flash.utils.getTimer() to build the Stopwatch demonstrated above.

The component constantly resets the time based on when it is made visible/invisible (click here twice to see it get reset +/-). If your components show a custom busy / loading skin rather than just a simple busy cursor, then you can leverage this component to also track how long your activities usually take visually.

Here's the source code:
  1. main.mxml
  2. StopWatch.as
  3. StopWatchSkin.mxml



Friday, August 13, 2010

Best Practice (my way) for managing "states" in ItemRenderer

When you have an ItemRenderer that has many states and the look/size of the ItemRenderer changes drastically between these states, what's the best way to manage them? What do you do when you need to maintain/keep track of the state of the ItemRenderer?

Because Flex framework reuses ItemRenderer for performance optimization, you can not maintain/keep track of the state in the ItemRenderer itself - ItemRenderer has to be stateless. The state of the ItemRenderer should be maintained by 'data' that drives it. The 'data' should keep enough information about the state of the ItemRenderer such that when ItemRenderer renders this 'data' it can determine which state it should go into.

Here an example -
ItemRendererA has two states 'a' and 'b'. The 'data' it renders is 'objectA'. 'objectA' has two vars - 'stateA' and 'stateB' that keeps track of this particular ItemRenererA state. Note: 'objectA' is part of the model and it persists state information.


<s:States>
  <s:state name='a'/>
  <s:state name='b'/>
</s:States>

// define boolean vars that will drive state changes
// State 'a'
private var _a:Boolean = false;
public function get a():Boolean
{
  return _a;
}
public function set a(value:Boolean):void
{
  if (value)
  {
    _a = value;
    _b = !value;

    // need to do this below to force a call to getCurrentRendererState()
    // ItemRenderer does not have 'invalidateRendererState()' function
    // which really sucks!
    setCurrentState(getCurrentRendererState(), true);
    if (autoDrawBackground)
    {
      redrawRequested = true;
      invalidateDisplayList();
    }
  }
}

// Do the same thing as above for state 'b'

// override set data function to set initial state
override public function set data(value:Object):void
{
  super.data = value;
  initializeRendererState();
}

private function initializeRendererState():void
{
  // 'data' here is 'objectA' which contains vars 'stateA' and 'stateB'
  if (data.stateA)
  {
    // setter for 'a' will force a call to getCurrentRendererState()
    a = true;
  }
  else if (data.stateB)
  {
    // setter for 'b' will force a call to getCurrentRendererState()
    b = true;
  }
}

// returns current state of the ItemRenderer
override protected function getCurrentRendererState():String
{
  if (a)
  {
    return "a";
  }
  else if (b)
  {
    return "b";
  }
}

Code above will make sure that ItemRenderer state is driven off of the 'data' that it's rendering and that ItemRenderer itself remain stateless.

Flex Pretty Formatting

When you have multiple Flex developers working together, it's often a good idea to agree upon a single syntax for .as and .mxml files. It'll enhance readability and maintainability of the code. But it'd be a nightmare trying to adhere to the agreed upon syntax manually so there's a nifty tool (Flash Builder plug-in) that you can use to do so.

Plug-In Site -
http://flexformatter.googlecode.com/svn/trunk/FlexFormatter/FlexPrettyPrintCommandUpdateSite/

Just install this plug-in and you'll have an option called "FlexFormatting" under the Flash Builder preferences. Set the syntax rule for Actionscript and MXML and export it. Now you can give this exported file to your co-developers for one uniform syntax.

Word of Caution - We found out the hard way that if you format existing MXML code using this plug-in, the layout defined in the MXML gets messed(?) up. It's only the syntax/format that gets changed/re-arranged and property values stay absolutely the same, but layout is affected somehow. So be careful to turn on auto formatting feature if you're editing existing MXML files. Make sure the layout stays the same before committing your changes.

Thursday, August 12, 2010

Hudson: Deploy to container based on a schedule

Challenges:
1) The schedules in Hudson jobs apply to Build Triggers. There isn't any separate place to specify a schedule for Post Build Actions like Deploy war/ear to a container.
2) A job without any build information and only deployment info, will not run the Post Build Actions.
3) Cloning an existing job only for the sake of changing the schedule for deployment will mean throwing off the Hudson build numbers placed inside of your artifacts. Even if you un-check the Archive the artifacts option in the cloned job's configuration it will be meaningless ... the clone's artifacts will continue to be published/installed into your local repository over the original ones by maven itself.
4) The clone might get associated as a downstream job and therefore would end up running whenever your original job had finished running. This would make the custom schedule pointless!

Solutions:
  1. Clone the job for which you want to schedule deployments.
  2. If you are using a pom.xml which is set up to use child modules then just directly have the cloned configuration reference the pom.xml of the child which actually puts together the war/ear artifact ... instead of the main parent project's pom.xml file.
  3. Uncheck the following option from the clone's configuration to decouple the upstream/downstream relationship if there is any:
    Build whenever a SNAPSHOT dependency is built
  4. Within the pom.xml file which actually generates your war/ear artifact, place the cargo plugin and its configuration to deploy remotely.
    1. It wouldn't hurt to start with the original documentation for reference on how to do this exactly. But it doesn't talk about the most crucial part which is the use of the cargo.tomcat.manager.url property which is covered in this blog. It is a very good example on how to do this.
    2. Since you are going to commit the altered pom.xml file you may be worried about the side-effects on your original job that performs the build. Well if you build only runs up to the install phase, you don't have to worry about anything as cargo goals are not part of the maven lifecycle up until that point. Everything about your original build will continue to work as it did.
    3. You can also check This build is parameterized and specify string parameters so that you don't have to go changing your pom.xml everytime that your source location of the war/ear file changes or the tomcat that you want to deploy to changes. Here's a sample (+/-)
        <properties>
          <artifactFileLocation>${ARTIFACT_FILE_LOCATION}</artifactFileLocation>
          <remoteTomcat>${REMOTE_TOMCAT_URL}</remoteTomcat>
        </properties>
        ...
            <plugin>
              <groupId>org.codehaus.cargo</groupId>
              <artifactId>cargo-maven2-plugin</artifactId>
              <configuration>
                <!-- Container configuration -->
                <container>
                  <containerId>tomcat6x</containerId>
                  <type>remote</type>
                </container>
                <!-- Configuration to use with the container -->
                <configuration>
                  <type>runtime</type>
                  <properties>
                    <cargo.tomcat.manager.url>${remoteTomcat}/manager</cargo.tomcat.manager.url>
                    <cargo.remote.username>username</cargo.remote.username>
                    <cargo.remote.password>password</cargo.remote.password>
                  </properties>
                </configuration>
                <!-- Deployer configuration -->
                <deployer>
                  <type>remote</type>
                  <deployables>
                    <deployable>
                      <location>${artifactFileLocation}</location>
                      <pingURL>${remoteTomcat}</pingURL>
                    </deployable>
                  </deployables>
                </deployer>
              </configuration>
            </plugin>
    4. Come to think of it, username and password would also benefit from being parameterized.
  5. Take advantage of the new configuration in your artifact generating pom.xml file by configuring the following goal in Hudson for the cloned job:
    org.codehaus.cargo:cargo-maven2-plugin:deployer-redeploy

Wednesday, August 4, 2010

Illustrator to Catalyst: Make Rects not Paths

Catalyst has this annoying habit of converting almost all shapes coming from an Illustrator's .ai file into paths. Even if we have simple rectangles or curved edges, the whole thing becomes a path which is such a waste.

Monday, August 2, 2010

Making the most of Hudson: File System SCM plugin

Often enough your development team may get into situations where they are sure that the code works just fine on their local machines but they are not so sure what would happen if they check-in and let Hudson build it.

Simply downloading & deploying hudson.war to the developer's machine to perform builds may not seem like a very useful solution. The build may now run through the Hudson hosted on the local dev box, but the build configuration would still have to point to an actual repository. This would make the whole endeavor pointless!

This is where the File System SCM comes in. If this plugin is also installed on the Hudson instance deployed to the dev box, then the developer can point to the locally checked out code and modified files as a standalone repository of sorts. It is an easy way to test that Hudson builds go through successfully. If this works then checking into the actual repository after a successful run is not a risk anymore.

Versioning Flex Applications: Displaying Hudson, Maven, SVN build or revision numbers

Hudson sets the values for the following environment variables:
  1. BUILD_NUMBER
  2. SVN_REVISION
In order to show the build and revision numbers in the UI, these variables could be written out to a properties file via a maven project's pom.xml file using a plugin. And then if one did this early enough in the maven lifecycle, your flex application could be compiled to read the version information as key-value pairs from the properties file and show the info on screen when it runs.

Alas there is no decent maven plugin out there to write environment variables out to a file. I found the following plugins out there but none of them (+/-) did the trick.
  1. org.codehaus.mojo:properties-maven-plugin can be found in the following repo You can find proper documentation here. It never printed anything but the Java system level variables so it was useless when it came to tracking the environment variables set by Hudson.
  2. org.sonatype.plugins:maven-properties-plugin can be found in the following repo but this isn't the one you want to use. It has only one goal called filter-file and I cannot find any page documenting its usage no matter how hard I try.
  3. Even placing the info generated by the mvn help:system command-line invocation seemed like a decent idea. But after configuring the same command to be invoked inside a pom file(+/-) I realized that it spit out some header lines that weren't commented out in a manner suited for a properties file.
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-help-plugin</artifactId>
            <version>2.1.1</version>
            <executions>
              <execution>
                <phase>generate-resources</phase>
                <goals>
                  <goal>system</goal>
                </goals>
                <configuration>
                  <output>${basedir}/src/locale/app.properties</output>
                </configuration>
              </execution>
            </executions>
          </plugin>

You can resort to usind the ant plugin inside Maven to do a macro-style replace technique. You can read more about it here.

Or the best way is to have a template file (+-) and leverage Maven model like this (+-)
<?xml version="1.0" encoding="UTF-8"?>
<root>
<buildNumber>${buildNumber}</buildNumber>
<svnRevisionNumber>${svnRevision}</svnRevisionNumber>
</root>
<project >
  ...
  <!-- Map the values provided by the Hudson build to local variables -->
  <properties>
    <buildNumber>${BUILD_NUMBER}</buildNumber>
    <svnRevision>${SVN_REVISION}</svnRevision>
  </properties>
  ...
  <build>
    ...
    <!-- Update version.xml file with the versioning data -->
    <resources>
      <resource>
        <targetPath>${project.build.directory}/${project.artifactId}-${project.version}</targetPath>
        <filtering>true</filtering>
        <directory>${basedir}/src/main/resources</directory>
        <includes><include>version.xml</include></includes>
      </resource>
    </resources>
    ...
  <build>
  ...
<project >

Also as a sidenote: The Hudson variables can be placed inside the manifest file if your artifact being built happens to be a war or jar file. Read more on that here.

Links:
Home / Using Flex 4 / Developer tools / Flex compilers / Using mxmlc, the application compiler / Passing Strings
How to configure flexmojos to pass in compile time variables:
gmail thread
official docs


Thursday, July 29, 2010

How to do runtime property substitution for web.xml

  1. Place ${propertyName} in you web.xml file and specify the actual value via -DpropertyName=value (see a forum entry related to this...) also known as variable substitution.
  2. If you can afford to do this at compile time then:
    1. do so using a build tool such as maven (an example)
    2. Filter the web.xml file by configuring the maven-war-plugin as shown in the last post in this thread. There are some generic examples here too but they aren't as clear cut for the web.xml file.

Friday, July 23, 2010

Flex 4: Best Practices for working with Events & Event Listeners

In Flex 4, it is easy to separate a component into an actionscript and mxml file, one for the logic and another for layout and skinning.

The actionscript file usually contains common framework methods such as partAdded(), partRemoved(), getCurrentSkinState() etc. whereas the skin file had all the visual components laid out.

Best Practices:
  1. When adding event listeners, always put them in using the partAdded() method and NOT in the constructor.
    Because if your component is included in multiple states, then somewhere along the line while you may be switching back & forth between the states, the event listener which was added in the constructor will just disappear and it will seem like any events that you are dispatching for that listener aren't getting caught and disappearing into limbo.
    A guess here is that even though the listener may not have had a weak reference, taking the component on & off the stage between state changes might cause its listener to get garbage collected.
    With the use of partAdded() method to add the event listener, this risk disappears because even if the same component is being taken off the stage and being put back then the framework will make sure to call partAdded() again. Unlike the constructor which had already been used to create the object.

Friday, July 9, 2010

Flex Deep Linking and Server Side Redirects

With Flex its easy to:
a) use deep-linking (IBrowserManager & BrowserManager) to create application URLs that allow the use of the browser's backward & forward navigation buttons,
b) bookmarking a deep-linked URL and reloading it also works just fine

B U T ... what doesn't work is when you need to authenticate users before letting them access their bookmarked content. The reason behind this is simple ... the out-of-the-box javascript (history.js file) provided by the flex framework uses the # (pound/sharp) symbol to manage the deep link fragments. For ex:

1) http://www.hostname.com/application.swf#view=account
2) http://www.hostname.com/application.swf#view=profile
3) http://www.hostname.com/application.swf#edit=account
4) http://www.hostname.com/application.swf#edit=profile

Now according to the HTTP spec, the part after the # symbol is not sent over to the server in the HTTP request. This means that your server has no clue where to redirect the users after they successfully authenticate!

What can you do?

Workaround # 1:
1) Provide a bookmark button in the application itself and replace the # symbol with the ? symbol when storing the link.
2) Edit your client side to treat the ? symbol in the same way it treats the # symbol, therefore picking up the deep link fragments properly.

Workaround # 2:
1) Have your users manually edit their bookmarked links to replace the # symbol with the ? symbol.
2) Now that the deep link fragment is making it over to your server side as a URL parameter, edit your server side to replace the ? symbol with the # symbol when redirecting the user back to their bookmarked link. If you are using the spring-security framework then you can refer to the following blog as a reference on how to configure your application context's xml files properly.

Saturday, June 26, 2010

SSO, Pre Authentication & Spring Security 2.0.x

The Spring Security 2.0.x documentation does a great job of explaining:
  • how the pre-authentication concept ties in with SSO systems,
  • what classes are offered out-of-the-box,
  • and how to configure them
but it doesn't explicitly state how the the preAuthN Provider is reading the authentication data accumulated by the preAuthN Filters.

One would imagine that there would be a default UserDetailService implementation as well, which can be configured with the preAuthN Provider but if you go looking into the UserDetail package summary, there is no such thing.

What to do? Well if we look closer, the AuthenticationUserDetailsService interface in the org.springframework.security.userdetails package is implemented by PreAuthenticatedGrantedAuthoritiesUserDetailsService which sits in the org.springframework.security.providers.preauth package.

This works out well but the spring documentation offers a "Siteminder Example Configuration" where they place the UserDetailsByNameServiceWrapper inside the preAUthN user details service and PreAuthenticatedGrantedAuthoritiesUserDetailsService is nowhere to be seen ... so it can seem a bit confusing as to how it should be used or where it should be specified.

I found my a clue through this forum entry and apparently PreAuthenticatedGrantedAuthoritiesUserDetailsService can be specified as the class attribute of the preAuthenticatedUserDetailsService property ... and the use of an UserDetailService is strictly optional depending on whether or not one needs to pull anymore information about the user.

That's all folks, hope this sends you on your way to a successful integration.

Wednesday, June 23, 2010

Ramp Up on Spring Security 2.0.x

  1. What allows web.xml to leverage spring style configuration for Spring Security?
    Configuring a DelegatingFilterProxy in web.xml links the two together.

  2. How does Spring Security simplify the use of DelegatingFilterProxy?
    Usually we would have to create a Filter and then configure it by naming its bean the same as the filter-name for DelegatingFilterProxy. BUT instead the process is simplified if we provide springSecurityFilterChain as the filter-name and use the <http/> configuration element, which auto creates a default springSecurityFilterChain for us.

  3. Are the positions for the standard Filters in Spring Security always fixed?
    Yes.

  4. What does the concept of "authentication mechanism" refer to in Spring Security?
    It refers to collecting authentication credentials/details from a user agent (usually a web browser).Examples are form-based login and Basic authentication. Once the authentication details have been collected from the user agent, an Authentication "request" object is built and then presented to the AuthenticationManager.

  5. What is the function of an AuthenticationProvider?
    An AuthenticationProvider takes an Authentication request object and decides whether or not it is valid and then it will either throw an exception or return a fully populated Authentication object. Most AuthenticationProviders will ask a UserDetailsService to provide a UserDetails object. The resultant UserDetails object - and particularly the GrantedAuthority[]s contained within the UserDetails object - will be used when building the fully populated Authentication object.

  6. What is the function of an AuthenticationManager? What are its benefits?
    An AuthenticationManager is responsible for passing requests through a chain of AuthenticationProviders. Each Provider will be fed its respective "authentication mechanism" counter-part and proceed to validate the request, therefore, having a chain allows us to support various forms of authentication.

  7. What is the purpose of the <security:custom-authentication-provider/> element?
    AuthenticationProvider bean definitions can be marked for addition to the list maintained by AuthenticationManager using the <custom-authentication-provider/> element.

  8. What is the major difference between the configuration for spring-security 3.0.x vs 2.0.x?
    TBD

  9. How/Where does SecurityContextHolder store details of the principal currently using the application?
    By default, it uses a ThreadLocal to store these details. But you can choose between one the following modes:
    • SecurityContextHolder.MODE_GLOBAL
    • SecurityContextHolder.MODE_INHERITABLETHREADLOCAL
    • SecurityContextHolder.MODE_THREADLOCAL (default)
  10. What can be used for storing a SecurityContext between HTTP requests?
    HttpSessionContextIntegrationFilter

  11. What is the function of a ChannelProcessor?
    A ChannelProcessor will review the request, and if it is unhappy with the request (e.g. if it was received across the incorrect transport protocol), it will perform a redirect, throw an exception or take whatever other action is appropriate.

  12. How do you decide whether a security check belongs in a ChannelProcessor or an AccessDecisionVoter?
    ChannelProcessor is designed to handle unauthenticated requests, whereas AccessDecisionVoter is designed to handle authenticated requests.

  13. Question TBD
    Answer TBD

Saturday, June 12, 2010

Multiple Row Filters for JTable

When using the JTable from Java's swing UI, one might often come across a requirement when data filters need to be combined to offer results from searching multiple columns ... the Java Tutorials cover the simple stuff but they don't talk about combining filters! What to do? You can just hit the javadocs and put the pieces together OR after you've read the simple stuff, just try this and it should work like magic:

RowFilter<TableModel, Object> firstFiler = null;
RowFilter<TableModel, Object> secondFilter = null;
List<RowFilter<TableModel,Object>> filters = new ArrayList<RowFilter<TableModel,Object>>();
RowFilter<TableModel, Object> compoundRowFilter = null;
try {
    firstFiler = RowFilter.regexFilter(yourRegexString, columnIndex);
    secondFilter = RowFilter.regexFilter(yourRegexString, columnIndex);
    filters.add(firstFiler);
    filters.add(secondFilter);
    compoundRowFilter = RowFilter.andFilter(filters); // you may also choose the OR filter
} catch (java.util.regex.PatternSyntaxException e) {
    return;
}
sorter.setRowFilter(compoundRowFilter);
Easy Huh?

Wednesday, June 9, 2010

Ramp Up on Java

When I decided to take my SJCP exam, I choose this book as my "blind date" ... and after I finished reading it cover-to-cover, I felt that there couldn't possibly have been a better choice. It was amusing, engaging and insightful ... all the things I wouldn't expect from a book preparing me for what I thought was a run-of-the-mill test.

If you decide to ahead with taking the SCJP exam then (a) expect satire from your co-workers, (b) a tip-of-the-hat from your manager and friends, and finally (c) extra meaningless hits from recruiters assuring you that you're qualified for some position but have no idea what the project is about.

Ah! But most importantly, if you love java, expect to feel smarter and blissfully satisfied =)

Anyway hats off to the folks who put the book together ... Now, without any claims of any ties to them, this blog posting is my meager attempt at putting together a quick review.


  1. What is an Interface? It is a contract which the classes implementing it must abide by.
  2. What is an Abstract Class? It is a class with the abstract modifier placed before it. Any other class which inherits from an abstract class must provide implementations for its methods. Or Else? The code will not compile.
  3. Can a regular class have abstract methods? No, the class must be an abstract class to define abstract methods.
  4. Does having abstract methods make a regular class abstract? Stupid question, given what we just established.
  5. Are all the methods inside an abstract class considered abstract by default? No, they need to be explicitly marked as abstract.
  6. Why would you use an abstract class? Unlike an Interface whose methods cannot have a body defined for its methods, abstract classes allow you to have non-abstract methods which can provide default functionality for its child classes to inherit while providing specific implementations of their own for the abstract methods of their parent. In such a use case an abstract class can be useful.
  7. What has higher visibility? package or protected? The protected level access provides higher visibility.
  8. Does the order in which exceptions are caught in a try-catch block matter? Yes it does. You can't even compile code where a more specific exception gets caught after a more generic one ... because then that piece of code is unreachable which is not something that any compiler would look down upon kindly.
  9. What method allows a thread to give up control of the current synchronized context/object/monitor immediately? The wait() method.
  10. What about notify() or notifyAll()? Regardless of which line they are placed on inside the synchronized block, these methods run/take-effect after the rest of the code in the sync-block has finished executing.
  11. Can the notifyAll() method control the order in which the waiting candidates get notified? Nope.
  12. What is the significance of a final class? It cannot be extended.
  13. What is the significance of a final method? It cannot be overriden in a child class.
  14. What is the significance of a final variable? The reference cannot be changed after it is set.
  15. Can an anonymous class be declared as both extending a class and implementing an interface? Nope, it can only do one of the two at a time.
  16. What is the finalize() method all about? This method is guaranteed to be called once by Java's GC at least, after it determines that an object has no more active references left.
  17. What would be one reason for avoiding the use of the finalize() method all together? Since this method is called only once ... for an object that already had it called once but did not ultimately get garbage collected for some reason ... there is no guarantee that this method will be visited again the next time the GC decides to consider that object for recycling. So relying on this method for some sort of predictable behavior would be ill advised.
  18. What are the different generations of the GC? Basically there are: young, tenured and permanent generations. They are just memory pools holding objects of different ages. Garbage collection occurs in each generation when the generation fills up.
  19. What is the scope/monitor of a static sync method? It locks-on/monitors the class.
  20. Can a static sync method and a non-static sync method butt-heads for locks? No ... one locks the class itself object whereas the other locks an instance object.
  21. Which collection would you use for unique entries? Any implementation of Set.
  22. What is a good collection for only inserting/appending tons of data? Think about ArrayList vs LinkedList?
  23. What about retrieval? Hmm ... HashMap?
  24. What does the join() method do? It puts the current thread in a blocking-mode where it waits for the other thread ... on which the join was invoked ... to finish running.
  25. What is the purpose of WeakReference
  26. What is a ReentrantLock all about?
  27. What are class loaders all about? link1 link2
  28. What is the difference between Enumerators and Iterators?
  29. What happens if a thread is using an iterator and another one tries to insert into the underlying list? ConcurrentModificationException should be thrown.
  30. If a thread t locks a particular monitor multiple times ... will an unlock reverse the effect of all the lock operations? No ... each unlock reverses the effect of one lock operation.
  31. Can elements be removed while traversing a list via an iterator in a single threaded environment? Yes, the remove() method guarantees safe-same-thread deletion.
  32. Can the remove() method be used safely with the new for-loop style introduced in Java 5? Nope.
  33. Why are thread pools useful? A common type of thread pool where we have a fixed number of threads running allows application to degrade gracefully. Rather than try to do much and crashing ... an application can service the fixed/maximum requests that its hardware can handle/sustain in a predictable fashion.
  34. What is the purpose of the volatile keyword? It is similar to asking the Java runtime to provide a guarantee that all the reads on the given variable are synchronized by forcing the threads to always read-from/stay-in-sync-with the master copy. Reads and writes are atomic for all variables declared volatile. Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. This means that changes to a volatile variable are always visible to other threads.
  35. What is the ideal # of threads that should be used on a machine with N cores? Umm...(n+1)/2 ?
  36. How do too many threads adversely affect a CPU intensive system? The context switching causes the thread-data to be loaded in & out of the chip level cache, this is an expensive overhead for hardware which is build around the precept of optimizing execution by retaining data in the chip level cache for the longest period possible.
  37. If the hashCode() and equals() methods are implemented properly for a given class, when can the equals() method return false even though the two objects being compared are equal? This happens when the classloaders for the two objects are different. For example: (a) in application servers, different application contexts (WARs) get their own separate classloaders, (b) two different classloaders can be in use for applications using RMI ... not so sure about this one ...
  38. How would you design your own GC in a language that had only objects? And how would you locate circular dependencies or islands?
  39. What happens when java classes are loaded into JVM? What is Java class file's magic number?

Saturday, May 22, 2010

Moving from compile time to run time locales

So you just woke up and realized that users are complaining about slow load times and you need to make you SWF file leaner ... where do you start?

Baby Step # 1: If you have localized your application then begin by removing all the properties files for the various locales and only loading what any given user needs at a given time.

The best place to start such an endeavor is at Adobe's live help: Using Flex 4 > Enhancing usability > Localization

The link above is helpful and critical in many ways but it doesn't talk about developers who use Maven and what they need to start doing differently in their build process before they start worrying about how to load the localized SWF files.

If you are using flexmojos then a part of your pom.xml probably looks something like:
        <configuration>
          ...
          <compiledLocales>
              <locale>en_US</locale>
              <locale>de_DE</locale>
          </compiledLocales>
          <mergeResourceBundle>true</mergeResourceBundle>
          <resourceBundlePath>${basedir}/src/main/flex/locale/{locale}</resourceBundlePath>
        </configuration>

Initially this may have seemed great as it did the job fast but now you need to change this to something like:
        <configuration>
          ...
          <runtimeLocales>
              <locale>en_US</locale>
              <locale>de_DE</locale>
          </runtimeLocales>
          <mergeResourceBundle>false</mergeResourceBundle>
          <resourceBundlePath>${basedir}/src/main/flex/locale/{locale}</resourceBundlePath>
        </configuration>
A few helpful flexmojos references can be found here and here.

Also in the project where you put together your war file, you need to get the runtime locales' SWF files over in addition to the application. So follow the instructions here, with a few more details listed here.

Now if you head over to the adobe site I mentioned earlier and follow their instructions, you may end up with:
Error: Unable to load resource module from ...
This happened when using:
var resourceModuleURL:String = "locales/myApp-version-locale.swf";
var resourceManager:IResourceManager = ResourceManager.getInstance();
var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
Even though it may seem logical to try and reference the resource SWF as if it was a relative file and hope that Flex will fill in the blanks, that is not the case ... so a quick & dirty solution can be to use localhost like so:
var resourceModuleURL:String = "http://localhost:8080/myApp/locales/myApp-version-locale.swf";
var resourceManager:IResourceManager = ResourceManager.getInstance();
var eventDispatcher:IEventDispatcher = resourceManager.loadResourceModule(resourceModuleURL);
And you'll have a working solution ... mind you that I've left out some critical code that Adobe cover in their article which come after the few lines I've outlined here.

If it is unappealing to use localhost, you can look into configuring crossdomail.xml or refer to these great articles for an alternative approach:
1) Flex: Loading Remote Modules Throws the following: Error: Unable to load resource module from…
2) Loading a Remote Module into a Local App

Monday, May 17, 2010

Fluid Layout

Assumptions:
1) The browser represents the container.
2) The resizing of the container's width and height are primarily at the user's mercy and the components inside it must behave like water, which has no choice but to overflow if the beaker that it is being poured into is too small.

I've provided a sample that demonstrates what it would be like to have fluidity on the horizontal plane.

Click here to see the sample in action.

1) Try to resize your browser window and click on the collapsible and expandable right/left side buttons to see how the horizontal scroller behaves as the browser is resized.
2) If both the left and right side buttons stay expanded, then you will see the horizontal scrollbar appear after shrinking the browser window to be smaller than 500 pixels wide.
2) If both the left and right side buttons stay collapsed, then you will see the horizontal scrollbar appear after shrinking the browser window to be smaller than 300 pixels wide.

Here's the sample source.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx">

    <fx:Script>
        <![CDATA[
            protected function expandCollapseHandler(event:Event):void
            {
                if (event.target.width>100) {
                    event.target.width=100;
                } else {
                    event.target.width=200;
                }
            }
        ]]>
    </fx:Script>

    <s:Scroller left="0" right="0" top="0" bottom="0">
        <s:Group width="100%" height="100%">
            <s:Group width="100%" height="100%">
                <s:Button id="buttonLeft"
                          minWidth="100"
                          width="200"
                          height="100%"
                          label="buttonLeft Height:{buttonLeft.height}, Width:{buttonLeft.width}"
                          click="expandCollapseHandler(event)"/>
                <s:Button id="buttonCenter"
                          left="{buttonLeft.width}"
                          right="{buttonRight.width}"
                          minWidth="100"
                          height="100%"
                          label="buttonCenter Height:{buttonCenter.height}, Width:{buttonCenter.width}" />
                <s:Button id="buttonRight"
                          right="0"
                          minWidth="100"
                          width="200"
                          height="100%"
                          label="buttonRight Height:{buttonRight.height}, Width:{buttonRight.width}"
                          click="expandCollapseHandler(event)"/>
            </s:Group>
        </s:Group>
    </s:Scroller>
</s:Application>
That's all folks.


Thursday, May 13, 2010

Adding SWFs to your blogger posts

1) Find a location to host your swf files.
For example, you can log into Google Sites and host your content by uploading the swf files as attachments:
http://sites.google.com/site/yourUsernameGoesHere/system/app/pages/admin/attachments

2) Make sure to upload the following swf files in addition to your main swf file.
2.1) spark_4.0.0.14159.swf
2.2) textLayout_1.0.0.595.swf
2.3) rpc_4.0.0.14159.swf
2.4) sparkskins_4.0.0.14159.swf
2.5) framework_4.0.0.14159.swf
2.6) playerProductInstall.swf
2.7) osmf_flex.4.0.0.13495.swf
These are dependencies without which you will face various errors when trying to run your main swf file.

a) Error: Error #2030: End of file was encountered.
at flash.net::URLStream/readBytes()
at flash.net::URLLoader/onComplete()

b) Error #2048: Security sandbox violation: http://...-s-sites.googlegroups.com/site/usernam/blah.swf?attachauth=...&attredirects=0 cannot load data from http://sites.google.com/site/username/some_missing_dependency.swf

3) Afterwards, get the link to your swf and to embed it in your blog as outlined here.

4) After embedding the SWFs in your blog, you may feel that your posts load significantly slower that they did before. You can remedy this situation and speed-up the load times if you place a div tag around your embedded tags and have the default mode set to be collapsed. This will give your readers the option of expanding the content and causing the flash player to load the swf files on demand.

Here's an example of all the code that I had to put into this post.
<style type="text/css">
  .commenthidden {display:none}
  .commentshown {display:inline}
</style>
<script type="text/Javascript">
  function togglecomments (postid)
  {
    var whichpost = document.getElementById(postid);
    if (whichpost.className=="commentshown")
    {
      whichpost.className="commenthidden";
    }
    else
    {
      whichpost.className="commentshown";
    }
  }
</script>

<a href="javascript:togglecomments('1')">Expand/Collapse Example</a>
<div class="commenthidden" id="1">

<embed src="http://sites.google.com/site/pulkitsinghal/Bounds1.swf" quality="high" bgcolor="#869ca7" width="650" height="100" name="Main" align="middle" play="true" loop="false" quality="high" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>

</div>

To get the following to work as I described above: Expand/Collapse Example




Wednesday, May 12, 2010

Flex4: Transitions

Why transitions suck?
Because of their workflow:
1) the components are getting included or excluded from the state, also their state-based properties are put into effect immediately
2) the animation/transition is run
3) the state-based properties are put into effect once again

For example:
For a component that can go between the collapsed and expanded state:
a) the body suddenly shows up in the expanded state and then it disappears to go from a fade of 0 to 1 ... very clunky
b) OR, if we try to fix that by saying that alpha.expanded=0 so that this component will come into the expanded state with alpha of 0 and the starting point of the animation and the state-based property will be the same ... then the initial presentation of fade from 0 to 1 goes well but afterwards the state-based alpha of 0 takes effect once again the component becomes invisible .... so bad :(

Flex4: Nuances of a flexible UI (Part 1)

Given:
1) a s:Group with a width of 100
2) a s:Label inside it with left="10", right="10", textAlign="right"
I would hope that flex calculates the width for the label to be 80 and my text stays right aligned within those bounds with the freedom to grow vertically as I haven't set the Height or maxDisplayedLines properties. But that is not the case!
Expand/Collapse Example



Inspecting the properties at runtime via flexspy shows that the width has set to an obscene number like 10000 and if I change the text to be really really long, it simply overflows its boundaries from the right side! Which is a bit of a surprise because it goes against my intuition of having textAlign="right", which I had hoped, would at least make the overflow happen towards the left side. Even setting maxDisplayedLines="1" does not truncate the text because it thinks that it can grow up to a width of 10000 before it has to honor that property.

So apparently the right way to do this is to give up on the idea that width will be calculated based on the gap between left and right.

So if instead, for the s:Label, you specify:
a) right="10", textAlign="right" then you'll have text that can overflow towards the left side
Expand/Collapse Example



b) right="10", textAlign="right" and width="80" then you'll have text that will wrap and grow vertically as it gets longer.
Expand/Collapse Example



c) right="10", textAlign="right", width="80 and maxDisplayedLines="1" then you'll have text that will wrap and grow towards left until it gets too long and will then get truncated.
Expand/Collapse Example



I would say that this is really inflexible as I can never have text that grows within its left and right bounds and gets truncated only when it overflows the dynamically calculated width within those bounds... but oh well, such is life.


Monday, May 10, 2010

Flex4: Templatizing skins

With Flex4 the convention is to leave the appearance up to the skins but you may sometimes find that you are copy pasting the same skin multiple times with only minor tweaks in them. For example: different gradient colors, thicker/thinner borders etc. One of the most common scenarios is having a consistent button appearance across the app. If you follow Adobe's approach you will end up with multiple button skins containing very few changes. The proposed solution is to move commonly changed properties to a generic component class and then reference those properties in the skin.

Example: you have 2 types of buttons in you app - one with gradient fill and one with solid fill.
One way is to create GradientFillButtonSkin and SolidFillButtonSkin. Wouldn't it be nice to have only one skin and just fill it with what you wish to use - gradient or solid? You can!
<templatebutton>
    <fill><gradientcolor.../></fill>
</templatebutton>
To accomplish this we define a custom class TemplateButton:
TemplateButton extends Button {
...
[Bindable]
var buttonFill:IFill;
and in its respective skin class TemplateButtonSkin (which is probably a copy of spark ButtonSkin), you define a host component and a default fill:
[HostComponent("TemplateButton")]
<fx:declarations>
    <s:lineargradient id="defaultButtonFill">
    </s:lineargradient>
</fx:declarations>
...
<s:rect>
    <s:fill>
        {hostComponent.buttonFill!=null ? hostComponent.buttonFill : defaultButtonFill}
    </s:fill>
</s:rect>
Following this approach you can have with all types of fills: Solid, Linear, Radial, etc. and just use as following
<templatebutton skinclass="TemplateButtonSkin">
<fill>
    <solidfill.../>
</fill>
The same approach can be applied to strokes, (up, over, down states for fill and strokes), styles for text in the button and many others.

Saturday, May 8, 2010

Flex4: Show the browser viewport as busy

If you had to place a busy message or icon to indicate a loading state in your flex application, where would you place it? Naturally, centering it along the application's height and width sounds like a good idea. But an application may easily overflow a browser's viewing area at any given time based on how the browser is re-sized ... then what?

A better approach would be to center the modal busy message/icon indicator according to the height and width of the viewing area provided by the browser at any given time.

Theory:
This may be possible in Flex4 if the application is provided a skin which has a s:Scroller defined. The s:Scroller can be pooled for its viewport's x & y coordinates and the busy message can be centered based on those coordinates. This way, even if the user scrolls or resizes the browser ... the busy icon would stay centered and visible to the user.

Solution:
The example given here with its downloadable sample source code ... will pretty much solve the entire problem for you by showing you how to access the viewport properties. After that just take use x="viewport.height/2 - verticalScrollPosition" and y="viewport.width/2 - horizontalScrollPosition" and the task is done.

Pitfalls:
If you try to refactor the scroller code into a skin for the application, the viewport is considered as un-bindable by the compiler and the solution won't work any more. So my original "theory" wasn't so accurate but oh well, lesson learned.

Key Takeaways:
1) The s:Group class hierarchy:
Group extends GroupBase -> GroupBase implements IViewport
shows that a group can directly be handled as a viewport. Therefore, the group immediately inside the s:Scroller for the s:Application is the viewport that you want to deal with. Its easy to reference directly via its id as shown by the example code in the link above.
2) If you have to factor out the s:Scroller into a skin for the application then the group must be named with an id="contentGroup" or nothing will show up when you launch your application. Whereas within the application's main mxml file, you can name the group anything you like.

Monday, May 3, 2010

Flex4: Best Practices for working with states

Flex4 makes it very easy to write custom components:
1) The data & layout logic can be easily split between a Host Component (data-oriented) and a Skin (layout-oriented).
2) The Host Component can expose public Boolean flags to let the Skin indicate which state should be active.
3) Whenever invalidateSkinState() method is called (either by the system or explicitly by you), overriding the getCurrentSkinState() method based on the Boolean flags allows you complete control over the behaviour.

BUT ... just when we are about to become complacent, all kinds of bugs crawl out of the wood works and we are left wondering ... what happened? This is where the best-practices part comes in:
1) The number of Boolean flags should be equal to the number of states that you component has. (+/-)
[SkinState("normal")]
[SkinState("expanded")]
[SkinState("collapsed")]
[SkinState("disabled")]
...
public class CustomComponentView {
...
   private var _normal:Boolean;
   private var _expanded:Boolean;
   private var _collapsed:Boolean;
   private var _disabled:Boolean;
...
}
2) The Boolean flags themselves should be private or protected and you should expose Bindable public getters and setters for them. (+/-)
private var _normal:Boolean;
...
[Bindable]
public function set normal(value:Boolean):void {
  ...
}
public function get normal():Boolean {
   return _normal;
}
3) The setter methods should always be called with a value of true. (+/-)
There is no point in knowing a state that you don't want to be in, it is far better to know the state that you want to goto. If you wish to enforce this, then place an if statement around your code as follows:
[Bindable]
public function set normal(value:Boolean):void {
  if (value) {
     _normal = value;
     ...
  }
}
4) Each setter should toggle-off the Boolean values for all of the other flags. (+/-)
[Bindable]
public function set normal(value:Boolean):void {
  if (value) {
     _normal = value;
     _expanded = !value;
     _collapsed= !value;
     _disabled= !value;
  }
}