Repository: tajo Updated Branches: refs/heads/master 696d2aa7f -> 32b524d74
http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResource.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResource.java b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResource.java new file mode 100644 index 0000000..47a7bcb --- /dev/null +++ b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResource.java @@ -0,0 +1,170 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tajo.ws.rs.resources; + +import java.net.URI; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.TajoConstants; +import org.apache.tajo.conf.TajoConf.ConfVars; +import org.apache.tajo.ipc.ClientProtos.ResultCode; +import org.apache.tajo.master.QueryInfo; +import org.apache.tajo.ws.rs.netty.gson.GsonFeature; +import org.apache.tajo.ws.rs.requests.NewSessionRequest; +import org.apache.tajo.ws.rs.requests.SubmitQueryRequest; +import org.apache.tajo.ws.rs.responses.NewSessionResponse; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.filter.LoggingFilter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.gson.internal.StringMap; + +import static org.junit.Assert.*; + +public class TestQueryResource extends QueryTestCaseBase { + + private URI restServiceURI; + private URI sessionsURI; + private URI queriesURI; + private Client restClient; + + private static final String tajoSessionIdHeaderName = "X-Tajo-Session"; + + public TestQueryResource() { + super(TajoConstants.DEFAULT_DATABASE_NAME); + } + + @Before + public void setUp() throws Exception { + int restPort = testBase.getTestingCluster().getConfiguration().getIntVar(ConfVars.REST_SERVICE_PORT); + restServiceURI = new URI("http", null, "127.0.0.1", restPort, "/rest", null, null); + sessionsURI = new URI(restServiceURI + "/sessions"); + queriesURI = new URI(restServiceURI + "/databases/" + TajoConstants.DEFAULT_DATABASE_NAME + "/queries"); + restClient = ClientBuilder.newBuilder() + .register(new GsonFeature(RestTestUtils.registerTypeAdapterMap())) + .register(LoggingFilter.class) + .property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true) + .property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true) + .build(); + } + + @After + public void tearDown() throws Exception { + restClient.close(); + } + + private SubmitQueryRequest createNewQueryRequest(String query) throws Exception { + SubmitQueryRequest request = new SubmitQueryRequest(); + request.setQuery(query); + return request; + } + + private String generateNewSessionAndGetId() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + request.setDatabaseName(TajoConstants.DEFAULT_DATABASE_NAME); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(ResultCode.OK.equals(response.getResultCode())); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + return response.getId(); + } + + @Test + public void testGetAllQueries() throws Exception { + String sessionId = generateNewSessionAndGetId(); + SubmitQueryRequest queryRequest = createNewQueryRequest("select * from lineitem"); + + Response response = restClient.target(queriesURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .post(Entity.entity(queryRequest, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + String locationHeader = response.getHeaderString("Location"); + assertTrue(locationHeader != null && !locationHeader.isEmpty()); + + String queryId = locationHeader.lastIndexOf('/') >= 0? + locationHeader.substring(locationHeader.lastIndexOf('/')+1):null; + + assertTrue(queryId != null && !queryId.isEmpty()); + + Map<String, List<StringMap>> queriesMap = restClient.target(queriesURI) + .request().get(new GenericType<Map<String, List<StringMap>>>(Map.class)); + + assertNotNull(queriesMap); + + List<StringMap> queryInfoList = queriesMap.get("queries"); + assertNotNull(queryInfoList); + + boolean assertQueryIdFound = false; + for (StringMap queryInfo: queryInfoList) { + if (queryId.equals(queryInfo.get("queryIdStr"))) { + assertQueryIdFound = true; + } + } + + assertTrue(assertQueryIdFound); + } + + @Test + public void testSubmitQuery() throws Exception { + String sessionId = generateNewSessionAndGetId(); + SubmitQueryRequest queryRequest = createNewQueryRequest("select * from lineitem"); + + Response response = restClient.target(queriesURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .post(Entity.entity(queryRequest, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + String locationHeader = response.getHeaderString("Location"); + assertTrue(locationHeader != null && !locationHeader.isEmpty()); + + String queryId = locationHeader.lastIndexOf('/') >= 0? + locationHeader.substring(locationHeader.lastIndexOf('/')+1):null; + + assertTrue(queryId != null && !queryId.isEmpty()); + + QueryInfo queryInfo = restClient.target(queriesURI) + .path("/{queryId}") + .resolveTemplate("queryId", queryId) + .queryParam("print", "BRIEF") + .request().get(new GenericType<QueryInfo>(QueryInfo.class)); + + assertNotNull(queryInfo); + assertEquals(queryId, queryInfo.getQueryIdStr()); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResultResource.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResultResource.java b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResultResource.java new file mode 100644 index 0000000..6fc4ea1 --- /dev/null +++ b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestQueryResultResource.java @@ -0,0 +1,287 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tajo.ws.rs.resources; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.InputStream; +import java.net.URI; +import java.security.MessageDigest; +import java.util.List; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.compress.compressors.CompressorInputStream; +import org.apache.commons.compress.compressors.CompressorStreamFactory; +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.TajoConstants; +import org.apache.tajo.conf.TajoConf.ConfVars; +import org.apache.tajo.ipc.ClientProtos.ResultCode; +import org.apache.tajo.storage.RowStoreUtil; +import org.apache.tajo.storage.Tuple; +import org.apache.tajo.util.TUtil; +import org.apache.tajo.ws.rs.netty.gson.GsonFeature; +import org.apache.tajo.ws.rs.requests.NewSessionRequest; +import org.apache.tajo.ws.rs.requests.SubmitQueryRequest; +import org.apache.tajo.ws.rs.responses.GetQueryResultDataResponse; +import org.apache.tajo.ws.rs.responses.NewSessionResponse; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.filter.LoggingFilter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class TestQueryResultResource extends QueryTestCaseBase { + + private URI restServiceURI; + private URI sessionsURI; + private URI queriesURI; + private Client restClient; + + private static final String tajoSessionIdHeaderName = "X-Tajo-Session"; + private static final String tajoDigestHeaderName = "X-Tajo-Digest"; + + public TestQueryResultResource() { + super(TajoConstants.DEFAULT_DATABASE_NAME); + } + + @Before + public void setUp() throws Exception { + int restPort = testBase.getTestingCluster().getConfiguration().getIntVar(ConfVars.REST_SERVICE_PORT); + restServiceURI = new URI("http", null, "127.0.0.1", restPort, "/rest", null, null); + sessionsURI = new URI(restServiceURI + "/sessions"); + queriesURI = new URI(restServiceURI + "/databases/" + TajoConstants.DEFAULT_DATABASE_NAME + "/queries"); + restClient = ClientBuilder.newBuilder() + .register(new GsonFeature(RestTestUtils.registerTypeAdapterMap())) + .register(LoggingFilter.class) + .property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true) + .property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true) + .build(); + } + + @After + public void tearDown() throws Exception { + restClient.close(); + } + + private String generateNewSessionAndGetId() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + request.setDatabaseName(TajoConstants.DEFAULT_DATABASE_NAME); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(ResultCode.OK.equals(response.getResultCode())); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + return response.getId(); + } + + private URI sendNewQueryResquest(String sessionId, String query) throws Exception { + + SubmitQueryRequest request = new SubmitQueryRequest(); + request.setQuery(query); + + Response response = restClient.target(queriesURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .post(Entity.entity(request, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + String locationHeader = response.getHeaderString("Location"); + assertTrue(locationHeader != null && !locationHeader.isEmpty()); + + URI queryIdURI = new URI(locationHeader); + + assertNotNull(queryIdURI); + + return queryIdURI; + } + + @Test + public void testGetQueryResult() throws Exception { + String sessionId = generateNewSessionAndGetId(); + URI queryIdURI = sendNewQueryResquest(sessionId, "select * from lineitem"); + URI queryResultURI = new URI(queryIdURI + "/result"); + + GetQueryResultDataResponse response = restClient.target(queryResultURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(new GenericType<GetQueryResultDataResponse>(GetQueryResultDataResponse.class)); + + assertNotNull(response); + assertNotNull(response.getResultCode()); + assertEquals(ResultCode.OK, response.getResultCode()); + assertNotNull(response.getSchema()); + assertEquals(16, response.getSchema().getColumns().size()); + assertNotNull(response.getResultset()); + assertTrue(response.getResultset().getId() != 0); + assertNotNull(response.getResultset().getLink()); + } + + @Test + public void testGetQueryResultNotFound() throws Exception { + String sessionId = generateNewSessionAndGetId(); + URI queryIdURI = new URI(queriesURI + "/q_11111_0001"); + URI queryResultURI = new URI(queryIdURI + "/result"); + + Response response = restClient.target(queryResultURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(); + + assertNotNull(response); + assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + } + + @Test + public void testGetQueryResultSet() throws Exception { + String sessionId = generateNewSessionAndGetId(); + URI queryIdURI = sendNewQueryResquest(sessionId, "select * from lineitem"); + URI queryResultURI = new URI(queryIdURI + "/result"); + + GetQueryResultDataResponse response = restClient.target(queryResultURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(new GenericType<GetQueryResultDataResponse>(GetQueryResultDataResponse.class)); + + assertNotNull(response); + assertNotNull(response.getResultCode()); + assertEquals(ResultCode.OK, response.getResultCode()); + assertNotNull(response.getSchema()); + assertEquals(16, response.getSchema().getColumns().size()); + assertNotNull(response.getResultset()); + assertTrue(response.getResultset().getId() != 0); + assertNotNull(response.getResultset().getLink()); + + URI queryResultSetURI = response.getResultset().getLink(); + + Response queryResultSetResponse = restClient.target(queryResultSetURI) + .queryParam("count", 100) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(); + + assertNotNull(queryResultSetResponse); + String tajoDigest = queryResultSetResponse.getHeaderString(tajoDigestHeaderName); + assertTrue(tajoDigest != null && !tajoDigest.isEmpty()); + + DataInputStream queryResultSetInputStream = + new DataInputStream(new BufferedInputStream(queryResultSetResponse.readEntity(InputStream.class))); + + assertNotNull(queryResultSetInputStream); + + boolean isFinished = false; + List<Tuple> tupleList = TUtil.newList(); + RowStoreUtil.RowStoreDecoder decoder = RowStoreUtil.createDecoder(response.getSchema()); + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + while (!isFinished) { + try { + int length = queryResultSetInputStream.readInt(); + byte[] dataByteArray = new byte[length]; + int readBytes = queryResultSetInputStream.read(dataByteArray); + + assertEquals(length, readBytes); + + tupleList.add(decoder.toTuple(dataByteArray)); + messageDigest.update(dataByteArray); + } catch (EOFException eof) { + isFinished = true; + } + } + + assertEquals(5, tupleList.size()); + assertEquals(tajoDigest, Base64.encodeBase64String(messageDigest.digest())); + + for (Tuple aTuple: tupleList) { + assertTrue(aTuple.getInt4(response.getSchema().getColumnId("l_orderkey")) > 0); + } + } + + @Test + public void testGetQueryResultSetWithOffset() throws Exception { + String sessionId = generateNewSessionAndGetId(); + URI queryIdURI = sendNewQueryResquest(sessionId, "select * from lineitem"); + URI queryResultURI = new URI(queryIdURI + "/result"); + + GetQueryResultDataResponse response = restClient.target(queryResultURI) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(new GenericType<GetQueryResultDataResponse>(GetQueryResultDataResponse.class)); + + assertNotNull(response); + assertNotNull(response.getResultCode()); + assertEquals(ResultCode.OK, response.getResultCode()); + assertNotNull(response.getSchema()); + assertEquals(16, response.getSchema().getColumns().size()); + assertNotNull(response.getResultset()); + assertTrue(response.getResultset().getId() != 0); + assertNotNull(response.getResultset().getLink()); + + URI queryResultSetURI = response.getResultset().getLink(); + + Response queryResultSetResponse = restClient.target(queryResultSetURI) + .queryParam("count", 100) + .queryParam("offset", 3) + .request().header(tajoSessionIdHeaderName, sessionId) + .get(); + + assertNotNull(queryResultSetResponse); + String tajoDigest = queryResultSetResponse.getHeaderString(tajoDigestHeaderName); + assertTrue(tajoDigest != null && !tajoDigest.isEmpty()); + + DataInputStream queryResultSetInputStream = + new DataInputStream(new BufferedInputStream(queryResultSetResponse.readEntity(InputStream.class))); + + assertNotNull(queryResultSetInputStream); + + boolean isFinished = false; + List<Tuple> tupleList = TUtil.newList(); + RowStoreUtil.RowStoreDecoder decoder = RowStoreUtil.createDecoder(response.getSchema()); + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + while (!isFinished) { + try { + int length = queryResultSetInputStream.readInt(); + byte[] dataByteArray = new byte[length]; + int readBytes = queryResultSetInputStream.read(dataByteArray); + + assertEquals(length, readBytes); + + tupleList.add(decoder.toTuple(dataByteArray)); + messageDigest.update(dataByteArray); + } catch (EOFException eof) { + isFinished = true; + } + } + + assertEquals(3, tupleList.size()); + assertEquals(tajoDigest, Base64.encodeBase64String(messageDigest.digest())); + + for (Tuple aTuple: tupleList) { + assertTrue(aTuple.getInt4(response.getSchema().getColumnId("l_orderkey")) > 0); + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestSessionsResource.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestSessionsResource.java b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestSessionsResource.java new file mode 100644 index 0000000..7b293d8 --- /dev/null +++ b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestSessionsResource.java @@ -0,0 +1,263 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tajo.ws.rs.resources; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.TajoConstants; +import org.apache.tajo.conf.TajoConf.ConfVars; +import org.apache.tajo.ws.rs.netty.gson.GsonFeature; +import org.apache.tajo.ws.rs.requests.NewSessionRequest; +import org.apache.tajo.ws.rs.responses.NewSessionResponse; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.filter.LoggingFilter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class TestSessionsResource extends QueryTestCaseBase { + + private URI restServiceURI; + private URI sessionsURI; + private Client restClient; + + public TestSessionsResource() { + super(TajoConstants.DEFAULT_DATABASE_NAME); + } + + @Before + public void setUp() throws Exception { + int restPort = testBase.getTestingCluster().getConfiguration().getIntVar(ConfVars.REST_SERVICE_PORT); + restServiceURI = new URI("http", null, "127.0.0.1", restPort, "/rest", null, null); + sessionsURI = new URI(restServiceURI + "/sessions"); + restClient = ClientBuilder.newBuilder() + .register(new GsonFeature(RestTestUtils.registerTypeAdapterMap())) + .register(LoggingFilter.class) + .property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true) + .property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true) + .build(); + } + + @After + public void tearDown() throws Exception { + restClient.close(); + } + + private NewSessionRequest createNewSessionRequest() { + NewSessionRequest request = new NewSessionRequest(); + + request.setUserName("tajo-user1"); + request.setDatabaseName("default"); + + return request; + } + + @Test + public void testNewSession() throws Exception { + NewSessionRequest request = createNewSessionRequest(); + + assertNotNull(request); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertNotNull(response.getId()); + assertTrue(response.getMessage() == null || response.getMessage().isEmpty()); + assertFalse(response.getId().isEmpty()); + } + + @Test + public void testNewSessionWithoutDBName() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertNotNull(response.getId()); + assertTrue(response.getMessage() == null || response.getMessage().isEmpty()); + assertFalse(response.getId().isEmpty()); + } + + @Test + public void testNewSessionWithBadRequest() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setDatabaseName("default"); + + Response response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus()); + } + + @Test + public void testRemoveSession() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + Response restResponse = restClient.target(sessionsURI) + .path("/{session-id}").resolveTemplate("session-id", response.getId()) + .request().delete(); + + assertNotNull(restResponse); + assertEquals(Status.OK.getStatusCode(), restResponse.getStatus()); + } + + @Test + public void testRemoveSessionNotFound() throws Exception { + String invalidSessionId = "invalid"; + + Response response = restClient.target(sessionsURI) + .path("/{session-id}").resolveTemplate("session-id", invalidSessionId) + .request().delete(); + + assertNotNull(response); + assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + } + + @Test + public void testGetAllSessionVariables() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + Map<String, Map<String, String>> variablesMap = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", response.getId()) + .request().get(new GenericType<Map<String, Map<String, String>>>(Map.class)); + + assertNotNull(variablesMap); + assertTrue(variablesMap.containsKey("variables")); + } + + @Test + public void testGetAllSessionVariablesNotFound() throws Exception { + String invalidSessionId = "invalid"; + + Response response = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", invalidSessionId) + .request().get(); + + assertNotNull(response); + assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + } + + @Test + public void testUpdateSessionVariables() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + Map<String, String> variablesMap = new HashMap<String, String>(); + variablesMap.put("variableA", "valueA"); + variablesMap.put("variableB", "valueB"); + Map<String, Map<String, String>> variables = new HashMap<String, Map<String, String>>(); + variables.put("variables", variablesMap); + Response restResponse = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", response.getId()) + .request().put(Entity.entity(variables, MediaType.APPLICATION_JSON)); + + assertNotNull(restResponse); + assertEquals(Status.OK.getStatusCode(), restResponse.getStatus()); + + Map<String, Map<String, String>> retrievedVariables = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", response.getId()) + .request().get(new GenericType<Map<String, Map<String, String>>>(Map.class)); + + assertNotNull(retrievedVariables); + assertFalse(retrievedVariables.isEmpty()); + + Map<String, String> retrievedVariablesMap = retrievedVariables.get("variables"); + + assertNotNull(retrievedVariablesMap); + assertFalse(retrievedVariablesMap.isEmpty()); + + assertTrue(retrievedVariablesMap.containsKey("variableA")); + assertTrue(retrievedVariablesMap.containsKey("variableB")); + assertTrue("valueA".equals(retrievedVariablesMap.get("variableA"))); + assertTrue("valueB".equals(retrievedVariablesMap.get("variableB"))); + } + + @Test + public void testUpdateSessionVariable() throws Exception { + NewSessionRequest request = new NewSessionRequest(); + request.setUserName("tajo-user"); + + NewSessionResponse response = restClient.target(sessionsURI) + .request().post(Entity.entity(request, MediaType.APPLICATION_JSON), NewSessionResponse.class); + + assertNotNull(response); + assertTrue(response.getId() != null && !response.getId().isEmpty()); + + Map<String, String> variablesMap = new HashMap<String, String>(); + variablesMap.put("variableA", "valueA"); + Response restResponse = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", response.getId()) + .request().put(Entity.entity(variablesMap, MediaType.APPLICATION_JSON)); + + assertNotNull(restResponse); + assertEquals(Status.OK.getStatusCode(), restResponse.getStatus()); + + Map<String, Map<String, String>> retrievedVariables = restClient.target(sessionsURI) + .path("/{session-id}/variables").resolveTemplate("session-id", response.getId()) + .request().get(new GenericType<Map<String, Map<String, String>>>(Map.class)); + + assertNotNull(retrievedVariables); + assertFalse(retrievedVariables.isEmpty()); + + Map<String, String> retrievedVariablesMap = retrievedVariables.get("variables"); + + assertNotNull(retrievedVariablesMap); + assertFalse(retrievedVariablesMap.isEmpty()); + + assertTrue(retrievedVariablesMap.containsKey("variableA")); + assertTrue("valueA".equals(retrievedVariablesMap.get("variableA"))); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestTablesResource.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestTablesResource.java b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestTablesResource.java new file mode 100644 index 0000000..6144534 --- /dev/null +++ b/tajo-core/src/test/java/org/apache/tajo/ws/rs/resources/TestTablesResource.java @@ -0,0 +1,195 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tajo.ws.rs.resources; + +import java.net.URI; +import java.util.List; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.catalog.CatalogUtil; +import org.apache.tajo.catalog.Column; +import org.apache.tajo.catalog.Schema; +import org.apache.tajo.catalog.TableDesc; +import org.apache.tajo.catalog.TableMeta; +import org.apache.tajo.catalog.proto.CatalogProtos.StoreType; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.conf.TajoConf.ConfVars; +import org.apache.tajo.storage.StorageConstants; +import org.apache.tajo.util.KeyValueSet; +import org.apache.tajo.ws.rs.netty.gson.GsonFeature; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.filter.LoggingFilter; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.gson.internal.StringMap; + +import static org.junit.Assert.*; + +public class TestTablesResource extends QueryTestCaseBase { + + private URI restServiceURI; + private URI tablesURI; + private Client restClient; + + private static final String defaultDatabaseName = "TestTablesDB"; + + public TestTablesResource() { + super(defaultDatabaseName); + } + + @Before + public void setUp() throws Exception { + int restPort = testBase.getTestingCluster().getConfiguration().getIntVar(ConfVars.REST_SERVICE_PORT); + restServiceURI = new URI("http", null, "127.0.0.1", restPort, "/rest", null, null); + tablesURI = new URI(restServiceURI + "/databases/" + defaultDatabaseName + "/tables"); + restClient = ClientBuilder.newBuilder() + .register(new GsonFeature(RestTestUtils.registerTypeAdapterMap())) + .register(LoggingFilter.class) + .property(ClientProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true) + .property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, true) + .build(); + } + + @After + public void tearDown() throws Exception { + restClient.close(); + } + + private TableDesc createNewTableForTestCreateTable(String tableName) throws Exception { + Schema tableSchema = new Schema(new Column[] {new Column("column1", TajoDataTypes.Type.TEXT)}); + KeyValueSet tableOptions = new KeyValueSet(); + tableOptions.set(StorageConstants.TEXT_DELIMITER, StorageConstants.DEFAULT_FIELD_DELIMITER); + TableMeta tableMeta = new TableMeta(StoreType.CSV, tableOptions); + return new TableDesc(tableName, tableSchema, tableMeta, null); + } + + @Test + public void testCreateTable() throws Exception { + String tableName = "TestCreateTable"; + TableDesc tableDesc = createNewTableForTestCreateTable(tableName); + + Response response = restClient.target(tablesURI) + .request().post(Entity.entity(tableDesc, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + } + + @Test + public void testGetAllTable() throws Exception { + String tableName = "TestGetAllTable"; + TableDesc tableDesc = createNewTableForTestCreateTable(tableName); + + Response response = restClient.target(tablesURI) + .request().post(Entity.entity(tableDesc, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + + List<StringMap<String>> tables = restClient.target(tablesURI) + .request().get(new GenericType<List<StringMap<String>>>(List.class)); + + assertNotNull(tables); + assertTrue(!tables.isEmpty()); + + boolean tableFound = false; + for (StringMap<String> table: tables) { + if (tableName.equals(CatalogUtil.extractSimpleName(table.get("tableName")))) { + tableFound = true; + break; + } + } + + assertTrue(tableFound); + } + + @Test + public void testGetTable() throws Exception { + String tableName = "TestGetTable"; + TableDesc tableDesc = createNewTableForTestCreateTable(tableName); + + Response response = restClient.target(tablesURI) + .request().post(Entity.entity(tableDesc, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + + TableDesc selectedTable = restClient.target(tablesURI) + .path("/{tableName}").resolveTemplate("tableName", tableName) + .request().get(new GenericType<TableDesc>(TableDesc.class)); + + assertNotNull(selectedTable); + assertEquals(tableName, CatalogUtil.extractSimpleName(selectedTable.getName())); + } + + @Test + public void testGetTableNotFound() throws Exception { + Response response = restClient.target(tablesURI) + .path("/{tableName}").resolveTemplate("tableName", "TestGetTableNotFound") + .request().get(); + + assertNotNull(response); + assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + } + + @Test + public void testDropTable() throws Exception { + String tableName = "TestDropTable"; + TableDesc tableDesc = createNewTableForTestCreateTable(tableName); + + Response response = restClient.target(tablesURI) + .request().post(Entity.entity(tableDesc, MediaType.APPLICATION_JSON)); + + assertNotNull(response); + assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); + + TableDesc selectedTable = restClient.target(tablesURI) + .path("/{tableName}").resolveTemplate("tableName", tableName) + .request().get(new GenericType<TableDesc>(TableDesc.class)); + + assertNotNull(selectedTable); + assertEquals(tableName, CatalogUtil.extractSimpleName(selectedTable.getName())); + + response = restClient.target(tablesURI) + .path("/{tableName}").resolveTemplate("tableName", tableName) + .request().delete(); + + assertNotNull(response); + assertEquals(Status.OK.getStatusCode(), response.getStatus()); + } + + @Test + public void testDropTableNotFound() throws Exception { + Response response = restClient.target(tablesURI) + .path("/{tableName}").resolveTemplate("tableName", "TestDropTableNotFound") + .request().delete(); + + assertNotNull(response); + assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus()); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-project/pom.xml ---------------------------------------------------------------------- diff --git a/tajo-project/pom.xml b/tajo-project/pom.xml index 7ad4ae0..e2b0a0e 100644 --- a/tajo-project/pom.xml +++ b/tajo-project/pom.xml @@ -1012,6 +1012,11 @@ <version>2.6</version> </dependency> <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.10</version> + </dependency> + <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>11.0.2</version> http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/pom.xml ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/pom.xml b/tajo-rpc/tajo-ws-rs/pom.xml index a87a67a..271d29a 100644 --- a/tajo-rpc/tajo-ws-rs/pom.xml +++ b/tajo-rpc/tajo-ws-rs/pom.xml @@ -95,6 +95,10 @@ <artifactId>tajo-rpc-common</artifactId> </dependency> <dependency> + <groupId>org.apache.tajo</groupId> + <artifactId>tajo-common</artifactId> + </dependency> + <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-common</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/ResourceConfigUtil.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/ResourceConfigUtil.java b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/ResourceConfigUtil.java new file mode 100644 index 0000000..10c680c --- /dev/null +++ b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/ResourceConfigUtil.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tajo.ws.rs; + +import javax.ws.rs.core.Application; + +import org.glassfish.jersey.server.ResourceConfig; + +public class ResourceConfigUtil { + + public static Application getJAXRSApplication(Application application) { + Application result = application; + + if (application instanceof ResourceConfig) { + ResourceConfig resourceConfig = (ResourceConfig) application; + result = resourceConfig.getApplication(); + } + + return result; + } + +} http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonFeature.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonFeature.java b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonFeature.java index 26086d4..20d7181 100644 --- a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonFeature.java +++ b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonFeature.java @@ -18,17 +18,38 @@ package org.apache.tajo.ws.rs.netty.gson; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; +import org.apache.tajo.json.GsonSerDerAdapter; + public class GsonFeature implements Feature { + + private Map<Type, GsonSerDerAdapter<?>> adapterMap; + + public GsonFeature() { + } + + public GsonFeature(Map<Type, GsonSerDerAdapter<?>> adapterMap) { + this.adapterMap = new HashMap<Type, GsonSerDerAdapter<?>>(adapterMap.size()); + this.adapterMap.putAll(adapterMap); + } @Override public boolean configure(FeatureContext featureContext) { - featureContext.register(GsonReader.class, MessageBodyReader.class); - featureContext.register(GsonWriter.class, MessageBodyWriter.class); + if (adapterMap != null && !adapterMap.isEmpty()) { + featureContext.register(new GsonReader().setAdapterMap(adapterMap), MessageBodyReader.class); + featureContext.register(new GsonWriter().setAdapterMap(adapterMap), MessageBodyWriter.class); + } else { + featureContext.register(GsonReader.class, MessageBodyReader.class); + featureContext.register(GsonWriter.class, MessageBodyWriter.class); + } return true; } } http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonReader.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonReader.java b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonReader.java index 4d6e440..fdaf811 100644 --- a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonReader.java +++ b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonReader.java @@ -26,15 +26,27 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyReader; + +import org.apache.tajo.json.GsonSerDerAdapter; + import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Map; +import java.util.Map.Entry; /** * Custom message body reader with Gson feature. */ @Consumes(MediaType.APPLICATION_JSON) public class GsonReader<T> implements MessageBodyReader<T> { + + private Map<Type, GsonSerDerAdapter<?>> adapterMap; + + public GsonReader<T> setAdapterMap(Map<Type, GsonSerDerAdapter<?>> adapterMap) { + this.adapterMap = adapterMap; + return this; + } @Override public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) { @@ -45,7 +57,16 @@ public class GsonReader<T> implements MessageBodyReader<T> { public T readFrom(Class<T> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> multivaluedMap, InputStream inputStream) throws IOException, WebApplicationException { - Gson gson = new GsonBuilder().create(); + Gson gson; + if (adapterMap != null && !adapterMap.isEmpty()) { + GsonBuilder gsonBuilder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation(); + for (Entry<Type, GsonSerDerAdapter<?>> adapter: adapterMap.entrySet()) { + gsonBuilder.registerTypeAdapter(adapter.getKey(), adapter.getValue()); + } + gson = gsonBuilder.create(); + } else { + gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + } Reader reader = new BufferedReader(new InputStreamReader(inputStream)); return gson.fromJson(reader, type); } http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonUtil.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonUtil.java b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonUtil.java index f16cb96..9994bfa 100644 --- a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonUtil.java +++ b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonUtil.java @@ -21,7 +21,7 @@ package org.apache.tajo.ws.rs.netty.gson; import javax.ws.rs.core.MediaType; public class GsonUtil { - + public static boolean isJsonType(MediaType mediaType) { if (mediaType != null) { String subType = mediaType.getSubtype(); http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonWriter.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonWriter.java b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonWriter.java index d215611..29a4bbf 100644 --- a/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonWriter.java +++ b/tajo-rpc/tajo-ws-rs/src/main/java/org/apache/tajo/ws/rs/netty/gson/GsonWriter.java @@ -26,15 +26,27 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyWriter; + +import org.apache.tajo.json.GsonSerDerAdapter; + import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.Type; +import java.util.Map; +import java.util.Map.Entry; /** * custom message body writer with Gson feature. */ @Produces(MediaType.APPLICATION_JSON) public class GsonWriter<T> implements MessageBodyWriter<T> { + + private Map<Type, GsonSerDerAdapter<?>> adapterMap; + + public GsonWriter<T> setAdapterMap(Map<Type, GsonSerDerAdapter<?>> adapterMap) { + this.adapterMap = adapterMap; + return this; + } @Override public boolean isWriteable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) { @@ -50,7 +62,16 @@ public class GsonWriter<T> implements MessageBodyWriter<T> { public void writeTo(T t, Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException { - Gson gson = new GsonBuilder().create(); + Gson gson; + if (adapterMap != null && !adapterMap.isEmpty()) { + GsonBuilder gsonBuilder = new GsonBuilder().excludeFieldsWithoutExposeAnnotation(); + for (Entry<Type, GsonSerDerAdapter<?>> adapter: adapterMap.entrySet()) { + gsonBuilder.registerTypeAdapter(adapter.getKey(), adapter.getValue()); + } + gson = gsonBuilder.create(); + } else { + gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); + } Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)); gson.toJson(t, type, writer); http://git-wip-us.apache.org/repos/asf/tajo/blob/32b524d7/tajo-rpc/tajo-ws-rs/src/test/java/org/apache/tajo/ws/rs/netty/testapp2/Directory.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-ws-rs/src/test/java/org/apache/tajo/ws/rs/netty/testapp2/Directory.java b/tajo-rpc/tajo-ws-rs/src/test/java/org/apache/tajo/ws/rs/netty/testapp2/Directory.java index 3851020..4ddc2b2 100644 --- a/tajo-rpc/tajo-ws-rs/src/test/java/org/apache/tajo/ws/rs/netty/testapp2/Directory.java +++ b/tajo-rpc/tajo-ws-rs/src/test/java/org/apache/tajo/ws/rs/netty/testapp2/Directory.java @@ -20,11 +20,13 @@ package org.apache.tajo.ws.rs.netty.testapp2; import java.io.Serializable; +import com.google.gson.annotations.Expose; + public class Directory implements Serializable { - private String name; - private String owner; - private String group; + @Expose private String name; + @Expose private String owner; + @Expose private String group; public String getName() { return name;
