Tapestry5 : URL Re-writing : Pass parameters to transformPageRenderLink method - java

I am upgrading tapestry from 5.2.4 to 5.3.8 and am stuck at re-implementing the URL re-writing part.
In my application a user account can have multiple data stores. User can have same page of different stores active at the same time. Hence I need to put the storeId in page links and event links URLs. So What is done is as follows.
I register MyLinkTransformerClass in AppModule as follows.
#Contribute(PageRenderLinkTransformer.class)
#Primary
public static void provideURLRewriting( OrderedConfiguration<PageRenderLinkTransformer> configuration){
configuration.addInstance(
"Faces", MyLinkTransformer.class);
}
Following is the MyLinkTransformer class which implements PageRenderLinkTransformer
public PageRenderRequestParameters decodePageRenderRequest(
Request request) {
// for incoming requests - remove the store id from URL and
// save into Request as an attribute
String path = request.getPath();
if (path.equals("/")) {
// Redirect to accounts page
return new PageRenderRequestParameters("account", new EmptyEventContext(), false);
}
else {
String start = path.split("/")[1];
if (!ignoredRewriteSet.contains(start) && !start.startsWith("account")) {
String storePath = path.substring(1).substring(path.indexOf("/"));
int idx = storePath.indexOf("/");
if (idx < 0) idx = storePath.length();
String storeId = storePath.substring(0, idx).trim();
RequestHelper.setStoreId(request, storeId);
EventContext urlEventContext = new URLEventContext(contextValueEncoder, new String[]{storeId});
EventContext arrayEventContext = new ArrayEventContext(typeCoercer, "foo");
return new PageRenderRequestParameters(storePath.substring(idx), arrayEventContext, false);
//return new PageRenderRequestParameters(storePath.substring(idx), new EmptyEventContext(), false);
}
}
return null;
}
public Link transformPageRenderLink(
Link defaultLink,
PageRenderRequestParameters parameters) {
// for outgoing requests- This is where I want to access the store Id
// which is stored in Request class of Tapestry as an attribute and
// add it to the URL
return null;
}
So, the idea is to remove storeId from URL in decodePageRenderRequest method and save it in the Request class of Tapestry as an attribute. And while creating outgoing URLs of page link and event link, I want to access the storeId which was saved in Request and inject it to the URL which will be rendered in method transformPageRenderLink.
But I don't know how to pass parameters to transformPageRenderLink method or access Request instance there.
I am following http://blog.tapestry5.de/index.php/2010/09/06/new-url-rewriting-api/ example.
I am new to URL Rewriting, any help with this will be appreciated.

You will probably be interested in the ModeComponentEventLinkEncoder here. It removes a "mode" from the URL and puts it onto the Environment before passing it on to the normal tapestry URL processing.
It's a two way process so the "mode" is included in any links generated on the page.
Note: This is applied as a decorator here

Related

IBM Mobilefirst JAVA adapter giving MFP-Conflict=Concurrency failure while storing user data

I am building a JAVA HTTP Adapter, I am authenticating the user in UserAuthenticationSecurityCheck class using the following method
#Override
protected AuthenticatedUser createUser() {
return new AuthenticatedUser(userId, logonId, this.getName(), attributes);
}
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
return false;
}
After this control goes to android app then they call the REST API called /updateClientRegistrtion which will update the ClientRegistrationData
#GET
public Response updateClientRegistartion(#Context HttpServletRequest request) {
AuthenticatedUser authUser = securityContext.getAuthenticatedUser();
Map<String, Object> attributes = authUser.getAttributes();
ClientData clientData = securityContext.getClientRegistrationData();
clientData.getProtectedAttributes().put(some parameter);
if (clientData.getClientId() != null) {
securityContext.storeClientRegistrationData(clientData);
}
But this code is giving me error like
Exception Message :
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
Is there any solution to this problem? Can someone please help me with this.
Tutorial followed : http://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/authentication-and-security/user-authentication/security-check/
409; headers=[ MFP-Conflict=Concurrency failure]; body={}
results when concurrent requests try to store attributes into the same row or the data in the row being modified by another request before it was updated.
This could be from the request being fired more than once ( in close proximity).Another possibility is that while one request was working on the data in memory, another had already modified and updated it.
The code should still work without the line:
securityContext.storeClientRegistrationData(clientData);
Try that out.
Alternatively, put a try-catch around the
storeClientRegistrationData(clientData)
and retry in the catch block.

Getting more data during a Post request using Spring / Thymeleaf

I'm not really sure how to ask the question, but I'm going to try here.
I've got a list of actions that could happen to a subject. The user of my system needs to approve these actions and does so by selecting (checkboxes) these actions and then clicking the Approve button. Some of these action might require extra data, so a new page is presented to the user. The user enters that new data. Then the backend sends the whole package off to the endpoint for modification on the database. Once completed, it will reload the page they were just on.
So this is how I have it setup:
Approve button jumps to the following method:
#PostMapping("ApproveActions")
public RedirectView approveActions(ModelandView mav, #ModelAttribute("pendingActions") PendingActionsForm pendingActions) {
boolean needsDetails = false;
ActionForm actionForm = new ActionForm();
// parse through each of the actions
pendingActions.forEach(action -> {
// verify if the action has been selected by the user.
if (action.isSelected()) {
// if needsDetails hasn't been set to true,
if (!needsDetails) {
// check to see if it is one of the special actions that needs more info
needsDetails = ActionTypes.NeedsDetails(action.typeId());
}
// build the data for the endpoint
actionForm.addActionData(action);
}
});
if (needsDetails) {
// load the new page
rv.setUrl("/extraActionDetails");
return rv; // This is not right, but it does get me to the new page.
// get data
// return to this point with that new data
actionForm.setExtraDetails(???);
}
actionService.ApproveActions(actionForm);
RedirectView rv = new RedirectView();
rv.setUrl("/subjects/" + pendingActions.getSubjectId() + "#actions-pending");
return rv;
}
The problem I'm having is I don't know how to do that part with // load the new page get data and return to this point with that new data. I've got the extra-details.jsp page built out. And it's controller can be called. Does this question make sense? Are there any tutorials out there that address this situation?

Spring Boot Thymeleaf JavaMail -"class path resource [images/logo.png] cannot be opened because it does not exist " with streams.foreach

I am using Spring Boot and Thymeleaf to send emails. I have one inline image as a signature in the email. Everything works fine if I send one email at a time. But, my use case is to send an individual email to a list of recipients. I am able to do that without the image. But, when I add the image, the first email is getting sent and for the second time I get class path resource [images/tp-logo.png] cannot be opened because it does not exist.
When I call emailService.send() from the stream.forEach() I get above error.
When I call it from a normal for loop, it works fine.
I understand that the streams are lazy, but why the resource is missing?
Working Caller method code:
for(ContactIfo contact : contactInfoList) {
ExecutorService emailExecutor = Executors.newCachedThreadPool();
emailExecutor.execute(() -> {
final String emailAddress = contact.getEmailAddress();
if (StringUtils.isNotBlank(emailAddress)) {
emailService.sendEmail(emailAddress);
}
});
}
Failing caller method code:
contactInfoList.parallelStream().forEach(contact -> {
ExecutorService emailExecutor = Executors.newCachedThreadPool();
emailExecutor.execute(() -> {
final String emailAddress = contact.getEmailAddress();
if (StringUtils.isNotBlank(emailAddress)) {
emailService.sendEmail(emailAddress);
}
});
});
Callee:
private void sendEmail(Mail mail) throws MessagingException {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
Context context = new Context();
context.setVariables(mail.getProps());
String html = templateEngine.process("me-event-update-template", context);
helper.setText(html , true);
helper.setTo(mail.getMailTo());
helper.setSubject(mail.getSubject());
helper.setFrom(mail.getFrom());
// adding inline resources with matching cId to the variable name/value
helper.addInline("logo", new ClassPathResource("images/logo.png"), "image/png");
emailSender.send(message);
}

Java CEF - Is it possible to access DOM document and elements of loaded page?

I've built java-cef from https://bitbucket.org/chromiumembedded/java-cef/overview , but I still can't find any info in docs and javadocs about how to access DOM document and elements of loaded page.
I need to access elements by something like document.getElementsByClassName("example");, document.getElementsByTagName("div");.
Something like in JSoup - https://jsoup.org/cookbook/extracting-data/selector-syntax :
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
Elements links = doc.select("a[href]"); // a with href
Elements pngs = doc.select("img[src$=.png]");
Is there same functional in Java-CEF?
Thank you!
You need to attach a load handler to the CEF Client and call CefBrowser::executeJavaScript(String code) inside the handler, e.g.:
cefClient.addLoadHandler(new LoadHandler());
...
class LoadHandler extends CefLoadHandlerAdapter {
#Override
public void onLoadEnd(CefBrowser browser, int frameId, int status) {
String jscode = "var x = document.getElementsByClassName('example')";
browser.executeJavaScript(jscode);
}
}
UPDATE
Then if you want to receive events from the browser script in your Java code, you need to register a call cefQuery with CefBrowser::executeJavaScript(String code), passing all necessary data in a single argument, and receive it with a message router, e.g:
CefMessageRouter msgRouter = CefMessageRouter.create();
msgRouter.addHandler(new MessageRouterHandler(), true);
cefClient.addMessageRouter(msgRouter);
...
browser.executeJavaScript("cefQuery({request: 'Hello World'})");
...
class MessageRouterHandler extends CefMessageRouterHandlerAdapter {
#Override
public boolean onQuery(CefBrowser browser, long query_id, String request, boolean persistent, CefQueryCallback callback) {
System.out.println(request); // prints "Hello World"
return true;
}
}

Render page to string in Wicket 1.5

I'm working on upgrading our existing Wicket webapp to 1.5 and have hit a snag in our renderPage function that we use to render our HTML emails.
Previously we used the code referenced/listed in this StackOverflow question and this (currently broken but maybe fixed later) link but that code no longer works as a lot of those classes don't exist in 1.5.
I also found this email thread but it is light on the details and I don't know how to create the WebPage from my pageClass and parameters.
http://apache-wicket.1842946.n4.nabble.com/Render-WebPage-to-String-in-Wicket-1-5-td3622130.html
Here is my code:
// Renders a page under a temporary request cycle in order to get the rendered markup
public static String renderPage(Class<? extends Page> pageClass, PageParameters pageParameters)
{
//get the servlet context
WebApplication application = (WebApplication) WebApplication.get();
ServletContext context = application.getServletContext();
//fake a request/response cycle
MockHttpSession servletSession = new MockHttpSession(context);
servletSession.setTemporary(true);
MockHttpServletRequest servletRequest = new MockHttpServletRequest(application, servletSession, context);
MockHttpServletResponse servletResponse = new MockHttpServletResponse(servletRequest);
//initialize request and response
servletRequest.initialize();
servletResponse.initialize();
WebRequest webRequest = new ServletWebRequest(servletRequest);
BufferedWebResponse webResponse = new BufferedWebResponse(servletResponse);
webResponse.setAjax(true);
WebRequestCycle requestCycle = new WebRequestCycle(application, webRequest, webResponse);
requestCycle.setRequestTarget(new BookmarkablePageRequestTarget(pageClass, pageParameters));
try
{
requestCycle.getProcessor().respond(requestCycle);
if (requestCycle.wasHandled() == false)
{
requestCycle.setRequestTarget(new WebErrorCodeResponseTarget(HttpServletResponse.SC_NOT_FOUND));
}
}
finally
{
requestCycle.detach();
requestCycle.getResponse().close();
}
return webResponse.toString();
}
Specifically, the code breaks because the WebRequestCycle and BookmarkablePageRequestTarget classes no longer exist. I feel like I should be able to use the StringResponse class some how but I'm missing the link that would help me trigger a render on that response.
Any help would be appreciated. Thanks.
My Final Solution
Using the example that I was directed to by the answer below I ended up with the following code. I'm pasting it here as well so that if that link disappears or is changed with a future version of Wicket then people from the future will still be able to get the answer they need.
I ended up passing in a PageProvider because in some cases I needed to pass in an instantiated Page and in others a pageClass + parameters.
public static String renderPage(final PageProvider pageProvider)
{
final RenderPageRequestHandler handler = new RenderPageRequestHandler(pageProvider, RedirectPolicy.NEVER_REDIRECT);
final PageRenderer pageRenderer = Application.get().getPageRendererProvider().get(handler);
RequestCycle requestCycle = RequestCycle.get();
final Response oldResponse = requestCycle.getResponse();
BufferedWebResponse tempResponse = new BufferedWebResponse(null);
try
{
requestCycle.setResponse(tempResponse);
pageRenderer.respond(requestCycle);
}
finally
{
requestCycle.setResponse(oldResponse);
}
return tempResponse.getText().toString();
}
Check the source code of http://www.wicket-library.com/wicket-examples/mailtemplate/ example.

Categories