001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import java.lang.reflect.*;
016
017/**
018 * Defines class/field/method visibilities.
019 * 
020 * <p>
021 * Used to specify minimum levels of visibility when detecting bean classes, methods, and fields.
022 * 
023 * <p>
024 * Used in conjunction with the following bean context properties:
025 * <ul>
026 *    <li class='jf'>{@link BeanContext#BEAN_beanConstructorVisibility}
027 *    <li class='jf'>{@link BeanContext#BEAN_beanClassVisibility}
028 *    <li class='jf'>{@link BeanContext#BEAN_beanFieldVisibility}
029 *    <li class='jf'>{@link BeanContext#BEAN_beanMethodVisibility}
030 * </ul>
031 */
032public enum Visibility {
033
034   /** Ignore all */
035   NONE,
036
037   /** Include only <jk>public</jk> classes/fields/methods. */
038   PUBLIC,
039
040   /** Include only <jk>public</jk> or <jk>protected</jk> classes/fields/methods. */
041   PROTECTED,
042
043   /** Include all but <jk>private</jk> classes/fields/methods. */
044   DEFAULT,
045
046   /** Include all classes/fields/methods. */
047   PRIVATE;
048
049   /**
050    * Identifies if the specified mod matches this visibility.
051    * 
052    * <h5 class='section'>Example:</h5>
053    * <p class='bcode'>
054    *    <jsf>PUBLIC</jsf>.isVisible(MyPublicClass.<jk>class</jk>.getModifiers()); <jc>//true</jc>
055    *    <jsf>PUBLIC</jsf>.isVisible(MyPrivateClass.<jk>class</jk>.getModifiers()); <jc>//false</jc>
056    *    <jsf>PRIVATE</jsf>.isVisible(MyPrivateClass.<jk>class</jk>.getModifiers()); <jc>//true</jc>
057    *    <jsf>NONE</jsf>.isVisible(MyPublicClass.<jk>class</jk>.getModifiers()); <jc>//false</jc>
058    * </p>
059    * 
060    * @param mod The modifier from the object being tested (e.g. results from {@link Class#getModifiers()}.
061    * @return <jk>true</jk> if this visibility matches the specified modifier attribute.
062    */
063   public boolean isVisible(int mod) {
064      switch(this) {
065         case NONE: return false;
066         case PRIVATE: return true;
067         case DEFAULT: return ! Modifier.isPrivate(mod);
068         case PROTECTED: return Modifier.isProtected(mod) || Modifier.isPublic(mod);
069         default: return Modifier.isPublic(mod);
070      }
071   }
072
073   /**
074    * Shortcut for <code>isVisible(x.getModifiers());</code>
075    * 
076    * @param x The constructor to check.
077    * @return <jk>true</jk> if the constructor is at least as visible as this object.
078    */
079   public boolean isVisible(Constructor<?> x) {
080      return isVisible(x.getModifiers());
081   }
082
083   /**
084    * Shortcut for <code>isVisible(x.getModifiers());</code>
085    * 
086    * @param x The method to check.
087    * @return <jk>true</jk> if the method is at least as visible as this object.
088    */
089   public boolean isVisible(Method x) {
090      return isVisible(x.getModifiers());
091   }
092
093   /**
094    * Shortcut for <code>isVisible(x.getModifiers());</code>
095    * 
096    * @param x The field to check.
097    * @return <jk>true</jk> if the field is at least as visible as this object.
098    */
099   public boolean isVisible(Field x) {
100      return isVisible(x.getModifiers());
101   }
102
103   /**
104    * Makes constructor accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
105    * 
106    * <p>
107    * Security exceptions thrown on the call to {@link Constructor#setAccessible(boolean)} are quietly ignored.
108    * 
109    * @param x The constructor.
110    * @return
111    *    The same constructor if visibility requirements met, or <jk>null</jk> if visibility requirement not
112    *    met or call to {@link Constructor#setAccessible(boolean)} throws a security exception.
113    */
114   public <T> Constructor<T> transform(Constructor<T> x) {
115      if (x == null)
116         return null;
117      if (isVisible(x))
118         if (! setAccessible(x))
119            return null;
120      return x;
121   }
122
123   /**
124    * Makes method accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
125    * 
126    * <p>
127    * Security exceptions thrown on the call to {@link Method#setAccessible(boolean)} are quietly ignored.
128    * 
129    * @param x The method.
130    * @return
131    *    The same method if visibility requirements met, or <jk>null</jk> if visibility requirement not
132    *    met or call to {@link Method#setAccessible(boolean)} throws a security exception.
133    */
134   public Method transform(Method x) {
135      if (x == null)
136         return null;
137      if (isVisible(x))
138         if (! setAccessible(x))
139            return null;
140      return x;
141   }
142
143   /**
144    * Makes field accessible if it matches the visibility requirements, or returns <jk>null</jk> if it doesn't.
145    * 
146    * <p>
147    * Security exceptions thrown on the call to {@link Field#setAccessible(boolean)} are quietly ignored.
148    * 
149    * @param x The field.
150    * @return
151    *    The same field if visibility requirements met, or <jk>null</jk> if visibility requirement not
152    *    met or call to {@link Field#setAccessible(boolean)} throws a security exception.
153    */
154   public Field transform(Field x) {
155      if (x == null)
156         return null;
157      if (isVisible(x))
158         if (! setAccessible(x))
159            return null;
160      return x;
161   }
162
163   /**
164    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
165    * 
166    * @param x The constructor.
167    * @return <jk>true</jk> if call was successful.
168    */
169   public static boolean setAccessible(Constructor<?> x) {
170      try {
171         if (! (x == null || x.isAccessible()))
172            x.setAccessible(true);
173         return true;
174      } catch (SecurityException e) {
175         return false;
176      }
177   }
178
179   /**
180    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
181    * 
182    * @param x The method.
183    * @return <jk>true</jk> if call was successful.
184    */
185   public static boolean setAccessible(Method x) {
186      try {
187         if (! (x == null || x.isAccessible()))
188            x.setAccessible(true);
189         return true;
190      } catch (SecurityException e) {
191         return false;
192      }
193   }
194
195   /**
196    * Attempts to call <code>x.setAccessible(<jk>true</jk>)</code> and quietly ignores security exceptions.
197    * 
198    * @param x The field.
199    * @return <jk>true</jk> if call was successful.
200    */
201   public static boolean setAccessible(Field x) {
202      try {
203         if (! (x == null || x.isAccessible()))
204            x.setAccessible(true);
205         return true;
206      } catch (SecurityException e) {
207         return false;
208      }
209   }
210}