/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library 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 library 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. */ package com.liferay.portal.kernel.tree; import com.liferay.portal.kernel.exception.PortalException; import com.liferay.portal.kernel.model.TreeModel; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.kernel.util.PropsUtil; import com.liferay.portal.kernel.util.ReflectionUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.VerifyThreadLocal; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; /** * @author Shinn Lok */ public class TreePathUtil { public static void rebuildTree( long companyId, long parentPrimaryKey, String parentTreePath, TreeModelTasks<?> treeModelTasks) throws PortalException { if (VerifyThreadLocal.isVerifyInProgress() && _VERIFY_DATABASE_TRANSACTIONS_DISABLED) { ForkJoinPool forkJoinPool = new ForkJoinPool(); try { forkJoinPool.invoke( new RecursiveRebuildTreeTask( treeModelTasks, companyId, parentPrimaryKey, parentTreePath, 0L)); } finally { forkJoinPool.shutdown(); } return; } Deque<Object[]> traces = new LinkedList<>(); traces.push(new Object[] {parentPrimaryKey, parentTreePath, 0L}); Object[] trace = null; while ((trace = traces.poll()) != null) { Long curParentPrimaryKey = (Long)trace[0]; String curParentTreePath = (String)trace[1]; Long previousPrimaryKey = (Long)trace[2]; treeModelTasks.rebuildDependentModelsTreePaths( curParentPrimaryKey, curParentTreePath); List<? extends TreeModel> treeModels = treeModelTasks.findTreeModels( previousPrimaryKey, companyId, curParentPrimaryKey, _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE); if (treeModels.isEmpty()) { continue; } if (treeModels.size() == _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE) { TreeModel treeModel = treeModels.get(treeModels.size() - 1); trace[2] = treeModel.getPrimaryKeyObj(); traces.push(trace); } for (TreeModel treeModel : treeModels) { String treePath = curParentTreePath.concat( String.valueOf(treeModel.getPrimaryKeyObj())).concat( StringPool.SLASH); if (!treePath.equals(treeModel.getTreePath())) { treeModel.updateTreePath(treePath); } traces.push( new Object[] {treeModel.getPrimaryKeyObj(), treePath, 0L}); } } } private static final int _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE = GetterUtil.getInteger( PropsUtil.get( PropsKeys.MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE)); private static final boolean _VERIFY_DATABASE_TRANSACTIONS_DISABLED = GetterUtil.getBoolean( PropsUtil.get(PropsKeys.VERIFY_DATABASE_TRANSACTIONS_DISABLED)); private static class RecursiveRebuildTreeTask extends RecursiveAction { @Override protected void compute() { try { _treeModelTasks.rebuildDependentModelsTreePaths( _parentPrimaryKey, _parentTreePath); } catch (PortalException pe) { ReflectionUtil.throwException(pe); } List<? extends TreeModel> treeModels = _treeModelTasks.findTreeModels( _previousPrimaryKey, _companyId, _parentPrimaryKey, _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE); if (treeModels.isEmpty()) { return; } if (treeModels.size() == _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE) { TreeModel treeModel = treeModels.get(treeModels.size() - 1); RecursiveRebuildTreeTask recursiveRebuildTreeTask = new RecursiveRebuildTreeTask( _treeModelTasks, _companyId, _parentPrimaryKey, _parentTreePath, (long)treeModel.getPrimaryKeyObj()); recursiveRebuildTreeTask.fork(); } for (TreeModel treeModel : treeModels) { String treePath = _parentTreePath.concat( String.valueOf(treeModel.getPrimaryKeyObj())).concat( StringPool.SLASH); if (!treePath.equals(treeModel.getTreePath())) { treeModel.updateTreePath(treePath); } RecursiveRebuildTreeTask recursiveRebuildTreeTask = new RecursiveRebuildTreeTask( _treeModelTasks, _companyId, (long)treeModel.getPrimaryKeyObj(), treePath, 0L); recursiveRebuildTreeTask.fork(); } } private RecursiveRebuildTreeTask( TreeModelTasks<?> treeModelTasks, long companyId, long parentPrimaryKey, String parentTreePath, long previousPrimaryKey) { _treeModelTasks = treeModelTasks; _companyId = companyId; _parentPrimaryKey = parentPrimaryKey; _parentTreePath = parentTreePath; _previousPrimaryKey = previousPrimaryKey; } private final long _companyId; private final long _parentPrimaryKey; private final String _parentTreePath; private final long _previousPrimaryKey; private final TreeModelTasks<?> _treeModelTasks; } }