Java tutorial
/* * Copyright 2014-present the original author or authors. * * Licensed 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.spring.data.gemfire.rest; import static org.junit.Assert.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Random; import java.util.Set; import javax.annotation.Resource; import com.fasterxml.jackson.core.JsonParser.Feature; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheFactory; import com.gemstone.gemfire.cache.DataPolicy; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.RegionFactory; import com.gemstone.gemfire.cache.RegionService; import com.gemstone.gemfire.pdx.PdxInstance; import com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer; import org.codeprimate.io.FileSystemUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestTemplate; /** * The GemFireRestInterfaceTest class is a test suite of test cases testing the contract and functionality of the * GemFire Developer REST API, mixing Java clients, this test GemFire's Cache Region API, along with * a REST-based client, also this test using Spring's RestTemplate, testing the proper interaction, especially * in the case of an application domain object type having a java.util.Date property. * * @author John Blum * @see org.junit.Test * @see org.junit.runner.RunWith * @see org.springframework.test.context.ContextConfiguration * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner * @see org.springframework.web.client.RestTemplate * @see com.gemstone.gemfire.cache.Cache * @see com.gemstone.gemfire.cache.Region * @see com.gemstone.gemfire.pdx.PdxInstance * @see com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer * @since 1.0.0 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @SuppressWarnings("unused") public class GemFireRestInterfaceTest { protected static int DEFAULT_HTTP_SERVICE_PORT = 8189; protected static final String REST_API_SERVICE_ENDPOINT = "http://localhost:%1$d/gemfire-api/v1/%2$s/%3$s"; protected static final String UTF_8 = "UTF-8"; @Autowired private Cache gemfireCache; @Autowired private ObjectMapper objectMapper; @Resource(name = "gemfireProperties") private Properties gemfireProperties; @Resource(name = "People") private Region<String, Object> people; @Before public void setupGemFire() { if (gemfireCache == null) { gemfireProperties = (gemfireProperties != null ? gemfireProperties : new Properties()); gemfireCache = new CacheFactory() //.setPdxSerializer(new ReflectionBasedAutoSerializer(Person.class.getPackage().getName().concat(".*"))) .setPdxSerializer( new ReflectionBasedAutoSerializer(Person.class.getName().replaceAll("\\$", "."))) .setPdxReadSerialized(true).setPdxIgnoreUnreadFields(false) .set("name", getClass().getSimpleName()).set("mcast-port", "0").set("log-level", "config") .set("http-service-bind-address", "localhost") .set("http-service-port", String.valueOf(getHttpServicePort())) //.set("http-service-ssl-enabled", "false") .set("start-dev-rest-api", "true").create(); RegionFactory<String, Object> peopleRegionFactory = gemfireCache.createRegionFactory(); peopleRegionFactory.setDataPolicy(DataPolicy.PARTITION); peopleRegionFactory.setKeyConstraint(String.class); peopleRegionFactory.setValueConstraint(Object.class); people = peopleRegionFactory.create("People"); } } @After public void tearDown() { gemfireCache.close(); } protected synchronized int getHttpServicePort() { try { return Integer.parseInt(StringUtils.trimWhitespace(gemfireProperties.getProperty("http-service-port"))); } catch (NumberFormatException ignore) { int httpServicePort = getHttpServicePort(DEFAULT_HTTP_SERVICE_PORT); gemfireProperties.setProperty("http-service-port", String.valueOf(httpServicePort)); return httpServicePort; } } private int getHttpServicePort(final int defaultPort) { int httpServicePort = (1024 + new Random(System.currentTimeMillis()).nextInt(65535 - 1024)); return (httpServicePort > 1024 && httpServicePort < 65536 ? httpServicePort : defaultPort); } protected ObjectMapper getObjectMapper() { if (objectMapper == null) { Jackson2ObjectMapperFactoryBean objectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean(); objectMapperFactoryBean.setFailOnEmptyBeans(true); objectMapperFactoryBean.setFeaturesToEnable(Feature.ALLOW_COMMENTS); objectMapperFactoryBean.setFeaturesToEnable(Feature.ALLOW_SINGLE_QUOTES); objectMapperFactoryBean.setFeaturesToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); objectMapperFactoryBean.setFeaturesToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); objectMapperFactoryBean.setIndentOutput(true); objectMapperFactoryBean.setSimpleDateFormat("MM/dd/yyyy"); objectMapperFactoryBean.afterPropertiesSet(); objectMapper = objectMapperFactoryBean.getObject(); } return objectMapper; } protected Region<String, Object> getPeopleRegion() { assertNotNull("The 'People' Region was not properly initialized!", people); return people; } protected String getAdhocQueryRestApiEndpoint(final String query) { return getAdhocQueryRestApiEndpoint(getHttpServicePort(), query); } protected String getAdhocQueryRestApiEndpoint(final int httpServicePort, final String query) { return String.format(REST_API_SERVICE_ENDPOINT, httpServicePort, "queries", String.format("adhoc?q=%1$s", query)); } protected String getRegionGetRestApiEndpoint(final Region<?, ?> region, final String key) { return getRegionGetRestApiEndpoint(getHttpServicePort(), region, key); } protected String getRegionGetRestApiEndpoint(final int httpServicePort, final Region<?, ?> region, final String key) { return String.format(REST_API_SERVICE_ENDPOINT, httpServicePort, region.getName(), key); } protected Date createDate(final int year, final int month, final int dayOfMonth) { Calendar dateTime = Calendar.getInstance(); dateTime.clear(); dateTime.set(Calendar.YEAR, year); dateTime.set(Calendar.MONTH, month); dateTime.set(Calendar.DAY_OF_MONTH, dayOfMonth); return dateTime.getTime(); } protected Person createPerson(final String firstName, final String lastName) { return createPerson(firstName, lastName, null); } protected Person createPerson(final String firstName, final String lastName, final Date birthDate) { return new Person(firstName, lastName, birthDate); } protected RestTemplate createRestTemplate() { MappingJackson2HttpMessageConverter httpMessageConverter = new MappingJackson2HttpMessageConverter(); httpMessageConverter.setObjectMapper(getObjectMapper()); return setErrorHandler( new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(httpMessageConverter))); } @SuppressWarnings("deprecation") private RestTemplate setErrorHandler(final RestTemplate restTemplate) { restTemplate.setErrorHandler(new ResponseErrorHandler() { private final Set<HttpStatus> errorStatuses = new HashSet<>(); /* non-static */ { errorStatuses.add(HttpStatus.BAD_REQUEST); errorStatuses.add(HttpStatus.UNAUTHORIZED); errorStatuses.add(HttpStatus.FORBIDDEN); errorStatuses.add(HttpStatus.NOT_FOUND); errorStatuses.add(HttpStatus.METHOD_NOT_ALLOWED); errorStatuses.add(HttpStatus.NOT_ACCEPTABLE); errorStatuses.add(HttpStatus.REQUEST_TIMEOUT); errorStatuses.add(HttpStatus.CONFLICT); errorStatuses.add(HttpStatus.REQUEST_ENTITY_TOO_LARGE); errorStatuses.add(HttpStatus.REQUEST_URI_TOO_LONG); errorStatuses.add(HttpStatus.UNSUPPORTED_MEDIA_TYPE); errorStatuses.add(HttpStatus.TOO_MANY_REQUESTS); errorStatuses.add(HttpStatus.INTERNAL_SERVER_ERROR); errorStatuses.add(HttpStatus.NOT_IMPLEMENTED); errorStatuses.add(HttpStatus.BAD_GATEWAY); errorStatuses.add(HttpStatus.SERVICE_UNAVAILABLE); } @Override public boolean hasError(final ClientHttpResponse response) throws IOException { return errorStatuses.contains(response.getStatusCode()); } @Override public void handleError(final ClientHttpResponse response) throws IOException { System.err.printf("%1$d - %2$s%n", response.getRawStatusCode(), response.getStatusText()); System.err.println(readBody(response)); } private String readBody(final ClientHttpResponse response) throws IOException { BufferedReader responseBodyReader = null; try { responseBodyReader = new BufferedReader(new InputStreamReader(response.getBody())); StringBuilder buffer = new StringBuilder(); String line; while ((line = responseBodyReader.readLine()) != null) { buffer.append(line).append(System.getProperty("line.separator")); } return buffer.toString().trim(); } finally { FileSystemUtils.close(responseBodyReader); } } }); return restTemplate; } @Test public void testRegionObjectWithDatePropertyAccessedWithRestApi() throws Exception { String key = "1"; Person jonDoe = createPerson("Jon", "Doe", createDate(1977, Calendar.OCTOBER, 31)); assertTrue(getPeopleRegion().isEmpty()); getPeopleRegion().put(key, jonDoe); assertFalse(getPeopleRegion().isEmpty()); assertEquals(1, getPeopleRegion().size()); assertTrue(getPeopleRegion().containsKey(key)); Object jonDoeRef = getPeopleRegion().get(key); assertTrue(jonDoeRef instanceof PdxInstance); assertEquals(jonDoe.getClass().getName(), ((PdxInstance) jonDoeRef).getClassName()); assertEquals(jonDoe.getFirstName(), ((PdxInstance) jonDoeRef).getField("firstName")); assertEquals(jonDoe.getLastName(), ((PdxInstance) jonDoeRef).getField("lastName")); assertEquals(jonDoe.getBirthDate(), ((PdxInstance) jonDoeRef).getField("birthDate")); RestTemplate restTemplate = createRestTemplate(); Person jonDoeResource = restTemplate.getForObject(getRegionGetRestApiEndpoint(getPeopleRegion(), key), Person.class); assertNotNull(jonDoeResource); assertNotSame(jonDoe, jonDoeResource); assertEquals(jonDoe, jonDoeResource); /* Object result = runQueryUsingApi(getPeopleRegion().getRegionService(), String.format("SELECT * FROM %1$s", getPeopleRegion().getFullPath())); System.out.printf("(OQL Query using API) Person is (%1$s)%n", result); */ String url = getAdhocQueryRestApiEndpoint( String.format("SELECT * FROM %1$s", getPeopleRegion().getFullPath())); System.out.printf("URL (%1$s)%n", url); List<?> queryResults = restTemplate.getForObject(url, List.class); assertNotNull(queryResults); assertFalse(queryResults.isEmpty()); assertEquals(1, queryResults.size()); jonDoeResource = objectMapper.convertValue(queryResults.get(0), Person.class); assertNotNull(jonDoeResource); assertNotSame(jonDoe, jonDoeResource); assertEquals(jonDoe, jonDoeResource); } private Object runQueryUsingApi(final RegionService regionService, final String queryString) throws Exception { return regionService.getQueryService().newQuery(queryString).execute(); } //@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE) //@JsonIgnoreProperties(ignoreUnknown = true) //@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@type") public static class Person { protected static final String DEFAULT_BIRTH_DATE_FORMAT_PATTERN = "MM/dd/yyyy"; private Date birthDate; private String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this(firstName, lastName, null); } public Person(final String firstName, final String lastName, final Date birthDate) { setFirstName(firstName); setLastName(lastName); setBirthDate(birthDate); } public Date getBirthDate() { return birthDate; } public void setBirthDate(final Date birthDate) { Assert.isTrue(birthDate == null || birthDate.compareTo(Calendar.getInstance().getTime()) <= 0, "A Person's date of birth cannot be after today!"); this.birthDate = birthDate; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { Assert.hasText(firstName, "The Person must have a first name!"); this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { Assert.hasText(firstName, "The Person must have a last name!"); this.lastName = lastName; } protected final String format(final Date dateTime) { return format(dateTime, DEFAULT_BIRTH_DATE_FORMAT_PATTERN); } protected String format(final Date dateTime, final String dateFormatPattern) { return (dateTime == null ? null : new SimpleDateFormat(StringUtils.hasText(dateFormatPattern) ? dateFormatPattern : DEFAULT_BIRTH_DATE_FORMAT_PATTERN).format(dateTime)); } @Override public boolean equals(final Object obj) { if (obj == this) { return true; } if (!(obj instanceof Person)) { return false; } Person that = (Person) obj; return ObjectUtils.nullSafeEquals(this.getFirstName(), that.getFirstName()) && ObjectUtils.nullSafeEquals(this.getLastName(), that.getLastName()) && ObjectUtils.nullSafeEquals(this.getBirthDate(), that.getBirthDate()); } @Override public int hashCode() { int hashValue = 17; hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getFirstName()); hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getLastName()); hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getBirthDate()); return hashValue; } @Override public String toString() { return String.format("{ @type = %1$s, firstName = %2$s, lastName = %3$s, birthDate = %4$s }", getClass().getName(), getFirstName(), getLastName(), format(getBirthDate())); } } }