Index: docs/reference/src/main/docbook/en-US/content/developers/tools.xml =================================================================== --- docs/reference/src/main/docbook/en-US/content/developers/tools.xml (revision 1997) +++ docs/reference/src/main/docbook/en-US/content/developers/tools.xml (working copy) @@ -342,13 +342,23 @@ ModeShape clustering uses JGroups for communication between members of a cluster, and some of our - unit and integration tests test this clustering capability. The JGroups configurations used in these tests attempt to use a network - stack that supports both IPv4 and IPv6 addresses. However, these may fail if your machine is configured only for IPv4 or IPv6. + unit and integration tests test this clustering capability. There are two common issues that you may run into when building + and testing ModeShape. + + + Firstly, the JGroups configurations used in these tests attempt to use a network + stack that supports both IPv4 and IPv6 addresses. However, these may fail (by the various engines failing to find other members + in the cluster) if your machine is configured only for IPv4 or IPv6. We've defined two Maven profiles ("preferIpv4" and "preferIpv6") that you may need to use to say whether IPv4 or IPv6 (respectively) is preferred, and you can enable these on the Maven command line by adding "-PpreferIpv4" or "-PpreferIpv6". Of course, if your command already specifies other profiles, just combine the profile names with a comma (e.g., "mvn clean install -Pintegration,preferIpv4"). + + Secondly, as with all network communications, your firewall may be blocking incoming connections to Java. If test tests + fail (again, where each engine fails to find other members in the cluster), check your firewall settings. Temporarily + disabling your firewall and rerunning the tests may help determine if your firewall is involved. + Index: modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java =================================================================== --- modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java (revision 1997) +++ modeshape-integration-tests/src/test/java/org/modeshape/test/integration/ClusteringTest.java (working copy) @@ -44,6 +44,7 @@ import javax.jcr.observation.EventListener; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.modeshape.common.collection.Problem; import org.modeshape.common.util.FileUtil; import org.modeshape.connector.store.jpa.JpaSource; import org.modeshape.jcr.JcrConfiguration; @@ -97,7 +98,16 @@ public class ClusteringTest { // Create an engine and use it to populate the source ... engine1 = configuration.build(); - engine1.start(); + try { + engine1.start(); + } catch (RuntimeException e) { + // There was a problem starting the engine ... + System.err.println("There were problems starting the engine:"); + for (Problem problem : engine1.getProblems()) { + System.err.println(problem); + } + throw e; + } Repository repository = engine1.getRepository("cars"); Index: modeshape-repository/src/main/java/org/modeshape/repository/ModeShapeEngine.java =================================================================== --- modeshape-repository/src/main/java/org/modeshape/repository/ModeShapeEngine.java (revision 1997) +++ modeshape-repository/src/main/java/org/modeshape/repository/ModeShapeEngine.java (working copy) @@ -55,6 +55,7 @@ import org.modeshape.graph.mimetype.ExtensionBasedMimeTypeDetector; import org.modeshape.graph.mimetype.MimeTypeDetector; import org.modeshape.graph.mimetype.MimeTypeDetectorConfig; import org.modeshape.graph.mimetype.MimeTypeDetectors; +import org.modeshape.graph.observe.ObservationBus; import org.modeshape.graph.property.Name; import org.modeshape.graph.property.Path; import org.modeshape.graph.property.PathExpression; @@ -355,6 +356,12 @@ public class ModeShapeEngine { * configuration repository into the services. */ protected class ConfigurationScanner { + /** + * The name of the {@link ObservationBus} implementation class that will be used when clustering. This class will be + * loaded reflectively (so that this library doesn't always require the clustering dependencies). + */ + protected static final String CLUSTERED_OBSERVATION_BUS_CLASSNAME = "org.modeshape.clustering.ClusteredObservationBus"; + private final Problems problems; private final ExecutionContext context; private final ModeShapeConfiguration.ConfigurationDefinition configurationRepository; @@ -431,11 +438,16 @@ public class ModeShapeEngine { Node clusterNode = subgraph.getRoot(); String name = stringValueOf(clusterNode); + String clusterName = stringValueOf(clusterNode, ModeShapeLexicon.CLUSTER_NAME); String desc = stringValueOf(clusterNode, ModeShapeLexicon.DESCRIPTION); String classname = stringValueOf(clusterNode, ModeShapeLexicon.CLASSNAME); String[] classpath = stringValuesOf(clusterNode, ModeShapeLexicon.CLASSPATH); if (classname == null || classname.trim().length() == 0) { - classname = "org.modeshape.clustering.ClusteredObservationBus"; + classname = CLUSTERED_OBSERVATION_BUS_CLASSNAME; + } + if (clusterName == null || clusterName.trim().length() == 0) { + problems.addError(RepositoryI18n.clusteringConfigurationRequiresClusterName); + return null; } Map properties = new HashMap(); @@ -449,7 +461,7 @@ public class ModeShapeEngine { properties.put(propertyName.getLocalName(), property.getValuesAsArray()); } } - return new ClusteringConfig(name, desc, properties, classname, classpath); + return new ClusteringConfig(clusterName, desc, properties, classname, classpath); } catch (PathNotFoundException e) { // no detectors registered ... } @@ -530,7 +542,11 @@ public class ModeShapeEngine { private String stringValueOf( Node node, Name propertyName ) { Property property = node.getProperty(propertyName); - if (property == null) return null; + if (property == null) { + // Check whether the property exists with no namespace ... + property = node.getProperty(context.getValueFactories().getNameFactory().create(propertyName.getLocalName())); + if (property == null) return null; + } if (property.isEmpty()) return null; return context.getValueFactories().getStringFactory().create(property.getFirstValue()); } @@ -538,7 +554,11 @@ public class ModeShapeEngine { private String[] stringValuesOf( Node node, Name propertyName ) { Property property = node.getProperty(propertyName); - if (property == null) return null; + if (property == null) { + // Check whether the property exists with no namespace ... + property = node.getProperty(context.getValueFactories().getNameFactory().create(propertyName.getLocalName())); + if (property == null) return null; + } return context.getValueFactories().getStringFactory().create(property.getValuesAsArray()); } Index: modeshape-repository/src/main/java/org/modeshape/repository/RepositoryI18n.java =================================================================== --- modeshape-repository/src/main/java/org/modeshape/repository/RepositoryI18n.java (revision 1997) +++ modeshape-repository/src/main/java/org/modeshape/repository/RepositoryI18n.java (working copy) @@ -60,6 +60,7 @@ public final class RepositoryI18n { // Clustering service ... public static I18n clusteringServiceName; + public static I18n clusteringConfigurationRequiresClusterName; public static I18n unableToRegisterObserverOnUnstartedClusteringService; public static I18n unableToUnregisterObserverOnUnstartedClusteringService; public static I18n unableToNotifyObserversOnUnstartedClusteringService; Index: modeshape-repository/src/main/resources/org/modeshape/repository/RepositoryI18n.properties =================================================================== --- modeshape-repository/src/main/resources/org/modeshape/repository/RepositoryI18n.properties (revision 1997) +++ modeshape-repository/src/main/resources/org/modeshape/repository/RepositoryI18n.properties (working copy) @@ -43,6 +43,7 @@ errorFindingPropertyNameInPropertyRemovedEvent = Error finding the name of the r repositoryServiceName = Repository Service clusteringServiceName = Clustering Service +clusteringConfigurationRequiresClusterName = Clustering configuration requires a non-blank 'clusterName' attribute unableToRegisterObserverOnUnstartedClusteringService = Unable to register an observer until the clustering service is started unableToUnregisterObserverOnUnstartedClusteringService = Unable to unregister an observer until the clustering service is started unableToNotifyObserversOnUnstartedClusteringService = Unable to notify observers until the clustering service is started