Sling servlet invalid recursion selector with json extension - aem

I am registering a Sling Servlet using
#Component(service=Servlet.class,
property={
Constants.SERVICE_DESCRIPTION + "=Simple Demo Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_GET,
"sling.servlet.resourceTypes="+ "myapp/components/structure/page",
"sling.servlet.extensions=" + "json",
"sling.servlet.selectors=" + "myselector"
})
But when calling URL <host:port>/content/myapp/en.myselector.js I get error
Invalid recursion selector value 'myselector'
Cannot serve request to /content/myapp/en.myselector.json in
org.apache.sling.servlets.get.DefaultGetServlet
If we remove "sling.servlet.extensions=" + "json", from annotation, we are able to hit the servlet using <host:port>/content/myapp/en.myselector.js or <host:port>/content/myapp/en.myselector.html but not <host:port>/content/myapp/en.myselector.json
Any additional configurations required? or its conflicting with DefaultGetServlet? We were trying to expose JSON out of resource using servlet and JSON extension semantically making sense.

Since you've registered the servlet against the resource instead of a path, the resource is actually the jcr:content node of the page, rather than the page node itself.
Hence, the servlet should work when accessed with the jcr:content in the URL as shown below
<host:port>/content/myapp/en/_jcr_content.myselector.json

Related

AEM Page manager return null for mapped page with Sling Mapping

I am using Sling Mapping (configurations are located under /etc/map) for mapping the resources , e.g. /content/path/en should get page /content/path_real/en.
When I try to get resource via resourceResolver.getResource("/content/path/en") it works correctly and return the resource under path /content/path_real/en.
But when I try to get page via pageManger.getPage(""/content/path/en") it returns null.
Is there any way to configure pageManager so they also use sling mapping configuration from /etc/map folder?

AEM resource resolver failing

I am working on the AEM resource resolver and I currently have the following configuration on the Adobe Sling Resource Resolver Factory.
/content/mywebsite/>/
I have this a tag being generated from a component that looks something like:
<a data-desktop='/content/mywebsite/desktop.html'
data-android-href='/content/mywebsite/android.html'
data-ios-href='/content/mywebsite/mywebsite/ios.html'
href='/content/mywebsite/normal.html'>Click here</a>
This should have ideally been resolved to something likeL
<a data-desktop='/desktop.html'
data-adroid-href='/android.html'
data-ios-href='ios.html'
href='/normal.html'>Click here</a>
The irony is the last href in the above a tag is also not resolved by the resource resolver and I'm still getting the unresolved URL on dispatcher.
All the other resource resolver for a tags with just <a href='/content/mywebsite/something.html></a>' gets resolved. I don't understand why the resource resolver does not pick up the one with multiple data elements.
Are you sure it depends on the number of attributes? It looks like your configuration only affects resource resolution and not the outgoing mapping. The rule will be applied for incoming requests so when the user hits your AEM instance with /something.html, the Resource Resolver will look for the resource at /content/mywebsite.something, as well as other paths mapped to the root (if any) but as far as I understand, it will not affect the way AEM renders links to that content.
Try changing your rule so that it uses a two way mapping: /content/mywebsite/:/
To quote the description of the URL Mappings field in the Apache Sling Resource Resolver Factory configuration in the OSGi console:
List of mappings to apply to paths. Incoming mappings are applied to request paths to map to resource paths, outgoing mappings are applied to map resource paths to paths used on subsequent requests. Form is <internalPathPrefix><op><externalPathPrefix> where <op> is ">" for incoming mappings, "<" for outgoing mappings and ":" for mappings applied in both directions. Mappings are applied in configuration order by comparing and replacing URL prefixes. Note: The use of "-" as the <op> value indicating a mapping in both directions is deprecated. (resource.resolver.mapping)
You can easily test the configurations you setin the Apache Sling Resource Resolver Factory using the Configuration Test field on the Resource Resolver page in the OSGi console. You'll find it at http://<host>:<port>/system/console/jcrresolver
Use the Resolve and Map buttons to se.e how the path is transformed both ways.
Also, if you're getting inconsistent behaviour between components, check if they both map the URLs using resourceResolver#map if not covered by the Externalizer already.

Send message to a client when an HTTP method not supported

I've created a REST controller the can handle, as usual, GET, POST, PUT and DELETE HTTP requests using Spring MVC. The web server is Tomcat 8.
If a send request, for instance, with HEAD method, the response is an error page from Tomcat with message
HTTP Status 501 - Method LINK is not is not implemented by this servlet for this URI
I have such exception handler:
#ResponseBody
#ExceptionHandler(Throwable.class)
public ResponseEntity<?> exceptionHandler() {
Error error = createError("error_message.unforeseen_error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
But it doesn't catch any error in this case.
Is there a way to send back a message wrapped in JSON object as a response instead of this Tomcat page?
The problem is that SpringMVC does not find any method for HEAD in your controller, so it does not use it and your #ExceptionHandler is not used. It would be used for exception arising inside the controller. Extract from Spring Frameword Reference : You use the #ExceptionHandler method annotation within a controller to specify which method is invoked when an exception of a specific type is thrown during the execution of controller methods (emphasis mine).
To process exception outside of any controller, you must register a HandlerExceptionResolver bean that will replace the DefaultHandlerExceptionResolver provided by default by Spring MVC. You could either directly put the Json String in the response and return null from resolve method (my prefered way), or put the elements in a model and use a view to format the Json.

Can I add multiple servlets to a WebAppContext?

I have the following Scala code to setup a Jetty server with Scalatra.
val server = new Server(8080)
val context = new WebAppContext()
context.setResourceBase("visualization")
context.addServlet(new ServletHolder(new CallTreeServlet(dataProvider)), "/*")
context.addServlet(new ServletHolder(new DataLoadingServlet(dataProvider)), "/*")
server.setHandler(context)
My problem is that it seems to work only if I register a single servlet.
If I register more than one, like I do in the code I posted, it loads only one of them.
Is it possible to load multiple servlets? I guess it is, but I can't figure out how.
If I try to load a page from the first servlet I got this error message that references only pages belonging to the second servlet:
Requesting "GET /callTrees" on servlet "" but only have:
GET /components
POST /load
POST /searchCallTrees
POST /selectPlugIn
To troubleshoot this, you should verify the servlet lifecycle. One convenient way to do this is to peruse the servlet container's logs to see what it reports while starting up the web application. It should tell you about each web app ( servlet context ) and each servlet . . .
However, I think I see what your problem is. Your servlet path mappings are kind of funky. It looks to me that you are mapping both servlets to receive ALL requests. This can't work, from a practical point of view, and might not work in terms of the servlet rules. From the servlet specification:
SRV.11.2
Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define
mappings:
• A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used
for path mapping.
• A string beginning with a ‘*.’ prefix is used as an extension mapping.
• A string containing only the ’/’ character indicates the "default" servlet of
the application. In this case the servlet path is the request URI minus the con-
text path and the path info is null.
• All other strings are used for exact matches only.
I suggest you make them both unique. As it looks now, you have them both at "/*" which is kind of like the "default servlet", but not . . .
Why not try "/first/" and "/second/" as a sanity check. Then move from there toward getting the configuration how you like.

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