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.
Related
I am working in magnolia and the backend is in java. I need to check whether a node is present in the component that I do with these steps
if (!MgnlContext.getJCRSession("repository").nodeExists(path)) {
MgnlContext.getJCRSession ("repository").getRootNode().addNode("nodeName", "mgnl:content");
}
now I need to put a bean (java object bean) inside this node. for eg: as it should come as a content node under it.
Can anyone suggest any methods to do it better?
To map any java been to content in repository, your best option in Magnolia is to use the Node2Bean. It allows you to map the content of your java bean/pojo to JCR Node and back. More details in documentation.
Fixed by denoting a #Field(path = true) in the bean and set that variable in the node path which is created using created. – MgnlContext.getJCRSession ("repository").getRootNode().addNode("nodeName", "mgnl:content"). so by doing this when i persisted the bean it went inside the node which i created .
In order to manage nodes/properties in Magnolia you can also use these utils:
info.magnolia.jcr.util.NodeUtil
info.magnolia.jcr.util.SessionUtil
info.magnolia.jcr.util.PropertyUtil
I am working on a Spring-MVC application, in which I have to save a String value which would be required in many other places but from within the java code. I checked out some solutions on net, but I only found how to declare it, not access it.
I require something like this :
<bean id="commontoAllProperty" value="String_value"/>
And access above from java code something similar to this :
class someClass {
private String getValueInBeanWithId(commontoAllProperty);
}
A very vague description but I am going nuts typing that String all the time. Its a FileSystem path by the way. Any help would be nice. Thanks a lot. :-)
You can store the value in your properties file and access it all throughout your Spring using the #Value annotation. You have an example in this blog post, note the
#Value("${msg}")
private String msg;
Is there any baked-in way, or established Tapestry pattern, to decouple the name of a page Class from the URL which renders it?
My specific problem is that I have a page class in an English codebase but I want the URLs to be in another language.
For example, the Hello.java page should be accessible from www.example.com/hola rather than the standard www.example.com/hello - though it's fine if both of these URLs work.
Ideally I want something like an annotation to configure a different URL name in-place for each individual page class.
Off the top of my head I could solve this myself with a map of URLs to page class names and a custom RequestFilter to do the mapping on each request - but I don't want to reinvent the wheel if there's a baked-in way to do this or a better pattern that anyone can suggest?
Tynamo's tapestry-routing could help you. It depends on how do you want to generate the links to www.example.com/hola and www.example.com/hello
The #At annotation only allows one route per page, but you can contribute all the routes you want via your AppModule, like this:
#Primary
#Contribute(RouteProvider.class)
public static void addRoutes(OrderedConfiguration<Route> configuration, ComponentClassResolver componentClassResolver) {
String pageName = componentClassResolver.resolvePageClassNameToPageName(Home.class.getName());
String canonicalized = componentClassResolver.canonicalizePageName(pageName);
configuration.add("home1", new Route("/home1", canonicalized));
configuration.add("home2", new Route("/home2", canonicalized));
configuration.add("home3", new Route("/home3", canonicalized));
configuration.add("home4", new Route("/home4", canonicalized));
configuration.add("hola", new Route("/hola", canonicalized)); // the last one is going to be use by default to create links to the page
}
The routes are ordered and by default the last one is going to be used to generate the links.
Currently there is no way to avoid using the default route to generate the links.
Tapestry has a LinkTransformer but I've always found the API lacking since you don't have access to the default behaviour. Igor has written a blog post about the LinkTransformer API here
I've always found it necessary to decorate the ComponentEventLinkEncoder so that I can access the default behaviour and tweak it. See ModeComponentEventLinkEncoder.java and AppModule.java for an example which tweaks the default behaviour and does some string manipulation on the URL.
Thiago has created a url rewriter api here but I've never used it myself. I'm pretty sure his solution is based on decorating the ComponentEventLinkEncoder for outbound URLs and a RequestFilter for inbound URLs.
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);
What is the best way to enable my webapplication to use JSF files stored in the database?
I'd like to be able to dynamically (during runtime) create new JSF pages which will be made available without having to redeploy the application.
So in other words: I would like to store the bigger part of my JSF pages in the database and would like JSF to use the database as a datasource for getting JSF files.
I've thought long about a solution and found some possible ways. However, I haven't been able to implement either of them.
Whenever a new page has to be added/removed: manipulate the files in the classpath (e.g. remove or add a file to the .war file)
Extending the classpath of the webapplication so it will be able to get files from an at runtime defined location (i.e. /tmp or directly using a database connection)
Provide JSF with a way to find resources another way ( this doesn't seem possible? )
My environment:
Java SE 6
Jetty as servlet container
Mojarra as jsf implementation
Now, my question:
Is it possible for someone to let JSF find pages at a location other than the default classpath, preferably the database?
Any response is greatly appreciated!
1: Whenever a new page has to be added/removed: manipulate the files in the classpath (e.g. remove or add a file to the .war file)
This is definitely possible if the WAR is expanded. I am not sure about Jetty, but it works for me with Mojarra 2.x on Tomcat 7 and Glassfish 3. Just writing the file to the expanded WAR folder the usual Java IO way suffices.
File file = new File(servletContext.getRealPath("/foo.xhtml"));
if (!file.exists()) {
OutputStream output = new FileOutputStream(file);
try {
output.write(bytes); // Can be bytes from DB.
} finally {
output.close();
}
}
This needs to be executed before the FacesServlet kicks in. A Filter is a perfect place. See also this related answer:
How to create dynamic JSF form fields
2: Extending the classpath of the webapplication so it will be able to get files from an at runtime defined location (i.e. /tmp or directly using a database connection)
You can package Facelets files in a JAR file and put it in the classpath and provide a Facelets ResourceResolver which serves the files from the JAR on when no match is found in WAR. You can find complete code examples in the following answers:
how to share a jsf error page between multiple wars
How to create a modular JSF 2.0 application?
3: Provide JSF with a way to find resources another way ( this doesn't seem possible? )
You've plenty of play room in the custom ResourceResolver.
Nice question. BalusC's answer is - as always - complete and right.
However, if your point is to create an application where gui is built dynamically, there is a way that might serve you better (depending on what you really want to achieve).
JSF views are similar to Swing forms - they are just a bunch of JavaBeans(tm) glued together. The big difference is that when a field is bound to an EL expression, you do not use standard accessors, but rather a special method (setValueExpression).
This means you can build your GUI from objects (the concrete classes can be found in javax.faces.component.html) in a pure programmatic way and then use binding attribute to show it on page. Something like:
<h:form>
<h:panelGrid binding="#{formBuilder.component}"/>
</h:form>
And then in the managed formBuilder bean:
#PostConstruct
public void init() {
HtmlInputText hit = new HtmlInputText();
// properties are easy:
hol.setStyle("border: 2px solid red");
// binding is a bit harder:
hit.setValueExpression("value", expression("#{test.counter}", String.class));
HtmlOutcomeTargetLink hol = new HtmlOutcomeTargetLink();
hol.setValue("link leading to another view");
hol.setOutcome("whatever");
component = new UIPanel();
component.getChildren().add(hit);
component.getChildren().add(hol);
}
private ValueExpression expression(String s, Class c){
return FacesContext.getCurrentInstance().getApplication().getExpressionFactory().createValueExpression(
FacesContext.getCurrentInstance().getELContext(),
s, c
);
}
The example above builds a static panel, but it would be possible to:
create an object model of your GUI
map the model to database (with hibernate or another orm)
write some kind of adapter or bridge to build JSF objects from your object model
make a managed bean that receives the form id, grabs the relevant form from database, builds a JSF panel out of it and presents it as a property, ready to be bound.
This way you could have just one static xhtml with a single tag and use it to present any number of dynamic forms.
As I said, this method could be better than just storing files, but not necessarily. If you just want to save yourself the hassle of redeployment, this is a huge overkill (then again, you do NOT need to redeploy JSF applications just to change forms). If on the other hand your goal is to have something like user-defined and edited forms, having a good object model and storing it in a proper way could be a good idea.
The bumps ahead would be:
navigation (perhaps a custom navigation handler would suffice?)
problems with generating plain html
possibly some problems with lifecycle of view scoped forms