I understand how the JCR API works and is used in Magnolia. I want to get the result as JSON object
My Node object has a hierarchical structure(each subnode has type mgnl:category)
test_1
test_a
test_b
test_c
test_c1
test_d
If I use
var session = context.getJCRSession("category");
Iterable<Node> categoryItems = NodeUtil.collectAllChildren(
session.getNode(nodePath),
new NodeTypePredicate("mgnl:category"));
List<String> result = new ArrayList<>();
for (Node node : categoryItems) {
result.add(node.getName());
}
I get just a list of children like: [test_a, test_b, test_c, text_c1, test_d].
How can I check if a child has a subnode? Because I need [test_a, test_b, test_c: {text_c1}, test_d].
I think recursion will do here... but I need info about if a node has a subnode...
You can check if a node has a subnode by hasNodes() method. You can refer more JCR Node APIs here https://developer.adobe.com/experience-manager/reference-materials/spec/jsr170/javadocs/jcr-2.0/javax/jcr/Node.html
Thanks
Related
When traversing a tree structure recursively in order to calculate weights and volumes for an entire bill of materials, I run into a ConcurrentModificationException. My approach in pseudocode:
Query initialization: add root node to list of nodes and check if it has any childs.
Progress documentation: Flag the node as visited.
Query childs: Checking for child nodes and if present add to allNodes with a level up flag.
Recursive traversal: Recursively traverse list until no more child elements are found.
I have tried to use iterators to allow myself to expand that array of nodes but ran into the same problem. Slowly running out of ideas here I am grateful for any hint.
NOTE: please forgive me to paste my problem not stating all the context for better readability. Let me know if you need more info.
// Initialization
List<Node> allNodes = new ArrayList<>();
allNodes.add(new Node(input, input, 0, false) // (1)
int counter = 0;
// Method call
getAllNodes(allNodes);
// Query parent for child elements
public void getAllNodes(List<Node> nodes){
for (Node node : nodes) {
if (!node.isVisited()) { // (2)
node.setVisited(true);
String parentId = node.getId();
Product product = QueryUtil.getFirstByIdNo(ctx, parentId, Product.class);
if (isComposite(product)) {
Iterable<Product.Row> rows = product.table().getRows(); // (3)
for (Product.Row row : rows) {
allNodes.add(new Node(parentId, row.getProductListElem().getIdno(), ++counter, false));
--counter;
}
++counter;
// Recursive query of all node elements
getAllNodes(allNodes); // (4)
}
}
}
}
//Node Bean with getters, setters, constructor, toString
#Data
class Node {
String parent;
String id;
int level;
boolean visited;
}
You are getting the error because you are trying to modify the list that you are iterating(reading) over. And this is not allowed in JAVA. [for more explanation check here]
To avoid this you can either get an iterator for your list and then loop over it, but that does not seem like a very good option for the code you have posted above. Thus, I'll recommend using List<Node> allNodes = new CopyOnWriteArrayList<>(); instead of List<Node> allNodes = new ArrayList<>().
I'm using neo4j through java and I was wondering if there's a way to save some metadata with that node. I wanted to be able to have a node from the graph include more information, for instance to have each node have a dictionary associated with it.
edit - A dictionary was just an example, I want to be able to associate also class instances which contain as one of the fields a dictionary for example.
Unfortunately, there is no such functionality in Neo4j.
Neo4j is simple property graph.
But you can "emulate" such behaviour by using conventions in your application.
Special properties
You can specify in your application that all properties that starts with __ are metadata.
Then storing metadata is trivial:
try (Transaction tx = db.beginTx()) {
Node node = db.createNode();
node.setProperty("__version", "1.0.0");
node.setProperty("__author", "Dmitry");
tx.success();
}
JSON metadata
Other way - store JSON string in __metadata property and specify all your metadata as JSON.
Example:
ObjectMapper mapper = new ObjectMapper();
// create node and set metadata
try (Transaction tx = db.beginTx()) {
Map<String, Object> metadata = new HashMap<>();
metadata.put("version", "1.0.0");
metadata.put("author", "Dmitry");
Node node = db.createNode();
node.setProperty("__metadata", mapper.writeValueAsString(metadata));
tx.success();
}
// find node and get metadata
try (Transaction tx = db.beginTx()) {
Node node = db.findNode(...);
Map<String, Object> metadata = map = mapper.readValue(
node.getProperty("__metadata"), HashMap.class);
tx.success();
}
Note: if you go with this option, then you should create some sort of wrapper/helper for Node to minimize code duplication.
Note2: ObjectMapper should be created only once per application.
In addition to the other answer you can easily create a separate node representing your class and holding class-level meta information.
Either connect all the nodes representing instances to the class node using a relationship (this might cause lock contention if a lot of instances are added concurrently) or use a naming convention:
Node for instances: (:Person{name:'Danny'})
Metanode for person: (:Meta{clazz:'Person', metaProp1: value1, ...})
So the label if the instance node is linked to the clazz property of the meta node.
I have a BeanTreeView that shows a some nodes. And I have another component that isn't netbeans-related that needs to know what is in the tree at this moment. Preferably just a straight list of the nodes in the tree. (Clarification; when I talk about nodes here I mean netbeans nodes, not the TreeNodes in a JTree.)
I haven't found any useful methods of doing this. I can't seem to get the information from the associated ExplorerManager that's connected to the BeanTreeView. So far I've subclassed the BeanTreeView and added the private method
private List<Object> getNodesAsList(){
LinkedList<Object> result = new LinkedList<>();
for (int i = 0; i < tree.getRowCount(); i++) {
TreePath pathForRow = tree.getPathForRow(i);
Object lastPathComponent = pathForRow.getLastPathComponent();
result.add(lastPathComponent);
}
return result;
}
The Object I get from getLastPathComponent is a VisualizerNode, which holds the node I want to get. But I can't cast to VisualizerNode since it's not public in org.openide.explorer.view. And it's final. And there's no getters for the node anyway...
Any ideas? I feel like there's something I've missed with the ExplorerManager...
Update; this worked for me, could probably be done more elegant. Thanks paddy!
private List<Node> getNodesInTree(){
LinkedList<Node> result = new LinkedList<>();
ExplorerManager em = ExplorerManager.find(this);
for (Node node : em.getRootContext().getChildren().getNodes()) {
result.add(node);
result.addAll(getChildNodesInTree(node));
}
return result;
}
private List<Node> getChildNodesInTree(Node root){
LinkedList<Node> result = new LinkedList<>();
if(root.getChildren().getNodesCount() > 0){
if(isExpanded(root)){
for (Node node : root.getChildren().getNodes()) {
result.add(node);
result.addAll(getChildNodesInTree(node));
}
}
}
return result;
}
You could use ExplorerManager.getRootContext(). This returns the root Node shown in your ExplorerManager. From this node you could iterate through all the other nodes (using Node.getChildren()) and create your own list. I am not aware of a function that handles that for you.
Say that I have an index named "user". How do I get all the nodes belonging to that index using Neo4j-Java Api?
I tried the code below
val nodeIndex = getNodeIndex("article").get
val nodes = nodeIndex.getGraphDatabase().getAllNodes()
But, I got all the nodes present in the db. How do I solve this?
You should use "get" or "query" on the nodeIndex, like:
IndexHits<Node> allArticles = nodeIndex.query( "*:*" );
... do stuff ...
allArticles.close();
or
Node myArticle = nodeIndex.get( "name", "MyArticle" ).getSingle();
What you did above was to regardless of the index, get the graph database and return all nodes.
I know how to parse XML documents with DOM when they are in the form:
<tagname> valueIWant </tagname>
However, the element I'm now trying to get is instead in the form
<photo farm="9" id="8147664661" isfamily="0" isfriend="0" ispublic="1"
owner="8437609#N04" secret="4902a217af" server="8192" title="Rainbow"/>
I usually use cel.getTextContent() to return the value, but that doesn't work in this case. Neither does cel.getAttributes(), which I thought would work...
Ideally, I need to just get the id and owner numerical values. However if someone can help on how to get all of it, then I can deal with removing the parts I don't want later.
What you're looking to retrieve is the value of different attributes that are attached with an Element. Look at using the getAttribute(String name) method to achieve this
If you want to retrieve all the attributes, all you can do so using getAttributes() and iterate through it. An example of both of these methods might be something like this:
private void getData(Document document){
if(document == null)
return;
NodeList list = document.getElementsByTagName("photo");
Element photoElement = null;
if(list.getLength() > 0){
photoElement = (Element) list.item(0);
}
if(photoElement != null){
System.out.println("ID: "+photoElement.getAttribute("id"));
System.out.println("Owner: "+photoElement.getAttribute("owner"));
NamedNodeMap childList = photoElement.getAttributes();
Attr attribute;
for(int index = 0; index < childList.getLength(); index++){
if(childList.item(index).getNodeType() == Node.ATTRIBUTE_NODE){
attribute = ((Attr)childList.item(index));
System.out.println(attribute.getNodeName()+" : "+attribute.getNodeValue());
}else{
System.out.println(childList.item(index).getNodeType());
}
}
}
}
Something like:
Element photo = (Element)yournode;
photo.getAttribute("farm");
will get you the value of the farm attribute. You need to treat your node as an Element to have access to these attributes (doc).