Enterprise Java

Quick way to check if the REST API is alive – GET details from Manifest file

There might be cases when you want to quickly verify if your REST API, that is deployed either on dev, test or prod environments, is reachable altogether. A common way to do this is by building a generic resource that delivers for example the version of the deployed API. You can trigger a request to this resource manually or, even better, have a Jenkings/Hudson job, which runs a checkup job after deployment. In this post, I will present how to implement such a service that reads the implementation details from the application’s manifest file. The API verified, is the one developed in the Tutorial – REST API design and implementation in Java with Jersey and Spring
 
 

Software used

  1. Jersey JAX-RS implementation 2.14
  2. Spring 4.1.4
  3. Maven 3.1.1
  4. JDK 7

REST resource

I have developed two REST resources reading from the Manifest file :

  • /manifest – returns the manifest’s main attributes as a key, value pairs
  • /manifest/implementation-details – returns only the implementation details from the manifest file

Manifest REST resource

@Path("/manifest")
public class ManifestResource {
	
	@Autowired
	ManifestService manifestService;
	
	@GET
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public Response getManifestAttributes() throws FileNotFoundException, IOException{
		Attributes manifestAttributes = manifestService.getManifestAttributes();
		
		return Response.status(Response.Status.OK)
				.entity(manifestAttributes)
				.build();
	}	
	
	@Path("/implementation-details")
	@GET	
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public Response getVersion() throws FileNotFoundException, IOException{
		ImplementationDetails implementationVersion = manifestService.getImplementationVersion();
		
		return Response.status(Response.Status.OK)
				.entity(implementationVersion)
				.build();
	}
	
}

Request

GET request example – implementation details

GET http://localhost:8888/demo-rest-jersey-spring/manifest HTTP/1.1
Accept-Encoding: gzip,deflate
Accept: application/json
Host: localhost:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

Response – 200 OK

Response in JSON format

{
   "Implementation-Title": "DemoRestWS",
   "Implementation-Version": "0.0.1-SNAPSHOT",
   "Implementation-Vendor-Id": "org.codingpedia",
   "Built-By": "ama",
   "Build-Jdk": "1.7.0_40",
   "Manifest-Version": "1.0",
   "Created-By": "Apache Maven 3.1.1",
   "Specification-Title": "DemoRestWS",
   "Specification-Version": "0.0.1-SNAPSHOT"
}

The returned values in case of success (HTTP Status 200 OK) contain different default data related to implementation and specification details. These are automatically generated  the Manifest file with Maven plugin, which I will present in the next section.

Generate Manifest file with Maven

Since the demo application is a web application, I am using the Apache maven war plugin supported by the Apache Maven Archiver to generate a Manifest file:

maven-war-plugin configuration

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-war-plugin</artifactId>
	<version>2.5</version>
	<configuration>
		<warName>${project.artifactId}</warName>
		<archive>
			<manifest>
				<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
				<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
			</manifest>
		</archive>					
	</configuration>
	<executions>
		<execution>
			<phase>package</phase>
			<goals>
				<goal>manifest</goal>
			</goals>
			<inherited>true</inherited>
		</execution>
	</executions>				
</plugin>

The addDefaultImplementationEntries and addDefaultSpecificationEntries will generate default implementation, respectively specification details, out of the project properties defined in the pom.xml file:

Default implementation details

Implementation-Title: ${project.name}
Implementation-Version: ${project.version}
Implementation-Vendor-Id: ${project.groupId}
Implementation-Vendor: ${project.organization.name}
Implementation-URL: ${project.url}

, respectively:

Default specifiation details

Specification-Title: ${project.name}
Specification-Version: ${project.version}
Specification-Vendor: ${project.organization.name}

See  Apache Maven Archiver for further details.

Notice that in order to generate the Manifest.mf file also in the file system under webapp/META-INF, you need to bind the manifest goal to an execution phase (e.g. package):

Bind manifest goal to package phase

<executions>
	<execution>
		<phase>package</phase>
		<goals>
			<goal>manifest</goal>
		</goals>
		<inherited>true</inherited>
	</execution>
</executions>

Read from Manifest file

Reading from the manifest file occurs in the injected ManifestService class:

ManifestService.java

public class ManifestService {
	
	@Autowired
	ServletContext context;
		
	Attributes getManifestAttributes() throws FileNotFoundException, IOException{
	    InputStream resourceAsStream = context.getResourceAsStream("/META-INF/MANIFEST.MF");
	    Manifest mf = new Manifest();
	    mf.read(resourceAsStream);
	    Attributes atts = mf.getMainAttributes();
	    
	    return atts;	    		
	}	
	
	ImplementationDetails getImplementationVersion() throws FileNotFoundException, IOException{
	    String appServerHome = context.getRealPath("/");
	    File manifestFile = new File(appServerHome, "META-INF/MANIFEST.MF");

	    Manifest mf = new Manifest();

	    mf.read(new FileInputStream(manifestFile));

	    Attributes atts = mf.getMainAttributes();
	    ImplementationDetails response = new ImplementationDetails();
	    response.setImplementationTitle(atts.getValue("Implementation-Title"));
	    response.setImplementationVersion(atts.getValue("Implementation-Version"));
	    response.setImplementationVendorId(atts.getValue("Implementation-Vendor-Id"));
	    
	    return response;		
	}
	
}

To access the MANIFEST.MF file you need to inject the ServletContext, and call one of its methods

  • SerlvetContext#getResourceAsStream() – (the preferred way)
  • ServletContext#getRealPath() – gets the real path corresponding to the given virtual path. The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. Its biggest problem in this case, if you don’t deploy the .war exploded you won’t have access to the manifest file.

Java EE version

In a JavaEE environment, you would have the ServletContext injected via the @Context annotation:

Java EE implementation version

public class ManifestResource {
	
	@Context
	ServletContext context;
	
	@GET
	@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })	
	public Response getManifestAttributes() throws FileNotFoundException, IOException{
	    InputStream resourceAsStream = context.getResourceAsStream("/META-INF/MANIFEST.MF");
	    Manifest mf = new Manifest();
	    mf.read(resourceAsStream);
	    Attributes atts = mf.getMainAttributes();
	    
		return Response.status(Response.Status.OK)
				.entity(atts)
				.build();	    		
	}
	...
}

Here you have – a quick way to verify that your REST api is reachable.

Resources

  1. Apache Maven
    1. Apache Maven Archiver
    2. Introduction to the Build Lifecycle#Built-in_Lifecycle_Bindings
  2. Oracle docs – Working with Manifest Files: The Basics
  3.  Stackoverflow
    1. How to get Maven Artifact version at runtime?
    2. How to Get Maven Project Version From Java Method as Like at Pom

Adrian Matei

Adrian Matei (ama [AT] codingpedia DOT org) is the founder of Podcastpedia.org and Codingpedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button