package com.smockin.utils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.smockin.admin.enums.UserModeEnum; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.apache.http.client.utils.URLEncodedUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import spark.Request; import java.io.*; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Created by mgallina. */ public final class GeneralUtils { private static final Logger logger = LoggerFactory.getLogger(GeneralUtils.class); public static final String ISO_DATE_FORMAT = "yyyy-MM-dd"; public static final String ISO_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; public static final String UNIQUE_TIMESTAMP_FORMAT = "yyMMdd_HHmmss"; public static final String OAUTH_HEADER_VALUE_PREFIX = "Bearer"; public static final String OAUTH_HEADER_NAME = "Authorization"; public static final String KEEP_EXISTING_HEADER_NAME = "KeepExisting"; public static final String ENABLE_CORS_PARAM = "ENABLE_CORS"; public static final String LOG_REQ_ID = "X-Smockin-Trace-ID"; public static final String PROXIED_RESPONSE_HEADER = "X-Proxied-Response"; static final ObjectMapper JSON_MAPPER = new ObjectMapper(); static { JSON_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } public final static String generateUUID() { return UUID.randomUUID().toString(); } // Should be set to UTC from command line public final static Date getCurrentDate() { return Date.from(getCurrentDateTime().atZone(ZoneId.systemDefault()).toInstant()); } public final static Date toDate(final LocalDateTime localDateTime) { return Date.from(localDateTime.toInstant(ZoneOffset.UTC)); } public final static LocalDateTime getCurrentDateTime() { return LocalDateTime.now(); } public final static Instant getCurrentDateTimeInstant() { return getCurrentDateTime().toInstant(ZoneOffset.UTC); } public final static String createFileNameUniqueTimeStamp() { return new SimpleDateFormat(UNIQUE_TIMESTAMP_FORMAT) .format(getCurrentDate()); } /** * * Returns the header value for the given name. * Look up is case insensitive (as Java Spark handles header look ups with case sensitivity, which is wrong) * * @param request * @param headerName * @returns String * */ public static String findHeaderIgnoreCase(final Request request, final String headerName) { for (String h : request.headers()) { if (h.equalsIgnoreCase(headerName)) { return request.headers(h); } } return null; } /** * * Returns the request parameter value for the given name. * Look up is case insensitive (as Java Spark handles request parameter look ups with case sensitivity. Unclear on what the standard is for this...) * * @param request * @param requestParamName * @returns String * */ public static String findRequestParamIgnoreCase(final Request request, final String requestParamName) { for (String q : request.queryParams()) { if (q.equalsIgnoreCase(requestParamName)) { return request.queryParams(q); } } return null; } public static String findPathVarIgnoreCase(final String inboundPath, final String mockPath, final String pathVarName) { if (pathVarName == null) { return null; } return findAllPathVars(inboundPath, mockPath).get(pathVarName.toLowerCase()); } public static Map<String, String> findAllPathVars(final String inboundPath, final String mockPath) { final String[] inboundPathSegments = StringUtils.split(inboundPath, "/"); final String[] mockPathSegments = StringUtils.split(mockPath, "/"); final Map<String, String> pathVars = new HashMap<>(); if (inboundPathSegments.length < mockPathSegments.length) { return pathVars; } int index = 0; for (String segment : mockPathSegments) { if (segment != null && ("*".equals(segment) || (segment.startsWith("{") && segment.endsWith("}")))) { segment = StringUtils.remove(segment, "{"); segment = StringUtils.remove(segment, "}"); if ("*".equals(segment)) { segment = "*" + index; } pathVars.put(segment.toLowerCase(), inboundPathSegments[index]); } index++; } return pathVars; } public static String sanitizeMultiUserPath(final UserModeEnum usermode, final String pathInfo, final String ctxPath) { return ( UserModeEnum.ACTIVE.equals(usermode) && StringUtils.isNotBlank(ctxPath) ) ? StringUtils.removeFirst(pathInfo, ctxPath) : pathInfo; } public static void checkForAndHandleSleep(final long sleepInMillis) { if (sleepInMillis > 0) { try { Thread.sleep(sleepInMillis); } catch (InterruptedException ex) { logger.error("Error pausing response for the specified period of " + sleepInMillis, ex); } } } public static String prefixPath(final String path) { if (StringUtils.isBlank(path)) { return null; } final String prefix = "/"; if (!path.startsWith(prefix)) { return prefix + path; } return path; } public static int exactVersionNo(String versionNo) { if (versionNo == null) throw new IllegalArgumentException("versionNo is not defined"); versionNo = org.apache.commons.lang3.StringUtils.removeIgnoreCase(versionNo, "-SNAPSHOT"); versionNo = org.apache.commons.lang3.StringUtils.remove(versionNo, "."); if (!NumberUtils.isDigits(versionNo)) throw new IllegalArgumentException("extracted versionNo is not a valid number: " + versionNo); return Integer.valueOf(versionNo); } public static String removeAllLineBreaks(final String original) { return StringUtils.replaceAll(original, System.getProperty("line.separator"), ""); } public static List<Map<String, ?>> deserialiseJSONToList(final String jsonStr) { return deserialiseJson(jsonStr); } public static Map<String, ?> deserialiseJSONToMap(final String jsonStr) { return deserialiseJson(jsonStr); } public static <T> T deserialiseJson(final String jsonStr) { return deserialiseJson(jsonStr, true); } public static Map<String, ?> deserialiseJSONToMap(final String jsonStr, final boolean logFailure) { return deserialiseJson(jsonStr, logFailure); } public static <T> T deserialiseJson(final String jsonStr, final boolean logFailure) { if (jsonStr != null) { try { return JSON_MAPPER.readValue(jsonStr, new TypeReference<T>() {}); } catch (IOException e) { if (logFailure) { logger.error("Error de-serialising json", e); } // always fail silently } } return null; } public static <T> T deserialiseJson(final String jsonStr, final TypeReference<T> type) { if (jsonStr != null) { try { return JSON_MAPPER.readValue(jsonStr, type); } catch (IOException e) { logger.error("Error de-serialising json", e); // fail silently } } return null; } public static <T> String serialiseJson(final T t) { try { return JSON_MAPPER.writeValueAsString(t); } catch (JsonProcessingException e) { logger.error("Error serialising json", e); // fail silently } return null; } public static String extractOAuthToken(final String bearerToken) { if (bearerToken == null) { return null; } return StringUtils.replace(bearerToken, OAUTH_HEADER_VALUE_PREFIX, "").trim(); } public static String getFileTypeExtension(final String fileName) { if (fileName == null) { return null; } final int extPos = fileName.lastIndexOf("."); if (extPos == -1) { return null; } return fileName.substring(extPos); } public static byte[] createArchive(final String zipFileName, final byte[] zipFileContent) { ZipOutputStream zos = null; ByteArrayOutputStream baos = null; try { baos = new ByteArrayOutputStream(); zos = new ZipOutputStream(baos); final ZipEntry entry = new ZipEntry(zipFileName); entry.setSize(zipFileContent.length); zos.putNextEntry(entry); zos.write(zipFileContent); zos.closeEntry(); closeOSQuietly(zos); return baos.toByteArray(); } catch (Throwable ex) { logger.error("Error creating zip archive", ex); closeOSQuietly(zos); closeOSQuietly(baos); } return null; } public static void unpackArchive(final String zipFilePath, final String destDir) { final File dir = new File(destDir); if (!dir.exists()) dir.mkdirs(); final byte[] buffer = new byte[1024]; FileInputStream fis = null; try { fis = new FileInputStream(zipFilePath); final ZipInputStream zis = new ZipInputStream(fis); ZipEntry ze = zis.getNextEntry(); while (ze != null) { final File newFile = new File(destDir + File.separator + ze.getName()); if (ze.isDirectory()) { newFile.mkdir(); } else { FileOutputStream fos = null; try { fos = new FileOutputStream(newFile); int len; while ((len = zis.read(buffer)) > 0) { fos.write(buffer, 0, len); } } finally { closeOSQuietly(fos); } } zis.closeEntry(); ze = zis.getNextEntry(); } zis.closeEntry(); closeISQuietly(zis); } catch (IOException e) { logger.error("Error unpacking archive file", e); } finally { closeISQuietly(fis); } } private static void closeISQuietly(final InputStream is) { if (is != null) { try { is.close(); } catch (IOException e) { logger.error("Error closing input stream", e); } } } private static void closeOSQuietly(final OutputStream os) { if (os != null) { try { os.close(); } catch (IOException e) { logger.error("Error closing output stream", e); } } } public static String extractRequestParamByName(final Request req, final String fieldName) { return extractAllRequestParams(req).get(fieldName); } public static Map<String, String> extractAllRequestParams(final Request req) { final Map<String, String> allParams = req.queryMap() .toMap() .entrySet() .stream() .collect(HashMap::new, (m,v) -> m.put(v.getKey(), (v.getValue() != null && v.getValue().length != 0) ? v.getValue()[0] : null), HashMap::putAll); if (req.contentType() != null && (req.contentType().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) || req.contentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE))) { if (req.body() != null) { allParams.putAll(URLEncodedUtils.parse(req.body(), Charset.defaultCharset()) .stream() .collect(HashMap::new, (m,v) -> m.put(v.getName(), v.getValue()), HashMap::putAll)); } } return allParams; } public static String removeJsComments(final String jsSrc) { final String carriage = "\n"; final String comment = "//"; if (jsSrc == null || StringUtils.indexOf(jsSrc, comment) == -1) { return jsSrc; } // i.e single line if (StringUtils.indexOf(jsSrc, carriage) == -1) { return StringUtils.substring(jsSrc, 0, StringUtils.indexOf(jsSrc, comment)).trim(); } final String[] lines = StringUtils.split(jsSrc, carriage); return Stream.of(lines) .filter(l -> !l.trim().startsWith(comment)) .map(l -> { final int commentInLine = StringUtils.indexOf(l, comment); return (commentInLine > -1) ? StringUtils.substring(l, 0, commentInLine) : l; }) .collect(Collectors.joining(carriage)) .trim(); } }