Wicket で XML-RPC API を作る

## 環境
- Wicket 7.10
- Tomcat 8
- Java 8
- org.apache.xmlrpc 3.1.3

## 背景
Wicket で XML-RPCがやりたい!


## XML-RPC受信用のページを準備
* respond, detach を override

```java:XmlRpcPage.java
public class XmlRpcPage extends WebPage {

	private static final long serialVersionUID = 1L;

	public XmlRpcPage(PageParameters params) {
		super(params);
		setStatelessHint(true);
		Session.get().bind();

		HttpServletRequest request = (HttpServletRequest)getRequestCycle().getRequest().getContainerRequest();
		HttpServletResponse response = (HttpServletResponse)getRequestCycle().getResponse().getContainerResponse();

		getRequestCycle().replaceAllRequestHandlers(new IRequestHandler() {

			@Override
			public void respond(IRequestCycle requestCycle) {
				try {
					processXmlRpcRequest(request, response);
				} catch (ServletException | IOException e) {
					throw new WicketRuntimeException(e);
				}
			}

			@Override
			public void detach(IRequestCycle requestCycle) {

			}

		});
	}

	/**
	 * Get XML-RPC server
	 * @return
	 */
	protected XmlRpcServletServer getXmlRpcServer() {
		return ((WicketApplication)getApplication()).getXmlRpcServer();
	}

	/**
	 * Process XML-RPC request
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void processXmlRpcRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
		getXmlRpcServer().execute(request, response);
	}

	@Override
	public Markup getAssociatedMarkup() {
		return null;
	}

	@Override
	protected void configureResponse(WebResponse response) {
		final String encoding = getApplication().getRequestCycleSettings().getResponseRequestEncoding();
		response.setContentType("application/xhtml+xml; charset=" + encoding);
	}
}
```
## Wicketアプリケーションの設定

* XmlRpc用 Server, Config 準備  

```java:WicketApplication.java

	protected XmlRpcServletServer xmlRpcServer	= null;
	protected XmlRpcServerConfigImpl xmlRpcConfig	= null;

        // コンストラクタ
	public WicketApplication() {
		super();
		xmlRpcServer = new XmlRpcServletServer();
		xmlRpcConfig = new XmlRpcServerConfigImpl();
	}
```
* 初期化処理メソッド

```java:WicketApplication.java
	/*
	 * Initialize xmlrpc server
	 */
	public void initXmlRpc() {

		/* configure xml-rpc server */
		xmlRpcServer.setTypeFactory(new CustomTypeFactory(xmlRpcServer));

		//CustomTypeConverterFactory は Xml-Rpcで型変換用のファクトリ
		xmlRpcServer.setTypeConverterFactory(new CustomTypeConverterFactory());

		xmlRpcConfig = (XmlRpcServerConfigImpl)this.xmlRpcServer.getConfig();
		xmlRpcConfig.setBasicEncoding(XmlRpcConfigImpl.UTF8_ENCODING);
		xmlRpcConfig.setEnabledForExceptions(true);
		xmlRpcConfig.setEnabledForExtensions(true);

		PropertyHandlerMapping mapping = createXmlRpcHandlerMapping();
		this.xmlRpcServer.setHandlerMapping(mapping);
	}
```
*CustomTypeFactory* は org.apache.xmlrpc.common.TypeFactoryImpl を extends したもの
*CustomTypeConverterFactory* は org.apache.xmlrpc.common.TypeConverterFactoryImpl を extends したもの

* Xml-Rpcのマッピングメソッド

```java:WicketApplication.java
	/**
	 * XML-RPC 用プロパティハンドラマップ生成
	 * @return
	 */
	private PropertyHandlerMapping createXmlRpcHandlerMapping() {

		PropertyHandlerMapping mapping = new PropertyHandlerMapping();
		mapping.setRequestProcessorFactoryFactory(new StatelessProcessorFactoryFactory());
		mapping.setTypeConverterFactory(new CustomTypeConverterFactory());
		try {
			mapping.load(getClass().getClassLoader(), "xmlrpc.properties");
		} catch (XmlRpcException | IOException e) {
			StringWriter sw = new StringWriter();
			e.printStackTrace(new PrintWriter(sw));
			logger.error("ERROR:\n"+sw.toString());
			throw new WicketRuntimeException(e);
		}
		return mapping;
	}
```

```code:xmlrpc.properties
SampleService=my.api.xmlrpc.service.impl.SampleServiceImpl
```

* initメソッド内で呼び出す

```java:WicketApplication.java
		// initialize XML-RPC
		initXmlRpc();
```

* initメソッド内上記初期化後にページマウント

```java:WicketApplication.java
		// xml-rpc base
		mount(new MountedMapper("/XmlRpc", XmlRpcPage.class));
```

## 呼び出す

```java:TestSampleXmlRpc.java
	public static void main(String[] args) throws Exception {
		
		XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
		config.setServerURL(new URL("http://localhost:8080/sample/XmlRpc"));
		config.setEnabledForExtensions(true);
		config.setEnabledForExceptions(true);

		XmlRpcClient client = new XmlRpcClient();
		client.setTransportFactory(new XmlRpcLoggingTransportFactory(client));
		client.setTypeFactory(new CustomTypeFactory(client));
		client.setConfig(config);

		Vector<Object> arg = new Vector<Object>();
		arg.add("some.parameter");

		Object response = client.execute("SampleService.sampleMethod", arg);
		System.out.println("Response: " + response);
	}
```
*CustomTypeFactory* は org.apache.xmlrpc.common.TypeFactoryImpl を extends したもの

## その他
ご質問等あればお気軽にどうぞ。
エラーハンドリングはtry ~ catch で全てキャッチして結果を戻り値として返すようにしています。
（後で書こうかとも思いましたが、わざわざ書くほどの事でもなかった、、、）