Skip to content

Commit

Permalink
Merge pull request #851 from jroper/851-java-classloader
Browse files Browse the repository at this point in the history
[2.1.0] JPA: Parameter value [*] was not matching type [java.util.Map]
  • Loading branch information
jroper committed Jun 27, 2013
2 parents a2c3a7b + 093b842 commit 9162546
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 17 deletions.
45 changes: 28 additions & 17 deletions framework/src/play/src/main/java/play/libs/F.java
Expand Up @@ -240,6 +240,7 @@ public <B> Promise<Either<A,B>> or(Promise<B> another) {
*/
public void onRedeem(final Callback<A> action) {
final play.mvc.Http.Context context = play.mvc.Http.Context.current.get();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
new play.api.libs.concurrent.PlayPromise<A>(promise).onRedeem(new scala.runtime.AbstractFunction1<A,scala.runtime.BoxedUnit>() {
public scala.runtime.BoxedUnit apply(A a) {
try {
Expand All @@ -254,7 +255,7 @@ public Object apply(A a) {
throw new RuntimeException(t);
}
}
}, a, context);
}, a, context, classLoader);
} catch (RuntimeException e) {
throw e;
} catch (Throwable t) {
Expand All @@ -277,11 +278,12 @@ public Object apply(A a) {
*/
public <B> Promise<B> map(final Function<A, B> function) {
final play.mvc.Http.Context context = play.mvc.Http.Context.current.get();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return new Promise<B>(
promise.flatMap(new scala.runtime.AbstractFunction1<A,scala.concurrent.Future<B>>() {
public scala.concurrent.Future<B> apply(A a) {
try {
return run(function, a, context);
return run(function, a, context, classLoader);
} catch (RuntimeException e) {
throw e;
} catch(Throwable t) {
Expand All @@ -305,11 +307,12 @@ public scala.concurrent.Future<B> apply(A a) {
*/
public Promise<A> recover(final Function<Throwable,A> function) {
final play.mvc.Http.Context context = play.mvc.Http.Context.current.get();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return new Promise<A>(
play.core.j.JavaPromise.recover(promise, new scala.runtime.AbstractFunction1<Throwable, scala.concurrent.Future<A>>() {
public scala.concurrent.Future<A> apply(Throwable t) {
try {
return run(function,t, context);
return run(function,t, context, classLoader);
} catch (RuntimeException e) {
throw e;
} catch(Throwable e) {
Expand All @@ -332,11 +335,12 @@ public scala.concurrent.Future<A> apply(Throwable t) {
*/
public <B> Promise<B> flatMap(final Function<A,Promise<B>> function) {
final play.mvc.Http.Context context = play.mvc.Http.Context.current.get();
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return new Promise<B>(
promise.flatMap(new scala.runtime.AbstractFunction1<A,scala.concurrent.Future<Promise<B>>>() {
public scala.concurrent.Future<Promise<B>> apply(A a) {
try {
return run(function, a, context);
return run(function, a, context, classLoader);
} catch (RuntimeException e) {
throw e;
} catch(Throwable t) {
Expand Down Expand Up @@ -375,7 +379,7 @@ static List<akka.actor.ActorRef> actors() {
return actors;
}

static <A,B> scala.concurrent.Future<B> run(Function<A,B> f, A a, play.mvc.Http.Context context) {
static <A,B> scala.concurrent.Future<B> run(Function<A,B> f, A a, play.mvc.Http.Context context, ClassLoader classLoader) {
Long id;
if(context == null) {
id = 0l;
Expand All @@ -384,7 +388,7 @@ static <A,B> scala.concurrent.Future<B> run(Function<A,B> f, A a, play.mvc.Http.
}
return play.core.j.JavaPromise.akkaAsk(
actors().get((int)(id % actors().size())),
Tuple3(f, a, context),
Tuple4(f, a, context, classLoader),
akka.util.Timeout.apply(60000 * 60 * 1) // Let's wait 1h here. Unfortunately we can't avoid a timeout.
).map(new scala.runtime.AbstractFunction1<Object,B> () {
public B apply(Object o) {
Expand All @@ -407,17 +411,24 @@ public B apply(Object o) {
// This Actor is used as Agent to ensure function execution ordering for a given context.
public static class PromiseActor extends akka.actor.UntypedActor {

public void onReceive(Object o) {
Function f = (Function)(((Tuple3)o)._1);
Object a = (Object)(((Tuple3)o)._2);
play.mvc.Http.Context context = (play.mvc.Http.Context)(((Tuple3)o)._3);
try {
play.mvc.Http.Context.current.set(context);
getSender().tell(Either.Right(f.apply(a)));
} catch(Throwable t) {
getSender().tell(Either.Left(t));
} finally {
play.mvc.Http.Context.current.remove();
public void onReceive(Object msg) {
if (msg instanceof Tuple4) {
Tuple4 tuple = (Tuple4) msg;
Function f = (Function) tuple._1;
Object a = tuple._2;
play.mvc.Http.Context context = (play.mvc.Http.Context) tuple._3;
ClassLoader classLoader = (ClassLoader) tuple._4;
ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
play.mvc.Http.Context.current.set(context);
getSender().tell(Either.Right(f.apply(a)));
} catch(Throwable t) {
getSender().tell(Either.Left(t));
} finally {
play.mvc.Http.Context.current.remove();
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
}

Expand Down
Expand Up @@ -66,4 +66,12 @@ public static Result user(User user) {
public static Result thread() {
return ok(Thread.currentThread().getName());
}

public static Result classLoader(String resource) {
if (Thread.currentThread().getContextClassLoader().getResource(resource) == null) {
return notFound();
} else {
return ok();
}
}
}
1 change: 1 addition & 0 deletions framework/test/integrationtest-java/conf/routes
Expand Up @@ -11,6 +11,7 @@ POST /json controllers.Application.getIdenticalJson()
GET /paged controllers.Application.paged(p: controllers.Pager)
GET /user/:user controllers.Application.user(user: models.User)
GET /thread controllers.Application.thread
GET /classLoader/:resource controllers.Application.classLoader(resource)

POST /parsers/json controllers.BodyParsers.json()
POST /parsers/limitedjson controllers.BodyParsers.limitedJson()
Expand Down
30 changes: 30 additions & 0 deletions framework/test/integrationtest-java/test/test/SimpleTest.java
@@ -1,5 +1,7 @@
package test;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -332,4 +334,32 @@ public void run() {
});
}

@Test
public void actionShouldBeExcecutedWithTheRightContextClassLoader() {
// Test classloader environment and dev classloader environment are very different. Let's provide our own
// classloader
ClassLoader classLoader = new ClassLoader() {
@Override
public URL findResource(String name) {
if (name.equals("dummy-resource")) {
try {
return new URL("file:///dummy-resource");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
} else {
return null;
}
}
};
FakeApplication app = new FakeApplication(new java.io.File("."), classLoader, new HashMap<String,Object>(), new ArrayList<String>(), null);
running(testServer(3333, app), new Runnable() {
@Override
public void run() {
WS.Response response = WS.url("http://localhost:3333/classLoader/dummy-resource").get().get();
assertThat(response.getStatus()).isEqualTo(200);
}
});
}

}

0 comments on commit 9162546

Please sign in to comment.