001: /*
002:
003: Derby - Class org.apache.derby.impl.services.bytecode.d_BCValidate
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.services.bytecode;
023:
024: import java.lang.reflect.*;
025: import org.apache.derby.iapi.services.classfile.VMOpcode;
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import java.util.Hashtable;
028: import org.apache.derby.iapi.services.loader.*;
029: import org.apache.derby.iapi.services.context.*;
030:
031: /**
032: * Validate BC calls.
033: *
034: * @author jamie
035: */
036: class d_BCValidate {
037:
038: private static final String[] csPackages = { "java",
039: "org.apache.derby.exe.", "org.apache.derby.iapi.",
040: "org.apache.derby.jdbc.", "org.apache.derby.iapi.",
041: "org.apache.derby.impl.",
042: "org.apache.derby.authentication.",
043: "org.apache.derby.catalog.", "org.apache.derby.iapi.db.",
044: "org.apache.derby.iapi.types.",
045: "org.apache.derby.iapi.types.",
046: "org.apache.derby.catalog.types.", };
047:
048: private static final Class[] NO_PARAMS = new Class[0];
049:
050: static void checkMethod(short opcode, Type dt, String methodName,
051: String[] debugParameterTypes, Type rt) {
052:
053: if (SanityManager.DEBUG) {
054: String reason = null;
055: try {
056:
057: String declaringClass = dt.javaName();
058: if (declaringClass.startsWith("org.apache.derby.exe."))
059: return;
060:
061: // only validate against Cloudscape engine or Java classes. Not user defined classes
062: int p;
063: for (p = 0; p < csPackages.length; p++) {
064: if (declaringClass.startsWith(csPackages[p]))
065: break;
066: }
067: if (p == csPackages.length)
068: return;
069:
070: Class[] params = NO_PARAMS;
071:
072: Class declaring = loadClass(declaringClass);
073:
074: if (debugParameterTypes != null) {
075: params = new Class[debugParameterTypes.length];
076: for (int i = 0; i < debugParameterTypes.length; i++) {
077: params[i] = loadClass(debugParameterTypes[i]);
078: }
079:
080: }
081:
082: // If the class is not in the same class loader then it
083: // it must be a non-Derby class. In that case any method etc.
084: // being accessed must be public, so don't use the getDeclared
085: // methods. Default SecurityManager behaviour is to grant access to public members
086: // and members from classes loaded by the same class loader. Thus
087: // we try to fall into these categories to avoid having to grant
088: // permissions to derby jars for the function tests.
089:
090: ClassLoader declareLoader = declaring.getClassLoader();
091: ClassLoader myLoader = d_BCValidate.class
092: .getClassLoader();
093:
094: boolean sameClassLoader = false;
095: if (declareLoader == myLoader)
096: sameClassLoader = true;
097: else if (declareLoader != null)
098: sameClassLoader = declareLoader.equals(myLoader);
099:
100: String actualReturnType;
101:
102: if (methodName.equals("<init>")) {
103: Constructor c;
104:
105: if (sameClassLoader) {
106: c = declaring.getDeclaredConstructor(params);
107: } else {
108: c = declaring.getConstructor(params);
109:
110: // check this construct is declared by this
111: // class, has to be, right? But no harm checking.
112: if (!c.getDeclaringClass().equals(declaring)) {
113: reason = "constructor " + c.toString()
114: + " declared on "
115: + c.getDeclaringClass()
116: + " expected " + declaring;
117: }
118: }
119:
120: actualReturnType = "void";
121: } else {
122: Method m;
123:
124: if (sameClassLoader) {
125: m = declaring.getDeclaredMethod(methodName,
126: params);
127: } else {
128: m = declaring.getMethod(methodName, params);
129:
130: // check this method is declared by this
131: // class? But no harm checking.
132: if (!m.getDeclaringClass().equals(declaring)) {
133: reason = "method " + m.toString()
134: + " declared on "
135: + m.getDeclaringClass()
136: + " expected " + declaring;
137: }
138: }
139:
140: actualReturnType = m.getReturnType().getName();
141: }
142:
143: // do we already have a problem?
144: if (reason == null) {
145:
146: Class requestedReturnType = loadClass(rt.javaName());
147:
148: // check the return type
149: if (actualReturnType.equals(requestedReturnType
150: .getName())) {
151:
152: // check the inteface match
153: if (opcode != VMOpcode.INVOKEINTERFACE)
154: return;
155:
156: if (declaring.isInterface())
157: return;
158:
159: reason = "declaring class is not an interface";
160:
161: } else {
162: reason = "return type is " + actualReturnType;
163: }
164: }
165:
166: } catch (Exception e) {
167: reason = e.toString();
168: e.printStackTrace(System.out);
169: }
170:
171: String sig = dt.javaName() + " >> " + rt.javaName() + " "
172: + methodName + "(";
173: if (debugParameterTypes != null) {
174: for (int i = 0; i < debugParameterTypes.length; i++) {
175: if (i != 0)
176: sig = sig + ", ";
177: sig = sig + debugParameterTypes[i];
178: }
179: }
180: sig = sig + ")";
181:
182: String msg = "Invalid method " + sig + " because " + reason;
183:
184: System.out.println(msg);
185: SanityManager.THROWASSERT(msg);
186: }
187: }
188:
189: private static Hashtable primitives;
190:
191: static {
192: if (SanityManager.DEBUG) {
193: primitives = new Hashtable();
194: primitives.put("boolean", Boolean.TYPE);
195: primitives.put("byte", Byte.TYPE);
196: primitives.put("char", Character.TYPE);
197: primitives.put("double", Double.TYPE);
198: primitives.put("float", Float.TYPE);
199: primitives.put("int", Integer.TYPE);
200: primitives.put("long", Long.TYPE);
201: primitives.put("short", Short.TYPE);
202: primitives.put("void", Void.TYPE);
203: }
204:
205: }
206:
207: private static Class loadClass(String name)
208: throws ClassNotFoundException {
209:
210: if (SanityManager.DEBUG) {
211:
212: Class c = (Class) primitives.get(name);
213: if (c != null)
214: return c;
215:
216: if (name.endsWith("[]")) {
217: Class baseClass = loadClass(name.substring(0, name
218: .length() - 2));
219: return Array.newInstance(baseClass, 0).getClass();
220: }
221:
222: return Class.forName(name);
223: }
224:
225: return null;
226: }
227: }
|