Apache Sling Resource Resolver - java

What exactly is the ResourceResolver? More important, how do you use it? I'm struggling to find a simple example. So, say I have a path and want to use the resource resolver to see if the path resolves to a resource. How would I do that? I know this is wrong but if someone can correct this it would help.
Iterator<String> nodeSample = getResource("title");
return nodeSample

The RequestResolver, to quote the javadoc, defines the service API which may be used to resolve Resource objects.
You typically access it in a SlingServlet by calling request.getResourceResolver() or in a script ( JSP script for instance ) under the resourceResolver variable. For more details on variables on scripts see Scripting variables in the Sling wiki.
One you get a hold of it you can use it to access resources in the content tree:
Resource resource = requestResolver.getResource("/content/my/resource");
if ( resource != null ) // bingo!
To display a resource's properties I usually adapt it to a ValueMap and then extract the properties
ValueMap properties = resource.adaptTo(ValueMap.class);
String title = properties.get("jcr:title", String.class);

Related

Tomcat 7 get resource using new URL and "classpath" string , ClassLoader.getSystemClassLoader().getResource return null

I try to get file resource in tomcat 7 using this code :
confFileUrl = new URL("classpath:/conf/plugins/my_app_conf.txt");
final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
URLConnection urlc = resourceUrl.openConnection();
The WEB-INF looks like this :
WEB-INF/classes/conf/plugins/my_app_conf.txt
i need to load it and verify it exist and pass it as URL object to Thired party app ( Accepes only URL object )
But the problem is that :
ClassLoader.getSystemClassLoader().getResource(confFileUrl.getPath());
result allways null
Any idea why ?
Note: You're mixing file names in your question: gappFileUrl vs confFileUrl.
As you specifically check SystemClassLoader, you won't get your webapp's classloader, thus there's nothing to find.
Use this.getClass().getResourceAsStream(name) to utilize the webapp's classloader (or, to be more precise, the classloader that has loaded the current class. Hopefully it's also from within WEB-INF/lib or WEB-INF/classes. If it isn't, pick a class that can be found there.
Also note that a web application is not necessarily "exploded" (unzipped) into the file system, but can legitimately be served from a WAR file. Thus, you'll need to use stream-operations, and can't expect any file-based operations to work consistently.
Edit (after your comment): I've never used the classpath: component int the URL. From https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html (emphasis mine):
The method getResource() returns a URL for the resource. The URL (and its representation) is specific to the implementation and the JVM (that is, the URL obtained in one runtime instance may not work in another). Its protocol is usually specific to the ClassLoader loading the resource. If the resource does not exist or is not visible due to security considerations, the methods return null.
If the client code wants to read the contents of the resource as an InputStream, it can apply the openStream() method on the URL. This is common enough to justify adding getResourceAsStream() to Class and ClassLoader. getResourceAsStream() the same as calling getResource().openStream(), except that getResourceAsStream() catches IO exceptions returns a null InputStream.
...
The getResource and getResourceAsStream methods find a resource with a given name. They return null if they do not find a resource with the specified name. The rules for searching for resources associated with a given class are implemented by the class's ClassLoader. The Class methods delegate to ClassLoader methods, after applying a naming convention: if the resource name starts with "/", it is used as is. Otherwise, the name of the package is prepended, after converting all periods (.) to slashes (/).
Based on that: Try loading a resource named "/conf/plugins/my_app_conf.txt". And you don't need to go through the URL construction, but you can pass that name right to getResourceAsStream, e.g. ...getResourceAsStream("/conf/plugins/my_app_conf.txt");

Set current compilation time in a java class or jsf page

I have a WAR archive compiled with maven.
I want to insert the compilation timestamp in a jsf page.
How can I change a string in a jsf page at compilation time ?
Example
<div>Compiled at (copilationTime)</div>
Must became
<div>Compiled at 2017-01-01 15:50</div>
If it is too complicate, I have an applicationscooped bean and i wrote
<div>Compiled at ${MyApp.compilationTime}</div>
But in my class how can i set 'xxxx'?
public class MyApp{
String compilationTime = 'xxxx';
public String getCompilationTime(){
return compilationTime;
}
}
I think you're talking about a variation of resource filtering via maven-resources-plugin. The idea is this:
You ask Maven to filter a certain resource (either a src/main/resources resource, or a variation of it, via maven-resources-plugin, a src/main/webapp resource via maven-war-plugin) in which you have placed the Maven pre-defined variable ${maven.build.timestamp}
You make sure that the filtered resource is included in your project
You read that resource either via Class.getResourceAsStream (or a variation of it), or via servlet mechanisms (depending where you place it).
You use the value in your JSF.
Please note that you can ask Maven to replace a filter a variable directly in your JSF and cut some steps.
From this answer you can get a reference to a file:
final File classFile = new File(MyApp.class.getProtectionDomain().getCodeSource().getLocation().getPath());
and then from here you get the property:
BasicFileAttributes attr = Files.readAttributes(classFile, BasicFileAttributes.class);
String compilationTime = attr.creationTime().toString();
You can use #CompileTime from Kolobok and create a field
#CompileTime
private static long ct; // This field will contain compilation time in ms

Loading templates in Freemarker templates without setting Directory or Class for template loading

Is there any way of loading the Freemarker templates directly without having need to first load the Directory from which templates will be loaded or setting the Class relative to which templates will be loaded.
i.e Is there any way so that i can load a template like
Template template = getTemplate("PathToTemplate/myTemplate.ftl");
I need this, because user specifies the complete path to ftl files. So,first i have to separate directory name and file name, then i am doing
Configuration cfg = new Configuration();
int indexOfLast = templatePath.lastIndexOf("\\");
String dir = templatePath;
String fileName="";
if(indexOfLast>=0){
dir = templatePath.substring(0,indexOfLast);
fileName= templatePath.substring(indexOfLast+1,templatePath.length());
}
cfg.setDirectoryForTemplateLoading(new File(dir));
Template template = cfg.getTemplate(fileName);
I do not want to do all this.
Templates can be created by directly calling a Template constructor, to which you pass a String or Reader as argument. Then of course you get that Reader or String from wherever you want. This approach has two disadvantages though:
Other templates won't be able to #import or #include those templates, as FreeMarker doesn't know how to load them (only you do)
Caching those templates (if that's needed anyway) is up to you
If the above two is a problem for you, then see Seelenvirtuose's answer: create a TemplateLoader that interprets the template names as full paths.
As of your example code, know that the Configuration instance will clear its template cache every time you replace the TemplateLoader. Also note that it's not thread-safe to do.
The getTemplate method is heavily overloaded. As per the documentation the method getTemplate(String, Locale, String, boolean) will eventually be called regardless which getTemplate method you called.
This method's documentation expresses the following:
The exact syntax of the name is interpreted by the underlying TemplateLoader, but the cache makes some assumptions. First, the name is expected to be a hierarchical path, with path components separated by a slash character (not with backslash!). The path (the name) given here must not begin with slash; it's always interpreted relative to the "template root directory".
There are two notable things:
The name parameter is already handling a hierarchical path, but must not begin with a slash. So maybe you could set the configuration's directory once to the root of your disk and then simply provide the full path (but without the leading slash).
The documentation explains something about a TemplateLoader. So you can simply write an implementation of that interface for loading the template. In that implementation you have full hands on the provided name.

CQ5 - Sling accessing nodes

I'm a complete newb to this so I apologize in advance. I've got an instance of CQ5 set up
and I can't figure out how to access specific nodes. So say I have a component with the
path:
/project/components/content/leftsidebar
but I want to access properties of another node here:
/content/dam/campaign
I know the properties.get method works but only if your within that node
properties.get("title", "placeholder");
I'm a complete newb so please post code samples were possible.
Thanks!
You'd want to use the ResourceResolver in order to get the resource that you're looking for. From there, you can adapt it to a ValueMap & read its properties:
ResourceResolver resourceResolver = slingRequest.getResourceResolver();
Resource campaignResource = resourceResolver.getResource("/content/dam/campaign");
ValueMap campaignProperties = campaignResource.adaptTo(ValueMap.class);
String title = campaignProperties.get("title", "placeholder");
You can read more about accessing properties on the Apache Sling website. Remember, CQ5 is Sling under the hood, so it's a great resource & you're still a level of abstraction above accessing the JCR directly.

Java - Setting context attributes (ServletContextListener)

I read a properties-file at the webapplication startup phase (contextInitialized()) and I started to think about how to make these settings 'visible' to the servlets. Do I need to loop through the keys and add each and every one to the context, like this
Iterator i = settings.keySet().iterator();
while (i.hasNext()) {
key = (String) i.next();
value = (String) settings.get(key);
context.setAttribute(key, value);
}
or are there better methods?
Thank you!
/Adam
why not store the entire contents in your servlet context?
context.setAttribute("mySettings", settings);
setAttribute's signature is:
public void setAttribute(String name, Object object)
Have you considered the possibility of defining the settings in web.xml?
Also, if that's not possible, use generics if possible:
String key = null;
Iterator<String> i = settings.keySet().iterator();
while (i.hasNext())
context.setAttribute(key = i.next(), settings.get(key));
I've been toying with an idea:
In the context initialized method, I've planned to create just one global object for the settings. Much like toolkit proposed. But instead of setting context attributes for each key/attribute/setting, would it be a terrible idea to add a settings container/wrapper object? I'm thinking this class would be responsible for holding (static?) classes of module settings. This way I can get typed references like so
//ExampleServlet.java
Settings settings = (Settings)context.getAttribute("application.settings");
String color = settings.getModule1().getColor();
String font = settings.getModule1().getFont();
int blogs = settings.getModule2().getActiveBlogCount();
Throughout the code I'll have to remember only one attribute key, the one for the entire settings container. Less risk of typos which could cause rumtime exceptions!
It will also make it easy to rename attributes.
What do you think?
/Adam
What about using the JNDI context. JNDI is a more common way to pass properties to a webapp.
Any Properties may be specified in the META-INF/context.xml for tomcat or any application specific setup.
It's something that I have contemplated, setting the entire properties object as a context attribute.
If I do not go this route, are there any guidelines for how to name these attributes or do you feel that "application.settings" or "myBlog.settings"? How do you group keys? Would this be okay:
application.module1.color=black
application.module1.font=arial
I feel, in a way, that it could become a burden to maintain such an application where the property keys are spread throughout the code? Should another developer rename a property in the properties file, we'll know only when running the application (if/when/what referenced the old key). Right?
I'll have to lookup JNDI.

Categories

Resources