/*
 * 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.geode.rest.internal.web.controllers;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import org.apache.geode.SerializationException;
import org.apache.geode.cache.CacheLoaderException;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.LowMemoryException;
import org.apache.geode.cache.PartitionedRegionStorageException;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.TimeoutException;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.LeaseExpiredException;
import org.apache.geode.distributed.internal.ClusterDistributionManager;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.InternalCacheForClientAccess;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.pdx.JSONFormatter;
import org.apache.geode.pdx.JSONFormatterException;
import org.apache.geode.pdx.PdxInstance;
import org.apache.geode.rest.internal.web.controllers.support.CacheProvider;
import org.apache.geode.rest.internal.web.controllers.support.JSONTypes;
import org.apache.geode.rest.internal.web.controllers.support.UpdateOp;
import org.apache.geode.rest.internal.web.exception.DataTypeNotSupportedException;
import org.apache.geode.rest.internal.web.exception.GemfireRestException;
import org.apache.geode.rest.internal.web.exception.MalformedJsonException;
import org.apache.geode.rest.internal.web.exception.RegionNotFoundException;
import org.apache.geode.rest.internal.web.exception.ResourceNotFoundException;
import org.apache.geode.rest.internal.web.security.RestSecurityService;
import org.apache.geode.rest.internal.web.util.ArrayUtils;
import org.apache.geode.rest.internal.web.util.IdentifiableUtils;
import org.apache.geode.rest.internal.web.util.JSONUtils;
import org.apache.geode.rest.internal.web.util.NumberUtils;
import org.apache.geode.rest.internal.web.util.ValidationUtils;
import org.apache.geode.util.internal.GeodeConverter;

/**
 * AbstractBaseController class contains common functionalities required for other controllers.
 *
 * @since GemFire 8.0
 */
@SuppressWarnings("unused")
public abstract class AbstractBaseController implements InitializingBean {

  private static final String NEW_META_DATA_PROPERTY = "@new";
  private static final String OLD_META_DATA_PROPERTY = "@old";
  private static final String TYPE_META_DATA_PROPERTY = "@type";
  private static final String UTF_8 = "UTF-8";
  private static final String DEFAULT_ENCODING = UTF_8;
  private static final Logger logger = LogService.getLogger();
  private static final AtomicLong ID_SEQUENCE = new AtomicLong(0l);

  @Autowired
  protected RestSecurityService securityService;
  @Autowired
  private ObjectMapper objectMapper;
  @Autowired
  private CacheProvider cacheProvider;

  @Override
  public void afterPropertiesSet() {
    JSONUtils.setObjectMapper(objectMapper);
  }

  protected InternalCacheForClientAccess getCache() {
    InternalCacheForClientAccess cache = cacheProvider.getCache();
    Assert.state(cache != null, "The Gemfire Cache reference was not properly initialized");
    return cache;
  }

  URI toUri(final String... pathSegments) {
    return ServletUriComponentsBuilder.fromCurrentContextPath().path(getRestApiVersion())
        .pathSegment(pathSegments).build().toUri();
  }

  protected abstract String getRestApiVersion();

  String validateQuery(String queryInUrl, String queryInBody) {

    if (!(StringUtils.hasText(queryInUrl) || StringUtils.hasText(queryInBody))) {
      throw new GemfireRestException("could not process null value specified in query String");
    }
    return (StringUtils.hasText(queryInUrl) ? decode(queryInUrl) : queryInBody);
  }

  String decode(final String value) {
    if (value == null) {
      throw new GemfireRestException("could not process null value specified in query String");
    }

    return decode(value, DEFAULT_ENCODING);
  }

  protected PdxInstance convert(final String json) {
    try {
      return (StringUtils.hasText(json) ? JSONFormatter.fromJSON(json) : null);
    } catch (JSONFormatterException jpe) {
      throw new MalformedJsonException("Json doc specified is either not supported or invalid!",
          jpe);
    }
  }

  protected String convert(final PdxInstance pdxObj) {
    try {
      return (pdxObj != null ? JSONFormatter.toJSON(pdxObj) : null);
    } catch (JSONFormatterException jpe) {
      throw new GemfireRestException("Requested data could not convert into REST format(JSON)!",
          jpe);
    }
  }

  protected String convert(final Iterable<PdxInstance> pdxObjs) {
    final StringBuilder buffer = new StringBuilder("[");
    int count = 0;

    for (final PdxInstance pdxObj : pdxObjs) {
      final String json = convert(pdxObj);

      if (StringUtils.hasText(json)) {
        buffer.append(count++ > 0 ? ", " : "").append(json);
      }
    }

    buffer.append("]");

    return buffer.toString();
  }

  @SuppressWarnings("unchecked")
  private <T> T casValue(String regionNamePath, String key, String jsonData) {
    try {
      JsonNode jsonObject = objectMapper.readTree(jsonData);
      JsonNode oldValue = jsonObject.get("@old");
      JsonNode newValue = jsonObject.get("@new");

      if (oldValue == null || newValue == null) {
        throw new MalformedJsonException("Json doc specified in request body is invalid!");
      }

      return (T) casValue(regionNamePath, key, convert(oldValue.toString()),
          convert(newValue.toString()));

    } catch (IOException je) {
      throw new MalformedJsonException("Json doc specified in request body is invalid!", je);
    }
  }

  ResponseEntity<String> processQueryResponse(Query query, Object args[], Object queryResult) {
    if (queryResult instanceof Collection<?>) {
      Collection processedResults = new ArrayList(((Collection) queryResult).size());
      for (Object result : (Collection) queryResult) {
        processedResults.add(securityService.postProcess(null, null, result, false));
      }
      String queryResultAsJson = JSONUtils.convertCollectionToJson(processedResults);

      final HttpHeaders headers = new HttpHeaders();
      headers.setLocation(toUri("queries", query.getQueryString()));
      return new ResponseEntity<>(queryResultAsJson, headers, HttpStatus.OK);
    } else {
      throw new GemfireRestException(
          "Server has encountered error while generating query result into restful format(JSON)!");
    }
  }

  Collection<PdxInstance> convertJsonArrayIntoPdxCollection(final String jsonArray) {
    try {
      JsonNode array = objectMapper.readTree(jsonArray);
      if (!array.isArray()) {
        throw new MalformedJsonException(
            "Json document specified in request body is not an array!");
      }

      Collection<PdxInstance> pdxInstances = new ArrayList<>();

      for (int index = 0; index < array.size(); index++) {
        JsonNode object = array.get(index);
        String element = objectMapper.writeValueAsString(object);

        PdxInstance pi = convert(element);
        pdxInstances.add(pi);
      }
      return pdxInstances;

    } catch (IOException je) {
      throw new MalformedJsonException("Json document specified in request body is not valid!", je);
    }
  }

  private Object casValue(final String regionNamePath, final Object key, final Object oldValue,
      final Object newValue) {
    final Region<Object, Object> region = getRegion(regionNamePath);
    try {
      return (region.replace(key, oldValue, newValue) ? null : region.get(key));
    } catch (UnsupportedOperationException use) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not support the requested operation!",
              regionNamePath),
          use);
    } catch (ClassCastException cce) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow to store specified key or value type in this region!",
          regionNamePath), cce);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys or values!",
              regionNamePath),
          npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration prevents specified data from being stored in it!",
          regionNamePath), iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (CacheWriterException cwe) {
      throw new GemfireRestException(
          "Server has encountered CacheWriter error while processing this request!", cwe);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException(
          "Requested operation could not be completed on a partitioned region!", prse);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  private void replaceValue(final String regionNamePath, final Object key,
      final PdxInstance value) {
    try {
      if (getRegion(regionNamePath).replace(key, value) == null) {
        throw new ResourceNotFoundException(String.format("No resource at (%1$s) exists!",
            toUri(regionNamePath, String.valueOf(key))));
      }
    } catch (UnsupportedOperationException use) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not support the requested operation!",
              regionNamePath),
          use);
    } catch (ClassCastException cce) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow to store specified key or value type in this region!",
          regionNamePath), cce);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys or values!",
              regionNamePath),
          npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration prevents specified data from being stored in it!",
          regionNamePath), iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (CacheWriterException cwe) {
      throw new GemfireRestException(
          "Server has encountered CacheWriter error while processing this request!", cwe);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException(
          "Requested operation could not be completed on a partitioned region!", prse);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  protected void replaceValue(final String regionNamePath, final Object key, final Object value) {
    // still do we need to worry for race condition..?
    try {
      if (getRegion(regionNamePath).replace(key, value) == null) {
        throw new ResourceNotFoundException(String.format("No resource at (%1$s) exists!",
            toUri(regionNamePath, String.valueOf(key))));
      }
    } catch (UnsupportedOperationException use) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not support the requested operation!",
              regionNamePath),
          use);
    } catch (ClassCastException cce) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow to store specified key or value type in this region!",
          regionNamePath), cce);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys or values!",
              regionNamePath),
          npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration prevents specified data from being stored in it!",
          regionNamePath), iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (CacheWriterException cwe) {
      throw new GemfireRestException(
          "Server has encountered CacheWriter error while processing this request!", cwe);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException(
          "Requested operation could not be completed on a partitioned region!", prse);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  private void putValue(final String regionNamePath, final Object key, final Object value) {
    try {
      getRegion(regionNamePath).put(key, value);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys or values!",
              regionNamePath),
          npe);
    } catch (ClassCastException cce) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow to store specified key or value type in this region!",
          regionNamePath), cce);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (CacheWriterException cwe) {
      throw new GemfireRestException(
          "Server has encountered CacheWriter error while processing this request!", cwe);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException(
          "Requested operation could not be completed on a partitioned region!", prse);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  private void deleteQueryId(final String regionNamePath, final String key) {
    getQueryStore(regionNamePath).remove(key);
  }

  void deleteNamedQuery(final String regionNamePath, final String key) {
    // Check whether query ID exist in region or not
    checkForQueryIdExist(regionNamePath, key);
    deleteQueryId(regionNamePath, key);
  }

  void checkForQueryIdExist(String region, String key) {
    if (!getQueryStore(region).containsKey(key)) {
      throw new ResourceNotFoundException(String.format("Named query (%1$s) does not exist!", key));
    }
  }

  Region<String, String> getQueryStore(final String namePath) {
    return ValidationUtils.returnValueThrowOnNull(getCache().getInternalRegion(namePath),
        new GemfireRestException(String.format("Query store (%1$s) does not exist!", namePath)));
  }

  protected String getQueryIdValue(final String regionNamePath, final String key) {
    Assert.notNull(key, "queryId cannot be null!");
    try {
      return getQueryStore(regionNamePath).get(key);
    } catch (NullPointerException npe) {
      throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException("Server has not allowed to perform the requested operation!",
          iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException te) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", te);
    }
  }

  void updateNamedQuery(final String regionNamePath, final String key, final String value) {
    try {
      getQueryStore(regionNamePath).put(key, value);
    } catch (NullPointerException npe) {
      throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
    } catch (ClassCastException cce) {
      throw new GemfireRestException("specified queryId or query string is not supported!", cce);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  @SuppressWarnings("unchecked")
  <T> T createNamedQuery(final String regionNamePath, final String key, final String value) {
    try {
      return (T) getQueryStore(regionNamePath).putIfAbsent(key, value);
    } catch (UnsupportedOperationException use) {
      throw new GemfireRestException("Requested operation is not supported!", use);
    } catch (ClassCastException cce) {
      throw new GemfireRestException("Specified queryId or query string is not supported!", cce);
    } catch (NullPointerException npe) {
      throw new GemfireRestException("NULL query ID or query string is not supported!", npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(
          "Configuration does not allow to perform the requested operation!", iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  private void putPdxValues(final String regionNamePath, final Map<Object, PdxInstance> map) {
    try {
      getRegion(regionNamePath).putAll(map);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException("low memory condition is detected.", lme);
    }
  }

  private void putValues(final String regionNamePath, final Map<Object, Object> values) {
    getRegion(regionNamePath).putAll(values);
  }

  protected void putValues(final String regionNamePath, String[] keys, List<?> values) {
    Map<Object, Object> map = new HashMap<Object, Object>();
    if (keys.length != values.size()) {
      throw new GemfireRestException("Bad request, Keys and Value size does not match");
    }
    for (int i = 0; i < keys.length; i++) {
      Object domainObj = introspectAndConvert(values.get(i));
      map.put(keys[i], domainObj);
    }

    if (!map.isEmpty()) {
      putValues(regionNamePath, map);
    }
  }

  @SuppressWarnings("unchecked")
  <T> T postValue(final String regionNamePath, final Object key, final Object value) {
    try {
      return (T) getRegion(regionNamePath).putIfAbsent(key, value);
    } catch (UnsupportedOperationException use) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not support the requested operation!",
              regionNamePath),
          use);
    } catch (ClassCastException cce) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow to store specified key or value type in this region!",
          regionNamePath), cce);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys or values!",
              regionNamePath),
          npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration prevents specified data from being stored in it!",
          regionNamePath), iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException toe) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", toe);
    } catch (CacheWriterException cwe) {
      throw new GemfireRestException(
          "Server has encountered CacheWriter error while processing this request!", cwe);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException(
          "Requested operation could not be completed on a partitioned region!", prse);
    } catch (LowMemoryException lme) {
      throw new GemfireRestException(
          "Server has detected low memory while processing this request!", lme);
    }
  }

  protected Object getActualTypeValue(final String value, final String valueType) {
    Object actualValue = value;
    if (valueType != null) {
      try {
        actualValue = GeodeConverter.convertToActualType(value, valueType);
      } catch (IllegalArgumentException ie) {
        throw new GemfireRestException(ie.getMessage(), ie);
      }
    }
    return actualValue;
  }

  String generateKey(final String existingKey) {
    return generateKey(existingKey, null);
  }

  private String generateKey(final String existingKey, final Object domainObject) {
    Object domainObjectId = IdentifiableUtils.getId(domainObject);
    String newKey;

    if (StringUtils.hasText(existingKey)) {
      newKey = existingKey;
      if (NumberUtils.isNumeric(newKey) && domainObjectId == null) {
        final Long newId = IdentifiableUtils.createId(NumberUtils.parseLong(newKey));
        if (newKey.equals(newId.toString())) {
          IdentifiableUtils.setId(domainObject, newId);
        }
      }
    } else if (domainObjectId != null) {
      final Long domainObjectIdAsLong = NumberUtils.longValue(domainObjectId);
      if (domainObjectIdAsLong != null) {
        final Long newId = IdentifiableUtils.createId(domainObjectIdAsLong);
        if (!domainObjectIdAsLong.equals(newId)) {
          IdentifiableUtils.setId(domainObject, newId);
        }
        newKey = String.valueOf(newId);
      } else {
        newKey = String.valueOf(domainObjectId);
      }
    } else {
      domainObjectId = IdentifiableUtils.createId();
      newKey = String.valueOf(domainObjectId);
      IdentifiableUtils.setId(domainObject, domainObjectId);
    }

    return newKey;
  }

  private String decode(final String value, final String encoding) {
    try {
      return URLDecoder.decode(value, encoding);
    } catch (UnsupportedEncodingException e) {
      throw new GemfireRestException("Server has encountered unsupported encoding!");
    }
  }

  @SuppressWarnings("unchecked")
  protected <T> Region<Object, T> getRegion(final String namePath) {
    return (Region<Object, T>) ValidationUtils
        .returnValueThrowOnNull(getCache().getRegion(namePath), new RegionNotFoundException(
            String.format("The Region identified by name (%1$s) could not be found!", namePath)));
  }

  private void checkForKeyExist(String region, String key) {
    if (!getRegion(region).containsKey(key)) {
      throw new ResourceNotFoundException(
          String.format("Key (%1$s) does not exist for region (%2$s) in cache!", key, region));
    }
  }

  List<String> checkForMultipleKeysExist(String region, String... keys) {
    List<String> unknownKeys = new ArrayList<String>();
    for (int index = 0; index < keys.length; index++) {
      if (!getRegion(region).containsKey(keys[index])) {
        unknownKeys.add(keys[index]);
      }
    }
    return unknownKeys;
  }

  protected Object[] getKeys(final String regionNamePath, Object[] keys) {
    return (!(keys == null || keys.length == 0) ? keys
        : getRegion(regionNamePath).keySet().toArray());
  }

  protected <T> Map<Object, T> getValues(final String regionNamePath, Object... keys) {
    try {
      final Region<Object, T> region = getRegion(regionNamePath);
      final Map<Object, T> entries = region.getAll(Arrays.asList(getKeys(regionNamePath, keys)));
      for (Object key : entries.keySet()) {
        entries.put(key,
            (T) securityService.postProcess(regionNamePath, key, entries.get(key), false));
      }
      return entries;
    } catch (SerializationException se) {
      throw new DataTypeNotSupportedException(
          "The resource identified could not convert into the supported content characteristics (JSON)!",
          se);
    }
  }

  protected <T> Map<Object, T> getValues(final String regionNamePath, String... keys) {
    return getValues(regionNamePath, (Object[]) keys);
  }

  protected <T extends PdxInstance> Collection<T> getPdxValues(final String regionNamePath,
      final Object... keys) {
    final Region<Object, T> region = getRegion(regionNamePath);
    final Map<Object, T> entries = region.getAll(Arrays.asList(getKeys(regionNamePath, keys)));

    return entries.values();
  }

  private void deleteValue(final String regionNamePath, final Object key) {
    getRegion(regionNamePath).remove(key);
  }

  void deleteValues(final String regionNamePath, final Object... keys) {
    // Check whether all keys exist in cache or not
    for (final Object key : keys) {
      checkForKeyExist(regionNamePath, key.toString());
    }

    for (final Object key : keys) {
      deleteValue(regionNamePath, key);
    }
  }

  void deleteValues(String regionNamePath) {
    try {
      getRegion(regionNamePath).clear();
    } catch (UnsupportedOperationException ue) {
      throw new GemfireRestException("Requested operation not allowed on partition region", ue);
    }
  }

  private boolean isForm(final Map<Object, Object> rawDataBinding) {
    return (!rawDataBinding.containsKey(TYPE_META_DATA_PROPERTY)
        && rawDataBinding.containsKey(OLD_META_DATA_PROPERTY)
        && rawDataBinding.containsKey(NEW_META_DATA_PROPERTY));
  }

  @SuppressWarnings("unchecked")
  private <T> T introspectAndConvert(final T value) {
    if (value instanceof Map) {
      final Map rawDataBinding = (Map) value;

      if (isForm(rawDataBinding)) {
        rawDataBinding.put(OLD_META_DATA_PROPERTY,
            introspectAndConvert(rawDataBinding.get(OLD_META_DATA_PROPERTY)));
        rawDataBinding.put(NEW_META_DATA_PROPERTY,
            introspectAndConvert(rawDataBinding.get(NEW_META_DATA_PROPERTY)));

        return (T) rawDataBinding;
      } else {
        final String typeValue = (String) rawDataBinding.get(TYPE_META_DATA_PROPERTY);
        if (typeValue == null) {
          return (T) new Object();
        }
        // Added for the primitive types put. Not supporting primitive types
        if (NumberUtils.isPrimitiveOrObject(typeValue)) {
          final Object primitiveValue = rawDataBinding.get("@value");
          try {
            return (T) GeodeConverter.convertToActualType(primitiveValue.toString(), typeValue);
          } catch (IllegalArgumentException e) {
            throw new GemfireRestException(
                "Server has encountered error (illegal or inappropriate arguments).", e);
          }
        } else {
          Assert.state(
              ClassUtils.isPresent(typeValue,
                  Thread.currentThread().getContextClassLoader()),
              String.format("Class (%1$s) could not be found!", typeValue));

          return (T) objectMapper.convertValue(rawDataBinding, ClassUtils.resolveClassName(
              typeValue, Thread.currentThread().getContextClassLoader()));
        }
      }
    }

    return value;
  }

  String convertErrorAsJson(String errorMessage) {
    return ("{" + "\"cause\"" + ":" + "\"" + errorMessage + "\"" + "}");
  }

  String convertErrorAsJson(Throwable t) {
    return String.format("{\"message\" : \"%1$s\"}", t.getMessage());
  }

  private Map<?, ?> convertJsonToMap(final String jsonString) {
    Map<String, String> map = new HashMap<String, String>();

    // convert JSON string to Map
    try {
      map = objectMapper.readValue(jsonString, new TypeReference<HashMap<String, String>>() {});
    } catch (JsonParseException e) {
      throw new MalformedJsonException(
          "Bind params specified as JSON document in the request is incorrect!", e);
    } catch (JsonMappingException e) {
      throw new MalformedJsonException(
          "Server unable to process bind params specified as JSON document in the request!", e);
    } catch (IOException e) {
      throw new GemfireRestException("Server has encountered error while process this request!", e);
    }
    return map;
  }

  private Object jsonToObject(final String jsonString) {
    return introspectAndConvert(convertJsonToMap(jsonString));
  }

  Object[] jsonToObjectArray(final String arguments) {
    JsonNode node;
    try {
      node = objectMapper.readTree(arguments);
    } catch (IOException e) {
      throw new MalformedJsonException("Json document specified in request body is not valid!");
    }

    if (node.isArray()) {
      try {
        Object[] args = new Object[node.size()];
        for (int index = 0; index < node.size(); index++) {
          args[index] = jsonToObject(objectMapper.writeValueAsString(node.get(index)));
        }
        return args;
      } catch (JsonProcessingException je) {
        throw new MalformedJsonException("Json document specified in request body is not valid!",
            je);
      }
    } else if (node.isObject()) {
      return new Object[] {jsonToObject(arguments)};
    } else {
      throw new MalformedJsonException("Json document specified in request body is not valid!");
    }
  }

  ResponseEntity<String> updateSingleKey(final String region, final String key, final String json,
      final String opValue) {

    final JSONTypes jsonType = validateJsonAndFindType(json);

    final UpdateOp op = UpdateOp.valueOf(opValue.toUpperCase());
    String existingValue = null;

    switch (op) {
      case CAS:
        PdxInstance existingPdxObj = casValue(region, key, json);
        existingValue = convert(existingPdxObj);
        break;

      case REPLACE:
        replaceValue(region, key, convert(json));
        break;

      case PUT:
      default:
        if (JSONTypes.JSON_ARRAY.equals(jsonType)) {
          putValue(region, key, convertJsonArrayIntoPdxCollection(json));
          // putValue(region, key, convertJsonIntoPdxCollection(json));
        } else {
          putValue(region, key, convert(json));
        }
    }

    final HttpHeaders headers = new HttpHeaders();
    headers.setLocation(toUri(region, key));
    return new ResponseEntity<String>(existingValue, headers,
        (existingValue == null ? HttpStatus.OK : HttpStatus.CONFLICT));
  }


  ResponseEntity<String> updateMultipleKeys(final String region, final String[] keys,
      final String json) {

    JsonNode jsonArr;
    try {
      jsonArr = objectMapper.readTree(json);
    } catch (IOException e) {
      throw new MalformedJsonException("JSON document specified in the request is incorrect", e);
    }

    if (!jsonArr.isArray() || jsonArr.size() != keys.length) {
      throw new MalformedJsonException(
          "Each key must have corresponding value (JSON document) specified in the request");
    }

    Map<Object, PdxInstance> map = new HashMap<Object, PdxInstance>();
    for (int i = 0; i < keys.length; i++) {
      if (logger.isDebugEnabled()) {
        logger.debug("Updating (put) Json document ({}) having key ({}) in Region ({})", json,
            keys[i], region);
      }

      try {
        PdxInstance pdxObj = convert(objectMapper.writeValueAsString(jsonArr.get(i)));
        map.put(keys[i], pdxObj);
      } catch (JsonProcessingException e) {
        throw new MalformedJsonException(
            String.format("JSON document at index (%1$s) in the request body is incorrect", i), e);
      }
    }

    if (!CollectionUtils.isEmpty(map)) {
      putPdxValues(region, map);
    }

    HttpHeaders headers = new HttpHeaders();
    headers.setLocation(toUri(region, StringUtils.arrayToCommaDelimitedString(keys)));
    return new ResponseEntity<>(headers, HttpStatus.OK);
  }

  JSONTypes validateJsonAndFindType(String json) {
    try {
      JsonParser jp = new JsonFactory().createParser(json);
      JsonToken token = jp.nextToken();

      if (token == JsonToken.START_OBJECT) {
        return JSONTypes.JSON_OBJECT;
      } else if (token == JsonToken.START_ARRAY) {
        return JSONTypes.JSON_ARRAY;
      } else {
        return JSONTypes.UNRECOGNIZED_JSON;
      }
    } catch (IOException je) {
      throw new MalformedJsonException("JSON document specified in the request is incorrect", je);
    }
  }

  protected QueryService getQueryService() {
    return getCache().getQueryService();
  }

  @SuppressWarnings("unchecked")
  protected <T> T getValue(final String regionNamePath, final Object key) {
    return getValue(regionNamePath, key, true);
  }

  protected <T> T getValue(final String regionNamePath, final Object key, boolean postProcess) {
    Assert.notNull(key, "The Cache Region key to read the value for cannot be null!");

    Region r = getRegion(regionNamePath);
    try {
      Object value = r.get(key);
      if (postProcess) {
        return (T) securityService.postProcess(regionNamePath, key, value, false);
      } else {
        return (T) value;
      }
    } catch (SerializationException se) {
      throw new DataTypeNotSupportedException(
          "The resource identified could not convert into the supported content characteristics (JSON)!",
          se);
    } catch (NullPointerException npe) {
      throw new GemfireRestException(
          String.format("Resource (%1$s) configuration does not allow null keys!", regionNamePath),
          npe);
    } catch (IllegalArgumentException iae) {
      throw new GemfireRestException(String.format(
          "Resource (%1$s) configuration does not allow requested operation on specified key!",
          regionNamePath), iae);
    } catch (LeaseExpiredException lee) {
      throw new GemfireRestException("Server has encountered error while processing this request!",
          lee);
    } catch (TimeoutException te) {
      throw new GemfireRestException(
          "Server has encountered timeout error while processing this request!", te);
    } catch (CacheLoaderException cle) {
      throw new GemfireRestException(
          "Server has encountered CacheLoader error while processing this request!", cle);
    } catch (PartitionedRegionStorageException prse) {
      throw new GemfireRestException("CacheLoader could not be invoked on partitioned region!",
          prse);
    }

  }

  protected Set<DistributedMember> getMembers(final String... memberIdNames) {
    ValidationUtils.returnValueThrowOnNull(memberIdNames,
        new GemfireRestException("No member found to run function"));
    final Set<DistributedMember> targetedMembers = new HashSet<>(ArrayUtils.length(memberIdNames));
    final List<String> memberIdNameList = Arrays.asList(memberIdNames);

    InternalCache cache = getCache();
    Set<DistributedMember> distMembers = cache.getDistributedSystem().getAllOtherMembers();

    // Add the local node to list
    distMembers.add(cache.getDistributedSystem().getDistributedMember());
    for (DistributedMember member : distMembers) {
      if (memberIdNameList.contains(member.getId())
          || memberIdNameList.contains(member.getName())) {
        targetedMembers.add(member);
      }
    }
    return targetedMembers;
  }

  Set<DistributedMember> getAllMembersInDS() {
    InternalCache cache = getCache();
    Set<DistributedMember> distMembers = cache.getDistributedSystem().getAllOtherMembers();
    final Set<DistributedMember> targetedMembers = new HashSet<>();

    // find valid data nodes, i.e non locator, non-admin, non-loner nodes
    for (DistributedMember member : distMembers) {
      InternalDistributedMember idm = (InternalDistributedMember) member;
      if (idm.getVmKind() == ClusterDistributionManager.NORMAL_DM_TYPE) {
        targetedMembers.add(member);
      }
    }
    // Add the local node to list
    targetedMembers.add(cache.getDistributedSystem().getDistributedMember());
    return targetedMembers;
  }
}
