/*
* 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.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.zip.DataFormatException;
import org.apache.geode.management.cli.Result.Status;
import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.CliUtil.DeflaterInflaterData;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.json.GfJsonArray;
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.shell.Gfsh;
/**
*
*
* @since GemFire 7.0
*/
public abstract class AbstractResultData implements ResultData {
public static final String SECTION_DATA_ACCESSOR = "__sections__";
public static final String TABLE_DATA_ACCESSOR = "__tables__";
public static final String BYTE_DATA_ACCESSOR = "__bytes__";
public static final int FILE_TYPE_BINARY = 0;
public static final int FILE_TYPE_TEXT = 1;
private static final String FILE_NAME_FIELD = "fileName";
private static final String FILE_TYPE_FIELD = "fileType";
private static final String FILE_DATA_FIELD = "fileData";
private static final String DATA_FIELD = "data";
private static final String DATA_LENGTH_FIELD = "dataLength";
private static final String FILE_MESSAGE = "fileMessage";
protected GfJsonObject gfJsonObject;
protected GfJsonObject contentObject;
private Status status = Status.OK;
protected AbstractResultData() {
gfJsonObject = new GfJsonObject();
contentObject = new GfJsonObject();
try {
gfJsonObject.putOpt(RESULT_CONTENT, contentObject);
} catch (GfJsonException ignorable) {
// ignorable as key won't be null here & it's thrown for ignorable values
}
}
protected AbstractResultData(GfJsonObject jsonObject) {
this.gfJsonObject = jsonObject;
this.contentObject = gfJsonObject.getJSONObject(RESULT_CONTENT);
}
/**
* @return the gfJsonObject
*/
public GfJsonObject getGfJsonObject() {
return gfJsonObject;
}
public abstract String getType();
@Override
public String getHeader() {
return gfJsonObject.getString(RESULT_HEADER);
}
@Override
public String getFooter() {
return gfJsonObject.getString(RESULT_FOOTER);
}
/**
*
* @param headerText
* @return this ResultData
* @throws ResultDataException If the value is non-finite number or if the key is null.
*/
public AbstractResultData setHeader(String headerText) {
try {
gfJsonObject.put(RESULT_HEADER, headerText);
} catch (GfJsonException e) {
throw new ResultDataException(e.getMessage());
}
return this;
}
/**
*
* @param footerText
* @return this ResultData
* @throws ResultDataException If the value is non-finite number or if the key is null.
*/
public AbstractResultData setFooter(String footerText) {
try {
gfJsonObject.put(RESULT_FOOTER, footerText);
} catch (GfJsonException e) {
throw new ResultDataException(e.getMessage());
}
return this;
}
private static String addTimeStampBeforeLastDot(String src) {
String toAdd = String.valueOf(new java.sql.Time(System.currentTimeMillis()));
toAdd = "-" + toAdd.replaceAll(":", "_");
int lastIndexOf = src.lastIndexOf(".");
if (lastIndexOf != -1) {
String substr1 = src.substring(0, lastIndexOf);
String substr2 = src.substring(lastIndexOf);
src = substr1 + toAdd + substr2;
} else {
src = src + toAdd;
}
return src;
}
public ResultData addAsFile(String fileName, String fileContents, String message,
boolean addTimeStampToName) {
return this.addAsFile(fileName, fileContents.getBytes(), FILE_TYPE_TEXT, message,
addTimeStampToName);
}
public ResultData addAsFile(String fileName, byte[] data, int fileType, String message,
boolean addTimeStampToName) {
byte[] bytes = data;
if (addTimeStampToName) {
fileName = addTimeStampBeforeLastDot(fileName);
}
return addAsFile(fileName.getBytes(), bytes, fileType, message);
}
public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
boolean addTimeStampToName) throws FileNotFoundException, IOException {
byte[][] filesToBytes = CliUtil.filesToBytes(new String[] {filePath});
byte[] bytes = filesToBytes[0];
if (addTimeStampToName) {
String fileName = new String(filesToBytes[0]);
fileName = addTimeStampBeforeLastDot(fileName);
bytes = fileName.getBytes();
}
return addAsFile(bytes, filesToBytes[1], fileType, message);
}
private ResultData addAsFile(byte[] fileName, byte[] data, int fileType, String message) {
// System.out.println("fileType :: "+fileType);
// System.out.println("FILE_TYPE_BINARY :: "+FILE_TYPE_BINARY);
// System.out.println("FILE_TYPE_TEXT :: "+FILE_TYPE_TEXT);
if (fileType != FILE_TYPE_BINARY && fileType != FILE_TYPE_TEXT) {
throw new IllegalArgumentException("Unsupported file type is specified.");
}
GfJsonObject sectionData = new GfJsonObject();
try {
GfJsonArray fileDataArray = contentObject.getJSONArray(BYTE_DATA_ACCESSOR);
if (fileDataArray == null) {
fileDataArray = new GfJsonArray();
contentObject.put(BYTE_DATA_ACCESSOR, fileDataArray);
}
fileDataArray.put(sectionData);
sectionData.put(FILE_NAME_FIELD, fileName);
sectionData.put(FILE_TYPE_FIELD, fileType);
sectionData.put(FILE_MESSAGE, message.getBytes());
sectionData.putAsJSONObject(FILE_DATA_FIELD, CliUtil.compressBytes(data));
// System.out.println(data);
// sectionData.put(FILE_DATA_FIELD, Base64.encodeBytes(data, Base64.GZIP));
} catch (GfJsonException e) {
throw new ResultDataException(e.getMessage());
// } catch (IOException e) {
// e.printStackTrace();
}
return this;
}
/**
* @param byteDataArray
* @throws GfJsonException
* @throws DataFormatException
* @throws IOException
*/
public static void readFileDataAndDump(GfJsonArray byteDataArray, String directory)
throws GfJsonException, DataFormatException, IOException {
boolean overwriteAllExisting = false;
int length = byteDataArray.size();
String options = length > 1 ? "(y/N/a)" : "(y/N)"; // TODO - Abhishek Make this consistent -
// with
// AbstractCliAroundInterceptor.readYesNo()
BYTEARRAY_LOOP: for (int i = 0; i < length; i++) {
GfJsonObject object = byteDataArray.getJSONObject(i);
int fileType = object.getInt(FILE_TYPE_FIELD);
if (fileType != FILE_TYPE_BINARY && fileType != FILE_TYPE_TEXT) {
throw new IllegalArgumentException("Unsupported file type found.");
}
// build file name
byte[] fileNameBytes = null;
GfJsonArray fileNameJsonBytes = object.getJSONArray(FILE_NAME_FIELD);
if (fileNameJsonBytes != null) { // if in gfsh
fileNameBytes = GfJsonArray.toByteArray(fileNameJsonBytes);
} else { // if on member
fileNameBytes = (byte[]) object.get(FILE_NAME_FIELD);
}
String fileName = new String(fileNameBytes);
// build file message
byte[] fileMessageBytes = null;
GfJsonArray fileMessageJsonBytes = object.getJSONArray(FILE_MESSAGE);
if (fileMessageJsonBytes != null) { // if in gfsh
fileMessageBytes = GfJsonArray.toByteArray(fileMessageJsonBytes);
} else { // if on member
fileMessageBytes = (byte[]) object.get(FILE_MESSAGE);
}
String fileMessage = new String(fileMessageBytes);
// System.out.println(object.names());
// System.out.println(fileName);
GfJsonObject fileDataBytes = object.getJSONObject(FILE_DATA_FIELD);
byte[] byteArray = GfJsonArray.toByteArray(fileDataBytes.getJSONArray(DATA_FIELD));
int dataLength = fileDataBytes.getInt(DATA_LENGTH_FIELD);
DeflaterInflaterData uncompressBytes = CliUtil.uncompressBytes(byteArray, dataLength);
byte[] uncompressed = uncompressBytes.getData();
// String encodedString = object.getString(FILE_DATA_FIELD);
// byte[] uncompressed = Base64.decode(encodedString, Base64.GZIP);
if (directory == null || directory.isEmpty()) {
directory = System.getProperty("user.dir", ".");
}
boolean isGfshVM = CliUtil.isGfshVM();
File fileToDumpData = new File(fileName);
if (!fileToDumpData.isAbsolute()) {
fileToDumpData = new File(directory, fileName);
}
File parentDirectory = fileToDumpData.getParentFile();
if (fileToDumpData.exists()) {
String fileExistsMessage =
CliStrings.format(CliStrings.ABSTRACTRESULTDATA__MSG__FILE_WITH_NAME_0_EXISTS_IN_1,
new Object[] {fileName, fileToDumpData.getParent(), options});
if (isGfshVM) {
Gfsh gfsh = Gfsh.getCurrentInstance();
if (gfsh != null && !gfsh.isQuietMode() && !overwriteAllExisting) {
fileExistsMessage = fileExistsMessage + " Overwrite? " + options + " : ";
String interaction = gfsh.interact(fileExistsMessage);
if ("a".equalsIgnoreCase(interaction.trim())) {
overwriteAllExisting = true;
} else if (!"y".equalsIgnoreCase(interaction.trim())) {
// do not save file & continue
continue BYTEARRAY_LOOP;
}
}
} else {
throw new IOException(fileExistsMessage);
}
} else if (!parentDirectory.exists()) {
handleCondition(CliStrings.format(
CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_DIRECTORY_OF_0_DOES_NOT_EXIST,
fileToDumpData.getAbsolutePath()), isGfshVM);
return;
} else if (!parentDirectory.canWrite()) {
handleCondition(CliStrings.format(
CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_DIRECTORY_OF_0_IS_NOT_WRITABLE,
fileToDumpData.getAbsolutePath()), isGfshVM);
return;
} else if (!parentDirectory.isDirectory()) {
handleCondition(
CliStrings.format(CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_OF_0_IS_NOT_DIRECTORY,
fileToDumpData.getAbsolutePath()),
isGfshVM);
return;
}
if (fileType == FILE_TYPE_TEXT) {
FileWriter fw = new FileWriter(fileToDumpData);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(new String(uncompressed));
bw.flush();
fw.flush();
fw.close();
} else if (fileType == FILE_TYPE_BINARY) {
FileOutputStream fos = new FileOutputStream(fileToDumpData);
fos.write(uncompressed);
fos.flush();
fos.close();
}
// System.out.println("fileMessage :: "+fileMessage);
if (fileMessage != null && !fileMessage.isEmpty()) {
if (isGfshVM) {
Gfsh.println(
MessageFormat.format(fileMessage, new Object[] {fileToDumpData.getAbsolutePath()}));
}
}
// System.out.println(new String(uncompressed));
}
}
// TODO - Abhishek : prepare common utility for this & ANSI Styling
static void handleCondition(String message, boolean isGfshVM) throws IOException {
if (isGfshVM) {
Gfsh gfsh = Gfsh.getCurrentInstance();
// null check required in GfshVM too to avoid test issues
if (gfsh != null && !gfsh.isQuietMode()) {
gfsh.logWarning(message, null);
}
} else {
throw new IOException(message);
}
}
@Override
public void setStatus(final Status status) {
this.status = status;
}
@Override
public Status getStatus() {
return this.status;
}
}