CQ5: How to programmatically find out the Resource given a URL? - aem

According to ResourceResolver Interface:
http://dev.day.com/docs/en/cq/current/javadoc/org/apache/sling/api/resource/ResourceResolver.html
There are three ways to resolve either path or request to a Resource:
Resource resolve(HttpServletRequest request)
Deprecated. as of 2.0.4, use resolve(HttpServletRequest, String) instead.
Resource resolve(HttpServletRequest request, String absPath)
Resolves the resource from the given absPath optionally taking
HttpServletRequest into account, such as the value of the Host request header.
Resource resolve(String absPath)
Resolves the resource from the given absolute path.
But if I have a random given URL string (e.g. http://www.mycompany.com/whatever.html), how do I programmatically find out the corresponding Resource of the given URL?

If the hostname/port from the URL is mapped to a content repository location CQ will attempt to resolve the URL supplied.
In a servlet the ResourceResolver can be obtained from the slingRequest:
ResourceResolver resourceResolver = slingRequest.getResourceResolver();
String resourcePath = new URI("http://www.mycompany.com/whatever.html").getPath();
Resource res = resourceResolver.resolve(resourcePath);
Bear in mind that for short urls and domains like the above to work you would need to configure mapping on your instance.
In a JSP, as long as you have called the <sling:defineObjects/> or <cq:defineObjects/> tag you will be able to use:
<sling:defineObjects>
<%
String resourcePath = new URI("http://www.mycompany.com/whatever.html").getPath();
Resource res = resourceResolver.resolve(resourcePath);
%>
Some more information is provided in "Getting Resources and Properties in Sling"
Test out on a couple of URLs you know are good. For example:
Resource res = resourceResolver.resolve("http://localhost:4502/content/geometrixx.html");
Resource res = resourceResolver.resolve("/content/geometrixx.html");
Both of the above should resolve to the same resource.
If you want to test whether CQ can resolve the URL you are providing, try the jcr resolver page in the system console
http://localhost:4502/system/console/jcrresolver to see if the url is mapped if it does not contain the full /content/.. in the path. Any mapped should be able to be resolved.

ResourceResolver class was implemented to return Resource. Specifically, the resolve() functions exist for this type of resolution. However, even there are three overloaded resolve() functions, none of them takes in a URL String.
Given ResourceResolver takes in HttpServletRequest as input, if I can transform (adapt) a given URL into a HttpServletRequest using HttpServletRequestWrapper, the problem will be solved. Therefore, the solution is to implement a ResolverRequest class which extends HttpServletRequestWrapper.
For the complete solution and code sample please see "Programmatically find the Sling Resource from a Given a URL"

Related

Is "/literal/{param}/literal" a valid url template for a WCF restful service

I am trying to add a new endpoint to a WCF based REST service with the following URL template:
/books/{bookId}/pdf
but it gives an error saying:
The UriTemplate '/books/*/pdf' is not valid; the wildcard ('*') cannot appear in a variable name or literal, unless as a construct for a wildcard segment. Note that a wildcard segment, either a literal or a variable, is valid only as the last path segment in the template; the wildcard can appear only once. See the documentation for UriTemplate for more details.'
Here's the service contract:
[OperationContract]
[WebInvoke(UriTemplate = "/books/{bookId}/pdf", Method = "POST")]
Message GetBookPDF(string bookId);
Is this a limitation that the variable is only valid as the last part of the url? I couldn't find any link that confirms that.
I am sure that the variable needn’t configured in the last part of the URL.
My service contract
public interface ITestService
{
[OperationContract]
[WebInvoke(Method ="POST",UriTemplate ="/books/{id}/pdf")]
string Test(string id);
}
Result.
Please have a look at this link.
https://stackoverflow.com/questions/13956889/in-wcf-can-i-have-a-wildcard-character-in-a-literal-segment-of-my-uritemplate
The most likely scenario is that the UriTemplate can match multiple OperationContract, thus the error happened.
Feel free to let me know if the problem still exists.

How to access suffixes using HTL/Sightly?

TLDR: Create a new AEM page called "mypage.html". Supply suffixes in the URL. Pass this suffixes to an Sling servlet. The suffixes act as URL parameters.
sample desired URL: http://localhost:4502/mypage.html/john/smith
So I created a servlet (used this guide: http://www.aemcq5tutorials.com/tutorials/sling-servlet-in-aem/) that can read a suffix.
#SuppressWarnings("serial")
#SlingServlet(paths="geometrixx/components/hompepage", selectors="name", extensions="html",methods="GET", metatype=true)
public class StaffProfileServlet extends SlingAllMethodsServlet {
private static final Logger log = LoggerFactory.getLogger(CourseBookmarkServlet.class);
#Override
protected void doGet(final SlingHttpServletRequest request,
final SlingHttpServletResponse response) throws ServletException, IOException {
RequestPathInfo rpi = request.getRequestPathInfo();
String[] suffixes = rpi.getSuffix().split("/");
and it working fine if I access it via http://localhost:4502/content/geometrixx/en.name.html/first/last
What I want to do next is create a new page called "mypage.html" and supply first and last as suffixes.
mypage will display information relevant to the person in a properly formatted page. With code above, all I get is JSON response.
Some assumptions/changes which I think is needed to achieve my goal:
I will be using paths and using request parameters (i.e. using request.getParameter("myparameter") on servlet code
I will be using AJAX to access the servlet
If my assumptions are correct, how do I access suffixes from HTL/Sightly? I understand I can get the URI via ${request.requestURI} or even Javascript. And using this value, I can then use this in my AJAX call.
But is this the AEM/Sling way of doing it? Or perhaps there is a better way to do what I want?
Thanks a lot!
You can use RequestPathInfo interface from HTL to access suffix's. ${request.requestPathInfo.suffix}
Global objects accessible through HTL -> here.
Methods accessible through request object -> here.

What is the restTemplate.exchange() method for?

Actually what does the restTemplate.exchange() method do?
#RequestMapping(value = "/getphoto", method = RequestMethod.GET)
public void getPhoto(#RequestParam("id") Long id, HttpServletResponse response) {
logger.debug("Retrieve photo with id: " + id);
// Prepare acceptable media type
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.IMAGE_JPEG);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
HttpEntity<String> entity = new HttpEntity<String>(headers);
// Send the request as GET
ResponseEntity<byte[]> result =
restTemplate.exchange("http://localhost:7070/spring-rest-provider/krams/person/{id}",
HttpMethod.GET, entity, byte[].class, id);
// Display the image
Writer.write(response, result.getBody());
}
The method documentation is pretty straightforward:
Execute the HTTP method to the given URI template, writing the given request entity to the request, and returns the response as ResponseEntity.
URI Template variables are expanded using the given URI variables, if any.
Consider the following code extracted from your own question:
ResponseEntity<byte[]> result =
restTemplate.exchange("http://localhost:7070/spring-rest-provider/krams/person/{id}",
HttpMethod.GET, entity, byte[].class, id);
We have the following:
A GET request will be performed to the given URL sending the HTTP headers that are wrapped in the HttpEntity instance.
The given URL contains a template variable ({id}). It will be replaced with the value given in the last method parameter (id).
The response entity will be returned​ as a byte[] wrapped into a ResponseEntity instance.
TL;DR: Q: What is a request-response pair called? A: An "exchange".
The term exchange is used, almost incidentally, in the official technical documentation of HTTP to refer to an HTTP request combined with the corresponding response.
However looking at the answers to the following questions, it is clear that while this may have represented a de facto standard for some people, many other were not aware of it, or hadn't adopted it.
What is a request-response pair called?
Name for HTTP Request+Response
The documentation doesn't bother to mention the etymology of the name -- probably assuming that it's obvious.
Notice, however, that there are many different RestTemplate HTTP request methods listed and only a small fraction of them are named exchange. The list is primarily made up of HTTP method-specific names such as delete, put, getForEntity, postForObject, et cetera. Technically speaking, all of these methods perform exchanges in the same sense, but the more focused convenience methods are limited to a specific subset of the possible exchange functionality and parameter+return types.
To put it simply, the set of exchange functions are the most general/capable methods provided by RestTemplate, so you can use exchange when none of the other methods provides a complete enough parameter set to meet your needs.
For example:
Sending GET request with Authentication headers using restTemplate, in which the OP has noticed that "...the only way to send Headers such as accept and Authorization is by using the exchange method..."
The more generic exchange API requires a HttpMethod parameter and a request object for completeness. Compare:
ResponseEntity<Foo> response =
restTemplate.exchange(url, HttpMethod.GET, request, Foo.class);
ResponseEntity<Foo> response =
restTemplate.getForEntity(url, Foo.class);
The exchange method executes the HTTP method against the specified URI template, passing in the parameters for replacement. In this case it gets an image for a person entity for its Id parameter and returns the byte array for it.

What is a REST response, what does it do?

I had made a REST webservice using redirecting to various paths like if i need to delete some user then i will redirect the user to this address in the #Path annotation :
user/delete
and therefore there is no thing like RESPONSE i have used.
While going through a code given to me by my senior i came accross these lines :
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
Response.created(uri).build();
What are these lines doing, i have no idea.
Can someone explain me this w/o wiki links or any other 'Basic Rest Service' links.
Without any explicit details about the uriInfo object I can only speculate its type is the JAX-RS UriInfo class.
The first line can be broken down as below:
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
The getAbsolutePathBuilder is documented http://jackson.codehaus.org/javadoc/jax-rs/1.0/javax/ws/rs/core/UriInfo.html#getAbsolutePathBuilder%28%29
java.net.URI uri = uriInfo.getAbsolutePathBuilder().path(id).build();
The method returns a UriBuilder object. On which the 'path(...)' method is called passing the id so if the absolute path returned http://www.host.com (this may or may not have a port number) adding the id in this method will then result in the effectively Builder holding the two parts. The base URI and the path. The two values have not yet been put together
The build method then concatenates the two values resulting a full URI. For example http://www.google.com/id (Where http://www.google.com is the absolute path)
The second line
Response.created(uri).build();
Is basically saying 'Respond with a created (201) response code, and set a Location header containing the build uri value'

Url as path parameter in restful api causes bad request

We are developing a restful api using jersey (1.9.1) and tomcat 5.5.
A given resource is identified with a urn and we would like to address a specific instance of that resource. In order to achieve this, we used the following code:
#Path("/XXXs")
public interface XXXResource {
#GET
#Path("{id}")
#Produces({ MediaType.APPLICATION_JSON })
XXXInfo getXXX(#PathParam("id") String id);
}
The idea is to address this resource using the following url:
http://localhost:8080/restapi/XXXs/http%3A%2F%2Fns.something.com%2FXXX%2F2
The decoded path param value should be:
http://ns.something.com/XXX/2
However, when I make the request using the encoded url I get a bad request message from tomcat. So my questions are:
Is it correct to use a Urn as a path parameter?
Why is tomcat considering this request as a bad request?
Just in case, I changed the signature of the method so that the parameter is taken from the query string and it worked fine, but I want the parameter to be part of the path.
Thanks.
Ok, I solved it by adding the following line in catalina.properties:
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true