Moonshine Container Basics


Overview

Moonshine container configures the services, manages dependencies between them and provides the environment for their execution.

Bootstrapping the Container

Below you can find the basic code needed to bootstrap a Moonshine container.

import org.atteo.moonshine.Moonshine;
import org.atteo.moonshine.MoonshineException;

public class Main {
	public static void main(String[] args) throws IOException, MoonshineException {
		Moonshine moonshine = Moonshine.Factory.builder()
				.arguments(args)
				.build();
		if (moonshine != null) {
			moonshine.start();
		}
	}
}
The builder allows to customize the container by specifying additional configuration files, changing default directory names, adding command line parameters processors, etc. Here you can find the example project with the Moonshine startup customizations.

Note that the builder build() method can actually return null. This is correct behavior when according to the provided command line arguments, the application is not supposed to be started. This is true when, for instance, '--help' switch was specified.

If you don't want to alter any startup options, you can use the default Main class provided with the Moonshine:

org.atteo.moonshine.Main
Here you can find the example which uses the default Main class for startup.

You will also need Moonshine container library itself to execute the project:

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.atteo.moonshine</groupId>
			<artifactId>bom</artifactId>
			<version>0.9</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
<dependencies>
	<dependency>
		<groupId>org.atteo.moonshine</groupId>
		<artifactId>container</artifactId>
	</dependency>
</dependencies>

Service Definition Class

Service is a basic component of Moonshine application. Services are instantiated from the XML configuration files. They can register bindings in Google Guice, can be started and stopped repeatedly and are finally closed on container shut down.

Let's see how a basic Service looks like:

import javax.xml.bind.annotation.XmlRootElement;

import org.atteo.moonshine.TopLevelService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Service with simple start/stop logic.
 */
@XmlRootElement(name = "printer")
public class PrinterService extends TopLevelService {
	private static final Logger logger = LoggerFactory.getLogger(PrinterService.class);

	@Override
	public void start() {
		logger.warn("Basic service start() method called");
	}

	@Override
	public void stop() {
		logger.warn("Basic service stop() method called");
	}
}

A lot of things happen here behind the scenes, so let's go through them one by one.

Service instantiation

Services are instantiated by declaring their associated name in the configuration file. The configuration files are read from:

Below you can see the XML file which will trigger instantiation of the PrinterService defined above:

<config>
	<printer/>
</config>
You can instantiate the service multiple times, but in this case you need to provide an unique ID to both services to differentiate them:
<config>
	<printer id='first'/>
	<printer id='second'/>
</config>

You can download the code of PrinterService example from here.

The project from the example also contains POM configuration for exec-maven-plugin which allows to start Moonshine Service directly from the source code project. To do that execute:

mvn clean install exec:java
...
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ 01_simple_service ---
15:43:23.853 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Bootstrapping Moonshine
15:43:24.604 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Building Guice injector hierarchy
15:43:24.711 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Configuring: "first" PrinterService (Service with simple start/stop logic)
15:43:24.712 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Configuring: "second" PrinterService (Service with simple start/stop logic)
15:43:24.835 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Starting services
15:43:24.835 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Starting: "first" PrinterService (Service with simple start/stop logic)
15:43:24.835 [org.atteo.moonshine.Main.main()] WARN  o.a.moonshine.example.PrinterService - Basic service start() method called
15:43:24.835 [org.atteo.moonshine.Main.main()] INFO  Moonshine - Starting: "second" PrinterService (Service with simple start/stop logic)
15:43:24.835 [org.atteo.moonshine.Main.main()] WARN  o.a.moonshine.example.PrinterService - Basic service start() method called
15:43:24.835 [org.atteo.moonshine.Main.main()] INFO  Moonshine - All services started
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.078s (Wall Clock)
[INFO] Finished at: Mon Oct 28 15:43:24 CET 2013
[INFO] Final Memory: 23M/217M
[INFO] ------------------------------------------------------------------------
15:43:24.970 [Thread-3] INFO  Moonshine - Shutting down moonshine
15:43:24.972 [Thread-3] INFO  Moonshine - Stopping: "first" PrinterService (Service with simple start/stop logic)
15:43:24.972 [Thread-3] WARN  o.a.moonshine.example.PrinterService - Basic service stop() method called
15:43:24.972 [Thread-3] INFO  Moonshine - Stopping: "second" PrinterService (Service with simple start/stop logic)
15:43:24.972 [Thread-3] WARN  o.a.moonshine.example.PrinterService - Basic service stop() method called
15:43:24.972 [Thread-3] INFO  Moonshine - All services stopped
	
As you can see the Moonshine configures, starts and stops each each service. Each time it prints service ID inside quotation marks, service class name and service description in parentheses.

Service Testing

There is also an easy way to start Moonshine container from JUnit tests. Just extend your test class from MoonshineTest. This will initialize and start Moonshine container once before execution of all test methods and then shutdown it after the tests are done. You can find an example project with simple test here.

If you want to customize Moonshine container execution for the tests, annotate your test class with @MoonshineConfiguration annotation. You can, for instance, skip loading of '/default-config.xml' file and provide your own configuration in-place like that:

@MoonshineConfiguration(skipDefault = true, fromString = ""
	+ "<config>"
	+ "    <printer/>"
	+ "</config>")
public class PrinterServiceTest extends MoonshineTest {
	@Test
	public void shouldStartMoonshine() {
	}
}

Services Bundled With Moonshine

Moonshine, out of the box, provides services to start and configure transactions, database access with migrations, persistence using Hibernate and Spring Data, two HTTP engines: Jetty and Tomcat, servlets, websockets and REST services. Additionally Moonshine contains services which allow to profile your application and collect metrics which can be retrieved directly using JMX or through the provided REST wrapper or web console.

For instance let modify our test class to measure execution time of a test method. We will use Perf4J service for that. It provides @Profiled annotation which logs the execution time of the annotated method.

@MoonshineConfiguration(fromString = ""
		+ "<config>"
		+ "    <perf4j/>"
		+ "</config>")
public class PrinterServiceTest extends MoonshineTest {
	@Test
	@Profiled
	public void shouldLogExecutionTime() {
	}
}
After test execution in the log file located in 'target/test-home/logs/PrinterServiceTest.log' there will be a log entry with information about when the method was executed and how long the execution took:
18:59:07.921 [main] INFO  org.perf4j.TimingLogger - start[1382983147918] time[2] tag[shouldLogExecutionTime]
	


Next: Writing Services.