URL rewriting with OcpSoft adds parameter multiple times - java

Im' using OcpSoft rewrite, and I have this only rule for forwarding:
#Override public Configuration getConfiguration(ServletContext servletContext) {
return ConfigurationBuilder.begin().addRule(
Join.path("/x/{vendor}/{url}")
.to("/vendors/{url}")
);
}
Now, this works fine, I can find the "vendor" parameter in my list of parameters, and the "url" too.
The problem is that when I debug, I can see that the vendor and url are present multiple times instead of just once in the list of parameters:
Here, {url} is added 16 (!!) times in my list of parameters.
Do you know why ?

Ok, this is actually a bug of the library: https://github.com/ocpsoft/rewrite/issues/223
So, yeah.

Related

How do I respond to tickets with camel Jira Producer?

I'm following the examples here -> https://github.com/apache/camel-k-examples. Working on 05-knative-source-jira
When running this integration, I'm able to read and log new jira issues just fine, I fall down when I try to use info from the ticket, or respond to the ticket with the jira addComment producer.
I've tried just putting a static ticket number in for the IssueKey option, but I get build errors and can't even get the producer to run.
I've tried tinkering with the URI...
Ex: Changing URI to -> .to("jira://addComment?IssueKey=EQ-7") returns below on build
No signature of method: org.apache.camel.builder.ValueBuilder.to() is applicable for argument types: (String) values: [jira://addComment&IssueKey=EQ-7]
I've tried this with both ? and &, as well as adding properties to the URI with similar results.
I feel like I'm missing something pretty fundamental, so any docs pointers would be well appreciated.
Full integration here
// camel-k: language=groovy
from('knative:channel/jira')
.unmarshal()
.json()
.log('Recieved: ${body}')
.to('direct:ticket')
from("direct:ticket")
.setBody().simple("testing")
.to("jira://addComment?IssueKey=EQ-7")
I ended up sorting through enough docs to find the answer. I'll share details just for others who might find this (or if I google it again).
The key was to
a) Set the required headers for the issue key. Seting headers examples
b) Ensure that my properties are set correctly. I used a configmap to set my properties, and then referenced them as shown below in the URI. I believe this should also be possible through DSL but URI was easiest for me to just get working.
Functional Integration below.
from("direct:ticket")
.setHeader("IssueKey").simple('${body["key"]}')
.setBody().simple("We've recieved the ticket -- we'll update you soon!")
.to("jira://addComment?jiraUrl={{url}}&consumerKey={{consumer_key}}&accessToken={{access_token}}&privateKey={{private_key}}&verificationCode={{verification_code}}")

Can't get the routes object in play framework to show my custom route

I'm attempting to do a reverse lookup on a route I've created.
The route is defined as such in my routes file:
POST /login controllers.Web.Application.authenticate
However, when I try to do a reverse on it in a form I made, I can't seem to find it. I'm attempting to do a reverse like this:
#helper.form(action = routes.login())) {
rest of the form here...
}
However, the login appears in red in intellij and when attempting to run the program, I get the following error:
play.sbt.PlayExceptions$CompilationException: Compilation error[value login is not a member of object controllers.routes]
I've attempted recompiling the project multiple times and looking around the docs, but it's just not working... Any ideas?
So, an interesting thing happened recently and I found a way to point to the original structure properly. To do so, rather than writing:
routes.Web.Application.authenticate()
As Tyler suggested, I was supposed to write:
Web.routes.Application.authenticate()
Which is totally counter-intuitive and all, but that allows me to use the original package structure.
Edit:
As we discovered in the comments, the reverse router doesn't seem to like sub packages. You should remove the Web part of your package, and move everything up a level, then change the code to be this:
#helper.form(action = routes.Application.authenticate())) {
rest of the form here...
}
Original answer:
You need to refer to the controller function, and not the name of the route, so it should look something like this:
#helper.form(action = routes.Web.Application.authenticate())) {
rest of the form here...
}

Play Framework Multi-Tenant Filter

I'm attempting to build a multi-tenant application using Play Framework 2.2 and have run into a problem. I want to set a session key in the global onRouteRequest (or onRequest in Java) that identifies the site ID for the domain the user is requesting. In literally dozens of other frameworks this type of thing is painless (e.g. Django), but I'm learning that the session object in Play is apparently immutable, however.
So, right now, I have something like this:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteUIDFromURL(request.host.toLowerCase()).toString()
if (!id.isEmpty){
//what goes here to set the session?
}else{
//not found - redirect to a general notFound page
}
}
super.onRouteRequest(request)
}
And, although it's not the most efficient way using a database lookup, it works for testing right now. I need to be able to set a session key in the global but am completely lost on how to do that. If there are any better methods I am all ears (perhaps wrapping my controllers?).
I'm open to solution examples in either Java or Scala.
Think of actions in Play as being function calls, the input is the request, the output is the result. If you want to change the result of a wrapped function call, then you must first invoke the function, and then apply your change. Adding a key to a session is changing the result, since the session is sent to the client in the session cookie. In the code above, you're trying to do the change before you have a result to change, ie, before you call super.onRouteRequest.
If you don't need to modify routing at all, then don't do this in onRouteRequest, do it in a filter, much easier there. But assuming you do need to modify routing, then you need to apply a filter to handler returned. This is what it might look like:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
val maybeSite: Option[String] = request.session.get("site").orElse {
// Let's just assume that getSiteUIDFromUrl returns Option[String], always use Option if you're returning values that might not exist.
models.Site.getSiteUIDFromURL(request.host.toLowerCase())
}
maybeSite.flatMap { site =>
super.onRouteRequest(request).map {
case e: EssentialAction => EssentialAction { req =>
e(req).map(_.withSession("site" -> site))
}
case other => other
}
}
}
Check the source code for the CSRFFilter to see examples of how to add things to the session in a filter.

Upsert for LDAP directory in Java

I'm attempting to execute an Upsert using the Novell JLDAP library, unfortunately, I'm having trouble finding an example of this. Currently, I have to:
public EObject put(EObject eObject){
Subject s = (Subject) eObject;
//Query and grab attributes from subject
LDAPAttributes attr = resultsToAttributes(getLDAPConnection().get(s));
//No modification needed - return
if(s.getAttributes().equals(attr)){
return eObject;
} else {
//Keys:
//REPLACE,ADD,DELETE, depending on which attributes are present in the maps, I choose the operation which will be used
Map<String,LDAPAttribute> operationalMap = figureOutWhichAttributesArePresent(c.getAttributes(),attr);
//Add the Modifcations to a modification array
ArrayList<LDAPModification> modList = new ArrayList<LDAPModification>();
for(Entry entry: operationalMap.getEntrySet()){
//Specify whether it is an update, delete, or insert here. (entry.getKey());
modList.add(new LDAPModification(entry.getKey(),entry.getValue());
}
//commit
connection.modify("directorypathhere",modList.toArray(new LDAPModification[modList.size()]));
}
I'd prefer to not have to query on the customer first, which results in cycling through the subject's attributes as well. Is anyone aware if JNDI or another library is able to execute an update/insert without running multiple statements against LDAP?
Petesh was correct - the abstraction was implemented within the Novell library (as well as the UnboundId library). I was able to "upsert" values using the Modify.REPLACE param for every attribute that came in, passing in null for empty values. This effectively created, updated, and deleted the attributes without having to parse them first.
In LDAP, via LDIF files, an upset would be a single event with two steps. A remove and add of a value. This is denoted by a single dash on a line, between the remove then the add.
I am not sure how you would do it in this library. I would would try to modList.remove and then modList.add one after another and see if that works.

Redirect with anchor in play 2

I'm looking for possibility to add anchor to url returned in controller:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id));
}
I found that it was possible in play 1 using addRef method, but I couldn't find any replacement of the method in play 2.
Of course I can use concatenation like:
public static Result open(String id) {
// here I want to add acnhor like #foo to the produced url
return redirect(routes.MyPage.show(id).url + "#foo");
}
But it seems ugly.
Thank you for any help! Have a good day!
Before trying to answer that question.
I should recommend you change whatever behavior you're currently setting.
Because, an URL fragment's purpose is client side only. Such fragment is never sent to the server, so that it's cumbersome to do the opposite.
However, here is the embryo of a (quite?) elegant solution that you could follow.
What I'll try to do is to leave the browser deal with the fragment, in order to keep potential behaviors (f.i. go to ID or even deal with history...).
To do so, you could add an implicit parameter to your main template which will define the fragment that the URL should have:
#(title: String)(content: Html)(urlFragment:Option[UrlFragment] = None)
As you can see I wrapped the parameter in an Option and default'ed it to None (in order to avoid AMAP pollution).
Also, it simply wraps a String but you could use String alone -- using a dedicated type will enforce the semantic. Here is the definition:
case class UrlFragment(hash:String)
Very simple.
Now here is how to tell the browser to deal with it. Right before the end of the head element, and the start of body, just add the following:
#urlFragment.map { f =>
<script>
$(function() {
//after everything is ready, so that other mechanism will be able to use the change hash event...
document.location.hash = "#Html(#f.hash)";
});
</script>
}
As you can see, using map (that is when the urlFragment is not None) we add a script block that will set the hash available in urlFragment.
This might be a start, however... Think about another solution for the whole scenario.
As of Play 2.4, it's possible to use Call.withFragment().
routes.Application.index.withFragment("some-id").absoluteURL(request)
This was added by PR #4152.

Categories