Статьи

Быстрый способ проверить, активен ли REST API — ПОЛУЧИТЬ детали из файла манифеста

Могут быть случаи, когда вы хотите быстро проверить, доступен ли ваш REST API, развернутый в средах dev, test или prod, в целом. Обычный способ сделать это — создать общий ресурс, который предоставляет, например, версию развернутого API. Вы можете инициировать запрос к этому ресурсу вручную или, что еще лучше, иметь задание Jenkings / Hudson, которое запускает задание проверки после развертывания. В этой статье я расскажу, как реализовать такой сервис, который считывает подробности реализации из файла манифеста приложения. Проверено API, разработанное в Учебном пособии — проектирование и реализация REST API на Java с использованием Jersey и Spring

Программное обеспечение используется

  1. Джерси JAX-RS реализация 2.14
  2. Весна 4.1.4
  3. Maven 3.1.1
  4. JDK 7

Ресурс REST

Я разработал два ресурса REST для чтения из файла Manifest:

  • / manifest — возвращает основные атрибуты манифеста в виде ключа, пары значений
  • / manifest / creation-details — возвращает только детали реализации из файла манифеста

Манифест REST ресурса

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@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();
    }
     
}

Запрос

Пример запроса GET — детали реализации

1
2
3
4
5
6
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)

Отклик — 200 ОК

Ответ в формате JSON

01
02
03
04
05
06
07
08
09
10
11
{
   "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"
}

Возвращаемые значения в случае успеха (HTTP Status 200 OK) содержат различные данные по умолчанию, относящиеся к деталям реализации и спецификации. Это автоматически генерируется файл Manifest с плагином Maven, который я представлю в следующем разделе.

Создать файл манифеста с Maven

Поскольку демонстрационное приложение является веб-приложением, я использую подключаемый модуль Apache Maven War, поддерживаемый Apache Maven Archiver, для создания файла манифеста:

конфигурация maven-war-plugin

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<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>

AddDefaultImplementationEntries и addDefaultSpecificationEntries будут генерировать реализацию по умолчанию, соответственно подробности спецификации, из свойств проекта, определенных в файле pom.xml:

Детали реализации по умолчанию

1
2
3
4
5
Implementation-Title: ${project.name}
Implementation-Version: ${project.version}
Implementation-Vendor-Id: ${project.groupId}
Implementation-Vendor: ${project.organization.name}
Implementation-URL: ${project.url}

соответственно:

Детали спецификации по умолчанию

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

См. Apache Maven Archiver для получения дополнительной информации.

Обратите внимание, что для создания файла Manifest.mf также в файловой системе в webapp / META-INF вам необходимо привязать цель манифеста к фазе выполнения (например, package):

Привязать явную цель к этапу упаковки

1
2
3
4
5
6
7
8
9
<executions>
    <execution>
        <phase>package</phase>
        <goals>
            <goal>manifest</goal>
        </goals>
        <inherited>true</inherited>
    </execution>
</executions>

Читать из файла манифеста

Чтение из файла манифеста происходит во внедренном классе ManifestService:

ManifestService.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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;       
    }
     
}

Для доступа к файлу MANIFEST.MF вам нужно ввести ServletContext и вызвать один из его методов.

  • SerlvetContext # getResourceAsStream () — (предпочтительный способ)
  • ServletContext # getRealPath () — получает реальный путь, соответствующий данному виртуальному пути. Возвращенный реальный путь будет иметь форму, соответствующую компьютеру и операционной системе, в которой работает контейнер сервлета, включая надлежащие разделители пути. В этом случае это самая большая проблема, если вы не развернете .war в разобранном виде, у вас не будет доступа к файлу манифеста.

Версия Java EE

В среде JavaEE вам нужно внедрить ServletContext с помощью аннотации @Context:

Версия реализации Java EE

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
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();              
    }
    ...
}

Вот вам и быстрый способ убедиться, что ваш REST API доступен.

Ресурсы

  1. Apache Maven
    1. Apache Maven Archiver
    2. Введение в жизненный цикл сборки # Built-in_Lifecycle_Bindings
  2. Документы Oracle — Работа с файлами манифеста: основы
  3. Переполнение стека
    1. Как получить версию Maven Artifact во время выполнения?
    2. Как получить версию проекта Maven из метода Java как в Pom