I've been doing some experimenting using tag libraries. I started out following a classic approach by implementing my tag library as a Java class. Everything works fine but understanding how everything fits together is somewhat complicated. I decided to give tag *files* a try, mainly because one of the reasons why some people appear to prefer them is that they are simpler to implement and understand (i.e. they are just a special type of JSP).
I am actually using JSP Documents (JSPX) and as a consequence tagx files, but thats mostly incidental.
Again I have everything working BUT, my tag file (and library) make a call to an OSGi service and to get a reference to the service instance I am using :-
sling.getService(myservice_interface.class)
I don't appear to be able to resolve a reference to sling in my tag file at least not by simply including a taglib directive in my file (or rather the tagx equivalent XML namespace declaration :-
<jsp:root xmlns="http://www.w3.org/1999/xhtml" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:sling="http://sling.apache.org/taglibs/sling/1.0" version="2.1">
If I subsequently try and use sling.getService(...) I just get a 'cannot resolve sling' exception.
I also tried using various import directives, but couldn't find one that had any [positive] effect. E.g. :-
<jsp:directive.tag import="org.apache.sling.xxx"/>
I *have* been able to get it to work by PASSING a reference to sling as an attribute FROM the calling JSP :-
JSP
<h1><aviva-aem:helloWorld name="AEM User" sling="${sling}"/></h1>
mytagfile.tagx
<jsp:directive.attribute name="sling" rtexprvalue="true" required="true" type="org.apache.sling.api.scripting.SlingScriptHelper"/>
The call to sling.getService(...) now operately successfully, ... but it seems a bit klunky ... is there a neater approach ??
Thanks
Fraser.
Solved! Go to Solution.
Views
Replies
Total Likes
I've made a bit more progress on this, so I'm posting where I am for anyone else who is interested.
As Justin said using <sling:defineObjects/> is important. I had tried it previously and still saw the 'cannot resolve sling' exception in the log, BUT as it turns out this was NOT caused by adding that element but my subsequent use of the sling prefix in a function. The line numbers in exception stack trace were just a bit misleading and the code snippet it showed started with <sling:defineObjects/> so naturally I put 2 and 2 together and can up with 5 !
Here's what my current slingTest.tagx file looks like (I know its a bit naff, but it's just a test to understand behaviour) :-
<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns="http://www.w3.org/1999/xhtml" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:sling="http://sling.apache.org/taglibs/sling/1.0" xmlns:c="http://java.sun.com/jsp/jstl/core" version="2.1"> <jsp:directive.tag trimDirectiveWhitespaces="true"/> <jsp:directive.tag import="com.aviva.aem.archetypetest.jspcompile.jspcompile.services.api.IGoodbyeWorldService"/> <jsp:directive.tag import="org.apache.sling.api.scripting.SlingScriptHelper"/> <jsp:directive.attribute name="name" rtexprvalue="true" required="true" type="java.lang.String"/> <sling:defineObjects /> <jsp:declaration> private String getServiceMessage(String username, SlingScriptHelper sling) throws JspException { IGoodbyeWorldService gws = sling.getService(com.aviva.aem.archetypetest.jspcompile.jspcompile.services.api.IGoodbyeWorldService.class); String message = gws.getMessage(username); return message; } </jsp:declaration> <jsp:scriptlet> out.println("Message from service (called from slingTest.tagx): " + getServiceMessage(name, sling)); </jsp:scriptlet> </jsp:root>
There's a few things to note :-
So the culprit for the exception was the sling.getService(...) call inside the function. The key was to pass it as an argument and getting access to the sling reference required <sling:defineObjects/>
There's still room for improvement, but at least this is a step forward from passing sling in as an attribute from the calling JSP.
Fraser.
Views
Replies
Total Likes
Hi Fraser,
It looks like you need to add <sling:defineObjects/> or <cq:defineObjects/> in your tag file.
Justin
Views
Replies
Total Likes
Hey Justin,
I'm pretty sure I did include a <sling:defineObjects/> at some point in the tag file and got the same 'cannot resolve sling' exception and the exception trace pointed directly to that line. I'll give I another try tomorrow to be sure and report back.
Thanks for your suggestion
Fraser
Views
Replies
Total Likes
I've made a bit more progress on this, so I'm posting where I am for anyone else who is interested.
As Justin said using <sling:defineObjects/> is important. I had tried it previously and still saw the 'cannot resolve sling' exception in the log, BUT as it turns out this was NOT caused by adding that element but my subsequent use of the sling prefix in a function. The line numbers in exception stack trace were just a bit misleading and the code snippet it showed started with <sling:defineObjects/> so naturally I put 2 and 2 together and can up with 5 !
Here's what my current slingTest.tagx file looks like (I know its a bit naff, but it's just a test to understand behaviour) :-
<?xml version="1.0" encoding="UTF-8"?> <jsp:root xmlns="http://www.w3.org/1999/xhtml" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:sling="http://sling.apache.org/taglibs/sling/1.0" xmlns:c="http://java.sun.com/jsp/jstl/core" version="2.1"> <jsp:directive.tag trimDirectiveWhitespaces="true"/> <jsp:directive.tag import="com.aviva.aem.archetypetest.jspcompile.jspcompile.services.api.IGoodbyeWorldService"/> <jsp:directive.tag import="org.apache.sling.api.scripting.SlingScriptHelper"/> <jsp:directive.attribute name="name" rtexprvalue="true" required="true" type="java.lang.String"/> <sling:defineObjects /> <jsp:declaration> private String getServiceMessage(String username, SlingScriptHelper sling) throws JspException { IGoodbyeWorldService gws = sling.getService(com.aviva.aem.archetypetest.jspcompile.jspcompile.services.api.IGoodbyeWorldService.class); String message = gws.getMessage(username); return message; } </jsp:declaration> <jsp:scriptlet> out.println("Message from service (called from slingTest.tagx): " + getServiceMessage(name, sling)); </jsp:scriptlet> </jsp:root>
There's a few things to note :-
So the culprit for the exception was the sling.getService(...) call inside the function. The key was to pass it as an argument and getting access to the sling reference required <sling:defineObjects/>
There's still room for improvement, but at least this is a step forward from passing sling in as an attribute from the calling JSP.
Fraser.
Views
Replies
Total Likes
Are you following online AEM documentation or KB that needs to be updated? If so -- can you please post the URL of the Adobe online content that you are following here.
Views
Replies
Total Likes
smacdonald2008 wrote...
Are you following online AEM documentation or KB that needs to be updated? If so -- can you please post the URL of the Adobe online content that you are following here.
Hey Scott,
no I'm not following any existing AEM article though it would be useful if there were some that covered custom tag handler (including tag file) development practice. This one also touches on JSP[x], JSTL and the numerous OOTB tag libraries (JSP core, CQ, Sling, et al), and a few others (like Headwire's Squeakysand). There are also important aspect that relate to the development environment and tooling (e.g. various Maven plugins that play in this space).
I am partly responsible for creating our internal software engineering best practice (in this case for AEM), and this is one of the topics in what is becoming a large body of work !
Thanks for your interest
Fraser
Views
Replies
Total Likes
Views
Likes
Replies
Views
Likes
Replies