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: /**
018: * @author Evgueni Brevnov
019: * @version $Revision: 1.1.2.2.4.4 $
020: */package java.lang.reflect;
021:
022: import org.apache.harmony.lang.reflect.ReflectAccessor;
023:
024: /**
025: * @com.intel.drl.spec_ref
026: */
027: class ReflectExporter implements ReflectAccessor {
028:
029: public <T> Constructor<T> copyConstructor(Constructor<T> c) {
030: return new Constructor<T>(c);
031: }
032:
033: public Field copyField(Field f) {
034: return new Field(f);
035: }
036:
037: public Method copyMethod(Method m) {
038: return new Method(m);
039: }
040:
041: public Method[] mergePublicMethods(Method[] declared,
042: Method[] super Public, Method[][] intf, int estimate) {
043: Method[] store = new Method[estimate];
044: int size = 0;
045: for (Method m : declared) {
046: if (Modifier.isPublic(m.getModifiers())) {
047: store[size++] = m;
048: }
049: }
050: if (super Public != null) {
051: nextSuper: for (Method m : super Public) {
052: for (int i = 0; i < size; i++) {
053: if (m.getName() == store[i].getName()
054: && m.getSignature() == store[i]
055: .getSignature()) {
056: continue nextSuper;
057: }
058: }
059: store[size++] = m;
060: }
061: }
062: if (intf != null) {
063: for (Method[] mi : intf) {
064: nextIntf: for (Method m : mi) {
065: for (int i = 0; i < size; i++) {
066: if (m.getName() == store[i].getName()
067: && m.getSignature() == store[i]
068: .getSignature()) {
069: continue nextIntf;
070: }
071: }
072: store[size++] = m;
073: }
074: }
075: }
076: Method[] real = new Method[size];
077: System.arraycopy(store, 0, real, 0, size);
078:
079: return real;
080: }
081:
082: public void checkMemberAccess(Class callerClass,
083: Class declaringClass, Class runtimeClass,
084: int memberModifiers) throws IllegalAccessException {
085: if (!allowAccess(callerClass, declaringClass, runtimeClass,
086: memberModifiers)) {
087: throw new IllegalAccessException("A member of the \""
088: + declaringClass + "\" with \""
089: + Modifier.toString(memberModifiers)
090: + "\" modifiers can not be accessed from the \""
091: + callerClass + "\"");
092: }
093: }
094:
095: /*
096: * NON EXPORTED
097: */
098:
099: private boolean allowAccess(Class<?> callerClass,
100: Class<?> declaringClass, Class<?> runtimeClass,
101: int memberModifiers) {
102: // it is allways safe to access members from the class declared in the
103: // same top level class as the declaring class
104: if (hasSameTopLevelClass(declaringClass, callerClass)) {
105: return true;
106: }
107: // no way to access private methods at this point
108: if (Modifier.isPrivate(memberModifiers)) {
109: return false;
110: }
111: // check access to public members
112: if (Modifier.isPublic(memberModifiers)) {
113: // fast check
114: if (allowClassAccess(declaringClass, callerClass)) {
115: return true;
116: }
117: // full inspection of the hierarchy
118: if (runtimeClass != declaringClass) {
119: do {
120: if (allowClassAccess(runtimeClass, callerClass)
121: || hasSameTopLevelClass(runtimeClass,
122: callerClass)) {
123: return true;
124: }
125: } while ((runtimeClass = runtimeClass.getSuperclass()) != declaringClass);
126: }
127: return false;
128: }
129:
130: // this check should cover package private access
131: if (hasSamePackage(declaringClass, callerClass)
132: && allowClassAccess(declaringClass, callerClass)) {
133: return true;
134: }
135:
136: // check access to protected members through hierarchy
137: if (Modifier.isProtected(memberModifiers)) {
138: Class<?> outerClass = callerClass;
139: // scan from the caller to the top level class
140: do {
141: // find closest enclouser class which extends declaring class
142: while (!declaringClass.isAssignableFrom(outerClass)) {
143: outerClass = outerClass.getDeclaringClass();
144: if (outerClass == null) {
145: return false;
146: }
147: }
148: // provide access if and only if outer is subclass of runtime class
149: if (outerClass.isAssignableFrom(runtimeClass)) {
150: return true;
151: }
152: outerClass = outerClass.getDeclaringClass();
153: } while (outerClass != null);
154: }
155: return false;
156: }
157:
158: private boolean allowClassAccess(Class<?> callee, Class<?> caller) {
159: if (callee == null || callee == caller) {
160: return true;
161: }
162: int modifiers = callee.getModifiers();
163: Class calleeDeclaringClass = callee.getDeclaringClass();
164: if (calleeDeclaringClass == null) {
165: // the callee is either a top level class or a local class
166: if (Modifier.isPublic(modifiers)
167: || hasSamePackage(callee, caller)) {
168: return true;
169: }
170: // other top level classes and local classes
171: return false;
172: }
173: // here callee is a member class
174: return allowAccess(caller, calleeDeclaringClass,
175: calleeDeclaringClass, modifiers);
176: }
177:
178: private boolean hasSameTopLevelClass(Class<?> class1,
179: Class<?> class2) {
180: Class topClass;
181: while ((topClass = class1.getEnclosingClass()) != null) {
182: class1 = topClass;
183: }
184: while ((topClass = class2.getEnclosingClass()) != null) {
185: class2 = topClass;
186: }
187: return class1 == class2;
188: }
189:
190: private boolean hasSamePackage(Class<?> class1, Class<?> class2) {
191: if (class1.getClassLoader() != class2.getClassLoader()) {
192: return false;
193: }
194: final String pkg1 = class1.getName();
195: final String pkg2 = class2.getName();
196: int i1 = pkg1.lastIndexOf('.');
197: int i2 = pkg2.lastIndexOf('.');
198: // in the case of default packages i1 == i2 == -1
199: return i1 == i2 ? pkg1.regionMatches(0, pkg2, 0, i1) : false;
200: }
201: }
|