/* Copyright 2004-2014 Jim Voris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.qumasoft.server; import com.qumasoft.qvcslib.AbstractProjectProperties; import com.qumasoft.qvcslib.ArchiveDirManagerInterface; import com.qumasoft.qvcslib.DirectoryCoordinate; import com.qumasoft.qvcslib.ProjectPropertiesFactory; import com.qumasoft.qvcslib.QVCSConstants; import com.qumasoft.qvcslib.QVCSException; import com.qumasoft.qvcslib.ServerResponseFactoryInterface; import com.qumasoft.qvcslib.Utility; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; /** * Archive Directory Manager Factory. * * @author Jim Voris */ public final class ArchiveDirManagerFactoryForServer { // This is a singleton. private static final ArchiveDirManagerFactoryForServer FACTORY = new ArchiveDirManagerFactoryForServer(); // Create our logger object private static final Logger LOGGER = Logger.getLogger("com.qumasoft.server"); private final Map<String, ArchiveDirManagerInterface> directoryManagerMap; private final Map<String, AbstractProjectProperties> projectPropertiesMap; /** * Creates a new instance of ArchiveDirManagerFactory. */ private ArchiveDirManagerFactoryForServer() { directoryManagerMap = Collections.synchronizedMap(new TreeMap<String, ArchiveDirManagerInterface>()); projectPropertiesMap = Collections.synchronizedMap(new TreeMap<String, AbstractProjectProperties>()); } /** * Get the Archive directory manager factory for server singleton. * @return the Archive directory manager factory for server singleton. */ public static ArchiveDirManagerFactoryForServer getInstance() { return FACTORY; } /** * Get the archive directory manager for the given parameters. * @param serverName the server name. * @param directoryCoordinate the directory coordinates. * @param projectType the type of project. * @param userName the user name. * @param response identify the client. * @param discardObsoleteFilesFlag discard obsolete files. * @return the archive directory manager for the given directory. * @throws QVCSException if we can't find or build the archive directory manager. */ public synchronized ArchiveDirManagerInterface getDirectoryManager(String serverName, DirectoryCoordinate directoryCoordinate, String projectType, String userName, ServerResponseFactoryInterface response, boolean discardObsoleteFilesFlag) throws QVCSException { AbstractProjectProperties projectProperties = getProjectProperties(serverName, directoryCoordinate.getProjectName(), directoryCoordinate.getViewName(), projectType); return getDirectoryManager(serverName, directoryCoordinate, projectProperties, userName, response, discardObsoleteFilesFlag); } /** * Discard all the directory managers associated with the given server/project/view. This just removes the references to those objects from the map maintained by this * factory class. * @param serverName the server name. * @param projectName the project name. * @param viewName the view name. */ public synchronized void discardViewDirectoryManagers(String serverName, String projectName, String viewName) { String keyPrefix; if (serverName.length() > 0) { keyPrefix = serverName + ":" + projectName + ":" + viewName + "//"; } else { keyPrefix = projectName + ":" + viewName + "//"; } Iterator<String> it = directoryManagerMap.keySet().iterator(); while (it.hasNext()) { String key = it.next(); if (key.startsWith(keyPrefix)) { it.remove(); } } } /** * Reset the directory map. This discards all references to all directory managers. */ public void resetDirectoryMap() { directoryManagerMap.clear(); } private ArchiveDirManagerInterface getDirectoryManager(String serverName, DirectoryCoordinate directoryCoordinate, AbstractProjectProperties projectProperties, String userName, ServerResponseFactoryInterface response, boolean discardObsoleteFilesFlag) throws QVCSException { String projectName = directoryCoordinate.getProjectName(); String viewName = directoryCoordinate.getViewName(); String appendedPath = directoryCoordinate.getAppendedPath(); String keyValue = getProjectViewKey(serverName, projectName, viewName, projectProperties, appendedPath); LOGGER.log(Level.FINE, "ArchiveDirManagerFactory.getDirectoryManager: Getting directory manager for: " + keyValue); ArchiveDirManagerInterface directoryManager = directoryManagerMap.get(keyValue); if (directoryManager == null) { // We're running on the server... String localAppendedPath = Utility.convertToLocalPath(appendedPath); if (0 == viewName.compareTo(QVCSConstants.QVCS_TRUNK_VIEW)) { directoryManager = new ArchiveDirManager(projectProperties, viewName, localAppendedPath, userName, response, discardObsoleteFilesFlag); LOGGER.log(Level.INFO, "ArchiveDirManagerFactory.getDirectoryManager: creating ArchiveDirManager for directory [" + localAppendedPath + "] for Trunk view."); } else { directoryManager = ArchiveDirManagerFactoryForViews.getInstance().getDirectoryManager(serverName, projectName, viewName, appendedPath, userName, response); LOGGER.log(Level.INFO, "ArchiveDirManagerFactory.getDirectoryManager: creating ArchiveDirManager for view directory [" + localAppendedPath + "] for [" + viewName + "] view."); } if (directoryManager != null) { directoryManagerMap.put(keyValue, directoryManager); // If the discardObsoleteFilesFlag is true, then we'll throw away (actually move!) // any obsolete files. During an upgrade, we need to preserve obsolete // files until after we've captured the directory contents... so we // have this flag so we don't have to re-write all the archiveDirManager // code for the upgrade... if (discardObsoleteFilesFlag) { // Get rid of any obsolete files (needed to migrate from pre-2.1 to post 2.1 releases. if (directoryManager instanceof ArchiveDirManager) { ArchiveDirManager archiveDirManager = (ArchiveDirManager) directoryManager; archiveDirManager.deleteObsoleteFiles(userName, response); } } } } else { LOGGER.log(Level.FINE, "Re-using existing directory manager for " + keyValue); } return directoryManager; } /** * Get the project properties. * @param serverName the server name. * @param projectName the project name. * @param viewName the view name. * @param projectType the type of project. * @return the project properties. * @throws QVCSException if we can't find or build the project properties. */ public synchronized AbstractProjectProperties getProjectProperties(String serverName, String projectName, String viewName, String projectType) throws QVCSException { String propertiesKey = getPropertiesViewKey(serverName, projectName, viewName, projectType); AbstractProjectProperties projectProperties = projectPropertiesMap.get(propertiesKey); if (projectProperties == null) { // There is no project properties for this project yet. // We'll need to make one. projectProperties = ProjectPropertiesFactory.getProjectPropertiesFactory().buildProjectProperties(projectName, projectType); if (projectProperties == null) { throw new QVCSException("Failed to build " + projectType + " project properties for project: " + projectName); } projectPropertiesMap.put(propertiesKey, projectProperties); } return projectProperties; } /** * Remove a specific directory manager from the factory's map. * @param serverName the server name. * @param projectName the project name. * @param viewName the view name. * @param projectType the type of project. * @param appendedPath the appended path. */ public synchronized void removeDirectoryManager(String serverName, String projectName, String viewName, String projectType, String appendedPath) { String propertiesKey = getPropertiesViewKey(serverName, projectName, viewName, projectType); AbstractProjectProperties projectProperties = projectPropertiesMap.get(propertiesKey); if (projectProperties != null) { String keyValue = getProjectViewKey(serverName, projectName, viewName, projectProperties, appendedPath); LOGGER.log(Level.FINE, "ArchiveDirManagerFactory.removeDirectoryManager: removing directory manager for: " + keyValue); directoryManagerMap.remove(keyValue); } } private String getPropertiesViewKey(String serverName, String projectName, String viewName, String projectType) { String keyValue = serverName + "." + projectType + "." + projectName + "." + viewName; if (0 == projectType.compareTo((QVCSConstants.QVCS_SERVED_PROJECT_TYPE))) { keyValue = projectType + "." + projectName + "." + viewName; } return keyValue; } private String getProjectViewKey(String serverName, String projectName, String viewName, AbstractProjectProperties projectProperties, String appendedPath) { // Make this a standard appended path... String standardAppendedPath = Utility.convertToStandardPath(appendedPath); if (projectProperties.getIgnoreCaseFlag()) { standardAppendedPath = standardAppendedPath.toLowerCase(); } String keyValue = serverName + ":" + projectName + ":" + viewName + "//" + projectProperties.getProjectType() + ":" + standardAppendedPath; if (0 == projectProperties.getProjectType().compareTo(QVCSConstants.QVCS_SERVED_PROJECT_TYPE)) { // If we're running on the server, the key value must not include the server name, since it may vary. // NOTE: IF THIS CHANGES, YOU HAVE TO CHANGE CODE IN ViewManager.removeView() SINCE THAT // CODE ASSUMES THAT A BLANK SERVERNAME WILL WORK WHEN RUNNING ON THE SERVER. keyValue = projectName + ":" + viewName + "//" + projectProperties.getProjectType() + ":" + standardAppendedPath; } return keyValue; } }