In my post Tagfile vs. Tag in a Sling or CQ5 Application we created the groundwork for developing Servlet artifacts: Tag files, Classic Tags, and EL Functions. The definition of all these items require the file taglib.tld. This defines the URL that identifies the library via the uri in a <%@taglib prefix=".." uri=".." %> JSP statement within a JSP. Here we address creating EL functions and managing them.
Additionally, I will provide some of my thoughts on a reply from Avi in my previous post related to storage of the tagfiles themselves.
I use EL functions frequently for: property fetching, I18n translation, various kinds of String translation, handling/creating XSS encoded Strings, dealing with CQ tags, etc. An important paradigm to adhere to is that execution of these functions should not change JCR state. They can however create scoped variables, but they should not be modifying the JCR.
If you rely on these even a little, I suspect you will find yourself with dozens of these, and then the concern becomes management. What I have done is use a Singleton class, and in some cases function as a Facade. This makes management of the EL function definitions within taglib.tld much easier.
Here is a sample function definition:
<function-signature>java.lang.String getPageTitle(com.day.cq.wcm.api.Page, java.lang.Boolean)</function-signature>
and all other defined EL functions would point to the class com.mjk.cq5.foundation.ElFunctions as well. The implementation of this is just a static method in a static class.
While this is not exactly earth shattering, it has simplified to some extent the management of these functions. I have approximately two dozen. Imagine if every single function were managed from a different class. (Insert headache here - - ) With this appraoch, at least the definitions are located in one place, and easy to find. Additionally, I ensure that the order they are defined within the TLD file is the same order they are defined within the class, but thats just a detail.
If the actual functionality for some of these functions resides elsewhere, simply defer the work to that class from the EL Functions class, making the class a Facade. I would be careful from deferring too many functions elsewhere, defeating the purpose of the pattern. Although, if you want to wrap some of the CQ classes in an EL function, you don't have a choice.
Some of the normal self imposed software development rules I operate by are suspended for this one case. The EL function class is not your normal class. Make sure you define a private no args constructor to ensure an instance of the class is never instantiated, These are all static methods, and this class should never have state, static or instance.
This approach will prevent easter egg hunts for the functions that define the EL functions, and simplify some of the plumbing construction by collocating all the methods.
In regards to Avi's reply (thanks Avi for the info!), I am conflicted, sort of. The way I manage CQ applications is that I have a corporate "foundation" application that contains generic, extensible functionality. It will contain some usable generic components (an instance of a text component with some or all of the tools), and some "base" components meant to be extended: such as a refactored search component. It will contain the templates, components, and install folder containing all the needed OSGi bundles.
Knowing that tagfiles can be stored within the component and template application structure would potentially not work well. If the reuse of the of simply the "foundation" OSGi bundle is wanted, it makes more sense to store the tagfiles within the bundle. If reuse will be accomplished by installing the entire "foundation" application, storage of the tagfiles in the application structure (/apps/yourcofoundation) would work just fine. No hard and fast rules. Simply spend a bit of time to determine how you may use and reuse the tagfiles.
In general, I believe it will be easier (and logical) to create and manage the tagfiles from the application structure rather than within an OSGi bundle.
Go forth, develop, and...