How can I get link for REST resource in JSF2 - rest

Say, I have a simple REST service, that get content of PDF file:
#Path("/pdf")
#Stateless
public class GroupSheetEJB {
. . .
#GET
#Path("examsheet/{groupId: \\d+}/{course: \\d+}/{semester: \\d+}/{subjectId: \\d+}")
#Produces("application/pdf")
public Response examSheet(#PathParam("groupId") int groupCode, #PathParam("course") int course,
#PathParam("semester") int semester, #PathParam("subjectId") int subjectCode) {
try {
StudyGroup grp = groups.get(groupCode);
Subject sub = subjects.get(subjectCode);
ResponseBuilder response = Response.ok(getExamSheet(grp, sub, course, semester));
return response.build();
} catch (Exception e) {
throw new NotFoundException(e.getMessage());
}
}
}
Is any way to easily get link for this REST service from <h:link> component?
Now I use plain HTML tag:
<a target="examsheet" href="#{request.contextPath}/webresources/#{semesterSubjectMarksMB.examSheetLink}">REST link</a>
outcome parameter of with value /webresources/#{semesterSubjectMarksMB.examSheetLink} gets a disabled link.
Best regards.

Related

How to retrieve link from email message using the Gmail plugin/GMail API for Java/Jakarta Mail API/...?

I am using Katalon Studio, and need to retrieve some sign-up link from test email inbox. I found some API/service to access the test email inbox, can get the message I need from it, and it's a string of what looks like HTML.
I don't care about the HTML, I just want to "click on" the link in that email message!
How do I do that!?
Assuming you successfully have the message string, here's how you can retrieve the link from it, assuming that your email message retrival method call returns HTML string.
To save you some clicking:
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathFactory
import org.w3c.dom.Element
// feel free to make this your own :)
public final class EmailUtils {
/**
* **NOTE**: forked from https://stackoverflow.com/a/2269464/2027839 , and then refactored
*
* Processes HTML, using XPath
*
* #param html
* #param xpath
* #return the result
*/
public static String ProcessHTML(String html, String xpath) {
final String properHTML = this.ToProperHTML(html);
final Element document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream( properHTML.bytes ))
.documentElement;
return XPathFactory.newInstance()
.newXPath()
.evaluate( xpath, document );
}
private static String ToProperHTML(String html) {
// SOURCE: https://stackoverflow.com/a/19125599/2027839
String properHTML = html.replaceAll( "(&(?!amp;))", "&" );
if (properHTML.contains('<!DOCTYPE html'))
return properHTML;
return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head></head>
<body>
${properHTML}
</body>
</html>
""";
}
}
From there, you'll have to log out your HTML message string (or put debug breakpoint around your method call and extract it from debugger), pretty print it, and from there, you can use your web-testing skills to create some xpath selector string for the actual link.
Then, you use my code like:
WebUI.navigateToUrl(yourEmailMessageContent, "${yourLinkXPath}/#href");
To be fair, email messages can take some time to hit inboxes. Hence you might also want to have some retry logic in place. Here is example from my real project code base:
import java.util.concurrent.TimeUnit
// ...rest of imports
public final class EmailUtils {
//...rest of code base
public static String ExtractSignUpLink() {
String link;
int retryAttempts;
ActionHandler.Handle({
link = this.ProcessHTML(this.GetLatestMessageBody(30),
"//a[.//div[#class = 'sign-mail-btn-text']]/#href");
}, { boolean success, ex ->
if (success)
return;
// handle ex
if (((GoogleJsonResponseException)ex).getDetails().getCode() >= 400)
throw ex;
sleep(1000 * 2**retryAttempts++);
}, TimeUnit.MINUTES.toSeconds(15))
return link;
}
//...rest of code base
}
public final class ActionHandler {
public static void Handle(Closure onAction, Closure onDone, long timeOut) {
long startTime = System.currentTimeSeconds();
while (System.currentTimeSeconds() < startTime + timeOut) {
try {
onDone(true, onAction());
return;
} catch (Exception ex) {
onDone(false, ex);
}
}
}
}

Inject paramater into Spring Aspect Advice

I have a basic spring rest controller and have a company requirement which needs to log request and response in one combined log message. I planned on doing this with some simple aspect.
However the controller calls a service which in turn calls out to another third party api and there is requirement to include the time taken for this third party call in the log output from the controller mentioned above.
I am wondering if this can be achieved with aspects?
I guess it would need an #Around aspect for main controller and then another #Around for the downstream api call and some way to inject the result of the inner aspect to the advice or outer one. Not sure if this can be done?? Or perhaps a request scoped bean passed through aspects??
Thanks
How about a class Log
public class Log {
private long start;
private long end;
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
#Override
public String toString() {
return "Log [start=" + start + ", end=" + end + "]";
}
And pass the instance of this object through the api calls.
Say BeanOne.methodOne(Log,..) -> BeanTwo.methodTwo(Log,..) . BeanTwo.methodTwo() calls the external api and the time is recorded in Log instance.
and an advice as follows
#Around("execution(* methodOne(..)) && args(log)")
public void testAdviceBeanOne(ProceedingJoinPoint pjp,Log log) {
System.out.println("Before methodOne()");
try {
System.out.println(log);
pjp.proceed();
System.out.println(log);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("After methodOne()");
}
Gives the output
Before methodOne()
Log [start=0, end=0]
Log [start=1572408716134, end=1572408716136]
After methodOne()
There could be a more elegant solution , still my two cents

AEM 6.1 Sightly basic form submit and redirect to same page

I am trying to do the following on AEM 6.1:
Develop a simple form (3 input fields)
Process the submitted values,
And redirect to the same page with processed values/result
I am able to submit the values to a servlet, and process them (business logic), and the result to a requestparamter so i can retrieve them on the UI. But i am stuck at these:
Redirecting to the same page
And retrieving the request parameters and display them using Sightly.
Code Snippets:
Servlet
#SlingServlet(
methods = { "POST","GET" },
name="com.tti.tticommons.service.servlets.LeadTimeTrendsServlet",
paths = { "/services/processFormData" }
)
public class TTICommonServlet extends SlingAllMethodsServlet{
...
#Override
protected void doPost(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
String result;
try {
Enumeration<String> parameterNames = request.getParameterNames();
Map<String, String> formParametersMap = new HashMap<String, String>();
while (parameterNames.hasMoreElements()) {
paramName = parameterNames.nextElement();
paramValue = request.getParameter(paramName);
.......
.......
}
request.setAttribute("result",result);
response.sendRedirect("/content/ttii/en/**posttest.html**");
}
}
Can anyone please help on ho to retireve the above "result" in posttest.html using sightly.
After lot of research and several trials, i finally had the code working. I had to pick up related info from several answers in stackoverflow. Thanks to all the authors. Posting my solution here so beneficial for others.
Result Form with response from webservice:
Process flow
Submit form data to Servlet's POST method
In Servlet, get the values entered by the user from the request
Make the necessary webservice calls. Get the response(json)
I added the response-json as a parameter to the request
Using Wrapper, forward to the necessary page
Define a WCMUse class for use with Sightly.
Assign the 'request' to the Use-class and process it there
Use the assigned values from the Use-class to the UI using sightly
Code snippets - HTML
<form name="userRegistrationForm" method="post" action="/services/processFormData">
<input type="hidden" name=":redirect" value="posttest.html" />
<input type="submit" title="Submit" class="btn submit btn-success" value="Submit" tabindex="25" name="bttnAction">
<div data-sly-use.model="${'com.abccommons.service.helpers.PostServiceHelper' # slingreq=request }">
**${model.getRawJson}**
</div>
Code snippets - Servlet
#SlingServlet(
label = "ABC - Common Servlet",
metatype = true,
methods = { "POST" },
name="com.abccommons.service.servlets.ABCPostServlet",
paths = { "/services/processFormData" }
)
public class ABCPostServlet extends SlingAllMethodsServlet{
#Override
protected void doPost(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException {
log.info("\n\n----- ABCPostServlet POST: ");
String paramName;
String paramValue;
String osgiService="";
try {
Enumeration<String> parameterNames = request.getParameterNames();
Map<String, String> formParametersMap = new HashMap<String, String>();
while (parameterNames.hasMoreElements()) {
paramName = parameterNames.nextElement();
paramValue = request.getParameter(paramName);
if (paramName.equals("osgiService")) {
osgiService = paramValue;
} else if (paramName.equals(":cq_csrf_token")) {
//TODO: don't add to the map
} else if (paramName.equals("bttnAction")) {
//TODO: dont' add to the map
} else {
//log.info("\n---ParamName="+paramName+", value="+paramValue);
formParametersMap.put(paramName, paramValue);
}
}
String parametersInJSON = JSONHelper.toJson(formParametersMap);
log.info("\n\n----------- POST paramters in json="+parametersInJSON);
String json = webServiceHelper.getJSON(osgiService, parametersInJSON, request, response);
log.info("\n\n----------- POST json from web service="+json);
request.setAttribute("jsonResponse",json);
//String redirectPage = request.getParameter(":redirect");
//RequestDispatcher dispatcher = request.getRequestDispatcher("/content/en/"+redirectPage);
RequestDispatcher dispatcher = request.getRequestDispatcher("/content/en/postformtest.html");
GetRequest getRequest = new GetRequest(request);
dispatcher.forward(getRequest, response);
} catch (Exception e) {
log.error("SlingServlet Failed while retrieving resources");
} finally {
//TODO
}
}
/** Wrapper class to always return GET for AEM to process the request/response as GET.
*/
private static class GetRequest extends SlingHttpServletRequestWrapper {
public GetRequest(SlingHttpServletRequest wrappedRequest) {
super(wrappedRequest);
}
#Override
public String getMethod() {
return "GET";
}
}
Code snippets - PostServiceHelper - WCMUSe class
public class PostServiceHelper extends WCMUse {
protected final Logger log = LoggerFactory.getLogger(PostServiceHelper.class);
private SlingHttpServletRequest httpRequest;
private String rawJson;
#Override
public void activate() throws Exception {
log.info("\n\n========= PostServiceHelper.activate():"+get("slingreq", SlingHttpServletRequest.class));
this.httpRequest = get("slingreq", SlingHttpServletRequest.class);
//this.resourceResolver = getResourceResolver();
//log.info("\n\n========= getRequest()="+getRequest());
SlingHttpServletRequest tRequest;
Set<String> keys = new HashSet<String>();
Enumeration<?> attrNames = this.httpRequest.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attr = (String) attrNames.nextElement();
//log.info("\n--- Key="+attr);
if (attr.equals("jsonResponse")) {
this.setRawJson((String)this.httpRequest.getAttribute(attr));
//log.info("\n---rawJson is SET with : "+this.rawJson);
}
}
}
public void setRawJson(String json) {
this.rawJson = json;
}
public String getRawJson() {
return this.rawJson;
}
}
This is actually a rather tricky pattern to achieve in Sling. You may be better served by submitting the form asynchronously and updating your HTML dynamically via JavaScript.
If you do need to submit your form in the manner you specify, then your servlet needs to produce the HTML response. To produce a response made up of a rendering of the page identified by the requested path your servlet will need to dispatch the request to the appropriate rendering mechanism. You can reference Get JSP output within Servlet in AEM for information concerning how that can be accomplished. Upon dispatch your page and its components should have access to the submitted form values as well as the attributes set on the request.

Render output format (HTML, JSON, XML) depending on parameter?

is there a good or proper way to render the output in Play Framework depending on a parameter? Example:
For HTML:
http://localhost:9000/user/get/5?v=HTML // should render HTML template
For JSON:
http://localhost:9000/user/get/5?v=JSON // should render JSON template
I think that a request interceptor could have the ability to achieve this, but I have no clue how to start or where to start :-(
Or perhaps, write a general render method that reads the parameters and output as requested, but this seems to me like overkill?
If /user/5?v=html and /user/5?v=json return two representations of the same resource, they should be the same URL, e.g. /user/5, according to the REST principles.
On client side, you can use the Accept header in your requests to indicate which representation you want the server to send you.
On server side, you can write the following with Play 2.1 to test the value of the Accept header:
public static Result user(Long id) {
User user = User.find.byId(id);
if (user == null) {
return notFound();
}
if (request().accepts("text/html")) {
return ok(views.html.user(user));
} else if (request().accepts("application/json")) {
return ok(Json.toJson(user));
} else {
return badRequest();
}
}
Note that the test against "text/html" should always be written prior to any other content type because browsers set the Accept header of their requests to */* which matches all types.
If you don’t want to write the if (request().accepts(…)) in each action you can factor it out, e.g. like the following:
public static Result user(Long id) {
User user = User.find.byId(id);
return representation(user, views.html.user.ref);
}
public static Result users() {
List<User> users = User.find.all();
return representation(users, views.html.users.ref);
}
private <T> Result representation(T resource, Template1<T, Html> html) {
if (resource == null) {
return notFound();
}
if (request().accepts("text/html")) {
return ok(html.apply(resource));
} else if (request().accepts("application/json")) {
return ok(Json.toJson(resource));
} else {
return badRequest();
}
}
Write 2 methods, use 2 routes (as you don't specify I will use Java samples:
public static Result userAsHtml(Long id) {
return ok(someView.render(User.find.byId(id)));
}
public static Result userAsJson(Long id) {
return play.libs.Json.toJson(User.find.byId(id));
}
routes:
/GET /user/get/:id/html controllers.YourController.userAsHtml(id:Long)
/GET /user/get/:id/json controllers.YourController.userAsJson(id:Long)
next you can just make a link in other view to display user's data
Show details
Get JSON
or something else...
edit #1
you can also use common if or case to determine final output
public static Result userAsV() {
String vType = form().bindFromRequest().get("v");
if (vTtype.equals("HTML")){
return ok(someView.render(User.find.byId(id)));
}
return play.libs.Json.toJson(User.find.byId(id));
}
I wanted the user to be able to be viewed in the browser as html or as json so the accepts method did not work for me.
I solved it by putting a generic renderMethod in a base class with the following style syntax
public static Result requestType( )
{
if( request().uri().indexOf("json") != -1)
{
return ok(Json.toJson(request()));
}
else
{
return ok("Got HTML request " + request() );
}
}

Pass a parameter to REST web service via URL

I'm creating a small REST web service using Netbeans. This is my code:
private UriInfo context;
private String name;
public GenericResource() {
}
#GET
#Produces("text/html")
public String getHtml() {
//TODO return proper representation object
return "Hello "+ name;
}
#PUT
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
I'm calling the get method ok since when I call http://localhost:8080/RestWebApp/resources/greeting I get "Hello null" but I'm trying to pass a parameter using http://localhost:8080/RestWebApp/resources/greeting?name=Krt_Malta but the PUT method is not being called... Is this the correct way to pass a parameter or am I missing something?
I'm a newbie to Rest bdw, so sry if it's a simple question.
Thanks! :)
Krt_Malta
The second URL is a plain GET request. To pass data to a PUT request you have to pass it using a form. The URL is reserved for GET as far as I know.
If you build the HTTP-header yourself, you must use POST instead of GET:
GET /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
versus
POST /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
If you use a HTML-form, you must set the method-attribute to "PUT":
<form action="/RestWebApp/resources/greeting" method="PUT">
For JAX-RS to mactch a method annotated with #PUT, you need to submit a PUT request. Normal browsers don't do this but cURL or a HTTP client library can be used.
To map a query parameter to a method argument, JAX-RS provides the #QueryParam annotation.
public void putWithQueryParam(#QueryParam("name") String name) {
// do something
}
You can set:
#PUT
#path{/putHtm}
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
and if you use something like google`s Volley library you can do.
GsonRequest<String> asdf = new GsonRequest<String>(ConnectionProperties.happyhourURL + "/putHtm", String.class, yourString!!, true,
new Response.Listener<Chain>() {
#Override
public void onResponse(Chain response) {
}
}, new CustomErrorListener(this));
MyApplication.getInstance().addToRequestQueue(asdf);
and GsonRequest will look like:
public GsonRequest(String url, Class<T> _clazz, T object, boolean needLogin, Listener<T> successListener, Response.ErrorListener errorlistener) {
super(Method.PUT, url, errorlistener);
_headers = new HashMap<String, String>();
this._clazz = _clazz;
this.successListener = successListener;
this.needsLogin = needLogin;
_object = object;
setTimeout();
}