/* * This file is part of ReadonlyREST. * * ReadonlyREST 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. * * ReadonlyREST 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 ReadonlyREST. If not, see http://www.gnu.org/licenses/ */ package org.elasticsearch.plugin.readonlyrest.utils; import org.apache.logging.log4j.Logger; import org.elasticsearch.plugin.readonlyrest.ESContext; import org.elasticsearch.plugin.readonlyrest.SecurityPermissionException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Set; import static org.reflections.ReflectionUtils.getAllFields; /** * Created by sscarduzio on 24/03/2017. */ public class ReflecUtils { public static String[] extractStringArrayFromPrivateMethod(String methodName, Object o, ESContext context) { final String[][] result = {new String[]{}}; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { if (o == null) { throw context.rorException("cannot extract field from null!"); } Class<?> clazz = o.getClass(); while (!clazz.equals(Object.class)) { try { Method m = exploreClassMethods(clazz, methodName, String[].class); if (m != null) { result[0] = (String[]) m.invoke(o); return null; } m = exploreClassMethods(clazz, methodName, String.class); if (m != null) { result[0] = new String[]{(String) m.invoke(o)}; return null; } } catch (SecurityException e) { context.logger(ReflecUtils.class) .error("Can't get indices for request because of wrong security configuration " + o.getClass()); throw new SecurityPermissionException( "Insufficient permissions to extract field " + methodName + ". Abort! Cause: " + e.getMessage(), e); } catch (Exception e) { context.logger(ReflecUtils.class) .debug("Cannot to discover field " + methodName + " associated to this request: " + o.getClass()); } clazz = clazz.getSuperclass(); } return null; }); return result[0]; } private static Method exploreClassMethods(Class<?> c, String methodName, Class<?> returnClass) { // Explore methods without the performance cost of throwing field not found exceptions.. // The native implementation is O(n), so we do likewise, but without the exception object creation. for (Method m : c.getDeclaredMethods()) { m.setAccessible(true); if (methodName.equals(m.getName()) && m.getReturnType().equals(returnClass)) { return m; } } return null; } private static Field exploreClassFields(Class<?> c, String fieldName) throws NoSuchFieldException { // Explore fields without the performance cost of throwing field not found exceptions.. // The native implementation is O(n), so we do likewise, but without the exception object creation. for (Field f : c.getDeclaredFields()) { if (fieldName.equals(f.getName())) { f.setAccessible(true); return f; } } return null; } public static boolean setIndices(Object o, Set<String> fieldNames, Set<String> newIndices, Logger logger) { final boolean[] res = {false}; AccessController.doPrivileged((PrivilegedAction<Void>) () -> { @SuppressWarnings("unchecked") Set<Field> indexFields = getAllFields( o.getClass(), (Field field) -> field != null && fieldNames.contains(field.getName()) && (field.getType().equals(String.class) || field.getType().equals(String[].class)) ); String firstIndex = newIndices.iterator().next(); for (Field f : indexFields) { f.setAccessible(true); try { if (f.getType().equals(String[].class)) { f.set(o, newIndices.toArray(new String[]{})); } else { f.set(o, firstIndex); } res[0] = true; } catch (IllegalAccessException | IllegalArgumentException e) { logger.error("could not find index or indices field to replace: " + e.getMessage() + " and then " + e.getMessage()); } } return null; }); return res[0]; } @FunctionalInterface public interface CheckedFunction<T, R> { R apply(T t) throws IllegalAccessException; } static class SetFieldException extends Exception { SetFieldException(Class<?> c, String id, String fieldName, Throwable e) { super(" Could not set " + fieldName + " to class " + c.getSimpleName() + "for req id: " + id + " because: " + e.getClass().getSimpleName() + " : " + e.getMessage() + (e.getCause() != null ? " caused by: " + e.getCause().getClass().getSimpleName() + " : " + e.getCause().getMessage() : "")); } } }