/*
* 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.management.internal.cli.functions;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.subject.Subject;
import org.json.JSONArray;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.execute.FunctionAdapter;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.cache.partition.PartitionRegionHelper;
import org.apache.geode.cache.query.FunctionDomainException;
import org.apache.geode.cache.query.NameResolutionException;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.QueryInvocationTargetException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.cache.query.Struct;
import org.apache.geode.cache.query.TypeMismatchException;
import org.apache.geode.cache.query.internal.CompiledValue;
import org.apache.geode.cache.query.internal.DefaultQuery;
import org.apache.geode.cache.query.internal.IndexTrackingQueryObserver;
import org.apache.geode.cache.query.internal.QCompiler;
import org.apache.geode.cache.query.internal.QueryObserver;
import org.apache.geode.cache.query.internal.QueryObserverHolder;
import org.apache.geode.cache.query.internal.StructImpl;
import org.apache.geode.cache.query.internal.Undefined;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.internal.InternalEntity;
import org.apache.geode.internal.NanoTimer;
import org.apache.geode.internal.cache.PartitionedRegion;
import org.apache.geode.internal.logging.LogService;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.management.cli.Result;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.commands.DataCommands;
import org.apache.geode.management.internal.cli.domain.DataCommandRequest;
import org.apache.geode.management.internal.cli.domain.DataCommandResult;
import org.apache.geode.management.internal.cli.domain.DataCommandResult.SelectResultRow;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.json.GfJsonException;
import org.apache.geode.management.internal.cli.json.GfJsonObject;
import org.apache.geode.management.internal.cli.multistep.CLIMultiStepHelper;
import org.apache.geode.management.internal.cli.remote.CommandExecutionContext;
import org.apache.geode.management.internal.cli.result.CommandResult;
import org.apache.geode.management.internal.cli.result.CompositeResultData;
import org.apache.geode.management.internal.cli.result.CompositeResultData.SectionResultData;
import org.apache.geode.management.internal.cli.result.ResultBuilder;
import org.apache.geode.management.internal.cli.shell.Gfsh;
import org.apache.geode.management.internal.cli.util.JsonUtil;
import org.apache.geode.pdx.PdxInstance;
/**
* @since GemFire 7.0
*/
public class DataCommandFunction extends FunctionAdapter implements InternalEntity {
private static final Logger logger = LogService.getLogger();
private static final long serialVersionUID = 1L;
private boolean optimizeForWrite = false;
protected static final String SELECT_STEP_DISPLAY = "SELECT_DISPLAY";
protected static final String SELECT_STEP_MOVE = "SELECT_PAGE_MOVE";
protected static final String SELECT_STEP_END = "SELECT_END";
protected static final String SELECT_STEP_EXEC = "SELECT_EXEC";
private static final int NESTED_JSON_LENGTH = 20;
// this needs to be static so that it won't get serialized
private static SecurityService securityService = SecurityService.getSecurityService();
@Override
public String getId() {
return DataCommandFunction.class.getName();
}
@Override
public boolean hasResult() {
return true;
}
@Override
public boolean isHA() {
return false;
}
@Override
/**
* Read only function
*/
public boolean optimizeForWrite() {
return optimizeForWrite;
}
public void setOptimizeForWrite(boolean optimizeForWrite) {
this.optimizeForWrite = optimizeForWrite;
}
@Override
public void execute(FunctionContext functionContext) {
try {
Cache cache = CacheFactory.getAnyInstance();
DataCommandRequest request = (DataCommandRequest) functionContext.getArguments();
if (logger.isDebugEnabled()) {
logger.debug("Executing function : \n{}\n on member {}", request,
System.getProperty("memberName"));
}
DataCommandResult result = null;
if (request.isGet())
result = get(request);
else if (request.isLocateEntry())
result = locateEntry(request);
else if (request.isPut())
result = put(request);
else if (request.isRemove())
result = remove(request);
else if (request.isSelect())
result = select(request);
if (logger.isDebugEnabled()) {
logger.debug("Result is {}", result);
}
functionContext.getResultSender().lastResult(result);
} catch (CacheClosedException e) {
e.printStackTrace();
functionContext.getResultSender().sendException(e);
} catch (Exception e) {
e.printStackTrace();
functionContext.getResultSender().sendException(e);
}
}
public DataCommandResult remove(DataCommandRequest request) {
String key = request.getKey();
String keyClass = request.getKeyClass();
String regionName = request.getRegionName();
String removeAllKeys = request.getRemoveAllKeys();
return remove(key, keyClass, regionName, removeAllKeys);
}
public DataCommandResult get(DataCommandRequest request) {
String key = request.getKey();
String keyClass = request.getKeyClass();
String valueClass = request.getValueClass();
String regionName = request.getRegionName();
Boolean loadOnCacheMiss = request.isLoadOnCacheMiss();
return get(request.getPrincipal(), key, keyClass, valueClass, regionName, loadOnCacheMiss);
}
public DataCommandResult locateEntry(DataCommandRequest request) {
String key = request.getKey();
String keyClass = request.getKeyClass();
String valueClass = request.getValueClass();
String regionName = request.getRegionName();
boolean recursive = request.isRecursive();
return locateEntry(key, keyClass, valueClass, regionName, recursive);
}
public DataCommandResult put(DataCommandRequest request) {
String key = request.getKey();
String value = request.getValue();
boolean putIfAbsent = request.isPutIfAbsent();
String keyClass = request.getKeyClass();
String valueClass = request.getValueClass();
String regionName = request.getRegionName();
return put(key, value, putIfAbsent, keyClass, valueClass, regionName);
}
public DataCommandResult select(DataCommandRequest request) {
String query = request.getQuery();
return select(request.getPrincipal(), query);
}
/**
* To catch trace output
*/
public static class WrappedIndexTrackingQueryObserver extends IndexTrackingQueryObserver {
@Override
public void reset() {
// NOOP
}
public void reset2() {
super.reset();
}
}
@SuppressWarnings("rawtypes")
private DataCommandResult select(Object principal, String queryString) {
Cache cache = CacheFactory.getAnyInstance();
AtomicInteger nestedObjectCount = new AtomicInteger(0);
if (queryString != null && !queryString.isEmpty()) {
QueryService qs = cache.getQueryService();
// TODO : Find out if is this optimised use. Can you have something equivalent of parsed
// queries with names
// where name can be retrieved to avoid parsing every-time
Query query = qs.newQuery(queryString);
DefaultQuery tracedQuery = (DefaultQuery) query;
WrappedIndexTrackingQueryObserver queryObserver = null;
String queryVerboseMsg = null;
long startTime = -1;
if (tracedQuery.isTraced()) {
startTime = NanoTimer.getTime();
queryObserver = new WrappedIndexTrackingQueryObserver();
QueryObserverHolder.setInstance(queryObserver);
}
List<SelectResultRow> list = new ArrayList<SelectResultRow>();
try {
Object results = query.execute();
if (tracedQuery.isTraced()) {
queryVerboseMsg = getLogMessage(queryObserver, startTime, queryString);
queryObserver.reset2();
}
if (results instanceof SelectResults) {
SelectResults selectResults = (SelectResults) results;
for (Iterator iter = selectResults.iterator(); iter.hasNext();) {
Object object = iter.next();
// Post processing
object = this.securityService.postProcess(principal, null, null, object, false);
if (object instanceof Struct) {
StructImpl impl = (StructImpl) object;
GfJsonObject jsonStruct = getJSONForStruct(impl, nestedObjectCount);
if (logger.isDebugEnabled())
logger.debug("SelectResults : Adding select json string : {}", jsonStruct);
list.add(new SelectResultRow(DataCommandResult.ROW_TYPE_STRUCT_RESULT,
jsonStruct.toString()));
} else {
if (JsonUtil.isPrimitiveOrWrapper(object.getClass())) {
if (logger.isDebugEnabled())
logger.debug("SelectResults : Adding select primitive : {}", object);
list.add(new SelectResultRow(DataCommandResult.ROW_TYPE_PRIMITIVE, object));
} else {
if (logger.isDebugEnabled())
logger.debug("SelectResults : Bean Results class is {}", object.getClass());
String str = toJson(object);
GfJsonObject jsonBean;
try {
jsonBean = new GfJsonObject(str);
} catch (GfJsonException e) {
logger.fatal(e.getMessage(), e);
jsonBean = new GfJsonObject();
try {
jsonBean.put("msg", e.getMessage());
} catch (GfJsonException e1) {
}
}
if (logger.isDebugEnabled())
logger.debug("SelectResults : Adding bean json string : {}", jsonBean);
list.add(new SelectResultRow(DataCommandResult.ROW_TYPE_BEAN, jsonBean.toString()));
}
}
}
} else {
if (logger.isDebugEnabled())
logger.debug("BeanResults : Bean Results class is {}", results.getClass());
String str = toJson(results);
GfJsonObject jsonBean;
try {
jsonBean = new GfJsonObject(str);
} catch (GfJsonException e) {
e.printStackTrace();
jsonBean = new GfJsonObject();
try {
jsonBean.put("msg", e.getMessage());
} catch (GfJsonException e1) {
}
}
if (logger.isDebugEnabled())
logger.debug("BeanResults : Adding bean json string : {}", jsonBean);
list.add(new SelectResultRow(DataCommandResult.ROW_TYPE_BEAN, jsonBean.toString()));
}
return DataCommandResult.createSelectResult(queryString, list, queryVerboseMsg, null, null,
true);
} catch (FunctionDomainException e) {
logger.warn(e.getMessage(), e);
return DataCommandResult.createSelectResult(queryString, null, queryVerboseMsg, e,
e.getMessage(), false);
} catch (TypeMismatchException e) {
logger.warn(e.getMessage(), e);
return DataCommandResult.createSelectResult(queryString, null, queryVerboseMsg, e,
e.getMessage(), false);
} catch (NameResolutionException e) {
logger.warn(e.getMessage(), e);
return DataCommandResult.createSelectResult(queryString, null, queryVerboseMsg, e,
e.getMessage(), false);
} catch (QueryInvocationTargetException e) {
logger.warn(e.getMessage(), e);
return DataCommandResult.createSelectResult(queryString, null, queryVerboseMsg, e,
e.getMessage(), false);
} catch (GfJsonException e) {
logger.warn(e.getMessage(), e);
return DataCommandResult.createSelectResult(queryString, null, queryVerboseMsg, e,
e.getMessage(), false);
} finally {
if (queryObserver != null) {
QueryObserverHolder.reset();
}
}
} else {
return DataCommandResult.createSelectInfoResult(null, null, -1, null,
CliStrings.QUERY__MSG__QUERY_EMPTY, false);
}
}
private String toJson(Object object) {
if (object instanceof Undefined) {
return "{\"Value\":\"UNDEFINED\"}";
} else if (object instanceof PdxInstance)
return pdxToJson((PdxInstance) object);
else
return JsonUtil.objectToJsonNestedChkCDep(object, NESTED_JSON_LENGTH);
}
private GfJsonObject getJSONForStruct(StructImpl impl, AtomicInteger ai) throws GfJsonException {
String fields[] = impl.getFieldNames();
Object[] values = impl.getFieldValues();
GfJsonObject jsonObject = new GfJsonObject();
for (int i = 0; i < fields.length; i++) {
Object value = values[i];
if (value != null) {
if (JsonUtil.isPrimitiveOrWrapper(value.getClass())) {
jsonObject.put(fields[i], value);
} else {
// jsonObject.put(fields[i], value.getClass().getCanonicalName());
jsonObject.put(fields[i], toJson(value));
}
} else {
jsonObject.put(fields[i], "null");
}
}
return jsonObject;
}
@SuppressWarnings({"rawtypes"})
public DataCommandResult remove(String key, String keyClass, String regionName,
String removeAllKeys) {
Cache cache = CacheFactory.getAnyInstance();
if (regionName == null || regionName.isEmpty()) {
return DataCommandResult.createRemoveResult(key, null, null,
CliStrings.REMOVE__MSG__REGIONNAME_EMPTY, false);
}
boolean allKeysFlag = (removeAllKeys == null || removeAllKeys.isEmpty());
if (allKeysFlag && (key == null || key.isEmpty())) {
return DataCommandResult.createRemoveResult(key, null, null,
CliStrings.REMOVE__MSG__KEY_EMPTY, false);
}
Region region = cache.getRegion(regionName);
if (region == null) {
return DataCommandResult.createRemoveInfoResult(key, null, null,
CliStrings.format(CliStrings.REMOVE__MSG__REGION_NOT_FOUND, regionName), false);
} else {
if (removeAllKeys == null) {
Object keyObject = null;
try {
keyObject = getClassObject(key, keyClass);
} catch (ClassNotFoundException e) {
return DataCommandResult.createRemoveResult(key, null, null,
"ClassNotFoundException " + keyClass, false);
} catch (IllegalArgumentException e) {
return DataCommandResult.createRemoveResult(key, null, null,
"Error in converting JSON " + e.getMessage(), false);
}
if (region.containsKey(keyObject)) {
Object value = region.remove(keyObject);
if (logger.isDebugEnabled())
logger.debug("Removed key {} successfully", key);
// return DataCommandResult.createRemoveResult(key, value, null, null);
Object array[] = getJSONForNonPrimitiveObject(value);
DataCommandResult result =
DataCommandResult.createRemoveResult(key, array[1], null, null, true);
if (array[0] != null)
result.setValueClass((String) array[0]);
return result;
} else {
return DataCommandResult.createRemoveInfoResult(key, null, null,
CliStrings.REMOVE__MSG__KEY_NOT_FOUND_REGION, false);
}
} else {
DataPolicy policy = region.getAttributes().getDataPolicy();
if (!policy.withPartitioning()) {
region.clear();
if (logger.isDebugEnabled())
logger.debug("Cleared all keys in the region - {}", regionName);
return DataCommandResult.createRemoveInfoResult(key, null, null,
CliStrings.format(CliStrings.REMOVE__MSG__CLEARED_ALL_CLEARS, regionName), true);
} else {
return DataCommandResult.createRemoveInfoResult(key, null, null,
CliStrings.REMOVE__MSG__CLEAREALL_NOT_SUPPORTED_FOR_PARTITIONREGION, false);
}
}
}
}
@SuppressWarnings({"rawtypes"})
public DataCommandResult get(Object principal, String key, String keyClass, String valueClass,
String regionName, Boolean loadOnCacheMiss) {
Cache cache = CacheFactory.getAnyInstance();
if (regionName == null || regionName.isEmpty()) {
return DataCommandResult.createGetResult(key, null, null,
CliStrings.GET__MSG__REGIONNAME_EMPTY, false);
}
if (key == null || key.isEmpty()) {
return DataCommandResult.createGetResult(key, null, null, CliStrings.GET__MSG__KEY_EMPTY,
false);
}
Region region = cache.getRegion(regionName);
if (region == null) {
if (logger.isDebugEnabled())
logger.debug("Region Not Found - {}", regionName);
return DataCommandResult.createGetResult(key, null, null,
CliStrings.format(CliStrings.GET__MSG__REGION_NOT_FOUND, regionName), false);
} else {
Object keyObject = null;
try {
keyObject = getClassObject(key, keyClass);
} catch (ClassNotFoundException e) {
return DataCommandResult.createGetResult(key, null, null,
"ClassNotFoundException " + keyClass, false);
} catch (IllegalArgumentException e) {
return DataCommandResult.createGetResult(key, null, null,
"Error in converting JSON " + e.getMessage(), false);
}
// TODO determine whether the following conditional logic (assigned to 'doGet') is safer or
// necessary
// boolean doGet = (Boolean.TRUE.equals(loadOnCacheMiss) &&
// region.getAttributes().getCacheLoader() != null);
boolean doGet = Boolean.TRUE.equals(loadOnCacheMiss);
if (doGet || region.containsKey(keyObject)) {
Object value = region.get(keyObject);
// run it through post processor. region.get will return the deserialized object already, so
// we don't need to
// deserialize it anymore to pass it to the postProcessor
value = this.securityService.postProcess(principal, regionName, keyObject, value, false);
if (logger.isDebugEnabled())
logger.debug("Get for key {} value {}", key, value);
// return DataCommandResult.createGetResult(key, value, null, null);
Object array[] = getJSONForNonPrimitiveObject(value);
if (value != null) {
DataCommandResult result =
DataCommandResult.createGetResult(key, array[1], null, null, true);
if (array[0] != null)
result.setValueClass((String) array[0]);
return result;
} else {
return DataCommandResult.createGetResult(key, array[1], null, null, false);
}
} else {
if (logger.isDebugEnabled())
logger.debug("Key is not present in the region {}", regionName);
return DataCommandResult.createGetInfoResult(key, null, null,
CliStrings.GET__MSG__KEY_NOT_FOUND_REGION, false);
}
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public DataCommandResult locateEntry(String key, String keyClass, String valueClass,
String regionPath, boolean recursive) {
Cache cache = CacheFactory.getAnyInstance();
if (regionPath == null || regionPath.isEmpty()) {
return DataCommandResult.createLocateEntryResult(key, null, null,
CliStrings.LOCATE_ENTRY__MSG__REGIONNAME_EMPTY, false);
}
if (key == null || key.isEmpty()) {
return DataCommandResult.createLocateEntryResult(key, null, null,
CliStrings.LOCATE_ENTRY__MSG__KEY_EMPTY, false);
}
List<Region> listofRegionStartingwithRegionPath = new ArrayList<Region>();
if (recursive) {
// Recursively find the keys starting from the specified region path.
List<String> regionPaths = getAllRegionPaths(cache, true);
for (int i = 0; i < regionPaths.size(); i++) {
String path = regionPaths.get(i);
if (path.startsWith(regionPath) || path.startsWith(Region.SEPARATOR + regionPath)) {
Region targetRegion = cache.getRegion(path);
listofRegionStartingwithRegionPath.add(targetRegion);
}
}
if (listofRegionStartingwithRegionPath.size() == 0) {
if (logger.isDebugEnabled())
logger.debug("Region Not Found - {}", regionPath);
return DataCommandResult.createLocateEntryResult(key, null, null,
CliStrings.format(CliStrings.REMOVE__MSG__REGION_NOT_FOUND, regionPath), false);
}
} else {
Region region = cache.getRegion(regionPath);
if (region == null) {
if (logger.isDebugEnabled())
logger.debug("Region Not Found - {}", regionPath);
return DataCommandResult.createLocateEntryResult(key, null, null,
CliStrings.format(CliStrings.REMOVE__MSG__REGION_NOT_FOUND, regionPath), false);
} else
listofRegionStartingwithRegionPath.add(region);
}
Object keyObject = null;
try {
keyObject = getClassObject(key, keyClass);
} catch (ClassNotFoundException e) {
logger.fatal(e.getMessage(), e);
return DataCommandResult.createLocateEntryResult(key, null, null,
"ClassNotFoundException " + keyClass, false);
} catch (IllegalArgumentException e) {
logger.fatal(e.getMessage(), e);
return DataCommandResult.createLocateEntryResult(key, null, null,
"Error in converting JSON " + e.getMessage(), false);
}
Object value = null;
DataCommandResult.KeyInfo keyInfo = null;
keyInfo = new DataCommandResult.KeyInfo();
DistributedMember member = cache.getDistributedSystem().getDistributedMember();
keyInfo.setHost(member.getHost());
keyInfo.setMemberId(member.getId());
keyInfo.setMemberName(member.getName());
for (Region region : listofRegionStartingwithRegionPath) {
if (region instanceof PartitionedRegion) {
// Following code is adaptation of which.java of old Gfsh
PartitionedRegion pr = (PartitionedRegion) region;
Region localRegion = PartitionRegionHelper.getLocalData((PartitionedRegion) region);
value = localRegion.get(keyObject);
if (value != null) {
DistributedMember primaryMember =
PartitionRegionHelper.getPrimaryMemberForKey(region, keyObject);
int bucketId = pr.getKeyInfo(keyObject).getBucketId();
boolean isPrimary = member == primaryMember;
keyInfo.addLocation(new Object[] {region.getFullPath(), true,
getJSONForNonPrimitiveObject(value)[1], isPrimary, "" + bucketId});
} else {
if (logger.isDebugEnabled())
logger.debug("Key is not present in the region {}", regionPath);
return DataCommandResult.createLocateEntryInfoResult(key, null, null,
CliStrings.LOCATE_ENTRY__MSG__KEY_NOT_FOUND_REGION, false);
}
} else {
if (region.containsKey(keyObject)) {
value = region.get(keyObject);
if (logger.isDebugEnabled())
logger.debug("Get for key {} value {} in region {}", key, value, region.getFullPath());
if (value != null)
keyInfo.addLocation(new Object[] {region.getFullPath(), true,
getJSONForNonPrimitiveObject(value)[1], false, null});
else
keyInfo.addLocation(new Object[] {region.getFullPath(), false, null, false, null});
} else {
if (logger.isDebugEnabled())
logger.debug("Key is not present in the region {}", regionPath);
keyInfo.addLocation(new Object[] {region.getFullPath(), false, null, false, null});
}
}
}
if (keyInfo.hasLocation()) {
return DataCommandResult.createLocateEntryResult(key, keyInfo, null, null, true);
} else {
return DataCommandResult.createLocateEntryInfoResult(key, null, null,
CliStrings.LOCATE_ENTRY__MSG__KEY_NOT_FOUND_REGION, false);
}
}
@SuppressWarnings({"rawtypes"})
public DataCommandResult put(String key, String value, boolean putIfAbsent, String keyClass,
String valueClass, String regionName) {
if (regionName == null || regionName.isEmpty()) {
return DataCommandResult.createPutResult(key, null, null,
CliStrings.PUT__MSG__REGIONNAME_EMPTY, false);
}
if (key == null || key.isEmpty()) {
return DataCommandResult.createPutResult(key, null, null, CliStrings.PUT__MSG__KEY_EMPTY,
false);
}
if (value == null || value.isEmpty()) {
return DataCommandResult.createPutResult(key, null, null, CliStrings.PUT__MSG__VALUE_EMPTY,
false);
}
Cache cache = CacheFactory.getAnyInstance();
Region region = cache.getRegion(regionName);
if (region == null) {
return DataCommandResult.createPutResult(key, null, null,
CliStrings.format(CliStrings.PUT__MSG__REGION_NOT_FOUND, regionName), false);
} else {
Object keyObject = null;
Object valueObject = null;
try {
keyObject = getClassObject(key, keyClass);
} catch (ClassNotFoundException e) {
return DataCommandResult.createPutResult(key, null, null,
"ClassNotFoundException " + keyClass, false);
} catch (IllegalArgumentException e) {
return DataCommandResult.createPutResult(key, null, null,
"Error in converting JSON " + e.getMessage(), false);
}
try {
valueObject = getClassObject(value, valueClass);
} catch (ClassNotFoundException e) {
return DataCommandResult.createPutResult(key, null, null,
"ClassNotFoundException " + valueClass, false);
}
Object returnValue;
if (putIfAbsent && region.containsKey(keyObject))
returnValue = region.get(keyObject);
else
returnValue = region.put(keyObject, valueObject);
Object array[] = getJSONForNonPrimitiveObject(returnValue);
DataCommandResult result = DataCommandResult.createPutResult(key, array[1], null, null, true);
if (array[0] != null)
result.setValueClass((String) array[0]);
return result;
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private Object getClassObject(String string, String klassString)
throws ClassNotFoundException, IllegalArgumentException {
if (klassString == null || klassString.isEmpty())
return string;
else {
Object o = null;
Class klass = ClassPathLoader.getLatest().forName(klassString);
if (klass.equals(String.class))
return string;
if (JsonUtil.isPrimitiveOrWrapper(klass)) {
try {
if (klass.equals(Byte.class)) {
o = Byte.parseByte(string);
return o;
} else if (klass.equals(Short.class)) {
o = Short.parseShort(string);
return o;
} else if (klass.equals(Integer.class)) {
o = Integer.parseInt(string);
return o;
} else if (klass.equals(Long.class)) {
o = Long.parseLong(string);
return o;
} else if (klass.equals(Double.class)) {
o = Double.parseDouble(string);
return o;
} else if (klass.equals(Boolean.class)) {
o = Boolean.parseBoolean(string);
return o;
} else if (klass.equals(Float.class)) {
o = Float.parseFloat(string);
return o;
}
return o;
} catch (NumberFormatException e) {
throw new IllegalArgumentException(
"Failed to convert input key to " + klassString + " Msg : " + e.getMessage());
}
}
try {
o = getObjectFromJson(string, klass);
return o;
} catch (IllegalArgumentException e) {
throw e;
}
}
}
@SuppressWarnings({"rawtypes"})
public static Object[] getJSONForNonPrimitiveObject(Object obj) {
Object[] array = new Object[2];
if (obj == null) {
array[0] = null;
array[1] = "<NULL>";
return array;
} else {
array[0] = obj.getClass().getCanonicalName();
Class klass = obj.getClass();
if (JsonUtil.isPrimitiveOrWrapper(klass)) {
array[1] = obj;
} else if (obj instanceof PdxInstance) {
String str = pdxToJson((PdxInstance) obj);
array[1] = str;
} else {
GfJsonObject object = new GfJsonObject(obj, true);
Iterator keysIterator = object.keys();
while (keysIterator.hasNext()) {
String key = (String) keysIterator.next();
Object value = object.get(key);
if (GfJsonObject.isJSONKind(value)) {
GfJsonObject jsonVal = new GfJsonObject(value);
// System.out.println("Re-wrote inner object");
try {
if (jsonVal.has("type-class")) {
object.put(key, jsonVal.get("type-class"));
} else {
// Its Map Value
object.put(key, "a Map");
}
} catch (GfJsonException e) {
throw new RuntimeException(e);
}
} else if (value instanceof JSONArray) {
// Its a collection either a set or list
try {
object.put(key, "a Collection");
} catch (GfJsonException e) {
throw new RuntimeException(e);
}
}
}
String str = object.toString();
array[1] = str;
}
return array;
}
}
private static String pdxToJson(PdxInstance obj) {
if (obj != null) {
try {
GfJsonObject json = new GfJsonObject();
for (String field : obj.getFieldNames()) {
Object fieldValue = obj.getField(field);
if (fieldValue != null) {
if (JsonUtil.isPrimitiveOrWrapper(fieldValue.getClass())) {
json.put(field, fieldValue);
} else {
json.put(field, fieldValue.getClass());
}
}
}
return json.toString();
} catch (GfJsonException e) {
return null;
}
}
return null;
}
public static <V> V getObjectFromJson(String json, Class<V> klass) {
String newString = json.replaceAll("'", "\"");
if (newString.charAt(0) == '(') {
int len = newString.length();
StringBuilder sb = new StringBuilder();
sb.append("{").append(newString.substring(1, len - 1)).append("}");
newString = sb.toString();
}
V v = JsonUtil.jsonToObject(newString, klass);
return v;
}
// Copied from RegionUtil of old Gfsh
/**
* Returns a sorted list of all region full paths found in the specified cache.
*
* @param cache The cache to search.
* @param recursive recursive search for sub-regions
* @return Returns a sorted list of all region paths defined in the distributed system.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static List getAllRegionPaths(Cache cache, boolean recursive) {
ArrayList list = new ArrayList();
if (cache == null) {
return list;
}
// get a list of all root regions
Set regions = cache.rootRegions();
Iterator itor = regions.iterator();
while (itor.hasNext()) {
String regionPath = ((Region) itor.next()).getFullPath();
Region region = cache.getRegion(regionPath);
list.add(regionPath);
Set subregionSet = region.subregions(true);
if (recursive) {
for (Iterator subIter = subregionSet.iterator(); subIter.hasNext();) {
list.add(((Region) subIter.next()).getFullPath());
}
}
}
Collections.sort(list);
return list;
}
private static DataCommandResult cachedResult = null;
public static class SelectDisplayStep extends CLIMultiStepHelper.LocalStep {
public SelectDisplayStep(Object[] arguments) {
super(SELECT_STEP_DISPLAY, arguments);
}
@Override
public Result exec() {
boolean interactive = (Boolean) commandArguments[2];
GfJsonObject args = CLIMultiStepHelper.getStepArgs();
int startCount = args.getInt(DataCommandResult.QUERY_PAGE_START);
int endCount = args.getInt(DataCommandResult.QUERY_PAGE_END);
int rows = args.getInt(DataCommandResult.NUM_ROWS); // returns Zero if no rows added so it
// works.
boolean flag = args.getBoolean(DataCommandResult.RESULT_FLAG);
CommandResult commandResult = CLIMultiStepHelper.getDisplayResultFromArgs(args);
Gfsh.println();
while (commandResult.hasNextLine()) {
Gfsh.println(commandResult.nextLine());
}
if (flag) {
boolean paginationNeeded = (startCount < rows) && (endCount < rows) && interactive && flag;
if (paginationNeeded) {
while (true) {
String message = ("Press n to move to next page, q to quit and p to previous page : ");
try {
String step = Gfsh.getCurrentInstance().interact(message);
if ("n".equals(step)) {
int nextStart = startCount + getPageSize();
return CLIMultiStepHelper.createBannerResult(
new String[] {DataCommandResult.QUERY_PAGE_START,
DataCommandResult.QUERY_PAGE_END,},
new Object[] {nextStart, (nextStart + getPageSize())}, SELECT_STEP_MOVE);
} else if ("p".equals(step)) {
int nextStart = startCount - getPageSize();
if (nextStart < 0)
nextStart = 0;
return CLIMultiStepHelper.createBannerResult(
new String[] {DataCommandResult.QUERY_PAGE_START,
DataCommandResult.QUERY_PAGE_END},
new Object[] {nextStart, (nextStart + getPageSize())}, SELECT_STEP_MOVE);
} else if ("q".equals(step))
return CLIMultiStepHelper.createBannerResult(new String[] {}, new Object[] {},
SELECT_STEP_END);
else
Gfsh.println("Unknown option ");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
return CLIMultiStepHelper.createBannerResult(new String[] {}, new Object[] {},
SELECT_STEP_END);
}
}
public static class SelectMoveStep extends CLIMultiStepHelper.RemoteStep {
private static final long serialVersionUID = 1L;
public SelectMoveStep(Object[] arguments) {
super(SELECT_STEP_MOVE, arguments);
}
@Override
public Result exec() {
GfJsonObject args = CLIMultiStepHelper.getStepArgs();
int startCount = args.getInt(DataCommandResult.QUERY_PAGE_START);
int endCount = args.getInt(DataCommandResult.QUERY_PAGE_END);
return cachedResult.pageResult(startCount, endCount, SELECT_STEP_DISPLAY);
}
};
public static class SelectExecStep extends CLIMultiStepHelper.RemoteStep {
private static final long serialVersionUID = 1L;
private static SecurityService securityService = SecurityService.getSecurityService();
public SelectExecStep(Object[] arguments) {
super(SELECT_STEP_EXEC, arguments);
}
@Override
public Result exec() {
String remainingQuery = (String) commandArguments[0];
boolean interactive = (Boolean) commandArguments[2];
DataCommandResult result = _select(remainingQuery);
int endCount = 0;
cachedResult = result;
if (interactive) {
endCount = getPageSize();
} else {
if (result.getSelectResult() != null)
endCount = result.getSelectResult().size();
}
if (interactive)
return result.pageResult(0, endCount, SELECT_STEP_DISPLAY);
else
return CLIMultiStepHelper.createBannerResult(new String[] {}, new Object[] {},
SELECT_STEP_END);
}
/*
* private int getLimit(CompiledValue compiledQuery) { return compiledQuery instanceof
* CompiledSelect ? ((CompiledSelect)compiledQuery).getLimitValue(): -1; }
*/
public DataCommandResult _select(String query) {
Cache cache = CacheFactory.getAnyInstance();
DataCommandResult dataResult = null;
if (query == null || query.isEmpty()) {
dataResult = DataCommandResult.createSelectInfoResult(null, null, -1, null,
CliStrings.QUERY__MSG__QUERY_EMPTY, false);
return dataResult;
}
// String query = querySB.toString().trim();
Object array[] = DataCommands.replaceGfshEnvVar(query, CommandExecutionContext.getShellEnv());
query = (String) array[1];
query = addLimit(query);
@SuppressWarnings("deprecation")
QCompiler compiler = new QCompiler();
Set<String> regionsInQuery = null;
try {
CompiledValue compiledQuery = compiler.compileQuery(query);
Set<String> regions = new HashSet<String>();
compiledQuery.getRegionsInQuery(regions, null);
// authorize data read on these regions
for (String region : regions) {
this.securityService.authorizeRegionRead(region);
}
regionsInQuery = Collections.unmodifiableSet(regions);
if (regionsInQuery.size() > 0) {
Set<DistributedMember> members =
DataCommands.getQueryRegionsAssociatedMembers(regionsInQuery, cache, false);
if (members != null && members.size() > 0) {
DataCommandFunction function = new DataCommandFunction();
DataCommandRequest request = new DataCommandRequest();
request.setCommand(CliStrings.QUERY);
request.setQuery(query);
Subject subject = this.securityService.getSubject();
if (subject != null) {
request.setPrincipal((Serializable) subject.getPrincipal());
}
dataResult = DataCommands.callFunctionForRegion(request, function, members);
dataResult.setInputQuery(query);
return (dataResult);
} else {
return (dataResult =
DataCommandResult.createSelectInfoResult(null, null, -1, null, CliStrings.format(
CliStrings.QUERY__MSG__REGIONS_NOT_FOUND, regionsInQuery.toString()), false));
}
} else {
return (dataResult = DataCommandResult.createSelectInfoResult(null, null, -1, null,
CliStrings.format(CliStrings.QUERY__MSG__INVALID_QUERY,
"Region mentioned in query probably missing /"),
false));
}
} catch (QueryInvalidException qe) {
logger.error("{} Failed Error {}", query, qe.getMessage(), qe);
return (dataResult = DataCommandResult.createSelectInfoResult(null, null, -1, null,
CliStrings.format(CliStrings.QUERY__MSG__INVALID_QUERY, qe.getMessage()), false));
}
}
private String addLimit(String query) {
if (StringUtils.containsIgnoreCase(query, " limit")
|| StringUtils.containsIgnoreCase(query, " count("))
return query;
return query + " limit " + getFetchSize();
}
};
public static class SelectQuitStep extends CLIMultiStepHelper.RemoteStep {
public SelectQuitStep(Object[] arguments) {
super(SELECT_STEP_END, arguments);
}
private static final long serialVersionUID = 1L;
@Override
public Result exec() {
boolean interactive = (Boolean) commandArguments[2];
GfJsonObject args = CLIMultiStepHelper.getStepArgs();
DataCommandResult dataResult = cachedResult;
cachedResult = null;
if (interactive)
return CLIMultiStepHelper.createEmptyResult("END");
else {
CompositeResultData rd = dataResult.toSelectCommandResult();
SectionResultData section = rd.addSection(CLIMultiStepHelper.STEP_SECTION);
section.addData(CLIMultiStepHelper.NEXT_STEP_NAME, "END");
return ResultBuilder.buildResult(rd);
}
}
};
public static int getPageSize() {
int pageSize = -1;
Map<String, String> session = null;
if (CliUtil.isGfshVM()) {
session = Gfsh.getCurrentInstance().getEnv();
} else {
session = CommandExecutionContext.getShellEnv();
}
if (session != null) {
String size = session.get(Gfsh.ENV_APP_COLLECTION_LIMIT);
if (size == null || size.isEmpty())
pageSize = Gfsh.DEFAULT_APP_COLLECTION_LIMIT;
else
pageSize = Integer.parseInt(size);
}
if (pageSize == -1)
pageSize = Gfsh.DEFAULT_APP_COLLECTION_LIMIT;
return pageSize;
}
private static int getFetchSize() {
return CommandExecutionContext.getShellFetchSize();
}
public static String getLogMessage(QueryObserver observer, long startTime, String query) {
String usedIndexesString = null;
String rowCountString = null;
float time = 0.0f;
if (startTime > 0L) {
time = (NanoTimer.getTime() - startTime) / 1.0e6f;
}
if (observer != null && observer instanceof IndexTrackingQueryObserver) {
IndexTrackingQueryObserver indexObserver = (IndexTrackingQueryObserver) observer;
Map usedIndexes = indexObserver.getUsedIndexes();
indexObserver.reset();
StringBuffer buf = new StringBuffer();
buf.append(" indexesUsed(");
buf.append(usedIndexes.size());
buf.append(")");
if (usedIndexes.size() > 0) {
buf.append(":");
for (Iterator itr = usedIndexes.entrySet().iterator(); itr.hasNext();) {
Map.Entry entry = (Map.Entry) itr.next();
buf.append(entry.getKey().toString() + entry.getValue());
if (itr.hasNext()) {
buf.append(",");
}
}
}
usedIndexesString = buf.toString();
} else if (DefaultQuery.QUERY_VERBOSE) {
usedIndexesString = " indexesUsed(NA due to other observer in the way: "
+ observer.getClass().getName() + ")";
}
/*
* if (resultSize != -1){ rowCountString = " rowCount = " + resultSize + ";"; }
*/
return "Query Executed" + (startTime > 0L ? " in " + time + " ms;" : ";")
+ (rowCountString != null ? rowCountString : "")
+ (usedIndexesString != null ? usedIndexesString : "")
/* + " \"" + query + "\"" */;
}
}