Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 52803 invoked from network); 29 Jan 2010 16:01:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 29 Jan 2010 16:01:01 -0000 Received: (qmail 72071 invoked by uid 500); 29 Jan 2010 16:01:01 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 71982 invoked by uid 500); 29 Jan 2010 16:01:01 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 71973 invoked by uid 99); 29 Jan 2010 16:01:01 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 29 Jan 2010 16:01:01 +0000 X-ASF-Spam-Status: No, hits=-1998.9 required=10.0 tests=ALL_TRUSTED,FB_GET_MEDS X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 29 Jan 2010 16:00:50 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 6A6EB23889E3; Fri, 29 Jan 2010 16:00:30 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r904534 - in /jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi: Activator.java RepositoryConfigurer.java Date: Fri, 29 Jan 2010 16:00:30 -0000 To: commits@jackrabbit.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100129160030.6A6EB23889E3@eris.apache.org> Author: fmeschbe Date: Fri Jan 29 16:00:29 2010 New Revision: 904534 URL: http://svn.apache.org/viewvc?rev=904534&view=rev Log: JavaDoc and streamlining default configuration implementation to prevent duplicate work and to be consistent Modified: jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/Activator.java jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/RepositoryConfigurer.java Modified: jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/Activator.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/Activator.java?rev=904534&r1=904533&r2=904534&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/Activator.java (original) +++ jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/Activator.java Fri Jan 29 16:00:29 2010 @@ -16,8 +16,6 @@ */ package org.apache.jackrabbit.core.osgi; -import java.io.File; -import java.io.IOException; import java.util.Hashtable; import org.apache.jackrabbit.core.api.security.LoginModulePluginFactory; @@ -69,7 +67,8 @@ // the repository configurer ManagedServiceFactory private RepositoryConfigurer repositoryConfigurer; -// TODO: private static AccessManagerFactoryTracker accessManagerFactoryTracker; + // TODO: private static AccessManagerFactoryTracker + // accessManagerFactoryTracker; public void start(BundleContext context) { @@ -101,12 +100,12 @@ ise); } } -// TODO -// if (accessManagerFactoryTracker == null) { -// accessManagerFactoryTracker = new AccessManagerFactoryTracker( -// bundleContext); -// } -// accessManagerFactoryTracker.open(); + // TODO + // if (accessManagerFactoryTracker == null) { + // accessManagerFactoryTracker = new AccessManagerFactoryTracker( + // bundleContext); + // } + // accessManagerFactoryTracker.open(); } public void stop(BundleContext arg0) { @@ -126,11 +125,11 @@ loginModuleTracker = null; } -// TODO -// if (accessManagerFactoryTracker != null) { -// accessManagerFactoryTracker.close(); -// accessManagerFactoryTracker = null; -// } + // TODO + // if (accessManagerFactoryTracker != null) { + // accessManagerFactoryTracker.close(); + // accessManagerFactoryTracker = null; + // } // clear the bundle context field bundleContext = null; @@ -192,22 +191,14 @@ return moduleCache; } -// TODO -// public static AccessManagerFactoryTracker getAccessManagerFactoryTracker() { -// return accessManagerFactoryTracker; -// } + // TODO + // public static AccessManagerFactoryTracker + // getAccessManagerFactoryTracker() { + // return accessManagerFactoryTracker; + // } // ---------- internal ----------------------------------------------------- - private String getRepositoryName() { - String repoName = bundleContext.getProperty("sling.repository.name"); - if (repoName != null) { - return repoName; // the repository name is set - } - - return "jackrabbit"; - } - private void verifyConfiguration(ServiceReference ref) { ConfigurationAdmin ca = (ConfigurationAdmin) bundleContext.getService(ref); if (ca == null) { @@ -230,7 +221,15 @@ // No config, create a default one. Hashtable defaultConfig = new Hashtable(); - initDefaultConfig(defaultConfig, bundleContext); + setProperty(defaultConfig, RepositoryConfigurer.REPOSITORY_CONFIG, + bundleContext, "jackrabbit.repository.config", + "sling.repository.config.file.url"); + setProperty(defaultConfig, + RepositoryConfigurer.REPOSITORY_HOME_DIR, bundleContext, + "jackrabbit.repository.home", "sling.repository.home"); + setProperty(defaultConfig, RepositoryConfigurer.REPOSITORY_NAME, + bundleContext, "jackrabbit.repository.name", + "sling.repository.name"); // create the factory and set the properties Configuration config = ca.createFactoryConfiguration(SERVER_REPOSITORY_FACTORY_PID); @@ -247,57 +246,16 @@ } } - private void initDefaultConfig(Hashtable props, - BundleContext bundleContext) throws IOException { - File homeDir = getHomeDir(bundleContext); - if (homeDir == null) return; - - // default config values - props.put(RepositoryConfigurer.REPOSITORY_CONFIG_URL, - getConfig(bundleContext, homeDir)); - props.put(RepositoryConfigurer.REPOSITORY_HOME_DIR, homeDir.getPath()); - props.put(RepositoryConfigurer.REPOSITORY_REGISTRATION_NAME, - this.getRepositoryName()); - } - - private File getHomeDir(BundleContext bundleContext) { - File homeDir; - - String repoHomePath = bundleContext.getProperty("sling.repository.home"); - String slingHomePath = bundleContext.getProperty("sling.home"); - - if (repoHomePath != null) { - homeDir = new File(repoHomePath, getRepositoryName()); - } else if (slingHomePath != null) { - homeDir = new File(slingHomePath, getRepositoryName()); - } else { - homeDir = new File(getRepositoryName()); + private static void setProperty(final Hashtable props, + final String propName, final BundleContext context, + final String contextPropName, final String slingContextPropName) { + String value = context.getProperty(contextPropName); + if (value == null) { + value = context.getProperty(slingContextPropName); } - // make sure jackrabbit home exists - log.info("Creating default config for Jackrabbit in " + homeDir); - if (!homeDir.isDirectory()) { - if (!homeDir.mkdirs()) { - log.info("verifyConfiguration: Cannot create Jackrabbit home " - + homeDir + ", failed creating default configuration"); - return null; - } - } - - return homeDir; - } - - private static String getConfig(BundleContext bundleContext, File homeDir) { - File configFile; - - String repoConfigFileUrl = bundleContext.getProperty("sling.repository.config.file.url"); - if (repoConfigFileUrl != null) { - return repoConfigFileUrl; + if (value != null) { + props.put(propName, value); } - - // ensure the configuration file (inside the home Dir !) - configFile = new File(homeDir, "repository.xml"); - return configFile.getAbsolutePath(); } - } Modified: jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/RepositoryConfigurer.java URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/RepositoryConfigurer.java?rev=904534&r1=904533&r2=904534&view=diff ============================================================================== --- jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/RepositoryConfigurer.java (original) +++ jackrabbit/sandbox/jackrabbit2-bundle/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/osgi/RepositoryConfigurer.java Fri Jan 29 16:00:29 2010 @@ -20,12 +20,10 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.MalformedURLException; import java.net.URL; import java.util.Dictionary; import java.util.Enumeration; @@ -50,33 +48,42 @@ /** * The RepositoryConfigurer is a ManagedServiceFactory receiving * configurations to managed (start/stop) embedded repository instances. + *

+ * This class may be overwritten by bundles extending Jackrabbit Core. Please + * review the method comments for more information as to what can be customized + * in extensions. */ public class RepositoryConfigurer implements ManagedServiceFactory { /** - * The name of the configuration property defining the URL to the repository - * configuration file (value is "config"). + * The name of the configuration property providing the name of the + * repository configuration file (value is "config"). If this parameter is + * missing from the configuration the default value assumed is provided by + * the {@link #getDefaultRepositoryUrl()} method. *

- * If the configuration file is located in the local file system, the - * "file:" scheme must still be specified. - *

- * This parameter is mandatory for this activator to start the repository. + * If this is a relative path, it is resolved against the repository home + * directory. */ - public static final String REPOSITORY_CONFIG_URL = "config"; + public static final String REPOSITORY_CONFIG = "config"; /** * The name of the configuration property defining the file system directory - * where the repository files are located (value is "home"). + * where the repository files are located (value is "home"). If this + * parameter is missing from the configuration the default value assumed is + * provided by the {@link #getDefaultRepositoryHome()} method. *

- * This parameter is mandatory for this activator to start the repository. + * If this is a relative path, it is resolved against the value of the + * sling.home framework property or against the current working + * directory as set in the user.dir system property. */ public static final String REPOSITORY_HOME_DIR = "home"; /** * The name of the configuration property defining the name of the - * repository. + * repository (value is "name"). If this parameter is missing from the + * configuration the last segment of the repository home directory is used. */ - public static final String REPOSITORY_REGISTRATION_NAME = "name"; + public static final String REPOSITORY_NAME = "name"; /** default log */ private final Logger log = LoggerFactory.getLogger(getClass()); @@ -98,7 +105,7 @@ */ private final ServiceRegistration configurerService; - public RepositoryConfigurer(final BundleContext bundleContext) { + protected RepositoryConfigurer(final BundleContext bundleContext) { this.bundleContext = bundleContext; final Hashtable cfgServiceProps = new Hashtable(); @@ -112,6 +119,14 @@ "org.osgi.service.cm.ManagedServiceFactory", this, cfgServiceProps); } + /** + * Shuts this configurer instance down by unregistering the configuration + * service and stopping all repository, which may still be running. + *

+ * This method may be overwritten by extensions. To properly shutdown the + * repositories overwriting methods must call this base class + * implementation. + */ protected void shutdown() { if (configurerService != null) { configurerService.unregister(); @@ -124,62 +139,131 @@ } } + /** + * Returns the BundleContext which is used by this instance to + * register services. + */ + protected final BundleContext getBundleContext() { + return bundleContext; + } + // ---------- Overwritable support methods + /** + * Returns the value to be set as the service.vendor property + * for all service registrations of this class. This default implementation + * returns "The Apache Software Foundation". + *

+ * This method may be overwritten by extensions to provide a different + * vendor name. + */ protected String getVendor() { return "The Apache Software Foundation"; } + /** + * Returns the value to be set as the service.description + * property of the configuration service registration of this class. This + * default implementation returns "Apache Jackrabbit Repository Configurer". + *

+ * The value returned by this method is also returned by the + * {@link #getName()} method. + *

+ * This method may be overwritten by extensions to provide a different + * configurer service description name. + */ protected String getConfigurerServiceDescription() { return "Apache Jackrabbit Repository Configurer"; } + /** + * Returns the list of services implemented by repository created by the + * {@link #createRepository(InputStream, String)} method. This default + * implementation returns { "javax.jcr.Repository", + * "org.apache.jackrabbit.api.JackrabbitRepository" }. + *

+ * This method may be overwritten by extensions to provide a different list + * of services. It is highly recommended to include the default service + * names. + */ protected String[] getRepositoryServiceNames() { return new String[] { "javax.jcr.Repository", "org.apache.jackrabbit.api.JackrabbitRepository" }; } + /** + * Returns the value to be set as the service.description + * property of the registered repository services. This default + * implementation returns "Embedded Jackrabbit Repository". + *

+ * This method may be overwritten by extensions to provide a different + * repository service description name. + */ protected String getRepositoryServiceDescription() { return "Embedded Jackrabbit Repository"; } - protected String getDefaultRepositoryUrl() { + /** + * Returns the default name of a configuration file to use for starting + * repositories. This default implementation returns "repository.xml". + *

+ * This method may be overwritten by extensions to provide a different + * default configuration file name. + */ + protected String getDefaultRepositoryConfig() { return "repository.xml"; } + /** + * Returns the default path of a repository home directory to use for + * starting repositories. This default implementation returns "repository". + *

+ * This method may be overwritten by extensions to provide a different + * default home directory path. + */ protected String getDefaultRepositoryHome() { return "repository"; } - protected InputStream openConfig(final String config) - throws FileNotFoundException, IOException { - - // 1. check for an existing file - final File configFile = new File(config); - if (configFile.isFile() && configFile.canRead()) { - log.info("startRepository: Using configuration file {}", - configFile.getAbsolutePath()); - return new FileInputStream(configFile); - } - - // 2. check for an URL - try { - - final URL configURL = new URL(config); - log.info("startRepository: Using configuration URL ", configURL); - return configURL.openStream(); - - } catch (MalformedURLException mue) { - // ignore, just check whether we can copy a default file - } - - // 3. config is a file, which we have to prepare yet - copyFile(configFile); - log.info("startRepository: Using new default configuration file {}", - configFile.getAbsolutePath()); - return new FileInputStream(configFile); + /** + * Returns an URL to a default configuration file to use if the + * configuration file indicated by the configuration file property of the + * configuration does not exist. This default implementation returns the URL + * to the "OSGI-INF/repository_osgi.xml" entry in the Jackrabbit Core + * bundle. + *

+ * This method may be overwritten by extensions to provide a different URL + * or default configuration file. + */ + protected URL getDefaultConfiguration() { + final String entryPath = "OSGI-INF/repository_osgi.xml"; + return bundleContext.getBundle().getEntry(entryPath); } + /** + * Creates the repository from the given configuration (to be read from the + * input stream) in the indicated location. This default implementation does + * the following: + * + *

+     * final RepositoryConfig crc = RepositoryConfig.create(config, home);
+     * return RepositoryImpl.create(crc);
+     * 
+ *

+ * This method may be overwritten by extensions to provide a different way + * of creating the repository. The result must be a repository object + * implementing the JackrabbitRepository interface (for the + * repository to be easily stoppable when the configuration is deleted). + * + * @param config An InputStream to read the repository + * configuration from. + * @param home The absolute path to the repository home directory + * @return The started repository (null is not a valid result). + * @throws org.apache.jackrabbit.core.config.ConfigurationException May be + * thrown if the configuration contains errors + * @throws RepositoryException If the repository cannot be started for any + * one reason. + */ protected JackrabbitRepository createRepository(final InputStream config, final String home) throws org.apache.jackrabbit.core.config.ConfigurationException, @@ -190,10 +274,26 @@ // ---------- ManagedServiceFactory interface + /** + * Returns the name of the ManagedServiceFactory which is the result of + * calling the {@link #getConfigurerServiceDescription()} method. + *

+ * This is part of the OSGi ManagedServiceFactory API and cannot be + * overwritten be extensions of this class. + */ public final String getName() { return getConfigurerServiceDescription(); } + /** + * Updates (or creates) an embedded repository identified by the given + * pid with the given configuration. If a repository of that + * name is already running, it is stopped first before it is restarted with + * the new configuration. + *

+ * This is part of the OSGi ManagedServiceFactory API and cannot be + * overwritten be extensions of this class. + */ @SuppressWarnings("unchecked") public final void updated(final String pid, final Dictionary properties) throws ConfigurationException { @@ -210,31 +310,60 @@ startRepository(pid, properties); } + /** + * Stops a running repository identified by the given pid + * because the respective configuration object has been deleted. + *

+ * This is part of the OSGi ManagedServiceFactory API and cannot be + * overwritten be extensions of this class. + */ public final void deleted(final String pid) { stopRepository(pid); } // ---------- Repository startup and shutdown + /** + * Actually sets up the RepositoryConfiguration to start the repository and + * register it under the names provided by the + * {@link #getRepositoryServiceNames()} method. + *

+ * This method is called by the {@link #updated(String, Dictionary)} method + * to start a configured repository. The overall implementation cannot be + * changed by extensions, but parts of it are modifiable by overwriting the + * respective methods. + */ private void startRepository(final String pid, final Dictionary properties) throws ConfigurationException { - final String config = getProperty(properties, REPOSITORY_CONFIG_URL, - getDefaultRepositoryUrl()); - final String home = getProperty(properties, REPOSITORY_HOME_DIR, - getDefaultRepositoryHome()); + final File homeDir = getHomeDir(properties); + final String home = homeDir.getAbsolutePath(); + + final File configFile = getConfigFile(properties, homeDir); + final String config = configFile.getAbsolutePath(); + + final String name = getProperty(properties, REPOSITORY_NAME, + homeDir.getName()); InputStream ins = null; try { - ins = openConfig(config); - final JackrabbitRepository repository = createRepository(ins, home); + ins = new FileInputStream(configFile); + final JackrabbitRepository repository = createRepository(ins, + homeDir.getAbsolutePath()); final Dictionary props = copyProperties(properties); + + // identify the service props.put(Constants.SERVICE_DESCRIPTION, getRepositoryServiceDescription()); props.put(Constants.SERVICE_VENDOR, getVendor()); + // ensure the correctly resolved configuration information + props.put(REPOSITORY_CONFIG, config); + props.put(REPOSITORY_HOME_DIR, home); + props.put(REPOSITORY_NAME, name); + final ServiceRegistration registration = bundleContext.registerService( getRepositoryServiceNames(), repository, props); @@ -269,6 +398,13 @@ } } + /** + * Unregisters and stops the repository identified with the given pid. + *

+ * This method is called from {@link #updated(String, Dictionary)} if + * configuration has been changed and from {@link #deleted(String)} if + * configuration has been deleted. + */ private void stopRepository(final String pid) { RepositoryHolder repository = repositories.remove(pid); if (repository != null) { @@ -284,28 +420,151 @@ // ---------- Repository setup helper - private String getProperty(final Dictionary properties, - final String propName, final String defaultValue) + /** + * Returns the absolute home directory file as read from the + * {@link #REPOSITORY_HOME_DIR} property. If the property is missing the + * {@link #getDefaultRepositoryHome()} value is used. If the property is a + * relative path, it is resolved by {@link #resolve(String, File)} using a + * null parent file. + * + * @throws ConfigurationException if home directory is not a directory + * and/or cannot be created. + */ + private File getHomeDir(final Dictionary properties) throws ConfigurationException { - final Object propertyObj = properties.get(propName); - if (propertyObj == null) { - return defaultValue; + + final String homePath = getProperty(properties, REPOSITORY_HOME_DIR, + getDefaultRepositoryHome()); + final File homeDir = resolve(homePath, null); + + // make sure jackrabbit home exists + if (!homeDir.isDirectory()) { + if (!homeDir.mkdirs()) { + throw new ConfigurationException(REPOSITORY_HOME_DIR, + "Cannot create repository home directory at " + + homeDir.getAbsolutePath()); + } } + return homeDir; + } + + /** + * Returns the absolute configuration file as read from the + * {@link #REPOSITORY_CONFIG} property. If the property is missing the + * {@link #getDefaultRepositoryConfig()} value is used. If the property is a + * relative path, it is resolved by {@link #resolve(String, File)} using the + * repository home directory as the parent file. If the file does not exist + * it is created from data read from the URL provided by the + * {@link #getDefaultConfiguration()}. + * + * @throws ConfigurationException If the default configuration file provided + * by the {@link #getDefaultConfiguration()} cannot be read of + * if the configuration file cannot be written. + */ + private File getConfigFile(final Dictionary properties, + final File homeDir) throws ConfigurationException { + + final String configPath = getProperty(properties, REPOSITORY_CONFIG, + getDefaultRepositoryConfig()); + final File configFile = resolve(configPath, homeDir); + + // make sure the file exists + if (!configFile.exists()) { + + // copy default config file + // access the defualt file (fail if missing) + URL defaultConfigUrl = getDefaultConfiguration(); + if (defaultConfigUrl == null) { + throw new ConfigurationException(REPOSITORY_CONFIG, + "Missing default configuration for " + + configFile.getAbsolutePath()); + } + + InputStream source = null; + OutputStream dest = null; + try { + // open the file for reading + source = defaultConfigUrl.openStream(); + + // ensure the path to the config file exists + configFile.getParentFile().mkdirs(); + + dest = new FileOutputStream(configFile); + IOUtils.copy(source, dest); + + } catch (IOException ioe) { + + throw new ConfigurationException(REPOSITORY_CONFIG, + "Failed copying default configuration file from " + + defaultConfigUrl + " to " + + configFile.getAbsolutePath(), ioe); + + } finally { + + IOUtils.closeQuietly(dest); + IOUtils.closeQuietly(source); + + } + } + + return configFile; + } + + /** + * Returns the value of the named property. If the property does not exist + * or is an empty string or is not a string type property, the default value + * is returned. + */ + private String getProperty(final Dictionary properties, + final String propName, final String defaultValue) { + final Object propertyObj = properties.get(propName); if (propertyObj instanceof String) { final String tmp = (String) propertyObj; - if (tmp == null || tmp.length() == 0) { - return getDefaultRepositoryUrl(); + if (tmp != null && tmp.length() > 0) { + return tmp; + } + } + + return defaultValue; + } + + /** + * Resolves the path name against the given parent file. If the path name + * already is an absolute path, it is returned unmodified. If the parent + * file is null the path name is resolved against the + * sling.home framework property or (if that property is + * missing) the current working directory. + */ + private File resolve(final String pathName, final File parent) { + File pathFile = new File(pathName); + if (!pathFile.isAbsolute()) { + + // resolve relative path against parent, if set + if (parent != null) { + pathFile = new File(parent, pathName); + + } else { + // otherwise check whether sling.home is set + final String slingHomePath = bundleContext.getProperty("sling.home"); + if (slingHomePath != null) { + pathFile = new File(slingHomePath, pathName); + } } - return tmp; + // ensure the File is absolute now + pathFile = pathFile.getAbsoluteFile(); } - // property is not a string - throw new ConfigurationException(propName, - "Property must be a single string value"); + return pathFile; } + /** + * Copies all public properties from the given dictionary into a new + * dictionary. A property is public if its name does not start with a dot + * (as specified in the OSGi Compendium R 4.2 Configuration Admin Service + * specification). + */ private Dictionary copyProperties( final Dictionary source) { Hashtable dest = new Hashtable(); @@ -319,41 +578,10 @@ return dest; } - private void copyFile(File destFile) throws FileNotFoundException, - IOException { - - // if the file already exists, there is nothing more to do - if (destFile.canRead()) { - return; - } - - // access the defualt file (fail if missing) - final String entryPath = "OSGI-INF/repository_osgi.xml"; - URL entryURL = bundleContext.getBundle().getEntry(entryPath); - if (entryURL == null) { - throw new FileNotFoundException(entryPath); - } - - // check for a file property - InputStream source = entryURL.openStream(); - - OutputStream dest = null; - try { - - // ensure the path to the config file exists - destFile.getParentFile().mkdirs(); - - dest = new FileOutputStream(destFile); - IOUtils.copy(source, dest); - - } finally { - - IOUtils.closeQuietly(dest); - IOUtils.closeQuietly(source); - - } - } - + /** + * The RepositoryHolder holds a repository and its service + * registration for ease management in a map. + */ private static class RepositoryHolder { private final JackrabbitRepository repository; @@ -371,4 +599,5 @@ repository.shutdown(); } } + }