Build Java EE Projects with Forge 3

JBoss Forge ships now with the 3.x release which brings several enhancements to the project creator engine. Besides it, the release 3.x has changed the option names syntax a bit, switching to a dashed and lower-cased structure. Let’s see how we can quickly create a project to be deployed on WildFly 10.

Starting Forge 3

Forge downloads are available at: https://forge.jboss.org/download

Pickup the latest stable version and start the forge tool:

$ bin/forge

You can even skip the installation if you have JBoss Developer Studio which already ships with Forge Console. Just switch the view to Forge Console and you can start using Forge!

JBoss Forge 3 tutorial

Creating a simple Java EE Project with Forge

Let’s start building up a new project named “demo-forge” which uses the JAVA EE 7 stack, therefore its target will be WildFly:

project-new  --named demo-forge --type war --stack JAVA_EE_7

What is really cool if you are using JBoss Developer Studio is that the project will be automatically created in your Workspace so no need to search and import it:

JBoss Forge 3 tutorial

Now let’s create one Model object which will be eventually scaffolded:

jpa-new-entity --named Customer

jpa-new-field --named name --not-nullable
jpa-new-field --named surname --not-nullable
jpa-new-field --named email --not-nullable

As you can see, we have created the Customer Entity class and included a basic NotNull constraint on the top of it. If we want, we can create more complex constraint such as Regular Expression patterns as follows:

constraint-add --on-property email --constraint Pattern --regexp ^(.+)@(.+)$

Done with the model, we will now create the Faces layer through the scaffold-generate command, specifying the provider (Faces) and the Web context root:

scaffold-generate --targets org.demo.forge.model.Customer --web-root demo-forge --provider Faces

Please note that Forge uses lots of defaults to simplify your project creation. In our case, as we have omitted the base package name in the project creation, the root package org.[project.name] has been usedDone with the project, it’s time to build it, which will trigger the maven install command:@SHELLbuild

Deploying the project to WildFly can be easily achieved by adding to your pom.xml the Maven’s WildFly plugin

<plugin>
    <groupId>org.wildfly.plugins</groupId>
    <artifactId>wildfly-maven-plugin</artifactId>
    <version>1.0.2.Final</version>
    <configuration>
        <filename>${project.build.finalName}.war</filename>
    </configuration>
</plugin>

Otherwise, you can do it directly from Forge, but you have to install a couple of adds-on first:

addon-install-from-git --url https://github.com/forge/as-addon  --coordinate org.jboss.forge.addon:as
addon-install-from-git --url https://github.com/forge/jboss-as-addon  --coordinate org.jboss.forge.addon:jboss-as-wf

Now you will need to set up at first the application server version to be used with:

as-setup --server wildfly --version 10.1.0.Final

And finally, you can deploy it with:

as-deploy

Here is your application up and running:

jboss forge tutorial

Please note that on some versions of Linux (such as Fedora 21) you can incur in issues when installing the jboss-as-addon, due to an excessive number of io watches created. In order to cope with it (if you really don’t want to install the Maven WildFly plugin :-)!) you can increase that number with:

$ sudo sysctl fs.inotify.max_user_watches=20000

How to create a CRUD REST application with Forge

In the second example, we will show how to scaffold a JAX-RS application which uses JPA to store your data.

Firstly, create a new Project named “demo-rest” which uses JAVA EE 7 stack

project-new  --named demo-rest --type war --stack JAVA_EE_7

We will then add an Entity object named Customer

jpa-new-entity --named Customer

jpa-new-field --named firstname
jpa-new-field --named surname
jpa-new-field --named email

Now we move to the top of our project and we generate the REST Endpoints to CRUD our Entities:

cd ~~
rest-generate-endpoints-from-entities --targets org.demo.rest.model.Customer 

As you can see, the following EJB Rest Resource has been created:

@Stateless
@Path("/customers")
public class CustomerEndpoint {
	@PersistenceContext(unitName = "demo-rest-persistence-unit")
	private EntityManager em;

	@POST
	@Consumes("application/json")
	public Response create(Customer entity) {
		em.persist(entity);
		return Response.created(
				UriBuilder.fromResource(CustomerEndpoint.class)
						.path(String.valueOf(entity.getId())).build()).build();
	}

	@DELETE
	@Path("/{id:[0-9][0-9]*}")
	public Response deleteById(@PathParam("id") Long id) {
		Customer entity = em.find(Customer.class, id);
		if (entity == null) {
			return Response.status(Status.NOT_FOUND).build();
		}
		em.remove(entity);
		return Response.noContent().build();
	}

	@GET
	@Path("/{id:[0-9][0-9]*}")
	@Produces("application/json")
	public Response findById(@PathParam("id") Long id) {
		TypedQuery<Customer> findByIdQuery = em
				.createQuery(
						"SELECT DISTINCT c FROM Customer c WHERE c.id = :entityId ORDER BY c.id",
						Customer.class);
		findByIdQuery.setParameter("entityId", id);
		Customer entity;
		try {
			entity = findByIdQuery.getSingleResult();
		} catch (NoResultException nre) {
			entity = null;
		}
		if (entity == null) {
			return Response.status(Status.NOT_FOUND).build();
		}
		return Response.ok(entity).build();
	}

	@GET
	@Produces("application/json")
	public List<Customer> listAll(@QueryParam("start") Integer startPosition,
			@QueryParam("max") Integer maxResult) {
		TypedQuery<Customer> findAllQuery = em.createQuery(
				"SELECT DISTINCT c FROM Customer c ORDER BY c.id",
				Customer.class);
		if (startPosition != null) {
			findAllQuery.setFirstResult(startPosition);
		}
		if (maxResult != null) {
			findAllQuery.setMaxResults(maxResult);
		}
		final List<Customer> results = findAllQuery.getResultList();
		return results;
	}

	@PUT
	@Path("/{id:[0-9][0-9]*}")
	@Consumes("application/json")
	public Response update(@PathParam("id") Long id, Customer entity) {
		if (entity == null) {
			return Response.status(Status.BAD_REQUEST).build();
		}
		if (id == null) {
			return Response.status(Status.BAD_REQUEST).build();
		}
		if (!id.equals(entity.getId())) {
			return Response.status(Status.CONFLICT).entity(entity).build();
		}
		if (em.find(Customer.class, id) == null) {
			return Response.status(Status.NOT_FOUND).build();
		}
		try {
			entity = em.merge(entity);
		} catch (OptimisticLockException e) {
			return Response.status(Response.Status.CONFLICT)
					.entity(e.getEntity()).build();
		}

		return Response.noContent().build();
	}
}

Now our Forge REST project is complete.

Scripting with JBoss Forge

Running a JBoss Forge script is an handy feature to create quickly an application starting from a script file. All you have to do is starting Forge and run the script file as follows:

run <scriptname>

As an example, pickup the following script from the quickstarts:

https://github.com/jboss-developer/jboss-eap-quickstarts/blob/7.1.0.Beta/forge-from-scratch/generate.fsh

Run this file from the Forge console using the run command:

 $ run generate.fsh

At this point, Forge creates the new project and builds it.