--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.services.reflect.DatabaseClasses\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.services.reflect;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.loader.ClassFactory;\r
+import org.apache.derby.iapi.services.loader.GeneratedClass;\r
+import org.apache.derby.iapi.services.loader.ClassInspector;\r
+\r
+import org.apache.derby.iapi.services.monitor.ModuleControl;\r
+import org.apache.derby.iapi.services.monitor.ModuleSupportable;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+\r
+import org.apache.derby.iapi.services.stream.HeaderPrintWriter;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+\r
+import org.apache.derby.iapi.services.compiler.*;\r
+import java.lang.reflect.Modifier;\r
+import org.apache.derby.iapi.sql.compile.CodeGeneration;\r
+\r
+import org.apache.derby.iapi.util.ByteArray;\r
+import org.apache.derby.iapi.services.io.FileUtil;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.reference.Property;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.reference.MessageId;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import java.util.Properties;\r
+import java.util.Hashtable;\r
+\r
+import java.io.ObjectStreamClass;\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.Serializable;\r
+\r
+/**\r
+\r
+ An abstract implementation of the ClassFactory. This package can\r
+ be extended to fully implement a ClassFactory. Implementations can\r
+ differ in two areas, how they load a class and how they invoke methods\r
+ of the generated class.\r
+\r
+ <P>\r
+ This class manages a hash table of loaded generated classes and\r
+ their GeneratedClass objects. A loaded class may be referenced\r
+ multiple times -- each class has a reference count associated\r
+ with it. When a load request arrives, if the class has already\r
+ been loaded, its ref count is incremented. For a remove request,\r
+ the ref count is decremented unless it is the last reference,\r
+ in which case the class is removed. This is transparent to users.\r
+\r
+ @see org.apache.derby.iapi.services.loader.ClassFactory\r
+*/\r
+\r
+abstract class DatabaseClasses\r
+ implements ClassFactory, ModuleControl\r
+{\r
+ /*\r
+ ** Fields\r
+ */\r
+\r
+ private ClassInspector classInspector;\r
+ private JavaFactory javaFactory;\r
+\r
+ private UpdateLoader applicationLoader;\r
+\r
+ /*\r
+ ** Constructor\r
+ */\r
+\r
+ DatabaseClasses() {\r
+ }\r
+\r
+ /*\r
+ ** Public methods of ModuleControl\r
+ */\r
+\r
+ public void boot(boolean create, Properties startParams)\r
+ throws StandardException\r
+ {\r
+\r
+ classInspector = new ClassInspector(this);\r
+\r
+ //\r
+ //The ClassFactory runs per service (database) mode (booted as a service module after AccessFactory).\r
+ //If the code that booted\r
+ //us needs a per-database classpath then they pass in the classpath using\r
+ //the runtime property BOOT_DB_CLASSPATH in startParams\r
+\r
+\r
+ String classpath = null;\r
+ if (startParams != null) {\r
+ classpath = startParams.getProperty(Property.BOOT_DB_CLASSPATH);\r
+ }\r
+\r
+ if (classpath != null) {\r
+ applicationLoader = new UpdateLoader(classpath, this, true,\r
+ true);\r
+ }\r
+\r
+ javaFactory = (JavaFactory) org.apache.derby.iapi.services.monitor.Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.JavaFactory);\r
+ }\r
+\r
+\r
+\r
+ public void stop() {\r
+ if (applicationLoader != null)\r
+ applicationLoader.close();\r
+ }\r
+\r
+ /*\r
+ ** Public methods of ClassFactory\r
+ */\r
+\r
+ /**\r
+ Here we load the newly added class now, rather than waiting for the\r
+ findGeneratedClass(). Thus we are assuming that the class is going\r
+ to be used sometime soon. Delaying the load would mean storing the class\r
+ data in a file, this wastes cycles and compilcates the cleanup.\r
+\r
+ @see ClassFactory#loadGeneratedClass\r
+\r
+ @exception StandardException Class format is bad.\r
+ */\r
+ public final GeneratedClass loadGeneratedClass(String fullyQualifiedName, ByteArray classDump)\r
+ throws StandardException {\r
+\r
+\r
+ try {\r
+\r
+\r
+ return loadGeneratedClassFromData(fullyQualifiedName, classDump);\r
+\r
+ } catch (LinkageError le) {\r
+\r
+ WriteClassFile(fullyQualifiedName, classDump, le);\r
+\r
+ throw StandardException.newException(SQLState.GENERATED_CLASS_LINKAGE_ERROR,\r
+ le, fullyQualifiedName);\r
+\r
+ } catch (VirtualMachineError vme) { // these may be beyond saving, but fwiw\r
+\r
+ WriteClassFile(fullyQualifiedName, classDump, vme);\r
+\r
+ throw vme;\r
+ }\r
+\r
+ }\r
+\r
+ private static void WriteClassFile(String fullyQualifiedName, ByteArray bytecode, Throwable t) {\r
+\r
+ // get the un-qualified name and add the extension\r
+ int lastDot = fullyQualifiedName.lastIndexOf((int)'.');\r
+ String filename = fullyQualifiedName.substring(lastDot+1,fullyQualifiedName.length()).concat(".class");\r
+\r
+ Object env = Monitor.getMonitor().getEnvironment();\r
+ File dir = env instanceof File ? (File) env : null;\r
+\r
+ File classFile = FileUtil.newFile(dir,filename);\r
+\r
+ // find the error stream\r
+ HeaderPrintWriter errorStream = Monitor.getStream();\r
+\r
+ try {\r
+ FileOutputStream fis = new FileOutputStream(classFile);\r
+ fis.write(bytecode.getArray(),\r
+ bytecode.getOffset(), bytecode.getLength());\r
+ fis.flush();\r
+ if (t!=null) { \r
+ errorStream.printlnWithHeader(MessageService.getTextMessage(MessageId.CM_WROTE_CLASS_FILE, fullyQualifiedName, classFile, t));\r
+ }\r
+ fis.close();\r
+ } catch (IOException e) {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("Unable to write .class file");\r
+ }\r
+ }\r
+\r
+ public ClassInspector getClassInspector() {\r
+ return classInspector;\r
+ }\r
+\r
+\r
+ public final Class loadApplicationClass(String className)\r
+ throws ClassNotFoundException {\r
+ \r
+ if (className.startsWith("org.apache.derby.")) {\r
+ // Assume this is an engine class, if so\r
+ // try to load from this class loader,\r
+ // this ensures in strange class loader\r
+ // environments we do not get ClassCastExceptions\r
+ // when an engine class is loaded through a different\r
+ // class loader to the rest of the engine.\r
+ try {\r
+ return Class.forName(className);\r
+ //Added by Jeff Huang\r
+ //TODO: FIXIT\r
+ } catch (ClassNotFoundException cnfe)\r
+ {\r
+ // fall through to the code below,\r
+ // could be client or tools class\r
+ // in a different loader.\r
+ }\r
+ }\r
+ \r
+ Throwable loadError;\r
+ try {\r
+ try {\r
+ return loadClassNotInDatabaseJar(className);\r
+ } catch (ClassNotFoundException cnfe) {\r
+ if (applicationLoader == null)\r
+ throw cnfe;\r
+ Class c = applicationLoader.loadClass(className, true);\r
+ if (c == null)\r
+ throw cnfe;\r
+ return c;\r
+ }\r
+ }\r
+ catch (SecurityException se)\r
+ {\r
+ // Thrown if the class has been comprimised in some\r
+ // way, e.g. modified in a signed jar.\r
+ loadError = se; \r
+ }\r
+ catch (LinkageError le)\r
+ {\r
+ // some error linking the jar, again could\r
+ // be malicious code inserted into a jar.\r
+ loadError = le; \r
+ }\r
+ throw new ClassNotFoundException(className + " : " + loadError.getMessage());\r
+ }\r
+ \r
+ abstract Class loadClassNotInDatabaseJar(String className)\r
+ throws ClassNotFoundException;\r
+\r
+ public final Class loadApplicationClass(ObjectStreamClass classDescriptor)\r
+ throws ClassNotFoundException {\r
+ return loadApplicationClass(classDescriptor.getName());\r
+ }\r
+\r
+ public boolean isApplicationClass(Class theClass) {\r
+\r
+ return theClass.getClassLoader()\r
+ instanceof JarLoader;\r
+ }\r
+\r
+ public void notifyModifyJar(boolean reload) throws StandardException {\r
+ if (applicationLoader != null) {\r
+ applicationLoader.modifyJar(reload);\r
+ }\r
+ }\r
+\r
+ /**\r
+ Notify the class manager that the classpath has been modified.\r
+\r
+ @exception StandardException thrown on error\r
+ */\r
+ public void notifyModifyClasspath(String classpath) throws StandardException {\r
+\r
+ if (applicationLoader != null) {\r
+ applicationLoader.modifyClasspath(classpath);\r
+ }\r
+ }\r
+\r
+\r
+ public int getClassLoaderVersion() {\r
+ if (applicationLoader != null) {\r
+ return applicationLoader.getClassLoaderVersion();\r
+ }\r
+\r
+ return -1;\r
+ }\r
+\r
+ public ByteArray buildSpecificFactory(String className, String factoryName)\r
+ throws StandardException {\r
+\r
+ ClassBuilder cb = javaFactory.newClassBuilder(this, CodeGeneration.GENERATED_PACKAGE_PREFIX,\r
+ Modifier.PUBLIC | Modifier.FINAL, factoryName, "org.apache.derby.impl.services.reflect.GCInstanceFactory");\r
+\r
+ MethodBuilder constructor = cb.newConstructorBuilder(Modifier.PUBLIC);\r
+\r
+ constructor.callSuper();\r
+ constructor.methodReturn();\r
+ constructor.complete();\r
+ constructor = null;\r
+\r
+ MethodBuilder noArg = cb.newMethodBuilder(Modifier.PUBLIC, ClassName.GeneratedByteCode, "getNewInstance");\r
+ noArg.pushNewStart(className);\r
+ noArg.pushNewComplete(0);\r
+ noArg.methodReturn();\r
+ noArg.complete();\r
+ noArg = null;\r
+\r
+ return cb.getClassBytecode();\r
+ }\r
+\r
+ /*\r
+ ** Class specific methods\r
+ */\r
+ \r
+ /*\r
+ ** Keep track of loaded generated classes and their GeneratedClass objects.\r
+ */\r
+\r
+ abstract LoadedGeneratedClass loadGeneratedClassFromData(String fullyQualifiedName, ByteArray classDump); \r
+}\r