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.

Wednesday, August 23, 2006

Friday, August 18, 2006

How to run Rails on JRuby

Im order to do it, you have to perform the following steps.


1. Install ruby interpreter into ${ruby.home} (e.g. c:\ruby-1.8.4-20).
You can download latest version for Windows from here:

http://rubyforge.org/frs/download.php/11926/ruby184-20.exe

Test it (check ruby version):

>ruby.exe -v


Ruby installation has packaging tool called gem. Test it's version:

>gem.bat -v



2. Install rails. You can do it in one command:

>gem.bat --no-rdoc --no-ri --include-dependencies install rails


If you are behind the proxy, download gems separately and then install them individually:

>gem.bat install --no-rdoc --no-ri activesupport-1.3.1.gem
>gem.bat install --no-rdoc --no-ri activerecord-1.14.4.gem
>gem.bat install --no-rdoc --no-ri actionpack-1.12.5.gem
>gem.bat install --no-rdoc --no-ri actionmailer-1.2.5.gem
>gem.bat install --no-rdoc --no-ri actionwebservice-1.1.6.gem
>gem.bat install --no-rdoc --no-ri RbYAML-0.1.0.gem
>gem.bat install --no-rdoc --no-ri rails-1.1.6.gem

All of these gem files could be downloaded from http://rubyforge.org site.

You can also update gem tool to the latest version:

>gem.bat install --no-rdoc --no-ri rubygems-update-0.9.0.gem

Test rails version:

>rails.bat -v



3. Install jruby library into ${jruby.home} folder (e.g. c:\jruby-0.9.1).
Prepare jruby.bat script file:

SET RUBY_HOME=c:\ruby-1.8.4-20
SET JRUBY_HOME=c:\jruby-0.9.1

SET CLASSPATH=%JRUBY_HOME%\lib\jruby.jar;%JRUBY_HOME%\lib\jvyaml.jar;%JRUBY_HOME%\lib\plaincharset.jar;%JRUBY_HOME%\lib\asm.jar

java -Djruby.home=%RUBY_HOME% -Djruby.shell="cmd.exe" -Djruby.script=jruby.bat -classpath %CLASSPATH% org.jruby.Main


The trick here is that we use native ruby libraries from ruby installation (not from jruby installation).

Now you can execute all commands, required for building/running Rails application.



4. Create new project (testrails). Keep in mind that the project will be created in the current directory:

>jruby.bat c:\ruby-1.8.4-20\bin\rails testrails


Newly generated project has already some commands inside, so we need to change the current directory:

>cd testrails



5. Modify testrails\config\database.yml to point to your database. By default, it's MySQL database.



6. Start the database. Create database for devepoment: testrails_development



7. Generate the model

>jruby.bat .\script\generate controller MyTest



8. Generate the controller

>jruby.bat .\script\generate controller MyTest



9. Start the WEBrick server

>start jruby.bat .\script\server



10. Test if server is started properly in the browser:

>http://localhost:3000/my_test

Now you should see your view.


Rails on JRuby is very slow. Let's wait for improvements from JRuby team.

Monday, June 19, 2006

How to pre-compile JSP pages for Weblogic8 with Ant

It can be done in similar way as for Tomcat Application Server (see this link). The only difference is: we have another JSP compiler which takes different input parameters and expects JSP pages in well specified locations. It does not "like" JSP pages within WEB-INF folder, so you need to follow this rule. Otherwise you have to copy files with "wrong" locations into "right" locations.

1. Specify "project.classpath" for your project. It will include all jars required to compile or run your project:


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


2. Specify "weblogic.jsp.classpath". You need to have Weblogic Web Server installed ar ${weblogic.home}. You also need to specify, where you have your implementation of logging system ("${repository.home}/log4j").


  <path id="weblogic.jsp.classpath">

    <!-- 1. You have to include jars from your project. -->

    <path refid="project.classpath"/>

    <!-- 2. Weblogic jsp compiler and dependent classes (including JavaEE/Servlet/JSP interface classes). -->

    <fileset dir="${weblogic.home}/server/lib">
      <include name="weblogic.jar"/>
    </fileset>

    <!-- 3. This library is required by Weblogic jsp compiler (not in weblogic installation!). -->

    <fileset dir="${repository.home}/saxpath">
      <include name="saxpath-1.0-FCS.jar"/>
    </fileset>

    <!-- 4. Weblogic jsp compiler internally uses Java compiler. -->

    <fileset dir="${java.home}/lib">
      <include name="tools.jar"/>
    </fileset>

    <fileset dir="${java.home}/../lib">
      <include name="tools.jar"/>
    </fileset>

    <!-- 5. Implementation of logging system (if it is not in "project.classpath" yet). -->

     <fileset dir="${global.repository.home}/log4j">
       <include name="log4j-1.2.8.jar"/>
     </fileset>
  </path>


3. Now we can generate Java sources for JSP files.


  <property name="jsp.src.dir" value="<the root for your JSP files>"/>
  <property name="jsp.package.name" value="<the package name for your JSPs, like com.mycompany.jsp>"/>

  <property name="build.dir" value="target/build"/>
  <property name="jsp.generated.src.dir" value="${build.dir}/jsp_sources"/>
  <property name="jsp.classes.dir" value="${build.dir}/jsp_classes"/>

  <target name="tomcat.jsp.generate">
    <mkdir dir="${jsp.generated.src.dir}"/>
    <mkdir dir="${jsp.classes.dir}"/>

    <java classname="org.apache.jasper.JspC" fork="yes">
      <classpath refid="tomcat.jsp.classpath" />

      <arg line="-uriroot ${jsp.src.dir} -d ${jsp.generated.src.dir} -p ${jsp.package.name} -webapp ${jsp.src.dir}" />
    </java>
  </target>

  <target name ="weblogic.jsp.generate">
    <mkdir dir="${jsp.generated.src.dir}"/>
    <mkdir dir="${jsp.classes.dir}"/>

    <java classname="weblogic.jspc" fork="yes">
      <classpath refid="weblogic.jsp.classpath" />

      <sysproperty key="weblogic.jsp.windows.caseSensitive" value="false"/>

      <arg line="-forceGeneration -keepgenerated -compileAll -webapp ${jsp.src.dir} -d ${jsp.generated.src.dir}"/>
    </java>
  </target>


It is very important to set "weblogic.jsp.windows.caseSensitive" to "false". At the same step Weblogic will compile Java sources into Java classes (-forceGeneration and -keepgenerated). Compiled JSP java classes will be located in same folders as JSP compiled classes. We will separate them on next step.

You don't have to specify package name for JSP pages. JSP compiler will assign default "jsp_servlet" package name for all JSP pages. Each folder will be converted with the "_" prefix plus original name, each jsp page into "__" prefix plus original name.

4. Now, it's better to separate generated Java sources from compiled files.


  <target name ="weblogic.jsp.compile" depends="weblogic.jsp.generate"
          description="Separates sources from classes">
    <move todir="${jsp.classes.dir}/jsp_servlet">
      <fileset dir="${jsp.generated.src.dir}/jsp_servlet">
        <include name="**/*.class"/>
      </fileset>
    </move>
  </target>


If, on this step you don't have compiler errors, your source code (JSP part) is not broken.

When you assemble war file, you should include everything from ${jsp.src.dir} folder except JSP files and their includes.