001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.tree;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.model.TreeModel;
019    import com.liferay.portal.kernel.util.GetterUtil;
020    import com.liferay.portal.kernel.util.PropsKeys;
021    import com.liferay.portal.kernel.util.PropsUtil;
022    import com.liferay.portal.kernel.util.ReflectionUtil;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.VerifyThreadLocal;
025    
026    import java.util.Deque;
027    import java.util.LinkedList;
028    import java.util.List;
029    import java.util.concurrent.ForkJoinPool;
030    import java.util.concurrent.RecursiveAction;
031    
032    /**
033     * @author Shinn Lok
034     */
035    public class TreePathUtil {
036    
037            public static void rebuildTree(
038                            long companyId, long parentPrimaryKey, String parentTreePath,
039                            TreeModelTasks<?> treeModelTasks)
040                    throws PortalException {
041    
042                    if (VerifyThreadLocal.isVerifyInProgress() &&
043                            _VERIFY_DATABASE_TRANSACTIONS_DISABLED) {
044    
045                            ForkJoinPool forkJoinPool = new ForkJoinPool();
046    
047                            try {
048                                    forkJoinPool.invoke(
049                                            new RecursiveRebuildTreeTask(
050                                                    treeModelTasks, companyId, parentPrimaryKey,
051                                                    parentTreePath, 0L));
052                            }
053                            finally {
054                                    forkJoinPool.shutdown();
055                            }
056    
057                            return;
058                    }
059    
060                    Deque<Object[]> traces = new LinkedList<>();
061    
062                    traces.push(new Object[] {parentPrimaryKey, parentTreePath, 0L});
063    
064                    Object[] trace = null;
065    
066                    while ((trace = traces.poll()) != null) {
067                            Long curParentPrimaryKey = (Long)trace[0];
068                            String curParentTreePath = (String)trace[1];
069                            Long previousPrimaryKey = (Long)trace[2];
070    
071                            treeModelTasks.rebuildDependentModelsTreePaths(
072                                    curParentPrimaryKey, curParentTreePath);
073    
074                            List<? extends TreeModel> treeModels =
075                                    treeModelTasks.findTreeModels(
076                                            previousPrimaryKey, companyId, curParentPrimaryKey,
077                                            _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE);
078    
079                            if (treeModels.isEmpty()) {
080                                    continue;
081                            }
082    
083                            if (treeModels.size() ==
084                                            _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE) {
085    
086                                    TreeModel treeModel = treeModels.get(treeModels.size() - 1);
087    
088                                    trace[2] = treeModel.getPrimaryKeyObj();
089    
090                                    traces.push(trace);
091                            }
092    
093                            for (TreeModel treeModel : treeModels) {
094                                    String treePath = curParentTreePath.concat(
095                                            String.valueOf(treeModel.getPrimaryKeyObj())).concat(
096                                                    StringPool.SLASH);
097    
098                                    if (!treePath.equals(treeModel.getTreePath())) {
099                                            treeModel.updateTreePath(treePath);
100                                    }
101    
102                                    traces.push(
103                                            new Object[] {treeModel.getPrimaryKeyObj(), treePath, 0L});
104                            }
105                    }
106            }
107    
108            private static final int _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE =
109                    GetterUtil.getInteger(
110                            PropsUtil.get(
111                                    PropsKeys.MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE));
112    
113            private static final boolean _VERIFY_DATABASE_TRANSACTIONS_DISABLED =
114                    GetterUtil.getBoolean(
115                            PropsUtil.get(PropsKeys.VERIFY_DATABASE_TRANSACTIONS_DISABLED));
116    
117            private static class RecursiveRebuildTreeTask extends RecursiveAction {
118    
119                    @Override
120                    protected void compute() {
121                            try {
122                                    _treeModelTasks.rebuildDependentModelsTreePaths(
123                                            _parentPrimaryKey, _parentTreePath);
124                            }
125                            catch (PortalException pe) {
126                                    ReflectionUtil.throwException(pe);
127                            }
128    
129                            List<? extends TreeModel> treeModels =
130                                    _treeModelTasks.findTreeModels(
131                                            _previousPrimaryKey, _companyId, _parentPrimaryKey,
132                                            _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE);
133    
134                            if (treeModels.isEmpty()) {
135                                    return;
136                            }
137    
138                            if (treeModels.size() ==
139                                            _MODEL_TREE_REBUILD_QUERY_RESULTS_BATCH_SIZE) {
140    
141                                    TreeModel treeModel = treeModels.get(treeModels.size() - 1);
142    
143                                    RecursiveRebuildTreeTask recursiveRebuildTreeTask =
144                                            new RecursiveRebuildTreeTask(
145                                                    _treeModelTasks, _companyId, _parentPrimaryKey,
146                                                    _parentTreePath, (long)treeModel.getPrimaryKeyObj());
147    
148                                    recursiveRebuildTreeTask.fork();
149                            }
150    
151                            for (TreeModel treeModel : treeModels) {
152                                    String treePath = _parentTreePath.concat(
153                                            String.valueOf(treeModel.getPrimaryKeyObj())).concat(
154                                                    StringPool.SLASH);
155    
156                                    if (!treePath.equals(treeModel.getTreePath())) {
157                                            treeModel.updateTreePath(treePath);
158                                    }
159    
160                                    RecursiveRebuildTreeTask recursiveRebuildTreeTask =
161                                            new RecursiveRebuildTreeTask(
162                                                    _treeModelTasks, _companyId,
163                                                    (long)treeModel.getPrimaryKeyObj(), treePath, 0L);
164    
165                                    recursiveRebuildTreeTask.fork();
166                            }
167                    }
168    
169                    private RecursiveRebuildTreeTask(
170                            TreeModelTasks<?> treeModelTasks, long companyId,
171                            long parentPrimaryKey, String parentTreePath,
172                            long previousPrimaryKey) {
173    
174                            _treeModelTasks = treeModelTasks;
175                            _companyId = companyId;
176                            _parentPrimaryKey = parentPrimaryKey;
177                            _parentTreePath = parentTreePath;
178                            _previousPrimaryKey = previousPrimaryKey;
179                    }
180    
181                    private final long _companyId;
182                    private final long _parentPrimaryKey;
183                    private final String _parentTreePath;
184                    private final long _previousPrimaryKey;
185                    private final TreeModelTasks<?> _treeModelTasks;
186    
187            }
188    
189    }