Getting Started

Here we will go through the basic steps on setting up a Beadledom project. We will go over the key components needed to make sure your new service is bootstrapped and running correctly; additionally, we will highlight the major pieces of the service so that you can extend it to fit your needs. Finally we will point to some additional resources that will show some of the additional functionality that you can get with the Beadledom framework.

Before we Start

We know there are a lot of different build tools available for Java, and we think that is great. However for Beadledom we currently use maven as our build tool and dependency manager. The script we will install to help us create our first Beadledom project is really just a wrapper around maven archetypes that let us remove a lot of the boilerplate around project creation.

Installing the Installer

Before we create our first Beadledom project we need to download the beadledom installer utility. If you would like to take a look at the installer source code before running it you can find it here install.sh script.

Then to install execute in your shell

curl -L http://cerner.github.io/beadledom/2.4/beadledom-archetype/downloads/install.sh | sh

Once the download has completed you should be greeted by some sort of success message and now be able to run

beadledom --help

which should print the usage details to the screen.

Creating Our First Project

We are going to use the default archetype simple-service in our example because it is fairly basic while doing a good job at showing off a fair amount of the base feature set that Beadledom offers. In order to kick off our project creation we just need to run

beadledom new

or

beadledom new simple-service

You will be prompted for several things many of which will have some relatively sane defaults. For our example we are going to choose the following values

Package Name:com.example
Project Name:AwesomeThing
Artifact Id:awesome-thing
Group Id:com.example
Beadledom Version:
 (whatever the default)

Feel free to choose whatever you like, we are just calling it out here to make it easier to references pieces of the service later.

Running Our Service

After a successful project creation we can go ahead and build our project and start the service

> cd awesome-thing
awesome-thing> mvn clean install
. . .
[INFO] BUILD SUCCESS
. . .
awesome-thing> cd service
awesome-thing/service> mvn tomcat7:run-war

Once the service has started we can navigate to our swagger resource to explore the rest of the default api.

http://localhost:8080/awesome-thing-service/meta/swagger/ui

Go ahead and play around with the healthcheck and hello resources for a while. Once you get tired of that move onto the next section where we will breakdown the components.

The Breakdown

Our project has three maven sub-modules: api, client and service. We will go through each of these and talk about the classes they contain.

API sub-module

This module contains the interfaces defining your service api and the models defining your responses. The code living here ends up being used by both the client and the service.

HelloWorldResource

@Api(value = "/hello", description = "Retrieve hello world data")
@Path("/hello")
public interface HelloWorldResource {

  @ApiOperation(
      value = "Retrieves hello world data.",
      response = HelloWorldDto.class)
  @ApiResponse(code = 200, message = "Success")
  @GET
  @Produces(MediaType.APPLICATION_JSON)
  public GenericResponse<HelloWorldDto> getHelloWorld();
}

This is the definition for the /hello resource (and by resource we are talking about an api resource). There is a lot going on here so we will add some comments to explain what each of these lines are doing.

/**
 * Swagger annotation defining the base resource for the generated swagger documentation.
 */
@Api(value = "/hello", description = "Retrieve hello world data")

/**
 * JAX-RS annotation defining the base URI path for the resource.
 */
@Path("/hello")
public interface HelloWorldResource {

/**
 * Swagger annotation defining the documentation for the HTTP verb this method provides. It
 * also includes the Dto class that is used for the response.
 */
  @ApiOperation(
      value = "Retrieves hello world data.",
      response = HelloWorldDto.class)

  /**
   * Swagger annotation for the different status codes our resource can
   * return (500 is often omitted).
   */
  @ApiResponse(code = 200, message = "Success")

  /**
   * JAX-RS annotation for the HTTP verb this method is providing functionality for.
   */
  @GET

  /**
   * JAX-RS annotation for the media type our service returns.
   */
  @Produces(MediaType.APPLICATION_JSON)

  /**
   * Method definition for the resource. The GenericResponse is an implementation provided
   * by Beadledom. It allows consumers (mostly of the client) to get a type safe response
   * from the server instead of having to do the casting or deserialization of the Json
   * payload themselves.
   */
  public GenericResponse<HelloWorldDto> getHelloWorld();
}

And that’s pretty much all that is needed to define an end-point. To learn more about how to extend your path and about additional annotations that can be used in defining a resource we suggest taking a look at RESTEasy’s documentation to get started (RESTEasy is the current implementation of the JAX-RS standard that Beadledom is using).

HelloWorldDto

@ApiModel(value = "HelloWorldDto")
public class HelloWorldDto {

  @ApiModelProperty(required = true, value = "name of the message author")
  private String name;
  @ApiModelProperty(required = true, value = "message content")
  private String helloWorldMessage;

  private HelloWorldDto(String name, String message) {
    this.name = Preconditions.checkNotNull(name);
    this.helloWorldMessage = Preconditions.checkNotNull(message);
  }

  /**
   * Creates a new {@link HelloWorldDto} instance.
   *
   * @param name author to be associated with the message
   * @param message the message to be returned
   * @return {@link HelloWorldDto} encapsulating a name and message
   */
  public static HelloWorldDto create(String name, String message) {
    return new HelloWorldDto(name, message);
  }

  /** Returns name. */
  public String getName() {
    return name;
  }

  /** Returns hello world message. */
  public String getHelloWorldMessage() {
    return helloWorldMessage;
  }
}

This class is much less exciting than the HelloWorldResource. The few things to note here are the Swagger annotations. @ApiModel(value = "HelloWordDto") defines the high level API model, and as we are sure you have already guessed @ApiModelProperty allows us to add some documentation around the various fields that are going to be a part of our response.

Service sub-module

Now that we have defined our api lets dive into the implementation and how this all gets wired together. You’ll notice that within our service sub-module we have not only our source code directory we also have a resources and webapp directory. Lets spend just a short amount of time going over what is in our non source code directories.

webapp/META-INF

Files:
  • web.xml - deployment descriptor that loads our context listener class as our servlets entry point

resources

Files:
  • log4j.properties - configuration for our logger
  • stagemonitor.properties - configuration for stagemonitor
  • build-info.properties - properties from the current build used in health checks

All of the above mentioned configuration files are pretty standard. There are lots of other options that can be tinkered with but we suggest you head to the developers pages for the various libraries to learn more.

AwesomeThingContextListener

Note

Your class names might be slightly different depending on what you choose for your Project Name.

public class AwesomeThingContextListener extends ResteasyContextListener {
  @Override
  protected List<? extends Module> getModules(ServletContext context) {
    return Lists.newArrayList(new AwesomeThingModule(), new ResteasyBootstrapModule());
  }
}

There isn’t a lot going on in this file, but it is very important. This is the entry point to our service and where we define our base Guice modules and configuration. We won’t dive much into the configuration component if you want to learn more about it (and we recommend you do) you can find more documentation here.

The method we are overriding here is providing our AwesomeThingModule, which is our service module and ResteasyBootstrapModule, which bootstraps ResteasyModule for our service.

so Let’s take a look at the ResteasyBootstrapModule next.

ResteasyBootstrapModule

public class ResteasyBootstrapModule extends AbstractModule {

  protected void configure() {
    install(new ResteasyModule());

    BuildInfo buildInfo = BuildInfo.load(getClass().getResourceAsStream("build-info.properties"));
    bind(BuildInfo.class).toInstance(buildInfo);
    bind(ServiceMetadata.class).toInstance(ServiceMetadata.create(buildInfo));
  }

  @Provides
  SwaggerConfig provideSwaggerConfig(ServiceMetadata serviceMetadata) {
    SwaggerConfig config = new SwaggerConfig();
    config.setApiVersion(serviceMetadata.getBuildInfo().getVersion());
    config.setSwaggerVersion(SwaggerSpec.version());
    return config;
  }
}

This is where we install the main Beadledom module install(new ResteasyModule());. Inside this module is where Beadledom is going to install and bootstrap the various features it needs in order to make our service tick. Below are some of the many awesome features that we get just by installing ResteasyModule without any extra efforts

The next chunk of code

BuildInfo buildInfo = BuildInfo.load(getClass().getResourceAsStream("build-info.properties"));
bind(BuildInfo.class).toInstance(buildInfo);
bind(ServiceMetadata.class).toInstance(ServiceMetadata.create(buildInfo));

We pull in the properties from the build-info.properties and make them available to the service and more importantly the healthcheck.

AwesomeThingModule

public class AwesomeThingModule extends PrivateModule {
  protected void configure() {
    bind(HelloWorldResource.class).to(HelloWorldResourceImpl.class);

    expose(HelloWorldResource.class);
  }
}

AwesomeThingModule is a private module, which contains configuration information for our service. PrivateModule encapsulates the service’s environment and only exposes objects needed for JAX-RS/Resteasy(ex: resource classes, providers and features). It also prevents dependency issues with a configuration bound to Guice gobally.

With this binding bind(HelloWorldResource.class).to(HelloWorldResourceImpl.class); we are telling Guice that whenever we ask for an instance of HelloWorldResource we want it to inject the implementation HelloWorldResourceImpl. And the next line expose(HelloWorldResource.class);, exposes HelloWorldResource to modules that install AwesomeThingModule.

That’s it! There are additional Beadledom modules that we can install for other functionality, and we could even create our own modules or bindings to provide additional classes our service will need to operate. We recommend that you take some time and become familiar with Guice so that you will know all it enables you to do.

HelloWorldResourceImpl

Last but not least, we have our implementation of the HelloWorldResource interface.

public class HelloWorldResourceImpl implements HelloWorldResource {
  public GenericResponse<HelloWorldDto> getHelloWorld() {
    return GenericResponses
        .ok(HelloWorldDto.create("Beadledom", "Hello World!"))
        .build();
  }
}

That’s it. Not very impressive we know, but it is just a starter service after all! More realistic services will implement whatever sort of business logic, parameter validation, reading and writing from databases here that they need to back their apis.

Client sub-module

There is a lot going on in the client sub-module, and none of it really has anything to do with the implementation of your service. What we are able to do is build a client whose api is based on the same JAX-RS annotations you use for your server. That makes it really easy to make clients for your Java consumers; however, it won’t help you much with consumers of other languages. Instead of trying to explain all the concepts that are going on within the client we recommend you take a look at our client documentation.

Where to go now

The service we just created and went through is just using a subset of features that Beadledom can provide. If you would like to learn more about what Beadledom has to offer take a look at our table of contents and the related documentation and code. If you find a bug or have an idea of a feature Beadledom is lacking open an issue or pull request we are always happy to collaborate to help everyone get to a better place.

Now go build something awesome!