/* * 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.xml; import org.exoplatform.services.jcr.access.AccessManager; import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager; import org.exoplatform.services.jcr.dataflow.ItemDataConsumer; import org.exoplatform.services.jcr.dataflow.ItemState; import org.exoplatform.services.jcr.dataflow.PlainChangesLogImpl; import org.exoplatform.services.jcr.datamodel.ItemType; import org.exoplatform.services.jcr.datamodel.NodeData; 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.RepositoryImpl; import org.exoplatform.services.jcr.impl.core.SessionImpl; import org.exoplatform.services.jcr.impl.dataflow.ItemDataRemoveVisitor; import org.exoplatform.services.jcr.impl.dataflow.ValueDataUtil; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.security.ConversationState; import java.util.List; import javax.jcr.RepositoryException; /** * Created by The eXo Platform SAS. Helper class for removing version history. * * @author <a href="mailto:Sergey.Kabashnyuk@gmail.com">Sergey Kabashnyuk</a> * @version $Id: $ */ public class VersionHistoryRemover { /** * Class logger. */ private final Log log = ExoLogger.getLogger("exo.jcr.component.core.VersionHistoryRemover"); /** * Version history identifier. */ private final String vhID; /** * ItemDataConsumer. */ private final ItemDataConsumer dataManager; /** * NodeTypeManager. */ private final NodeTypeDataManager ntManager; /** * Repository. */ private final RepositoryImpl repository; /** * Current workspace name. */ private final String currentWorkspaceName; /** * Containing history path. */ private final QPath containingHistory; /** * Ancestor to save. */ private final QPath ancestorToSave; /** * Changes log. */ private final PlainChangesLogImpl transientChangesLog; /** * Access manager. */ private final AccessManager accessManager; /** * User state. */ private final ConversationState userState; /** * @param vhID - version history identifier. * @param dataManager - ItemDataConsumer. * @param ntManager - NodeTypeManagerImpl. * @param repository - RepositoryImpl. * @param currentWorkspaceName - current workspace name. * @param containingHistory - containingHistory. * @param ancestorToSave - ancestor to save. * @param transientChangesLog - changes log. * @param accessManager - access manager. * @param userState - user state. */ public VersionHistoryRemover(String vhID, ItemDataConsumer dataManager, NodeTypeDataManager ntManager, RepositoryImpl repository, String currentWorkspaceName, QPath containingHistory, QPath ancestorToSave, PlainChangesLogImpl transientChangesLog, AccessManager accessManager, ConversationState userState) { super(); this.vhID = vhID; this.dataManager = dataManager; this.ntManager = ntManager; this.repository = repository; this.currentWorkspaceName = currentWorkspaceName; this.containingHistory = containingHistory; this.ancestorToSave = ancestorToSave; this.transientChangesLog = transientChangesLog; this.accessManager = accessManager; this.userState = userState; } /** * Remove history. * * @exception RepositoryException if an repository error occurs. */ public void remove() throws RepositoryException { NodeData vhnode = (NodeData)dataManager.getItemData(vhID); if (vhnode == null) { ItemState vhState = null; List<ItemState> allStates = transientChangesLog.getAllStates(); for (int i = allStates.size() - 1; i >= 0; i--) { ItemState state = allStates.get(i); if (state.getData().getIdentifier().equals(vhID)) vhState = state; } if (vhState != null && vhState.isDeleted()) { return; } throw new RepositoryException("Version history is not found. UUID: " + vhID + ". Context item (ancestor to save) " + ancestorToSave.getAsString()); } // mix:versionable // we have to be sure that any versionable node somewhere in repository // doesn't refers to a VH of the node being deleted. for (String wsName : repository.getWorkspaceNames()) { SessionImpl wsSession = repository.getSystemSession(wsName); try { for (PropertyData sref : wsSession.getTransientNodesManager().getReferencesData(vhID, false)) { // Check if this VH isn't referenced from somewhere in workspace // or isn't contained in another one as a child history. // Ask ALL references incl. properties from version storage. if (sref.getQPath().isDescendantOf(Constants.JCR_VERSION_STORAGE_PATH)) { if (!sref.getQPath().isDescendantOf(vhnode.getQPath()) && (containingHistory != null ? !sref.getQPath().isDescendantOf(containingHistory) : true)) // has a reference to the VH in version storage, // it's a REFERENCE property jcr:childVersionHistory of // nt:versionedChild // i.e. this VH is a child history in an another history. // We can't remove this VH now. return; } else if (!currentWorkspaceName.equals(wsName)) { // has a reference to the VH in traversed workspace, // it's not a version storage, i.e. it's a property of versionable // node somewhere in ws. // We can't remove this VH now. return; } // else -- if we has a references in workspace where the VH is being // deleted we can remove VH now. } } finally { wsSession.logout(); } } // remove child versions from VH (if found) // ChildVersionRemoveVisitor cvremover = new // ChildVersionRemoveVisitor(session, // vhnode.getQPath(), // ancestorToSave); // vhnode.accept(cvremover); List<NodeData> childs = dataManager.getChildNodesData(vhnode); for (NodeData nodeData : childs) { if (ntManager.isNodeType(Constants.NT_VERSIONEDCHILD, vhnode.getPrimaryTypeName(), vhnode.getMixinTypeNames())) { PropertyData property = (PropertyData)dataManager.getItemData(nodeData, new QPathEntry(Constants.JCR_CHILDVERSIONHISTORY, 1), ItemType.PROPERTY); if (property == null) throw new RepositoryException("Property " + Constants.JCR_CHILDVERSIONHISTORY.getAsString() + " for node " + nodeData.getQPath().getAsString() + " not found"); String childVhID = ValueDataUtil.getString(property.getValues().get(0)); VersionHistoryRemover historyRemover = new VersionHistoryRemover(childVhID, dataManager, ntManager, repository, currentWorkspaceName, containingHistory, ancestorToSave, transientChangesLog, accessManager, userState); historyRemover.remove(); } } // remove VH ItemDataRemoveVisitor visitor = new ItemDataRemoveVisitor(dataManager, ancestorToSave); vhnode.accept(visitor); transientChangesLog.addAll(visitor.getRemovedStates()); }; }