/*
* ====================================================================
* Copyright (c) 2005-2012 sventon project. All rights reserved.
*
* This software is licensed as described in the file LICENSE, which
* you should have received as part of this distribution. The terms
* are also available at http://www.sventon.org.
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package org.sventon.appl;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sventon.SventonException;
import org.sventon.model.Credentials;
import org.sventon.model.RepositoryName;
import org.sventon.model.SVNURL;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Sventon application configuration class holding configuration parameters
* and repository connection information for a single configured repositories.
*
* @author patrik@sventon.org
* @author jesper@sventon.org
*/
public final class RepositoryConfiguration {
/**
* Default number of RSS feed items, default set to 20.
*/
public static final int DEFAULT_RSS_ITEMS_COUNT = 20;
/**
* Default template, /rsstemplate.html
*/
public static final String DEFAULT_RSS_TEMPLATE_FILE = "/rsstemplate.html";
/**
* Default template, /mailtemplate.html
*/
public static final String DEFAULT_MAIL_TEMPLATE_FILE = "/mailtemplate.html";
public static final String PROPERTY_KEY_REPOSITORY_URL = "repositoryRootUrl";
public static final String PROPERTY_KEY_REPOSITORY_DISPLAY_URL = "repositoryDisplayRootUrl";
public static final String PROPERTY_KEY_USER_NAME = "userName";
public static final String PROPERTY_KEY_USER_PASSWORD = "userPassword";
public static final String PROPERTY_KEY_USE_CACHE = "useCache";
public static final String PROPERTY_KEY_CACHE_USER_NAME = "cacheUserName";
public static final String PROPERTY_KEY_CACHE_USER_PASSWORD = "cacheUserPassword";
public static final String PROPERTY_KEY_ALLOW_ZIP_DOWNLOADS = "allowZipDownloads";
public static final String PROPERTY_KEY_ENABLE_ACCESS_CONTROL = "enableAccessControl";
public static final String PROPERTY_KEY_ENABLE_ISSUE_TRACKER_INTEGRATION = "enableIssueTrackerIntegration";
public static final String PROPERTY_KEY_RSS_ITEMS_COUNT = "rssItemsCount";
public static final String PROPERTY_KEY_RSS_TEMPLATE_FILE = "rssTemplateFile";
public static final String PROPERTY_KEY_MAIL_TEMPLATE_FILE = "mailTemplateFile";
public static final String PROPERTY_KEY_ENABLE_ENTRY_TRAY = "enableEntryTray";
/**
* The logging instance.
*/
private final Log logger = LogFactory.getLog(getClass());
/**
* Repository name.
*/
private final RepositoryName repositoryName;
/**
* The repository URL.
*/
private String repositoryUrl;
/**
* The repository URL displayed to the user.
*/
private String repositoryDisplayUrl;
/**
* The repository location.
*/
private SVNURL svnUrl;
/**
* If a global user is configured for repository browsing, the credentials property should be set.
*/
private Credentials userCredentials;
/**
* Credentials used by the cache to access the repository.
*/
private Credentials cacheCredentials;
/**
* Decides whether the caching feature will be used.
*/
private boolean useCache;
/**
* Decides whether <i>download as zip</i> is allowed.
*/
private boolean zipDownloadsAllowed;
/**
* Decides whether repository access control is enforced (this is configured on the
* SVN server).
*/
private boolean enableAccessControl;
/**
* Decides whether the <i>entry tray</i> is enabled.
*/
private boolean enableEntryTray = true;
/**
* Decides whether the issue tracker integration should be used.
*/
private boolean enableIssueTrackerIntegration;
/**
* Number of items in the generated RSS feed, default set to {@link #DEFAULT_RSS_ITEMS_COUNT}.
*/
private int rssItemsCount = DEFAULT_RSS_ITEMS_COUNT;
/**
* RSS template file, default set to {@link #DEFAULT_RSS_TEMPLATE_FILE}.
*/
private String rssTemplateFile = DEFAULT_RSS_TEMPLATE_FILE;
/**
* RSS template string.
*/
private String rssTemplate;
/**
* Mail template file, default set to {@link #DEFAULT_MAIL_TEMPLATE_FILE}.
*/
private String mailTemplateFile = DEFAULT_MAIL_TEMPLATE_FILE;
/**
* Mail template string.
*/
private String mailTemplate;
/**
* Flag indicating if configuration is persisted or not.
*/
private boolean persisted;
/**
* Constructor.
*
* @param repositoryName Repository name.
*/
public RepositoryConfiguration(final String repositoryName) {
Validate.isTrue(RepositoryName.isValid(repositoryName), "The name must not contain whitespace");
this.repositoryName = new RepositoryName(repositoryName);
}
/**
* Creates a repository configuration using given name and properties.
*
* @param repositoryName Repository name
* @param properties Properties
* @return The RepositoryConfiguration
*/
public static RepositoryConfiguration create(final String repositoryName, final Properties properties) {
final RepositoryConfiguration ic = new RepositoryConfiguration(repositoryName);
ic.setRepositoryUrl((String) properties.get(PROPERTY_KEY_REPOSITORY_URL));
ic.setRepositoryDisplayUrl((String) properties.get(PROPERTY_KEY_REPOSITORY_DISPLAY_URL));
ic.setUserCredentials(new Credentials((String) properties.get(PROPERTY_KEY_USER_NAME), (String) properties.get(PROPERTY_KEY_USER_PASSWORD)));
ic.setCacheCredentials(new Credentials((String) properties.get(PROPERTY_KEY_CACHE_USER_NAME), (String) properties.get(PROPERTY_KEY_CACHE_USER_PASSWORD)));
ic.setCacheUsed(Boolean.parseBoolean((String) properties.get(PROPERTY_KEY_USE_CACHE)));
ic.setZippedDownloadsAllowed(Boolean.parseBoolean((String) properties.get(PROPERTY_KEY_ALLOW_ZIP_DOWNLOADS)));
ic.setEnableAccessControl(Boolean.parseBoolean((String) properties.get(PROPERTY_KEY_ENABLE_ACCESS_CONTROL)));
ic.setEnableIssueTrackerIntegration(Boolean.parseBoolean((String) properties.get(PROPERTY_KEY_ENABLE_ISSUE_TRACKER_INTEGRATION)));
ic.setRssItemsCount(Integer.parseInt(properties.getProperty(PROPERTY_KEY_RSS_ITEMS_COUNT, String.valueOf(DEFAULT_RSS_ITEMS_COUNT))));
if (properties.get(PROPERTY_KEY_ENABLE_ENTRY_TRAY) != null) {
ic.setEnableEntryTray(Boolean.parseBoolean((String) properties.get(PROPERTY_KEY_ENABLE_ENTRY_TRAY)));
}
if (properties.get(PROPERTY_KEY_RSS_TEMPLATE_FILE) != null) {
ic.setRssTemplateFile((String) properties.get(PROPERTY_KEY_RSS_TEMPLATE_FILE));
}
if (properties.get(PROPERTY_KEY_MAIL_TEMPLATE_FILE) != null) {
ic.setMailTemplateFile((String) properties.get(PROPERTY_KEY_MAIL_TEMPLATE_FILE));
}
return ic;
}
/**
* Gets the configuration as a properties instance.
*
* @return Populated properties instance.
*/
public Properties getAsProperties() {
final Properties properties = new Properties();
properties.put(PROPERTY_KEY_REPOSITORY_URL, getRepositoryUrl());
properties.put(PROPERTY_KEY_REPOSITORY_DISPLAY_URL, getRepositoryDisplayUrl());
if (userCredentials != null) {
properties.put(PROPERTY_KEY_USER_NAME, userCredentials.getUserName());
properties.put(PROPERTY_KEY_USER_PASSWORD, userCredentials.getPassword());
}
if (cacheCredentials != null) {
properties.put(PROPERTY_KEY_CACHE_USER_NAME, cacheCredentials.getUserName());
properties.put(PROPERTY_KEY_CACHE_USER_PASSWORD, cacheCredentials.getPassword());
}
properties.put(PROPERTY_KEY_USE_CACHE, isCacheUsed() ? "true" : "false");
properties.put(PROPERTY_KEY_ALLOW_ZIP_DOWNLOADS, isZippedDownloadsAllowed() ? "true" : "false");
properties.put(PROPERTY_KEY_ENABLE_ACCESS_CONTROL, isAccessControlEnabled() ? "true" : "false");
properties.put(PROPERTY_KEY_ENABLE_ENTRY_TRAY, isEntryTrayEnabled() ? "true" : "false");
properties.put(PROPERTY_KEY_ENABLE_ISSUE_TRACKER_INTEGRATION, isIssueTrackerIntegrationEnabled() ? "true" : "false");
properties.put(PROPERTY_KEY_RSS_ITEMS_COUNT, String.valueOf(getRssItemsCount()));
properties.put(PROPERTY_KEY_RSS_TEMPLATE_FILE, getRssTemplateFile());
properties.put(PROPERTY_KEY_MAIL_TEMPLATE_FILE, getMailTemplateFile());
return properties;
}
/**
* Gets the configured user credentials, if any.
* The credentials will be used for repository access.
*
* @return Returns the credentials, or null.
*/
public Credentials getUserCredentials() {
return userCredentials;
}
/**
* Sets the configured user credentials.
* The credentials will be used for repository access.
*
* @param userCredentials Credentials if any
*/
public void setUserCredentials(final Credentials userCredentials) {
this.userCredentials = userCredentials;
}
/**
* Gets the configured cache credentials, if any.
* The credentials will be used by the cache for repository access.
*
* @return Returns the credentials, or null.
*/
public Credentials getCacheCredentials() {
return cacheCredentials;
}
/**
* Sets the credentials used by the cache to connect to the repository.
*
* @param cacheCredentials Credentials used by the cache.
*/
public void setCacheCredentials(final Credentials cacheCredentials) {
this.cacheCredentials = cacheCredentials;
}
/**
* Get the configured repository URL.
*
* @return Returns the repository url.
*/
public String getRepositoryUrl() {
return repositoryUrl;
}
/**
* Sets the repository root URL. Trailing slashes will be trimmed.
*
* @param repositoryUrl The root url.
*/
public void setRepositoryUrl(String repositoryUrl) {
Validate.notEmpty(repositoryUrl, "Repository URL cannot be empty");
repositoryUrl = repositoryUrl.trim();
// Strip last slash if any.
if (repositoryUrl.endsWith("/")) {
repositoryUrl = repositoryUrl.substring(0, repositoryUrl.length() - 1);
}
this.repositoryUrl = repositoryUrl;
try {
svnUrl = SVNURL.parse(this.repositoryUrl);
} catch (final SventonException ex) {
logger.warn("Unable to parse URL [" + repositoryUrl + "]", ex);
}
}
/**
* Sets the repository URL displayed to the user.
*
* @param repositoryDisplayUrl Display URL.
*/
public void setRepositoryDisplayUrl(final String repositoryDisplayUrl) {
this.repositoryDisplayUrl = repositoryDisplayUrl;
}
/**
* Gets the repository URL displayed to the user.
*
* @return Display URL, never <tt>null</tt>. If no display URL is set, the
* repository URL will be returned instead.
*/
public String getRepositoryDisplayUrl() {
return repositoryDisplayUrl != null ? repositoryDisplayUrl : repositoryUrl;
}
/**
* Get the SVNURL, this is the typed version of the URL set using method
* {@link #setRepositoryUrl(String)}.
*
* @return Returns the location.
*/
public SVNURL getSVNURL() {
return svnUrl;
}
/**
* Sets the 'useCache' flag.
*
* @param useCache <code>true</code> if cache should be enabled, <code>false</code> if not.
*/
public void setCacheUsed(final boolean useCache) {
this.useCache = useCache;
}
/**
* Checks if the cache should be used.
*
* @return <code>true</code> if cache is enabled, <code>false</code> if not.
*/
public boolean isCacheUsed() {
return this.useCache;
}
/**
* Checks if repository access control is enabled.
*
* @return {@code true} if access control is enabled.
*/
public boolean isAccessControlEnabled() {
return enableAccessControl;
}
/**
* Checks if the entry tray is enabled.
*
* @return {@code true} if entry tray is enabled.
*/
public boolean isEntryTrayEnabled() {
return enableEntryTray;
}
/**
* Sets the 'enableEntryTray' flag.
*
* @param enableEntryTray <code>true</code> if <i>entry tray</i> is enabled.
*/
public void setEnableEntryTray(final boolean enableEntryTray) {
this.enableEntryTray = enableEntryTray;
}
/**
* Sets the 'enableAccessControl' flag.
* <b>Note</b> Enabling access control <i>disables</i> cache.
*
* @param enableAccessControl {@code true} enables repository access control.
*/
public void setEnableAccessControl(final boolean enableAccessControl) {
this.enableAccessControl = enableAccessControl;
}
/**
* Sets the 'zipDownloadsAllowed' flag.
*
* @param zipDownloadsAllowed <code>true</code> if <i>download as zip</i> is allowed.
*/
public void setZippedDownloadsAllowed(final boolean zipDownloadsAllowed) {
this.zipDownloadsAllowed = zipDownloadsAllowed;
}
/**
* Checks if <i>download as zip</i> is allowed.
*
* @return <code>true</code> if zipped downloads are allowed.
*/
public boolean isZippedDownloadsAllowed() {
return this.zipDownloadsAllowed;
}
/**
* Gets the RSS feed items count.
*
* @return Number of rss feed items generated for this repository.
*/
public int getRssItemsCount() {
return rssItemsCount;
}
/**
* Sets the number of rss items.
*
* @param count Count.
*/
private void setRssItemsCount(final int count) {
rssItemsCount = count;
}
/**
* Gets the repository name.
*
* @return Repository name.
*/
public RepositoryName getName() {
return repositoryName;
}
/**
* Checks if the issue tracker integration is enabled.
*
* @return {@code true} if enabled.
*/
public boolean isIssueTrackerIntegrationEnabled() {
return enableIssueTrackerIntegration;
}
/**
* Enables or disables the issue tracker integration.
*
* @param enableIssueTrackerIntegration True or false.
*/
public void setEnableIssueTrackerIntegration(final boolean enableIssueTrackerIntegration) {
this.enableIssueTrackerIntegration = enableIssueTrackerIntegration;
}
/**
* @param rssTemplateFile RSS template file.
*/
public void setRssTemplateFile(final String rssTemplateFile) {
this.rssTemplateFile = rssTemplateFile;
}
/**
* @param mailTemplateFile Mail template file.
*/
public void setMailTemplateFile(final String mailTemplateFile) {
this.mailTemplateFile = mailTemplateFile;
}
/**
* @return RSS template file.
*/
public String getRssTemplateFile() {
return rssTemplateFile;
}
/**
* @return mail template file.
*/
public String getMailTemplateFile() {
return mailTemplateFile;
}
/**
* @return RSS template
* @throws IOException if unable to load template.
*/
public String getRssTemplate() throws IOException {
if (rssTemplate == null) {
rssTemplate = loadTemplateFile(rssTemplateFile);
}
return rssTemplate;
}
/**
* @return Mail template
* @throws IOException if unable to load template.
*/
public String getMailTemplate() throws IOException {
if (mailTemplate == null) {
mailTemplate = loadTemplateFile(mailTemplateFile);
}
return mailTemplate;
}
/**
* Marks the configuration as persisted.
*/
public void setPersisted() {
this.persisted = true;
}
/**
* @return True if the configuration is persisted, false if not.
*/
public boolean isPersisted() {
return persisted;
}
private String loadTemplateFile(final String filename) throws IOException {
InputStream is = null;
try {
is = this.getClass().getResourceAsStream(filename);
if (is == null) {
throw new FileNotFoundException("Unable to find: " + filename);
}
return IOUtils.toString(is);
} finally {
IOUtils.closeQuietly(is);
}
}
@Override
public String toString() {
return "RepositoryConfiguration{" +
"repositoryName=" + repositoryName +
'}';
}
}