Thứ Bảy, 12 tháng 12, 2009

Favorite SQL*Plus Tips

Although there are many tools available that are far more user-friendly than SQL*Plus for manipulating and accessing Oracle database data, I still find myself occasionally using SQL*Plus when I need to do something with the database for which a more extravagant tool actually takes longer to use and feels like overkill.

Acquiring Current Date and Time

This SELECT statement not only provides the current date and time, but also demonstrates use of the DUAL table, column name aliasing, and use of the to_char SQL function.


SELECT to_char(sysdate, 'DD-MON-YYYY HH:MI:SS') "Current Date / Time"
FROM dual;



Viewing Database Object Metadata

I posted previously on the usefulness of the Oracle Data Dictionary. This examples makes use of the Oracle Data Dictionary and demonstrates setting a column to a fixed width.


column object_name format a20
SELECT object_name, object_type, created, last_ddl_time, timestamp, status
FROM user_objects;



Run Operating System Commands from SQL*Plus

One of my favorite commands in SQL*Plus is the host command. This command is useful when one wants to run a particular script but cannot remember the exact name of the script file or its host directory. The command "host ls" or "host dir" can be used to see directory listings.


Make nulls Easily Identifiable

It can sometimes be difficult to distinguish null from an empty string or other value that does not get printed in SQL*Plus for a SELECT statement. The set null command is useful here because it allows one to specify what string should appear to indicate null values. For example, I frequently set up my SQL*Plus environments with set null <null>.


Use column Command to Format Columns Appropriately

The SQL*Plus column command is useful for setting a column's format to appear more aesthetically pleasing in an SQL*Plus query and other work done in SQL*Plus.


Displaying Output

When writing output from PL/SQL to SQL*Plus (such as with the built-in package/procedure DBMS_OUTPUT.PUT_LINE), it can be frustrating when no output appears. This is typically remedied by changing the specification of the serveroutput with a command set serveroutput on. Even with serveroutput enabled, one might still not see all of the results. This can be adjusted with the size parameter for the serveroutput option (including an unlimited setting). Run show serveroutput in SQL*Plus to see its settings. Another useful SQL*Plus option to set for displaying LONG data is set long NNNNN to display full CLOB output in SQL*Plus.


Working with set and Options

Many of the tips covered in this blog post are related to the SQL*Plus set command. The currently configured value for a particular SQL*Plus variable can be displayed with the show command. The command help set can also be used to view the potential SQL*Plus environment variables that can be set and SQL*PLUS - SET Statement contains additional details on them.


Conclusion

SQL*Plus has never been known for its ease of use, but its appeal does seem to grow as one uses it regularly. One recent piece of evidence regarding the continued use of SQL*Plus is the recent blog post How to Execute Process Flow from SQL*Plus. SQL*Plus is a tool that can be particularly useful for quick operations, especially when one knows a few tips and tricks to make it easier to use.


Other SQL*Plus References

SQL*Plus Product Page

SQL*Plus Documentation

SQL*Plus FAQ

René Nyffenegger's SQL*Plus Posts (several referenced in this post)

SQL*Plus Tips and Tricks

SQL*Plus Tips for Oracle Beginners

SQL*Plus

PSOUG SQL*Plus Reference

Thứ Ba, 8 tháng 12, 2009

Favorite Oracle Data Dictionary Query Statements

I write a software development blog for a variety of reasons, not the least of which is as a "glorified bookmark" and easy reference to find things I need to look up quickly. This post is a good example of that because it provides me a convenient location to store some notes I have taken regarding my favorite queries on the Oracle Data Dictionary.

General Notes on Oracle Data Dictionary

The Oracle Data Dictionary contains metadata that is readily available via database views. These static data dictionary views are typically prefixed with USER_, DBA_, or ALL_ that respectively include metadata about that user's own schema, metadata for administration, and metadata available to the current user about his or her own schema and other authorized metadata.

Most of the syntax shown in the queries in this post is case insensitive. The exceptions are the strings contained within single quotes, which are case sensitive.

Many modern tools reduce the necessity of being familiar with these views, but I still find them to be a "quick and dirty" way to determine what is going on in my Oracle database. As I have blogged before, there are times when I can find out metadata about my database more quickly with SQL*Plus than with the fancier tools.


List All of One's Own Objects


SELECT object_name, object_type
FROM user_objects;


The public synonym for this is accessed with:


SELECT * FROM obj;



List Own Tables


SELECT table_name
FROM user_tables;


SELECT object_name
FROM user_objects
WHERE object_type = 'TABLE';


Related public synonyms are:


SELECT * FROM tab;
SELECT * FROM tabs;



List Own Views


SELECT view_name, text
FROM user_views;


SELECT object_name
FROM user_objects
WHERE object_type = 'VIEW';



List Own Synonyms


SELECT synonym_name
FROM user_synonyms;


SELECT object_name
FROM user_objects
WHERE object_type = 'SYNONYM';


A related public synonym is:


SELECT * FROM syn;



List Own Sequences


SELECT sequence_name, last_number
FROM user_sequences;


SELECT object_name
FROM user_objects
WHERE object_type = 'SEQUENCE';


A related public synonym is:


SELECT * FROM seq;



List Own Constraints


SELECT constraint_name, constraint_type, r_constraint_name
FROM user_constraints;



List Own Table Comments


SELECT table_name, comments
FROM user_tab_comments;



List Own Column Comments


SELECT table_name, column_name, comments
FROM user_col_comments;



List Own Indexes


SELECT index_name, index_type
FROM user_indexes;


SELECT object_name
FROM user_objects
WHERE object_type = 'INDEX';


A related public synonym is:


SELECT * FROM ind;



List One's Entire Catalog


SELECT *
FROM user_catalog;


A related public synonym is:


SELECT * FROM cat;



Listing Database Privileges

Useful data dictionary views for viewing database privileges include ROLE_SYS_PRIVS, ROLE_TAB_PRIVS, USER_ROLE_PRIVS, USER_TAB_PRIVS_MADE, USER_TAB_PRIVS_RECD, USER_COL_PRIVS_MADE, and USER_COL_PRIVS_RECD.


Conclusion

Each of the above queries of Oracle Data Dictionary metadata views can be easily executed as shown. However, they can often be joined together for even more useful details. There are many, many more views available in the Oracle database, but these views provide perspective on some of the most commonly used database objects.

Thứ Ba, 1 tháng 12, 2009

Java Boolean's getBoolean: Useful Albeit Imperfect

The Boolean.getBoolean(String) method is a static method that can be useful now and then. It's very easy to confuse this method as one that somehow returns the appropriate Boolean based on the provided String (such as what Boolean.valueOf(String) and Boolean.parseBoolean(String) do), but the Javadoc documentation for this method explains what it really does: the Boolean.getBoolean(String) method "Returns true if and only if the system property named by the argument exists and is equal to the string 'true'."

The Boolean.getBoolean(String) method provides developers with a method for determining if a particular property is set to "true." It only returns "true" if the property is defined and the value it is defined to is some form of "true" where the case of "true" does not matter. The case of the property name itself is case sensitive, but its value ("true", "TRUE", "trUE", "TRue", etc.) is case insensitive.

The following Java code demonstrates Boolean.getBoolean(String) in action.

DemonstrateBooleanGetBoolean.java

package dustin.examples;

import static java.lang.System.out;

/**
* Demonstrate the usefulness of Boolean.getBoolean(String) despite its naming
* issue.
*/
public class DemonstrateBooleanGetBoolean
{
/**
* Main function for executing examples demonstrating use and effects of
* Boolean.getBoolean(String).
*/
public static void main(final String[] arguments)
{
final String basicPropertyName = "i.am.here";
final String basicUppercasePropertyName = basicPropertyName.toUpperCase();
final String wereHereProperty = "were.here.property";
final String wasHereProperty = "was.here.property";

out.println(basicPropertyName + " is " + Boolean.getBoolean(basicPropertyName));
out.println(basicUppercasePropertyName + " is " + Boolean.getBoolean(basicUppercasePropertyName));

out.println(wereHereProperty + " is " + Boolean.getBoolean(wereHereProperty));
out.println(wasHereProperty + " is " + Boolean.getBoolean(wasHereProperty));

if (Boolean.getBoolean("i.am.set"))
{
System.out.println("I'm set!!!");
}
else
{
System.out.println("I'm NOT set!!!");
}
}
}


By executing the above class with properties specified via the Java application launcher's -D option, the nuances of Boolean.getBoolean(String) are demonstrated. The results contained in the next screen snapshot indicate that Boolean.getBoolean(String) does indeed return true when a particular property name is specified and is defined with a String value of "true" with any case for the four letters making up "true." On the other hand, changing the case of the property name does affect the results of Boolean.getBoolean(String). In other words, while "true" and "TRUE" are the same from a property value perspective, "i.am.here" and "I.AM.HERE" are completely different property names from a property name perspective.



There are several uses for the Boolean.getBoolean(String) method including conditional runtime logic based on whether a parameter is set or not. The blog post Please use Boolean.getBoolean(SOME_FLAG_KEY) covers this use in more detail.

Although this method is highly useful, there is no question that it not as well named as it might have been. Several blog posts express Java developers' disappointment with this API naming choice and hosting class for the static method: I Fell in the Trap of Boolean.getBoolean() [October 2007], Java API Pitfalls: Boolean.getBoolean(String) [October 2005], Some Fun with Boolean.getBoolean(String) [July 2009], Boolean.getBoolean not what you think it is [October 2003], and Ever Been Busted by Boolean.getBoolean(String) [this month!].

Conclusion

I find Boolean.getBoolean(String) to be a highly useful method at times, but I also agree with other Java developers cited above that it is not one of the better API decisions. As several others have suggested, it seems like it might have fit better in the java.lang.System class and I would have preferred a method name such as "isPropertyTrue(String)". That being said, once one is aware of this subtlety and the distinction between Boolean.getBoolean(String) and Boolean.valueOf(String) (or Boolean.parseBoolean(String), available since J2SE 5), both methods can be applied appropriately and be highly valuable in certain situations.

Thứ Hai, 30 tháng 11, 2009

Groovy: Java Enum Generation from XML

Besides the obvious use of Groovy to write applications, Groovy is also very useful for performing Java development related tasks such building applications, deploying applications, and managing/monitoring applications. In this post, I look at an example of generating a Java enum from XML source using Groovy.

I have previously blogged on slurping XML with Groovy. That technique is used again here. The Groovy code that follows uses this technique to read the source XML and then writes out a 100% compilable Java enum called AlbumsEnum.java. The Groovy script is shown next.


#!/usr/bin/env groovy
// generateAlbumsEnumFromXml.groovy
//
// Demonstrates use of Groovy's XML slurping to generate
// a Java enum from source XML.
//

// Set up enum attributes' names and data types
attributes = ['albumTitle' : 'String', 'artistName' : 'String', 'year' : 'int']

// Base package name off command-line parameter if provided
packageName = args.length > 0 ? args[0] : "albums"

NEW_LINE = System.getProperty("line.separator")
SINGLE_INDENT = ' '
DOUBLE_INDENT = SINGLE_INDENT.multiply(2)
outputFile = new File("AlbumsEnum.java")
outputFile.write "package ${packageName};${NEW_LINE.multiply(2)}"
outputFile << "public enum AlbumsEnum${NEW_LINE}"
outputFile << "{${NEW_LINE}"

outputFile << generateEnumConstants()

// Build enum attributes
attributesSection = new StringBuilder();
attributesAccessors = new StringBuilder();
attributesCtorSetters = new StringBuilder();
attributes.each
{
attributesSection << generateAttributeDeclaration(it.key, it.value)
attributesAccessors << buildAccessor(it.key, it.value) << NEW_LINE
attributesCtorSetters << buildConstructorAssignments(it.key)
}
outputFile << attributesSection
outputFile << NEW_LINE

outputFile << generateParameterizedConstructor(attributes)
outputFile << NEW_LINE

outputFile << attributesAccessors

outputFile << '}'

def String generateEnumConstants()
{
// Get input from XML source
albums = new XmlSlurper().parse("albums.xml")
def enumConstants = new StringBuilder()
albums.Album.each
{
enumConstants << SINGLE_INDENT
enumConstants << it.@artist.toString().replace(' ', '_').toUpperCase() << '_'
enumConstants << it.@title.toString().replace(' ', '_').toUpperCase()
enumConstants << "(\"${it.@title}\", \"${it.@artist}\", ${it.@year.toInteger()}),"
enumConstants << NEW_LINE
}
// Subtract three off end of substring: one for new line, one for extra comma,
// and one for zero-based indexing.
returnStr = new StringBuilder(enumConstants.toString().substring(0, enumConstants.size()-3))
returnStr << ';' << NEW_LINE.multiply(2)
return returnStr
}

def String generateAttributeDeclaration(String attrName, String attrType)
{
return "${SINGLE_INDENT}private ${attrType} ${attrName};${NEW_LINE}"
}

def String buildAccessor(String attrName, String attrType)
{
returnStr = new StringBuilder()
returnStr << SINGLE_INDENT << "public ${attrType} get${capitalizeFirstLetter(attrName)}()" << NEW_LINE
returnStr << SINGLE_INDENT << '{' << NEW_LINE
returnStr << DOUBLE_INDENT << "return this.${attrName};" << NEW_LINE
returnStr << SINGLE_INDENT << '}' << NEW_LINE
return returnStr
}

def String generateParameterizedConstructor(Map<String,String> attributesMap)
{
constructorInit = new StringBuilder()
constructorInit << SINGLE_INDENT << 'AlbumsEnum('
attributesMap.each
{
constructorInit << "final ${it.value} new${capitalizeFirstLetter(it.key)}, "
}
constructorFinal = new StringBuilder(constructorInit.substring(0, constructorInit.size()-2))
constructorFinal << ')'
constructorFinal << NEW_LINE << SINGLE_INDENT << '{' << NEW_LINE
constructorFinal << attributesCtorSetters
constructorFinal << SINGLE_INDENT << "}${NEW_LINE}"
return constructorFinal
}

def String buildConstructorAssignments(String attrName)
{
return "${DOUBLE_INDENT}this.${attrName} = new${capitalizeFirstLetter(attrName)};${NEW_LINE}"
}

def String capitalizeFirstLetter(String word)
{
firstLetter = word.getAt(0)
uppercaseLetter = firstLetter.toUpperCase()
return word.replaceFirst(firstLetter, uppercaseLetter)
}


The XML source that this script is run against is shown next:


<?xml version="1.0"?>
<Albums>
<Album title="Frontiers" artist="Journey" year="1983">
<Song title="Separate Ways" peak="8" />
<Song title="Send Her My Love" peak="23" />
<Song title="Faithfully" peak="12" />
</Album>
<Album title="Hysteria" artist="Def Leppard" year="1987">
<Song title="Hysteria" peak="10" />
<Song title="Animal" peak="19" />
<Song title="Women" />
<Song title="Pour Some Sugar On Me" peak="2" />
<Song title="Love Bites" peak="1" />
<Song title="Armageddon It" peak="3" />
<Song title="Rocket" peak="15" />
</Album>
<Album title="The Joshua Tree" artist="U2" year="1987">
<Song title="With or Without You" peak="1" />
<Song title="I Still Haven't Found What I'm Looking For" peak="1" />
<Song title="Where The Streets Have No Name" peak="13" />
<Song title="In God's Country" peak="14" />
</Album>
<Album title="Songs from the Big Chair" artist="Tears for Fears" year="1985">
<Song title="Shout" peak="1" />
<Song title="Everybody Wants to Rule the World" peak="1" />
<Song title="Head Over Heels" peak="3" />
<Song title="Mothers Talk" peak="27" />
</Album>
</Albums>


When the Groovy script is run against this source XML, the Java enum that it generates is shown next.


package albums;

public enum AlbumsEnum
{
JOURNEY_FRONTIERS("Frontiers", "Journey", 1983),
DEF_LEPPARD_HYSTERIA("Hysteria", "Def Leppard", 1987),
U2_THE_JOSHUA_TREE("The Joshua Tree", "U2", 1987),
TEARS_FOR_FEARS_SONGS_FROM_THE_BIG_CHAIR("Songs from the Big Chair", "Tears for Fears", 1985);

private String albumTitle;
private String artistName;
private int year;

AlbumsEnum(final String newAlbumTitle, final String newArtistName, final int newYear)
{
this.albumTitle = newAlbumTitle;
this.artistName = newArtistName;
this.year = newYear;
}

public String getAlbumTitle()
{
return this.albumTitle;
}

public String getArtistName()
{
return this.artistName;
}

public int getYear()
{
return this.year;
}

}


There are, of course, many ways in which this simple draft script could be improved and many features could be added to it. However, it serves the purpose of illustrating how easy it is to use Groovy to generate Java code from source data such as XML.

Thứ Sáu, 27 tháng 11, 2009

Slurping XML with Groovy

In the early days of using Java in conjunction with XML, it often seemed more difficult than it should be to use the Java programming language with the XML markup language. Besides the non-trivial and often differently implemented DOM and SAX APIs, simply finding the correct version of Xerces (and later, Crimson) without having too many conflicting versions of that library was also a common problem. This environment led to the creation and successively received JDOM project. Later developments such as the introduction of the standard Java XML parsing API of JAXP (JDK 1.4) and the inclusion of JAXB in Java SE 6 (and other Java/XML binding libraries available separately) would make parsing and working with XML in Java much easier. Groovy continues these advances in ease of Java/XML integration. In this blog post, I look at how use of Groovy's XmlSlurper makes XML parsing refreshingly easy and almost transparent.

The following simple XML code will be used to demonstrate Groovy's XmlSlurper. The XML file for this example is called RockAndRoll.xml.

RockAndRoll.xml

<Albums>
<Album title="Frontiers" artist="Journey" year="1983">
<Song title="Separate Ways" peak="8" />
<Song title="Send Her My Love" peak="23" />
<Song title="Faithfully" peak="12" />
</Album>
<Album title="Hysteria" artist="Def Leppard" year="1987">
<Song title="Hysteria" peak="10" />
<Song title="Animal" peak="19" />
<Song title="Women" />
<Song title="Pour Some Sugar On Me" peak="2" />
<Song title="Love Bites" peak="1" />
<Song title="Armageddon It" peak="3" />
<Song title="Rocket" peak="15" />
</Album>
<Album title="The Joshua Tree" artist="U2" year="1987">
<Song title="With or Without You" peak="1" />
<Song title="I Still Haven't Found What I'm Looking For" peak="1" />
<Song title="Where The Streets Have No Name" peak="13" />
<Song title="In God's Country" peak="14" />
</Album>
<Album title="Songs from the Big Chair" artist="Tears for Fears" year="1985">
<Song title="Shout" peak="1" />
<Song title="Everybody Wants to Rule the World" peak="1" />
<Song title="Head Over Heels" peak="3" />
<Song title="Mothers Talk" peak="27" />
</Album>
</Albums>


The next code snippet shows some Groovy code using XMLSlurper to print out some details based on this source XML. The Groovy script in this case is called slurpXml.groovy.

slurpXml.groovy

#!/usr/bin/env groovy
// slurpXml.groovy
// Demonstrates use of Groovy's XML slurping.
//

albums = new XmlSlurper().parse("RockAndRoll.xml")

albums.Album.each
{
println "${it.@artist}'s album ${it.@title} was released in ${it.@year}."
it.Song.each
{
println "\tFeaturing ${it.@title} that peaked in the U.S. at ${it.@peak}"
}
}


As the Groovy code above demonstrates, only a few lines of code are required to parse the XML and to print out its results as part of longer strings. The single line new XmlSlurper().parse("RockAndRoll.xml") is all it takes to parse the source XML. Then the variable to which those results are assigned (in this case, albums) provides access to the XML content via familiar syntax.

When the Groovy code above is executed, its results look like those shown in the following screen snapshot.



The Groovy User Guide has a section devoted to coverage of Reading XML Using Groovy's XmlSlurper. This section points out additional issues related to using Groovy's XmlSlurper such as dealing with XML tag names that include hyphens (use double quotes around name with hyphen included) and namespace matching details.

Conclusion

Because Groovy really is Java, Groovy can make use of the plethora of XML handling APIs for Java. However, Groovy can and does go beyond this and provides even easier-to-use APIs for XML manipulation. Groovy's XmlSlurper is an example of how Groovy makes XML reading/parsing/slurping easier than ever.

Additional References

Besides the Groovy User Guide section on XmlSlurper, there are many other online resources that cover use of XmlSlurper. I list some of them here.

Reading XML Using Groovy's XmlSlurper

Groovy: Processing Existing XML (6 March 2009)

Practically Groovy: Building, Parsing, and Slurping XML (19 May 2009)

Nothing Makes You Want Groovy More than XML (12 March 2008)

Updating XML with XmlSlurper

Groovy XMLSlurper

Thứ Ba, 24 tháng 11, 2009

Where Have All the Groovy Licenses Gone?

One of the nice things about working with Groovy is the ready availability of good online documentation (both supplied via the Groovy site and by third parties via articles, blogs, and presentations) and the availability of several books on Groovy. I was surprised, however, when I tried to find a valid online link to the Groovy license to include in my Rocky Mountain Oracle Users Group Training Days 2010 paper "Applied Groovy: Scripting for Java Development."

I did not see a direct link to license information on the main Groovy page, so I turned to my favorite tool in such cases: the Google search engine. The next two images show the top results from search for the two words "Groovy license" both with and without quotes. The results provides several links to licenses about products related to Groovy and to things with the word "groovy" that have nothing to do with Java or software development.





Limiting the Google search to links about "license" specifically results in more tailored responses, but the license references still seem to be mostly related to products affiliated with or based on Groovy rather than Groovy itself.



The searches did help turn up mention of the Groovy license on the Groovy FAQ page. The next image shows the FAQ entry regarding the Groovy license (explaining that it is a BSD/Apache 2 style license) and the image after that one shows that the provided link does NOT point to a valid page.





The second link ("Project License") on this Groovy FAQ page is in the top left corner of the page, but it also points to a non-existent page. The next two images show the link and the non-existent page it points to.





So far, it has turned out to be more difficult than one would have guessed it to be to get a link to a valid page containing the license applicable to Groovy. However, one of the searches did point to this page with a Groovy 1.0 license. Unfortunately, this page (a portion of which is shown in the next screen image) is neither on the official Groovy site nor it is applicable to Groovy 1.6.5.



Although I was surprised at how difficult it was to find a current working link to the license applicable to Groovy 1.6.5 online, the good news is that a text file dealing with the license is bundled with the Groovy distribution. The next screen image shows the existence of this file (LICENSE.txt) in the Groovy installation directory.



As the image above demonstrates, there are other files related to licenses in this same directory. These licenses apply to products that Groovy makes use of such as Apache Commons CLI (CLI-LICENSE.txt, an Apache 2 license), the ASM bytecode manipulation framework (ASM-LICENSE.txt), and ANother Tool for Language Recognition (ANTLR-LICENSE.txt). The LICENSE.txt file basically summarizes the licensing of Groovy as being the Apache 2 license and provides that URL: http://www.apache.org/licenses/LICENSE-2.0.

In summary, the LICENSE.txt file included with the Groovy 1.6.5 distribution states, 'Licensed under the Apache License, Version 2.0 (the "License").'

Thứ Hai, 23 tháng 11, 2009

The Positive Impact of Java Users Groups

The last Java.net poll asked "Do you belong to a Java users group?" and of the nearly 300 votes (at time of this writing), well over half of the respondents stated that they are in someway affiliated with or have participated in a local Java users group. I have blogged before about my appreciation of user groups and I have definitely benefited from the existence of Java users groups. In this post, I'll look at some concrete ways that participation in Java users groups has directly benefited me.

The most obvious Java users group that has been of benefit to me is the Denver Java Users Group (affectionately known as DJUG). DJUG typically holds one meeting per month with two technical sessions in each meeting. The two sessions are billed as "Main Meeting" and "Basic Concepts," but I have definitely attended when the "Basic Concepts" was every bit as important, useful, and informative as the "Main Meeting." I have always felt that my investment of time and effort to get to these meetings has been well rewarded.

A few years ago, when DJUG still met in the then-Qwest building on 17th and Curtis, I attended around over half the DJUG meetings for a while. It so happened they were covering many subjects of interest to me and the meetings fit my schedule fairly well. Unfortunately, since then increasing work and personal demands have made it more difficult to attend. I am still able to benefit from DJUG, however, thanks to their posting of presentations online in their archive and thanks to the blog posts of people who do attend.

I have definitely learned and re-learned/remembered some useful concepts from attending DJUG meetings. I have also been able to see and listen to speakers well-known in our industry. Many of them speak at major software development conferences, but there is a certain advantage to seeing them locally and in that environment. The cost (free) is also difficult to beat.

There are other local users groups as well that, although not Java-specific, are often useful to me. One example is the Rocky Mountain Oracle Users Group (RMOUG). Their meetings have covered several Java-related topics and products over the years.

I have also benefited from other non-local Java users groups. For example, there have been occasions when I have found a useful presentation on the NYJavaSIG site where they post some of their presentations.

How Java User Groups Benefit Java Developers

Java users groups can benefit Java developers in many ways. They obviously provide benefit by providing free or low-cost training, but they also provide benefits of regular meetings (throughout the year) and opportunities to meet and network with other Java developers. In addition, many Java users groups provide book reviews, newsletters, web sites, code samples, and other items that benefit Java developers.

Java Users Groups Are What Their Members Put Into Them

Any user groups, including those devoted to Java, depend on their users for success. The user groups need people to run the group (officers) as well as other types of volunteers and speakers. Even meeting attendees provide value to the user group by providing an audience, by asking good questions, and by answering each others' questions.

Characteristics of Successful Java Users Groups

The success of a Java users group is largely dependent on the base of involved and participating users. Large cities with large numbers of Java developers have an advantage here because a larger pool of Java developers often means a larger pool of enthusiastic Java developers to power the user group. Successful Java users groups tend to be run by energetic and enthusiastic individuals with a vested interest in sharing Java knowledge and learning more about Java and related topics.

What I've Learned from Java-Related User Groups

Here I list a few examples of some of the things I first learned or was exposed to thanks to a Java-related users group.

JMX - My first solid exposure to Java Management Extensions was at a 2004 DJUG meeting (during what was in many ways JMX's heyday) and via a Dr. Dobb's magazine article.

Ruby on Rails - David Geary's July 2005 DJUG presentation on Ruby on Rails was a big part of my learning and using Ruby on Rails.

• Software Development Methods - Al Davis's October 2006 presentation What's New About New Methods of Software Development? reaffirmed my belief that there is very little that is really all that new in software development and that most of the "new" processes and approaches are really just old ideas returning to fashion.

• Software Development Tools and Libraries - I have observed that I often learn about presenters' and attendees' favorite tools and libraries at user group meetings. In fact, it is often the mention of these new (to me) tools and frameworks that really makes me happy that I attended.

• Things Not to Use - I have attended user group meetings where the main thing I learned during the presentation was that I did not need to invest any more time in learning about the subject of the presentation. Although it is always fun to attend a meeting and learn about a new concept that I can apply quickly, it is just as worthwhile (albeit a little disappointing at the time) to learn about things that won't work for my situation or that I should not spend any more time on.


Conclusion

In the end, successful users groups rely mostly on peoples' time. It takes a few dedicated individuals to make it happen and many committed members to make it worth while. For developers willing to invest the time, users groups can be valuable sources of new information.