Apache CXFを使用したRESTサーバ構築(Spring未使用)

Jerseyが諸事情で使えず、Apache CXFを使用したRESTサーバを構築した際の覚書

##やること
Tomcat8.0 + Apache CXFでのRESTサーバの構築
※Spring Frameworkは使用しない

##Apache CXFについて
JAX-WS, JAX-RSのフレームワーク。今回は主にJAX-RS
[ダウンロード](http://cxf.apache.org/download.html)はここから

Mavenを使用する場合は

```xml:pom.xml
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-frontend-jaxrs</artifactId>
    <version>3.1.0</version>
</dependency>
```

##環境構築
Tomcat 8.0

**リソースクラス**

```java:SampleResource.java
package hoge.fuga.test.resource;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
	
@Path("/SampleResource")
public class SampleResource {
	
	@Path("/text")
	@Produces(MediaType.TEXT_PLAIN)
	@GET
	public String getText(){
		return "getText";
	}
}
```

**web.xmlの編集[(参考)](http://cxf.apache.org/docs/jaxrs-services-configuration.html#JAXRSServicesConfiguration-ConfiguringJAX-RSendpointsprogrammaticallywithoutSpring)**
CXFNonSpringJaxrsServletを使用

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  id="ihdtool"
  version="3.0" >

    <servlet>
        <servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
        <servlet-class>
            org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
        </servlet-class>
        <init-param>
            <param-name>jaxrs.serviceClasses</param-name>
            <param-value>
                hoge.fuga.test.resource.SampleResource
             </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>
```

**起動**
Tomcatを起動し、ブラウザから[http://localhost:8080/[ContextName]/rest/SampleResource/text](http://localhost:8080/[ContextName]/rest/SampleResource/text)にアクセス、`getText`と表示されればOK

リソースクラスの追加は、カンマ区切りで追加していく

```xml:web.xml
<init-param>
    <param-name>jaxrs.serviceClasses</param-name>
    <param-value>
        hoge.fuga.test.resource.SampleResource,
        hoge.fuga.test.resource.SampleResource2,
        hoge.fuga.test.resource.SampleResource3
     </param-value>
</init-param>
```

パッケージでの指定や、`hoge.fuga.test.resource.*`のような指定方法はできない

自前のProviderなんかは、

```xml:web.xml
<init-param>
     <param-name>jaxrs.providers</param-name>
     <param-value>
         hoge.fuga.test.provider.CustomProvider1,
         hoge.fuga.test.provider.CustomProvider2           
     </param-value>
</init-param>
```

で登録できる


##おまけ、パッケージ指定でのリソースクラス登録方法
`javax.ws.rs.Application`の自前サブクラスを作成することで、クラス登録やProvider登録
をすることが可能(JerseyのResourceConfigクラスのような)

**web.xmlの編集**

```xml:web.xml
<web-app>
    <servlet>
        <servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
        <servlet-class>
            org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>
                hoge.fuga.test.application.MyApplication
             </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFNonSpringJaxrsServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>
```

`<param-name>javax.ws.rs.Application</param-name>`を設定

**Applicationクラスの作成**

```java:MyApplication.java
package hoge.fuga.test.application;

import java.util.Set;
import javax.ws.rs.core.Application;
import org.reflections.Reflections;

public class MyApplication extends Application {

    private static Set<Class<?>> resources = null;

    public MyApplication(){
        String resourcePackage = "hoge.fuga.test.resource";
        Reflections reflection = new Reflections(resourcePackage);
        resources = reflection.getTypesAnnotatedWith(javax.ws.rs.Path.class);
    }

    @Override
    public Set<Class<?>> getClasses(){
        return resources;
    }
}
```

指定したパッケージ名配下のPathアノテーションを持つクラスをスキャンして、クラスSetを取得
クラススキャンには[reflections](https://code.google.com/p/reflections/)を使用