What is Seedlet?

Seedlet is an easily-embedded, source-code-embeddable, simple AWT GUI for standalone Java applications. It can be used as a realtime test platform for any class, as a GUI front-end for command-line APIs or as the basis for a complete desktop application. It provides a basic yet very flexible and extensible GUI, more GUI-construction equipment for convenience and a lot of extra tools 'under the hood,' both for testing and for application use. The Seedlet GUI itself is simple and straightforward but, since Seedlet extends java.awt.Panel, it can provide a GUI as complex as is needed for any occasion.

How do you use it?

Seedlets are designed to be source-code embedded. The first step is to include its code (cox/jmatt/java/seedlet/*) in your project. It has no external dependencies so there are no other libraries necessary. Just drop in the source code and it's ready to go. To create a Seedlet,

      import cox.jmatt.java.seedlet.Seedlet;

      public class MySpecialSeedlet extends Seedlet {

        // Application code and overridden Seedlet methods.

        // All Seedlets Must Have A Name!
        public String getName() { return "My Special Seedlet"; }

        public static void main(String[] args) {
          new MySpecialSeedlet().runMyself();
        }
      
      }
    
and it is done. For testing a class, this is the only Seedlet reference needed. Create the class ('// Application code...') and define Seedlet methods to test it. GUI elements can be added or the six predefined Function Buttons can be used. Once the class being tested is ready, the Seedlet code can be deleted and the now-ready API deployed. Or, to allow further development, simply instruct the compiler to ignore it.

The protected final runMyslef() method is where the magic happens. It creates the GUI, initializes the things that need it and begins the Seedlet lifecycle. It handles the built-in GUI elements and provides other GUI services. The base Seedlet GUI consists of a BorderLayout Panel with a TextArea in the center. This is 'The Console' and it receives text output. To the left are the six Function Buttons, F1 through F6, along with the Console Help button ('?'). Each of these buttons is connected to an empty method designed to be overridden. The 'F' buttons are totally empty and undedicated. The Help button connects to the (empty) consoleHelp() method intended to provide abbreviated help hints for using the program.

To the right of the console are the Clear button ('CC') along with seven Checkboxes. Five of these correspond to logging levels: Trace, Debug, Info, Error and Fatal. The 'ST' checkbox enables/disables stack trace printing and the 'CB' checkbox controls clipboard access. There are four more buttons at the very bottom: '[|<]', '[<<]', '[>>]', '[>|]'. These are used to flip between Panels (cards) when a CardLayout is used. In order, the Button methods are firstCard(), previousCard(), nextCard() and lastCard(). One of the things Seedlet does is to make using a CardLayout completely hassle-free.

Printing and Logging

Since Seedlet provides a console, it also provides a number of methods to use it. The most basic method is println() This method takes a String argument and prints it on the console along with a newline. The printClip() method takes a String and places it into the system clipboard subject to two things: the clipboard must be available and the 'CB' box must be checked. If the 'ST' box is checked, printStackTrace() takes a Throwable, extracts the stack trace (getStackTrace() method) and prints it on the console.

Add Logging

Seedlet defines a simple yet flexible logging mechanism. There are five levels: Trace for fine-grained use, Debug for development and trouble spots, Info for useful information that isn't necessarily an error condition, Error for serious erros and potential crash-spots, and Fatal for conditions that will terminate execution. Each of these levels has three methods defined for it: isLevelEnabled(), level(String) and level(String, Throwable). If the corresponding Checkbox is checked, the message and stack trace ('ST checked) are printed to the console.

To avoid embedding Seedlet logging statememts, if that is desirable, the Seedlet package includes a helpler class: SeedJULHandler. This extends java.util.logging.Handler and uses a Seedlet to receive log messages. Simply use Java's logging framework and configure the Seedlet to receive messages. Then, when the other class is deployed, Java-based logging is already included.

Playing with XML

Seedlet makes an excellent platform for working with XML. That's because of its auxillary classes SeedDefaultHandler, XMLSeedKit and XMLTag. SeedletDefaultHandler extends the SAX Handler2 class and implements the XSLT and DOM Error-catching methods in order to direct them to the Seedlet logging methods. None of the other methods are defined (Asterisk: startDocument() clears out the SAX error counts) so all of the actual XML handling methods are available. Extending this class allows the best of all worlds: total XML error handling plus whatever processing the application needs.

XMLSeedKit provides an easy way to create and use SAX, DOM, XPATH and XSLT. It has a place for an alternate ClassLoader (and Seedlet provides one) to locate and use any of the factory classes. Best of all, the XMLKit can handle parsing, XPath and transforms totally internally. Although it has the ability to create the tools to manipulate XML, this is not necessary. Whenever it creates an XML tool, it retains an internal copy. It also defines the methods to use these internal tools and present the results as simple Strings or whatever else is needed.

The XMLTag class is a low-level String-crunching monster. Its primary purpose was creating large numbers of basically-similar XML tags but it can be used for more than that. It doesn't worry about SAX, DOM or any high-level XML standards. All it does is crunch Strings to create well-formed XML tags. It handles attributes, content and formatting and its toString() method produces a well-formed XML tag. It's also designed for subclassing so it can be used as a base class for creating other specific tag classes. As an added bonus, the class includes a macro language designed for quick tag creation and configuration.

Templating

There are two templating engines (static methods) in the base Seedlet class. The basic one, fillTemplate() accepts a String template and a String array of replacement values. The process is position based; the template includes replacement tokens of the form '<N>' where N is the index of the array element to replace. This method is designed for simple, position-based replacement.

fillMondoTemplate() is a keyword-based process that uses a Map<String, String> for replacement values. It includes a set of built-in tokens, a String array for positional replacement, an index parameter and a timestamp-formatting String. This method is more versatile and more flexible, at the cost of a slightly higher learning curve.

Macro Languages

Seedlet.processMacro() provides Seedlets and other arbitrary classes a way to embed a simple line-oriented macro interpreter. Although designed with GUI configuration in mind, this is by far not the only use for this tool. In operation, each line is interpreted as a single command. The first non-whitespace character is the command ('opcode') and the rest of the line, data. Including macro processing is as simple as implementing the MacroListener interface. Seedlet implements it automatically but it is provided to allow macro capacity for other classes as well (e.g. XMLTag).

Scripting

One of the brightest crown jewels in the Seedlet package is its scripting capability. The static Seedlet.runSeedletScript() method makes using JSR 223 (javax.scripting.*) both easy and fun. The ScriptListener interface, again implemented by Seedlet, allows any class to include and benefit from scripting. If that isn't enough, Seedlet also provides a GUI panel designed specifically to implement scripting.

The companion SeedConsole class is designed to allow script access to Seedlet's handier methods. It also provides access to a Properties object and a way to guarantee a return value from a script.

SQL and JDBC

The Seedlet package provides a trifecta of JDBC/SQL tools: JDBCSeedKit, SQLListener and the SQL (Loadable)Panel. JDBCSeedKit contains equipment to create and manipulate JDBC things in a completely 'hands-free' manner. Everything necessary to execute SQL statements is contained within and error-wrapped for safety. On the other hand, it also allows full access and modification of each of these things. Using JDBCSeedKit, it's possible to automatically create everything up to the java.sql.Statement, pull it out of the box and handle things manually from that point on. Or, the Statement can be adjusted and put back into the box for more automatic handling.

The SQLListener interface provides execution- and result-processing tools. Executing SQL can produce a mixture of ResultSet objects and update counts. JDBCSeedKit's execution methods detect the what and the what order and dispatch to the SQLListener's methods accordingly. Add to the mix the multi-talented static JDBCSeedKit.formatResultSet() method, which actually uses Seedlet.fillTemplate() under the hood, and the result is a fast, simple way to create, query and format database operations. As an added bonus, formatting can be adjusted within the SQL by a 'micro-macro' language embedded in SQL comments.

The SQL Panel provides a ready-made GUI element (LoadablePanel) capable of configuring and using JDBCSeedKit equipment from a GUI. Besides the Panel, there is also an associated configuration Dialog full of configuration options.

Loadable Panels

A LoadablePanel is a BorderLayout Panel with four buttons standard and other components possible. The common buttons are 'Load', 'Run', 'Clip' and 'Clear'. 'Load' opens a FileDialog and copies the contents of the selected file into the TextArea in the center. The 'Run' button makes something happen, 'Clip' copies the TextArea into the clipboard and 'Clear' clears it.

The specific flavors of LoadablePanel are Script Panel, Macro Panel, ClassLoader Panel, Mondo Template Panel and SQL Panel. The Script Panel loads and runs a script. It has extra components for setting the language and script engine lookup method. The ClassLoader Panel provides a way to select files or other URLs and build an URLClassLoader from them. Classes that need it (such as XMLSeedKit) can access it through the protected '_altClassLoader' field that Seedlet provides. The Mondo Template Panel holds a template (Mondo) and fills it from a Properties object.

The Macro Panel loads and executes a macro. It also provides a way to parse a Properties-formatted text file into a Properties object and store it in a protected field, '_scriptPizza'. Classes that need access have it and any Macro Panel can set it. Finally, Macro Panel can load an XMLTag macro and create an instance from it. The SQL Panel puts a GUI on the JDBCSeedKit class which provides an easy way to create and manipulate databases via JDBC.

The Seedlet Lifecycle

Besides the GUI, runMyself() starts and manages the Seedlet lifecycle. There are five methods, four of which are patterend after Applet and one that isn't. All of these methods are handled automatically and need only be overridden to take advantage of them.

  1. init() - Called one time only, after runMyself() and before the GUI is created. This is the place to create any custom GUI elements and to take care of resource creation and initialization.
  2. start() - Called once (guaranteed) after init() and any time the GUI is de-iconified. The GUI has been created and is available. This method is best used to start tasks that require the user's undivided attention.
  3. stop() - Called any time the GUI is iconified (minimized) and once, guaranteed, before destroy(). The GUI is still active so this is not the place to get rid of GUI elements.
  4. destroy() - The last method called before the Seedlet dies. The GUI has already been taken down and disposed and won't be available. This is the place to get rid of any external resources that need to be freed up or destroyed.
The reset() method is not a formal part of the lifecycle but is considered as such. It was designed to give Seedlet subclasses 'reset' capability, whatever that might entail.

Although not a part of the formal lifecycle, getMenus() also deserves attention. Since the containing Frame is handled automatically, this method provides a way to add Menus. The default implemention returns null but can return an array of Menus. If so, they will be added to the Frame's menu bar in array order. A companion method, Seedlet.quickMenuItem(), allows very fast creation and configuration of Menus, MenuItems and CheckboxMenuItems.

And Plenty More!

In addition to this, Seedlet provides a lot more equipment and convenience methods, all designed to simplify application testing and development. Most of these methods are designed around common tasks, to alleviate the need to re-do them in every single application. An example of this are the polymorphic copyStream() methods. These copy data from any combination of InputStream/Reader to OutputStream/Writer. Handy to have and easy to do, through Seedlet.

The Incredible TestSeedlet

The Seedlet JAR is executable. Its Main-Class is TestSeedlet and it is designed to showcase and demonstrate the machinery Seedlet provides. As such, it also provides a basic scripting environment, complete with SeedConsole, XMLSeedKit and others. The GUI demonstrates how easy it is to use a CardLayout, each of the specific LoadablePanels, a generic one and two custom Panels. Although meant only to demonstrate, TestSeedlet can also be extended. Simply overriding configureScriptEngine() allows extra scripting tools to be added, transforming the simple TestSeedlet into a fully-customized and more powerful scripting environment.

Best Of All: It's Open-Source

The Seedlet package is released under the Apache Software License. Since it is designed for source-code embedding, this license applies only to the Seedlet source code. Anything outside the cox.jmatt.java.seedlet.* namespace is excluded, and can be licensed any way, including commercially. See the Seedlet package.html javadoc for details.

If desired, the Seedlet code can also be released under other licenses, provided they are open-source and encourage the use of Seedlet. The only proviso, and this includes the Apache license, is that the source code be included AS-IS, including the javadoc and 'package.html' file.

The Namespace. When using Seedlet, even for deployed applications, please do not use the cox.jmatt.java.* namespace. The reason for this is to avoid collision with other Java projects, which do or will use only this.

Seedlet Philosophy

Seedlet had an interesting and humble beginning. The name is a rough contraction of 'CD Applet,' which was the original intent. The original, unpublished Seedlet was designed to provide a test platform for other classes or a GUI front-end for command-line packages. It was meant to be quickly written and burned to a CD as an executable JAR. This way no command line was required, only an operating system that understood executable JARs.

Seedlet was initially written to provide a simple snap-on GUI for programs and packages that needed one. From those humble beginnings it grew. Most of the functionality sprang from tasks that had to be done manually more than three times. After many iterations, the current Seedlet was born. This code is much lighter and more agile than its predecessors, hence the name SeedLite. Even though this is the name of the JAR file, the class and philosophy are all Seedlet. It is designed to meet three goals.

A Test and Development Platform. Seedlet is an excellent way to develop classes designed for command-line use. It provides interactive testing and logging capability. Since it isn't meant to be deployed, the launch class can be included in the 'seedlet' directory alongside the other classes. This keeps all Seedlet code out of the files meant for deployment. When the class is ready to go, the Seedlet directory tree can be deleted or moved without a trace. Or, the compiler can be instructed to ignore it.

A GUI Front-End. The pre-Seedlet code came from a desire to experiment with the Apache Xerces, Xalan and FOP packages. The desire, if not the code, remained throughout Seedlet development. Seedlet can be compiled with or without the desired package code. For the latter option, simply include the required JAR files in the classpath and manifest file and deploy only the Seedlet. If the application only requires a single launch class, and no others, it can be included in the seedlet directory provided it is documented as an additional class and NOT part of the original code. All other conditions still apply.

Seedlet As An Application. This is the most versatile use for Seedlet. Seedlet-based applications allow the full range of equipment to be used throughout the entire application. The GUI becomes the easiest part to create with the lifecycle, scripting and other equipment as a bonus. To create a Seedlet application, include the Seedlet directory in the source code tree and create the launch class outside it. Done.

Licensed For Personal Use. And all other uses, of course, but especially for personal use. After the first few, writing Seedlets becomes automatic. Give it a name, override init() for custom GUI elements and start hacking out the code. This means it is basically a non-task to slap a GUI on highly-specialized, personal-use programs. This makes GUI-based code almost as easy to write as command-line. Adding a manifest and JARring it yields a 'clickable' application that can be burned to a CD, put on a pen drive etc. For extra versatility, write the main() method to skip runMyself() if the argument array is not empty. Presto! The result is an application usable from the GUI and command line both. Nothing in the Seedlet precludes a non-zero-argument constructor or requires that it have a GUI. In fact, a Seedlet doesn't become a Seedlet until runMyself() is called.

No External Dependencies

The base Seedlet code has no dependencies outside Java. No external packages are required unless a Seedlet-based application requires one. This results in an incredibly easy application to deploy: simply copy the JAR anywhere, no batteries required. If the application doesn't require anything outside Java, it can also be easily deployed anywhere.

For applications that do require external packages, including the source code still results in no external dependencies. This may not be the best option for webapps or server-based technology but Seedlet is designed for desktop applications where no dependencies is a good and desirable thing. Since the GUI is simple, it's also ideal for large-scale deployment and support. Non-fluffy GUIs make for easier user support in a decentralized-deployment environment. It also leads to fewer GUI-related problems.

Make Matt Some Money!

(Copied from 'package.html'.)

If you use my code and you make lots of money, you owe me a pizza. Maybe two. If we ever meet in person, which isn't likely given how little I travel.

If you use my code and you really think I should get some money OR if you really like great science fiction, please consider buying my books. They're available at Amazon, Smashwords and DriveThruFiction. If you're into paper-and-dice fantasy RPGs, I've also published my own system: Dungeon Crawl Unlimited. Go from zero to game in 30 minutes or less and have a lot of fun doing it.

My contact information/pages are:

Whew! Having said all of this, I hope you enjoy using Seedlets as much as I enjoyed writing them.
James Matthew Cox, Jr.
29 December, 2015