/* * Copyright (C) 2005-2009 Alfresco Software Limited. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * As a special exception to the terms and conditions of version 2.0 of * the GPL, you may redistribute this Program in connection with Free/Libre * and Open Source Software ("FLOSS") applications as described in Alfresco's * FLOSS exception. You should have received a copy of the text describing * the FLOSS exception, and it is also available here: * http://www.alfresco.com/legal/licensing" */ package org.alfresco.filesys.avm; import java.util.StringTokenizer; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.filesys.alfresco.AlfrescoContext; import org.alfresco.filesys.alfresco.AlfrescoDiskDriver; import org.alfresco.filesys.alfresco.IOControlHandler; import org.alfresco.filesys.state.FileState; import org.alfresco.filesys.state.FileStateTable; import org.alfresco.jlan.server.filesys.DiskInterface; import org.alfresco.jlan.server.filesys.FileName; import org.alfresco.jlan.server.filesys.FileSystem; import org.alfresco.jlan.server.filesys.NotifyChange; import org.alfresco.jlan.util.StringList; import org.alfresco.repo.avm.CreateStoreCallback; import org.alfresco.repo.avm.CreateVersionCallback; import org.alfresco.repo.avm.PurgeStoreCallback; import org.alfresco.repo.avm.PurgeVersionCallback; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * AVM Filesystem Context Class * *
Contains per filesystem context. * * @author GKSpencer */ public class AVMContext extends AlfrescoContext implements CreateStoreCallback, PurgeStoreCallback, CreateVersionCallback, PurgeVersionCallback { // Logging private static final Log logger = LogFactory.getLog(AVMContext.class); // Constants // // Version id that indicates the head version public static final int VERSION_HEAD = -1; // Store types to show in the virtualization view public static final int ShowNormalStores = 0x0001; public static final int ShowSiteStores = 0x0002; public static final int ShowStagingStores = 0x0004; public static final int ShowAuthorStores = 0x0008; public static final int ShowPreviewStores = 0x0010; // Store, root path and version private String m_storePath; private int m_version = VERSION_HEAD; // Flag to indicate if the virtualization view is enabled // // The first set of folders then map to the stores and the second layer map to the versions with // paths below. private boolean m_virtualView; // Virtualization view filtering options private int m_showOptions = ShowStagingStores + ShowAuthorStores; // List of newly created store names that need adding into the virtualization view private StringList m_newStores; private Object m_newStoresLock; // Allow admin user to write to web project staging stores private boolean m_allowAdminStagingWrites; // Auto create the store if it doesn't exist? private boolean m_createStore; /** * Default constructor allowing initialization by container. */ public AVMContext() { } /** * Class constructor * *
Construct a context for a normal view onto a single store/version within AVM. * * @param filesysName String * @param storePath String * @param version int */ public AVMContext( String filesysName, String storePath, int version) { setDeviceName(filesysName); // Set the store root path setStorePath(storePath); // Set the store version to use setVersion(version); } /** * Class constructor * *
Construct a context for a virtualization view onto all stores/versions within AVM. * * @param filesysName String * @param showOptions int * @param avmDriver AVMDiskDriver */ public AVMContext( String filesysName, int showOptions, AVMDiskDriver avmDriver) { setDeviceName(filesysName); // Enable the virtualization view setVirtualView(true); setShowOptions(showOptions); } public void setStorePath(String path) { this.m_storePath = path; } public void setVersion(int version) { this.m_version = version; } public void setShowOptions(int showOptions) { this.m_showOptions = showOptions; } public void setStores(String showAttr) { if ( showAttr != null) { // Split the show options string StringTokenizer tokens = new StringTokenizer( showAttr, ","); StringList optList = new StringList(); while ( tokens.hasMoreTokens()) optList.addString( tokens.nextToken().trim().toLowerCase()); // Build the show options mask this.m_showOptions = 0; if ( optList.containsString("normal")) this.m_showOptions += ShowNormalStores; if ( optList.containsString("site")) this.m_showOptions += ShowSiteStores; if ( optList.containsString("author")) this.m_showOptions += ShowAuthorStores; if ( optList.containsString("preview")) this.m_showOptions += ShowPreviewStores; if ( optList.containsString("staging")) this.m_showOptions += ShowStagingStores; } } public void setVirtualView(boolean isVirtualView) { this.m_virtualView = isVirtualView; } public boolean getCreateStore() { return m_createStore; } public void setCreateStore(boolean createStore) { m_createStore = createStore; } @Override public void initialize(AlfrescoDiskDriver filesysDriver) { if (m_virtualView) { // A context for a view onto all stores/versions within AVM. m_newStoresLock = new Object(); m_newStores = new StringList(); setShareName("VirtualView"); } else { if (m_storePath == null || m_storePath.length() == 0) throw new AlfrescoRuntimeException("Device missing init value: storePath"); // A context for a normal view onto a single store/version within AVM. if (m_storePath.endsWith("/")) m_storePath = m_storePath.substring(0, m_storePath.length() - 1); // Range check the version id if (m_version < 0 && m_version != AVMContext.VERSION_HEAD) throw new AlfrescoRuntimeException("Invalid store version id specified, " + m_version); setShareName(m_storePath + "(" + m_version + ")"); } super.initialize(filesysDriver); } /** * Return the filesystem type, either FileSystem.TypeFAT or FileSystem.TypeNTFS. * * @return String */ public String getFilesystemType() { return FileSystem.TypeNTFS; } /** * Return the store path * * @return String */ public final String getStorePath() { return m_storePath; } /** * Return the version * * @return int */ public final int isVersion() { return m_version; } /** * Check if the virtualization view is enabled * * @return boolean */ public final boolean isVirtualizationView() { return m_virtualView; } /** * Check if the admin user is allowed to write to web project staging stores * * @return boolean */ public final boolean allowAdminStagingWrites() { return m_allowAdminStagingWrites; } /** * Set the admin web project staging store writeable status * * @param writeable boolean */ public final void setAllowAdminStaginWrites(boolean writeable) { m_allowAdminStagingWrites = writeable; } /** * Check if there are any new stores queued for adding to the virtualization view * * @return boolean */ protected final boolean hasNewStoresQueued() { if ( m_newStores == null || m_newStores.numberOfStrings() == 0) return false; return true; } /** * Return the new stores queue, and reset the current queue * * @return StringList */ protected StringList getNewStoresQueue() { StringList storesQueue = null; synchronized ( m_newStoresLock) { storesQueue = m_newStores; m_newStores = new StringList(); } return storesQueue; } /** * Check if normal stores should be shown in the virtualization view * * @return boolean */ public final boolean showNormalStores() { return (m_showOptions & ShowNormalStores) != 0 ? true : false; } /** * Check if site data stores should be shown in the virtualization view * * @return boolean */ public final boolean showSiteStores() { return (m_showOptions & ShowSiteStores) != 0 ? true : false; } /** * Check if author stores should be shown in the virtualization view * * @return boolean */ public final boolean showAuthorStores() { return (m_showOptions & ShowAuthorStores) != 0 ? true : false; } /** * Check if preview stores should be shown in the virtualization view * * @return boolean */ public final boolean showPreviewStores() { return (m_showOptions & ShowPreviewStores) != 0 ? true : false; } /** * Check if staging stores should be shown in the virtualization view * * @return boolean */ public final boolean showStagingStores() { return (m_showOptions & ShowStagingStores) != 0 ? true : false; } /** * Check if the specified store type should be visible * * @param storeType int * @return boolean */ public final boolean showStoreType(int storeType) { boolean showStore = false; switch (storeType) { case StoreType.Normal: showStore = showNormalStores(); break; case StoreType.SiteStore: showStore = showSiteStores(); break; case StoreType.WebAuthorMain: showStore = showAuthorStores(); break; case StoreType.WebStagingMain: showStore = showStagingStores(); break; case StoreType.WebAuthorPreview: case StoreType.WebStagingPreview: showStore = showPreviewStores(); break; } return showStore; } /** * Close the filesystem context */ public void CloseContext() { // Call the base class super.CloseContext(); } /** * Create the I/O control handler for this filesystem type * * @param filesysDriver DiskInterface * @return IOControlHandler */ protected IOControlHandler createIOHandler( DiskInterface filesysDriver) { return null; } /** * Create store call back handler * * @param storeName String * @param versionID int */ public void storeCreated(String storeName) { // Not interested if the virtualization view is not enabled if ( isVirtualizationView() == false) return; // Make sure the file state cache is enabled FileStateTable fsTable = getStateTable(); if ( fsTable == null) return; // Find the file state for the root folder FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR, true, true); if ( rootState != null) { // DEBUG if ( logger.isDebugEnabled()) logger.debug("Queueing new store " + storeName + " for addition to virtualization view"); // Add the new store name to the list to be picked up by the next file server access // to the filesystem synchronized ( m_newStoresLock) { // Add the new store name m_newStores.addString( storeName); } } } /** * Purge store call back handler * * @param storeName String */ public void storePurged(String storeName) { // Not interested if the virtualization view is not enabled if ( isVirtualizationView() == false) return; // Make sure the file state cache is enabled FileStateTable fsTable = getStateTable(); if ( fsTable == null) return; // Find the file state for the root folder FileState rootState = fsTable.findFileState( FileName.DOS_SEPERATOR_STR); if ( rootState != null && rootState.hasPseudoFiles()) { // Remove the pseudo folder for the store rootState.getPseudoFileList().removeFile( storeName, false); // Build the filesystem relative path to the deleted store folder StringBuilder pathStr = new StringBuilder(); pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( storeName); // Remove the file state for the deleted store String storePath = pathStr.toString(); fsTable.removeFileState( storePath); // DEBUG if ( logger.isDebugEnabled()) logger.debug( "Removed pseudo folder for purged store " + storeName); // Update the file state modify time rootState.updateModifyDateTime(); // Send a change notification for the deleted folder if ( hasChangeHandler()) { // Send the change notification getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, storePath); } } } /** * Create version call back handler * * @param storeName String * @param versionID int */ public void versionCreated(String storeName, int versionID) { // Not interested if the virtualization view is not enabled if ( isVirtualizationView() == false) return; // Make sure the file state cache is enabled FileStateTable fsTable = getStateTable(); if ( fsTable == null) return; // Build the path to the store version folder StringBuilder pathStr = new StringBuilder(); pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( storeName); pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( AVMPath.VersionsFolder); // Find the file state for the store versions folder FileState verState = fsTable.findFileState( pathStr.toString()); if ( verState != null) { // Create the version folder name StringBuilder verStr = new StringBuilder(); verStr.append( AVMPath.VersionFolderPrefix); verStr.append( versionID); String verName = verStr.toString(); // Add a pseudo folder for the new version pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( verName); verState.addPseudoFile( new VersionPseudoFile( verName, pathStr.toString())); // DEBUG if ( logger.isDebugEnabled()) logger.debug( "Added pseudo folder for new version " + storeName + ":/" + verName); // Send a change notification for the new folder if ( hasChangeHandler()) { // Build the filesystem relative path to the new version folder pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( verName); // Send the change notification getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionAdded, pathStr.toString()); } } } /** * Purge version call back handler * * @param storeName String */ public void versionPurged(String storeName, int versionID) { // Not interested if the virtualization view is not enabled if ( isVirtualizationView() == false) return; // Make sure the file state cache is enabled FileStateTable fsTable = getStateTable(); if ( fsTable == null) return; // Build the path to the store version folder StringBuilder pathStr = new StringBuilder(); pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( storeName); pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( AVMPath.VersionsFolder); // Find the file state for the store versions folder FileState verState = fsTable.findFileState( pathStr.toString()); if ( verState != null && verState.hasPseudoFiles()) { // Create the version folder name StringBuilder verStr = new StringBuilder(); verStr.append( AVMPath.VersionFolderPrefix); verStr.append( versionID); String verName = verStr.toString(); // Remove the pseudo folder for the purged version verState.getPseudoFileList().removeFile( verName, true); // DEBUG if ( logger.isDebugEnabled()) logger.debug( "Removed pseudo folder for purged version " + storeName + ":/" + verName); // Send a change notification for the deleted folder if ( hasChangeHandler()) { // Build the filesystem relative path to the deleted version folder pathStr.append( FileName.DOS_SEPERATOR); pathStr.append( verName); // Send the change notification getChangeHandler().notifyDirectoryChanged(NotifyChange.ActionRemoved, pathStr.toString()); } } } }