/*
* JFileSync
* Copyright (C) 2002-2007, Jens Heidrich
*
* 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 St, Fifth Floor, Boston, MA, 02110-1301, USA
*/
package jfs.conf;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import jfs.sync.JFSFile;
/**
* Manages all configuration options of JFileSync user profile.
*
* @author Jens Heidrich
* @version $Id: JFSConfig.java,v 1.31 2007/06/06 19:51:33 heidrich Exp $
*/
public abstract class JFSConfig implements Cloneable {
/** Stores the default configuration file. */
protected static File defaultFile = new File(JFSConst.HOME_DIR+File.separator+JFSConst.DEFAULT_PROFILE_FILE);
/** Stores the title of the configuration. */
protected String title;
/** Stores the current synchronization mode. */
protected byte syncMode;
/** Stores the current view onto the comparison table. */
protected byte view;
/** Vector with all directory pairs that have to be compared. */
protected List<JFSDirectoryPair> directoryList = new ArrayList<>();
/** Stores the granularity in ms for file comparisons. */
protected int granularity;
/** The used buffer size for file operations. */
protected int bufferSize;
/** Determines whether the system should keep user-defined actions. */
protected boolean keepUserActions;
/** Determines whether the history of the directory pairs is stored. */
protected boolean storeHistory;
/** Determines whether the set can write property of a file is set. */
protected boolean doSetCanWrite;
/** The files to include in comparison. */
protected List<JFSFilter> includes = new ArrayList<>();
/** The files to exclude from comparison. */
protected List<JFSFilter> excludes = new ArrayList<>();
/** The used server name to log in. */
protected String serverUserName;
/** The used server pass phrase for authentication. */
protected String serverPassPhrase;
/** The used default server timeout for all used sockets. */
protected int serverTimeout;
/** The used pass phrase for encryption. */
protected String encryptionPassPhrase;
/** The used cipher type for encryption. */
protected String encryptionCipher;
/** shorten paths by use of seven bit file name character tables */
protected boolean shortenPaths = false;
/** Determines whether the current profile was stored to a file. */
protected boolean currentProfileStored;
/** Vector with all oberservers of the configuration object. */
protected List<JFSConfigObserver> observers = new ArrayList<>();
/** tell if the user wants safety questions before actions */
protected boolean dontAskQuestions = true;
/**
* Stores the only instance of the class.
*
* SingletonHolder is loaded on the first execution of JFSConfig.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
public static final JFSConfig INSTANCE = new JFSConfigXML();
}
/**
* Sets some default values for the configuration object.
*/
protected JFSConfig() {
clean();
}
/**
* Returns the reference of the only object of the class.
*
* @return The only instance.
*/
public static JFSConfig getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* Restores the default values, but keeps all registered observers.
*/
public final void clean() {
// Basic settings:
title = JFSText.getInstance().get("profile.defaultTitle");
syncMode = (byte)JFSSyncModes.getInstance().getDefaultMode();
view = (byte)JFSViewModes.getInstance().getDefaultMode();
directoryList.clear();
// Advanced settings:
granularity = JFSConst.GRANULARITY;
bufferSize = JFSConst.BUFFER_SIZE;
keepUserActions = JFSConst.KEEP_USER_ACTIONS;
storeHistory = JFSConst.STORE_HISTORY;
doSetCanWrite = JFSConst.SET_CAN_WRITE;
// Includes and excludes:
includes.clear();
excludes.clear();
// Server settings:
serverUserName = JFSConst.SERVER_USER_NAME;
serverPassPhrase = JFSConst.SERVER_PASS_PHRASE;
serverTimeout = JFSConst.SERVER_TIMEOUT;
encryptionPassPhrase = "";
encryptionCipher = "AES";
shortenPaths = false;
// When cleaned, the profile is stored by definition:
currentProfileStored = true;
}
/**
* Loads the default configuration file in the user's home directory after program start if no configuration file
* was specified (GUI only).
*/
public final void loadDefaultFile() {
if (defaultFile.exists()) {
// Loading the default file should not change whether the profile
// was changed:
boolean isStored = isCurrentProfileStored();
loadProfile(defaultFile);
setCurrentProfileStored(isStored);
}
}
/**
* Stores the default configuration file to the user's home directory after program termination (GUI only). If the
* directory doesn't exist, it is created from scratch.
*/
public final void storeDefaultFile() {
File home = new File(JFSConst.HOME_DIR);
if ( !home.exists()) {
home.mkdir();
}
storeProfile(defaultFile);
}
/**
* Loads a profile.
*
* @param profile
* The profile to load.
* @return True if and only if loading did not fail.
*/
protected abstract boolean loadProfile(File profile);
/**
* Stores a profile.
*
* @param profile
* The profile to store.
* @return True if and only if storing did not fail.
*/
protected abstract boolean storeProfile(File profile);
/**
* Loads a profile. If loading the profile did not fail, it sets the profile as the current one in the JFS settings
* object, and adds the profile to the list of last opened profiles. Else, the current profile is set to null and
* the profile is removed from the list of opened profiles.
*
* @param profile
* The profile to load.
* @return True if and only if loading did not fail.
*/
public final boolean load(File profile) {
if (profile==null) {
return false;
}
JFSSettings s = JFSSettings.getInstance();
if (loadProfile(profile)) {
s.setCurrentProfile(profile);
s.addLastOpenedProfile(profile);
setCurrentProfileStored(true);
return true;
}
s.setCurrentProfile(null);
s.getLastOpenedProfiles().remove(profile);
return false;
}
/**
* Stores a profile. If storing the profile did not fail, it sets the profile as the current one in the JFS settings
* object, and adds the profile to the list of last opened profiles.
*
* @param profile
* The profile to load.
* @return True if and only if storing did not fail.
*/
public final boolean store(File profile) {
if (profile==null) {
return false;
}
JFSSettings s = JFSSettings.getInstance();
if (storeProfile(profile)) {
s.setCurrentProfile(profile);
s.addLastOpenedProfile(profile);
setCurrentProfileStored(true);
return true;
}
return false;
}
/**
* Returns the name of the configuration.
*
* @return Title.
*/
public final String getTitle() {
return title;
}
/**
* Sets the title of the configuration.
*
* @param title
* The title.
*/
public final void setTitle(String title) {
if ( !title.equals(this.title)) {
this.title = title;
setCurrentProfileStored(false);
}
}
/**
* Returns the chosen synchronization mode.
*
* @return Number of the choosen mode.
*/
public final byte getSyncMode() {
return syncMode;
}
/**
* Sets the synchronization mode.
*
* @param syncMode
* Number of the choosen mode.
*/
public void setSyncMode(byte syncMode) {
// Set only, if mode exists:
if (JFSSyncModes.getInstance().contains(syncMode)&&syncMode!=this.syncMode) {
this.syncMode = syncMode;
setCurrentProfileStored(false);
}
}
/**
* Returns the chosen view on the comparison table.
*
* @return Number of the chosen view.
*/
public final byte getView() {
return view;
}
/**
* Sets the view.
*
* @param view
* Number of the chosen view.
*/
public void setView(byte view) {
// Set only, if mode exists:
if (JFSViewModes.getInstance().contains(view)&&view!=this.view) {
this.view = view;
setCurrentProfileStored(false);
}
}
/**
* Returns the vector of all directory pairs that have to be compared.
*
* @return Vector of directory pairs.
*/
public final List<JFSDirectoryPair> getDirectoryList() {
return directoryList;
}
/**
* Adds a directory pair.
*
* @param pair
* The pair to add.
*/
public final void addDirectoryPair(JFSDirectoryPair pair) {
directoryList.add(pair);
setCurrentProfileStored(false);
}
/**
* Determines whether the configuration contains a special directory pair.
*
* @param pair
* The pair to check.
* @return Returns true, if the pair is part of the configuration.
*/
public final boolean hasDirectoryPair(JFSDirectoryPair pair) {
return directoryList.contains(pair);
}
/**
* Removes a directory pair.
*
* @param index
* The index of the element to remove.
* @return The removed element.
*/
public final JFSDirectoryPair removeDirectoryPair(int index) {
setCurrentProfileStored(false);
return directoryList.remove(index);
}
/**
* Inserts a directory pair.
*
* @param pair
* The pair to insert.
* @param index
* The index of the element to insert.
*/
public final void insertDirectoryPair(JFSDirectoryPair pair, int index) {
directoryList.add(index, pair);
setCurrentProfileStored(false);
}
/**
* Returns the chosen granularity of the comparison in milliseconds that is used in order to comapare the last
* modified time of two files. Under the DOS and Windows FAT filesystem, the finest granularity on time resolution
* is two seconds. So we define the default maximum tollerance range for each comparison as 2000ms.
*
* @return Granularity in ms.
*/
public final int getGranularity() {
return granularity;
}
/**
* Sets the granularity if it is greater than zero.
*
* @param granularity
* Granularity in ms.
*/
public void setGranularity(int granularity) {
if (granularity>0&&granularity!=this.granularity) {
this.granularity = granularity;
setCurrentProfileStored(false);
}
}
/**
* Returns the chosen buffer size.
*
* @return Size in byte.
*/
public final int getBufferSize() {
return bufferSize;
}
/**
* Sets the buffer size.
*
* @param bufferSize
* Size in byte.
*/
public void setBufferSize(int bufferSize) {
if (bufferSize!=this.bufferSize) {
this.bufferSize = bufferSize;
setCurrentProfileStored(false);
}
}
/**
* Returns whether the system should keep user-defined actions.
*
* @return True, if the system should do so.
*/
public final boolean isKeepUserActions() {
return keepUserActions;
}
/**
* Determines whether the system should keep user-defined actions.
*
* @param keepUserActions
* True, if the system should do so.
*/
public void setKeepUserActions(boolean keepUserActions) {
if (keepUserActions!=this.keepUserActions) {
this.keepUserActions = keepUserActions;
setCurrentProfileStored(false);
}
}
/**
* Returns whether the program should store the history of a synchronized files. This is needed when the program
* should automatically use the information of its previous run in order to determine which files to copy and
* delete.
*
* @return True if and only if the program should store the history.
*/
public boolean isStoreHistory() {
return storeHistory;
}
/**
* Sets whether the program should store the history of a synchronized files. This is needed when the program should
* automatically use the information of its previous run in order to determine which files to copy and delete.
*
* @param storeHistory
* True if and only if the program should store the history.
*/
public void setStoreHistory(boolean storeHistory) {
if (storeHistory!=this.storeHistory) {
this.storeHistory = storeHistory;
setCurrentProfileStored(false);
}
}
/**
* @return Determines whether the set can write property of a file is set.
*/
public boolean isSetCanWrite() {
return doSetCanWrite;
}
/**
* Determines whether the set can write property of a file is set.
*
* @param setCanWrite
* True if and only if the set can write property of a file is set.
*/
public void setCanWrite(boolean setCanWrite) {
if (setCanWrite!=this.doSetCanWrite) {
this.doSetCanWrite = setCanWrite;
setCurrentProfileStored(false);
}
}
/**
* Returns the vector of filters used to determine whether a file should be included in the comparison.
*
* @return Vector of JFSFilter objects.
*/
public final List<JFSFilter> getIncludes() {
return includes;
}
/**
* Adds an include filter.
*
* @param filter
* The include filter to add.
*/
public final void addInclude(JFSFilter filter) {
includes.add(filter);
setCurrentProfileStored(false);
}
/**
* Replaces all include filters.
*
* @param filters
* The include filters to use.
*/
public final void replaceIncludes(List<JFSFilter> filters) {
includes.clear();
includes.addAll(filters);
setCurrentProfileStored(false);
}
/**
* Determines whether a given file matches an include expression.
*
* @param file
* The file to test.
* @return True, if and only if the file matches at least one include expression.
*/
public final boolean matchesIncludes(JFSFile file) {
for (JFSFilter f : includes) {
if (f.matches(file)) {
return true;
}
}
return false;
}
/**
* Returns the vector of filters used to determine whether a file should be excluded in the comparison.
*
* @return Vector of JFSFilter objects.
*/
public final List<JFSFilter> getExcludes() {
return excludes;
}
/**
* Adds an exclude filter.
*
* @param filter
* The exclude filter to add.
*/
public final void addExclude(JFSFilter filter) {
excludes.add(filter);
setCurrentProfileStored(false);
}
/**
* Replaces all exclude filters.
*
* @param filters
* The exclude filters to use.
*/
public final void replaceExcludes(List<JFSFilter> filters) {
excludes.clear();
excludes.addAll(filters);
setCurrentProfileStored(false);
}
/**
* Determines whether a given file matches an exclude expression.
*
* @param file
* The file to test.
* @return True, if and only if the file matches at least one exclude expression.
*/
public final boolean matchesExcludes(JFSFile file) {
for (JFSFilter f : excludes) {
if (f.matches(file)) {
return true;
}
}
return false;
}
/**
* Returns the server username for remote connections.
*
* @return The server username.
*/
public String getServerUserName() {
return serverUserName;
}
/**
* Sets the server username for remote connections.
*
* @param serverUserName
* The server base directory.
*/
public void setServerUserName(String serverUserName) {
if ( !serverUserName.equals(this.serverUserName)) {
this.serverUserName = serverUserName;
setCurrentProfileStored(false);
}
}
/**
* Returns the server pass phrase for remote connections.
*
* @return The server pass phrase.
*/
public String getServerPassPhrase() {
return serverPassPhrase;
}
/**
* Sets the server pass phrase for remote connections.
*
* @param serverPassPhrase
* The server pass phrase.
*/
public void setServerPassPhrase(String serverPassPhrase) {
if ( !serverPassPhrase.equals(this.serverPassPhrase)) {
this.serverPassPhrase = serverPassPhrase;
setCurrentProfileStored(false);
}
}
/**
* Returns the server timeout.
*
* @return The server timeout.
*/
public int getServerTimeout() {
return serverTimeout;
}
/**
* Sets the server timeout.
*
* @param serverTimeout
* The server timeout.
*/
public void setServerTimeout(int serverTimeout) {
if (serverTimeout!=this.serverTimeout) {
this.serverTimeout = serverTimeout;
setCurrentProfileStored(false);
}
}
public String getEncryptionPassPhrase() {
return encryptionPassPhrase;
}
public void setEncryptionPassPhrase(String encryptionPassPhrase) {
if ( !encryptionPassPhrase.equals(this.encryptionPassPhrase)) {
this.encryptionPassPhrase = encryptionPassPhrase;
setCurrentProfileStored(false);
}
}
public String getEncryptionCipher() {
return encryptionCipher;
}
public void setEncryptionCipher(String encryptionCipher) {
if ( !encryptionCipher.equals(this.encryptionCipher)) {
this.encryptionCipher = encryptionCipher;
setCurrentProfileStored(false);
}
}
public boolean isShortenPaths() {
return shortenPaths;
}
public void setShortenPaths(boolean shortenPaths) {
if ( shortenPaths!=this.shortenPaths) {
setCurrentProfileStored(false);
}
this.shortenPaths = shortenPaths;
}
public boolean isDontAskQuestions() {
return dontAskQuestions;
}
public void setDontAskQuestions(boolean dontAskQuestions) {
if ( dontAskQuestions!=this.dontAskQuestions) {
setCurrentProfileStored(false);
}
this.dontAskQuestions = dontAskQuestions;
}
/**
* Determines whether the current profile was stored to a file. If the profile was changed and is not stored yet,
* this method will return false.
*/
public final boolean isCurrentProfileStored() {
return currentProfileStored;
}
/**
* Determines whether the current profile was stored to a file.
*
* @param isCurrentProfileStored
* True, if the profile was stored.
*/
public final void setCurrentProfileStored(boolean isCurrentProfileStored) {
this.currentProfileStored = isCurrentProfileStored;
}
/**
* Send to all observers when the configuration has to be updated.
*/
public final void fireConfigUpdate() {
for (JFSConfigObserver co : observers) {
co.updateConfig(this);
}
}
/**
* Send to all observers when the computed comparison has to be updated.
*/
public final void fireComparisonUpdate() {
for (JFSConfigObserver co : observers) {
co.updateComparison(this);
}
}
/**
* Send to all observers when the server has to be updated.
*/
public final void fireServerUpdate() {
for (JFSConfigObserver co : observers) {
co.updateServer(this);
}
}
/**
* Attaches an additional observer.
*
* @param observer
* The new observer.
*/
public final void attach(JFSConfigObserver observer) {
observers.add(observer);
updateObserver(observer);
}
/**
* Detaches an existing observer.
*
* @param observer
* An old observer.
*/
public final void detach(JFSConfigObserver observer) {
observers.remove(observer);
}
/**
* Updates the current state of the configuration for a special observer.
*
* @param observer
* The observer to update.
*/
private void updateObserver(JFSConfigObserver observer) {
observer.updateConfig(this);
observer.updateComparison(this);
observer.updateServer(this);
}
/**
* Updates the current state of the configuration for all existing observers.
*/
public final void fireUpdate() {
for (JFSConfigObserver co : observers) {
updateObserver(co);
}
}
/**
* Transfers the content of the configuration object to an other configuration object (without the registered
* observers).
*
* @param config
* The transfer target.
*/
public final void transferContentTo(JFSConfig config) {
boolean configUpdate = false;
boolean serverUpdate = false;
boolean comparisonUpdate = false;
// Transfer basic settings:
if ( !title.equals(config.title)) {
config.title = title;
configUpdate = true;
}
if (syncMode!=config.syncMode) {
config.syncMode = syncMode;
configUpdate = true;
}
if (view!=config.view) {
config.view = view;
configUpdate = true;
}
if ( !directoryList.equals(config.directoryList)) {
config.directoryList.clear();
for (JFSDirectoryPair pair : directoryList) {
config.directoryList.add(pair.clone());
}
comparisonUpdate = true;
}
// Transfer advanced settings:
if (granularity!=config.granularity) {
config.granularity = granularity;
configUpdate = true;
}
if (bufferSize!=config.bufferSize) {
config.bufferSize = bufferSize;
serverUpdate = true;
}
if (keepUserActions!=config.keepUserActions) {
config.keepUserActions = keepUserActions;
configUpdate = true;
}
if (storeHistory!=config.storeHistory) {
config.storeHistory = storeHistory;
configUpdate = true;
}
if (doSetCanWrite!=config.doSetCanWrite) {
config.doSetCanWrite = doSetCanWrite;
configUpdate = true;
}
// Transfer includes and excludes:
if ( !includes.equals(config.includes)) {
config.includes.clear();
for (JFSFilter f : includes) {
config.includes.add(f.clone());
}
comparisonUpdate = true;
}
if ( !excludes.equals(config.excludes)) {
config.excludes.clear();
for (JFSFilter f : excludes) {
config.excludes.add(f.clone());
}
comparisonUpdate = true;
}
if ( !serverUserName.equals(config.serverUserName)) {
config.serverUserName = serverUserName;
serverUpdate = true;
}
if ( !serverPassPhrase.equals(config.serverPassPhrase)) {
config.serverPassPhrase = serverPassPhrase;
serverUpdate = true;
}
if (serverTimeout!=config.serverTimeout) {
config.serverTimeout = serverTimeout;
serverUpdate = true;
}
if ( !encryptionPassPhrase.equals(config.encryptionPassPhrase)) {
config.encryptionPassPhrase = encryptionPassPhrase;
configUpdate = true;
} // if
if ( !encryptionCipher.equals(config.encryptionCipher)) {
config.encryptionCipher = encryptionCipher;
configUpdate = true;
} // if
// Transfer whether profile was stored:
if (currentProfileStored!=config.currentProfileStored) {
config.currentProfileStored = currentProfileStored;
}
// Fire updates accordingly:
if (configUpdate) {
config.fireConfigUpdate();
}
if (comparisonUpdate) {
config.fireComparisonUpdate();
}
if (serverUpdate) {
config.fireServerUpdate();
}
}
/**
* @see Object#clone()
*/
@Override
public final Object clone() {
JFSConfig clone = new JFSConfigXML();
this.transferContentTo(clone);
return clone;
}
}