Wednesday Jul 30, 2008

Ruby Eye for the Java guy: Constants

In Java, it is common to use public, final, static fields to represent utility constants. Since the fields are public, they can be used from any package; and since they are final, values cannot be assigned to them once they have been initialized. If the field is a primitive type, such as java.lang.Integer.MAX_VALUE then it is also effectively immutable (and, by extension, effectively thread-safe). These two conditions - finality and immutability - are what guarantee that the field will remain constant. Some classes, like java.lang.String, are also immutable, and so can be used to represent constants. A common design pattern is to group sets of related constants together in a public final class, such as for example javax.xml.XMLConstants.

It would seem like the need for an API to expose constants is universal, and so should find expression in every language. How to do this in Ruby?

In Ruby, any field that begins with an upper-case letter is treated as constant. If you attempt to assign to a constant more than once, the interpreter will issue a warning. Constants may be defined inside of a class, and since the Ruby Class class inherits from Module, you can use the module "::" accessor syntax to read the constant's value:

  class MyClass
    MY_VAR = "xxx"
  end

  puts MyClass::MY_VAR           #=> "xxx"
  MyClass::MY_VAR = "yyy"        #=> "warning: already initialized constant MY_VAR"
However, the Ruby String class is mutable, so the constant is still open to modification:
  MyClass::MY_VAR[1] = "z"
  puts MyClass::MY_VAR           #=> "xzx"
Everything in Ruby is an object, and all objects inherit from the Object class. Object defines a freeze method, which, once invoked, prevents any further modification to the object's state. Once frozen, an object can never be "thawed". So a final, immutable class constant in Ruby might look like this:
  class MyClass
    MY_VAR = "xxx"
    MY_VAR.freeze
  end

  puts MyClass::MY_VAR           #=> "xxx"
  MyClass::MY_VAR = "yyy"        #=> "warning: already initialized constant MY_VAR"
  MyClass::MY_VAR[1] = "z"       #=> "in '[]=': can't modify frozen string (TypeError)
The attempt to modify the frozen object results in an unchecked error, and execution halts. Re-assigning to the constant results in a warning only, and execution continues. It is possible to make assignment a fatal error, too, if we wrap the constants in a module, and freeze the module:
  module MyModule
    MY_VAR = "xxx"
    MY_VAR.freeze
  end
  MyConstants.freeze

  MyModule::MY_VAR = "YYY"       #=> "can't modify frozen module (TypeError)
Be careful, if you want to "mix in" the module's functionality, callers of your class will access the module's constants through an unfrozen path:
  class MyClass
    include MyConstants
  end

  MyClass::VAR = "qqq"
  MyClass::VAR[1] = 'r'
  puts MyClass::VAR              #=> "qrq"
One solution might be to freeze your class, if you want to guarantee the immutability of everything in the class. If you want to leave the class open to extension or modification, you could wrap the included constants in an inner module:
  module MyConstants
    VAR = "xxx"
    VAR.freeze
  end
  MyConstants.freeze

  class MyClass
    class Constants
      include MyConstants
    end
    Constants.freeze
  end

  puts MyClass::Constants::VAR   #=> "xxx"

Monday May 14, 2007

A rack up with sketchup

A few months ago, I started to play with the free version of Google Sketchup. After mastering the basics, I was able to produce a few, prototypical architectural features, such as cornices and fluted columns. Last week I put the tool to a more practical use. My wife wanted a small wine rack in our kitchen. Counter space is scarce, so we decided to try something under the cupboards. I used Sketchup to design the rack. Being able to visualize it from any angle was helpful, and we eliminated some early designs when we realized they would look funny from certain angles, or prove impractical in the small space.

Here is the final "sketchup":

I downloaded the wine bottle from the Google Sketchup 3D Warehouse, and dropped it in the model.

And here is the actual rack:

I probably spent about six hours on the design, including the two that I discarded. With practice I'll become faster, I'm sure. The rack itself took only a few hours - including ten minutes to sand the initial coat of primer that my three-year old applied.

Thursday Apr 26, 2007

Ruby script to toggle CVS root in a workspace

Sandip Chitale posted a Java program that toggles the CVS root setting of a workspace that is already checked out (see A simple program to toggle CVSROOT of existing checked out workspace). At the end of his post, Sandip solicits alternative solutions. I have been playing around with Ruby, and was curious as to how much more compactly the same logic could be expressed in Ruby.

Stripped of empty lines and comments, Sandip's Java solution weighs in at 83 lines. That's roughly four times the 16 lines required for a roughly equivalent program in Ruby, which I give below.

The Java program has explicit exception handlers, which I chose to leave out, since both programs will leave the repository in a corrupted state if IO fails midway.

# A simple program to fix the CVSROOT.  
# 
# One may check out a cvs workspace using a CVSROOT e.g.
# :pserver:username@extranet.foo.com:/cvs. This value of CVSROOT 
# is recorded in the CVS/Root file in the checkedout directories.
# At some later time, depending on the network connectivity, it may be faster
# to use an alternate (aliased) CVSROOT e.g. 
# :pserver:username@intranet.foo.com:/cvs.
#
# This simple program provides the functionality to fix the CVSROOT settings
# in each CVS/Root file. It skips entries found in .cvsignore.
#
# CAUTION: Care must be taken to make sure that both cvs servers are really the
# same servers, or mirrors that are in sync.
#
# DISCLAIMER: This is an experimental program. Use at your own risk.

require 'find'
abort 'No server name specified' unless $\*[0]

roots = []
ignore_patterns = []


# Use the find module to traverse the source code repository, collecting all CVS root
# files found, and patterns of directories to ignore

Find.find('./') do |path|
  if path =~ /CVS\\/Root$/
    roots << path
  elsif path =~ /.cvsignore$/
    ignores = IO.readlines(path).collect{ |line| line.chop }
    ignore_patterns << File.dirname(path) + '/(' + ignores.join('|') + ')'
  end
end


# Construct a regexp of all directories to ignore, use it to prune the array of root
# files, then, update each root file with the new pserver name

ignore_expr = Regexp.new('\^(' + ignore_patterns.join('|') + ')')
roots.reject { |root| ignore_expr.match(root) ? true : false }.each do |root|
  (pserver = File.open(root, 'r').gets)[/@[\^:]+:/] = ('@' + $\*[0] + ':')
  File.open(root, 'w').puts pserver
end 

Tuesday Mar 06, 2007

"Neutered Theme" for Java Studio Creator

The basic components that ship with Java Studio Creator (and with its successor, Visual Web Pack> for NetBeans) derive their look and feel from a theme. If you need to apply your corporate colors to an entire application, themes make the job easier. But if you want to adjust the appearance of just one component, or make a set of components play nicely with other styles, themes can get in the way.

Unfortunately, you can't just unplug the theme from an application. In addition to things like fonts and colors that affect only the look of an application, the theme defines things that are critical to component behavior, like messages and client-side scripts.

To help in these situations, I put together a "neutered theme." This is a theme from which everything extraneous has been excised. With the neutered them, most of the components end up looking pretty much like their standard JSF counterparts. For example, here is a basic button rendered with the default theme:

Notice the border, gradient color, and text font, all of which are derived from the default theme. Switch to the neutered theme, and the button looks pretty much like a plain HTML input button:

What if you want one button on your page to be yellow? If your application relies on the default theme, and you set a button's style property so that it's background is yellow, the component remains colored a gradient blue. That's because your CSS settings in the component property are conflicting with CSS settings in the theme. But if you use the neutered theme, you'll get what you want:

Neutered themes are also useful when developing portlets, as it reduces the likelihood of conflict between portlet theme styles and styles assigned to a whole portal page.

How to use the Neutured Theme

  1. This theme will work in Java Studio Creator, and in Visual Web Pack for Java EE 1.4 project types (the theme format for Java EE 5 projects is different).
  2. Download the theme JAR: NeuteredTheme.jar
  3. From the tools menu, choose "library manager", then "import new library". Add the them JAR to the library class path, calling it "Neutered Theme" or whatever else suits your fancy.
  4. Open up the "themes" node in your project's logic view, right click on the new theme, and choose to make it the project's theme.

Wednesday Dec 13, 2006

Update to PropertyResourceProvider

There was a bug in the first version of the PropertyResourceProvider that I made available from this blog a few months ago (see DataProvider component for internationalizing Creator applications), which manifested itself in the glassfish application server. The order of two elements in the library's faces-config file was incorrect. I have fixed the bug and updated the complib available for download.

You can download the updated PropertyResourceProvider Component Library here.

Monday Dec 04, 2006

NetBeans Free-Form Projects as Library Wrappers

When the developer defines a library in NetBeans 5.x, the library definition is stored locally, in the user directory. This makes it difficult to share library definitions among more than one workspace. While library definitions are stored locally, references to them, in the form of entries in a project's properties file, are typically stored along with all other project files, in a remote code repository. When a user first fetches the project from the repository and opens it in NetBeans, a missing references error will occur. All missing local library definitions must be created anew in each local workspace.

One solution to this problem is to store shared libraries in the remote workspace, and to make projects depend directly on the libraries' constituent JAR files. Such dependencies are stored in the project's properties file as relative paths to the JAR files, so assuming that the directory structure that includes both project and library remains the same in all users' workspaces, no local definitions are needed.

There are however drawbacks to this solution. Under the Libraries node of the project logical view, only the JAR file name is displayed. If your project depends on a large number of libraries, it can be difficult to distinguish among them by file name alone. The names may by cryptic, or worse, there may be files in different directories that share the same name. There is also no way of determining from the project logical view that a group of JAR files form a logical unit, unless they share a common infix.

As an example, consider the following project, in which one library provided JAR files aaa and bbb, and another library provided another JAR file, also named aaa:

There is a hack that I have used to improve the quality of the information available about JAR files in the project logical view, which does not require use of the local storage. Instead of grouping them into library definitions, I add them to free-form projects. Projects may then be declared to depend on the library wrapper projects.

Here is the same example, with the JAR files from the two libraries exported from two free-form library projects:

How to create a free-form library wrapper project

To create a free-form library wrapper project, start by putting all JAR files that belong together into a directory, which will serve as the project root directory. For this example, I will define two libraries, 01 and 02, the first containing two JAR files, aaa.jar and bbb.jar, and the second containing just one, aaa.jar:

    lib01/aaa.jar
    lib01/bbb.jar
    lib02/aaa.jar
Each directory will server as one logical library, represented by one free-form project. To create the project skeleton, in each directory create an empty source directory, e.g. ./src. You will also need a stub ant build script. Add the following contents to the file build.xml in the project directory:
  <project name="01_Library_Wrapper" default="build" basedir=".">
    <target name="build"/>
    <target name="clean"/>
  </project>

To create the project, from within NetBeans, choose File->New Project, and choose a "Java Project with Existing Ant Script" within the General category. In the next wizard panel, select as location the project's directory, e.g. ./lib01. NetBeans will fill in the build file information. You'll want to choose a short, but descriptive, project name, as this will be the name that appears under the Libraries node once you have declared a dependency on this library wrapper project. I chose the names "01 Library Wrapper Project" and "02 Library Wrapper Project". In the next, penultimate wizard panel, NetBeans will fill in the ant targets found, and in the final panel it will prompt you for a source directory. Choose the source directory that you created earlier.

[It may seem superfluous to create an empty source directory and empty build targets, but I discovered that without these, some actions in the IDE can have the side effect of removing the exported JAR definintions.]

After the project is created, bring up the project's properties window, and choose Output. Here you will declare the JARs that this free-form project exports. Select all the JARs that you put into the library wrapper project directory. When later you declare a dependency on this project, these are the JARs that will be added to the class path. Here is what this step looks like for my first library, 01:

And that's it! Now you are ready to declare project dependencies on your new library wrapper projects. Right-click on the Libraries node in the project logical view, and choose "Add Project...". Select the project directory. All JARs in the project will be added as dependencies.

Wednesday Aug 23, 2006

DataProvider component for internationalizing Creator applications

How to use a PropertyResourceProvider component in Java Studio Creator to bind component values to localizable resource keys.[Read More]

Wednesday Feb 08, 2006

Rough Guide: Editing Themes for Creator 2.0

The components that ship with Java Studio Creator 2.0 derive their look and feel, and in some cases, their behavior, from a theme. At the most basic level, a theme is simply a JAR file that contains resources such as CSS stylesheets and graphical icons.

An easy way to create your own look and feel is to edit the contents of the default Creator theme. The following guidelines explain how to do it.

A theme JAR file has three main types of content:

  • manifest file: information about the theme's name, version, prefix, and locations of properties and resources
  • properties files: a map of theme keywords to theme resources, used by the theme manager to location theme resources
  • resource files: the images, Javascript files, CSS stylesheets, and messages that constitute the theme itself

You'll find a copy of the default theme jar (defaulttheme.jar) in the Creator install directory, under rave2.0/modules/ext. Or, after you have deployed an application, in the application directory build/web/WEB-INF/lib.

Expand the file into a new directory. Users of M$ Windows may find it more convenient to rename defaultheme.jar to defaulttheme.zip, so that they can expand its contents using the Explorer.

Step One: Updating the manifest

The first thing to do is to give your theme a name, and to edit the manifest accordingly. I'll start by renaming the Creator default theme, from defaulttheme to isopaleocopria. The theme name is given in the manifest entry X-SJWUIC-Theme-Name. At the same time, I'll modify the package names for the various resources so that they are based on a namespace that I own.

Here's the new manifest:

    Manifest-Version: 1.0
    Ant-Version: Apache Ant 1.6.2
    Created-By: 1.4.2_07-b05 (Sun Microsystems Inc.)

    Name: com/sun/rave/web/ui/theme/
    X-SJWUIC-SWAED-Version: 3.0
    X-SJWUIC-Theme-Version: 1.0
    X-SJWUIC-Theme-Name: isopaleocopria
    X-SJWUIC-Theme-Prefix: /theme
    X-SJWUIC-Theme-Messages: org.isopaleocopria.themes.messages.messages
    X-SJWUIC-Theme-Images: org.isopaleocopria.themes.properties.images
    X-SJWUIC-Theme-JavaScript: org.isopaleocopria.themes.properties.javascript
    X-SJWUIC-Theme-Stylesheets: org.isopaleocopria.themes.properties.stylesheets

A few important points about the manifest:

  • To be a valid theme JAR, the manifest must contain an attributes section named "com/sun/rave/web/ui/theme/"
  • The attibute X-SJWUIC-Theme-Name must be present, and it must contain a unique name (a name not used by any themes already loaded into Creator).
  • The last four entries are package names that must correspond to property files in the theme JAR. For example, org.isopaleocopria.themes.properties.images should correspond to the file org/isopaleocopria/themes/properties/images.properties. Do not edit the keys in these property files!

If the above conditions are not met, Creator will reject the theme.

Nota Bene: According to the spec, lines in a JAR manifest file are limited to a maximum length of 72 bytes. When you extract and first open the manifest for editing, you may notice that some lines longer than 72 bytes have been wrapped, and the enjambed portion has been indented with a single space character. You'll need to patch these lines back together again before reconstituting the JAR or ZIP file.

Step Two: Editing theme content

Before editing the content, you'll want to move it to your own package. In order for the theme manager to find the content in its new location, you'll need to update the path values in the various property files listed above. For example, as part of developing my new theme I would move the Javascript file /com/sun/rave/web/ui/defaulttheme/javascript/table.js to org/isopaleocopria/themes/javascript/table.js, and update the corresponding value in the javascript.properties file.

After updating the theme name and the locations of the property files, it's time to edit the theme content. In some cases, the key names in the property files will help you to identify which theme artifact belongs to which component. The CSS stylesheets also generally use a truncated version of the name of the component as the prefix of style class names that apply to the component.

Step Three: Importing the edited theme into Creator

When you are finished modifying the theme content, you will need to repackage the contents as a JAR or ZIP file which can then be imported into Creator.

To import the theme file, start Creator and open or create a project. From the menu, open Tools -> Library Manager. Select the Theme Libraries section, and click on "New Library". Give the library a name, e.g. IsoPaleoCopria (note that spaces are not accepted, probably a bug), and add the theme JAR or ZIP file to the library's classpath and to its runtime, using the appropriate tabs.

Finally, to apply the theme to the current project, select it in the project hierarchy, right-click, and choose "Apply Theme".

Have fun!

Tuesday Oct 12, 2004

NetBeans sex exception?

NetBeans 3.6 threw an IllegalStateException today while I was creating a new project. The exception was announced in a pop-up window, and also on the command line, with the message:

    gris-118% sex exception: java.lang.IllegalStateException: 
              can't declare any more prefixes in this context
Perhaps it should try whispering them softly in my ear?

Friday Oct 01, 2004

New meta-blog about XML

There is a new website that aggregates RSS feeds from several bloggers well-known in the XML community, dubbed "Planet XMLhack": http://planet.xmlhack.com.

Tuesday Sep 14, 2004

TRAX: Passing parameters to a "pull" transformer

The TRAX API for performing XSL transformations includes a factory extension, SAXTransformerFactory, which can return a transformer hidden behind a SAX XML Filter. This allows multiple transformations to be easily chained together, as per the Filter design pattern. Moreover, it allows filters backed by transformations to be intermixed with other types of filter implementations, which can simplify the code for iterative XML processing.

Unfortunately, returning the transformer as a class that implements only XMLFilter effectively hides the methods defined by javax.xml.transform.Transformer, including those used to pass global parameters to the transformation process. This is unfortunate.

I think a better solution would have been to return an interface that extends both XMLFilter and Transformer, allowing the caller to set up the filter chain, and then pass parameters to some or all of the filters before processing. This is one of the things that I liked about James Clark's XT: his XSLProcessor class extended XMLParser (the SAX 1.0 predecessor of XMLReader), so they could be made easily into filters. Of course, having to wrap processors in XMLReaderAdapators (to allow the SAX 1.0 parser to read from a SAX 2.0 reader) makes for its own headaches.

Wednesday Jun 30, 2004

Trip Report: Java ONE, June 28 - July 1 2004

My goal for this year's Java ONE conference (my first) was to learn as much as I could about the "state of the art" of XML processing in Java. Given the pervasiveness of XML in the J2EE platform, this was not an easy task. There were somtimes concurrent sessions that dealt with XML, and session overload kept me away from the evening BOFs after Tuesday. That said, here are some highlights.

On Monday, Jeff Suttor, Bhakti Mehta and Ramesh Mandava surveyed the tools that make up JAXP 1.3 (JSR 206), Java's most recent API for XML processing. Their survey's leitmotif was performance, and the star performer is XSLTC, Sun's XSL transformation compiler. Bhakti reviewed performance tests that demonstrated a ten-fold decrease in run time for transformations, when ported from Xalan to XSLTC. With 1.3, XSLTC has been made the default transformer, which means it's what the factory will give you unless you know the URI for Xalan. This is an interesting decision, because it means that even when an application loads a stylesheet at transformation time for a single use, the factory will have to pre-compile it. The benefits are analogous to those of just-in-time compiling for the JVM, and given that HotSpot is now the default JRE, it makes sense that XLSTC would become the default transformer. Compiled "translets" are thread-safe, and can be cached for re-use.

Fans of alternative validation methodologies will be happy to hear that Sun's Multi-Schema Validator has been bundled with JAXP 1.3, and is available through the API. Grammars may be pre-parsed and cached for repeated, thread-safe invocation. In addition to built-in support for XML Schema and Relax NG, there is a ValidatorHandler interface that can be used as the basis for a customized validator. Nota bene: there is no support for DTDs (the entity model makes this awkward). One of MSV's many advantages is that a compiled grammar can be used to validate a document in memory, and not just at parse-time, which opens up a wide range of new applications. For example, validation can be inserted in among series of transformations or SAX filters via "assertions" during testing and debugging.

JAXP 1.3 includes for the first time a stand-alone implementation of XPath 1.0. XPath is the W3C langauge for describing parts of an XML document. Expressions can be pre-computed for repeated evaluation, and applied against any document that can be represented as an abstract object model. There is built in support for DOM, but users can build their own. The value of an XPath expression can be returned as any type supported by the XPath data model, which is limited to Strings, Integers, and Nodes (more on datatypes later).

Though there is no support for XQuery (XML Query) 1.0 in JAXP 1.3, there is a separate project under way (JSR 225) to develop XQJ, the XQuery API for Java. As the standard is still in candidate status, the API will likely continue to evolve. Andrew Eisenberg (IBM) and Jim Melton (Oracle) gave an overview of the standard and a preview of the new API in a talk Tuesday Morning. XML Query is a functional, idempotent (side-effect free) language for asking questions of collections of XML resources, whether these be documents, relational databases, or object repositories; whether stored as XML, or viewed as XML via some kind of middle-ware.

An XQuery expression always returns a sequence (think SQL cursor), made up of zero or more atomic types or document nodes. As the language is functional in design, expressions can also operate on sequences - or the return values of other expressions. This allows for a much more flexible processing model than that supported by XSLT.

XQuery 1.0 is a strongly typed language. Its type system is borrowed from XML Schema. Future versions of XPath and XSLT will also make use of XML Schema's type system. Norman Walsh gave an overview of XPath 2.0 and XSLT 2.0 on Thursday afternoon.

The new versions of the standards are currently in last call, and it is hoped that they will become candidate recommendations by the end of this year. But the wheels of the W3C turn slowly, so don't hold your breath.

Like XQuery 1.0, XPath 2.0 will operate on sequences of items. An item may be a node, or it may be any atomic type supported by XML schema. Up to now, operations like comparison have always taken their operands to be strings or nodes, but with a full range of types available, comparison will be more clearly defined. If types are not correctly cast, a comparison could result in an error, and such errors must interrupt processing. This could cause problems for users who wish to upgrade their 1.0 stylesheets to take advantage of the 2.0 type system. To take advantage of the new type system, XPath 2.0 adds operators like "eq", "lt" and "gt" for performing value comparisons, and "<<" and ">>" for performing node comparisons.

XSLT 2.0 will include XPath 2.0 and a host of new features. Regular expressions will make it easier to replace characters with markup (such as when one wants to preserve space in a transformation to HTML). Improvements to the template priority mechanism will make it easier to specify fallback templates. Direct access to the result tree will make it easier to perform some complicated, multi-pass operations, such as sort and iterate.

All JAXP tools are based on two interfaces to an XML document: SAX, the parsing event-handler interface, and DOM, the in-memory, random-access document model. Chris Fry and Scott Ziegler, both from BEA, gave a presentation about StAX, an XML "stream reader" interface, that defines an alternate interface to an XML document. StAX is being developed as part of the Java Community Process (JSR 173). The reader interface allows the caller to control parsing, for example:

    XMLStreamReader reader =
        XMLStreamReaderFactory.newInstance( "foo.xml" );
    while( reader.hasNext() ) {
        // Get info about start element, end element, or character event
    }

The nice thing about StAX is that it maps directly to the iterator pattern. The caller can stop the parse at any time, skip ahead some number of events, or switch context. Applications that bind XML to data models will generally be much simpler to code if pull parsing is used.

Finally, I attended a preview of JDBC 4.0, which will include support for all of the SQL 2003 standard. This includes the new XML datatype, and SQL select operators for dynamically generating XML - albeit within the constraints of a tabular result set. For example, the expression

    SELECT generateElement( id, generateElement( 'name',
        generateElement( first_name ), generateElement( last_name )))
    FROM emp;

would return a single column, of type XML, with rows looking something like

    <id>1234<id>
    <name>
        <first_name>Gregory</first_name><last_name>Murphy</last_name>
    </name>

I have misgivings about the addition of this type to SQL. Since there is no obvious way to define a document context, and no way to simulate one within the scope of an RDBMS cursor, handling namespaces gracefully will be difficult. There is also no way to break out of the tabular result model. My prediction is that in five years we will all be using XQuery to extract relational data into a structured context, and the XML select functions will be deprecated relics.

About

gjmurphy

Search

Top Tags
Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today