/*
* 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.result;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import org.apache.geode.management.cli.Result;
import org.apache.geode.management.internal.cli.json.GfJsonException;
import org.apache.geode.management.internal.cli.json.GfJsonObject;
/**
*
*
* @since GemFire 7.0
*/
public class ResultBuilder {
public static final int CODE_SHELLCLIENT_ABORT_OP = 110;
// public static final int OKCODE = 200;
// error on gfsh
public static final int ERRORCODE_DEFAULT = 400;
public static final int ERRORCODE_CONNECTION_ERROR = 405;
public static final int ERRORCODE_SHELLCLIENT_ERROR = 410;
public static final int ERRORCODE_UNAUTHORIZED = 415;
// errors on member
public static final int ERRORCODE_PARSING_ERROR = 501;
public static final int ERRORCODE_GEMFIRE_ERROR = 505;
public static final int ERRORCODE_BADRESPONSE_ERROR = 510;
public static final int ERRORCODE_BADCONFIG_ERROR = 515;
public static final int ERRORCODE_USER_ERROR = 520;
// Result with constant message & error code
public static final Result ERROR_RESULT_DEFAULT =
createErrorResult(ERRORCODE_DEFAULT, "Error occurred while executing command.");
/**
* Method for convenience to create error result for connection error.
* <p/>
* Note: To build your own error result, use {@link #createErrorResultData()} to build
* {@link ErrorResultData} & then use {@link #buildResult(ResultData)}
*
* @param message Message to be shown to the user
* @return Result for connection error
*/
public static Result createConnectionErrorResult(String message) {
String errorMessage = message != null ? message : "Connection Error occurred.";
return createErrorResult(ERRORCODE_CONNECTION_ERROR, errorMessage);
}
public static Result createShellClientErrorResult(String message) {
return createErrorResult(ERRORCODE_SHELLCLIENT_ERROR, message);
}
public static Result createShellClientAbortOperationResult(String message) {
return createErrorResult(CODE_SHELLCLIENT_ABORT_OP, message);
}
/**
* Method for convenience to create error result for parsing error.
* <p/>
* Note: To build your own error result, use {@link #createErrorResultData()} to build
* {@link ErrorResultData} & then use {@link #buildResult(ResultData)}
*
* @param message Message to be shown to the user
* @return Result for parsing error
*/
public static Result createParsingErrorResult(String message) {
return createErrorResult(ERRORCODE_PARSING_ERROR, "Could not parse command string. " + message);
}
public static Result createBadConfigurationErrorResult(String message) {
return createErrorResult(ERRORCODE_BADCONFIG_ERROR, "Configuration error. " + message);
}
/**
* Method for convenience to create error result for error in GemFire while executing command.
* <p/>
* Note: To build your own error result, use {@link #createErrorResultData()} to build
* {@link ErrorResultData} & then use {@link #buildResult(ResultData)}
*
* @param message Message to be shown to the user
* @return Result for error in GemFire while executing command.
*/
public static Result createGemFireErrorResult(String message) {
return createErrorResult(ERRORCODE_GEMFIRE_ERROR,
"Could not process command due to GemFire error. " + message);
}
public static Result createGemFireUnAuthorizedErrorResult(String message) {
return createErrorResult(ERRORCODE_UNAUTHORIZED, message);
}
public static Result createUserErrorResult(String message) {
return createErrorResult(ERRORCODE_USER_ERROR, message);
}
/**
* Method for convenience to create error result for unreadable command response.
* <p/>
* Note: To build your own error result, use {@link #createErrorResultData()} to build
* {@link ErrorResultData} & then use {@link #buildResult(ResultData)}
*
* @param message Message to be shown to the user
* @return Result for unreadable command response.
*/
public static Result createBadResponseErrorResult(String message) {
return createErrorResult(ERRORCODE_BADRESPONSE_ERROR,
"Could not read command response. " + message);
}
/**
* Creates error Result with given error code & message
* <p/>
* Note: To build your own error result, use {@link #createErrorResultData()} to build
* {@link ErrorResultData} & then use {@link #buildResult(ResultData)}
*
* @param errorCode error code should be one of ResultBuilder.ERRORCODE_**
* @param message message for the error
* @return Result object with the given error code & message. If there's an exception while
* building result object, returns {@link #ERROR_RESULT_DEFAULT}
*/
private static Result createErrorResult(int errorCode, String message) {
ErrorResultData errorResultData = new ErrorResultData();
errorResultData.setErrorCode(errorCode);
errorResultData.addLine(message);
return buildResult(errorResultData);
}
/**
* Convenience method to create a simple Info Result that takes a message.
*
* @param message Message for the OK Result
* @return Result of InfoResultData type
*/
public static Result createInfoResult(String message) {
InfoResultData infoResultData = new InfoResultData();
infoResultData.addLine(message);
return buildResult(infoResultData);
}
/**
* Creates a {@link TabularResultData} object to start building result that should be shown in a
* Tabular Format.
*
* @return TabularResultData instance
*/
public static TabularResultData createTabularResultData() {
return new TabularResultData();
}
public static CompositeResultData createCompositeResultData() {
return new CompositeResultData();
}
public static <T extends CliJsonSerializable> ObjectResultData<T> createObjectResultData() {
return new ObjectResultData<T>();
}
// public static CatalogedResultData createCatalogedResultData() {
// return new CatalogedResultData();
// }
/**
* Creates a {@link InfoResultData} object to start building result that is required to be shown
* as an information without any specific format.
*
* @return InfoResultData instance
*/
public static InfoResultData createInfoResultData() {
return new InfoResultData();
}
/**
* Creates a {@link ErrorResultData} object to start building result for an error.
*
* @return ErrorResultData instance
*/
public static ErrorResultData createErrorResultData() {
return new ErrorResultData();
}
/**
* Build a Result object from the given ResultData
*
* @param resultData data to use to build Result
* @return Result object built from the given ResultData
*/
public static Result buildResult(ResultData resultData) {
return new CommandResult(resultData);
}
/**
* Prepare Result from JSON. Type of result is expected to there in the JSON as 'contentType'
* which should be one of {@link ResultData#TYPE_TABULAR}, {@link ResultData#TYPE_COMPOSITE},
* {@link ResultData#TYPE_INFO}, {@link ResultData#TYPE_ERROR}, {@link ResultData#TYPE_OBJECT}.
*
* @param gfJsonObject GemFire JSON Object to use to prepare Result
* @return Result from the given GemFire JSON Object
*/
public static Result fromJson(GfJsonObject gfJsonObject) {
return fromJson(gfJsonObject.toString());
}
/**
* Prepare a Result object from a JSON String. This is useful on gfsh/client to read the response
* & prepare a Result object from the JSON response
*
* @param json JSON string for Result
* @return Result object prepare from the JSON string. If it fails, creates an error Result for
* Bad Response.
*/
public static Result fromJson(String json) {
Result result = null;
try {
GfJsonObject jsonObject = new GfJsonObject(json);
String contentType = jsonObject.getString("contentType");
GfJsonObject data = jsonObject.getJSONObject("data");
AbstractResultData resultData = null;
if (ResultData.TYPE_TABULAR.equals(contentType)) {
resultData = new TabularResultData(data);
} /*
* else if (ResultData.TYPE_CATALOGED.equals(contentType)) { resultData = new
* CatalogedResultData(new GfJsonObject(String.valueOf(content))); }
*/ else if (ResultData.TYPE_INFO.equals(contentType)) {
resultData = new InfoResultData(data);
} else if (ResultData.TYPE_ERROR.equals(contentType)) {
resultData = new ErrorResultData(data);
} else if (ResultData.TYPE_COMPOSITE.equals(contentType)) {
resultData = new CompositeResultData(data);
} else if (ResultData.TYPE_OBJECT.equals(contentType)) {
resultData = new ObjectResultData<CliJsonSerializable>(data);
} else {
ErrorResultData errorResultData = new ErrorResultData();
errorResultData.addLine("Can not detect result type, unknown response format: " + json);
resultData = errorResultData;
}
result = buildResult(resultData);
} catch (GfJsonException e) {
result = createBadResponseErrorResult(json);
}
return result;
}
public static String resultAsString(Result result) {
StringBuilder builder = new StringBuilder();
if (result != null) {
while (result.hasNextLine()) {
builder.append(result.nextLine());
}
// TODO - Abhishek - what to do with incoming files??
}
return builder.toString();
}
/**
* Wraps a given ResultData and wraps it into appropriate ResultData of the same type but the
* returned object is immutable & throws UnsupportedOperationException on invoking those methods.
*
* @param resultData to be wrapped
* @return Read only ResultData of the same type
*/
static ResultData getReadOnlyResultData(ResultData resultData) {
ResultData wrapperResultData = null;
String contentType = resultData.getType();
if (ResultData.TYPE_TABULAR.equals(contentType)) {
wrapperResultData = new TabularResultData(resultData.getGfJsonObject()) {
@Override
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public TabularResultData accumulate(String accumulateFor, Object value) {
throw new UnsupportedOperationException("This is read only result data");
}
};
} else if (ResultData.TYPE_INFO.equals(contentType)) {
wrapperResultData = new InfoResultData(resultData.getGfJsonObject()) {
@Override
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ErrorResultData addLine(String line) {
throw new UnsupportedOperationException("This is read only result data");
}
};
} else if (ResultData.TYPE_ERROR.equals(contentType)) {
wrapperResultData = new ErrorResultData(resultData.getGfJsonObject()) {
@Override
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ErrorResultData addLine(String line) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ErrorResultData setErrorCode(int errorCode) {
throw new UnsupportedOperationException("This is read only result data");
}
};
} else if (ResultData.TYPE_COMPOSITE.equals(contentType)) {
wrapperResultData = new CompositeResultData(resultData.getGfJsonObject()) {
@Override
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public SectionResultData addSection() {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public SectionResultData addSection(String keyToRetrieve) {
throw new UnsupportedOperationException("This is read only result data");
}
public CompositeResultData addSeparator(char buildSeparatorFrom) {
throw new UnsupportedOperationException("This is read only result data");
}
};
} else if (ResultData.TYPE_OBJECT.equals(contentType)) {
final ObjectResultData<?> wrapped = (ObjectResultData<?>) resultData;
wrapperResultData = new ObjectResultData<CliJsonSerializable>() {
@Override
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ObjectResultData<CliJsonSerializable> addCollection(
Collection<CliJsonSerializable> infoBeans) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public ObjectResultData<CliJsonSerializable> addObject(CliJsonSerializable infoBean) {
throw new UnsupportedOperationException("This is read only result data");
}
@Override
public List<CliJsonSerializable> getAllObjects() {
return wrapped.getAllObjects();
}
};
} else {
ErrorResultData errorResultData = new ErrorResultData();
errorResultData
.addLine("Can not detect result type, unknown result data format for: " + resultData);
wrapperResultData = errorResultData;
}
return wrapperResultData;
}
}