SAP HANAにoData via olingo(V2) with ベーシック認証でアクセス
以下で作ったHANAに、テーブル作成。
CREATE COLUMN TABLE "SYSTEM"."TOKUTEST"( "ID" CHAR(5), "NAME" NVARCHAR(50), "GROUP" NVARCHAR(50), "CREATE_DATE" DATE, PRIMARY KEY("ID") );
データ投入。
insert into "SYSTEM"."TOKUTEST" values('GV001', 'NG TOKU', 'SYSTEM CONSULTING GROUP', CURRENT_DATE ); insert into "SYSTEM"."TOKUTEST" values('GV002', 'NG TOKU2', 'SYSTEM CONSULTING GROUP', CURRENT_DATE ); insert into "SYSTEM"."TOKUTEST" values('GV003', 'NG TOKU3', 'SYSTEM CONSULTING GROUP', CURRENT_DATE ); insert into "SYSTEM"."TOKUTEST" values('GV004', 'NG TOKU4', 'SYSTEM CONSULTING GROUP', CURRENT_DATE );
sensorjump.xsodata修正。
service { "SYSTEM"."TOKUTEST" as "TOKUTEST"; }
Javaで取得。
基本的に以下にあるサンプルコードのまんまで、最後にベーシック認証のユーザ名とパスワード入れてるだけ。
my-car-service/OlingoSampleApp.java at master · qinhaizong/my-car-service · GitHub
サンプルなのでベタ打ちだけど、URLとかベーシック認証のユーザ名とパスワードなんかはプロパティファイルに外だしが基本になるかと。
URL毎にユーザ名とパスワードが異なる場合はこんな感じで定義して、TOKUTESTはそれ用に用意したユーザ名とパスワード、TOKUTEST2は定義がないからDEFAULTから取ってくるみたいな感じになるんじゃないかと。
DEFAULT_USERNAME = xxxxxx DEFAULT_PASSWORD = xxxxxx TOKUTEST_URL = http://IPアドレス:8090/toku/oData/sensorjump.xsodata TOKUTEST_USERNAME = yyyyy TOKUTEST_PASSWORD = yyyyy TOKUTEST2_URL = = http://IPアドレス:8090/toku/oData/tokutest2.xsodata
Javaのコードは以下。
package com.servesync.olingo.clienttest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.SimpleDateFormat; import java.util.Base64; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.olingo.odata2.api.commons.HttpStatusCodes; import org.apache.olingo.odata2.api.edm.Edm; import org.apache.olingo.odata2.api.edm.EdmEntityContainer; import org.apache.olingo.odata2.api.edm.EdmEntitySet; import org.apache.olingo.odata2.api.edm.EdmException; import org.apache.olingo.odata2.api.ep.EntityProvider; import org.apache.olingo.odata2.api.ep.EntityProviderException; import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties; import org.apache.olingo.odata2.api.ep.EntityProviderWriteProperties; import org.apache.olingo.odata2.api.ep.entry.ODataEntry; import org.apache.olingo.odata2.api.ep.feed.ODataDeltaFeed; import org.apache.olingo.odata2.api.ep.feed.ODataFeed; import org.apache.olingo.odata2.api.exception.ODataException; import org.apache.olingo.odata2.api.processor.ODataResponse; public class App { public static final String HTTP_METHOD_PUT = "PUT"; public static final String HTTP_METHOD_POST = "POST"; public static final String HTTP_METHOD_GET = "GET"; private static final String HTTP_METHOD_DELETE = "DELETE"; public static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type"; public static final String HTTP_HEADER_ACCEPT = "Accept"; public static final String APPLICATION_JSON = "application/json"; public static final String APPLICATION_XML = "application/xml"; public static final String APPLICATION_ATOM_XML = "application/atom+xml"; public static final String APPLICATION_FORM = "application/x-www-form-urlencoded"; public static final String METADATA = "$metadata"; public static final String INDEX = "/index.jsp"; public static final String SEPARATOR = "/"; public static final boolean PRINT_RAW_CONTENT = true; public App() { } public static void main(String[] args) throws Exception { App app = new App(); String serviceUrl = "http://IPアドレス:8090/toku/oData/sensorjump.xsodata"; String usedFormat = APPLICATION_JSON; print("\n----- Generate sample data ------------------------------"); print("\n----- Read Edm ------------------------------"); Edm edm = app.readEdm(serviceUrl); print("Read default EntityContainer: " + edm.getDefaultEntityContainer().getName()); print("\n----- Read Feed ------------------------------"); ODataFeed feed = app.readFeed(edm, serviceUrl, usedFormat, "TOKUTEST"); print("Read: " + feed.getEntries().size() + " entries: "); for (ODataEntry entry : feed.getEntries()) { print("##########"); print("Entry:\n" + prettyPrint(entry)); print("##########"); } print("\n----- Read Entry ------------------------------"); ODataEntry entry = app.readEntry(edm, serviceUrl, usedFormat, "TOKUTEST", "'GV002'"); print("Single Entry:\n" + prettyPrint(entry)); } private static void print(String content) { System.out.println(content); } private static String prettyPrint(ODataEntry createdEntry) { return prettyPrint(createdEntry.getProperties(), 0); } private static String prettyPrint(Map<String, Object> properties, int level) { StringBuilder b = new StringBuilder(); Set<Entry<String, Object>> entries = properties.entrySet(); for (Entry<String, Object> entry : entries) { intend(b, level); b.append(entry.getKey()).append(": "); Object value = entry.getValue(); if(value instanceof Map) { value = prettyPrint((Map<String, Object>)value, level+1); b.append(value).append("\n"); } else if(value instanceof Calendar) { Calendar cal = (Calendar) value; value = SimpleDateFormat.getInstance().format(cal.getTime()); b.append(value).append("\n"); } else if(value instanceof ODataDeltaFeed) { ODataDeltaFeed feed = (ODataDeltaFeed) value; List<ODataEntry> inlineEntries = feed.getEntries(); b.append("{"); for (ODataEntry oDataEntry : inlineEntries) { value = prettyPrint((Map<String, Object>)oDataEntry.getProperties(), level+1); b.append("\n[\n").append(value).append("\n],"); } b.deleteCharAt(b.length()-1); intend(b, level); b.append("}\n"); } else { b.append(value).append("\n"); } } // remove last line break b.deleteCharAt(b.length()-1); return b.toString(); } private static void intend(StringBuilder builder, int intendLevel) { for (int i = 0; i < intendLevel; i++) { builder.append(" "); } } public Edm readEdm(String serviceUrl) throws IOException, ODataException { InputStream content = execute(serviceUrl + SEPARATOR + METADATA, APPLICATION_XML, HTTP_METHOD_GET); return EntityProvider.readMetadata(content, false); } public ODataFeed readFeed(Edm edm, String serviceUri, String contentType, String entitySetName) throws IOException, ODataException { EdmEntityContainer entityContainer = edm.getDefaultEntityContainer(); String absolutUri = createUri(serviceUri, entitySetName, null); InputStream content = execute(absolutUri, contentType, HTTP_METHOD_GET); return EntityProvider.readFeed(contentType, entityContainer.getEntitySet(entitySetName), content, EntityProviderReadProperties.init().build()); } public ODataEntry readEntry(Edm edm, String serviceUri, String contentType, String entitySetName, String keyValue) throws IOException, ODataException { return readEntry(edm, serviceUri, contentType, entitySetName, keyValue, null); } public ODataEntry readEntry(Edm edm, String serviceUri, String contentType, String entitySetName, String keyValue, String expandRelationName) throws IOException, ODataException { // working with the default entity container EdmEntityContainer entityContainer = edm.getDefaultEntityContainer(); // create absolute uri based on service uri, entity set name with its key property value and optional expanded relation name String absolutUri = createUri(serviceUri, entitySetName, keyValue, expandRelationName); InputStream content = execute(absolutUri, contentType, HTTP_METHOD_GET); return EntityProvider.readEntry(contentType, entityContainer.getEntitySet(entitySetName), content, EntityProviderReadProperties.init().build()); } private InputStream logRawContent(String prefix, InputStream content, String postfix) throws IOException { if(PRINT_RAW_CONTENT) { byte[] buffer = streamToArray(content); print(prefix + new String(buffer) + postfix); return new ByteArrayInputStream(buffer); } return content; } private byte[] streamToArray(InputStream stream) throws IOException { byte[] result = new byte[0]; byte[] tmp = new byte[8192]; int readCount = stream.read(tmp); while(readCount >= 0) { byte[] innerTmp = new byte[result.length + readCount]; System.arraycopy(result, 0, innerTmp, 0, result.length); System.arraycopy(tmp, 0, innerTmp, result.length, readCount); result = innerTmp; readCount = stream.read(tmp); } stream.close(); return result; } private HttpStatusCodes checkStatus(HttpURLConnection connection) throws IOException { HttpStatusCodes httpStatusCode = HttpStatusCodes.fromStatusCode(connection.getResponseCode()); if (400 <= httpStatusCode.getStatusCode() && httpStatusCode.getStatusCode() <= 599) { throw new RuntimeException("Http Connection failed with status " + httpStatusCode.getStatusCode() + " " + httpStatusCode.toString()); } return httpStatusCode; } private String createUri(String serviceUri, String entitySetName, String id) { return createUri(serviceUri, entitySetName, id, null); } private String createUri(String serviceUri, String entitySetName, String id, String expand) { final StringBuilder absolutUri = new StringBuilder(serviceUri).append(SEPARATOR).append(entitySetName); if(id != null) { absolutUri.append("(").append(id).append(")"); } if(expand != null) { //absolutUri.append("/?$expand=").append(expand); absolutUri.append("?$(").append(expand).append(")"); } return absolutUri.toString(); } private InputStream execute(String relativeUri, String contentType, String httpMethod) throws IOException { HttpURLConnection connection = initializeConnection(relativeUri, contentType, httpMethod); connection.connect(); checkStatus(connection); InputStream content = connection.getInputStream(); content = logRawContent(httpMethod + " request on uri '" + relativeUri + "' with content:\n ", content, "\n"); return content; } private HttpURLConnection initializeConnection(String absolutUri, String contentType, String httpMethod) throws MalformedURLException, IOException { URL url = new URL(absolutUri); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(String.format("%s:%s", "ユーザ名", "パスワード").getBytes())); connection.setRequestMethod(httpMethod); connection.setRequestProperty(HTTP_HEADER_ACCEPT, contentType); if(HTTP_METHOD_POST.equals(httpMethod) || HTTP_METHOD_PUT.equals(httpMethod)) { connection.setDoOutput(true); connection.setRequestProperty(HTTP_HEADER_CONTENT_TYPE, contentType); } return connection; } }
結果は以下
----- Generate sample data ------------------------------ ----- Read Edm ------------------------------ GET request on uri 'http://IPアドレス:8090/toku/oData/sensorjump.xsodata/$metadata' with content: <?xml version="1.0" encoding="utf-8" standalone="yes" ?><edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"><edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="2.0"><Schema Namespace="toku.oData.sensorjump" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"><EntityType Name="TOKUTESTType"><Key><PropertyRef Name="ID" /></Key><Property Name="ID" Type="Edm.String" Nullable="false" MaxLength="5" /><Property Name="NAME" Type="Edm.String" MaxLength="50" /><Property Name="GROUP" Type="Edm.String" MaxLength="50" /><Property Name="CREATE_DATE" Type="Edm.DateTime" /></EntityType><EntityContainer Name="sensorjump" m:IsDefaultEntityContainer="true"><EntitySet Name="TOKUTEST" EntityType="toku.oData.sensorjump.TOKUTESTType" /></EntityContainer></Schema></edmx:DataServices></edmx:Edmx> Read default EntityContainer: sensorjump ----- Read Feed ------------------------------ GET request on uri 'http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST' with content: {"d":{"results":[{"__metadata": {"type":"toku.oData.sensorjump.TOKUTESTType","uri":"http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV001')"},"ID":"GV001","NAME":"NG TOKU","GROUP":"SYSTEM CONSULTING GROUP","CREATE_DATE":"\/Date(1586736000000)\/"},{"__metadata": {"type":"toku.oData.sensorjump.TOKUTESTType","uri":"http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV002')"},"ID":"GV002","NAME":"NG TOKU2","GROUP":"SYSTEM CONSULTING GROUP","CREATE_DATE":"\/Date(1586736000000)\/"},{"__metadata": {"type":"toku.oData.sensorjump.TOKUTESTType","uri":"http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV003')"},"ID":"GV003","NAME":"NG TOKU3","GROUP":"SYSTEM CONSULTING GROUP","CREATE_DATE":"\/Date(1586736000000)\/"},{"__metadata": {"type":"toku.oData.sensorjump.TOKUTESTType","uri":"http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV004')"},"ID":"GV004","NAME":"NG TOKU4","GROUP":"SYSTEM CONSULTING GROUP","CREATE_DATE":"\/Date(1586736000000)\/"}]}} Read: 4 entries: ########## Entry: GROUP: SYSTEM CONSULTING GROUP CREATE_DATE: 20/04/13 9:00 ID: GV001 NAME: NG TOKU ########## ########## Entry: GROUP: SYSTEM CONSULTING GROUP CREATE_DATE: 20/04/13 9:00 ID: GV002 NAME: NG TOKU2 ########## ########## Entry: GROUP: SYSTEM CONSULTING GROUP CREATE_DATE: 20/04/13 9:00 ID: GV003 NAME: NG TOKU3 ########## ########## Entry: GROUP: SYSTEM CONSULTING GROUP CREATE_DATE: 20/04/13 9:00 ID: GV004 NAME: NG TOKU4 ########## ----- Read Entry ------------------------------ GET request on uri 'http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV002')' with content: {"d":{"__metadata": {"type":"toku.oData.sensorjump.TOKUTESTType","uri":"http://IPアドレス:8090/toku/oData/sensorjump.xsodata/TOKUTEST('GV002')"},"ID":"GV002","NAME":"NG TOKU2","GROUP":"SYSTEM CONSULTING GROUP","CREATE_DATE":"\/Date(1586736000000)\/"}} Single Entry: GROUP: SYSTEM CONSULTING GROUP CREATE_DATE: 20/04/13 9:00 ID: GV002 NAME: NG TOKU2
うぇーい。