/* * 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.ignite.console.agent; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule; import io.socket.client.Ack; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.security.ProtectionDomain; import java.util.Arrays; import org.apache.log4j.Logger; import org.json.JSONArray; import org.json.JSONObject; /** * Utility methods. */ public class AgentUtils { /** */ private static final Logger log = Logger.getLogger(AgentUtils.class.getName()); /** JSON object mapper. */ private static final ObjectMapper mapper = new ObjectMapper(); /** */ private static final Ack NOOP_CB = new Ack() { @Override public void call(Object... args) { if (args != null && args.length > 0 && args[0] instanceof Throwable) log.error("Failed to execute request on agent.", (Throwable) args[0]); else log.info("Request on agent successfully executed " + Arrays.toString(args)); } }; static { JsonOrgModule module = new JsonOrgModule(); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); mapper.registerModule(module); } /** * Default constructor. */ private AgentUtils() { // No-op. } /** * @param path Path to normalize. * @return Normalized file path. */ public static String normalizePath(String path) { return path != null ? path.replace('\\', '/') : null; } /** * @return App folder. */ public static File getAgentHome() { try { ProtectionDomain domain = AgentLauncher.class.getProtectionDomain(); // Should not happen, but to make sure our code is not broken. if (domain == null || domain.getCodeSource() == null || domain.getCodeSource().getLocation() == null) { log.warn("Failed to resolve agent jar location!"); return null; } // Resolve path to class-file. URI classesUri = domain.getCodeSource().getLocation().toURI(); boolean win = System.getProperty("os.name").toLowerCase().contains("win"); // Overcome UNC path problem on Windows (http://www.tomergabel.com/JavaMishandlesUNCPathsOnWindows.aspx) if (win && classesUri.getAuthority() != null) classesUri = new URI(classesUri.toString().replace("file://", "file:/")); return new File(classesUri).getParentFile(); } catch (URISyntaxException | SecurityException ignored) { log.warn("Failed to resolve agent jar location!"); return null; } } /** * Gets file associated with path. * <p> * First check if path is relative to agent home. * If not, check if path is absolute. * If all checks fail, then {@code null} is returned. * <p> * * @param path Path to resolve. * @return Resolved path as file, or {@code null} if path cannot be resolved. */ public static File resolvePath(String path) { assert path != null; File home = getAgentHome(); if (home != null) { File file = new File(home, normalizePath(path)); if (file.exists()) return file; } // 2. Check given path as absolute. File file = new File(path); if (file.exists()) return file; return null; } /** * Get callback from handler arguments. * * @param args Arguments. * @return Callback or noop callback. */ public static Ack safeCallback(Object[] args) { boolean hasCb = args != null && args.length > 0 && args[args.length - 1] instanceof Ack; return hasCb ? (Ack)args[args.length - 1] : NOOP_CB; } /** * Remove callback from handler arguments. * * @param args Arguments. * @return Arguments without callback. */ public static Object[] removeCallback(Object[] args) { boolean hasCb = args != null && args.length > 0 && args[args.length - 1] instanceof Ack; return hasCb ? Arrays.copyOf(args, args.length - 1) : args; } /** * Map java object to JSON object. * * @param obj Java object. * @return {@link JSONObject} or {@link JSONArray}. * @throws IllegalArgumentException If conversion fails due to incompatible type. */ public static Object toJSON(Object obj) { if (obj instanceof Iterable) return mapper.convertValue(obj, JSONArray.class); return mapper.convertValue(obj, JSONObject.class); } /** * Map JSON object to java object. * * @param obj {@link JSONObject} or {@link JSONArray}. * @param toValType Expected value type. * @return Mapped object type of {@link T}. * @throws IllegalArgumentException If conversion fails due to incompatible type. */ public static <T> T fromJSON(Object obj, Class<T> toValType) throws IllegalArgumentException { return mapper.convertValue(obj, toValType); } }