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.

Wednesday, December 13, 2006

New JiniExamples (2.1.001) Project

This new project is dedicated to Jini Technology. It is reincarnation of my very old project for Jini ver. 1.0. Now it's adapted to Jini ver. 2.1.

The project includes 22 examples, starting from simplest toward more practical examples. The advantages of this project over another similar projects are:
- up to date examples;
- ready to use Ant scripts (zero configuration);
- Maven 2 project file for automatic downloads of required dependent files.

As the result, even beginner could start examples before looking at actual sources for examples. And they are as simple as possible - I try to focus on one aspect only at the same time.

Hope it accelerates development speed as well as attracts more interest to this underestimated technology.

Structurally, all examples are divided into 3 groups:

Simple Tests

# Common tests
# Developing simple service
# Simple Remote Service over JERI
# Simple Remote Service over JERI started from configuration file
# Client as servlet/JSP
# Simple service as service UI

Advanced Tests

# Client listening for events
# Building event generator
# Administrable service
# Activatable Jeri service
# Administrable and Activatable service
# EventMailbox (mercury) example
# Norm example
# Fiddler example
# JavaSpace example
# JavaSpace (Blitz) examples
# Federate example
# Failover example

Practical Examples

# Jini and NetLib library
# Jini and Database
# Speaker service (Speech API)
# Jini Services for home (music, speech, time)

Wednesday, September 20, 2006

Java Kernel (Browser Edition)

It looks like Sun is trying to make right steps:

Ethan Nicholas's Blog

Feedback from Artima site

It's not only about the size, it's more about well designed system.