Tuesday, December 11, 2007

New version of CafeBabe Bytecode Editor plugin (ver. 1.0.0) for Intellij IDEA

This plugin integrates CafeBabe Bytecode Editor with Intellij IDEA.

Update:

1. Added implementation of ClassHound service.
2. Added implementation of Save Class File function.
3. Bug fix: disabling initial openning of plugin toolwindow.

How to use it inside Intellij IDEA:

How to use Class Viewer/Editor

- Select class file in the files tree or click on "Open File" icon within plugin toolwindow;
- Activate context menu for the selected file;
- Select "Open in CafeBabe" item from the context menu;
- Class will be disassembled and represented in CafeBabe toolwindow;
- If you want to disassemble some method, navigate to methods list, select one method
and activate context menu. Follow "Go to method body" link. You will be redirected to
"Bytecode Editor" toolwindow;
- Now you can create/delete/edit bytecode instructions;
- In constant pool you can modify UTF strings;
- If you want to get explanation for a given instruction, click on Help icon.
- If you modified the file and then trying to save it, "Save as" dialog will be initiated, allowing you to save modified class.
- You can click on "Save as" icon any time when you want to save your modifications.


How to use ClassHound

- Click on ClassHound icon - new toolwindow will be open;
- In ClassHound toolwindow select archive, then package, class, fileld or method. You can select only package
or only package class;
- By double clicking on package, class, field or method - selected item will be loaded into Class Viewer/Editor.
If it's field or method, Class File Viewer/Editor will be positioned on selected field/method;
- You can add new archive to the list of available archives - then you can explore it in standard way.

Monday, December 10, 2007

New version of Groovy language and most popular java information portals

New version of Groovy language - 1.5 - had been released. Great job!

But I want to ask everybody about the efficiency of our "leaders" in information ocean of Java events. Neither "javalobby" nor "theserverside"... For the last 3 days... What's wrong? Where can we get the most up-to-date and complete information about Java events?

My selection is "javablogs.com". What about yours?

Wednesday, December 05, 2007

New version of maven-archetypes plugin for Intellij IDEA (1.0.2)

This plugin helps to generate initial java project layout with the help of Maven Archetypes.

Update:

1. Downgrading java version to 1.5 (to be compatible for Mac users);
2. Changing appfuse version to 2.0.1;
3. Separating archetypes.xml file from jar file (make it avalilable for user modifications).

How to use it inside IDEA editor:

1. Select Working Directory;
2. Select archetype group;
3. Select archetype;
4. Enter groupId, artifactId, version for your project;
5. Click on Generate button. New project will be generated in the working directory.

Wednesday, November 28, 2007

New plugin for Intellij IDEA: CafeBabe Bytecode Editor plugin (ver. 0.8.0) is available for download

This plugin integrates CafeBabe Bytecode Editor with Intellij IDEA.

Update:

1. Initial implementation.

How to use it inside Intellij IDEA:

- Select class file in the files tree or click on "Open File" icon within plugin toolwindow;
- Activate context menu for the selected file;
- Select "Open in CafeBabe" item from the context menu;
- Class will be disassembled and represented in CafeBabe toolwindow;
- If you want to disassemble some method, navigate to methods list, select one method
and activate context menu. Follow "Go to method body" link. You will be redirected to
"Bytecode Editor" toolwindow;
- Now you can create/delete/edit bytecode instructions;
- If you want to get explanation for a given instruction, click on Help icon.

Tuesday, November 20, 2007

New maven-archetypes plugin (ver. 1.0.0) is available for Intellij IDEA

This plugin helps to generate initial java project layout with the help of Maven Archetypes.

Update:

1. Initial implementation.

How to use it inside IDEA editor:

1. Select Working Directory;
2. Select archetype group;
3. Select archetype;
4. Enter groupId, artifactId, version for your project;
5. Click on Generate button. New project will be generated in the working directory.

Saturday, November 17, 2007

Tips for Intellij IDEA plugins developers (my bloody experience)

1. How to get project with new API

Old fashion:


Project project = (Project)dataContext.getData(DataConstants.PROJECT);


New fashion:


Project project = DataKeys.PROJECT.getData(dataContext);


2. How to register tool window with new API


// Get toolwindow manager
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);

// Register your tool window at desired location
ToolWindow toolWindow =
        toolWindowManager.registerToolWindow("your_toolwindow_id", true, ToolWindowAnchor.RIGHT);

// Prepare content panel of your tool window (all your controls)
JPanel yourContentPanel = ...

// Get peer factory
PeerFactory peerFactory = PeerFactory.getInstance();

// Create content
Content content = peerFactory.getContentFactory().createContent(yourContentPanel, "", false);

// Add created content
toolWindow.getContentManager().addContent(content);


3. How to persist plugin properties with new API

If you did it for previous versions of IDEA, you probably have the following code:


public class YourPluginConfiguration
       implements ProjectComponent, Configurable, JDOMExternalizable {
  private final String COMPONENT_NAME = ...;
 
  publuc String yourProperty; // property to be persisted

  public String getComponentName() {
    return COMPONENT_NAME;
  }

  public void readExternal(Element element) throws InvalidDataException {
    DefaultJDOMExternalizer.readExternal(this, element); // load
  }

  public void writeExternal(Element element) throws WriteExternalException {
    DefaultJDOMExternalizer.writeExternal(this, element); // save
  }

}


With new API you have to do something like this:


@State(
    name = YourPluginConfiguration.COMPONENT_NAME,
    storages = {@Storage(id = "your_id", file = "$PROJECT_FILE$")}
)
public final class YourPluginConfiguration
          implements ProjectComponent, Configurable, PersistentStateComponent<YourPluginConfiguration> {
  public static final String COMPONENT_NAME = ...;

  publuc String yourProperty; // property to be persisted

  public String getComponentName() {
    return COMPONENT_NAME;
  }

  public YourPluginConfiguration getState() {
    return this; // load
  }

  public void loadState(YourPluginConfigurationstate) {
    XmlSerializerUtil.copyBean(state, this); // save
  }

}


In this example we use $PROJECT_FILE$ macro. You have to use appropriates macros according to component level.

There are 3 types of component level. Each of them has unique, only for this level macros:

- application-level components (ApplicationComponent): $APP_CONFIG$, $OPTIONS$;
- project-level components (ProjectComponent): $PROJECT_FILE$, $WORKSPACE_FILE$, $PROJECT_CONFIG_DIR$;
- module-level components (ModuleComponent): $MODULE_FILE$


4. How to register intention action

Usually intention action should be assoсiated with some analytical tool that recognizes important situation and indicates about it the user. We also can assoсiate intention action with changes in the editor.

First, your class should implement IntentionAction. Additionally, if you want to listen to editor changes,it should extend EditorAction:


public class YourIntentionAction extends EditorAction implements IntentionAction {

  public YourIntentionAction() {
    super(new YourEditorActionHandler());
  }

  private static class YourEditorActionHandler extends EditorActionHandler /* or EditorWriteActionHandler */ {

    // This method is executed every time you do modifications in the editor.
    // Wev are trying to look for selections
    public void execute(Editor editor, DataContext dataContext) {
      String searchText = null;

      SelectionModel selection = editor.getSelectionModel();
      if (selection.hasSelection()) {
        searchText = selection.getSelectedText();
      }

      if (searchText != null && searchText.trim().length() > 0) {
        // Displays pop up

        Project project = DataKeys.PROJECT.getData(dataContext);

        showPopup(project, editor, searchText);
      }
    }
  }

 /**
   * Returns text to be shown in the list of available actions, if this action
   * is available.
   */
  @NotNull
  public String getText() {
    return "The text to show in the intention popup.";
  }

  /**
   * Returns the identifier of the family of intentions. This id is used to externalize
   * "auto-show" state of intentions. When user clicks on a lightbulb in intention list,
   * all intentions with the same family name get enabled/disabled. The identifier
   * is also used to locate the description and preview text for the intention.
   */
  @NotNull
  public String getFamilyName() {
    return "popup";
  }

  /**
   * Checks whether this intention is available at a caret offset in file.
   * If this method returns true, a light bulb for this intention is shown.
   */
  public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
    return editor.getSelectionModel().hasSelection();
  }

  /**
   * Called when user invokes intention. This method is called inside command.
   * If {@link #startInWriteAction()} returns true, this method is also called
   * inside write action.
   */
  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    String searchText = null;

    SelectionModel selection = editor.getSelectionModel();

    if (selection.hasSelection()) {
      searchText = selection.getSelectedText();
    }

    showPopup(project, editor, searchText);
  }

  /**
   * Indicate whether this action should be invoked inside write action.
   * Should return false if e.g. modal dialog is shown inside the action.
   * If false is returned the action itself is responsible for starting write action
   * when needed, by calling {@link com.intellij.openapi.application.Application#runWriteAction(Runnable)}.
   */
  public boolean startInWriteAction() {
    return false;
  }

 private static void showPopup(Project project, Editor editor, String searchText) {
    JPanel panel = ... // Create your content here

    JBPopup jbPopup = JBPopupFactory.getInstance()
        .createComponentPopupBuilder(panel, panel)
        .setDimensionServiceKey(project, "popup", false)
        .setRequestFocus(true)
        .setResizable(true)
        .setMovable(true)
        .setTitle("Your title")
        .createPopup();

    jbPopup.showInBestPositionFor(editor);
  }

}


You have to register your intention action. If you have project component, you can do it
in projectOpened() method:


  public void projectOpened() {
    IntentionManager.getInstance().addAction(new YourIntentionAction());
  }


Useful links

1. Tutorial

2. Plugin Development FAQ

3. The Basics of Plugin Development for IntelliJ IDEA

4. IntelliJ IDEA 7.x Developers Documentation

5. IntelliJ Developing Custom Language Plugins for IntelliJ IDEA 5.0

Thursday, November 15, 2007

New version of google-translate plugin for Intellij IDEA (1.0.5)

Google-Translate Plug-in version 1.0.5 is available for download
using IDEA's internal Plugin Manager or directly from the IDEA plug-ins
website at http://plugins.intellij.net/plugin/?id=1460.

Update:

1. Added Translation Preview feature. Select the text for preview and then intention icon will appear. Or press
"Alt-Enter" key combination to force the intention. Another way is to click on "Translation Preview" item
in editor pop-up.
2. Removed deprecated code.

How to use it in side IDEA editor:

1. In editor select the part to be translated;
2. Select "Translate" item from the editor popup menu;
3. (hidden) "translate.google.com" web site (service) will perform actual translation;
4. Response from the service will be inserted in place of your selection.

Friday, September 14, 2007

Application template generation with "Archetypes" program (Scriptlandia, Maven2, Beanshell)

Maven 2 has the notion of archetype. It is a template of a project which is combined with some user input to produce a working Maven project that has been tailored to the user's requirements.

Some other projects are trying to achieve same goal by using similar or slightly different approaches:

- AppFuse 1.x; (light) - uses Ant scripts to generate template;

- AppFuse 2.x; - uses Maven2 scripts to generate template;

- Able Project (https://svn.opensymphony.com/svn/sandbox/able);

- HSE (Hibernate, Spring, Echo2) Project;

- Archy project.

Archetypes program is based on my previous scripts (see my
previous post) and also inspired by Archy project.

All definitions of archetypes and repository locations are decoupled from source code into external xml file (archetypes.xml).

All archetypes are divided by groups. Group is the list or archetypes that has
same groupId, version (e.g. AppFuse, Maven2 or WebTidy groups).

Each archetype has name, description and version (if different from group version). All archetypes from same group are located in same repository. For example AppFuse fragment looks like:


<groups>
  ...

  <group name="Appfuse" groupId="org.appfuse" prefix="appfuse-" version="2.0-m5" >
    <archetypes>
      <archetype name="basic-jsf"
            description="Archetype for creating a web application with Hibernate, Spring and JSF"/>

      <archetype name="basic-spring"
            description="Archetype for creating a web application with Hibernate, Spring and Spring MVC"/>
      ...
    </archetypes>

    <repositories>
      <repository>http://static.appfuse.org/repository</repository>
    </repositories>
  </group>
  ...
</groups>


In order to run the application you have ho have Scriptlandia
project installed on your computer. It will take care of downloading all required dependencies, installing them locally on your computer and then executing Beanshell script. Otherwise, you have to be ready to do this manually.

Program can function in 2 modes: console and gui. For console mode you have to execute the following command:


>create-archetype.bsh -console


Program will ask the user about archetype group name and archetype name. Then, for your application, you have to specify groupId, artifactId and version. For these parameters Archetypes program will generate the resulting template in current directory.

For "gui" mode you have to execute the following command:


>create-archetype.bsh -wait


"wait" parameter is used my Scriptlandia framework to indicate that our script should wait for completion of gui/swing thread execution. Otherwise, frame will appear for very short time and just after that script execution will be terminated.

In "gui" mode you will see same input parameters, just layed out in more convenient for typical Windows user. After selecting appropriate archetype and clicking on "Create archetype" button, new project will be created in the current directory.

This program uses behind the scene
Scriptlandia API to execute maven2 tool:


ScriptlandiaHelper.executeMaven(args);


The source for this script is located here or within examples for Scriptlandia.

Hope tis program will save you time for your family and friends!

Article about JLaunchPad in German Java Magazine

Saturday, September 08, 2007

Sony PRS (Portable Reader System) and how to read russian books

I got new gadget for my wife - Sony book reader. Unfortunately, it does not support Russian language (and any other languages except English). What to do?

The solution would be to use pdf file with embedded fonts. In order to generate pdf file I use Java pdf library that is available for everybody: iText.

In this example I will use Scriptlandia feature to download and install required dependencies automatically. I use beanshell for writing the program:


// txt2pdf.bsh

import org.sf.scriptlandia.ScriptlandiaHelper;

ScriptlandiaHelper.resolveDependencies("itext", "itext", "2.0.4");

import java.io.FileOutputStream;
import java.io.IOException;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

if(bsh.args.length == 0) {
  print("Please specify input file.");

  return;
}

String inFileName = bsh.args[0];

int index = inFileName.indexOf(".");

String title = inFileName.substring(0, index);

String outFileName = title + ".pdf";

Document document = new Document();

// Creates a writer that listens to the document and directs a PDF-stream to a file.
PdfWriter.getInstance(document, new FileOutputStream(outFileName));

document.addTitle(title);

document.open();

BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(inFileName), "Cp1251"));

boolean done = false;

Paragraph paragraph = null;

while(!done) {
  String line = reader.readLine();

  if(line == null) {
    done = true;
  }
  else {
    BaseFont baseFont = BaseFont.createFont("c:\\windows\\fonts\\arial.ttf", "CP1251", BaseFont.EMBEDDED);
    Font font = new Font(baseFont, 28);

    if(line.startsWith(" ")) {
      paragraph = new Paragraph();
      paragraph.setLeading(28);
      document.add(paragraph);
    }

    document.add(new Chunk(" ", font));
    document.add(new Chunk(line, font));

  }
}

document.close();

This program produces simple pdf that is executed very fast on the reader comparing to standard process (text-to-word-to-pdf).

Tuesday, September 04, 2007

New version of Scriptlandia: 2.2.3 has been released!

Scriptlandia is the effort to build scripting command line environment on top of JVM. The user don't have to worry how to install or configure libraries for different scripting languages. It will be done automatically at installation and/or at execution time.

This release includes:

1. Integration with JLaunchPad;

2. Support for latest versions for languages such as Groovy, JRuby, Jython, Scala etc.

3. Added support for platforms not supported by JDIC library (see documentation);

4. Bug fixes.

Friday, August 31, 2007

Problem with maven-javadoc-plugin

I tried to run Maven 2.07 and maven-javadoc-plugin 2.3. Suddenly on "mvn site" I got the following error:


Failed to configure plugin parameters for: org.apache.maven.plugins:maven-javadoc-plugin:2.3

Not a number: ''


After analyzing parameters of this plugin I found only one parameter that is a number:


<parameter>
  <name>proxyPort</name>
  <type>int</type>
  ...
</parameter>


It seems that when you are not behind firewall (and, as result, have proxy port represented as empty string: ""), plugin has a bug.

Simple problem fix could be done in this way:


<reporting>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-javadoc-plugin</artifactId>

      <configuration>
        <proxyPort>0</proxyPort>
      </configuration>
    </plugin>
  </plugins>
</reporting>

Wednesday, August 29, 2007

ANNOUNCEMENT: JLaunchPad - next generation of java launcher

I'm pleased to announce the release of new project: JLaunchPad, version 1.0.0.

This program (Java launcher) is the set of Java classes and shell scripts (Windows and Unix) for simplifying installation/launching of Java applications. Once the launcher is installed, it can be reused for starting different Java applications.

For your application you have to specify required dependencies on other Java libraries (in maven-like fashion). When application is getting executed first time, all dependencies will be downloaded and installed automatically into your local repository. For all consequent executions of the application download process is not required and the only one responsibility of the launcher is to build correct "classpath" and launch the application.

How it works? It could be explained in the following steps:

1. On the dedicated server we have Central Repository (sponsored, non-profit, for everybody in the community/ IT industry) of Java components represented in binary format. It could be a separate Java library, some convenient tool or even GUI program.

2. Each component is provided with the group name, artifact name and the version. Classifier also could be used for specifying Java version of the component (e.g. jdk15, jdk16 etc.).

3. Each component has binary artifact and could also contain (optional) sources, javadocs or other artifacts.

4. Each component describes dependencies to other components in the form of Dependencies File. As the result, we have Dependencies Tree (or Transitive Dependencies).

5. Launcher program connects to the remote Central Repositories and downloads required components to the client's computer. Then the launcher builds correct CLASSPATH and then starts up the programs.

6. All downloaded components are stored in the Local Repository - it is the mirror of
Central Repositories and it contains only required components with their dependencies.

7. If somebody wants to introduce new program, s(he) describes it in the form of dependencies,then s(he) writes the code. As the result, it is required to distribute new code only - all dependencies will be downloaded later and only "on-demand" - when it is really required.

8. "Smart" start-up program reads Dependencies File, installs all the required dependencies and then starts the original program.

This is real separation of new code from related dependencies. If your application
is, say, dependent on "jdom" library, your distribution does not have to include this file. Instead, you provide dependencies for the project and they will be downloaded automatically.

For the implementation the following projects were reused:

- classworlds project (http://dist.codehaus.org/classworlds)
- bootstrap-mini project (http://svn.apache.org/repos/asf/maven/components/tags/maven-2.0.7/bootstrap)
- Java App Launcher (https://java-app-launcher.dev.java.net)

The project has plenty of examples that explain how to use this launcher for existing applications. The benefit is that all application deliveries will be built by same
unified scenario and do not contain dependencies - they will be downloaded/reused automatically. Among examples you can see such programs as Ant, Maven 2, Tomcat, JRuby, Groovy, Intellij IDEA, Glean and some other.

Initially this idea was implemented in another project. During last few moths I was able to separate the code and represent it as standalone project.

Thursday, August 09, 2007

New version of google-translate plugin for Intellij IDEA

Update: it works now with the latest version of Intellij IDEA 7 (Selena; build 7118).

How to use it in side IDEA editor:

1. In editor select the part to be translated;
2. Select "Translate" item from the editor popup menu;
3. (hidden) "translate.google.com" web site (service) will perform actual translation;
4. Response from the service will be inserted in place of your selection.

Saturday, May 05, 2007

New version of Scriptlandia: 2.2.1 has been released!

This release includes new features and new supported languages. The full list of
supported languages include:

- Javascript (1.6R4);
- Groovy (1.1-beta1);
- Beanshell (2.0b5);
- Jelly (1.0);
- JRuby (0.9.9);
- Jython (2.2b1);
- Pnuts (1.1);
- Jaskell (1.0);
- JScheme (7.2);
- TCL (1.4.0);
- AWK (0.14);
- f3 (?.?);
- Fortress (build 156);
- Scala (2.4.0);
- Sleep (2.1-beta15);
- Janino (2.5.5);
- Scriptella (0.7);
- Velocity (1.4);
- Freemarker (2.3.9);
- Ant (1.7.0);
- Maven (2.0.6).

Scriptlandia: what is it? It's the effort to build scripting command line environment on top of JVM. The user don't have to worry how to install or configure libraries for different scripting languages. It will be done automatically at installation and/or at execution time.

This project is useful for doing fast prototyping in your favorite language without spending time at all on installation/configuration (AKA CoC - convention over Configuration). It's also good for building simple command-line tools.

How is it different, say, from scripting-for-java project?

1. It's not tied to Java 6 platform. You can use Java 5; it's possible to have this code ready for java 1.4.

2. You can specify dependencies for the language in the form of dependencies file (currently it is based on maven 2 pom.xml format). As the result, these dependencies will be downloaded automatically from the server to your local repository when it's required.

3. It's easy to build environment in which scripts are aware of each other. It can be done by adding new dependencies, not through ancient CLASSPATH approach, but rather through dependencies file.

4. Language gear is available through the file extension. Thanks to jdic project, corresponding gear will be executed, based on file extension.

5. Based on extension, different convenient programs-launchers can be assigned to existing extensions like jar, war etc. As an example, if jar represents micro-edition application, suitable launcher will be started. In another example we can associate jar file with ant script and extend available commands for jar file, but everything whatever could be expressed as ant target.

6. New extensions are introduced: .sl (scriptlandia) and .cw (classworld). They can be used for starting arbitrary programs with correct dependencies specified. See examples: "cafebabe", "jclasslib", "udoc", "jlgui" for details.

7. Ant and Maven scripts are first-class citizens: you can interpret them as yet another scripting languages.

8. Scriptlandia is integrated with Nailgun server. It means that for simple scripts you can keep JVM in-memory, drastically reducing start-up time for running scripts.

9. It is not nescessary to install all dependencies at installation time. Installer program will download and install only minimally required libraries. The rest will be downloaded when you invoke fitst time the script.

Friday, April 06, 2007

New plugin for Intellij IDEA: translate text from one language to another (translate.google.com)

This plugin performs translations in Intellij IDEA Editor Window from one language to another (e.g. from Russian to Spain). It uses "http://translate.google.com" service behind the scene.

Plugin is especially convenient when you are trying to translate long i18n property files in your project for different languages.

Plugin adds "Translate" item into popup menu for the editor (also, in "Code" menu and "Generate" group). It also have separate configuration screen for selecting "from" and "to" languages.

How to use

1. Select the part to be translated;
2. Select "Translate" item from popup menu;
3. "translate.google.com" web site will perform actual translation;
4. Response from the service will be inserted in place of selection.

The project is located here.

Wednesday, April 04, 2007

How to build java presistence example with maven2

Here I will show how to build a very simple example that uses java persistence API. In order to simplify the build process I use maven 2. As the result, example archive is very short in size and all required libraries will be downloaded automatically only when it's really required.

1. Create new Java class, where you map java class/properties to database table/fields. Java persistence annotations will do this job for us:


import javax.persistence.*;

@Entity
@Table(name = "MESSAGES")
public class Message {

  @Id @GeneratedValue @Column(name = "MESSAGE_ID")
  private Long id;

  @Column(name = "MESSAGE_TEXT")
  private String text;

  @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "NEXT_MESSAGE_ID")
  private Message nextMessage;

  public Message() {}

  public Message(String text) {
    this.text = text;
  }

  // getter and setter methods for java properties
  ...
}


As you can see, "Message" class is mapped to "MESSAGES" table, "id", "text" and "nextMessage" properties - to "MESSAGE_ID", "MESSAGE_TEXT" and "NEXT_MESSAGE_ID" fields.

2. Now we can create simple program that uses persistent "Message" object:


import java.util.*;
import javax.persistence.*;

public class HelloWorld {

  public static void main(String[] args) {

    // Start EntityManagerFactory
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("helloworld");

    // First unit of work
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    tx.begin();

    Message message = new Message("Hello World with JPA");
    em.persist(message);

    tx.commit();
    em.close();

    // Second unit of work
    EntityManager newEm = emf.createEntityManager();
    EntityTransaction newTx = newEm.getTransaction();
    newTx.begin();

    List messages =
        newEm.createQuery("select m from Message m order by m.text asc").getResultList();

    System.out.println( messages.size() + " message(s) found:" );

    for (Object m : messages) {
      Message loadedMsg = (Message) m;
      System.out.println(loadedMsg.getText());
    }

    newTx.commit();
    newEm.close();

    // Shutting down the application
    emf.close();
  }

}


This example does not refer to any persistent framework directly. Instead, it uses symvolic names to get access to the framework in indirect way. In the abovementioned example we have "helloworld" name to refer to.

So, who is doing the persistence work here? We can use various frameworks here, but they should comply with java persistence API. For example, Hibernate or Toplink.

3. In this example we use Hibernate (http://hibernate.org) as persistence framework and hsqldb (http://hsqldb.org) as database. Let's take a look ad the hibernate configuration file (persistence.xml) where we describe "helloworld" factory:


<persistence xmlns="http://java.sun.com/xml/ns/persistence"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
   http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
   version="1.0">

  <!-- persistence.xml -->

  <persistence-unit name="helloworld">

    <!-- The provider only needs to be set if you use several JPA providers -->
    <provider>org.hibernate.ejb.HibernatePersistence</provider>

    <properties>
      <!-- Scan for annotated classes and Hibernate mapping XML files -->
      <property name="hibernate.archive.autodetection" value="class, hbm"/>

      <!-- SQL stdout logging -->
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="use_sql_comments" value="true"/>

      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>

      <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
      <property name="hibernate.connection.url" value="jdbc:hsqldb:file:persistence-db/test"/>
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.hbm2ddl.auto" value="create"/>

      <property name="hibernate.c3p0.min_size" value="5"/>
      <property name="hibernate.c3p0.max_size" value="20"/>
      <property name="hibernate.c3p0.timeout" value="300"/>
      <property name="hibernate.c3p0.max_statements" value="50"/>
      <property name="hibernate.c3p0.idle_test_period" value="3000"/>
    </properties>
  </persistence-unit>

</persistence>


This file should be located on your CLASSPATH within META-INF directory. "hibernate.hbm2ddl.auto" property will take care of creating database table automatically.

4. Maven 2 file is responsible of downloading all dependent libraries, building correct CLASSPATH for the project and running the example (we use "exec:java" plugin for it):


<?xml version="1.0" encoding="UTF-8"?>

<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>persistence-deps</groupId>
  <artifactId>persistence-deps</artifactId>
  <version>1.0</version>

  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.0.4</version>
    </dependency>

    <dependency>
      <groupId>hsqldb</groupId>
      <artifactId>hsqldb</artifactId>
      <version>1.8.0.7</version>
    </dependency>

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate</artifactId>
      <version>3.2.2.ga</version>
    </dependency>

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>3.2.1.ga</version>
    </dependency>

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>3.2.1.ga</version>
    </dependency>

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-tools</artifactId>
      <version>3.2.0.beta9a</version>
    </dependency>

    <dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1</version>
    </dependency>
  </dependencies>

  <build>
    <defaultGoal>compile</defaultGoal>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>java</goal>
            </goals>
          </execution>
        </executions>

        <configuration>
          <mainClass>hello.HelloWorld</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>scriptlandia-repo</id>
      <name>Scriptlandia Maven2 repository</name>
      <url>http://scriptlandia-repository.googlecode.com/svn/trunk/tools</url>
    </repository>
  </repositories>
</project>


5. Now, you can run compete example in one line:


>mvn compile exec:java


Complete example is located here.

Tuesday, April 03, 2007

How to compile and run Scala program with Ant and Maven 2

We have small scala program:


// HelloWorld.scala

object HelloWorld {

  def main(args: Array[String]) = {
    Console.println("Hello, world!")
  }

}


and want to compile/run it. In order to do it, we have to perform some additional steps.



    Compile/run with Ant


a). Scala is preinstalled

You need to have "scala-library" and "scala compiler" libraries in order to compile Scala programs.
You can download them from Scala web site (http://scala-lang.org).

Your ant script will start with the following lines:


<!-- 1. Define common properties. -->

<property name="src.dir" value="src/main/scala"/>
<property name="build.dir" value="target/classes"/>

<property name="repository.home" value="c:/maven-repository"/>
<property name="scala-compiler.jar" value="${repository.home}/scala/scala-compiler/2.4.0/scala-compiler-2.4.0.jar"/>
<property name="scala-library.jar" value="${repository.home}/scala/scala-library/2.4.0/scala-library-2.4.0.jar"/>

<!-- 2. Define Scala CLASSPATH. -->

<path id="scala.classpath">
  <pathelement location="${scala-compiler.jar}"/>
  <pathelement location="${scala-library.jar}"/>
</path>

<!-- 3. Define project CLASSPATH. -->

<path id="project.classpath">
  <path refid="scala.classpath"/>

  <pathelement location="${build.dir}"/>
</path>

<!-- 4. Define scala compiler command. -->

<taskdef resource="scala/tools/ant/antlib.xml">
  <classpath refid="scala.classpath"/>
</taskdef>


Now you can compile sources by using "scalac" command:


<!-- 5. Compiles sources by using "scalac" command. -->

<target name="compile">
  <mkdir dir="${build.dir}"/>

  <scalac srcdir="${src.dir}" destdir="${build.dir}" classpathref="project.classpath" force="changed">
    <include name="**/*.scala"/>
  </scalac>
</target>


Once compiled, you can run scala program:


<!-- 6. Runs scala executable. -->

<target name="run" depends="compile">
  <java classname="scala.tools.nsc.MainGenericRunner" fork="true">
    <classpath>
      <path refid="project.classpath"/>
    </classpath>

    <arg line="HelloWorld"/>
  </java>
</target>


Run this command:


>ant run


It will compile and then run scala example.


b). scala is being installed by maven 2


If you don't want to install scala libraries manually, you can use maven tasks for ant
(see http://maven.apache.org/ant-tasks.html for further details):


<project name="scala-compile-test2" default="compile" basedir="."
         xmlns:artifact="antlib:org.apache.maven.artifact.ant">

  <!-- 1. Define common properties. -->

  <property name="src.dir" value="src/main/scala"/>
  <property name="build.dir" value="target/classes"/>

  <!-- 2. Define Scala CLASSPATH with the help of Maven 2. -->

  <!--property name="repository.home" value="c:/maven-repository"/-->

  <artifact:localRepository id="local.repository" location="${repository.home}" layout="default"/>

  <artifact:pom file="scala-compile-test2.maven" id="maven.project" />

  <artifact:dependencies pathId="scala.classpath" filesetId="compile.fileset" useScope="compile">
    <pom refid="maven.project"/>
  </artifact:dependencies>


Steps 3-6 are the same as in previous example.


    Compile/run with Maven2


There are 2 maven plugings to work with scala sources. First plugin is implemented as
standard extension to the plexus compiler
(http://svn.codehaus.org/plexus/plexus-components/trunk/plexus-compiler/plexus-compilers).

The extension is located in the following repository:
http://scriptlandia-repository.googlecode.com/svn/trunk/languages

Another plugin for scala is implemented as regular maven plugin
(see details here: http://millstone.iodp.tamu.edu/~blambi/maven-scala-plugin).

a). plexus-compiler-scalac

First, you have to specify the location of scala sources. We'll do it with the help of
"build-helper-maven-plugin":


  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <executions>
      <execution>
        <id>add-source</id>
        <phase>generate-sources</phase>
        <goals>
          <goal>add-source</goal>
        </goals>
        <configuration>
          <sources>
            <source>src/main/scala</source>
          </sources>
        </configuration>
      </execution>
    </executions>
  </plugin>


Then you configure "maven-compiler-plugin" plugin:


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
      <compilerId>scalac</compilerId>

      <includes>
        <include>**</include>
      </includes>
    </configuration>

    <dependencies>
      <dependency>
        <groupId>org.codehaus.plexus</groupId>
        <artifactId>plexus-compiler-scalac</artifactId>
        <version>1.5.3</version>

        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </plugin>


And don't forget about right repository:


  <repositories>
    <repository>
      <id>scriptlandia-repo</id>
      <name>Scriptlandia Maven2 repository</name>
      <url>http://scriptlandia-repository.googlecode.com/svn/trunk/languages</url>
    </repository>
  </repositories>


Now, compilation is easy:


>mvn compile


In order to run compiled code we'll use "exec" maven plugin:


  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <executions>
      <execution>
        <goals>
          <goal>java</goal>
        </goals>
      </execution>
    </executions>

    <configuration>
      <mainClass>HelloWorld</mainClass>
    </configuration>
  </plugin>


And run it:


>mvn exec:java


b). maven-scala-plugin

This plugin contains 2 parts: compiler and runner. It requires small configuration:


  <plugin>
    <groupId>iodp.usio</groupId>
    <artifactId>maven-scala-plugin</artifactId>

    <configuration>
      <mainClass>HelloWorld</mainClass>
    </configuration>
    <executions>
      <execution>
        <phase>compile</phase>
        <goals>
          <goal>compile</goal>
        </goals>
      </execution>
    </executions>
  </plugin>


You also have to specify the location of this plugin:


  <pluginRepositories>
    <pluginRepository>
      <id>maven2.iodp.usio</id>
      <name>IODP Maven2 Repository</name>
      <url>http://millstone.iodp.tamu.edu/maven2</url>
    </pluginRepository>
  </pluginRepositories>


Now you will be able to compile and run scala code now:


>mvn scala:compile

>mvn scala:run -DmainClass=HelloWorld

Wednesday, March 28, 2007

How to build completely dynamic example with Spring 2, Scriptlandia, Beanshell, Groovy and JRuby (revisited)

I made small modifications to previously explained example in order to use the custom dynamic language tags from Spring 2 to define dynamic-language-backed beans. Finally, the spring configuration file looks like

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

  <!-- Creates cat. -->
  <lang:groovy id="cat" script-source="classpath:Cat.groovy">
    <lang:property name="name" value="cat-name"/>
  </lang:groovy>

  <!-- Creates dog. -->
  <lang:jruby id="dog" script-interfaces="Animal" script-source="classpath:Dog.ruby"
              refresh-check-delay="5000"> <!-- switches refreshing on with 5 seconds between checks -->

    <lang:property name="name" value="dog-name"/>
  </lang:jruby>

  <!-- Creates cow. -->
  <lang:bsh id="cow" script-interfaces="Animal" script-source="classpath:Cow.bsh">
    <lang:property name="name" value="cow-name"/>
  </lang:bsh>

  <!-- Creates ant (inline script). -->
  <lang:groovy id="ant">
    <lang:inline-script>
      class Ant implements Animal {
        String name

        void makeSound() {
          println name + ": Shhh..."
        }
      }
    </lang:inline-script>
    <lang:property name="name" value="ant-name" />
  </lang:groovy>

  <!-- Creates animal farm. -->
  <bean id="farm" class="AnimalFarm">
    <property name="animals">
      <list>
        <ref bean="cat"/>
        <ref bean="dog"/>
        <ref bean="cow"/>
        <ref bean="ant"/>
      </list>
    </property>
  </bean>

</beans>



The final version of example is located here.

Monday, March 19, 2007

How to build completely dynamic example with Spring 2, Scriptlandia, Beanshell, Groovy and JRuby

Recently, I found this project: GroovyWorks;.
It tries to use together such things as Java, Groovy, Spring 2 and Struts 2. Because Struts actions are written as Groovy scripts, it is not required to restart web application for each and every change. It is possible because of dynamic nature of Groovy language.

But still, it's not completely dynamic. Small portion of the system is written in Java and for each change in Java you have to recompile and redeploy your web application. Is it possible to make it completely dynamic?

In the following lines I will explain how to build such completely dynamic code. It is standalone application, so Struts 2 is not required. But we still want to have IoC container. Spring 2 fits for our needs, especially with new struts-scripting library, that supports 3 popular languages: Groovy, JRuby and Beanshell.

1. In order to work with scripts inside Spring 2 we have to create Java classes first. Let's create animal farm that consists of animals:


// Animal.java

public interface Animal {

public void makeSound();

}

// AnimalFarm.java

import java.util.List;

public class AnimalFarm {
private List animals;

public AnimalFarm() {
System.out.println("New Animal farm has been created.");
}

public void setAnimals(List animals) {
this.animals = animals;
}

public void wakeUp() {
for(int i=0; i < animals.size(); i++) {
Animal animal = (Animal)animals.get(i);

animal.makeSound();
}
}

}


2. Now, we can implements different animals in different languages:


// Cat.groovy

class Cat implements Animal {

void makeSound() {
println "Meow!"
}

}

# Dog.rb

require "java"

include_class("Animal")

class Dog < Animal
def makeSound
puts "Bark!!!"
end
end

Dog.new

// Cow.bsh

void makeSound() {
System.out.println("Moo...");
}


3. We'll keep all required libraries in the form of maven2 dependencies file.
Because current version of spring (2.0.3) is not compatible with jruby version 0.9.8
(see bug SPR-3255),
we have to keep reference to temporary repository:
http://scriptlandia-repository.googlecode.com/svn/trunk/patches.

4. All required beans are defined inside spring file:


<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<!-- dynamo-test.xml -->

<beans>
<!-- Enables spring-scripting. -->
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>

<!-- Creates cat. -->
<bean id="cat" class="org.springframework.scripting.groovy.GroovyScriptFactory">
<constructor-arg value="file:Cat.groovy" />
</bean>

<!-- Creates dog. -->
<bean id="dog" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg value="file:Dog.ruby" />
<constructor-arg value="Animal" />
</bean>

<!-- Creates cow. -->
<bean id="cow" class="org.springframework.scripting.bsh.BshScriptFactory">
<constructor-arg value="file:Cow.bsh" />
<constructor-arg value="Animal" />
</bean>

<!-- Creates animal farm. -->
<bean id="farm" class="AnimalFarm">
<property name="animals">
<list>
<ref bean="cat"/>
<ref bean="dog"/>
<ref bean="cow"/>
</list>
</property>
</bean>
</beans>


5. The trickiest part here is how to avoid compilation of java code, making code
completely dynamic. To achieve it, we use janino library (http://www.janino.net/)
with JavaSourceClassLoader. We load class from source file, retrieve it as array of bytes
and then add this array as a class to our class loader.

To load required classes/libraries to CLASSPATH we use Scriptlandia API (http://scriptlandia.sf.net).
The complete example is represented below:


// dynamo-test.bsh

org.sf.scriptlandia.ScriptlandiaHelper.addMavenDependencies("pom.xml");

import org.sf.scriptlandia.launcher.ScriptlandiaLauncher;
import org.codehaus.janino.*;

import org.sf.scriptlandia.util.*;
import org.codehaus.classworlds.ClassRealm;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;


public class Dynamo {
private ClassRealm classRealm;
private ApplicationContext factory;

public Dynamo(String basedir, String[] classNames, String beansFile) {
ScriptlandiaLauncher launcher = ScriptlandiaLauncher.getInstance();

classRealm = launcher.getMainRealm();

register(basedir, classNames);

factory = new FileSystemXmlApplicationContext(new String[] { basedir + "/" + beansFile });
}

private void register(String basedir, String[] classNames) {
ScriptlandiaLauncher launcher = ScriptlandiaLauncher.getInstance();

ClassLoader sourceClassloader = new JavaSourceClassLoader(
launcher.getClass().getClassLoader(), // parentClassLoader
new File[] { new File(basedir) }, // optionalSourcePath
(String) null, // optionalCharacterEncoding
DebuggingInformation.NONE // debuggingInformation
);

for(int i=0; i < classNames.length; i++) {
loadClass(classNames[i], sourceClassloader);
}
}

/**
* Loads class specified by the name.
*/
private void loadClass(String name, ClassLoader classLoader) {
String[] args = new String[] { name };

Map bytecodes = ReflectionUtil.invokePrivateMethod(
classLoader,
new Object[] { name },
JavaSourceClassLoader.class,
"generateBytecodes",
new Class[] { String.class });

classRealm.addConstituent(name, bytecodes.get(name));
}

public Object getBean(String beanName) {
return factory.getBean(beanName);
}

public static void main(String[] args) throws Exception {
// Java classes that needs to be registered.
String[] classNames = new String[] {"Animal", "AnimalFarm" };
String basedir = System.getProperty("user.dir");

Dynamo dynamo = new Dynamo(basedir, classNames, "dynamo-test.xml");

AnimalFarm animalFarm = dynamo.getBean("farm");

animalFarm.wakeUp();
}

}

Thursday, March 08, 2007

Building GUI frontend for Maven2 archetype plugin (Beanshell, Swing, Scriptlandia)

There are multiple archetypes available for developers:
  • standard Maven 2 distribution contains 5 archetypes: "archetype", "j2ee-simple", "mojo", "quickstart", "site", "webapp";
  • AppFuse 2.0 project (http://appfuse.org) now is rewritten in form of different archetypes (8): "basic-jsf", "basic-spring", "basic-struts", "basic-tapestry", "modular-jsf", "modular-spring", "modular-struts", "modular-tapestry";
  • WebTide site (http://www.webtide.com/resources.jsp) published archetypes for web development (10): "ActiveMQ", "DOJO", "DWR", "JSF", "SiteMesh", "Spring", "SpringJpa", "Struts", "Tapestry", "WebWork";
  • JPA 101 (http://jroller.com/page/cmaki?entry=jpa_maven_2_archetype) archetype ("hibernate-archetype").
How to handle this amount of different types?

I wrote simple front-end with the help of Swing and Beanshell that displays all input parameters for the project (group ID, artifact ID, version and arche-type). After selecting appropriate archetype and clicking on "Create archetype" button, new project will be created in the current directory.

The source for this script is located here: create-archetype.bsh.

This program uses behind the scene Scriptlandia API to execute maven2 tool:

ScriptlandiaHelper.executeMaven(args);

After this work is done, it's easy to create simple starters for different archetype implementations.

For starting standard maven 2 archetypes:

// maven-archetype.bsh

sourceRelative("create-archetype.bsh");

String[] archetypes = {
"archetype", "j2ee-simple", "mojo", "quickstart", "site", "webapp"
};


CreateArchetype frame = new CreateArchetype("WebTide");

frame.setArchetypes(archetypes);
frame.setArchetypeGroupId("org.apache.maven.archetypes");
frame.setArchetypeArtifactIdPrefix("maven-archetype-");
frame.setArchetypeVersion("1.0");

frame.setVisible(true);

For starting AppFuse archetypes:

// appfuse-archetype.bsh

sourceRelative("create-archetype.bsh");

String[] archetypes = {
"basic-jsf", "basic-spring", "basic-struts", "basic-tapestry",
"modular-jsf", "modular-spring", "modular-struts", "modular-tapestry"
};


CreateArchetype frame = new CreateArchetype("Appfuse");

frame.setArchetypes(archetypes);
frame.setArchetypeGroupId("org.appfuse");
frame.setArchetypeArtifactIdPrefix("appfuse-");
frame.setArchetypeVersion("1.0-m3");
frame.setRemoteRepositories("http://static.appfuse.org/repository");

frame.setVisible(true);


For starting WebTide archetypes:

// webtide-archetype.bsh
// Resource: http://www.webtide.com/resources.jsp

sourceRelative("create-archetype.bsh");

String[] archetypes = {
"ActiveMQ", "DOJO", "DWR", "JSF", "SiteMesh", "Spring", "SpringJpa", "Struts", "Tapestry", "WebWork"
};


CreateArchetype frame = new CreateArchetype("WebTide");

frame.setArchetypes(archetypes);
frame.setArchetypeGroupId("com.webtide");
frame.setArchetypeArtifactIdPrefix("maven-archetype-");
frame.setArchetypeVersion("1.0");
frame.setRemoteRepositories("http://scriptlandia-repository.googlecode.com/svn/trunk/tools");

frame.setVisible(true);


For starting Jpa 101 archetype:

// jpa-archetype.bsh

// Resource: http://jroller.com/page/cmaki?entry=jpa_maven_2_archetype

sourceRelative("create-archetype.bsh");

String[] archetypes = {
"hibernate-archetype"
};

CreateArchetype frame = new CreateArchetype("JPA");

frame.setArchetypes(archetypes);
frame.setArchetypeGroupId("com.sourcebeat");
frame.setArchetypeArtifactIdPrefix("jpa-");
frame.setArchetypeVersion("1.0-SNAPSHOT");
frame.setRemoteRepositories("http://scriptlandia-repository.googlecode.com/svn/trunk/tools");

frame.setVisible(true);

Wednesday, March 07, 2007

New version of Scriptlandia: 2.2.0 has been released!

This release includes new features and new supported languages. The full list of
supported languages include:

- Javascript (1.6R4);
- Groovy (1.0);
- Beanshell (2.0b5);
- Jelly (1.0);
- JRuby (0.9.8);
- Jython (2.2b1);
- Pnuts (1.1);
- Jaskell (1.0);
- JScheme (7.2);
- TCL (1.4.0);
- AWK (0.14);
- f3 (?.?);
- Fortress (?.?);
- Scala (2.3.3);
- Janino (2.5.5);
- Scriptella (0.7);
- Velocity (1.4);
- Freemarker (2.3.9);
- Ant (1.7.0);
- Maven (2.0.5).

What is it: Scriptlandia? It's the effort to build environment on top of JVM. The user don't have
to worry how to install or configure libraries for different scripting languages. It will be done
automatically at installation and/or at execution time.

This project is useful for doing fast prototyping in your favorite language without spending time
on installation/configuration (aka CoC). It's also good for building simple command-line tools.

How is it different from, say scripting-for-java project?

1. It's not tied to Java 6 platform. You can use Java 5; it's possible to have this code ready for java 1.4.

2. You can specify dependencies for the language in the form of maven 2 project file. As the result, these dependencies will be downloaded automatically from the server to your local repository.

3. It's easy to build environment in which scripts are aware of each other. It can be done by adding new dependencies (not through ancient CLASSPATH approach).

4. Language gear is available through the file extension. Thanks to jdic project, corresponding
gear will be executed, based on extension.

5. Based on extension, different convenient programs-launchers can be assigned to existing extensions like jar, war etc. As an example, if jar represents micro-edition application, suitable launcher will be started. In another example we can associate jar file with ant script and extend available commands for jar file (now execute command only, see jdk documentation), but everything whatever could be expressed as ant target.

6. New extensions are introduced: .sl (scriptlandia) and .cw (classworld). They are used for starting arbitrary programs with correct dependencies specified.

7. Ant and Maven scripts are first-class citizens: you can interpret them as another scripting languages.

8. Scriptlandia is integrated with Nailgun server. It means that for simple scripts you can keep
JVM in-memory, drastically reducing start-up time for running scripts.