001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.jexl3.internal.introspection; 019 020import java.lang.reflect.Constructor; 021import java.lang.reflect.Field; 022import java.lang.reflect.Method; 023import java.lang.reflect.Modifier; 024import org.apache.commons.jexl3.annotations.NoJexl; 025 026/** 027 * Checks whether an element (ctor, field or method) is visible by JEXL introspection. 028 * Default implementation does this by checking if element has been annotated with NoJexl. 029 */ 030public class Permissions { 031 /** Allow inheritance. */ 032 protected Permissions() { 033 } 034 /** 035 * The default singleton. 036 */ 037 public static final Permissions DEFAULT = new Permissions(); 038 039 /** 040 * Checks whether a package explicitly disallows JEXL introspection. 041 * @param pack the package 042 * @return true if JEXL is allowed to introspect, false otherwise 043 */ 044 public boolean allow(final Package pack) { 045 if (pack == null || pack.getAnnotation(NoJexl.class) != null) { 046 return false; 047 } 048 return true; 049 } 050 051 /** 052 * Checks whether a class or one of its super-classes or implemented interfaces 053 * explicitly disallows JEXL introspection. 054 * @param clazz the class to check 055 * @return true if JEXL is allowed to introspect, false otherwise 056 */ 057 public boolean allow(final Class<?> clazz) { 058 return clazz != null && allow(clazz.getPackage()) && allow(clazz, true); 059 } 060 061 /** 062 * Checks whether a constructor explicitly disallows JEXL introspection. 063 * @param ctor the constructor to check 064 * @return true if JEXL is allowed to introspect, false otherwise 065 */ 066 public boolean allow(final Constructor<?> ctor) { 067 if (ctor == null) { 068 return false; 069 } 070 if (!Modifier.isPublic(ctor.getModifiers())) { 071 return false; 072 } 073 final Class<?> clazz = ctor.getDeclaringClass(); 074 if (!allow(clazz, false)) { 075 return false; 076 } 077 // is ctor annotated with nojexl ? 078 final NoJexl nojexl = ctor.getAnnotation(NoJexl.class); 079 if (nojexl != null) { 080 return false; 081 } 082 return true; 083 } 084 085 /** 086 * Checks whether a field explicitly disallows JEXL introspection. 087 * @param field the field to check 088 * @return true if JEXL is allowed to introspect, false otherwise 089 */ 090 public boolean allow(final Field field) { 091 if (field == null) { 092 return false; 093 } 094 if (!Modifier.isPublic(field.getModifiers())) { 095 return false; 096 } 097 final Class<?> clazz = field.getDeclaringClass(); 098 if (!allow(clazz, false)) { 099 return false; 100 } 101 // is field annotated with nojexl ? 102 final NoJexl nojexl = field.getAnnotation(NoJexl.class); 103 if (nojexl != null) { 104 return false; 105 } 106 return true; 107 } 108 109 /** 110 * Checks whether a method explicitly disallows JEXL introspection. 111 * <p>Since methods can be overridden, this also checks that no superclass or interface 112 * explicitly disallows this methods.</p> 113 * @param method the method to check 114 * @return true if JEXL is allowed to introspect, false otherwise 115 */ 116 public boolean allow(final Method method) { 117 if (method == null) { 118 return false; 119 } 120 if (!Modifier.isPublic(method.getModifiers())) { 121 return false; 122 } 123 // is method annotated with nojexl ? 124 NoJexl nojexl = method.getAnnotation(NoJexl.class); 125 if (nojexl != null) { 126 return false; 127 } 128 // is the class annotated with nojexl ? 129 Class<?> clazz = method.getDeclaringClass(); 130 nojexl = clazz.getAnnotation(NoJexl.class); 131 if (nojexl != null) { 132 return false; 133 } 134 // lets walk all interfaces 135 for (final Class<?> inter : clazz.getInterfaces()) { 136 if (!allow(inter, method)) { 137 return false; 138 } 139 } 140 // lets walk all super classes 141 clazz = clazz.getSuperclass(); 142 // walk all superclasses 143 while (clazz != null) { 144 if (!allow(clazz, method)) { 145 return false; 146 } 147 clazz = clazz.getSuperclass(); 148 } 149 return true; 150 } 151 152 /** 153 * Checks whether a class or one of its superclasses or implemented interfaces 154 * explicitly disallows JEXL introspection. 155 * @param clazz the class to check 156 * @param interf whether interfaces should be checked as well 157 * @return true if JEXL is allowed to introspect, false otherwise 158 */ 159 protected boolean allow(Class<?> clazz, final boolean interf) { 160 if (clazz == null) { 161 return false; 162 } 163 if (!Modifier.isPublic(clazz.getModifiers())) { 164 return false; 165 } 166 // lets walk all interfaces 167 if (interf) { 168 for (final Class<?> inter : clazz.getInterfaces()) { 169 // is clazz annotated with nojexl ? 170 final NoJexl nojexl = inter.getAnnotation(NoJexl.class); 171 if (nojexl != null) { 172 return false; 173 } 174 } 175 } 176 // lets walk all super classes 177 clazz = clazz.getSuperclass(); 178 // walk all superclasses 179 while (clazz != null) { 180 // is clazz annotated with nojexl ? 181 final NoJexl nojexl = clazz.getAnnotation(NoJexl.class); 182 if (nojexl != null) { 183 return false; 184 } 185 clazz = clazz.getSuperclass(); 186 } 187 return true; 188 } 189 190 /** 191 * Check whether a method is allowed to be JEXL introspected in all its 192 * superclasses and interfaces. 193 * @param clazz the class 194 * @param method the method 195 * @return true if JEXL is allowed to introspect, false otherwise 196 */ 197 protected boolean allow(final Class<?> clazz, final Method method) { 198 if (clazz != null) { 199 try { 200 // check if method in that class is different from the method argument 201 final Method wmethod = clazz.getMethod(method.getName(), method.getParameterTypes()); 202 if (wmethod != null) { 203 NoJexl nojexl = clazz.getAnnotation(NoJexl.class); 204 if (nojexl != null) { 205 return false; 206 } 207 // check if parent declaring class said nojexl (transitivity) 208 nojexl = wmethod.getAnnotation(NoJexl.class); 209 if (nojexl != null) { 210 return false; 211 } 212 } 213 } catch (final NoSuchMethodException ex) { 214 // unexpected, return no 215 return true; 216 } catch (final SecurityException ex) { 217 // unexpected, can't do much 218 return false; 219 } 220 } 221 return true; 222 } 223}