/* * Copyright (C) 2009 eXo Platform SAS. * * 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 org.exoplatform.services.jcr.impl.dataflow.persistent; import org.exoplatform.services.jcr.dataflow.ChangesLogIterator; import org.exoplatform.services.jcr.dataflow.CompositeChangesLog; import org.exoplatform.services.jcr.dataflow.DataManager; import org.exoplatform.services.jcr.dataflow.ItemState; import org.exoplatform.services.jcr.dataflow.PlainChangesLog; import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl; import org.exoplatform.services.jcr.dataflow.TransactionChangesLog; import org.exoplatform.services.jcr.datamodel.ItemData; import org.exoplatform.services.jcr.datamodel.ItemType; import org.exoplatform.services.jcr.datamodel.NodeData; import org.exoplatform.services.jcr.datamodel.NullItemData; import org.exoplatform.services.jcr.datamodel.PropertyData; import org.exoplatform.services.jcr.datamodel.QPath; import org.exoplatform.services.jcr.datamodel.QPathEntry; import org.exoplatform.services.jcr.impl.Constants; import org.exoplatform.services.jcr.impl.core.itemfilters.QPathEntryFilter; import org.exoplatform.services.jcr.impl.dataflow.session.TransactionableResourceManager; import org.exoplatform.services.jcr.util.IdGenerator; import java.util.ArrayList; import java.util.List; import javax.jcr.InvalidItemStateException; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. Responsible for: *redirecting repository operations if item is * descendant of /jcr:system/jcr:versionStorage *adding version history for newly added/assigned * mix:versionable * * @author <a href="mailto:gennady.azarenkov@exoplatform.com">Gennady Azarenkov</a> * @version $Id$ */ public class VersionableWorkspaceDataManager extends ShareableSupportedWorkspaceDataManager { private ShareableSupportedWorkspaceDataManager versionDataManager; /** * The resource manager */ private final TransactionableResourceManager txResourceManager; public VersionableWorkspaceDataManager(CacheableWorkspaceDataManager persistentManager, TransactionableResourceManager txResourceManager) { super(persistentManager); this.txResourceManager = txResourceManager; } /** * Called by WorkspaceContainer after repository initialization. */ public void setSystemDataManager(DataManager systemDataManager) { this.versionDataManager = (ShareableSupportedWorkspaceDataManager)systemDataManager; } /** * {@inheritDoc} */ @Override public List<NodeData> getChildNodesData(final NodeData nodeData) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.getChildNodesData(nodeData); } return super.getChildNodesData(nodeData); } /** * {@inheritDoc} */ @Override public boolean getChildNodesDataByPage(NodeData nodeData, int fromOrderNum, int offset,int pageSize, List<NodeData> childs) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.getChildNodesDataByPage(nodeData, fromOrderNum, offset, pageSize, childs); } return super.getChildNodesDataByPage(nodeData, fromOrderNum, offset, pageSize, childs); } /** * {@inheritDoc} */ @Override public List<NodeData> getChildNodesData(final NodeData nodeData, final List<QPathEntryFilter> patternFilters) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.getChildNodesData(nodeData, patternFilters); } return super.getChildNodesData(nodeData, patternFilters); } /** * {@inheritDoc} */ @Override public int getChildNodesCount(final NodeData parent) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(parent.getQPath())) { return versionDataManager.getChildNodesCount(parent); } return super.getChildNodesCount(parent); } /** * {@inheritDoc} */ @Override public int getLastOrderNumber(final NodeData parent) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(parent.getQPath())) { return versionDataManager.getLastOrderNumber(parent); } return super.getLastOrderNumber(parent); } /** * {@inheritDoc} */ @Override public List<PropertyData> getChildPropertiesData(final NodeData nodeData) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.getChildPropertiesData(nodeData); } return super.getChildPropertiesData(nodeData); } /** * {@inheritDoc} */ @Override public List<PropertyData> getChildPropertiesData(final NodeData nodeData, final List<QPathEntryFilter> itemDataFilters) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.getChildPropertiesData(nodeData, itemDataFilters); } return super.getChildPropertiesData(nodeData, itemDataFilters); } /** * {@inheritDoc} */ @Override public List<PropertyData> listChildPropertiesData(final NodeData nodeData) throws RepositoryException { if (!this.equals(versionDataManager) && isSystemDescendant(nodeData.getQPath())) { return versionDataManager.listChildPropertiesData(nodeData); } return super.listChildPropertiesData(nodeData); } /** * {@inheritDoc} */ @Override public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException { return getItemData(parentData, name, itemType, true); } /** * {@inheritDoc} */ public boolean hasItemData(NodeData parentData, QPathEntry name, ItemType itemType) throws RepositoryException { if (parentData != null) { final QPath ipath = QPath.makeChildPath(parentData.getQPath(), name); if (!this.equals(versionDataManager) && isSystemDescendant(ipath)) { return versionDataManager.hasItemData(parentData, name, itemType); } } return super.hasItemData(parentData, name, itemType); } /** * {@inheritDoc} */ public ItemData getItemData(NodeData parentData, QPathEntry name, ItemType itemType, boolean createNullItemData) throws RepositoryException { if (parentData != null) { final QPath ipath = QPath.makeChildPath(parentData.getQPath(), name); if (!this.equals(versionDataManager) && isSystemDescendant(ipath)) { return versionDataManager.getItemData(parentData, name, itemType, createNullItemData); } } return super.getItemData(parentData, name, itemType, createNullItemData); } /** * {@inheritDoc} */ @Override public ItemData getItemData(String identifier) throws RepositoryException { // from cache at first ItemData cdata = persistentManager.getCachedItemData(identifier); if (cdata != null && !(cdata instanceof NullItemData)) { return super.getItemData(identifier); } if (!this.equals(versionDataManager) && !identifier.equals(Constants.ROOT_UUID)) { // search in System cache for /jcr:system nodes only cdata = versionDataManager.persistentManager.getCachedItemData(identifier); if (cdata != null && !(cdata instanceof NullItemData)) { if (isSystemDescendant(cdata.getQPath())) { return versionDataManager.getItemData(identifier); } else { return null; } } } // then from persistence ItemData data = super.getItemData(identifier); if (data != null) { return data; } else if (!this.equals(versionDataManager)) { // try from version storage if not the same data = versionDataManager.getItemData(identifier); if (data != null && isSystemDescendant(data.getQPath())) { return data; } } return null; } public void save(CompositeChangesLog changesLog) throws RepositoryException, InvalidItemStateException { save(changesLog, false); } public void save(CompositeChangesLog changesLog, boolean versionLogsFirst) throws RepositoryException, InvalidItemStateException { final ChangesLogIterator logIterator = changesLog.getLogIterator(); final TransactionChangesLog versionLogs = new TransactionChangesLog(); final TransactionChangesLog nonVersionLogs = new TransactionChangesLog(); while (logIterator.hasNextLog()) { List<ItemState> vstates = new ArrayList<ItemState>(); List<ItemState> nvstates = new ArrayList<ItemState>(); PlainChangesLog changes = logIterator.nextLog(); if (this.equals(versionDataManager)) { nvstates.addAll(changes.getAllStates()); } else { for (ItemState change : changes.getAllStates()) { if (isSystemDescendant(change.getData().getQPath())) { vstates.add(change); } else { nvstates.add(change); } } } if (!vstates.isEmpty()) { if (!nvstates.isEmpty()) { // we have pair of logs for system and non-system (this) workspaces final String pairId = IdGenerator.generate(); versionLogs.addLog(PlainChangesLogImpl.createCopy(vstates, pairId, changes)); nonVersionLogs.addLog(PlainChangesLogImpl.createCopy(nvstates, pairId, changes)); } else { versionLogs.addLog(PlainChangesLogImpl.createCopy(vstates, changes)); nonVersionLogs.addLog(PlainChangesLogImpl.createCopy(nvstates, changes)); } } else if (!nvstates.isEmpty()) { nonVersionLogs.addLog(PlainChangesLogImpl.createCopy(nvstates, changes)); } } if (versionLogsFirst && versionLogs.getSize() > 0) { versionDataManager.save(versionLogs, txResourceManager); } if (nonVersionLogs.getSize() > 0) { super.save(nonVersionLogs); } if (!versionLogsFirst && versionLogs.getSize() > 0) { versionDataManager.save(versionLogs, txResourceManager); } } private boolean isSystemDescendant(QPath path) { return path.isDescendantOf(Constants.JCR_SYSTEM_PATH) || path.equals(Constants.JCR_SYSTEM_PATH); } }