Skip to content

Commit 40ffaf4

Browse files
committed
allow passing of arguments to functions executed by the context class load switcher
1 parent 5d8944d commit 40ffaf4

2 files changed

Lines changed: 128 additions & 14 deletions

File tree

javaloader/JavaLoader.cfc

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ Purpose: Utlitity class for loading Java Classes
104104

105105
<cffunction name="switchThreadContextClassLoader" hint="Sometimes you will need to switch out the ThreadContextClassLoader with the classloader used by JavaLoader.<br/>
106106
It has :
107-
switchThreadContextClassLoader(function object, [classLoader=getURLClassLoader()])
108-
switchThreadContextClassLoader(function name, [classLoader=getURLClassLoader()])
109-
switchThreadContextClassLoader(object, function name, [classLoader=getURLClassLoader()])
107+
switchThreadContextClassLoader(function object, [classLoader=getURLClassLoader()], [struct function arguments])
108+
switchThreadContextClassLoader(function name, [classLoader=getURLClassLoader()], [struct function arguments])
109+
switchThreadContextClassLoader(object, function name, [classLoader=getURLClassLoader()], [struct function arguments])
110110
This method can be used in 3 different ways:
111111
<ol>
112112
<li>Pass it the UDF itself</li>
@@ -119,18 +119,57 @@ Purpose: Utlitity class for loading Java Classes
119119
var System = createObject("java", "java.lang.System");
120120
var Thread = createObject("java", "java.lang.Thread");
121121
var currentClassloader = Thread.currentThread().getContextClassLoader();
122-
123-
if(structCount(arguments) == 2 && !isSimpleValue(arguments[2]))
124-
{
125-
classLoader = arguments[2];
122+
var classLoader = "";
123+
124+
if (structCount(arguments) == 4)
125+
{
126+
// the last 2 arguments are the classloader and function arguments
127+
classLoader = arguments[3];
128+
local.funcArgs = arguments[4];
129+
}
130+
else if (structCount(arguments) == 3)
131+
{
132+
// 2nd argument could be classloader or function arguments
133+
if (isInstanceOf(arguments[2],"java.lang.ClassLoader"))
134+
{
135+
classLoader = arguments[2];
136+
}
137+
else if (isStruct(arguments[2]))
138+
{
139+
local.funcArgs = arguments[2];
140+
}
141+
142+
// 3rd argument could be classloader or function arguments
143+
if (isInstanceOf(arguments[3],"java.lang.ClassLoader"))
144+
{
145+
classLoader = arguments[3];
146+
}
147+
else if (isStruct(arguments[3]))
148+
{
149+
local.funcArgs = arguments[3];
150+
}
151+
}
152+
else if (structCount(arguments) == 2)
153+
{
154+
// the 2nd argument could be a class loader or function arguments
155+
if (isInstanceOf(arguments[2],"java.lang.ClassLoader"))
156+
{
157+
classLoader = arguments[2];
158+
}
159+
else if (isStruct(arguments[2]))
160+
{
161+
local.funcArgs = arguments[2];
162+
}
126163
}
127-
else if(structCount(arguments) == 3)
164+
165+
if (!structKeyExists(local,"funcArgs"))
128166
{
129-
classLoader = arguments[3];
167+
local.funcArgs = {};
130168
}
131-
else //assume we are still in JL
169+
170+
if (isSimpleValue(classLoader))
132171
{
133-
classLoader = getURLClassLoader();
172+
classLoader = getURLClassLoader();
134173
}
135174
</cfscript>
136175

@@ -140,14 +179,22 @@ Purpose: Utlitity class for loading Java Classes
140179
</cfscript>
141180

142181
<cfif isSimpleValue(arguments[1])>
143-
<cfinvoke method="#arguments[1]#" returnvariable="local.return" />
182+
<cfinvoke method="#arguments[1]#" returnvariable="local.return">
183+
<cfloop collection="#local.funcArgs#" item="local.i">
184+
<cfinvokeargument name="#local.i#" value="#local.funcArgs[local.i]#" />
185+
</cfloop>
186+
</cfinvoke>
144187
<cfelseif isCustomFunction(arguments[1])>
145188
<cfscript>
146189
local.func = arguments[1];
147-
local.return = local.func();
190+
local.return = local.func(argumentCollection = funcArgs);
148191
</cfscript>
149192
<cfelseif isObject(arguments[1]) AND isSimpleValue(arguments[2])>
150-
<cfinvoke component="#arguments[1]#" method="#arguments[2]#" returnvariable="local.return" />
193+
<cfinvoke component="#arguments[1]#" method="#arguments[2]#" returnvariable="local.return">
194+
<cfloop collection="#local.funcArgs#" item="local.i">
195+
<cfinvokeargument name="#local.i#" value="#local.funcArgs[local.i]#" />
196+
</cfloop>
197+
</cfinvoke>
151198
<cfelse>
152199
<cfthrow type="javaloader.InvalidInvocationException" message="Unable to determine what method to invoke" detail="Please check the documentation for switchThreadContextClassLoader."/>
153200
</cfif>

unittests/load/SwitchThreadContextTest.cfc

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,66 @@
6767
</cfscript>
6868
</cffunction>
6969

70+
<cffunction name="testMixinApproachWithArguments" hint="testing using the mixing" access="public" returntype="void" output="false">
71+
<cfscript>
72+
var mixin = javaloader.switchThreadContextClassLoader;
73+
var args = { "arg1" = 1, "arg2" = 2};
74+
var result = mixin("returnCurrentClassLoaderAndArguments", javaloader.getURLClassLoader(), args);
75+
assertSame(javaloader.getURLClassLoader(), result.classLoader);
76+
assertStructEquals(args, result.args);
77+
</cfscript>
78+
</cffunction>
79+
80+
<cffunction name="testPassUDFInWithArguments" hint="pass in a UDF with arguments" access="public" returntype="void" output="false">
81+
<cfscript>
82+
var args = { "arg1" = 1, "arg2" = 2};
83+
var result = javaloader.switchThreadContextClassLoader(returnCurrentClassLoaderAndArguments, args);
84+
assertSame(javaloader.getURLClassLoader(), result.classLoader);
85+
assertStructEquals(args, result.args);
86+
</cfscript>
87+
</cffunction>
88+
89+
<cffunction name="testPassUDFInWithArgumentsWithCustomClassLoader" hint="pass in a UDF with arguments" access="public" returntype="void" output="false">
90+
<cfscript>
91+
var urlClassLoader = createObject("java", "java.net.URLClassLoader").init(ArrayNew(1));
92+
var args = { "arg1" = 1, "arg2" = 2};
93+
var result = javaloader.switchThreadContextClassLoader(returnCurrentClassLoaderAndArguments, urlClassLoader, args);
94+
assertSame(urlClassLoader, result.classLoader);
95+
assertStructEquals(args, result.args);
96+
</cfscript>
97+
</cffunction>
98+
99+
<cffunction name="testPassObjectAndMethodNameWithArguments" hint="pass in the object and method name with arguments" access="public" returntype="void" output="false">
100+
<cfscript>
101+
var local = {};
102+
local.class = getMetadata(this).name;
103+
local.object = createObject("component", local.class);
104+
local.args = { "arg1" = 1, "arg2" = 2};
105+
106+
makePublic(local.object, "returnCurrentClassLoaderAndArguments");
107+
108+
local.result = javaloader.switchThreadContextClassLoader(local.object, "returnCurrentClassLoaderAndArguments", local.args);
109+
assertSame(javaloader.getURLClassLoader(), local.result.classLoader);
110+
assertStructEquals(args, local.result.args);
111+
</cfscript>
112+
</cffunction>
113+
114+
<cffunction name="testPassObjectAndMethodNameWithArgumentsWithCustomClassLoader" hint="pass in the object and method name with arguments, with a custom classloader" access="public" returntype="void" output="false">
115+
<cfscript>
116+
var local = {};
117+
local.class = getMetadata(this).name;
118+
local.object = createObject("component", local.class);
119+
local.urlClassLoader = createObject("java", "java.net.URLClassLoader").init(ArrayNew(1));
120+
local.args = { "arg1" = 1, "arg2" = 2};
121+
122+
makePublic(local.object, "returnCurrentClassLoaderAndArguments");
123+
124+
local.result = javaloader.switchThreadContextClassLoader(local.object, "returnCurrentClassLoaderAndArguments", local.urlClassLoader, local.args);
125+
assertSame(local.urlClassLoader, local.result.classLoader);
126+
assertStructEquals(local.args, local.result.args);
127+
</cfscript>
128+
</cffunction>
129+
70130
<!------------------------------------------- PACKAGE ------------------------------------------->
71131

72132
<!------------------------------------------- PRIVATE ------------------------------------------->
@@ -78,4 +138,11 @@
78138
</cfscript>
79139
</cffunction>
80140

141+
<cffunction name="returnCurrentClassLoaderAndArguments" hint="returns the current contexts classloader and any arguments passed in" access="private" returntype="any" output="false">
142+
<cfscript>
143+
var Thread = createObject("java", "java.lang.Thread");
144+
return { "classLoader" = Thread.currentThread().getContextClassLoader(), args = arguments };
145+
</cfscript>
146+
</cffunction>
147+
81148
</cfcomponent>

0 commit comments

Comments
 (0)