I'm new to scala, but have some experience using the play framework in Java. I've added the SecureSocial authentication library, which defines a SecuredACtion, and it seems to be working correctly. However, I'm having trouble understanding the expected content within the custom action in scala code.
Here's my controllers class. Ideally, "index" would simply redirect the authenticated request to "unprotectedIndex" somehow, but that doesn't seem to be possible. So if not, next best thing is simply to serve the file directly from inside of the secured action, but that's also not working.
What is missing from my code?
object Application extends Controller with securesocial.core.SecureSocial {
// this doesn't compile, but it's a long scala exception that I don't know how to fix.
def index = SecuredAction { implicit request =>
Assets.at("/public", "index.html").apply(request)
}
def unprotectedIndex = Assets.at("/public", "index.html")
}
It seems like it's expecting a SimpleResult but getting a Future[SimpleResult] - this feels like it shouldn't be complicated, but what am I missing?
It seems like you are using play framework 2.2. There were some changes and most methods return Future[SimpleResult] instead of just Result or SimpleResult. You can check if you are able to do like this: def index = SecuredAction.async {...} (but I'm almost sure you can't).
You can use this approach to make it work correctly:
import scala.concurrent.Await
import scala.concurrent.duration._
def index = SecuredAction { implicit request =>
Await.result(Assets.at("/public", "index.html").apply(request), 5 seconds) //you can specify you maximum wait time here
}
EDIT
Even one more thing to simplify:
Await.result(unprotectedIndex(request), 5 seconds)
So you can call your unprotectedIndex from your index Action
So, just by looking at syntax highlighting in my IDE I have been able to get something that seems to compile and work but looks deeply wrong to me.
I changed it to this:
def index = SecuredAction { implicit request =>
Assets.at("/public", "index.html").apply(request).value.get.get
}
Is that the correct way to do this? It looks really weird to me, am I just not familiar with the idioms?
Related
I feel like I must be missing something obvious but can't seem to figure this one out.
For this project I am writing an http mock with mock-server using upsert so that during the runtime of mock I can change the behavior by upserting an expectation.
So like this:
mock.upsert(
new Expectation(request().withMethod("GET").withPath(MY_PATH))
.thenRespond(response().withBody(json("{\"hello\": \"world\"}")))
.withId(MY_REQUEST_ID));
Now I need some more dynamic behavior so I want to use a callback.
mock.when(request().withMethod("POST").withPath(MY_PATH))
.respond(
httpRequest -> {
final var response = dynamicResponse();
return response().withBody(json(response));
});
Now I can not figure out how to combine the above, so that I have an expectation with a known id, that I can upsert. Expectation does have an thenRespond overload that takes an HttpObjectCallback which sounds like what I am after, but that needs a clientId which I don't no where to get from, or how to pass the actual callback.
Again it feels like I am missing something obvious. Any help is much appreciated.
Please bear with me, i dont usually use spring and havent used newer versions of java (I say newer I mean anything past prob 1.4)
Anyway, I have an issue where I have to do rest calls to do a search using multiple parallel requests. Ive been looking around online and I see you can use CompletableFuture.
So I created my method to get the objects I need form the rest call like:
#Async
public CompletableFuture<QueryObject[]> queryObjects(String url)
{
QueryObject[] objects= restTemplate.getForObject(url, QueryObject[].class);
return CompletableFuture.completedFuture(objects);
}
Now I need to call that with something like:
CompletableFuture<QueryObject> page1 = QueryController.queryObjects("http://myrest.com/ids=[abc, def, ghi]);
CompletableFuture<QueryObject> page2 = QueryController.queryObjects("http://myrest.com/ids=[jkl, mno, pqr]);
The problem I have is that the call needs to only do three ids at a time and there could be a list of variable number ids. So I parse the idlist and create a query string like above. The problem with that I am having is that while I can call the queries I dont have separate objects that I can then call CompletableFuture.allOf on.
Can anyone tell me the way to do this? Ive been at it for a while now and Im not getting any further than where I am now.
Happy to provide more info if the above isnt sufficient
You are not getting any benefit of using the CompletableFuture in a way you're using it right now.
The restTemplate method you're using is a synchronous method, so it has to finish and return a result, before proceeding. Because of that wrapping the final result in a CompletableFuture doesn't cause it to be executed asynchronously (neither in parallel). You just wrap a response, that you have already retrieved.
If you want to benefit from the async execution, then you can use for example the AsyncRestTemplate or the WebClient .
A simplified code example:
public ListenableFuture<ResponseEntity<QueryObject[]>> queryForObjects(String url) {
return asyncRestTemplate.getForEntity(url, QueryObject[].class);
}
public List<QueryObject> queryForList(String[] elements) {
return Arrays.stream(elements)
.map(element -> queryForObjects("http://myrest.com/ids=[" + element + "]"))
.map(future -> future.completable().join())
.filter(Objects::nonNull)
.map(HttpEntity::getBody)
.flatMap(Arrays::stream)
.collect(Collectors.toList());
}
Integrating a RxJava in springboot application using Observable we are able to get the data from the service. But I have a doubt in using toBlocking() method, because I've read many forum postings saying it has issues in production server. See my below code,
Sample Code with toBlocking():
userService.getUsers()
.subscribeOn(Schedulers.io())
.toBlocking()
.single();
I want to change the above to get the user object instead of Observable object.
For example:
User user = new User();
userService.getUsers().subscribe(u ->user = u );
Here a variable user is declared globally in the class it work fine, but inside method it shows an error.
You probably want something like blockingFirst:
final User user = userService
.getUsers()
.blockingFirst()
I'd encourage you to think about if this is the right thing to do, though (do you really need to block and jump out of the reactive world for this use case?. As #akarnokd said, read Getting Started)
I'm currently using the session() of play framework in my template :
#if(session().get("email")==null){
<li>Login</li>
}else{
<li>Logout</li>
}
This template is used in all of my views. Some of these views are controlled by a Java controller, and some are with a Scala controller.
When I click on links that lead to Java controllers, I have no problems, the links for login and logout are correctly handled.
When I click on links that lead to Scala controllers, I get a [RuntimeException: There is no HTTP Context available from here.]
From what I read in here about scala controllers, I understood that they didn't return the http context when rendering a page, but I really want to be able to use the session in my template.
I thought about using an argument session() in my view, templates and controllers, but I believe that there will be a conflict between the java session (play.mvc.http.session) and the scala session (play.api.mvc.session) when play will compile the html pages.
Am I stuck? Is there a possibility to force scala controllers to give back the http context ?
The root cause maybe the Java controllers and Scala controllers are handled differently.
I have my project in Java first, and then try to add more Scala controllers. I also came across this problem (BTW, I am using Play 2.3.2).
I tried to fix this by setting my own Http.Context in the TheadLocal variable using my own ActionBuilder.
import play.api.mvc._
import scala.concurrent.Future
import play.mvc.Http.Context
import play.core.j.JavaHelpers
object ContextAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Context.current.set(JavaHelpers.createJavaContext(request))
block(request)
}
}
Then my Scala controller actions simply use this ContextAction instead:
class TestController extends Controller {
def test = ContextAction { implicit request =>
Ok(views.html.index())
}
}
And this way the index template can access all request() / session() / etc.
I may be wrong, but I think that your Scala controllers should look like:
def myaction() = Action { implicit request =>
...
}
instead of:
def myaction() = Action {
...
}
Ie, you have to add the request to the scope of your Action.
And add it also to your view, at the beginning of the file:
#(...)(implicit session:Session)
Okay I found a workaround this problem.
This is not really aesthetic, but it works, and gets rid of the problem entirely.
I created two different main templates : scalamain.scala.html and javamain.scala.html.
The scalamain template is used by all views that are controlled by a Scala controller, and used the usual trick to use the session (implicit arguments, see more here).
The javamain template is used by all view that are controlled by a Java controller. (these view use the session easily).
The two templates are of course, the same once rendered by play.
I end up with some redundancy in my code and it took to separate all the actions so that view are controlled by only one type of controller(scala or java).
I hope this will help others with the same problem. I validate this answer, as it solves the problem, but feel free to answer if you find a more gracious way to solve it.
I'm using Restlet to make a RESTful platform. I haven't used it before, but I decided to use 2.0 because it is better to start with the latest and greatest technology, right?
The key thing I am looking for is the ability to have someone to put in a URL like http://mysite/New%20York/3 and have the service respond with something like [New York,New York,New York], so I need to pass in request attributes. Using this post for Restlet 1.1 (because I can't seem to find any documentation for this on the Restlet site), I wired up my application like so:
router.attach("{text}/{count}", RepeaterResource.class);
The new way to do this is apparently in the UniformResource#doInit() method, so mine looks like (without error checking):
#Override
public void doInit()
{
magicText = "" + getRequestAttributes().get("text");
repeatAmount = Integer.parseInt("" + getRequestAttributes().get("count"));
}
The problem is that the Map<String, Object> returned from getRequestAttributes() is always completely empty! This seems rather odd. Am I wiring the routing up wrong?
Of course, I could just use getQuery() and parse it myself, but that is definitely the wrong way to go about doing this and it seems like there should be an easy way to do this (similar to the way previous versions worked).
My problem, is seems, is that router attachments must start with the / character. I should attached like so:
router.attach("/{text}/{count}", RepeaterResource.class);
I can't seem to find this behavior documented and it seems rather odd, but it certainly fixed my issues.
You can do this with 2.0 the same way as with 1.1.
See the tutorial, part 11: http://www.restlet.org/documentation/2.0/tutorial#part11
Restlet is great, BTW.