Permalink
Browse files

MODE-1119 Improved handling of errors in configuration

Changed the way that errors in the repository configurations are handled. Problems with
the initial content file location are reported with better messages (including that the
file cannot be found or might be empty). Also added a second "start" method on the
JcrEngine class that will automatically start all repositories in the configuration,
and will record all problems during repository initialization in the engine's problems.
This is necessary because the repository configurations are not really validated or used
until the repository is accessed; this new method provides a way to prestart all repositories
and, in the process, validate their configurations.
  • Loading branch information...
1 parent 8bf27db commit 6848d48d5ca0fcd0a67fa0b03cebca0528c5e930 @rhauch rhauch committed Mar 17, 2011
@@ -23,7 +23,10 @@
*/
package org.modeshape.graph;
+import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
@@ -2904,7 +2907,12 @@ protected Name getTypeAttribute() {
// Try the file name ...
File file = new File(pathToFile);
if (file.exists() && file.canRead()) {
- return importXmlFrom(new File(pathToFile).toURI());
+ try {
+ InputStream stream = new BufferedInputStream(new FileInputStream(file));
+ return importXmlFrom(stream);
+ } catch (FileNotFoundException e) {
+ return importXmlFrom(file.toURI());
+ }
}
// See if there is a resource on the classpath ...
ClassLoader classLoader = getClass().getClassLoader();
@@ -2914,7 +2922,11 @@ protected Name getTypeAttribute() {
}
// Try a URL ...
try {
- return importXmlFrom(new URI(pathToFile));
+ URI uri = new URI(pathToFile);
+ if (uri.isAbsolute()) {
+ // Must be absolute if we're going to turn it into a URL to resolve it ...
+ return importXmlFrom(new URI(pathToFile));
+ }
} catch (URISyntaxException e) {
// Must not be a URI ...
}
@@ -2941,6 +2953,9 @@ protected Name getTypeAttribute() {
RuntimeException error = null;
try {
stream = classLoader.getResourceAsStream(resourceName);
+ if (stream == null) {
+ throw new IllegalArgumentException(GraphI18n.errorImportingContent.text(sourceName, resourceName));
+ }
return importXmlFrom(stream);
} catch (RuntimeException e) {
error = e;
@@ -240,6 +240,30 @@
*/
RepositoryDefinition<ReturnType> registerNamespace( String prefix,
String uri );
+
+ /**
+ * Specify the location of the file containing the initial content for the repository.
+ *
+ * @param path the path to the file containing the initial content; may not be null or empty
+ * @param firstWorkspace the first workspace in which this content should be loaded
+ * @param otherWorkspaces additional workspaces in which this content should be loaded
+ * @return the interface used to set the value for the property; never null
+ */
+ RepositoryDefinition<ReturnType> setInitialContent( String path,
+ String firstWorkspace,
+ String... otherWorkspaces );
+
+ /**
+ * Specify the location of the file containing the initial content for the repository.
+ *
+ * @param file the file containing the initial content; may not be null, and must exist and be readable
+ * @param firstWorkspace the first workspace in which this content should be loaded
+ * @param otherWorkspaces additional workspaces in which this content should be loaded
+ * @return the interface used to set the value for the property; never null
+ */
+ RepositoryDefinition<ReturnType> setInitialContent( File file,
+ String firstWorkspace,
+ String... otherWorkspaces );
}
private final Map<String, RepositoryDefinition<? extends JcrConfiguration>> repositoryDefinitions = new HashMap<String, RepositoryDefinition<? extends JcrConfiguration>>();
@@ -630,6 +654,53 @@ public String getOption( Option option ) {
return addNodeTypes(new File(pathToCndFile));
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.modeshape.jcr.JcrConfiguration.RepositoryDefinition#setInitialContent(java.lang.String, java.lang.String,
+ * java.lang.String[])
+ */
+ @Override
+ public RepositoryDefinition<ReturnType> setInitialContent( String path,
+ String firstWorkspace,
+ String... otherWorkspaces ) {
+ CheckArg.isNotEmpty(path, "path");
+ path = path.trim();
+ File file = new File(path);
+ return setInitialContent(file, firstWorkspace, otherWorkspaces);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.modeshape.jcr.JcrConfiguration.RepositoryDefinition#setInitialContent(java.io.File, java.lang.String,
+ * java.lang.String[])
+ */
+ @Override
+ public RepositoryDefinition<ReturnType> setInitialContent( File file,
+ String firstWorkspace,
+ String... otherWorkspaces ) {
+ CheckArg.isNotNull(file, "file");
+ CheckArg.isNotEmpty(firstWorkspace, "firstWorkspace");
+ // Create the single comma-separated list of workspace names ...
+ String workspaces = firstWorkspace.trim();
+ if (otherWorkspaces.length != 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(workspaces); // add the first workspace
+ for (String other : otherWorkspaces) {
+ if (other == null) continue;
+ other = other.trim();
+ if (other.length() == 0) continue;
+ sb.append(',').append(other);
+ }
+ workspaces = sb.toString();
+ }
+ createIfMissing(ModeShapeLexicon.INITIAL_CONTENT).with(ModeShapeLexicon.WORKSPACES, workspaces)
+ .and(ModeShapeLexicon.CONTENT, file.getAbsolutePath())
+ .and();
+ return this;
+ }
+
public RepositoryDefinition<ReturnType> addNodeTypes( File file ) {
CheckArg.isNotNull(file, "file");
if (file.exists() && file.canRead()) {
@@ -201,6 +201,7 @@ protected void checkConfiguration( Subgraph configuration ) {
* @throws IllegalStateException if this method is called when already shut down.
* @throws JcrConfigurationException if there is an error in the configuration or any of the services that prevents proper
* startup
+ * @see #start(boolean)
* @see #shutdown()
*/
@Override
@@ -232,6 +233,32 @@ public void run() {
}
/**
+ * Start this engine to make it available for use, and optionally start each of the repositories in the configuration. Any
+ * errors starting the repositories will be logged as problems.
+ *
+ * @param validateRepositoryConfigs true if the configurations of each repository should be validated and each repository
+ * started/initialized, or false otherwise
+ * @throws IllegalStateException if this method is called when already shut down.
+ * @throws JcrConfigurationException if there is an error in the configuration or any of the services that prevents proper
+ * startup
+ * @see #start()
+ * @see #shutdown()
+ */
+ public void start( boolean validateRepositoryConfigs ) {
+ start();
+ if (validateRepositoryConfigs) {
+ for (String repositoryName : getRepositoryNames()) {
+ try {
+ getRepository(repositoryName);
+ } catch (Throwable t) {
+ // Record this in the problems ...
+ this.problems.addError(t, JcrI18n.errorStartingRepositoryCheckConfiguration, repositoryName, t.getMessage());
+ }
+ }
+ }
+ }
+
+ /**
* {@inheritDoc}
*
* @see org.modeshape.repository.ModeShapeEngine#newConfigurationException(java.lang.String)
@@ -373,7 +400,7 @@ protected JcrRepository doCreateJcrRepository( String repositoryName ) throws Re
if (repoNode == null) {
// There is no repository with the supplied name ...
throw new PathNotFoundException(Location.create(repoPath), repositoriesPath,
- JcrI18n.repositoryDoesNotExist.text(repoName));
+ JcrI18n.repositoryDoesNotExist.text(readable(repoName)));
}
Property property = repoNode.getProperty(ModeShapeLexicon.SOURCE_NAME);
if (property == null || property.isEmpty()) {
@@ -435,7 +462,12 @@ protected JcrRepository doCreateJcrRepository( String repositoryName ) throws Re
if (workspaceName != null && workspaceName.trim().length() != 0) {
// Load the content into the workspace with this name ...
sourceGraph.useWorkspace(workspaceName);
- sourceGraph.merge(initialContentGraph);
+ try {
+ sourceGraph.merge(initialContentGraph);
+ } catch (RuntimeException e) {
+ throw new RepositoryException(JcrI18n.unableToImportInitialContent.text(readable(repoName), contentRef),
+ e);
+ }
}
}
@@ -56,8 +56,10 @@
public static I18n failedToReadPropertiesFromManifest;
public static I18n failedToReadPropertyFromManifest;
public static I18n errorLoadingNodeTypeDefintions;
+ public static I18n errorStartingRepositoryCheckConfiguration;
public static I18n unableToFindNodeTypeDefinitionsOnClasspathOrFileOrUrl;
public static I18n unableToFindResourceOnClasspathOrFileOrUrl;
+ public static I18n unableToImportInitialContent;
public static I18n fileMustExistAndBeReadable;
public static I18n invalidJcrUrl;
@@ -46,8 +46,10 @@ fileDoesNotExist = Unable to find or read the file "{0}"
failedToReadPropertiesFromManifest = Error reading manifest properties: {0}
failedToReadPropertyFromManifest = "{0}" property not found in manifest
errorLoadingNodeTypeDefintions = Error loading CND file "{0}": {1}
+errorStartingRepositoryCheckConfiguration = Error starting the "{0}" repository (check the configuration): {1}
unableToFindNodeTypeDefinitionsOnClasspathOrFileOrUrl = Unable to find the node type definition file "{0}" on the classpath, as a relative or absolute file, or resolve as a URL
unableToFindResourceOnClasspathOrFileOrUrl = Unable to find "{0}" on the classpath, as a relative or absolute file, or resolve as a URL
+unableToImportInitialContent = Unable to import initial content for repository "{0}" from "{1}". Check that this file exists on the file system or classpath.
fileMustExistAndBeReadable = The file at "{0}" must exist and be readable
invalidJcrUrl = A valid JCR URL must be provided to use this method. "{0}" is not a valid JCR URL. Please consult the ModeShape Reference Guide for information on providing a valid JCR URL.
@@ -27,11 +27,14 @@
import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
import java.net.URL;
+import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Workspace;
import javax.jcr.nodetype.NodeType;
import org.junit.After;
import org.junit.Test;
+import org.modeshape.common.FixFor;
+import org.modeshape.common.collection.Problem;
import org.modeshape.graph.connector.inmemory.InMemoryRepositorySource;
import org.modeshape.jcr.JcrRepository.Option;
@@ -243,6 +246,142 @@ public void shouldAllowCreatingWorkspaces() throws Exception {
jcrSession.logout();
}
+ @FixFor( "MODE-1119" )
+ @Test
+ public void shouldCreateRepositoryConfiguredWithNoInitialContent() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start();
+ repository = engine.getRepository("cars");
+ session = repository.login();
+
+ assertNodeType("car:Car", false, false, true, false, null, 0, 11, "nt:unstructured", "mix:created");
+
+ // Check that the content is not there...
+ assertThat(session.getRootNode().hasNode("Cars"), is(false));
+ }
+
+ @FixFor( "MODE-1119" )
+ @Test
+ public void shouldCreateRepositoryConfiguredWithCorrectInitialContentPath() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setInitialContent("src/test/resources/initialWorkspaceContent.xml", "default")
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start();
+ repository = engine.getRepository("cars");
+ session = repository.login();
+
+ assertNodeType("car:Car", false, false, true, false, null, 0, 11, "nt:unstructured", "mix:created");
+
+ // Check that the content is there...
+ assertThat(session.getRootNode().hasNode("Cars"), is(true));
+ assertThat(session.getNode("/Cars"), is(notNullValue()));
+ }
+
+ @FixFor( "MODE-1119" )
+ @Test( expected = RepositoryException.class )
+ public void shouldCreateRepositoryConfiguredWithValidInitialContentPathButEmptyFile() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setInitialContent("src/test/resources/emptyFile.xml", "default")
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start();
+ repository = engine.getRepository("cars");
+ }
+
+ @FixFor( "MODE-1119" )
+ @Test( expected = RepositoryException.class )
+ public void shouldCreateRepositoryConfiguredWithIncorrectInitialContentPath() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setInitialContent("src/test/resources/blah/blah/blah", "default")
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start();
+ repository = engine.getRepository("cars");
+ }
+
+ @FixFor( "MODE-1119" )
+ @Test
+ public void shouldRecordProblemWhenStartingRepositoriesConfiguredWithValidInitialContentPathButEmptyFile() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setInitialContent("src/test/resources/emptyFile.xml", "default")
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start(true);
+ assertThat(engine.getProblems().hasErrors(), is(true));
+ assertThat(engine.getProblems().size(), is(1)); // one error
+ assertThat(engine.getProblems().iterator().next().getStatus(), is(Problem.Status.ERROR));
+ }
+
+ @FixFor( "MODE-1119" )
+ @Test
+ public void shouldRecordProblemWhenStartingRepositoriesConfiguredWithIncorrectInitialContentPath() throws Exception {
+ configuration = new JcrConfiguration();
+ configuration.repositorySource("car-source")
+ .usingClass(InMemoryRepositorySource.class)
+ .setDescription("The automobile content")
+ .setProperty("defaultWorkspaceName", "default");
+ configuration.repository("cars")
+ .setSource("car-source")
+ .registerNamespace("car", "http://www.modeshape.org/examples/cars/1.0")
+ .addNodeTypes(resourceUrl("cars.cnd"))
+ .setInitialContent("src/test/resources/blah/blah/blah", "default")
+ .setOption(Option.ANONYMOUS_USER_ROLES, ModeShapeRoles.ADMIN);
+ engine = configuration.build();
+ assertThat(engine.getProblems().hasErrors(), is(false));
+ engine.start(true);
+ assertThat(engine.getProblems().hasErrors(), is(true));
+ assertThat(engine.getProblems().size(), is(1)); // one error
+ assertThat(engine.getProblems().iterator().next().getStatus(), is(Problem.Status.ERROR));
+ }
+
protected void assertAccessibleWorkspace( Session session,
String workspaceName ) throws Exception {
assertAccessibleWorkspace(session.getWorkspace(), workspaceName);

0 comments on commit 6848d48

Please sign in to comment.