Wednesday, February 27, 2008

Announcement: New release of Scriptlandia (ver. 2.2.4)

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, partially at installation time and partially at execution time.

This release includes:

1. Support for latest versions of languages/tools: Scala, Jython, Pnuts, Groovy, JRuby, Sleep, Scriptella, Fortress, Freemarker, Ivy, Maven.

2. Added support for new languages: Clojure, P~, YOIX, GANT (Groovy Ant);

3. Integration with JLaunchPad 1.0.1 (Added support for proxy with authenication);

4. Removing dependency on JDIC library - replacing it with builtin support from "deploy.jar";

5. Other bug fixes/improvements.

Tuesday, February 26, 2008

Announcement : New version of JLaunchPad 1.0.1 - universal java launcher

This program tries to resolve the following challenges:

1. It gets rid of complex starting scripts to run JVM with different parameters (memory optimizers, classpath,
bootclasspath, native library path, system properties etc.). The idea is to have one universal script that fits all possible scenarios. The part that is different from one project to another is moved to configuration file. JLaunchPad provides ready to use scripts both for Windows and Unix environments that can be used by any Java program. If you need to customize the process of starting JVM, you don't modify these scripts. Instead, you make modifications in the configuration file.

For example, if you want to run your program that requires native library (*.dll), your configuration will
look something like this:


# my_prg.jlcfg
# my configuration

<java.library.path>
_path_to_your_dll_library_

<jvm.args>
-Xms256m
-Xmx512m

<launcher.class>
_your_fully_qualified_class_name_

<command.line.args>
_param1_
_param2_


You can use the following sections within your configuration file:

- "java.classpath";
- "java.endorsed.dirs";
- "java.ext.dirs";
- "java.library.path";
- "java.system.props";
- "java.bootclasspath";
- "java.bootclasspath.prepend";
- "java.bootclasspath.append";
- "jvm.args";
- "launcher.class";
- "set.variables";
- "command.line.args".

It seems that for projects with simple start scripts it's not worth using it. But JLaunchPad
offers some other features that could be useful for your project.

This part of the functionality is based (with some modification) on Java App Launcher project.

2. It downloads all dependent libraries (if necessary) from remote server and installs them locally. You don't have to install libraries manually. Once you declare the dependency, it will be downloaded and installed automatically.

It requires to have all used libraries located on remote server. It's true for all
installations that exist in WWW, but we have to organize these installations a little bit more. To eliminate infamous jar hell we want to introduce separation based on group name and version. Closest candidate that could make this organization happen is maven repository.

We have to make these changes in configuration to make it happen:


# my_prg.jlcfg
# my configuration

<launcher.class>
_special_launcher_class_

<command.line.args>
-deps.file.name=_my_deps_file_.xml


Remote maven repositories are used as the storage for libraries and maven project file is used for describing dependencies. As you can see, we try to reuse maven abilities as much as possible.

This part of functionality becomes available thanks to "bootstrap-mini" project that is
the part of maven2 source.
It provides file delivery mechanism, independent from maven2 standard delivery mechanism.

3. It builds CLASSPATH dynamically based on declared dependencies. You can put all the dependencies for your project in dependencies file. Current implementation
uses maven2 pom.xml file for describing dependencies. As an example, if you want to run JRuby engine, you need to have these files:

a). JLaunchPad configuration:


# my_prg.jlcfg
# my configuration

<launcher.class>
_special_launcher_class_

<command.line.args>
-deps.file.name=_jruby_deps_file_.xml
-main.class.name=org.jruby.Main


b). JRuby dependencies file


<!-- _jruby_deps_file_.xml -->

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.sf.scriptlandia</groupId>
<artifactId>jruby-starter</artifactId>
<version>1.0</version>
<packaging>pom</packaging>

<name>JRuby Starter</name>
<description>JRuby Starter</description>

<dependencies>
<dependency>
<groupId>jruby</groupId>
<artifactId>jruby</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
</project>


This functionality is possible thanks to classworlds project.

JLaunchPad's main responsibility is to integrate these 3 different approaches into one powerful solution.
Classworlds takes care of classloader management. We read dependencies files and inform classworlds about new libraries that should be added to CLASSPATH. To accomplish it, "_special_launcher_class_" should be substituted with "org.codehaus.classworlds.Launcher" class.
We only need to tell classworlds which class to run: "org.sf.jlaunchpad.JLaunchPadLauncher". This class is main integration point that performs main preparation work: it reads dependencies file, download them if required and add them dynamically to CLASSPATH. Then it tries to execute java class declared with "main.class.name" parameter.


Changes for current release:

- added proxy with authentication;

- storing configuration parameters (proxy, local repository location, remote repositories location)
in settings.xml file;

- added new examples;

- changes in installation program layout;

- other changes and improvements.

Sunday, February 24, 2008

New Free Service from Google - WebCall Button

If you have a blog on Google's www.blogspot.com site, you can benefit from new exciting service - WebCall Button. What does it mean?

Simply by putting this button on your web site (I don't think it's restricted with your blog only), you will get one "virtual" phone number that could redirect calls to your home, cell or work phone numbers. Or to voice mail. And sender shouldn't know your phone number at all.

Or imagine another situation. You don't want to share your home, cell and work phones. Instead, you expose your "virtual" phone number to outside world and this service will redirect all incoming calls to home, cell, work phones (or to voicemail).

You also could publish separate voice mail on your blog/web-site as embedded object.

In order to use this service you have to register your account at Grand Central. Now it's part of Google.

You can try this service by calling my home number right from my blog page at Scriptlandia blog.

Monday, February 11, 2008

Maven Archetypes as standalone program

Initial Release.

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

It is not required to have Maven 2 preinstalled - instead it uses JLaunchPad (as part of the installation). It means that required by Maven and Maven Archetypes Plugin parts will be downloaded and installed into your local repository automatically.

All you need to do is to specify the location of Java and the location of Maven repository. If you are working behind the firewall, you have to specify proxy parameters too.

Saturday, February 09, 2008

Tip: How to use Intellij IDEA and Maven 2 together for debugging and context help

Latest version of Intellij IDEA has excellent integration with Maven 2. I want to explain one tip that could help you to gain productivity.

When you debug with IDEA, it's nice to have sources and javadocs for each used library registered with IDEA. If you have registered additional sources, you can debug deeper, going inside those sources. If you have registered additional javadocs, you can get context help for used classes from that libraries.

Unfortunately, this process is manual and tedious. Usually you have to do the following actions:

1. Find out on Internet sources for given library and unzip them locally.


2. Find out on Internet javadocs for given library and unzip it locally.


3. With the help of Intellij IDEA you have to register unzipped sources and javadocs.

This should be done for each external library in the project. If you have a lot of dependencies,
it'll take a lot of time.

Even if your project is dependent on other your own libraries, you still won't get sources and context helps
for them automatically. To have this support, you will do same things as what you did for external libraries -
IDEA should know where your dependent sources/javadocs are located.

Is it possible to make this process less time consuming, less painful? And the answer is: Yes.

When your project is equipped with maven's pom.xml file, you can do the following trick. Close your current
project and next time, when you try to open this project again, use pom.xml file as the project file (use "Open Project" functionality) instead of regular IDEA project file.

What happens here, IDEA is trying to resolve dependencies, defined inside maven project file and populates them back into IDEA's project (synch up). After such synchronization, IDEA is looking for sources and javadocs inside maven reopsitory. They should be located in same folder as your jar file and should have name built by special scheme. For example, my example library is located here:


${maven.local.repository}/org/google/code/maven-archetypes/1.0.0/maven-archetypes-1.0.0.jar


My sources and javadocs should be layed out in this way


${maven.local.repository}/org/google/code/maven-archetypes/1.0.0/maven-archetypes-1.0.0-sources.jar
${maven.local.repository}/org/google/code/maven-archetypes/1.0.0/maven-archetypes-1.0.0-javadoc.jar


As you can see, maven has "classifier" notion that helps us to differentiate "jar" artifact from "sources" and
"javadocs" artifacts.

Good thing is that most of new artifacts to be deployed recently into maven repositories (or at least everybody who understand it and wants to benefit from it), follow this pattern.

Now, what we have to do for our project components to be "in synch" with this pattern? Follow these steps:

1. Generate sources and javadocs with the help of "maven-source-plugin" and "maven-javadoc-plugin"
plugins:


>mvn source:jar
                                                                              
>mvn javadoc:jar


After the execution of these commands, 2 new files will be created. By default, you will see these files in "target" folder:


maven-archetypes-1.0.0-javadoc.jar
maven-archetypes-1.0.0-sources.jar


2. Install sources into maven repository:


mvn install:install-file ^
  -Dfile=target/yourArtifactId-yourVersion-sources.jar ^
  -DgroupId=yourGroupId ^
  -DartifactId=yourArtifactId ^
  -Dversion=yourVersion ^
  -Dpackaging=jar ^
  -Dclassifier=sources ^
  -DgeneratePom=false


3. Install javadocs into maven repository:


mvn install:install-file ^
  -Dfile=target/yourArtifactId-yourVersion-javadoc.jar ^
  -DgroupId=yourGroupId ^
  -DartifactId=yourArtifactId ^
  -Dversion=yourVersion ^
  -Dpackaging=jar ^
  -Dclassifier=javadoc ^
  -DgeneratePom=false


You can use this batch script to do all commands in one step:


rem install-jar-javadoc-sources.bat

rem 1. generate sources jar file

call mvn source:jar

rem 2. generate javadoc jar file

call mvn javadoc:jar

SET GROUP_ID=org.google.code
SET ARTIFACT_ID=maven-archetypes
SET VERSION=1.0.0

SET SOURCES_CLASSIFIER=sources
SET JAVADOC_CLASSIFIER=javadoc

rem 3. install sources jar file

call mvn install:install-file ^
  "-Dfile=target/%ARTIFACT_ID%-%VERSION%-%SOURCES_CLASSIFIER%.jar" ^
  "-DgroupId=%GROUP_ID%" ^
  "-DartifactId=%ARTIFACT_ID%" ^
  "-Dversion=%VERSION%" ^
  "-Dpackaging=jar" ^
  "-Dclassifier=%SOURCES_CLASSIFIER%" ^
  "-DgeneratePom=false"

rem 4. install javadoc jar file

call mvn install:install-file ^
  "-Dfile=target/%ARTIFACT_ID%-%VERSION%-%JAVADOC_CLASSIFIER%.jar" ^
  "-DgroupId=%GROUP_ID%" ^
  "-DartifactId=%ARTIFACT_ID%" ^
  "-Dversion=%VERSION%" ^
  "-Dpackaging=jar" ^
  "-Dclassifier=%JAVADOC_CLASSIFIER%" ^
  "-DgeneratePom=false"


You also can run these commands as Beanshell script:


// installSourcesJavadocs.bsh

import org.sf.pomreader.PomReader;
import org.apache.maven.bootstrap.model.Model;
import org.sf.scriptlandia.MavenHelper;

MavenHelper.executeMaven(null, new String[] { "source:jar" });
MavenHelper.executeMaven(null, new String[] { "javadoc:jar" });

PomReader pomReader = new PomReader();
pomReader.init();

Model model = pomReader.readModel(new File("pom.xml"));

void installArtifact(Model model, String classifier) {
  System.setProperty("file", "target/" + model.getArtifactId() + "-" + classifier + ".jar");
  System.setProperty("groupId", model.getGroupId());
  System.setProperty("artifactId", model.getArtifactId());
  System.setProperty("version", model.getVersion());
  System.setProperty("packaging", model.getPackaging());
  System.setProperty("classifier", classifier);
  System.setProperty("generatePom", "false");

  MavenHelper.executeMaven(null, new String[] { "install:install-file" });
}

installArtifact(model, "sources");
installArtifact(model, "javadoc");


In order to run this script, you have to install Scriptlandia
launcher on your computer. It will take care of downloading all required dependencies, installing them locally on your computer and then executing Beanshell script.

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.