/* * LinShare is an open source filesharing software, part of the LinPKI software * suite, developed by Linagora. * * Copyright (C) 2015 LINAGORA * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version, provided you comply with the Additional Terms applicable for * LinShare software by Linagora pursuant to Section 7 of the GNU Affero General * Public License, subsections (b), (c), and (e), pursuant to which you must * notably (i) retain the display of the “LinShare™” trademark/logo at the top * of the interface window, the display of the “You are using the Open Source * and free version of LinShare™, powered by Linagora © 2009–2015. Contribute to * Linshare R&D by subscribing to an Enterprise offer!” infobox and in the * e-mails sent with the Program, (ii) retain all hypertext links between * LinShare and linshare.org, between linagora.com and Linagora, and (iii) * refrain from infringing Linagora intellectual property rights over its * trademarks and commercial brands. Other Additional Terms apply, see * <http://www.linagora.com/licenses/> for more details. * * 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 Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License and * its applicable Additional Terms for LinShare along with this program. If not, * see <http://www.gnu.org/licenses/> for the GNU Affero General Public License * version 3 and <http://www.linagora.com/licenses/> for the Additional Terms * applicable to LinShare software. */ package org.linagora.linshare.core.dao.jackRabbit; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.util.Properties; import javax.jcr.Repository; import org.apache.jackrabbit.api.JackrabbitRepository; import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.config.RepositoryConfig; import org.linagora.linshare.core.utils.PropertyPlaceholderConfigurer; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springmodules.jcr.RepositoryFactoryBean; import org.xml.sax.InputSource; /** * FactoryBean for creating a JackRabbit (JCR-170) repository through Spring * configuration files. Use this factory bean when you have to manually * configure the repository; for retrieving the repository from JNDI use the * JndiObjectFactoryBean {@link org.springframework.jndi.JndiObjectFactoryBean}. * Sample configuration : * <code> *<bean id="repository" class="BetterRepositoryFactoryBean"> * <!-- normal factory beans params --> * <property name="configuration" value="classpath:repository.xml" /> * <property name="homeDir" value="file:///c:/tmp/jackrabbit" /> * <property name="configurationProperties"> * <list> * <value>classpath:/first.properties</value> * <value>classpath:/second.properties</value> * </list> * </property> * </bean> *</code> * * @see org.springframework.jndi.JndiObjectFactoryBean * */ public class BetterRepositoryFactoryBean extends RepositoryFactoryBean { /** * Default repository configuration file. */ private static final String DEFAULT_CONF_FILE = "repository.xml"; /** * Default repository directory. */ private static final String DEFAULT_REP_DIR = "."; /** * Spring properties place holder */ private PropertyPlaceholderConfigurer propertyPlaceholderConfigurer; /** * Home directory for the repository. */ private Resource homeDir; /** * Repository configuration created through Spring. */ private RepositoryConfig repositoryConfig; /** * @see org.springmodules.jcr.RepositoryFactoryBean#createRepository() */ protected Repository createRepository() throws Exception { // return JackRabbit repository. return RepositoryImpl.create(repositoryConfig); } /** * @see org.springmodules.jcr.RepositoryFactoryBean#resolveConfigurationResource() */ protected void resolveConfigurationResource() throws Exception { // read the configuration object if (repositoryConfig != null) return; if (this.configuration == null) { log.debug("no configuration resource specified, using the default one:" + DEFAULT_CONF_FILE); configuration = new ClassPathResource(DEFAULT_CONF_FILE); } if (homeDir == null) { if (log.isDebugEnabled()) log.debug("no repository home dir specified, using the default one:" + DEFAULT_REP_DIR); homeDir = new FileSystemResource(DEFAULT_REP_DIR); } if (propertyPlaceholderConfigurer != null) { String goodConfig = replaceVariables(loadConfigurationKeys(), getConfiguration(configuration), true); repositoryConfig = RepositoryConfig.create(new InputSource( new StringReader(goodConfig)), homeDir.getFile().getAbsolutePath()); } else { repositoryConfig = RepositoryConfig.create(new InputSource(configuration .getInputStream()), homeDir.getFile().getAbsolutePath()); } } /** * Performs variable replacement on the given string value. Each * <code>${...}</code> sequence within the given value is replaced with the * value of the named parser variable. If a variable is not found in the * properties an IllegalArgumentException is thrown unless * <code>ignoreMissing</code> is <code>true</code>. In the later case, * the missing variable is not replaced. * * @param value * the original value * @param ignoreMissing * if <code>true</code>, missing variables are not replaced. * @return value after variable replacements * @throws IllegalArgumentException * if the replacement of a referenced variable is not found */ private String replaceVariables(Properties variables, String value, boolean ignoreMissing) throws IllegalArgumentException { StringBuffer result = new StringBuffer(); // Value: // +--+-+--------+-+-----------------+ // | |p|--> |q|--> | // +--+-+--------+-+-----------------+ int p = 0, q = value.indexOf("${"); // Find first ${ while (q != -1) { result.append(value.substring(p, q)); // Text before ${ p = q; q = value.indexOf("}", q + 2); // Find } if (q != -1) { String variable = value.substring(p + 2, q); String replacement = getSystemProperties(variable); if(replacement==null){ replacement = variables.getProperty(variable); } if (replacement == null) { if (ignoreMissing) { replacement = "${" + variable + '}'; } else { throw new IllegalArgumentException("Replacement not found for ${" + variable + "}."); } } if(replacement.contains("${")){ try { replacement = replaceVariables(variables,replacement,false); } catch (IllegalArgumentException e) { if (log.isDebugEnabled()) { log.debug(e.toString()); } } } result.append(replacement); p = q + 1; q = value.indexOf("${", p); // Find next ${ } } result.append(value.substring(p, value.length())); // Trailing text return result.toString(); } private String getSystemProperties(String key) { try { String value = System.getProperty(key); if (value == null) { // XXX : Work only on POSIX-like systems (not on Windows) value = System.getenv(key); } return value; } catch (Throwable ex) { if (log.isDebugEnabled()) { log.debug("Could not access system property '" + key + "': " + ex); } return null; } } /** * Shutdown method. * */ public void destroy() throws Exception { // force cast (but use only the interface) if (repository instanceof JackrabbitRepository) { log.info("Closing repository ..."); ((JackrabbitRepository) repository).shutdown(); } super.destroy(); } /** * @return Returns the defaultRepDir. */ public Resource getHomeDir() { return this.homeDir; } /** * @param defaultRepDir * The defaultRepDir to set. */ public void setHomeDir(Resource defaultRepDir) { this.homeDir = defaultRepDir; } /** * @return Returns the repositoryConfig. */ public RepositoryConfig getRepositoryConfig() { return this.repositoryConfig; } /** * @param repositoryConfig * The repositoryConfig to set. */ public void setRepositoryConfig(RepositoryConfig repositoryConfig) { this.repositoryConfig = repositoryConfig; } public void setPropertyPlaceholderConfigurer( PropertyPlaceholderConfigurer propertyPlaceholderConfigurer) { this.propertyPlaceholderConfigurer = propertyPlaceholderConfigurer; } /** * Load all the configuration properties * * @return */ protected Properties loadConfigurationKeys() { return propertyPlaceholderConfigurer.getProperties(); } /** * Load a Resource as a String. * @param config the resource * @return the String filled with the content of the Resource * @throws IOException */ protected String getConfiguration(Resource config) throws IOException { StringWriter out = new StringWriter(); Reader reader = null; try { reader = new InputStreamReader(config.getInputStream()); char[] buffer = new char[8]; int c = 0; while ((c = reader.read(buffer)) > 0) { out.write(buffer, 0, c); } return out.toString(); } finally { if (reader != null) { reader.close(); } } } }