Index: engine/src/main/java/org/teiid/query/function/FunctionTree.java
===================================================================
--- engine/src/main/java/org/teiid/query/function/FunctionTree.java	(revision 4505)
+++ engine/src/main/java/org/teiid/query/function/FunctionTree.java	(working copy)
@@ -81,7 +81,7 @@
      * @param source The metadata source
      */
     public FunctionTree(String name, FunctionMetadataSource source) {
-    	this(name, source, false, null);
+    	this(name, source, false);
     }
     
     /**
@@ -89,19 +89,12 @@
      * @param source The metadata source
      */
     public FunctionTree(String name, FunctionMetadataSource source, boolean validateClass) {
-    	this(name, source, validateClass, null);
-    }
-    
-    public FunctionTree(String name, FunctionMetadataSource source, boolean validateClass, ClassLoader defaultClassloader) {
         // Load data structures
     	this.validateClass = validateClass;
     	boolean system = CoreConstants.SYSTEM_MODEL.equalsIgnoreCase(name) || CoreConstants.SYSTEM_ADMIN_MODEL.equalsIgnoreCase(name);
         Collection<FunctionMethod> functions = source.getFunctionMethods();
     	for (FunctionMethod method : functions) {
 			if (!containsIndistinguishableFunction(method)){
-				if (method.getClassLoader() == null) {
-					method.setClassloader(defaultClassloader);
-				}
                 // Add to tree
                 addFunction(name, source, method, system);
 			} else if (!CoreConstants.SYSTEM_MODEL.equalsIgnoreCase(name)) {
@@ -309,30 +302,34 @@
         	inputTypes.set(inputTypes.size() - 1, DataTypeManager.getArrayType(inputTypes.get(inputTypes.size() - 1)));
         }
 
-        Method invocationMethod = null;
+        Method invocationMethod = method.getMethod();
         boolean requiresContext = false;
         // Defect 20007 - Ignore the invocation method if pushdown is not required.
         if (validateClass && (method.getPushdown() == PushDown.CAN_PUSHDOWN || method.getPushdown() == PushDown.CANNOT_PUSHDOWN)) {
-        	if (method.getInvocationClass() == null || method.getInvocationMethod() == null) {
-        		throw new MetadataException(QueryPlugin.Event.TEIID31123, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31123, method.getName()));
+        	if (invocationMethod == null) {
+	        	if (method.getInvocationClass() == null || method.getInvocationMethod() == null) {
+	        		throw new MetadataException(QueryPlugin.Event.TEIID31123, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31123, method.getName()));
+	        	}
+	            try {
+	                Class<?> methodClass = source.getInvocationClass(method.getInvocationClass());
+	                ReflectionHelper helper = new ReflectionHelper(methodClass);
+	                try {
+	                	invocationMethod = helper.findBestMethodWithSignature(method.getInvocationMethod(), inputTypes);
+	                } catch (NoSuchMethodException e) {
+	                    inputTypes.add(0, CommandContext.class);
+	                	invocationMethod = helper.findBestMethodWithSignature(method.getInvocationMethod(), inputTypes);
+	                	requiresContext = true;
+	                }
+	            } catch (ClassNotFoundException e) {
+	            	 throw new MetadataException(QueryPlugin.Event.TEIID30387, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30387, method.getName(), method.getInvocationClass()));
+	            } catch (NoSuchMethodException e) {
+	            	 throw new MetadataException(QueryPlugin.Event.TEIID30388, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30388, method, method.getInvocationClass(), method.getInvocationMethod()));
+	            } catch (Exception e) {                
+	                 throw new MetadataException(QueryPlugin.Event.TEIID30389, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30389, method, method.getInvocationClass(), method.getInvocationMethod()));
+	            } 
+        	} else {
+        		requiresContext = (invocationMethod.getParameterTypes().length > 0 && org.teiid.CommandContext.class.isAssignableFrom(invocationMethod.getParameterTypes()[0]));
         	}
-            try {
-                Class<?> methodClass = source.getInvocationClass(method.getInvocationClass(), method.getClassLoader()==null?Thread.currentThread().getContextClassLoader():method.getClassLoader());
-                ReflectionHelper helper = new ReflectionHelper(methodClass);
-                try {
-                	invocationMethod = helper.findBestMethodWithSignature(method.getInvocationMethod(), inputTypes);
-                } catch (NoSuchMethodException e) {
-                    inputTypes.add(0, CommandContext.class);
-                	invocationMethod = helper.findBestMethodWithSignature(method.getInvocationMethod(), inputTypes);
-                	requiresContext = true;
-                }
-            } catch (ClassNotFoundException e) {
-            	 throw new MetadataException(QueryPlugin.Event.TEIID30387, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30387, method.getName(), method.getInvocationClass()));
-            } catch (NoSuchMethodException e) {
-            	 throw new MetadataException(QueryPlugin.Event.TEIID30388, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30388, method, method.getInvocationClass(), method.getInvocationMethod()));
-            } catch (Exception e) {                
-                 throw new MetadataException(QueryPlugin.Event.TEIID30389, e,QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30389, method, method.getInvocationClass(), method.getInvocationMethod()));
-            } 
             if (invocationMethod != null) {
             	// Check return type is non void
         		Class<?> methodReturn = invocationMethod.getReturnType();
@@ -358,6 +355,7 @@
         		if (method.getAggregateAttributes() != null && !(UserDefinedAggregate.class.isAssignableFrom(invocationMethod.getDeclaringClass()))) {
     				throw new MetadataException(QueryPlugin.Event.TEIID30601, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30601, method.getName(), method.getInvocationClass(), UserDefinedAggregate.class.getName()));
         		}
+	            method.setMethod(invocationMethod);
             }
         }
 
Index: engine/src/test/java/org/teiid/query/optimizer/FakeFunctionMetadataSource.java
===================================================================
--- engine/src/test/java/org/teiid/query/optimizer/FakeFunctionMetadataSource.java	(revision 4505)
+++ engine/src/test/java/org/teiid/query/optimizer/FakeFunctionMetadataSource.java	(working copy)
@@ -61,8 +61,8 @@
         return methods;
     }
     
-    public Class<?> getInvocationClass(String className, ClassLoader cl) throws ClassNotFoundException { 
-        return Class.forName(className, true, cl); 
+    public Class<?> getInvocationClass(String className) throws ClassNotFoundException { 
+        return Class.forName(className, true, this.getClass().getClassLoader()); 
     }
     
     // dummy function
Index: runtime/src/main/java/org/teiid/deployers/CompositeVDB.java
===================================================================
--- runtime/src/main/java/org/teiid/deployers/CompositeVDB.java	(revision 4505)
+++ runtime/src/main/java/org/teiid/deployers/CompositeVDB.java	(working copy)
@@ -81,8 +81,8 @@
 	private static TransformationMetadata buildTransformationMetaData(VDBMetaData vdb, LinkedHashMap<String, Resource> visibilityMap, MetadataStore store, UDFMetaData udf, FunctionTree systemFunctions, MetadataStore[] additionalStores) {
 		Collection <FunctionTree> udfs = new ArrayList<FunctionTree>();
 		if (udf != null) {			
-			for (Map.Entry<String, Collection<FunctionMethod>> entry : udf.getFunctions().entrySet()) {
-				udfs.add(new FunctionTree(entry.getKey(), new UDFSource(entry.getValue()), true, udf.getClassLoader()));
+			for (Map.Entry<String, UDFSource> entry : udf.getFunctions().entrySet()) {
+				udfs.add(new FunctionTree(entry.getKey(), entry.getValue(), true));
 			}
 		}
 		
@@ -91,7 +91,11 @@
 			compositeStore.merge(s);
 			for (Schema schema:s.getSchemas().values()) {
 				if (!schema.getFunctions().isEmpty()) {
-					udfs.add(new FunctionTree(schema.getName(), new UDFSource(schema.getFunctions().values()), true, udf.getClassLoader()));
+					UDFSource source = new UDFSource(schema.getFunctions().values());
+					if (udf != null) {
+						source.setClassLoader(udf.getClassLoader());
+					}
+					udfs.add(new FunctionTree(schema.getName(), source, true));
 				}
 			}
 		}
Index: engine/src/main/java/org/teiid/query/function/source/SystemSource.java
===================================================================
--- engine/src/main/java/org/teiid/query/function/source/SystemSource.java	(revision 4505)
+++ engine/src/main/java/org/teiid/query/function/source/SystemSource.java	(working copy)
@@ -25,7 +25,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.metadata.FunctionMethod;
@@ -34,8 +33,8 @@
 import org.teiid.metadata.FunctionMethod.PushDown;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.function.FunctionLibrary;
-import org.teiid.query.function.FunctionMetadataSource;
 import org.teiid.query.function.FunctionMethods;
+import org.teiid.query.function.UDFSource;
 import org.teiid.query.function.metadata.FunctionCategoryConstants;
 import org.teiid.translator.SourceSystemFunctions;
 
@@ -44,20 +43,18 @@
  * This metadata source has metadata for the hard-coded system functions.  All
  * system functions are described by this metadata.
  */
-public class SystemSource implements FunctionMetadataSource, FunctionCategoryConstants {
+public class SystemSource extends UDFSource implements FunctionCategoryConstants {
 
     /** The name of the invocation class for all of the system functions. */
     private static final String FUNCTION_CLASS = FunctionMethods.class.getName(); 
     private static final String XML_FUNCTION_CLASS = XMLSystemFunctions.class.getName(); 
     private static final String SECURITY_FUNCTION_CLASS = SecuritySystemFunctions.class.getName(); 
     
-    /** Cached list of system function metadata, created in constructor */
-    private List<org.teiid.metadata.FunctionMethod> functions = new ArrayList<org.teiid.metadata.FunctionMethod>();
-    
     /**
      * Construct a source of system metadata.
      */
     public SystemSource(boolean allowEnvFunction) {
+    	super(new ArrayList<FunctionMethod>());
 		// +, -, *, /
         addArithmeticFunction(SourceSystemFunctions.ADD_OP, QueryPlugin.Util.getString("SystemSource.Add_desc"), "plus", QueryPlugin.Util.getString("SystemSource.Add_result_desc")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
         addArithmeticFunction(SourceSystemFunctions.SUBTRACT_OP, QueryPlugin.Util.getString("SystemSource.Subtract_desc"), "minus", QueryPlugin.Util.getString("SystemSource.Subtract_result_desc")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 
@@ -1093,16 +1090,6 @@
         return this.functions;
 	}
     
-    /**
-     * Sources are returned from the system classpath.
-     * @param className Name of class
-     * @return Class reference  
-     * @throws ClassNotFoundException If class could not be found
-     */
-    public Class<?> getInvocationClass(String className, ClassLoader classloader) throws ClassNotFoundException {
-        return Class.forName(className, true, classloader);    
-    }
-    
     public static FunctionMethod createSyntheticMethod(String name, String description, String category, 
             String invocationClass, String invocationMethod, FunctionParameter[] inputParams, 
             FunctionParameter outputParam) {
Index: jboss-integration/src/main/java/org/teiid/jboss/VDBDeployer.java
===================================================================
--- jboss-integration/src/main/java/org/teiid/jboss/VDBDeployer.java	(revision 4505)
+++ jboss-integration/src/main/java/org/teiid/jboss/VDBDeployer.java	(working copy)
@@ -39,7 +39,6 @@
 import org.jboss.as.server.deployment.DeploymentUnit;
 import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
 import org.jboss.as.server.deployment.DeploymentUnitProcessor;
-import org.jboss.modules.Module;
 import org.jboss.modules.ModuleClassLoader;
 import org.jboss.msc.service.AbstractServiceListener;
 import org.jboss.msc.service.Service;
@@ -136,15 +135,12 @@
 		deployment.addAttchment(ClassLoader.class, classLoader);
 		deployment.addAttchment(ScriptEngineManager.class, new ScriptEngineManager(classLoader));
 		
-		// check if this is a VDB with index files, if there are then build the TransformationMetadata
 		UDFMetaData udf = deploymentUnit.removeAttachment(TeiidAttachments.UDF_METADATA);
-		if (udf != null) {
-			final Module module = deploymentUnit.getAttachment(Attachments.MODULE);
-			if (module != null) {
-				udf.setFunctionClassLoader(module.getClassLoader());
-			}
-			deployment.addAttchment(UDFMetaData.class, udf);
+		if (udf == null) {
+			udf = new UDFMetaData();
 		}
+		udf.setFunctionClassLoader(classLoader);
+		deployment.addAttchment(UDFMetaData.class, udf);
 		
 		// set up the metadata repositories for each models
 		IndexMetadataRepository indexRepo = null;
Index: api/src/main/java/org/teiid/metadata/MetadataFactory.java
===================================================================
--- api/src/main/java/org/teiid/metadata/MetadataFactory.java	(revision 4508)
+++ api/src/main/java/org/teiid/metadata/MetadataFactory.java	(working copy)
@@ -453,10 +453,9 @@
 		FunctionMethod func = FunctionMethod.createFunctionMethod(name, null, null, returnType, paramTypes);
 		setUUID(func);
 		getSchema().addFunction(func);
-		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 		func.setInvocationMethod(method.getName());
 		func.setPushdown(PushDown.CANNOT_PUSHDOWN);
-		func.setClassloader(classLoader);
+		func.setMethod(method);
 		func.setInvocationClass(method.getDeclaringClass().getName());
 		func.setNullOnNull(nullOnNull);
 		return func;
Index: jboss-integration/src/main/java/org/teiid/jboss/FileUDFMetaData.java
===================================================================
--- jboss-integration/src/main/java/org/teiid/jboss/FileUDFMetaData.java	(revision 4505)
+++ jboss-integration/src/main/java/org/teiid/jboss/FileUDFMetaData.java	(working copy)
@@ -32,6 +32,7 @@
 import org.teiid.deployers.UDFMetaData;
 import org.teiid.metadata.FunctionMethod;
 import org.teiid.query.QueryPlugin;
+import org.teiid.query.function.UDFSource;
 import org.teiid.query.function.metadata.FunctionMetadataReader;
 import org.teiid.query.function.metadata.FunctionMetadataValidator;
 import org.teiid.query.validator.ValidatorReport;
@@ -63,7 +64,7 @@
 		if(report.hasItems()) {
 		    throw new IOException(QueryPlugin.Util.getString("ERR.015.001.0005", report)); //$NON-NLS-1$
 		}
-		this.methods.put(name, udfMethods);
+		this.methods.put(name, new UDFSource(udfMethods));
 	}
 	
 
Index: engine/src/main/java/org/teiid/query/function/UDFSource.java
===================================================================
--- engine/src/main/java/org/teiid/query/function/UDFSource.java	(revision 4505)
+++ engine/src/main/java/org/teiid/query/function/UDFSource.java	(working copy)
@@ -26,21 +26,28 @@
 
 import org.teiid.metadata.FunctionMethod;
 
-
-
 public class UDFSource implements FunctionMetadataSource {
 	
-    private Collection <FunctionMethod> methods = null;
+    protected Collection <FunctionMethod> functions;
+    private ClassLoader classLoader;
     
     public UDFSource(Collection <FunctionMethod> methods) {
-    	this.methods = methods;
+    	this.functions = methods;
     }    
     
     public Collection<FunctionMethod> getFunctionMethods() {
-        return this.methods;
+        return this.functions;
     }
 
-    public Class<?> getInvocationClass(String className, ClassLoader cl) throws ClassNotFoundException {
-        return Class.forName(className, true, cl);
+    public Class<?> getInvocationClass(String className) throws ClassNotFoundException {
+        return Class.forName(className, true, classLoader==null?Thread.currentThread().getContextClassLoader():classLoader);
     }
+    
+    public void setClassLoader(ClassLoader classLoader) {
+		this.classLoader = classLoader;
+	}
+    
+    public ClassLoader getClassLoader() {
+		return classLoader;
+	}
 }
Index: api/src/main/java/org/teiid/metadata/FunctionMethod.java
===================================================================
--- api/src/main/java/org/teiid/metadata/FunctionMethod.java	(revision 4505)
+++ api/src/main/java/org/teiid/metadata/FunctionMethod.java	(working copy)
@@ -22,6 +22,7 @@
 
 package org.teiid.metadata;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -102,13 +103,13 @@
     private String invocationMethod;
     private boolean nullOnNull;
     private AggregateAttributes aggregateAttributes;
+    private transient Method method;
     
     private Determinism determinism = Determinism.DETERMINISTIC;
     
     protected List<FunctionParameter> inParameters = new ArrayList<FunctionParameter>(2);
     private FunctionParameter outputParameter;
     private Schema parent;
-    private ClassLoader classLoader;
         
     public FunctionMethod() {
     }
@@ -449,14 +450,6 @@
     	return parent;
     }
     
-    public ClassLoader getClassLoader() {
-    	return this.classLoader;
-    }
-    
-    public void setClassloader(ClassLoader classloader) {
-    	this.classLoader = classloader;
-    }
-    
     /**
      * Gets the {@link AggregateAttributes} for this function if it 
      * represents an aggregate function.  Must be null for non-aggregates.
@@ -509,5 +502,13 @@
 			function.setAggregateAttributes(aa);
 		}
 	}
+	
+	public Method getMethod() {
+		return method;
+	}
+	
+	public void setMethod(Method method) {
+		this.method = method;
+	}
 
 }
Index: engine/src/main/java/org/teiid/query/function/FunctionMetadataSource.java
===================================================================
--- engine/src/main/java/org/teiid/query/function/FunctionMetadataSource.java	(revision 4505)
+++ engine/src/main/java/org/teiid/query/function/FunctionMetadataSource.java	(working copy)
@@ -52,5 +52,5 @@
      * @return Class reference  
      * @throws ClassNotFoundException If class could not be found
      */
-    Class getInvocationClass(String className, ClassLoader cl) throws ClassNotFoundException;    
+    Class getInvocationClass(String className) throws ClassNotFoundException;    
 }
Index: runtime/src/main/java/org/teiid/deployers/UDFMetaData.java
===================================================================
--- runtime/src/main/java/org/teiid/deployers/UDFMetaData.java	(revision 4505)
+++ runtime/src/main/java/org/teiid/deployers/UDFMetaData.java	(working copy)
@@ -23,39 +23,49 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.Map;
+import java.util.TreeMap;
 
 import org.teiid.metadata.FunctionMethod;
+import org.teiid.query.function.UDFSource;
 
 
 public class UDFMetaData {
-	protected HashMap<String, Collection <FunctionMethod>> methods = new HashMap<String, Collection<FunctionMethod>>();	
+	protected TreeMap<String, UDFSource> methods = new TreeMap<String, UDFSource>(String.CASE_INSENSITIVE_ORDER);	
 	private ClassLoader classLoader;
-		
-	public Map<String, Collection <FunctionMethod>> getFunctions(){
+	
+	public Map<String, UDFSource> getFunctions(){
 		return this.methods;
 	}
-	
+
 	public void addFunctions(String name, Collection <FunctionMethod> funcs){
 		if (funcs.isEmpty()) {
 			return;
 		}
-		Collection <FunctionMethod> old = this.methods.put(name, funcs);
-		if (old != null) {
-			ArrayList<FunctionMethod> combined = new ArrayList<FunctionMethod>(old);
-			combined.addAll(funcs);
-			this.methods.put(name, combined);
+		UDFSource udfSource = this.methods.get(name);
+		if (udfSource != null) {
+			//this is ambiguous about as to what classloader to use, but we assume the first is good and that the user will have set 
+			//the Java method if that's not the case
+			ArrayList<FunctionMethod> allMethods = new ArrayList<FunctionMethod>(udfSource.getFunctionMethods());
+			allMethods.addAll(funcs);
+			ClassLoader cl = udfSource.getClassLoader();
+			udfSource = new UDFSource(allMethods);
+			udfSource.setClassLoader(cl);
+		} else {
+			udfSource = new UDFSource(funcs);
+			udfSource.setClassLoader(classLoader);
 		}
+		this.methods.put(name, udfSource);
 	}
 	
 	public void addFunctions(UDFMetaData funcs){
-		for (Map.Entry<String, Collection<FunctionMethod>> entry : funcs.getFunctions().entrySet()) {
-			addFunctions(entry.getKey(), entry.getValue());
-		}
+		this.methods.putAll(funcs.methods);
 	}
 
 	public void setFunctionClassLoader(ClassLoader functionClassLoader) {
+		for (UDFSource udf : methods.values()) {
+			udf.setClassLoader(functionClassLoader);
+		}
 		this.classLoader = functionClassLoader;
 	}
 	
Index: engine/src/main/java/org/teiid/query/function/SystemFunctionManager.java
===================================================================
--- engine/src/main/java/org/teiid/query/function/SystemFunctionManager.java	(revision 4505)
+++ engine/src/main/java/org/teiid/query/function/SystemFunctionManager.java	(working copy)
@@ -24,6 +24,7 @@
 import java.util.Collection;
 
 import org.teiid.core.CoreConstants;
+import org.teiid.metadata.FunctionMethod;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.function.metadata.FunctionMetadataValidator;
 import org.teiid.query.function.source.SystemSource;
@@ -40,16 +41,16 @@
     	if(systemFunctionTree == null) { 
 	    	// Create the system source and add it to the source list
 	    	SystemSource systemSource = new SystemSource(this.allowEnvFunction);
-	
+	    	systemSource.setClassLoader(classLoader);
 			// Validate the system source - should never fail
 	    	ValidatorReport report = new ValidatorReport("Function Validation"); //$NON-NLS-1$
-	        Collection functionMethods = systemSource.getFunctionMethods();
+	        Collection<FunctionMethod> functionMethods = systemSource.getFunctionMethods();
 	    	FunctionMetadataValidator.validateFunctionMethods(functionMethods,report);
 			if(report.hasItems()) {
 			    // Should never happen as SystemSourcTe doesn't change
 			    System.err.println(QueryPlugin.Util.getString("ERR.015.001.0005", report)); //$NON-NLS-1$
 			}
-			systemFunctionTree = new FunctionTree(CoreConstants.SYSTEM_MODEL, systemSource, true, this.classLoader);
+			systemFunctionTree = new FunctionTree(CoreConstants.SYSTEM_MODEL, systemSource, true);
     	}
     	return systemFunctionTree;
     }
