Index: src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (revision 465218) +++ src/main/java/org/apache/jackrabbit/core/config/RepositoryConfig.java (working copy) @@ -31,6 +31,9 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; @@ -170,6 +173,11 @@ private final String defaultWorkspace; /** + * Information about if inherit configurance is tourned on or not. + */ + private final boolean inheritConfig; + + /** * the default parser */ private final RepositoryConfigurationParser parser; @@ -215,14 +223,15 @@ /** * Creates a repository configuration object. * - * @param template workspace configuration template * @param home repository home directory * @param sec the security configuration * @param fsc file system configuration * @param workspaceDirectory workspace root directory * @param workspaceConfigDirectory optional workspace configuration directory + * @param defaultWorkspace name of the default workspace * @param workspaceMaxIdleTime maximum workspace idle time in seconds - * @param defaultWorkspace name of the default workspace + * @param inheritConfig true if configuration inheritance is turned on + * @param template workspace configuration template * @param vc versioning configuration * @param sc search configuration for system search manager. * @param parser configuration parser @@ -230,8 +239,8 @@ public RepositoryConfig(String home, SecurityConfig sec, FileSystemConfig fsc, String workspaceDirectory, String workspaceConfigDirectory, String defaultWorkspace, int workspaceMaxIdleTime, - Element template, VersioningConfig vc, SearchConfig sc, - RepositoryConfigurationParser parser) { + boolean inheritConfig, Element template, VersioningConfig vc, + SearchConfig sc, RepositoryConfigurationParser parser) { workspaces = new HashMap(); this.home = home; this.sec = sec; @@ -244,6 +253,7 @@ this.vc = vc; this.sc = sc; this.parser = parser; + this.inheritConfig = inheritConfig; } /** @@ -354,7 +364,18 @@ parser.createSubParser(variables); return localParser.parseWorkspaceConfig(xml); } catch (FileNotFoundException e) { - return null; + if (!inheritConfig) + return null; + + String workspaceName = directory.getName(); + WorkspaceConfig wc = getWorkspaceConfig(workspaceName); + if (wc == null) { + internalCreateWorkspaceConfig(workspaceName, template); + } + + // if there was no file with specific configuration but inherit + // config is tourned on, generate config from template into memory + return wc; } } @@ -415,6 +436,52 @@ } /** + * Attempts to load a workspace configuration from the given config reader + * The configuration is parsed and returned as a workspace configuration + * object. The returned configuration object has not been initialized. + *
+ * If an invalid configuration file is found, then a + * {@link ConfigurationException ConfigurationException} is thrown. + * + * @param configDir + * workspace configuration directory in virtual file system + * @param configReader + * reader to read configuration from (e.g. file reader) + * @param configPath + * optional path if reader adheres to file + * @return workspace configuration + * @throws ConfigurationException + * if the workspace configuration is invalid + */ + private WorkspaceConfig loadWorkspaceConfig(String homeDirPath, + InputStream inputStream) + throws ConfigurationException { + Reader configReader = new InputStreamReader(inputStream); + InputSource xml = new InputSource(configReader); + + // the physical workspace home directory (TODO encode name?) + Properties variables = new Properties(); + variables.setProperty( + RepositoryConfigurationParser.WORKSPACE_HOME_VARIABLE, + homeDirPath); + RepositoryConfigurationParser localParser = parser + .createSubParser(variables); + try { + return localParser.parseWorkspaceConfig(xml); + } catch (ConfigurationException e) { + throw new ConfigurationException( + "Failed to load workspace configuration", e); + } finally { + if (configReader != null) { + try { + configReader.close(); + } catch (IOException ignore) { + } + } + } + } + + /** * Adds the given workspace configuration to the repository. * * @param wc workspace configuration @@ -442,32 +509,38 @@ * The initialized workspace configuration object is returned to * the caller. * - * @param name workspace name + * @param workspaceName workspace name * @param template the workspace template * @return created workspace configuration * @throws ConfigurationException if creating the workspace configuration * failed */ - private synchronized WorkspaceConfig internalCreateWorkspaceConfig(String name, + private synchronized WorkspaceConfig internalCreateWorkspaceConfig(String workspaceName, Element template) throws ConfigurationException { // The physical workspace home directory on disk (TODO encode name?) - File directory = new File(workspaceDirectory, name); + File directory = new File(workspaceDirectory, workspaceName); // Create the physical workspace directory, fail if it exists // or cannot be created - if (!directory.mkdir()) { + boolean success = directory.mkdir(); + if (!success) { if (directory.exists()) { - throw new ConfigurationException( - "Workspace directory already exists: " + name); + // if config inheritance is turned on, directory may exists and + // it is not an exception. + if (!inheritConfig) { + throw new ConfigurationException( + "Workspace directory already exists: " + workspaceName); + } } else { throw new ConfigurationException( - "Failed to create workspace directory: " + name); + "Failed to create workspace directory: " + workspaceName); } } - + FileSystem virtualFS; + ByteArrayOutputStream os = new ByteArrayOutputStream(); if (workspaceConfigDirectory != null) { // a configuration directoy had been specified; // workspace configurations are maintained in @@ -479,75 +552,78 @@ } try { Writer configWriter; - - // get a writer for the workspace configuration file - if (virtualFS != null) { - // a configuration directoy had been specified; create workspace - // configuration in virtual repository file system rather than - // on disk - String configDir = workspaceConfigDirectory - + FileSystem.SEPARATOR + name; - String configFile = configDir + FileSystem.SEPARATOR + WORKSPACE_XML; - try { - // Create the directory - virtualFS.createFolder(configDir); - configWriter = new OutputStreamWriter( - virtualFS.getOutputStream(configFile)); - } catch (FileSystemException e) { - throw new ConfigurationException( - "failed to create workspace configuration at path " - + configFile, e); - } + if (inheritConfig) { + configWriter = new OutputStreamWriter(os); } else { - File file = new File(directory, WORKSPACE_XML); - try { - configWriter = new FileWriter(file); - } catch (IOException e) { - throw new ConfigurationException( - "failed to create workspace configuration at path " - + file.getPath(), e); + // get a writer for the workspace configuration file + if (virtualFS != null) { + // a configuration directoy had been specified; create workspace + // configuration in virtual repository file system rather than + // on disk + String configDir = workspaceConfigDirectory + + FileSystem.SEPARATOR + workspaceName; + String configFile = configDir + FileSystem.SEPARATOR + WORKSPACE_XML; + try { + // Create the directory + virtualFS.createFolder(configDir); + configWriter = new OutputStreamWriter(virtualFS + .getOutputStream(configFile)); + } catch (FileSystemException e) { + throw new ConfigurationException( + "failed to create workspace configuration at path " + + configFile, e); + } + } else { + File file = new File(directory, WORKSPACE_XML); + try { + configWriter = new FileWriter(file); + } catch (IOException e) { + throw new ConfigurationException( + "failed to create workspace configuration at path " + + file.getPath(), e); + } } } - // Create the workspace.xml file using the configuration template and - // the configuration writer. - try { - template.setAttribute("name", name); + transformTemplateToWriter(workspaceName, template, configWriter); - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer transformer = factory.newTransformer(); - transformer.setOutputProperty(OutputKeys.INDENT, "yes"); - transformer.transform( - new DOMSource(template), new StreamResult(configWriter)); - } catch (TransformerConfigurationException e) { - throw new ConfigurationException( - "Cannot create a workspace configuration writer", e); - } catch (TransformerException e) { - throw new ConfigurationException( - "Cannot create a workspace configuration file", e); - } finally { - try { - configWriter.close(); - } catch (IOException ignore) { - } - } - // Load the created workspace configuration. WorkspaceConfig wc; - if (virtualFS != null) { - String configDir = workspaceConfigDirectory - + FileSystem.SEPARATOR + name; - wc = loadWorkspaceConfig(virtualFS, configDir); + + if (inheritConfig) { + String homeDirPath; + if (virtualFS != null) { + String configDir = workspaceConfigDirectory + + FileSystem.SEPARATOR + workspaceName; + File homeDir = new File(workspaceDirectory, + FileSystemPathUtil.getName(configDir)); + if (!homeDir.exists()) { + homeDir.mkdir(); + } + homeDirPath = homeDir.getPath(); + } else { + homeDirPath = directory.getPath(); + } + + InputStream is = new ByteArrayInputStream(os.toByteArray()); + wc = loadWorkspaceConfig(homeDirPath, is); } else { - wc = loadWorkspaceConfig(directory); - } + if (virtualFS != null) { + String configDir = workspaceConfigDirectory + + FileSystem.SEPARATOR + workspaceName; + wc = loadWorkspaceConfig(virtualFS, configDir); + } else { + wc = loadWorkspaceConfig(directory); + } + } + if (wc != null) { addWorkspaceConfig(wc); return wc; } else { throw new ConfigurationException( "Failed to load the created configuration for workspace " - + name + "."); + + workspaceName + "."); } } finally { try { @@ -560,6 +636,44 @@ } /** + * Create the workspace.xml file using the configuration template and the + * configuration writer. + * + * @param workspaceName + * workspace name + * @param template + * the workspace template + * @param configWriter + * writer to write result of transformation to. Writer is closed + * after method invocation. + * @throws ConfigurationException + */ + private void transformTemplateToWriter(String workspaceName, + Element template, Writer configWriter) + throws ConfigurationException { + try { + template.setAttribute("name", workspaceName); + + TransformerFactory factory = TransformerFactory.newInstance(); + Transformer transformer = factory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.transform(new DOMSource(template), new StreamResult( + configWriter)); + } catch (TransformerConfigurationException e) { + throw new ConfigurationException( + "Cannot create a workspace configuration writer", e); + } catch (TransformerException e) { + throw new ConfigurationException( + "Cannot create a workspace configuration file", e); + } finally { + try { + configWriter.close(); + } catch (IOException ignore) { + } + } + } + + /** * Creates a new workspace configuration with the specified name. * This method creates a workspace configuration subdirectory, * copies the workspace configuration template into it, and finally @@ -727,5 +841,15 @@ public SearchConfig getSearchConfig() { return sc; } + + /** + * This methods indicates if workspace configuration inheritance is turned + * on or not. + * @return true if workspace configuration inheritance is turned on, false + * otherwise. + */ + public boolean isInheritConfig() { + return inheritConfig; + } } Index: src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (revision 465218) +++ src/main/java/org/apache/jackrabbit/core/config/RepositoryConfigurationParser.java (working copy) @@ -19,6 +19,7 @@ import java.io.File; import java.util.Properties; +import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -96,6 +97,9 @@ public static final String DEFAULT_WORKSPACE_ATTRIBUTE = "defaultWorkspace"; + /** Name of the inherit config configuration attribute. */ + public static final String INHERIT_CONFIG_ATTRIBUTE = "inheritConfig"; + /** Name of the default search index implementation class. */ public static final String DEFAULT_QUERY_HANDLER = "org.apache.jackrabbit.core.query.lucene.SearchIndex"; @@ -184,6 +188,15 @@ String defaultWorkspace = replaceVariables( getAttribute(workspaces, DEFAULT_WORKSPACE_ATTRIBUTE)); + boolean inheritConfig = false; + Attr inherigConfigAttribute = workspaces + .getAttributeNode(INHERIT_CONFIG_ATTRIBUTE); + if (inherigConfigAttribute != null) { + String inheritConfigValue = replaceVariables(inherigConfigAttribute + .getValue()); + inheritConfig = "true".equals(inheritConfigValue); + } + int maxIdleTime = Integer.parseInt( getAttribute(workspaces, MAX_IDLE_TIME_ATTRIBUTE, "0")); @@ -198,7 +211,7 @@ return new RepositoryConfig(home, securityConfig, fsc, workspaceDirectory, workspaceConfigDirectory, defaultWorkspace, - maxIdleTime, template, vc, sc, this); + maxIdleTime, inheritConfig, template, vc, sc, this); } /** Index: src/test/java/org/apache/jackrabbit/core/config/repository.xml =================================================================== --- src/test/java/org/apache/jackrabbit/core/config/repository.xml (revision 465218) +++ src/test/java/org/apache/jackrabbit/core/config/repository.xml (working copy) @@ -117,7 +117,8 @@ rootPath CDATA #REQUIRED defaultWorkspace CDATA #REQUIRED configRootPath CDATA #IMPLIED - maxIdleTime CDATA #IMPLIED> + maxIdleTime CDATA #IMPLIED + inheritConfig (true|false) #IMPLIED>