package com.epam.wilma.extras.shortcircuit; /*========================================================================== Copyright 2013-2017 EPAM Systems This file is part of Wilma. Wilma is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Wilma is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wilma. If not, see <http://www.gnu.org/licenses/>. ===========================================================================*/ import com.epam.wilma.common.helper.FileFactory; import com.epam.wilma.common.helper.UniqueIdGenerator; import com.epam.wilma.webapp.config.servlet.stub.upload.helper.FileOutputStreamFactory; import org.apache.commons.codec.binary.Base64; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * This class provides file save and load utility for {@link ShortCircuitResponseInformation}. * * @author tkohegyi */ class ShortCircuitResponseInformationFileHandler { private static final Object SHORT_CIRCUIT_MAP_GUARD = ShortCircuitChecker.getShortCircuitMapGuard(); private static final Map<String, ShortCircuitResponseInformation> SHORT_CIRCUIT_MAP = ShortCircuitChecker.getShortCircuitMap(); private final Logger logger = LoggerFactory.getLogger(ShortCircuitResponseInformationFileHandler.class); /** * Saves the map to a folder, to preserve it for later use. * * @param httpServletResponse is the response object * @return with the response body - that is a json info about the result of the call */ String savePreservedMessagesFromMap(String path, FileFactory fileFactory, FileOutputStreamFactory fileOutputStreamFactory, HttpServletResponse httpServletResponse) { String response = null; String filenamePrefix = "sc" + UniqueIdGenerator.getNextUniqueId() + "_"; if (!SHORT_CIRCUIT_MAP.isEmpty()) { String[] keySet = SHORT_CIRCUIT_MAP.keySet().toArray(new String[SHORT_CIRCUIT_MAP.size()]); for (String entryKey : keySet) { ShortCircuitResponseInformation information = SHORT_CIRCUIT_MAP.get(entryKey); if (information != null) { //save only the cached files //save this into file, folder is in folder variable String filename = path + filenamePrefix + UniqueIdGenerator.getNextUniqueId() + ".json"; File file = fileFactory.createFile(filename); try { saveMapObject(fileOutputStreamFactory, file, entryKey, information); } catch (IOException e) { String message = "Cache save failed at file: " + filename + ", with message: " + e.getLocalizedMessage(); logger.info("ShortCircuit: " + message); response = "{ \"resultsFailure\": \"" + message + "\" }"; httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); break; } } } } if (response == null) { String message = "Cache saved as: " + path + filenamePrefix + "*.json files"; response = "{ \"resultsSuccess\": \"" + message + "\" }"; httpServletResponse.setStatus(HttpServletResponse.SC_OK); logger.info("ShortCircuit: " + message); } return response; } private void saveMapObject(FileOutputStreamFactory fileOutputStreamFactory, File file, String entryKey, ShortCircuitResponseInformation information) throws IOException { // if file does not exists, then create it if (!file.exists()) { if (file.getParentFile() != null) { file.getParentFile().mkdirs(); } file.createNewFile(); } FileOutputStream fos = fileOutputStreamFactory.createFileOutputStream(file); fos.write(("{\n \"Key\": \"" + entryKey + "\",\n").getBytes()); fos.write((" \"ResponseCode\": " + information.getStatusCode() + ",\n").getBytes()); fos.write((" \"ContentType\": \"" + information.getContentType() + "\",\n").getBytes()); Map<String, String> headers = information.getHeaders(); if (headers != null) { fos.write(" \"Headers\": [".getBytes()); int j = 1; for (String key : headers.keySet()) { fos.write((" { \"" + key + "\": \"" + encodeString(headers.get(key)) + "\" }").getBytes()); if (j != headers.size()) { fos.write(",".getBytes()); } fos.write("\n".getBytes()); j++; } fos.write(" ],\n".getBytes()); } fos.write(" \"Body\": ".getBytes()); String myBody = new JSONObject().put("Body", encodeString(information.getBody())).toString(); fos.write((myBody + "\n}").getBytes()); fos.close(); } /** * Load the map from a folder, and create a new map from it. * * @param path is the folder to be used, under Wilma's message folder. */ void loadPreservedMessagesToMap(String path) { //Map<String, ShortCircuitResponseInformation> newShortCircuitMap = new HashMap<>(); File folderFile = new File(path); File[] listOfFiles = folderFile.listFiles(); if (listOfFiles != null) { for (int i = 0; i < listOfFiles.length; i++) { if (listOfFiles[i].isFile() && listOfFiles[i].getName().endsWith(".json")) { try { ShortCircuitResponseInformation mapObject = loadMapObject(listOfFiles[i].getAbsolutePath()); if (mapObject != null) { synchronized (SHORT_CIRCUIT_MAP_GUARD) { SHORT_CIRCUIT_MAP.put(mapObject.getHashCode(), mapObject); } } } catch (JSONException e) { logger.info("Cannot load JSON file to Short Circuit map: " + listOfFiles[i].getAbsolutePath() + ", error:" + e.getLocalizedMessage()); } } } } } private ShortCircuitResponseInformation loadMapObject(String fileName) { ShortCircuitResponseInformation result = null; File file = new File(fileName); if (file.exists()) { //load the file String fileContent = loadFileToString(fileName); if (fileContent != null) { JSONObject obj = new JSONObject(fileContent); String hashKey = obj.getString("Key"); int responseCode = obj.getInt("ResponseCode"); String contentType = obj.getString("ContentType"); String body = decodeString(obj.getJSONObject("Body").getString("Body")); JSONArray headerArray = obj.getJSONArray("Headers"); ShortCircuitResponseInformation information = null; if (hashKey != null && contentType != null && body != null) { information = new ShortCircuitResponseInformation(Long.MAX_VALUE); information.setHashCode(hashKey); information.setStatusCode(responseCode); information.setContentType(contentType); information.setBody(body); } if (headerArray != null && information != null) { Map<String, String> headers = new HashMap<>(); for (int i = 0; i < headerArray.length(); i++) { JSONObject o = headerArray.getJSONObject(i); Iterator j = o.keys(); while (j.hasNext()) { String key = (String) j.next(); headers.put(key, decodeString(o.getString(key))); } } information.setHeaders(headers); } result = information; } } return result; } private String loadFileToString(final String fileName) { String text; try { //CHECKSTYLE OFF - ignoring new String() error, as this is the most effective implementation text = new String(Files.readAllBytes(Paths.get(fileName)), StandardCharsets.UTF_8); //CHECKSTYLE ON } catch (IOException e) { //cannot read a file text = null; } return text; } private String encodeString(final String toBeEncoded) { //CHECKSTYLE OFF - ignoring new String() error, as this is the most effective implementation return new String(Base64.encodeBase64(toBeEncoded.getBytes())); //CHECKSTYLE ON } private String decodeString(final String toBeDecoded) { //CHECKSTYLE OFF - ignoring new String() error, as this is the most effective implementation return new String(Base64.decodeBase64(toBeDecoded.getBytes())); //CHECKSTYLE ON } }