All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.db.CmsPublishList Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * 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.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.opencms.db;

import org.opencms.file.CmsObject;
import org.opencms.file.CmsProject;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.file.CmsVfsResourceNotFoundException;
import org.opencms.file.I_CmsResource;
import org.opencms.main.CmsException;
import org.opencms.main.CmsIllegalArgumentException;
import org.opencms.main.CmsLog;
import org.opencms.util.CmsFileUtil;
import org.opencms.util.CmsUUID;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;

/**
 * A container for all new/changed/deteled Cms resources that are published together.

* * Only classes inside the org.opencms.db package can add or remove elements to or from this list. * This allows the OpenCms API to pass the list around between classes, but with restricted access to * create this list.

* * To create a publish list, one of the public constructors must be used in order to set the basic operation mode * (project publish or direct publish). * After this, use {@link org.opencms.db.CmsDriverManager#fillPublishList(CmsDbContext, CmsPublishList)} * to fill the actual values of the publish list.

* * @since 6.0.0 * * @see org.opencms.db.CmsDriverManager#fillPublishList(CmsDbContext, CmsPublishList) */ public class CmsPublishList implements Externalizable { /** The log object for this class. */ private static final Log LOG = CmsLog.getLog(CmsPublishList.class); /** Indicates a non existent object in the serialized data. */ private static final int NIL = -1; /** Serial version UID required for safe serialization. */ private static final long serialVersionUID = -2578909250462750927L; /** Length of a serialized uuid. */ private static final int UUID_LENGTH = CmsUUID.getNullUUID().toByteArray().length; /** The list of deleted folder resources to be published.

*/ private List m_deletedFolderList; /** The list of deleted folder UUIDs to be published for later retrieval.

*/ private List m_deletedFolderUUIDs; /** The list of direct publish resources. */ private List m_directPublishResources; /** The list of direct publish resource UUIDs to be published for later retrieval.

*/ private List m_directPublishResourceUUIDs; /** The list of new/changed/deleted file resources to be published.

*/ private List m_fileList; /** The list of new/changed/deleted file resource UUIDs to be published for later retrieval.

*/ private List m_fileUUIDs; /** The list of new/changed folder resources to be published.

*/ private List m_folderList; /** The list of new/changed folder resource UUIDs to be published for later retrieval.

*/ private List m_folderUUIDs; /** Indicates whether this is a user publish list. */ private boolean m_isUserPublishList; /** Flag to indicate if the list needs to be revived. */ private boolean m_needsRevive; /** The id of the project that is to be published. */ private CmsUUID m_projectId; /** The publish history ID.

*/ private CmsUUID m_publishHistoryId; /** Indicates if siblings of the resources in the list should also be published. */ private boolean m_publishSiblings; /** Indicates if sub-resources in folders should be published (for direct publish only). */ private boolean m_publishSubResources; /** * Empty constructor.

*/ public CmsPublishList() { // noop } /** * Constructs a publish list for a list of direct publish resources.

* * @param all no redundant resource are filtered out * @param directPublishResources a list of {@link CmsResource} instances to be published directly * @param directPublishSiblings indicates if all siblings of the selected resources should be published */ public CmsPublishList(boolean all, List directPublishResources, boolean directPublishSiblings) { this(null, directPublishResources, directPublishSiblings, false, true); } /** * Constructs a publish list for a given project.

* * @param project the project to publish, this should always be the id of the current project */ public CmsPublishList(CmsProject project) { this(project, null, false, true, false); } /** * Constructs a publish list for a single direct publish resource.

* * @param directPublishResource a VFS resource to be published directly * @param publishSiblings indicates if all siblings of the selected resources should be published */ public CmsPublishList(CmsResource directPublishResource, boolean publishSiblings) { this(null, Collections.singletonList(directPublishResource), publishSiblings, true, false); } /** * Constructs a publish list for a list of direct publish resources.

* * @param directPublishResources a list of {@link CmsResource} instances to be published directly * @param publishSiblings indicates if all siblings of the selected resources should be published */ public CmsPublishList(List directPublishResources, boolean publishSiblings) { this(null, directPublishResources, publishSiblings, true, false); } /** * Constructs a publish list for a list of direct publish resources.

* * @param directPublishResources a list of {@link CmsResource} instances to be published directly * @param publishSiblings indicates if all siblings of the selected resources should be published * @param publishSubResources indicates if sub-resources in folders should be published (for direct publish only) */ public CmsPublishList( List directPublishResources, boolean publishSiblings, boolean publishSubResources) { this(null, directPublishResources, publishSiblings, publishSubResources, false); } /** * Internal constructor for a publish list.

* * @param project the project to publish * @param directPublishResources the list of direct publish resources * @param publishSiblings indicates if all siblings of the selected resources should be published * @param publishSubResources indicates if sub-resources in folders should be published (for direct publish only) * @param all if true the publish list will not be filtered for redundant resources */ private CmsPublishList( CmsProject project, List directPublishResources, boolean publishSiblings, boolean publishSubResources, boolean all) { m_fileList = new ArrayList(); m_folderList = new ArrayList(); m_deletedFolderList = new ArrayList(); m_publishHistoryId = new CmsUUID(); m_publishSiblings = publishSiblings; m_publishSubResources = publishSubResources; m_projectId = (project != null) ? project.getUuid() : null; if (directPublishResources != null) { if (!all) { // reduce list of folders to minimum m_directPublishResources = Collections.unmodifiableList( CmsFileUtil.removeRedundantResources(directPublishResources)); } else { m_directPublishResources = Collections.unmodifiableList(directPublishResources); } } } /** * Returns a list of all resources in the publish list, * including folders and files.

* * @return a list of {@link CmsResource} objects */ public List getAllResources() { List all = new ArrayList(); all.addAll(m_folderList); all.addAll(m_fileList); all.addAll(m_deletedFolderList); Collections.sort(all, I_CmsResource.COMPARE_ROOT_PATH); return Collections.unmodifiableList(all); } /** * Returns a list of folder resources with the deleted state.

* * @return a list of folder resources with the deleted state */ public List getDeletedFolderList() { if (m_needsRevive) { return null; } else { return m_deletedFolderList; } } /** * Returns the list of resources that should be published for a "direct" publish operation.

* * Will return null if this publish list was not initialized for a "direct publish" but * for a project publish.

* * @return the list of resources that should be published for a "direct" publish operation, or null */ public List getDirectPublishResources() { if (m_needsRevive) { return null; } else { return m_directPublishResources; } } /** * Returns an unmodifiable list of the files in this publish list.

* * @return the list with the files in this publish list */ public List getFileList() { if (m_needsRevive) { return null; } else { return Collections.unmodifiableList(m_fileList); } } /** * Returns an unmodifiable list of the new/changed folders in this publish list.

* * @return the list with the new/changed folders in this publish list */ public List getFolderList() { if (m_needsRevive) { return null; } else { return Collections.unmodifiableList(m_folderList); } } /** * Returns the id of the project that should be published, or -1 if this publish list * is initialized for a "direct publish" operation.

* * @return the id of the project that should be published, or -1 */ public CmsUUID getProjectId() { return m_projectId; } /** * Returns the publish history Id for this publish list.

* * @return the publish history Id */ public CmsUUID getPublishHistoryId() { return m_publishHistoryId; } /** * Gets the list of moved folders which are not subfolders of other moved folders in the publish list.

* @param cms the current cms context * @return the moved folders which are not subfolders of other moved folders in the publish list * @throws CmsException if something goes wrong */ public List getTopMovedFolders(CmsObject cms) throws CmsException { List movedFolders = getMovedFolders(cms); List result = getTopFolders(movedFolders); return result; } /** * Checks if this is a publish list is used for a "direct publish" operation.

* * @return true if this is a publish list is used for a "direct publish" operation */ public boolean isDirectPublish() { return (m_projectId == null); } /** * Returns true if all siblings of the project resources are to be published.

* * @return true if all siblings of the project resources are to be publisheds */ public boolean isPublishSiblings() { return m_publishSiblings; } /** * Returns true if sub-resources in folders should be published (for direct publish only).

* * @return true if sub-resources in folders should be published (for direct publish only) */ public boolean isPublishSubResources() { return m_publishSubResources; } /** * Returns true if this is a user publish list.

* * @return true if this is a user publish list */ public boolean isUserPublishList() { return m_isUserPublishList; } /** * @see java.io.Externalizable#readExternal(java.io.ObjectInput) */ public void readExternal(ObjectInput in) throws IOException { // read the history id m_publishHistoryId = internalReadUUID(in); // read the project id m_projectId = internalReadUUID(in); if (m_projectId.isNullUUID()) { m_projectId = null; } // read the flags m_publishSiblings = (in.readInt() != 0); m_publishSubResources = (in.readInt() != 0); // read the list of direct published resources m_directPublishResourceUUIDs = internalReadUUIDList(in); // read the list of published files m_fileUUIDs = internalReadUUIDList(in); // read the list of published folders m_folderUUIDs = internalReadUUIDList(in); // read the list of deleted folders m_deletedFolderUUIDs = internalReadUUIDList(in); // set revive flag to indicate that resource lists must be revived m_needsRevive = true; } /** * Revives the publish list by populating the internal resource lists with {@link CmsResource} instances.

* * @param cms a cms object used to read the resource instances */ public void revive(CmsObject cms) { if (m_needsRevive) { if (m_directPublishResourceUUIDs != null) { m_directPublishResources = internalReadResourceList(cms, m_directPublishResourceUUIDs); } if (m_fileUUIDs != null) { m_fileList = internalReadResourceList(cms, m_fileUUIDs); } if (m_folderUUIDs != null) { m_folderList = internalReadResourceList(cms, m_folderUUIDs); } if (m_deletedFolderUUIDs != null) { m_deletedFolderList = internalReadResourceList(cms, m_deletedFolderUUIDs); } m_needsRevive = false; } } /** * Sets the 'user publish list' flag on this publish list.

* * @param isUserPublishList if true, the list is marked as a user publish list */ public void setUserPublishList(boolean isUserPublishList) { m_isUserPublishList = isUserPublishList; } /** * Returns the number of all resources to be published.

* * @return the number of all resources to be published */ public int size() { if (m_needsRevive) { return 0; } else { return m_folderList.size() + m_fileList.size() + m_deletedFolderList.size(); } } /** * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer result = new StringBuffer(); result.append("\n[\n"); if (isDirectPublish()) { result.append("direct publish of resources: ").append(m_directPublishResources.toString()).append("\n"); } else { result.append("publish of project: ").append(m_projectId).append("\n"); } result.append("publish history ID: ").append(m_publishHistoryId.toString()).append("\n"); result.append("resources: ").append(m_fileList.toString()).append("\n"); result.append("folders: ").append(m_folderList.toString()).append("\n"); result.append("deletedFolders: ").append(m_deletedFolderList.toString()).append("\n"); result.append("]\n"); return result.toString(); } /** * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) */ public void writeExternal(ObjectOutput out) throws IOException { // write the history id out.write(m_publishHistoryId.toByteArray()); // write the project id out.write((m_projectId != null) ? m_projectId.toByteArray() : CmsUUID.getNullUUID().toByteArray()); // write the flags out.writeInt((m_publishSiblings) ? 1 : 0); out.writeInt((m_publishSubResources) ? 1 : 0); // write the list of direct publish resources by writing the uuid of each resource if (m_directPublishResources != null) { out.writeInt(m_directPublishResources.size()); for (Iterator i = m_directPublishResources.iterator(); i.hasNext();) { out.write((i.next()).getStructureId().toByteArray()); } } else { out.writeInt(NIL); } // write the list of published files by writing the uuid of each resource if (m_fileList != null) { out.writeInt(m_fileList.size()); for (Iterator i = m_fileList.iterator(); i.hasNext();) { out.write((i.next()).getStructureId().toByteArray()); } } else { out.writeInt(NIL); } // write the list of published folders by writing the uuid of each resource if (m_folderList != null) { out.writeInt(m_folderList.size()); for (Iterator i = m_folderList.iterator(); i.hasNext();) { out.write((i.next()).getStructureId().toByteArray()); } } else { out.writeInt(NIL); } // write the list of deleted folders by writing the uuid of each resource if (m_deletedFolderList != null) { out.writeInt(m_deletedFolderList.size()); for (Iterator i = m_deletedFolderList.iterator(); i.hasNext();) { out.write((i.next()).getStructureId().toByteArray()); } } else { out.writeInt(NIL); } } /** * Adds a new/changed Cms folder resource to the publish list.

* * @param resource a new/changed Cms folder resource * @param check if set an exception is thrown if the specified resource is unchanged, * if not set the resource is ignored * * @throws IllegalArgumentException if the specified resource is unchanged */ protected void add(CmsResource resource, boolean check) throws IllegalArgumentException { if (check) { // it is essential that this method is only visible within the db package! if (resource.getState().isUnchanged()) { throw new CmsIllegalArgumentException( Messages.get().container(Messages.ERR_PUBLISH_UNCHANGED_RESOURCE_1, resource.getRootPath())); } } if (resource.isFolder()) { if (resource.getState().isDeleted()) { if (!m_deletedFolderList.contains(resource)) { // only add files not already contained in the list m_deletedFolderList.add(resource); } } else { if (!m_folderList.contains(resource)) { // only add files not already contained in the list m_folderList.add(resource); } } } else { if (!m_fileList.contains(resource)) { // only add files not already contained in the list // this is required to make sure no siblings are duplicated m_fileList.add(resource); } } } /** * Appends all the given resources to this publish list.

* * @param resources resources to be added to this publish list * @param check if set an exception is thrown if the a resource is unchanged, * if not set the resource is ignored * * @throws IllegalArgumentException if one of the resources is unchanged */ protected void addAll(Collection resources, boolean check) throws IllegalArgumentException { // it is essential that this method is only visible within the db package! Iterator i = resources.iterator(); while (i.hasNext()) { add(i.next(), check); } } /** * Checks whether the publish list contains all sub-resources of a list of folders.

* * @param cms the current CMS context * @param folders the folders which should be checked * @return a folder from the list if one of its sub-resources is not contained in the publish list, otherwise null * * @throws CmsException if something goes wrong */ protected CmsResource checkContainsSubResources(CmsObject cms, List folders) throws CmsException { for (CmsResource folder : folders) { if (!containsSubResources(cms, folder)) { return folder; } } return null; } /** * Checks if the publish list contains a resource.

* * @param res the resource * @return true if the publish list contains a resource */ protected boolean containsResource(CmsResource res) { return m_deletedFolderList.contains(res) || m_folderList.contains(res) || m_fileList.contains(res); } /** * Checks if the publish list contains all sub-resources of a given folder.

* * @param cms the current CMS context * @param folder the folder for which the check should be performed * @return true if the publish list contains all sub-resources of a given folder * @throws CmsException if something goes wrong */ protected boolean containsSubResources(CmsObject cms, CmsResource folder) throws CmsException { String folderPath = cms.getSitePath(folder); List subResources = cms.readResources(folderPath, CmsResourceFilter.ALL, true); for (CmsResource resource : subResources) { if (!containsResource(resource)) { return false; } } return true; } /** * Gets the sub-resources of a list of folders which are missing from the publish list.

* * @param cms the current CMS context * @param folders the folders which should be checked * @return a list of missing sub resources * * @throws CmsException if something goes wrong */ protected List getMissingSubResources(CmsObject cms, List folders) throws CmsException { List result = new ArrayList(); for (CmsResource folder : folders) { String folderPath = cms.getSitePath(folder); List subResources = cms.readResources(folderPath, CmsResourceFilter.ALL, true); for (CmsResource resource : subResources) { if (!containsResource(resource)) { result.add(resource); } } } return result; } /** * Internal method to get the moved folders from the publish list.

* * @param cms the current CMS context * @return the list of moved folders from the publish list * @throws CmsException if something goes wrong */ protected List getMovedFolders(CmsObject cms) throws CmsException { CmsProject onlineProject = cms.readProject(CmsProject.ONLINE_PROJECT_ID); List movedFolders = new ArrayList(); for (CmsResource folder : m_folderList) { if (folder.getState().isChanged()) { CmsProject oldProject = cms.getRequestContext().getCurrentProject(); boolean isMoved = false; try { cms.getRequestContext().setCurrentProject(onlineProject); CmsResource onlineResource = cms.readResource(folder.getStructureId()); isMoved = !onlineResource.getRootPath().equals(folder.getRootPath()); } catch (CmsVfsResourceNotFoundException e) { // resource not found online, this means it doesn't matter whether it has been moved } finally { cms.getRequestContext().setCurrentProject(oldProject); } if (isMoved) { movedFolders.add(folder); } } } return movedFolders; } /** * Gives the "roots" of a list of folders, i.e. the list of folders which are not descendants of any other folders in the original list * @param folders the original list of folders * @return the root folders of the list */ protected List getTopFolders(List folders) { List folderPaths = new ArrayList(); List topFolders = new ArrayList(); Map foldersByPath = new HashMap(); for (CmsResource folder : folders) { folderPaths.add(folder.getRootPath()); foldersByPath.put(folder.getRootPath(), folder); } Collections.sort(folderPaths); Set topFolderPaths = new HashSet(folderPaths); for (int i = 0; i < folderPaths.size(); i++) { for (int j = i + 1; j < folderPaths.size(); j++) { if (folderPaths.get(j).startsWith((folderPaths.get(i)))) { topFolderPaths.remove(folderPaths.get(j)); } else { break; } } } for (String path : topFolderPaths) { topFolders.add(foldersByPath.get(path)); } return topFolders; } /** * Initializes the publish list, ensuring all internal lists are in the right order.

*/ protected void initialize() { if (m_folderList != null) { // ensure folders are sorted starting with parent folders Collections.sort(m_folderList, I_CmsResource.COMPARE_ROOT_PATH); } if (m_fileList != null) { // ensure files are sorted starting with files in parent folders Collections.sort(m_fileList, I_CmsResource.COMPARE_ROOT_PATH); } if (m_deletedFolderList != null) { // ensure deleted folders are sorted starting with child folders Collections.sort(m_deletedFolderList, I_CmsResource.COMPARE_ROOT_PATH); Collections.reverse(m_deletedFolderList); } } /** * Removes a Cms resource from the publish list.

* * @param resource a Cms resource * * @return true if this publish list contains the specified resource * * @see List#remove(java.lang.Object) */ protected boolean remove(CmsResource resource) { // it is essential that this method is only visible within the db package! boolean ret = m_fileList.remove(resource); ret |= m_folderList.remove(resource); ret |= m_deletedFolderList.remove(resource); return ret; } /** * Builds a list of CmsResource instances from a list of resource structure IDs.

* * @param cms a cms object * @param uuidList the list of structure IDs * @return a list of CmsResource instances */ private List internalReadResourceList(CmsObject cms, List uuidList) { List resList = new ArrayList(uuidList.size()); for (Iterator i = uuidList.iterator(); i.hasNext();) { try { CmsResource res = cms.readResource(i.next(), CmsResourceFilter.ALL); resList.add(res); } catch (CmsException exc) { LOG.error(exc.getLocalizedMessage(), exc); } } return resList; } /** * Reads a UUID from an object input.

* * @param in the object input * @return a UUID * @throws IOException */ private CmsUUID internalReadUUID(ObjectInput in) throws IOException { byte[] bytes = new byte[UUID_LENGTH]; in.readFully(bytes, 0, UUID_LENGTH); return new CmsUUID(bytes); } /** * Reads a sequence of UUIDs from an object input and builds a list of CmsResource instances from it.

* * @param in the object input * @return a list of {@link CmsResource} instances * * @throws IOException if something goes wrong */ private List internalReadUUIDList(ObjectInput in) throws IOException { List result = null; int i = in.readInt(); if (i >= 0) { result = new ArrayList(); while (i > 0) { result.add(internalReadUUID(in)); i--; } } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy