I have a service that's attempting to import blog pages into CQ 5.5.0. I am able to successfully create the page, but when I add nodes representing the content the nodes are not being saved. No errors are reported by CQ and I can see the nodes in the service immediately after creation. But when I look at the page in CRXDE Light the nodes are not part of the page content. The section of code that adds the nodes is here:
Node blogNode = blogPage.adaptTo(Node.class);
logOutput( INFO, "blogPage name = "+ blogPage.getName() );
// Create the author date node
Node authorDateNode = blogNode.addNode("jcr:content/authorDate", "nt:unstructured");
authorDateNode.setProperty("author", blog.getCreator());
authorDateNode.setProperty("date", sdf.format(blog.getPublishDate().getTime()));
authorDateNode.setProperty("sling:resourceType", "history/components/blog/authordate");
// Create the content node
Node blogPostNode = blogNode.addNode("jcr:content/blogPostBodyParSys", "nt:unstructured");
blogPostNode.setProperty("sling:resourceType", "history/components/parsys");
Node blogContentNode = blogNode.addNode("jcr:content/blogPostBodyParSys/text", "nt:unstructured");
blogContentNode.setProperty("sling:resourceType", "history/components/text");
blogContentNode.setProperty("text", blog.getContent());
blogContentNode.setProperty("textIsRich", "true");
// TODO: Test code only
NodeIterator itr = blogNode.getNode("jcr:content").getNodes();
while(itr.hasNext()) {
Node child = itr.nextNode();
logOutput(INFO, "Child node: " + child.getName(), 1 );
PropertyIterator propItr = child.getProperties();
while( propItr.hasNext() ) {
Property prop = propItr.nextProperty();
logOutput(INFO, "Property " + prop.getName() + ", value " + prop.getValue().getString(),2);
}
}
The test code at the bottom displays the newly created nodes and it shows values as expected. The last thing that occurs is a call to 'session.save' before the service exits.
No errors are reported but I do not see the nodes when I look at the page. Does anyone have any idea about what might be wrong here?
As pointed by #Sharath Maddapa you need to save the session. See the changes done in your code.
Node blogNode = blogPage.adaptTo(Node.class);
logOutput( INFO, "blogPage name = "+ blogPage.getName() );
// Create the author date node
Node authorDateNode = blogNode.addNode("jcr:content/authorDate", "nt:unstructured");
authorDateNode.setProperty("author", blog.getCreator());
authorDateNode.setProperty("date", sdf.format(blog.getPublishDate().getTime()));
authorDateNode.setProperty("sling:resourceType", "history/components/blog/authordate");
// Create the content node
Node blogPostNode = blogNode.addNode("jcr:content/blogPostBodyParSys", "nt:unstructured");
blogPostNode.setProperty("sling:resourceType", "history/components/parsys");
Node blogContentNode = blogNode.addNode("jcr:content/blogPostBodyParSys/text", "nt:unstructured");
blogContentNode.setProperty("sling:resourceType", "history/components/text");
blogContentNode.setProperty("text", blog.getContent());
blogContentNode.setProperty("textIsRich", "true");
//YOU must save the session here.
try {
blogNode.getSession().save();
} catch(Exception e) {// TODO Ideally log specific exceptions
logOutput( ERROR, "Error saving jcr session ");
}
// TODO: Test code only
NodeIterator itr = blogNode.getNode("jcr:content").getNodes();
while(itr.hasNext()) {
Node child = itr.nextNode();
logOutput(INFO, "Child node: " + child.getName(), 1 );
PropertyIterator propItr = child.getProperties();
while( propItr.hasNext() ) {
Property prop = propItr.nextProperty();
logOutput(INFO, "Property " + prop.getName() + ", value " + prop.getValue().getString(),2);
}
}
I appreciate the input and I finally figured out what was causing my problem: I had created two ResourceResolver instances so the session I was saving was apparently a different session from where the nodes were being created. And that session was not being saved.
Related
class Node
{
public int data;
public Node next;
public Node(int idata) {
data = idata;
next = null;
}
}
Node newnode = new Node(val);
newnode.next = null;
Like if I'm creating a new object newnode of the class Node , how is it able to use .next to find the next address of the list?
In your example code next is just null. Actually, it was not necessary to explicitly do newnode.next = null;, as it already was initialised to null in the Node constructor.
It becomes more interesting when you assign another new node to the next property of the node you have created:
Node newnode = new Node(1);
newnode.next = new Node(2);
In Java objects are accessed with references. newnode is such a reference, and newnode.next is also such a reference. Both are references to Node instances (if not null).
We could extend the linked list further:
newnode.next.next = new Node(3);
newnode.next.next.next = new Node(4);
When you realise that next is a property that can hold a value like any variable, then there is really no magic to it.
You could for instance also first create Node instances that are disconnected, and only after their creation link them together:
Node a = new Node(1);
Node b = new Node(2);
Node c = new Node(3);
Node d = new Node(4);
a.next = b;
b.next = c;
c.next = d;
I am trying to get the latest version number of my store app in order to notify user for updates if they are using an older version.
This is my code so far but its obviously just retrieving the div containing the text "Version Number". How do I get the actual version number (in this case 1.1) referring to the attached screenshot of the DOM tree?
public static string GetAndroidStoreAppVersion()
{
string androidStoreAppVersion = null;
try
{
using (var client = new HttpClient())
{
var doc = client.GetAsync("https://play.google.com/store/apps/details?id=" + AppInfo.PackageName + "&hl=en_CA").Result.Parse();
var versionElement = doc.Select("div:containsOwn(Current Version)");
androidStoreAppVersion = versionElement.Text;
}
}
catch (Exception ex)
{
// do something
Console.WriteLine(ex.Message);
}
return androidStoreAppVersion;
}
According to the parser doc,the containsOwm selector selects elements that directly contain the specified text.
As a result, your code
var versionElement = doc.Select("div:containsOwn(Current Version)");
will surely return "Current Version". The real element you would like to get is the child of the child of the sibling of "Current Version" element. So you would have to get that element using the selector.
So you can get the version number in this way:
var versionElement = doc.Select("div:containsOwn(Current Version)");
Element headElement = versionElement[0];
Elements siblingsOfHead = headElement.SiblingElements;
Element contentElement = siblingsOfHead.First;
Elements childrenOfContentElement = contentElement.Children;
Element childOfContentElement = childrenOfContentElement.First;
Elements childrenOfChildren = childOfContentElement.Children;
Element childOfChild = childrenOfChildren.First;
androidStoreAppVersion = childOfChild.Text;
I have a String which is the path of the page for example /content/xperia/public/events/eventeditor. I am gererating the XML of this page and saving it to DAM, but I want to save it in the similar tree structure under /content.
I tried the following code
String page = "/content/xperia/public/events/eventeditor";
page = page.replace("/content", "/content/dam");
if (adminSession.nodeExists(page+ "/"+ "jcr:content")) {
Node node = adminSession.getNode(page+ "/"+ "jcr:content");
node.setProperty("jcr:data", sb.toString());
} else {
Node feedNode = JcrUtil.createPath(page,"nt:file", adminSession);
Node dataNode = JcrUtil.createPath(feedNode.getPath() + "/"+ "jcr:content", "nt:resource", adminSession);
dataNode.setProperty("jcr:data",sb.toString());
}
But it gives the following error
No matching child node definition found for
{http://www.jcp.org/jcr/1.0}content
Because there is no such path in the repository. Is there a way through which I can create a directory on the fly. Because to save this file, I need to create the entire tree xperia/public/events under /content/dam and then save eventeditor.xml in that directory .
Please suggest.
There are a few issues with your code. The JcrUtil.createPath(String absolutePath, String nodeType, Session session) creates all the non-existent intermediate path with the given NodeType.
This means that all the nodes xperia, public and events are created with type nt:file instead of sling:OrderedFolder.
You can use the createPath(String absolutePath, boolean createUniqueLeaf, String intermediateNodeType, String nodeType, Session session, boolean autoSave) method instead, to specify the type of intermediary nodes that are to be created.
String page = "/content/xperia/public/events/eventeditor";
page = page.replace("/content", "/content/dam");
page += ".xml";
if (adminSession.nodeExists(page+ "/"+ "jcr:content")) {
Node node = adminSession.getNode(page+ "/"+ "jcr:content");
node.setProperty("jcr:data", sb.toString());
} else {
Node feedNode = JcrUtil.createPath(page, true, "sling:OrderedFolder", "nt:file", adminSession, false);
Node dataNode = feedNode.addNode("jcr:content", "nt:resource");
dataNode.setProperty("jcr:data",sb.toString());
}
adminSession.save();
I'm creating cluster dynamically in xtend/Java
for (int i : 0 ..< DistributorClusters.length) {
val clusterName = classnames.get(i) + clusterSuffix;
database.command(
new OCommandSQL('''ALTER CLASS «classnames.get(i)» ADDCLUSTER «clusterName»''')).execute();
}
Then I create I add the oRole and Grant the security to the new oRole
val queryOroleCreation = '''INSERT INTO orole SET name = '«clusterSuffix»', mode = 0, inheritedRole = (SELECT FROM orole WHERE name = 'Default')''';
val ODocument result = database.command(new OCommandSQL(queryOroleCreation)).execute();
for (int i : 0 ..< classnames.length) {
database.command(
new OCommandSQL(
'''GRANT ALL ON database.cluster.«classnames.get(i)»«clusterSuffix» TO «clusterSuffix»''')).
execute();
}
Finally I try to save a JsonObject to one of the newly created cluster. I checked in the database and the cluster exists.
val doc = new ODocument();
doc.fromJSON(jsonToSave.toString());
val savedDoc = database.save(doc, "ClassName"+clusterSuffix);
database.commit();
But Orient returns the following error :
SEVERE: java.lang.IllegalArgumentException: Cluster name 'cluster:ClassNameclusterSuffix' is not configured
My Question :
What causes that exception? And can you add values to new cluster created?
Edit
The doc object contains reference to other classes. i.e:
{
#class:"Customer",
#version:0,
name:"Kwik-E-Mart",
user : {
#class:"User",
#version:0,
username: "Apu",
firstName:"Apu",
lastName:"Nahasapeemapetilon"
}
}
The user gets created in the default cluster, but the customer throws the exception.
You should remove the "cluster:" part. The second parameter of the method is "Name of the cluster where to save", it doesn't need any special prefix.
So:
val savedDoc = database.save(doc, "ClassName"+clusterSuffix);
should just work
I find out that using a query works fine source.
The following code worked on the first try:
val query = '''INSERT INTO ClassNameCLUSTER «"ClassName"+clusterSuffix» CONTENT «jsonToSave.toString()»'''
val ODocument savedDoc = database.command(new OCommandSQL(query)).execute();
I'm having an issue when I'm trying to load my initial data for JSTree; I have 2 top level nodes attached to the root node but when I load them it looks like the last node added is being duplicated within JSTree. At first it looked as if it was my fault for not specifically declaring a new object each time but I've fixed that. I'm using .net MVC so the initial data is coming from the model that is passed to my view (that is the data passed into the data parameter of the method).
this.loadInitialData = function (data) {
var tree = self.getTree();
for (var i = 0; i < data.length; i++) {
var node = new Object();
node.id = data[i].Id;
node.parent = data[i].Parent;
node.text = data[i].Text;
node.state = {
opened: data[i].State.Opened,
disabled: data[i].State.Disabled,
selected: data[i].State.Selected
};
node.li_attr = { "node-type": data[i].NodeType };
node.children = [];
for (var j = 0; j < data[i].Children.length; j++) {
var childNode = new Object();
childNode.id = data[i].Children[j].Id;
childNode.parent = data[i].Children[j].Parent;
childNode.text = data[i].Children[j].Text;
childNode.li_attr = { "node-type": data[i].Children[j].NodeType };
childNode.children = data[i].Children[j].HasChildren;
node.children.push(childNode);
}
tree.create_node("#", node, "last");
}
}
My initial code was declaring node like the following:
var node = {
id: data[i].Id
}
I figured that was the cause of what I'm seeing but fixing it has not changed anything. Here is what is happening when I run the application; on the first pass of the method everything looks like it is working just fine.
But after the loop is run for the second (and last) time here is the final result.
It looks like the node objects are just a copy of each other, but when I run the code through the debugger I see the object being initialized each time. Does anyone have an idea what would cause this behavior in JSTree? Should I be using a different method to create my initial nodes besides create_node?
Thanks in advance.
I found the issue; I didn't realize but I was setting my id property to the same id for both node groups. After I fixed it everything started working as expected.