Unable to delete a Node in jackrabbit - java

I am trying to delete a Node which I have saved using jackrabbit but I get this error.
Failed to delete file
! javax.jcr.nodetype.ConstraintViolationException: Unable to perform operation. Node is protected.
Here is the code I have used to save it:
session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
Node parent = (Node) itemAtPath(parentPath, session);
Node newNode = parent.addNode(nodeName);
newNode.addMixin("mix:versionable");
session.save(); // Create Root Node
VersionableChanges changes = new VersionableChanges(newNode.getSession());
changes.checkout(newNode);
Binary binary = session.getValueFactory().createBinary(in);
newNode.setProperty(PROPERTY_DATA, binary);
newNode.setProperty(PROPERTY_NAME, fileName + System.currentTimeMillis());
newNode.setProperty(PROPERTY_CREATEDBY, createdBy);
newNode.setProperty(PROPERTY_CREATEDDATE, createdDate);
newNode.setProperty(PROPERTY_COMMENT, comment);
Value value = session.getValueFactory().createValue(binary);
changes.checkin();
session.save();
Here is the code I am using to delete it:
session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
Version fileVersion = null;
Node fileNode = null;
if (version != null && !version.isEmpty()) {
fileVersion = session.getWorkspace().getVersionManager().getVersionHistory(path).getVersion(version);
} else {
fileVersion = session.getWorkspace().getVersionManager().getBaseVersion(path);
}
fileNode = fileVersion.getFrozenNode();
fileNode.remove();
//need to save session to persist the remove operation
session.save();
How can I overcome this error?

Frozen nodes are protected because deleting them would (maybe) put the version store in a corrupted state. In order to remove a "complete" version from the history, you have to something like this:
VersionHistory history = session.getWorkspace().getVersionManager()
.getVersionHistory(info.getVersionedNodePath());
history.removeVersion(info.getVersionName());
session.save();

Related

Browsing OPCUA nodes only working on top level

I am using OPC UA project https://github.com/OPCFoundation/UA-Java. I was able to browse all the nodes on an OPCUA Server using UAExpert.
Now I am trying to browse all nodes using my java client. I am able to retrieve references for the nodes in the first level of the node hierarchy where
rootnameSpace = 1 and rootIdentifier = "simsre"
BrowseDescription browse = new BrowseDescription();
browse.setNodeId(new NodeId(rootnameSpace, rootIdentifier));
browse.setBrowseDirection(BrowseDirection.Forward);
browse.setIncludeSubtypes(true);
browse.setNodeClassMask(NodeClass.Object, NodeClass.Variable);
browse.setResultMask(BrowseResultMask.All );
BrowseResponse res = mySession.Browse(null, null, null, browse);
ReferenceDescription[] references = res.getResults()[0].getReferences();
When I call the code for other nodes like rootnameSpace = 31 and rootIdentifier = "/simsrede/" beneath I still get a result but no references ( so res.getResults()[0].getReferences() returns null)
- The status code of the browseResponse is something like "GOOD" -
According to specification all unicode characters are allowed in the identifiers so slashes and '|' shouldn't be the problem.
I also tried adding entries into my namespacetable and using the table to set the node id in consecutive browse requests starting at the root node with
NamespaceTable table = NamespaceTable.getDefaultInstance();
table.add(1, "urn:something:UnifiedAutomation:Uagateway");
...
//consecutive browse request starting from reference returned by first call
browse1.setNodeId(table.toNodeId(references[0].getNodeId()));
BrowseResponse res1 = mySession.Browse(null, null, null, browse);
ReferenceDescription[] references1 = res.getResults()[0].getReferences();
Anybody having an idea on why this is returning null references, or how to debug this ?
I used a Browse function
Byte[] cp;ReferenceDescriptionCollection refs; m_session.Browse(null, null, ObjectIds.ObjectsFolder, 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out cp, out refs)
and i get if refs collection of the nodes from first level. Foreach node I called Browse function in recursion where I add nodes to the collection of OPCTreeNode
public void GetChildNodes(Session sesja, ReferenceDescription Parametr, OPCTreeNode treeNode)
{
ReferenceDescriptionCollection nodes;
byte[] tmpbytes;
sesja.Browse(null, null, ExpandedNodeId.ToNodeId(Parametr.NodeId, sesja.NamespaceUris), 0u, BrowseDirection.Forward, ReferenceTypeIds.HierarchicalReferences, true, (uint)NodeClass.Variable | (uint)NodeClass.Object | (uint)NodeClass.Method, out tmpbytes, out nodes);
foreach (var tmpnode in nodes)
{
OPCTreeNode tmpNode = new OPCTreeNode($"{tmpnode.DisplayName}", $"{tmpnode.NodeId}");
treeNode.ChildTreeNodes.Add(tmpNode);
GetChildNodes(sesja, tmpnode, tmpNode);
}
}
OPCTreeNode class
public class OPCTreeNode // element struktury parametrów sesji
{
public string DiplayName { get; set; }
public string NodeId { get; set; }
public List<OPCTreeNode> ChildTreeNodes;
public OPCTreeNode()
{
ChildTreeNodes = new List<OPCTreeNode>();
}
public OPCTreeNode(string displayName, string nodeId)
{
this.DiplayName = displayName;
this.NodeId = nodeId;
ChildTreeNodes = new List<OPCTreeNode>();
}
}

Breadth First Neo4j tree traversal and TreeNode creation

I have a Neo4j graph database which maps a file system structure consisting of nodes representing folders and files.
Each node has a FATHER_OF and a CHILD_OF relationship.
Now I need to create a TreeNode structure in Java starting from the Neo4j graph: currently I implemented a breadth first print of the NEO4J structure as follows:
public Traverser getTraverser()
{
Transaction tx = graphDb.beginTx();
Traverser traverser = traverseStorage(rootNode);
return traverser;
}
private static Traverser traverseStorage(final Node startNode) {
TraversalDescription td = Traversal.description()
.breadthFirst()
.relationships(GraphStorage.RelTypes.FATHER_OF, Direction.OUTGOING);
return td.traverse(startNode);
}
Now I'm trying to create a Tree using the above breadth-first traverser but can't figure out how to properly assign the correct parent to each node.
TreeNode root = new DefaultTreeNode("root", null);
Traverser traverser = graphStorage.getTraverser();
TreeNode parent = root;
for (Path directoryPath : traverser) {
DefaultTreeNode tmp1 = new DefaultTreeNode((String)directoryPath.endNode().getProperty("name"), parent);
}
I hoped there was something like directoryPath.endNode().getParent() but apparently there isn't.
I'm searching for a solution which doesn't require me to use Cypher query language, any help?
Ok found out, just need a HashMap to map Neo4j node id's to TreeNode objects:
HashMap<Long, TreeNode> treeNodeMap = new HashMap();
then the rest becomes:
TreeNode root = new DefaultTreeNode("root", null);
Traverser traverser = graphStorage.getTraverser();
TreeNode parent = root;
Relationship parentRelationship = directoryPath.endNode().getSingleRelationship(
GraphStorage.RelTypes.CHILD_OF, Direction.OUTGOING);
if (parentRelationship != null) {
Node parentFileNode = parentRelationship.getEndNode();
if (parentFileNode != null) {
long parentId = parentFileNode.getId();
parent = treeNodeMap.get(new Long(parentId));
}
DefaultTreeNode tmp1 = new DefaultTreeNode((String)directoryPath.endNode().getProperty("name"), parent);
treeNodeMap.put(new Long(directoryPath.endNode().getId()), tmp1);
}
The above correctly works.

Jackrabbit update or merge node

I have already send the same message to jackrabbit user list, but nobody reply me.
I would like to update a node and his childs with Jackrabbit 2.4.3 throw jackrabbit-jcr2dav. ( like a merge : updating, creating or removing nodes ).
But when I update a property already existing in the repository I have an ERROR in the log, and nothing is saved. It's not an exception, only an error.
[ERROR] org.apache.jackrabbit.jcr2spi.hierarchy.ChildNodeEntriesImpl:176 - ChildInfo iterator contains multiple entries with the same name|index or uniqueID -> ignore ChildNodeInfo.
my code :
Repository repository = JcrUtils.getRepository(jcrUrl);
Session session = repository.login( new SimpleCredentials("admin", "admin".toCharArray()));
try {
String user = session.getUserID();
String repositoryname = repository.getDescriptor(Repository.REP_NAME_DESC);
LOGGER.debug( "Logged in as " + user + " to a " + repositoryname + " repository.");
// Retrieve content
StringBuilder expression = new StringBuilder();
expression.append("SELECT * FROM [nt:unstructured] AS mynode ");
expression.append("WHERE id = "+ mynode.getId() +" " );
QueryManager queryMgr = session.getWorkspace().getQueryManager();
Query query = queryMgr.createQuery(expression.toString(),Query.JCR_SQL2);
QueryResult result = query.execute();
RowIterator rowIterator = result.getRows();
if (rowIterator.hasNext() ) {
Node node = rowIterator.nextRow().getNode();
// Store metadata content
node.setProperty("description", mynode.getDescription());
node.setProperty("keywords", mynode.getKeywords());
node.setProperty("title", mynode.getTitle()); // ERROR IN THE LOG AT THIS LINE because description and keywords doesn't exist, but title already exist.
node.setProperty("resume", mynode.getResume());
[... updating childs node here ]
session.save();
}
} catch ( RepositoryException e) {
LOGGER.error("Error getting data", e);
throw e;
} finally {
session.logout();
}
return book;
}
Is someone already try to update a node property ?
Thanks
Finally, I have confirmation that two nodes under the same parent should note have the same name. That's why I have this error.
Without having the same name, my code is working.

JSF/ICEfaces Dynamic hierarchy tree example

i have list of departments and each department might have a parent or not,department domain object is as follows:
- departmentId
- parentDepartmentId (null if current department has no parent i,e should be under root directly, and have value if current department have parent).
.
.
.
looking at icefaces tutorial code for creating basic tree:
// create root node with its children expanded
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
IceUserObject rootObject = new IceUserObject(rootTreeNode);
rootObject.setText("Root Node");
rootObject.setExpanded(true);
rootTreeNode.setUserObject(rootObject);
// model is accessed by by the ice:tree component via a getter method, this object is what's needed in the view to display the tree
model = new DefaultTreeModel(rootTreeNode);
// add some child nodes
for (int i = 0; i <3; i++) {
DefaultMutableTreeNode branchNode = new DefaultMutableTreeNode();
IceUserObject branchObject = new IceUserObject(branchNode);
branchObject.setText("node-" + i);
branchNode.setUserObject(branchObject);
rootTreeNode.add(branchNode);
}
it's all about constructing basic node, and adding childs.
my case is complex that child A which is under root may have child nodes B,C,D and D have for example child nodes and so on so on.
so i am thinking of a best practice about how to accomplish something like that, i need a sample code or hints if anyone can help.
You would need a recursive method to construct the tree from your model.
public void buildRecursiveTreeNode(DefaultMutableTreeNode parentTreeNode,
String treeId, String treeName, GenericTreeVo modelVo)
{
// if the database model contains more children.
// add the current nodes first and pass in this nodes tree id and name to construct the children for this parent nodes.
}
Updated answer to include recursion example.
http://www.danzig.us/java_class/recursion.html
just added a recursion link, all I am saying is when you iterate the data from the database, you would see if you have any child records, if you have child records you would call the same method by passing the DefaultMutableTreeNode and that would become the parent.
finally i was able to do it as follows:
List<Department> departmentList = getAllDepartments();
// create root node with its children expanded
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
IceUserObject rootObject = new IceUserObject(rootTreeNode);
rootObject.setText("Root");
rootObject.setExpanded(true);
rootTreeNode.setUserObject(rootObject);
HashMap<Department, DefaultMutableTreeNode> createdNodesMap = new HashMap<Department, DefaultMutableTreeNode>(
0);
for (Department department : departmentList) {
DefaultMutableTreeNode currentNode = null;
if (createdNodesMap.get(department) == null) {
log.debug("############ CREATING NODE "
+ department.getName());
currentNode = new DefaultMutableTreeNode();
IceUserObject currentObject = new IceUserObject(currentNode);
currentObject.setText(department.getName());
currentObject.setExpanded(true);
currentNode.setUserObject(currentObject);
if (department.getParentDepartment() == null) {
rootTreeNode.add(currentNode);
log.debug("######### NODE " + department.getName()
+ " ADDED UNDER ROOT");
}
createdNodesMap.put(department, currentNode);
} else {
log.debug("############ GETTING CREATED NODE "
+ department.getName());
currentNode = createdNodesMap.get(department);
}
if (department.getChildren().size() > 0)
log.debug("############ NODE " + department.getName()
+ " HAVE " + department.getChildren().size()
+ " CHILDREN");
else
log.debug("############ NODE " + department.getName()
+ " DOES NOT HAVE CHILDREN");
for (Department department2 : department.getChildren()) {
log.debug("############ CREATING CHILD "
+ department2.getName() + " FOR PARENT "
+ department.getName());
DefaultMutableTreeNode branchNode;
if (createdNodesMap.get(department2) == null) {
branchNode = new DefaultMutableTreeNode();
IceUserObject branchObject = new IceUserObject(
branchNode);
branchObject.setText(department2.getName());
branchObject.setExpanded(true);
branchNode.setUserObject(branchObject);
} else
branchNode = createdNodesMap.get(department2);
createdNodesMap.put(department2, branchNode);
currentNode.add(branchNode);
}
}
model = new DefaultTreeModel(rootTreeNode);
Check http://click.avoka.com/click-examples/tree/checkbox-tree-page.htm
The latter is done via the Apache Click framework. Right now I'm developing a project where this data structure (hierarchy tree) is heavily used. You can set the root node or if you need to have several starting points, you can create a wildcard root node that won't affect the functionality, the subclasses, like others have commented, need to be created recursively.

Get Xpath from the org.w3c.dom.Node

Can i get the full xpath from the org.w3c.dom.Node ?
Say currently node is pointing to some where the middle of the xml document. I would like extract the xpath for that element.
The output xpath I'm looking for is //parent/child1/chiild2/child3/node. A parent to node xpath. Just ignore the xpath's which are having expressions and points to the same node.
There's no generic method for getting the XPath, mainly because there's no one generic XPath that identifies a particular node in the document. In some schemas, nodes will be uniquely identified by an attribute (id and name are probably the most common attributes.) In others, the name of each element (that is, the tag) is enough to uniquely identify a node. In a few (unlikely, but possible) cases, there's no one unique name or attribute that takes you to a specific node, and so you'd need to use cardinality (get the n'th child of the m'th child of...).
EDIT:
In most cases, it's not hard to create a schema-dependent function to assemble an XPath for a given node. For example, suppose you have a document where every node is uniquely identified by an id attribute, and you're not using namespaces. Then (I think) the following pseudo-Java would work to return an XPath based on those attributes. (Warning: I have not tested this.)
String getXPath(Node node)
{
Node parent = node.getParent();
if (parent == null) {
return "/" + node.getTagName();
}
return getXPath(parent) + "/" + "[#id='" + node.getAttribute("id") + "']";
}
I am working for the company behind jOOX, a library that provides many useful extensions to the Java standard DOM API, mimicking the jquery API. With jOOX, you can obtain the XPath of any element like this:
String path = $(element).xpath();
The above path will then be something like this
/document[1]/library[2]/books[3]/book[1]
I've taken this code from
Mikkel Flindt post & modified it so it can work for Attribute Node.
public static String getFullXPath(Node n) {
// abort early
if (null == n)
return null;
// declarations
Node parent = null;
Stack<Node> hierarchy = new Stack<Node>();
StringBuffer buffer = new StringBuffer();
// push element on stack
hierarchy.push(n);
switch (n.getNodeType()) {
case Node.ATTRIBUTE_NODE:
parent = ((Attr) n).getOwnerElement();
break;
case Node.ELEMENT_NODE:
parent = n.getParentNode();
break;
case Node.DOCUMENT_NODE:
parent = n.getParentNode();
break;
default:
throw new IllegalStateException("Unexpected Node type" + n.getNodeType());
}
while (null != parent && parent.getNodeType() != Node.DOCUMENT_NODE) {
// push on stack
hierarchy.push(parent);
// get parent of parent
parent = parent.getParentNode();
}
// construct xpath
Object obj = null;
while (!hierarchy.isEmpty() && null != (obj = hierarchy.pop())) {
Node node = (Node) obj;
boolean handled = false;
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) node;
// is this the root element?
if (buffer.length() == 0) {
// root element - simply append element name
buffer.append(node.getNodeName());
} else {
// child element - append slash and element name
buffer.append("/");
buffer.append(node.getNodeName());
if (node.hasAttributes()) {
// see if the element has a name or id attribute
if (e.hasAttribute("id")) {
// id attribute found - use that
buffer.append("[#id='" + e.getAttribute("id") + "']");
handled = true;
} else if (e.hasAttribute("name")) {
// name attribute found - use that
buffer.append("[#name='" + e.getAttribute("name") + "']");
handled = true;
}
}
if (!handled) {
// no known attribute we could use - get sibling index
int prev_siblings = 1;
Node prev_sibling = node.getPreviousSibling();
while (null != prev_sibling) {
if (prev_sibling.getNodeType() == node.getNodeType()) {
if (prev_sibling.getNodeName().equalsIgnoreCase(
node.getNodeName())) {
prev_siblings++;
}
}
prev_sibling = prev_sibling.getPreviousSibling();
}
buffer.append("[" + prev_siblings + "]");
}
}
} else if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
buffer.append("/#");
buffer.append(node.getNodeName());
}
}
// return buffer
return buffer.toString();
}
For me this one worked best ( using org.w3c.dom elements):
String getXPath(Node node)
{
Node parent = node.getParentNode();
if (parent == null)
{
return "";
}
return getXPath(parent) + "/" + node.getNodeName();
}
Some IDEs specialised in XML will do that for you.
Here are the most well known
oXygen
Stylus Studio
xmlSpy
For instance in oXygen, you can right-click on an element part of an XML document and the contextual menu will have an option 'Copy Xpath'.
There are also a number of Firefox add-ons (such as XPather that will happily do the job for you. For Xpather, you just click on a part of the web page and select in the contextual menu 'show in XPather' and you're done.
But, as Dan has pointed out in his answer, the XPath expression will be of limited use. It will not include predicates for instance. Rather it will look like this.
/root/nodeB[2]/subnodeX[2]
For a document like
<root>
<nodeA>stuff</nodeA>
<nodeB>more stuff</nodeB>
<nodeB cond="thisOne">
<subnodeX>useless stuff</subnodeX>
<subnodeX id="MyCondition">THE STUFF YOU WANT</subnodeX>
<subnodeX>more useless stuff</subnodeX>
</nodeB>
</root>
The tools I listed will not generate
/root/nodeB[#cond='thisOne']/subnodeX[#id='MyCondition']
For instance for an html page, you'll end-up with the pretty useless expression :
/html/body/div[6]/p[3]
And that's to be expected. If they had to generate predicates, how would they know which condition is relevant ? There are zillions of possibilities.
Something like this will give you a simple xpath:
public String getXPath(Node node) {
return getXPath(node, "");
}
public String getXPath(Node node, String xpath) {
if (node == null) {
return "";
}
String elementName = "";
if (node instanceof Element) {
elementName = ((Element) node).getLocalName();
}
Node parent = node.getParentNode();
if (parent == null) {
return xpath;
}
return getXPath(parent, "/" + elementName + xpath);
}

Categories

Resources