/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.celements.navigation.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.annotation.Requirement;
import org.xwiki.context.Execution;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.EntityReference;
import org.xwiki.model.reference.SpaceReference;
import com.celements.inheritor.InheritorFactory;
import com.celements.iterator.XObjectIterator;
import com.celements.navigation.INavigationClassConfig;
import com.celements.navigation.Navigation;
import com.celements.navigation.TreeNode;
import com.celements.navigation.cmd.GetMappedMenuItemsForParentCommand;
import com.celements.navigation.filter.INavFilter;
import com.celements.navigation.filter.InternalRightsFilter;
import com.celements.web.plugin.cmd.PageLayoutCommand;
import com.celements.web.service.IWebUtilsService;
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseCollection;
import com.xpn.xwiki.objects.BaseObject;
/**
* TreeNodeService access a tree node structure through the method of this service.
*
* @author Fabian Pichler
*/
@Component
public class TreeNodeService implements ITreeNodeService {
private static Logger LOGGER = LoggerFactory.getLogger(TreeNodeService.class);
public PageLayoutCommand pageLayoutCmd;
@Requirement
ITreeNodeCache treeNodeCache;
@Requirement
IWebUtilsService webUtilsService;
private InheritorFactory injectedInheritorFactory;
@Requirement
Map<String, ITreeNodeProvider> nodeProviders;
@Requirement
private INavigationClassConfig navClassConfig;
@Requirement
Execution execution;
private XWikiContext getContext() {
return (XWikiContext) execution.getContext().getProperty("xwikicontext");
}
private PageLayoutCommand getPageLayoutCmd() {
if (pageLayoutCmd == null) {
pageLayoutCmd = new PageLayoutCommand();
}
return pageLayoutCmd;
}
@Override
public int getActiveMenuItemPos(int menuLevel, String menuPart) {
List<DocumentReference> parents = webUtilsService.getDocumentParentsList(
getContext().getDoc().getDocumentReference(), true);
if (parents.size() >= menuLevel) {
return getMenuItemPos(parents.get(parents.size() - menuLevel), menuPart);
}
return -1;
}
@Override
public int getMenuItemPos(DocumentReference docRef, String menuPart) {
try {
EntityReference parent = getParentEntityRef(docRef);
int pos = -1;
for (TreeNode menuItem : getSubNodesForParent(parent, menuPart)) {
pos = pos + 1;
if (docRef.equals(menuItem.getDocumentReference())) {
return pos;
}
}
} catch (XWikiException exp) {
LOGGER.error("getMenuItemPos failed on getParentEntityRef", exp);
}
return -1;
}
@Override
public boolean isTreeNode(DocumentReference docRef) {
// TODO move to ITreeNodeProvider and integrate over all nodeProviders
try {
XWikiDocument document = getContext().getWiki().getDocument(docRef, getContext());
List<BaseObject> menuItems = document.getXObjects(navClassConfig.getMenuItemClassRef(
getContext().getDatabase()));
return ((menuItems != null) && !menuItems.isEmpty());
} catch (XWikiException exp) {
LOGGER.error("Failed to get document for reference [{}].", docRef, exp);
}
return false;
}
/**
* @deprecated since 2.17.0 use getSubNodesForParent(EntityReference, INavFilter) or
* getSubNodesForParent(EntityReference, String) instead
*/
@Deprecated
@Override
public <T> List<TreeNode> getSubNodesForParent(String parent, String menuSpace,
INavFilter<T> filter) {
if ("".equals(menuSpace)) {
menuSpace = getContext().getDoc().getDocumentReference().getLastSpaceReference().getName();
}
String parentKey = getParentKey(parent, menuSpace);
return getSubNodesForParent(resolveEntityReference(parentKey), filter);
}
String getParentKey(String parent, String menuSpace) {
String parentKey = "";
if (parent != null) {
parentKey = parent;
}
if (parentKey.indexOf('.') < 0) {
parentKey = menuSpace + "." + parentKey;
}
if (parentKey.indexOf(':') < 0) {
parentKey = getContext().getDatabase() + ":" + parentKey;
}
return parentKey;
}
String getParentKey(EntityReference reference, boolean withDataBase) {
String parentKey = "";
if (reference != null) {
parentKey = webUtilsService.getRefDefaultSerializer().serialize(reference);
if (!parentKey.contains(":") && !parentKey.endsWith(":")) {
parentKey += ":";
} else if (!parentKey.contains(".") && !parentKey.endsWith(".")) {
parentKey += ".";
}
if (!withDataBase) {
parentKey = parentKey.substring(parentKey.indexOf(":") + 1);
}
}
LOGGER.debug("getParentKey: returning [{}] for entityref [{}].", parentKey, reference);
return parentKey;
}
@Override
public <T> List<TreeNode> getSubNodesForParent(EntityReference entRef, INavFilter<T> filter) {
LOGGER.trace("getSubNodesForParent: entRef {}] filter class [{}].", entRef, filter.getClass());
ArrayList<TreeNode> menuArray = new ArrayList<TreeNode>();
for (TreeNode node : fetchNodesForParentKey(entRef)) {
if ((node != null) && filter.includeTreeNode(node, getContext())) {
// show only Menuitems of pages accessible to the current user
menuArray.add(node);
} else {
LOGGER.debug("getSubNodesForParent: omit [{}].", node);
}
}
return menuArray;
}
/**
* @deprecated since 2.17.0 use getSubNodesForParent(EntityReference, INavFilter) or
* getSubNodesForParent(EntityReference, String) instead
*/
@Deprecated
@Override
public List<TreeNode> getSubNodesForParent(String parent, String menuSpace, String menuPart) {
InternalRightsFilter filter = new InternalRightsFilter();
filter.setMenuPart(menuPart);
List<TreeNode> subNodesForParent = getSubNodesForParent(parent, menuSpace, filter);
LOGGER.debug("getSubNodesForParent deprecated use: parent [{}] menuSpace [{}] menuPart [{}]"
+ " returning [{}].", parent, menuSpace, menuPart, subNodesForParent.size());
return subNodesForParent;
}
@Override
public List<TreeNode> getSubNodesForParent(EntityReference entRef, String menuPart) {
InternalRightsFilter filter = new InternalRightsFilter();
filter.setMenuPart(menuPart);
return getSubNodesForParent(entRef, filter);
}
/**
* fetchNodesForParentKey
*
* @param parentKey
* @param context
* @return Collection keeps ordering of TreeNodes according to posId
*/
List<TreeNode> fetchNodesForParentKey(EntityReference parentRef) {
String parentKey = getParentKey(parentRef, true);
LOGGER.trace("fetchNodesForParentKey: parentRef [{}] parentKey [{}].", parentRef, parentKey);
long starttotal = System.currentTimeMillis();
long start = System.currentTimeMillis();
List<TreeNode> nodes = fetchNodesForParentKey_internal(parentKey, starttotal, start);
if ((nodeProviders != null) && (nodeProviders.values().size() > 0)) {
TreeMap<Integer, TreeNode> treeNodesMergedMap = new TreeMap<Integer, TreeNode>();
for (TreeNode node : nodes) {
treeNodesMergedMap.put(node.getPosition(), node);
}
for (ITreeNodeProvider tnProvider : nodeProviders.values()) {
try {
for (TreeNode node : tnProvider.getTreeNodesForParent(parentKey)) {
treeNodesMergedMap.put(node.getPosition(), node);
}
} catch (Exception exp) {
LOGGER.warn("Failed on provider [{}] to get nodes for parentKey [{}].",
tnProvider.getClass(), parentKey, exp);
}
}
nodes = new ArrayList<TreeNode>(treeNodesMergedMap.values());
long end = System.currentTimeMillis();
LOGGER.info("fetchNodesForParentKey: [{}] totaltime for list of [{}]: {}", parentKey,
nodes.size(), (end - starttotal));
}
return nodes;
}
private List<TreeNode> fetchNodesForParentKey_internal(String parentKey, long starttotal,
long start) {
List<TreeNode> notMappedmenuItems = treeNodeCache.getNotMappedMenuItemsForParentCmd().getTreeNodesForParentKey(
parentKey);
long end = System.currentTimeMillis();
LOGGER.debug("fetchNodesForParentKey_internal: time for getNotMappedMenuItemsFromDatabase: {}",
(end - start));
start = System.currentTimeMillis();
List<TreeNode> mappedTreeNodes = treeNodeCache.getMappedMenuItemsForParentCmd().getTreeNodesForParentKey(
parentKey, getContext());
end = System.currentTimeMillis();
LOGGER.debug("fetchNodesForParentKey_internal: time for getMappedMenuItemsForParentCmd: {}",
(end - start));
start = System.currentTimeMillis();
TreeMap<Integer, TreeNode> menuItemsMergedMap = null;
if ((notMappedmenuItems == null) || (notMappedmenuItems.size() == 0)) {
end = System.currentTimeMillis();
LOGGER.info("fetchNodesForParentKey_internal: [{}] totaltime for list of [{}]: {}", parentKey,
mappedTreeNodes.size(), (end - starttotal));
return mappedTreeNodes;
} else if (mappedTreeNodes.size() == 0) {
end = System.currentTimeMillis();
LOGGER.info("fetchNodesForParentKey_internal: [{}] totaltime for list of [{}]: {}", parentKey,
notMappedmenuItems.size(), (end - starttotal));
return notMappedmenuItems;
} else {
// TODO refactor GetNotMappedMenuItemsForParentCommand and
// TODO GetMappedMenuItemsForParentCommandas to ITreeNodeProvider
menuItemsMergedMap = new TreeMap<Integer, TreeNode>();
for (TreeNode node : notMappedmenuItems) {
menuItemsMergedMap.put(node.getPosition(), node);
}
for (TreeNode node : mappedTreeNodes) {
menuItemsMergedMap.put(node.getPosition(), node);
}
end = System.currentTimeMillis();
LOGGER.debug("fetchNodesForParentKey_internal: time for merging menu items: {}", (end
- start));
ArrayList<TreeNode> menuItems = new ArrayList<TreeNode>(menuItemsMergedMap.values());
LOGGER.info("fetchNodesForParentKey_internal: [{}] totaltime for list of [{}]: {}", parentKey,
menuItems.size(), (end - starttotal));
return menuItems;
}
}
/**
* @param parentKey
* @param context
* @return Collection keeps ordering of menuItems according to posId
* @deprecated since 2.14.0 use new fetchNodesForParentKey instead
*/
@Deprecated
List<BaseObject> fetchMenuItemsForXWiki(String parentKey) {
long starttotal = System.currentTimeMillis();
List<BaseObject> menuItemList = new ArrayList<BaseObject>();
EntityReference refParent = resolveEntityReference(parentKey);
for (TreeNode node : fetchNodesForParentKey(refParent)) {
try {
XWikiDocument itemdoc = getContext().getWiki().getDocument(node.getDocumentReference(),
getContext());
BaseObject cobj = itemdoc.getObject("Celements2.MenuItem");
if (cobj != null) {
menuItemList.add(cobj);
}
} catch (XWikiException exp) {
LOGGER.error("failed to get doc for menuItem", exp);
}
}
long end = System.currentTimeMillis();
LOGGER.info("fetchMenuItemsForXWiki: [{}] totaltime for list of [{}]: {}", parentKey,
menuItemList.size(), (end - starttotal));
return menuItemList;
}
EntityReference resolveEntityReference(String name) {
String wikiName = "", spaceName = "", docName = "";
String[] name_a = name.split("\\.");
String[] name_b = name_a[0].split(":");
// wikiName:spaceName
if (name_b.length > 1) {
wikiName = name_b[0];
spaceName = name_b[1];
// wikiName:
} else if (name_a[0].endsWith(":")) {
if (name_b.length > 0) {
wikiName = name_b[0];
}
// spaceName
} else {
wikiName = getContext().getDatabase();
if (name_b.length > 0) {
spaceName = name_b[0];
}
}
if (name_a.length > 1) {
docName = name_a[1];
}
EntityReference entRef = new EntityReference(wikiName, EntityType.WIKI);
if (spaceName.length() > 0) {
entRef = new EntityReference(spaceName, EntityType.SPACE, entRef);
if (docName.length() > 0) {
entRef = new EntityReference(docName, EntityType.DOCUMENT, entRef);
}
}
LOGGER.debug("resolveEntityReference: for [{}] returning [{}].", name, entRef);
return entRef;
}
/**
* @deprecated since 2.14.0 use getSubNodesForParent(EntityReference, INavFilter) or
* getSubNodesForParent(EntityReference, String) instead
*/
@Deprecated
@Override
public <T> List<T> getSubMenuItemsForParent(String parent, String menuSpace,
INavFilter<T> filter) {
if ("".equals(menuSpace)) {
menuSpace = getContext().getDoc().getSpace();
}
String parentKey = getParentKey(parent, menuSpace);
ArrayList<T> menuArray = new ArrayList<T>();
for (BaseObject baseObj : fetchMenuItemsForXWiki(parentKey)) {
if (filter.includeMenuItem(baseObj, getContext())) {
// show only Menuitems of pages accessible to the current user
menuArray.add(filter.convertObject(baseObj, getContext()));
}
}
return menuArray;
}
@Override
public Integer getMaxConfiguredNavigationLevel() {
List<BaseObject> navConfigObjects = new Vector<BaseObject>();
List<BaseObject> navConfigDocsObjs = getNavObjectsOnConfigDocs();
if (navConfigDocsObjs != null) {
navConfigObjects.addAll(navConfigDocsObjs);
}
List<BaseObject> navConfigLayoutObjs = getNavObjectsFromLayout();
if (navConfigLayoutObjs != null) {
navConfigObjects.addAll(navConfigLayoutObjs);
}
if ((navConfigObjects != null) && (!navConfigObjects.isEmpty())) {
int maxLevel = 0;
for (BaseObject navObj : navConfigObjects) {
if (navObj != null) {
maxLevel = Math.max(maxLevel, navObj.getIntValue(
INavigationClassConfig.TO_HIERARCHY_LEVEL_FIELD));
}
}
return maxLevel;
}
return Navigation.DEFAULT_MAX_LEVEL;
}
List<BaseObject> getNavObjectsFromLayout() {
List<BaseObject> navObjects = new Vector<BaseObject>();
SpaceReference layoutRef = getPageLayoutCmd().getPageLayoutForCurrentDoc();
if (layoutRef != null) {
XObjectIterator objectIterator = new XObjectIterator(getContext());
List<String> layoutCellList = new Vector<String>();
List<TreeNode> subNodesForParent = getSubNodesForParent(layoutRef, "");
while (!subNodesForParent.isEmpty()) {
List<TreeNode> newSubNodes = new Vector<TreeNode>();
for (TreeNode node : subNodesForParent) {
List<TreeNode> subNodes = getSubNodesForParent(node.getDocumentReference(), "");
newSubNodes.addAll(subNodes);
if (subNodes.isEmpty()) {
layoutCellList.add(webUtilsService.getRefDefaultSerializer().serialize(
node.getDocumentReference()));
}
}
subNodesForParent = newSubNodes;
}
objectIterator.setDocList(layoutCellList);
objectIterator.setClassName(INavigationClassConfig.NAVIGATION_CONFIG_CLASS);
for (BaseObject navConfigObj : objectIterator) {
navObjects.add(navConfigObj);
}
}
return navObjects;
}
private List<BaseObject> getNavObjectsOnConfigDocs() {
List<BaseObject> navConfigObjects2 = Collections.emptyList();
try {
BaseCollection navConfigObj = getInheritorFactory().getConfigDocFieldInheritor(
INavigationClassConfig.NAVIGATION_CONFIG_CLASS, getParentKey(
getContext().getDoc().getDocumentReference(), false), getContext()).getObject(
"menu_element_name");
if (navConfigObj != null) {
XWikiDocument navConfigDoc = getContext().getWiki().getDocument(
navConfigObj.getDocumentReference(), getContext());
String navConfigDocWikiName = navConfigDoc.getDocumentReference().getLastSpaceReference().getParent().getName();
navConfigObjects2 = navConfigDoc.getXObjects(navClassConfig.getNavigationConfigClassRef(
navConfigDocWikiName));
} else {
LOGGER.info("no config object found");
}
} catch (XWikiException exp) {
LOGGER.error("unable to get configDoc.", exp);
}
return navConfigObjects2;
}
@Override
public TreeNode getPrevMenuItem(DocumentReference docRef) throws XWikiException {
return getSiblingMenuItem(docRef, true);
}
@Override
public TreeNode getNextMenuItem(DocumentReference docRef) throws XWikiException {
return getSiblingMenuItem(docRef, false);
}
TreeNode getSiblingMenuItem(DocumentReference docRef, boolean previous) throws XWikiException {
XWikiDocument doc = getContext().getWiki().getDocument(docRef, getContext());
BaseObject menuItem = doc.getXObject(getRef("Celements2", "MenuItem"));
if (menuItem != null) {
try {
EntityReference parent = getParentEntityRef(docRef);
List<TreeNode> subMenuItems = getSubNodesForParent(parent, menuItem.getStringValue(
"part_name"));
LOGGER.debug("getPrevMenuItem: {} subMenuItems found for parent '{}'. {}",
subMenuItems.size(), parent, Arrays.deepToString(subMenuItems.toArray()));
int pos = getMenuItemPos(docRef, menuItem.getStringValue("part_name"));
if (previous && (pos > 0)) {
return subMenuItems.get(pos - 1);
} else if (!previous && (pos < (subMenuItems.size() - 1))) {
return subMenuItems.get(pos + 1);
}
LOGGER.info("getPrevMenuItem: no previous MenuItem found for {}", getParentKey(docRef,
true));
} catch (XWikiException exp) {
LOGGER.error("getSiblingMenuItem failed.", exp);
}
} else {
LOGGER.debug("getPrevMenuItem: no MenuItem Object found on doc {}", getParentKey(docRef,
true));
}
return null;
}
@Override
public List<TreeNode> getMenuItemsForHierarchyLevel(int menuLevel, String menuPart) {
DocumentReference parent = webUtilsService.getParentForLevel(menuLevel);
if (parent != null) {
List<TreeNode> submenuItems = getSubNodesForParent(parent, menuPart);
LOGGER.debug("submenuItems for parent: {} ; {}", parent, submenuItems);
return submenuItems;
}
LOGGER.debug("parent is null");
return new ArrayList<TreeNode>();
}
@Override
public void enableMappedMenuItems() {
GetMappedMenuItemsForParentCommand cmd = new GetMappedMenuItemsForParentCommand();
cmd.setIsActive(true);
getContext().put(GetMappedMenuItemsForParentCommand.CELEMENTS_MAPPED_MENU_ITEMS_KEY, cmd);
}
DocumentReference getRef(String spaceName, String pageName) {
return new DocumentReference(getContext().getDatabase(), spaceName, pageName);
}
/**
* getParentReference returns only DocumentReference or SpaceReference even though the
* return type is an EntityReference
*/
@Override
public EntityReference getParentReference(DocumentReference docRef) {
try {
return getParentEntityRef(docRef);
} catch (XWikiException exp) {
LOGGER.error("Failed to getParentReference for [{}].", docRef, exp);
}
return null;
}
/**
* getParentEntityRef returns only DocumentReference or SpaceReference even though the
* return type is an EntityReference
*/
@Override
public EntityReference getParentEntityRef(DocumentReference docRef) throws XWikiException {
EntityReference parentRef = getContext().getWiki().getDocument(docRef,
getContext()).getParentReference();
if ((parentRef == null) || (docRef.equals(parentRef))) {
parentRef = docRef.getLastSpaceReference();
}
return parentRef;
}
/**
* FOR TEST PURPOSES ONLY
*/
public void injectInheritorFactory(InheritorFactory injectedInheritorFactory) {
this.injectedInheritorFactory = injectedInheritorFactory;
}
private InheritorFactory getInheritorFactory() {
if (injectedInheritorFactory != null) {
return injectedInheritorFactory;
}
return new InheritorFactory();
}
/**
* TODO write unit tests and test if working
*/
@Override
public void moveTreeDocAfter(DocumentReference moveDocRef, DocumentReference insertAfterDocRef)
throws XWikiException {
if (isTreeNode(moveDocRef)) {
TreeNode insertAfterTreeNode = null;
if (insertAfterDocRef != null) {
insertAfterTreeNode = getTreeNodeForDocRef(insertAfterDocRef);
}
TreeNode moveTreeNode = getTreeNodeForDocRef(moveDocRef);
ArrayList<TreeNode> newTreeNodes = moveTreeNodeAfter(moveTreeNode, insertAfterTreeNode);
storeOrder(newTreeNodes);
} else {
LOGGER.info("Failed to moveTreeDocAfter for moveDocRef [{}] and insertAfterDocRef ["
+ "{}] because one of them is no TreeNode.", moveDocRef, insertAfterDocRef);
}
}
ArrayList<TreeNode> moveTreeNodeAfter(TreeNode moveTreeNode, TreeNode insertAfterTreeNode) {
List<TreeNode> treeNodes = new ArrayList<TreeNode>(fetchNodesForParentKey(
moveTreeNode.getParentRef()));
treeNodes.remove(moveTreeNode);
ArrayList<TreeNode> newTreeNodes = new ArrayList<TreeNode>();
int splitPos = 0;
int maxPos = treeNodes.size();
if (insertAfterTreeNode != null) {
int newSplitPos = treeNodes.indexOf(insertAfterTreeNode);
if (newSplitPos > -1) {
splitPos = newSplitPos + 1;
}
}
newTreeNodes.addAll(treeNodes.subList(0, splitPos));
newTreeNodes.add(moveTreeNode);
newTreeNodes.addAll(treeNodes.subList(splitPos, maxPos));
return newTreeNodes;
}
@Override
public TreeNode getTreeNodeForDocRef(DocumentReference docRef) throws XWikiException {
EntityReference parentRef = getParentReference(docRef);
TreeNode treeNode = null;
XWikiDocument moveDoc = getContext().getWiki().getDocument(docRef, getContext());
BaseObject menuItemObj = moveDoc.getXObject(navClassConfig.getMenuItemClassRef(
getContext().getDatabase()));
if (menuItemObj != null) {
int pos = menuItemObj.getIntValue(INavigationClassConfig.MENU_POSITION_FIELD, -1);
if (parentRef instanceof SpaceReference) {
String menuPart = menuItemObj.getStringValue(INavigationClassConfig.MENU_PART_FIELD);
treeNode = new TreeNode(docRef, parentRef, pos, menuPart);
} else if (parentRef instanceof DocumentReference) {
treeNode = new TreeNode(docRef, parentRef, pos);
}
}
return treeNode;
}
@Override
public List<TreeNode> getSiblingTreeNodes(DocumentReference moveDocRef) throws XWikiException {
TreeNode moveTreeNode = getTreeNodeForDocRef(moveDocRef);
List<TreeNode> siblingTreeNodes = getSubNodesForParent(moveTreeNode.getParentRef(),
moveTreeNode.getPartName());
return siblingTreeNodes;
}
@Override
public void storeOrder(List<TreeNode> newTreeNodes) {
storeOrder(newTreeNodes, false);
}
@Override
public void storeOrder(List<TreeNode> newTreeNodes, boolean isMinorEdit) {
int pos = -1;
XWiki wiki = getContext().getWiki();
for (TreeNode theNode : newTreeNodes) {
DocumentReference theDocRef = theNode.getDocumentReference();
try {
XWikiDocument theDoc = wiki.getDocument(theDocRef, getContext());
BaseObject menuItemObj = theDoc.getXObject(navClassConfig.getMenuItemClassRef(
getContext().getDatabase()));
if (menuItemObj != null) {
pos++;
int oldPos = menuItemObj.getIntValue(INavigationClassConfig.MENU_POSITION_FIELD, -1);
if (oldPos != pos) {
menuItemObj.setIntValue(INavigationClassConfig.MENU_POSITION_FIELD, pos);
wiki.saveDocument(theDoc, "changed menu position from '" + oldPos + "' to '" + pos
+ "'.", isMinorEdit, getContext());
}
} else {
LOGGER.error("storeOrder: failed to get menuItemObject of [{}].", theDocRef);
}
} catch (XWikiException exp) {
LOGGER.error("storeOrder: Failed to get document [{}].", theDocRef);
}
}
}
}