»
November 26, 2009
»

Attaching Artifacts to Maven Project in Mojo

While writing a GWT & AppEngine plugin for Maven I came across the Maven concept of “attached” artifacts. While project in Maven can have one “main” artifact, it also can have unlimited count of “attached” artifacts like sources or javadoc. For GWT compile mojo I wanted to attach gwt artifact what would be jar with compiled GWT module(s). This artifact then could be dependency for war project (module) and unpacked in appropriate folder in package phase.

So, to create a jar and attach it as a attached artifact to maven project:

public class DirectoryArtifactService {

  private final Log log;
  private final ArchiverManager archiverManager;
  private final MavenProjectHelper mavenProjectHelper;
  private final MavenProject mavenProject;

  public DirectoryArtifactService(Log log, ArchiverManager archiverManager, 
      MavenProjectHelper mavenProjectHelper, MavenProject mavenProject) {
    this.log = log;
    this.archiverManager = archiverManager;
    this.mavenProjectHelper = mavenProjectHelper;
    this.mavenProject = mavenProject;
  }

  public File attachDirectoryArchive(String finalName, String classifier, 
      File outputDirectory, File moduleDirectory) throws MojoExecutionException {
    String type = "jar";
    File output = new File(outputDirectory, 
      format("%s-%s.%s", finalName, classifier, type));
    createArchive(output, moduleDirectory);
    attachArchive(output, type, classifier);
    return output;
  }

  private void createArchive(File output, File directory) throws MojoExecutionException {
    try {
      log.info("Creating archive " + output + " from " + directory);
      Archiver archiver = archiverManager.getArchiver(output);
      archiver.setDestFile(output);
      archiver.addDirectory(directory);
      archiver.createArchive();
    } catch (NoSuchArchiverException e) {
      throw new MojoExecutionException("Failed to create archive " + output, e);
    } catch (ArchiverException e) {
      throw new MojoExecutionException("Failed to create archive " + output, e);
    } catch (IOException e) {
      throw new MojoExecutionException("Failed to create archive " + output, e);
    }
  }

  private void attachArchive(File output, String type, String classifier) {
    mavenProjectHelper.attachArtifact(mavenProject, type, classifier, output);
  }

}

Where ArchiverManager is plexus-archiver:

<dependency>
  <groupId>org.codehaus.plexus</groupId>
  <artifactId>plexus-archiver</artifactId>
  <version>1.0-alpha-9</version>
</dependency>

And all dependencies are injected from plexus container in mojo:

/**
 * @component
 */
public ArchiverManager archiverManager;

/**
 * @component
 */
public MavenProjectHelper mavenProjectHelper;

/**
 * @parameter default-value="${project}"
 */
public MavenProject mavenProject;

public DirectoryArtifactService getDirectoryArtifactService() {
  return new DirectoryArtifactService(getLog(), archiverManager, mavenProjectHelper, 
    mavenProject);
}

After running mojo we can see that Maven also installs gwt artifact:

[INFO] [install:install {execution: default-install}]
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT.jar to                          ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT.jar
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT-gwt.jar to                      ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT-gwt.jar
[INFO] Installing app/app-gwt/target/app-gwt-1.0-SNAPSHOT-sources.jar to                  ↩
  ~/.m2/repository/com/app/app-gwt/1.0-SNAPSHOT/app-gwt-1.0-SNAPSHOT-sources.jar
November 11, 2009
»

Running a Separate Java Process from Maven Mojo

While digging in various existing Maven Mojos and looking for easiest way to run a separate java process from Maven Mojo, in exec-maven-plugin I’ve found reference to nice helper class from Plexus Common Utilities named Commandline.

So, to run java (or any other) process using CommandLine and CommandLineUtils classes:

import org.codehaus.plexus.util.cli.Commandline;

/**
 * @parameter expression="${java.home}"
 * @required
 */
protected File javaHome;

public void run() {
  Commandline cmd = new Commandline();
  cmd.setExecutable(getJavaExecutable().getAbsolutePath());
  cmd.setWorkingDirectory( ... );
  cmd.addArguments( ... );

  StreamConsumer stdout = ...
  int result = CommandLineUtils.executeCommandLine(cmd, stdout, stdout);
}

private File getJavaExecutable() {
  return new File(new File(javaHome, "bin"), "java");
}
<dependency>
  <groupId>org.codehaus.plexus</groupId>
  <artifactId>plexus-utils</artifactId>
  <version>1.5.15</version>
</dependency>

I’m not sure if it is the “Maven way” of getting path to java executable but it should work just fine in all Java-supported OS’es.

November 08, 2009
»

Publishing Maven Artifacts

While mvn install publishes artifact to local ~/.m2/repository there is certainly good rationale to create a remote “company” maven repository (either using cool tools like nexus or with just simple HTTP server) to share built artifacts.

If you’re like me — just starting with Maven, plain old HTTP will be fine and when repository is ready (when mkdir /var/www/repository has done it’s job) then the next question is how to publish artifacts.

There are 2 ways (I’m aware of) to get built artifacts in repository:

  • maven-release-plugin
  • maven-deploy-plugin

Before diving in both of them pom.xml needs a tweaks.

Settings

Maven needs to know where your repository is. We need to add distributionManagement element:

<distributionManagement>
  <repository>
    <id>company-repository</id>
    <name>company m2 repository</name>
    <url>scp://deploy@company.server.com/var/www/repository</url>
  </repository>
</distributionManagement>

Example uses scp, few other protocols are supported.

And for maven-release-plugin we also need scm settings in place:

<scm>
  <connection>scm:hg:ssh://hg@company.server.com/hg/project</connection>
  <developerConnection>scm:hg:ssh://hg@company.server.com/hg/project</developerConnection>
</scm>

Deploy

Fine, lets deploy a SNAPSHOT release:

mvn clean deploy

This will clean, build and deploy artifact with current version (event if it is not marked as a SNAPSHOT). Note that it will also overwrite existing artifacts in repository if they exist.

Release

The release plugin is a lot smarter. The release process is divided in two steps — prepare and perform. Prepare works something like this (assuming artifactId is “zeeba”):

  • Updates current artifact version from 1.0-SNAPSHOT to 1.0
  • Creates a tag zeeba-1.0
  • Updates the version from 1.0 to 1.1-SNAPSHOT

After each of those tasks release:prepare also commits and pushes the change to scm. So after single release:prepare you’ll get 3 change-sets in scm

The perform side of the plugin is cloning repository based on saved release scm tag name in release.properties, rebuilding (goal ‘deploy’) and finally performing the actual release. So if release:perform fails it can be safely retried until it succeeds.

mvn release:prepare
mvn release:perform

Note, this plugin requires project to currently have SNAPSHOT version.

publishing/sonatype_maven_book.jpeg And I can’t recommend more the Maven: The Definitive Guide.
It is really good getting started guide for newcomers to maven.
November 04, 2009
»

Creating Classpath From Compile Scope Elements in Maven Mojo

Lets suppose we have the pom with following (shortened) structure:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <groupId>com.ampatspell.skeleton</groupId>
  <artifactId>frontend</artifactId>
  <version>0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <dependencies>
    <dependency>
      <groupId>com.google.webtoolkit</groupId>
      <artifactId>gwt-user</artifactId>
      <version>${gwt-version}</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>com.google.webtoolkit</groupId>
      <artifactId>gwt-dev</artifactId>
      <version>${gwt-version}</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
  
  <build>
    <plugins>
      <plugin>
        <groupId>com.ampatspell.maven.plugins</groupId>
        <artifactId>something</artifactId>
        <version>1.0-SNAPSHOT</version>
      </plugin>
    </plugins>
  </build>

</project>

To create ClassPath from both dependencies and compiled project classes (what can be filtered out of course):

/**
 * The maven project.
 *
 * @parameter expression="${project}"
 * @required
 */
protected MavenProject project;

protected ClassLoader getClassLoader() throws FewNastyExceptions {
  synchronized (SomethingMojo.class) {
    if (classLoader != null)
      return classLoader;
  }
  synchronized (SomethingMojo.class) {
    List<URL> urls = new ArrayList<URL>();
    for (Object object : project.getCompileClasspathElements()) {
      String path = (String) object;
      urls.add(new File(path).toURL());
    }
    classLoader = new URLClassLoader(urls.toArray(new URL[] {}) /*, parentClassLoader */);
    // Thread.currentThread().setContextClassLoader(classLoader); // if needed
    return classLoader;
  }
}

This created ClassLoader includes:

  • target/classes/
  • ~/.m2/repository/[..]/gwt-user-2.0.0-ms2.jar
  • ~/.m2/repository/[..]/gwt-dev-2.0.0-ms2.jar

To get class from given ClassLoader:

protected Class<?> getClass(String className) {
  return getClassLoader().loadClass(className);
}
November 03, 2009
»

Publishing Files as Maven Artifacts

Interwebs are filled with information how to install files in local maven repository — just type mvn install:install-file, add few parameters and done. But it took some time for me to find information how to publish (actually to deploy) file in own repository. So here it is:

Deploy file

mvn deploy:deploy-file \
  -Durl=scp://user@server.com/path/to/repository
  -Dfile=gwt-user.jar \
  -DgroupId=com.google.webtoolkit \
  -DartifactId=gwt-user \
  -Dversion=2.0.0-ms2 \
  -Dpackaging=jar \
  -DgeneratePom=true

Using uploaded artifacts

Just add repository in pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <repositories>
    <repository>
      <id>amateurinmotion</id>
      <name>amateurinmotion m2 repository</name>
      <url>http://www.amateurinmotion.com/repository</url>
    </repository>
  </repositories>

</project>

More info

November 02, 2009
»

GWT.runAsync with GIN

GWT-2.0 has great new feature called Code Splitting what allows to split module in smaller compiled parts and request parts only when (if) they’re needed. But I’m using GIN to wire all internal application object graph (models, presenters, views, service classes) and of corse if it’s left as is (one Ginjector) no code is split.

So I came up with this simple “design pattern” to continue using GIN modules while taking advantage of code splitting:

  • Split monolithic GIN module in multiple modules
  • For each GIN/runAsync module create Loader interface and implementation with void load(LoaderCallback cb) method

Loader:

  • on first load creates GIN module
  • possibly injects module stylesheets
  • stores GIN injector instance in private static field
  • connects parent and new GIN modules together
  • calls LoaderCallback method

Example

In this example (live version is deployed on AppEngine) I have one “base” StoriesModule:

public class StoriesModule extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(EventBus.class).to(EventBusImpl.class);
    bind(EventBusListener.class).to(LoggingEventBusListener.class);
    
    bind(AdminLoader.class).to(AdminLoaderImpl.class);
  }

}

and AdminModule:

public class AdminModule extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(AdminPresenter.class).to(AdminPresenterImpl.class);
    bind(AdminView.class).to(AdminViewImpl.class);
  }

}

Pretty basic stuff.

But AdminModule needs EventBus instance from StoriesModule. To connect both modules add 2 new interfaces:

public interface SharedServices {

  EventBus getEventBus();

}
public interface SharedServicesAware {

  void setSharedServices(SharedServices services);

}

In “base” module add SharedServices provider:

@Provides
@Singleton
public SharedServices sharedServices(final EventBus eventBus) {
  return new SharedServices() {
    public EventBus getEventBus() {
      return eventBus;
    }
  };
}

In “child” module add class what implements both SharedServicesAware and Provider<SharedServices>:

@Singleton
public static class SharedServicesAdapter implements Provider<SharedServices>, SharedServicesAware {

  private SharedServices services;

  public void setSharedServices(SharedServices services) {
    this.services = services;
  }

  public SharedServices get() {
    return services;
  }

}

And now EventBus in “child” module can be bound using SharedServices like this:

@Provides
public EventBus eventBus(SharedServices sharedServices) {
  return sharedServices.getEventBus();
}

The last thing — Loader.

Child module loader should contain only one method load:

public interface AdminLoader {

  public interface AdminLoaderCallback {
    void onLoaded(AdminPresenter admin);
  }

  void load(AdminLoaderCallback callback);

}

Implementation:

@Singleton
public class AdminLoaderImpl implements AdminLoader {

  private static AdminInjector injector;
  private final SharedServices sharedServices;

  @Inject
  public AdminLoaderImpl(SharedServices sharedServices) {
    this.sharedServices = sharedServices;
  }

  public void load(final AdminLoaderCallback callback) {
    GWT.runAsync(AdminLoader.class, new RunAsyncCallback() {
      public void onSuccess() {
        if (injector == null) {
          onFirstLoad();
        }

        callback.onLoaded(injector.presenter());
      }

      private void onFirstLoad() {
        // Inject just loaded stylesheets
        StyleInjector.inject(AdminClientBundle.I.css().getText());

        // create Injector and connect both "worlds"
        injector = GWT.create(AdminInjector.class);
        injector.sharedServicesAware().setSharedServices(sharedServices);
      }

      public void onFailure(Throwable reason) {
        Window.alert("Failed to load admin presenter");
      }
    });
  }

}

Note I’m setting AdminInjector as static. It’s because AdminLoaderImpl can be bound in more than one Module. This ensures that only one AdminInjector instance is present in application.

SOYC

Initialy downloaded code contains only AdminLoader:

Initially downloaded code

All other code comes after the split point:

Admin module

Download example

September 07, 2009
»

Injecting JavaScript in GWT-2.0

GWT-2.0 comes with ClientBundle class what allows creating not only CssResources and ImageResources but also TextResources what can be used to store and later in runtime retrieve JavaScript code and inject in HTML. This cuts down requests to server and makes easier to reuse existing JavaScript libraries.

To “embed” JavaScript into the compiled GWT application we must create ClientBundle:

public interface DemoClientBundle extends ClientBundle {

  @Strict
  @Source("someJavascriptFile.js")
  TextResource demo();

}

Now we can get JavaScript text in runtime using:

DemoClientBundle bundle = GWT.create(DemoClientBundle.class);
String text = bundle.demo().getText();

To make browser to run this code we need to create <script/> element in <head/> of host page. While CssResource has StyleInjector helper class, there is no JavascriptInjector class in current GWT trunk. Anyway, it’s easy to create one:

public class JavascriptInjector {

  private static HeadElement head;

  public static void inject(String javascript) {
    HeadElement head = getHead();
    ScriptElement element = createScriptElement();
    element.setText(javascript);
    head.appendChild(element);
  }

  private static ScriptElement createScriptElement() {
    ScriptElement script = Document.get().createScriptElement();
    script.setAttribute("language", "javascript");
    return script;
  }

  private static HeadElement getHead() {
    if (head == null) {
      Element element = Document.get().getElementsByTagName("head").getItem(0);
      assert element != null : "HTML Head element required";
      HeadElement head = HeadElement.as(element);
      JavascriptInjector.head = head;
    }
    return JavascriptInjector.head;
  }

}

So full injection looks something like this:

DemoClientBundle bundle = GWT.create(DemoClientBundle.class);
JavascriptInjector.inject(bundle.demo().getText());
August 17, 2009
»

GWT-MooTools

Anouncing GWT-MooTools — a little and easy to use wrapper around MooTools animation classes for GWT.

Go to “Gwt-Mootools” project page

August 16, 2009
»

Running GWT-2.0 with App Engine (Mac OS X)

At least on trunk’s revision 5967 GWT HostedMode with AppEngineLauncher fails to start.

If you’re getting something like:

failed com.google.apphosting.utils.jetty.DevAppEngineWebAppContext@3225c9{/,.}
javax.xml.parsers.FactoryConfigurationError: Provider                                     ↩
  org.apache.xerces.jaxp.SAXParserFactoryImpl not found

Just add xercesImpl.jar to

/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/endorsed

You can get it from GWT build tools at tools/lib/xerces/xerces-2_9_1

July 15, 2009
»

GWT Commands - Spring Integration

I’ve created and uploaded to bitbucket a small test/sample GWT-Spring application what explores one of easiest ways to integrate GWT Command Pattern (See my previous blog entry) with Spring server back-end.

gwt-spring/screenshot.png

The app demonstrates integration with simple ServerInfoAction with ServerInfoResult and ServerInfoActionHandler:

public class ServerInfoAction implements Action<ServerInfoResult> {

  private boolean includeUserAgent;

  public ServerInfoAction() {
    ;
  }

  public ServerInfoAction(boolean includeUserAgent) {
    this.includeUserAgent = includeUserAgent;
  }

  public boolean isIncludeUserAgent() {
    return includeUserAgent;
  }

}
public class ServerInfoResult implements Result {

  private String serverInfo;
  private String userAgent;

  public String getServerInfo() {
    return serverInfo;
  }

  public String getUserAgent() {
    return userAgent;
  }

  public void setServerInfo(String serverInfo) {
    this.serverInfo = serverInfo;
  }

  public void setUserAgent(String userAgent) {
    this.userAgent = userAgent;
  }

}
public class ServerInfoActionHandler implements ActionHandler<ServerInfoAction,           ↩
    ServerInfoResult> {

  public ServerInfoResult execute(ServerInfoAction action) {
    ServerInfoResult res = new ServerInfoResult();

    res.setServerInfo(ActionDispatchContext.getServletcontext().getServerInfo());

    if (action.isIncludeUserAgent())
      res.setUserAgent(ActionDispatchContext.getRequest().getHeader("User-Agent"));

    return res;
  }

}

I’m not going to describe the command pattern itself. See GWT mailing list and in previous post mentioned Google I/O video for lots of details and better description than I could write. Instead I’ll step thru implementation details of Spring integration.

And let’s start with web.xml:

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                      http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

  <servlet>
    <servlet-name>rpc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:dispatchServletContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>rpc</servlet-name>
    <url-pattern>*.rpc</url-pattern>
  </servlet-mapping>

</web-app>

I’m defining standard Spring DispatcherServlet, pointing to *.rpc this will handle GWT command requests. Next step is to handle requests. This is done by using Spring SimpleUrlHandlerMapping by mapping /**/dispatch.rpc to Spring Controller:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="interceptors">
    <list>
      <!--
        <ref bean="openSessionInViewInterceptor" />
        or whatever else per request
      -->
    </list>
  </property>
  <property name="mappings">
    <value>
      /**/dispatch.rpc=actionDispatchTransportService
    </value>
  </property>
</bean>

actionDispatchTransportService is defined as follows:

<bean id="actionDispatchTransportService" class="com.amateurinmotion.dispatch.server.     ↩
  action.support.impl.ActionDispatchTransportServiceImpl">
  <property name="actionDispatcher">
    <bean 
      class="com.amateurinmotion.dispatch.server.action.support.impl.ActionDispatcherImpl">
      <property name="actionHandlerRegistry" ref="actionHandlerRegistry" />
    </bean>
  </property>
</bean>  

The ActionDispatchTransportServiceImpl by itself is RemoteServiceServlet and Controller:

@SuppressWarnings("serial")
public class ActionDispatchTransportServiceImpl extends RemoteServiceServlet implementsActionDispatchTransportService, Controller, ServletContextAware {

  private ServletContext servletContext;
  private ActionDispatcher actionDispatcher;

  @Required
  public void setActionDispatcher(ActionDispatcher actionDispatcher) {
    this.actionDispatcher = actionDispatcher;
  }

  // ActionDispatchTransportService

  public Result execute(Action<?> action) throws Exception {
    return actionDispatcher.execute(action);
  }

  // Controller

  public ModelAndView handleRequest(HttpServletRequest request,                           ↩
      HttpServletResponse response) throws Exception {
    ActionDispatchContext.set(request, response, getServletContext());
    try {
      super.doPost(request, response);
    } finally {
      ActionDispatchContext.remove();
    }
    return null;
  }

  // ServletContextAware

  public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
  }

  @Override
  public ServletContext getServletContext() {
    return servletContext;
  }

}

When Controller receives request the handleRequest method is called, it is delegated to GWT doPost what after deserialization calls execute what delegates request to actionDispatcher who using actionHandlerRegistry lookups ActionHandler for given Action and invokes it.

ActionHandler definition list looks like this:

<bean id="actionHandlerRegistry" class="com.amateurinmotion.dispatch.server.action.       ↩
    support.impl.ActionHandlerRegistryImpl">
  <property name="handlers">
    <list>
      <bean class="com.amateurinmotion.dispatch.server.action.ServerInfoActionHandler" />
    </list>
  </property>
</bean>

For full details see http://bitbucket.org/ampatspell/dispatch (To run locally you’ll need Eclipse and few tweaks in .classpath)

Note: This is not production ready code

 
Internet Explorer 6
Are you serious?