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.

Friday, June 02, 2006

How to handle JSP Error Page

At first glance it looks like a very straightforward task.


1. Each JSP page should use "errorPage" attribute. For example:

<%-- /example.jsp --%>

<%@ page errorPage="/WEB-INF/templates/errorPage.jsp"%>

<%-- some JSP content --%>


If you don't want to repeat this for each JSP page, use Tiles template or specify error page in "web.xml" file:

<web-app>
  ...
 
  <error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/WEB-INF/templates/errorPage.jsp</location>
  </error-page>

  ...
 
</web-app>



This description registers "errorPage.jsp" JSP page as error page for all JSP pages within web application.


2. You need to create error page, which displays runtime exceptions:

<%-- /WEB-INF/templates/errorPage.jsp --%>

<%@ page isErrorPage="true" %>

<%
  out.println("Exception: " + exception);
%>



By using "isErrorPage" attribute you declare this JSP page as error page. As a result, you have access to "exception" JSP variable (in addition to regular "application", "session",
"request", etc.).


This is basic. The problem happened, when your JSP page generates big output (bigger than page buffer) before the exception. In this case your error page will be appended to the current content instead of displaying in the new page.

To overcome the problem you can:


3.A. Play with "buffer" attribute. Say, you know, that the size of your page will never be more than 1MB. In this case add these attributes to the page:


<%-- /example2.jsp --%>

<%@ page errorPage="/WEB-INF/templates/errorPage.jsp"%>

<%@ page buffer="1024kb"%>
<%@ page autoFlush="false"%>

<%-- some JSP content --%>


This approach is not perfect, because you cannot guarantee the maximum page size. Another drawback is that page will be refreshed only after completing the operation. This could hurt user's perception.


3.B.1. Use custom javascript code to clear flushed already output. By using "document.getElementById()" function we canget reference to the body and rewrite it:


<%-- /WEB-INF/templates/errorPage.jsp, ver.1 --%>

<%@ page isErrorPage="true" %>

<html>
  <head>
    <script type="text/javascript">
      function newPage() {
        var exception = '<%= exception %>';

        var body = document.getElementById("body");

        body.innerHTML =
            "<html>" +
            " <body>" +
            " Exception: " + exception +
            " </body>" +
            "</html>";
        }
      }
    </script>
  </head>

  <body/>

</html>


This solution fits for simple error pages only. If you want to display full-featured error page, you have to look for another solution (see 3.B.2).



3.B.2. Redirect to another page.


This scenario is based on 3.B.1 solution. Now, instead of preparing the content to display, we'll submit the form, redirecting the flow to the requested page. In order to get the reference to javascript's "document" obect and clear it, we'll use document.open()" function:


<%-- /WEB-INF/templates/errorPage.jsp, ver.2 --%>

<%@ page isErrorPage="true" %>

<%
  // We want to have exception available on the redirected page.
  session.setAttribute("javax.servlet.error.exception",
                        request.getAttribute("javax.servlet.error.exception"));
%>

<html>
  <head>
    <script type="text/javascript">
      function newPage(action) {
        var newDoc = document.open("text/html", true);

        if(newDoc) {
          var errorFormName = 'errorForm';
          var txt =
            "<html>" +
            " <body>" +
            " <form id='" + errorFormName + "' method='get'/>" +
            " </body>" +
            "</html>";

          newDoc.write(txt);
          newDoc.close();

          var form = newDoc.getElementById(errorFormName);
          form.action = action;
          form.submit();

          return true;
        }

        return false;
      }

      newPage("someURL"); // direct execution of javascript custom function
    </script>
  </head>

  <body/>

</html>


This solution does not work properly yet. The problem is, that at the time of javascript execution the html page is not completely generated yet. As the result, "document.open()" call will return "null" object and the conten for the redirection will not be generated. See 3.B.3 for the solution.


3.B.3. Using timer object.


This scenario is based on 3.B.2 solution. It is exactly the same, the only difference is how we call "newPage()" function. Instead of direct call we'll do it indirectly from the timer:

<%-- /WEB-INF/templates/errorPage.jsp, ver.3 --%>

<%@ page isErrorPage="true" %>

<%
  // We want to have exception available on the redirected page.
  session.setAttribute("javax.servlet.error.exception",
                        request.getAttribute("javax.servlet.error.exception"));
%>

<html>
  <head>
    <script type="text/javascript">
      function newPage(action) { ... }

      var timer = new Timer("timer");
      timer.setScript("newPage('someURL')");

      timer.start();
    </script>
  </head>

  <body/>

</html>


Timer is the special custom javascript class that performs call to a given script periodically until the script returns "true" value. After this, the timer will stop execution.

You can download inplementation for the timer from here:

http://home.comcast.net/~shvets/blog/timer.js

Now JSP error page work properly.

Wednesday, May 24, 2006

Search Engine for Maven 2 (and other Java artifacts) from SourceLabs.

CJAR is the combination of Maven2 structured repository of Java artifacts with powerful Lucene based search engine and related tools.

Tuesday, May 23, 2006

CafeBabe bytecode editor v.1.4 - welcome back!

This is my very old project - I started it probably in 1997-1998.

By using CafeBabe you can view/edit the content of Java bytecodes. Also it understands the format of serialized files. Initially the project had some oprimization/obfuscation tools. I removed them in favor of simplicity.

Project contains libraries that can be used separately:

* classfile - parsing of Java class file;
* serfile - parsing of Java *.ser file;
* MDI - represents Multi Document Interface implementation;
* Net Lib - library for working with sockets (similar to servlet API, but not attached to any container).

Project is well modularized and uses Maven 2 as the build (...) tool.

Scriptlandia 2.1.0 has been released.

Latest update of the Scriptlandia scripting environment, version 2.1.0.

It includes support for such extensions as *.jad, *cwd (classworld file), *.class, *.apt-jelly, *.apt-fmt.

The library of examples has new examples to show what this environment can do.

Friday, May 19, 2006

How to use Ant, Maven2 and Scripting Languages together

I have used Ant tool to organize build process for a long period of time. It's pretty convenient and helps you to organize a lot of useful actions around compilation, packaging, deployment etc.

After some period of time I found that it is very convenient to use "script" task to extend basic functionality of Ant tool or dynamically customize it. For example, Javascript or Beanshell scripting languages are perfect selection for doing this.

The only one thing that Ant doesn't take care of is the project dependency resolution for libraries used within your project. Maven tool is especially designed to solve this problem.

As the result, the following architecture could cover all or the most of possible scenarios for describing build process: Ant + Maven + Some Scripting Language (Beanshell, Javascript, Groovy etc.)

Let me introduce basic steps that help you to solve the problem.


1. Ant tool should be aware of Maven. In order to achieve this, download "Maven Tasks for Ant library" (e.g. maven-artifact-ant-2.x.x-dep.jar) and install it into ${ant.home}/lib directory.


2. Once Maven Tasks for Ant are installed, we can start using them (in project.xml). First of all, describe the namespace for maven tasks:


<project name="myProject" default="run" basedir="."
         xmlns:artifact="antlib:org.apache.maven.artifact.ant">



3. Specify the location of your local Maven repository ("${repository.home}"). Usually it is ${user.home}/.m2, but you can choose any other location. Maven will download dependent libraries and save them inside this repository:

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

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



4. Load the Maven project file and assign some id for the project:


  <artifact:pom file="pom.xml" id="maven.project" />


5. Export various classpath variables from the Maven. In the following example we have access to compile-time, run-time and test-time classpath variables:


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

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

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

  </target>



6. Now you can use Ant tasks/targets the same way as before. You don't need to build classpath manually, it will be built dynamically based on the information from "pom.xml" maven file.

You also should be aware of some commonly used properties inside Maven. For example:


${maven.project.build.sourceDirectory} -> src/main/java
${maven.project.build.directory} -> target
${maven.project.build.outputDirectory} -> target/classes
${maven.project.name} - the project name



You can find out other properties here: http://maven.apache.org/maven-model/maven.html.

Let's create basic Ant targets, like clean-compile-jar-run:


  <property name="jar.file" value="${maven.project.build.directory}/${maven.project.name}.jar"/>

  <target name="clean" description="Removes all compiled classes">
    <delete dir="${maven.project.build.directory}"/>
  </target>

   <target name="compile" depends="resolve.dependencies" description="Compiles java sources">
    <mkdir dir="${maven.project.build.outputDirectory}"/>

    <javac destdir="${maven.project.build.outputDirectory}"
           includeAntRuntime="false"
           debug="${debug}"
           optimize="${optimize}"
           deprecation ="${deprecation}">
        <classpath refid="compile.classpath"/>
        <src path="${maven.project.build.sourceDirectory}"/>
    </javac>
  </target>

  <target name="jar" depends="compile" description="Prepare packaging for the project">
    <jar destfile="${jar.file}">
      <fileset dir="${maven.project.build.outputDirectory}"/>
    </jar>
  </target>

  <target name="run" depends="jar">
    <java jar="${jar.file}" fork="true" failonerror="true" maxmemory="128m">
      <classpath>
        <path refid="runtime.classpath"/>
        <pathelement location="${jar.file}""/>
      </classpath>
     </java>
  </target>

  <target name="run.script">
    <script language="beanshell">
      print("Hello, World!");
    </script>
  </target>



7. Your dependencies for the project are expressed in the form of "pom.xml" maven file:

<project>
  <modelVersion>4.0.0</modelVersion>

  <groupId>your.group.id</groupId>
  <artifactId>your.artifact.id</artifactId>
  <version>your.version</version>

  <name>YourName</name>

  <!-- Here you have to describe all your dependencies. -->
  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
    </dependency>

    ...
  </dependencies>

  </repositories>

</project>


By using this approach we can build scripts of any level of complexity without introducing Java compilation at all. Such programs will contain light-weight code, related to implementation only. All heavy-weight parts of the program will be conveniently located in the repository.

Saturday, May 13, 2006

How to make JavaEE project with Maven2

You want to support multiple modules in your project. Suppose you plan to have these modules:

- Java Module (one or more);
- EJB Module (dependent on Java Module);
- WEB Application Module (dependent on Java and EJB Modules);
- Enterprise Application Module (dependent on Java, EJB and Web Application Module).

First of all, you have to create multi-module project. It is special type of maven project - it does not produce any artifact. Its main purpose is to host modules - single maven projects - and to perform group operations for all modules.

Each single maven project should be aware of parent project. The same is true for parent maven project - it has to be aware about all the children.

The following steps describe whole process of creating such a project.

1. Create multi-project with the following directory structure:

myMultiProject
    myJavaModule1
    myJavaModule2
    ...

    myEJBModule1
    myEJBModule2
    ...

    myWebApplicationModule1
    myWebApplicationModule2
    ...

    myEnterpriseApplicationModule


2. Create maven project "pom.xml" files inside parent directory and inside each child project. Each "pom.xml" file contains specific to given project information.

myMultiProject
    myJavaModule1
        pom.xml
    myJavaModule2
        pom.xml
    ...

    myEJBModule1
        pom.xml
    myEJBModule2
        pom.xml
    ...

    myWebApplicationModule1
        pom.xml
    myWebApplicationModule2
        pom.xml
    ...

    myEnterpriseApplicationModule
        pom.xml

    pom.xml


You can auto-generate "pom.xml" files by using special "archetype:create" command. Only these archetypes are supported now: "quickstart", "webapp", "site", "mojo" and "marmalade-mojo". For our process we can use only 2 first archetypes.

Run these commands:

- for parent multi-project (in the directory where you plan to hst whole project):

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId -DartifactId=myMultiProjectArtifactId -DpackageName= -Dversion=1.0

This command creates the directory with the name specified as artifactId: "myMultiProjectArtifactId". You have to change "packaging" value from "jar" to "pom" inside "pom.xml".

You have to change current directory to "myMultiProjectArtifactId" before running all following commands.

- for Java Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myJavaModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myJavaModule1" with minimal set of directories/files for "quickstart" archetype.

- for EJB Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myEJBModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myJavaModule" with minimal set of directories/files for "quickstart" archetype.

- for Web Application Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myWebApplicationModule1 -DpackageName=my.new.package -Dversion=1.0

This command creates "myWebApplicationModule1" with minimal set of directories/files for "webapp" archetype.

- for Enterprise Application Module:

>mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=myMultiProjectGroupId.myMultiProjectArtifactId -DartifactId=myEnterpriseApplicationModule -DpackageName=my.new.package -Dversion=1.0

This command creates "myEnterpriseApplicationModule" with minimal set of directories/files for "quickstart" archetype.

As you can see, for Java, EJB, Enterprise Application Modules and Multi-Project we use "quickstart" archetype and for Web Application - "webapp" archetype.

The cyclic dependency between parent and children projects should be expressed in the following way: for parent project we have to use "modules" tag, for children projects - "parent" tag.

Parent project's structure looks like this:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Specify group ID, artifact ID and version for the parent project. -->
  <groupId>myMultiProjectGroupId</groupId>
  <artifactId>myMultiProjectArtifactId</artifactId>
  <version>myMultiProjectVersion</version>

  <!-- 2. Specify "pom" type. This type indicates that this project is parent multi-project. -->
  <packaging>pom</packaging>

  <!-- 3. List all children projects names (name is directory name as well). -->
  <modules>
    <module>myJavaModule1</module>
    <module>myJavaModule2</module>
    ...
    <module>myEJBModule1</module>
    <module>myEJBModule2</module>
    ...
    <module>myWebApplicationModule1</module>
    <module>myWebApplicationModule2</module>
    ...
    <module>myEnterpriseApplicationModule</module>
  </modules>

</project>


Child project's structure looks like this:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Specify group ID, artifact ID and version for child project. -->
  <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
  <artifactId>myJavaArtifactId</artifactId>
  <version>myJavaModuleVersion</version>

  <!-- 2. Specify the type of the project:
           "jar", "war", "ear". "ejb", "ejb3", "rar", "par", "pom", "maven-plugin" -->

  <packaging>jar</packaging>

  <!-- 3. Specify parameters and the location of the parent project. -->
  <parent>
    <groupId>myMultiProjectGroupId</groupId>
    <artifactId>myMultiProjectArtifactId</artifactId>
    <version>myMultiProjectVersion</version>
    <relativePath>../pom.xml</relativePath>
  </parent>
</project>



3. Java Module


Below is typical "pom.xml" content for Java Module:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>jar</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    ...
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myJavaModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../src/java</sourceDirectory>

    <!-- 4.3. Specify the location of the filter file (if filtering is used). -->
    <filters>
      <filter>target/filter.properties</filter>
    </filters>

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/resources</directory>
        <filtering>true</filtering>
        <excludes>
          <exclude>*web*.xml</exclude>
        </excludes>
      </resource>
    </resources>

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

          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            <include>**/com/**</include>
          </includes>

          <!-- 4.7. Specify files to exclude (if required). -->
          <excludes>
            <exclude>com/sun/**/*.java</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


4. EJB Module

EJB Nodule is dependent on Java Module:

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>ejb</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    <!-- 3.1. Specify dependencies on external libraries. -->
    ...

    <!-- 3.2. Specify dependencies on EJB libraries. -->
    <dependency>
      <groupId>javax.ejb</groupId>
      <artifactId>ejb</artifactId>
      <version>2.1</version>

      <!-- 3.2.1. This library is provided by EJB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.3. Specify dependencies on internal libraries. -->
    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myJavaModule1ArtifactId</artifactId>
      <artifactId>myJavaModuleVersion</artifactId>

      <!-- 3.3.1. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myEJBModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (if you have non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../../src/java</sourceDirectory>

    <!-- 4.3. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/java/META-INF</directory>
        <targetPath>META-INF</targetPath>
        <filtering>false</filtering>
        <excludes>
          <exclude>*application*.xml</exclude>
        </excludes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            <include>**/ejb/**</include>
          </includes>

          <!-- 4.7. Nothing to exclude. -->
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>



5. WEB Application Module

Web Application Module is dependent on Java and EJB Modules.

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>war</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another libraries, projects etc. -->
  <dependencies>
    <!-- 3.1. Specify dependencies on external libraries. -->
    ...

    <!-- 3.2. Specify dependency on servlet API library. -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.4</version>

      <!-- 3.2.1. This library is provided by Web Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.3. Specify dependency on JSP API library (if required). -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>

      <!-- 3.3.1. This library is provided by WEB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.4. Specify dependency on other web libraries: tags, struts, tiles etc... (if required). -->
    ...

    <!-- 3.5. Specify dependency on database driver (if required). -->
    <dependency>
      <groupId>oracle</groupId>
      <artifactId>oracle-driver</artifactId>
      <version>9.2.0.5.0</version>
    </dependency>

    <!-- 3.6. Specify dependencies on EJB libraries (if required). -->
    <dependency>
      <groupId>javax.ejb</groupId>
      <artifactId>ejb</artifactId>
      <version>2.1</version>

      <!-- 3.6.1. This library is provided by EJB Container. -->
      <scope>provided</scope>
    </dependency>

    <!-- 3.7. Specify dependencies on internal libraries. -->
    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myJavaModule1ArtifactId</artifactId>
      <artifactId>myJavaModule1Version</artifactId>

      <!-- 3.7.1. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
      <artifactId>myEJBModule1ArtifactId</artifactId>
      <artifactId>myEJBModule1Version</artifactId>

      <!-- 3.7.2. This library is required at runtime. -->
      <scope>runtime</scope>
    </dependency>

  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myWebApplicationModule1FinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. Specify the location of sources (if you have non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/java -->
    <sourceDirectory>../src/java</sourceDirectory>

    <!-- 4.3. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.4. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${basedir}/src/main/resources -->
    <resources>
      <resource>
        <directory>../src/config</directory>
        <filtering>false</filtering>
        <includes>
          <include>*.properties</include>
        </includes>
      </resource>

      <resource>
        <directory>../src/resources</directory>
        <filtering>false</filtering>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 4.5. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>

          <!-- 4.6. Specify files to include. -->
          <includes>
            ...
          </includes>

          <!-- 4.7. Specify files to exclude (if required). -->
          <excludes>
            ...
          </excludes>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <!-- 4.8. Specify the location of Web Application directory (if non-standard). -->
          <!-- Defailt is: ${basedir}/src/main/webapp -->
          <warSourceDirectory>../src/web</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>


6. Enterprise Application Module

This module performs main assembly work plus adds some application-level resources, like "application.xml" file. You have to list all the modules to be included into "ear" file in "dependencies" section. Each module should be marked with the corresponding type: "jar", "war", "ejb", "ejb3", "ejb-client", "rar", "par", "sar".

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Current project description. -->
   ...
  <packaging>ear</packaging>

  <!-- 2. Reference to parent project. -->
   ...

  <!-- 3. Dependencies on another modules within the multi-module project. -->
  <dependencies>
    <dependency>
      <!-- 3.1. Dependency on Java Module. -->
      ...
      <type>jar</type>

      <!-- 3.2. We need to include this module into application.xml; required by EJB module. -->
      <includeInApplicationXml>true</includeInApplicationXml>
    </dependency>

    <dependency>
      <!-- 3.3. Dependency on EJB Module. -->
      ...
      <type>ejb</type>
    </dependency>

    <dependency>
      <!-- 3.4. Dependency on Web Application Module. -->
      <type>war</type>
    </dependency>
  </dependencies>

  <!-- 4. Specify the content of generated artifact. -->
  <build>

    <!-- 4.1. Specify the final name of the artifact. -->
    <finalName>myEnterpriseApplicationModuleFinalName</finalName>

    <defaultGoal>package</defaultGoal>

    <!-- 4.2. We don't want to filter for this module: "filters" section is empty. -->

    <!-- 4.3. Specify the location of resources (for non-standard location). -->
    <!-- Defailt is: ${project.build.outputDirectory} -->
    <!-- The file: application.xml will be automatically generated. -->
    <resources>
      <resource>
        <directory>../src/java/META-INF</directory>
        <targetPath>META-INF</targetPath>
        <filtering>false</filtering>
        <includes>
          <include>weblogic-application.xml</include>
        </includes>
      </resource>
    </resources>

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

        <!-- 4.4. Specify used Java version. -->
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <configuration>

          <!-- 4.5. Specify modules to include. -->
          <modules>

            <!-- 4.5.1. Include Java Module. -->
            <javaModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myJavaModule1ArtifactId</artifactId>
              <artifactId>myJavaModule1Version</artifactId>

              <!-- 4.5.1.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleJavaModule1FileName</bundleFileName>
            </javaModule>

            <!-- 4.5.2. Include EJB Module. -->
            <ejbModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myEJBModule1ArtifactId</artifactId>
              <artifactId>myEJBModule1Version</artifactId>

              <!-- 4.5.2.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleEJBModule1FileName</bundleFileName>
            </ejbModule>

            <!-- 4.5.3. Include Web Application Module. -->
            <webModule>
              <groupId>myMultiProjectGroupId.myMultiProjectArtifactId</groupId>
              <artifactId>myWebApplicationModule1ArtifactId</artifactId>
              <artifactId>myWebApplicationModule1Version</artifactId>

              <!-- 4.5.3.1. Only if you want different file name inside "ear" file. -->
              <bundleFileName>myBundleWebApplicationModule1FileName</bundleFileName>

              <!-- 4.5.3.2. Specify the context root if you need different name. -->
              <!-- Default is: "/${pom.artifactId} -->
              <contextRoot>iris</contextRoot>
            </webModule>

            <!-- 4.5.4. Maven will also treat dependent 3-rd-party libraries as modules.
                        You have to exclude them or redirect to "APP-INF/lib" directory. -->
            <javaModule>
              <groupId>antlr</groupId>
              <artifactId>antlr</artifactId>
              <bundleDir>APP-INF/lib</bundleDir>
            </javaModule>
            ...

          </modules>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>



7. Parent multi-project

Parent project can be used as convenient way to execute group commands, When you run particular command on the project, it executes this command for all children projects. Maven is able to discover the correct execution order and to detect circular dependencies.

<project>
  <modelVersion>4.0.0</modelVersion>

  <!-- 1. Parent multi-project description. -->
   ...
  <packaging>pom</packaging>

  <!-- 2. Chlidren modules description. -->
  <modules>
    ...
  </modules>

  <build>
    <defaultGoal>package</defaultGoal>
   
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <!-- 3. Specify used Java version. -->
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>

    </plugins>
  </build>

</project>



8. Usage

Now you can execute group commands, for example:

>mvn compile
>mvn install
>mvn site


These commands perform operations for each module sequentially.

Monday, May 01, 2006

How to make JavaME project with Ant

I prepared Ant script that can be used for the most of Java ME projects. It encapsulates all low-level detail dealing with tools/callses from Java ME platform.

1. Specify project name and default target:

<project name="MyFirstMidlet" default="compile" basedir=".">


2. Define useful properties that will be used throughout the project:

  <property name="java.mobile.home" value="c:/Java/j2me-2.3"/>

  <property name="midlet.class.name" value="${ant.project.name}"/>
  <property name="src.dir" value="src"/>
  <property name="target.dir" value="target"/>

  <property name="midlet.command.line" value=""/>



3. Specify the classpath that includes core mobile API and required extension APIs, e.g.:

  <path id="mobile.classpath">
    <pathelement location="${java.mobile.home}/lib/cldcapi11.jar"/>
    <pathelement location="${java.mobile.home}/lib/midpapi20.jar"/>

    <pathelement location="${java.mobile.home}/lib/wma20.jar"/>
    <pathelement location="${java.mobile.home}/lib/mmapi.jar"/>
    <pathelement location="${java.mobile.home}/lib/j2me-ws.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr75.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr082.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr184.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr179.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr177.jar"/>
    <pathelement location="${java.mobile.home}/lib/jsr211.jar"/>
  </path>


4. We need to create string version of our classpath. It will be used for executables, like "preverified.exe" and "emulator.exe":

    <property name="mobile.classpath" refid="mobile.classpath"/>

5. Prepare "compile" target. Keep in mind that target attribute should be on "1.1" level:

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

    <javac srcdir="${src.dir}" destdir="${target.dir}/classes"
           bootclasspathref="mobile.classpath"
           source="1.1" target="1.1"/>

  </target>


6. Compiled classes should be "preverified". It means that each class file in "classes" directory will have corresponding "preverified" class file in "preverified" directory.

  <target name="preverify" depends="compile">
    <mkdir dir="${target.dir}/preverified"/>

    <exec executable="${java.mobile.home}/bin/preverify">
      <arg line="-classpath ${mobile.classpath}"/>
      <arg line="-d ${target.dir}/preverified"/>
      <arg line="${target.dir}/classes"/>
    </exec>
  </target>


7. Resulting jar file will contain "preverified" classes and resources from "res"
directory:

  <target name="jar" depends="preverify">
    <mkdir dir="${target.dir}/bin"/>

    <jar basedir="${target.dir}/preverified"
         jarfile="${target.dir}/bin/${ant.project.name}.jar"
         manifest="bin/MANIFEST.MF">
      <fileset dir="res"/>
    </jar>

    <copy file="bin/${ant.project.name}.jad"
          tofile="${target.dir}/bin/${ant.project.name}.jad"/>

  </target>



8. In order to run generated artifact you have to launch the emulator. You can run
emulator as executable file or as java class.

- as executable:

  <target name="run2" depends="jar">
    <exec executable="${java.mobile.home}/bin/emulator">
      <!-- device: DefaultColorPhone, DefaultGrayPhone, MediaControlSkin, QwertyDevice -->
      <arg line="-Xdevice:DefaultColorPhone"/>
      <arg line="-Xdescriptor:${basedir}/${target.dir}/bin/${ant.project.name}.jad"/>

      <arg line="-classpath ${mobile.classpath};${basedir}/${target.dir}/bin/${ant.project.name}.jar"/>
    </exec>
  </target>


- as java class:

  <target name="run" depends="jar">
    <java fork="yes" classname="com.sun.kvem.environment.EmulatorWrapper">
      <sysproperty key="kvem.home" value="${java.mobile.home}"/>
      <sysproperty key="java.library.path" value="${java.mobile.home}/bin"/>
      <sysproperty key="sun.java2d.ddlock" value="true"/>
      <sysproperty key="sun.java2d.gdiblit" value="false"/>

      <arg line="-Xdevice:DefaultGrayPhone"/>
      <arg line="-Xdescriptor:${basedir}/${target.dir}/bin/${ant.project.name}.jad"/>

      <arg line="-classpath ${mobile.classpath};${target.dir}/bin/${ant.project.name}.jar"/>
      <arg line="${midlet.class.name}"/>
      <arg line="${midlet.command.line}"/>
      <arg line="0"/>
    </java>
  </target>

Wednesday, April 26, 2006

How to generate checksum files for Maven 2 repository

Sometimes you want to add libraries to your Maven 2 repository manually.
This tool will help you to generate checksum files recursively, starting from current directory.

Tool is located here.

You can use Scriptlangia in order to simplify launching of this tool.

Tuesday, April 25, 2006

Beanshell plugin for maven2

Plugin for running beanshell scripts in the same way as maven-antrun-plugin does. Based on the source from maven-antrun-plugin plugin.

Source code is located here: maven-beanshell-plugin.

in order to use the plugin you have to add new repository to the list of your repositories:

<repositories>
  ...
  <repository>
    <id>scriptlandia-maven2</id>
    <name>scriptlandia-maven2</name>
    <url>http://scriptlandia.sourceforge.net/maven2</url>
  </repository>
</repositories>


Then, configure the plugin:

<build>
  ...
  <plugins>
    <plugin>
      <groupId>org.apache.maven</groupId>
        <artifactId>maven-beanshell-plugin</artifactId>

      <executions>
        <execution>
          <id>validate</id>
          <phase>validate</phase>
          <configuration>
            <source>test.bsh</source>
            <!--content>print("Hello, World!");</content-->
          </configuration>
          <goals>
            <goal>run</goal>
          </goals>
          </execution>
      </executions>
    </plugin>
  </plugins>
</build>

New maven2 book (free, pre-release): Better Builds with Maven

Saturday, April 22, 2006

Scriptlandia Project Home Page

Welcome to the Scriptlandia World!

I started this project two years ago (Antlets). The idea was to simplify running various scripts written in scripting languages (Beanshell, Groovy, Jelly etc.) for JVM under Windows and Unix environment.

We have a plenty of scripting engines, each has the launcher/starter program. In order to run the script, you have to remember the name of the launcher program. In case if you need to add new libraries to your script, it's not so easy. If you want to have scripts in different languages to be aware of each other, it's even more difficult.

Scriptlandia is built in top of ClassWorlds framework, a convenient way of solving classloader problems in one unified way. Your batch/shell scripts will become as simple as possible and addition of new libraries will happen outside of them.

By the size this project is very small (~70K). It uses Maven2 as the delivery mechanizm to download all required parts. It has to deliver libraries for running Beanshell, Groovy etc. from Maven2 repositories.

After installing the Scriptlandia you will be able to launch beanshell, groovy, jelly, velocity scripts in one click. You can do the same for jar files. If jar file is written for Java Micro Edition, the system will recognize it and the file will be started in mobile phone emulator. See examples archive for more details. This file: README.txt contains complete description of the project.

Princeton JUG site

Tuesday, April 04, 2006

How to pre-compile JSP pages for Tomcat with Ant

JSP pre-compilation is very important part of the build process. Even if you don't want to use pre-compiled pages in your production environment (it's for specific application server (AS) only), it can guarantee the integrity of your source.

With regular approach you make changes to JSP pages, then copy/deploy them to AS and only at this time possible error will be discovered. In contrast, JSP pre-compilation will give you this knowledge at compile time.


How to do the pre-compilation? I will explain it with the help of Ant build tool.


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 "tomcat.jsp.classpath". You need to have Tomcat Web Server installed somewhere. For this example I use tomcat, embedded into JBoss Application Server ("${jboss.home}").

You also need to specify where you have your implementation of logging system
("${repository.home}/log4j").


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

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

<path refid="project.classpath"/>

<!-- 2. Tomcat jsp compiler (jasper) by itself. -->

<fileset dir="${jboss.home}/server/default/deploy/jbossweb-tomcat55.sar">
<include name ="jasper-compiler.jar"/>
<include name ="jasper-compiler-jdt.jar"/>
<include name ="jasper-runtime.jar"/>
<include name ="commons-logging.jar"/>
<include name ="commons-el.jar"/>
<include name ="jsp-api.jar"/>
</fileset>

<!-- 3. This library is required by jasper. -->

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

<!-- 4. JavaEE/Servlet/JSP interface classes. -->

<fileset dir="${jboss.home}/server/default/lib">
<include name ="jboss-j2ee.jar"/>
<include name ="javax.servlet.jar"/>
<include name ="javax.servlet.jsp.jar"/>
</fileset>

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

<fileset dir="${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>


4. After the generation of Java classes from JSPs, we need to compile them. The "depend" task is responsible for "smart" recompilation of JSP-Java files.


<target name="tomcat.jsp.compile" depends="tomcat.jsp.generate"
description="Generates java classes from jsp files, then compiles them">
<depend srcdir="${jsp.src.dir}"
destdir="${jsp.classes.dir}"
cache="${build.dir}"
closure="true">
<classpath refid="tomcat.jsp.classpath"/>
</depend>

<javac destdir="${jsp.classes.dir}" debug="off" optimize="false">
<classpath refid="tomcat.jsp.classpath"/>

<src path="${jsp.generated.src.dir}"/>
<include name ="com/**/*.java"/>
</javac>
</target>


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

Friday, March 31, 2006

Blog's birthday,

At the beginning it was a word. Then the blog was born...