$ bin/standalone.sh -c standalone.xml
ModeShape is not included with JBoss Wildfly, so none of the standard configurations include any ModeShape configurations. However, once ModeShape is installed into Wildfly, it's easy to add ModeShape to any Wildfly configuration.
Since the number of ModeShape configuration elements for Wildfly is very large, this page only provides some general configuration guidelines.
For a full list of elements & attributes we encourage reading/using the latest version of the ModeShape XML schema, which is part of the kit and is located in the docs/schema folder.
Start your server in standalone mode with your favorite configuration. For example, the following starts with the "standalone.xml" configuration file:
$ bin/standalone.sh -c standalone.xml
Use the appropriate command for your OS. See the Wildfly documentation for details.
JBoss Wildfly has a very nice low-level command line interface (CLI) tool that you can use to directly manipulate the configuration of the running server. If the server is running in domain mode, the CLI will immediately propagate the changes to all the servers.
Start the CLI and connect to your server:
$ ./bin/jboss-cli.sh You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands. [disconnected /] connect [standalone@localhost:9999 /]
ModeShape is installed, but the current configuration doesn't know about the ModeShape subsystem. So the next step is to add it:
[standalone@localhost:9999 /] /extension=org.modeshape:add() {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape:add {"outcome" => "success"}
The configuration's XML file (in this case "standalone.xml") is updated immediately. Watch the configuration file as you use the CLI.
We want to add a repository, but before we do that we need to add or configure the Wildfly resources that the repository will use.
This is an optional step as by default ModeShape will integrate with Wildfly's Application Realm. As such, you can simply add users via the add-user server script, as described here.
However, ModeShape can also use any security domain, as long as the domain defines the correct ModeShape roles for each user.
For example, since none of the out-of-the-box security domains includes these roles, let's create our own security domain that uses 2 properties files: modeshape-users.properties and modeshape-roles.properties files which should be placed in the JBOSS_HOME/standalone/configuration folder and should have the following content:
admin=admin guest=guest
and
admin=admin,connect,readonly,readwrite guest=connect,readonly
Once you've created these files in the above location, run the following commands:
[standalone@localhost:9999 /] /subsystem=security/security-domain=modeshape-security:add(cache-type=default) {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=security/security-domain=modeshape-security/authentication=classic:add(login-modules=[{"code"=>"UsersRoles","flag"=>"required","module-options"=>[("usersProperties"=>"${jboss.server.config.dir}/modeshape-users.properties"),("rolesProperties"=>"${jboss.server.config.dir}/modeshape-roles.properties")]}]) { "outcome" => "success", "response-headers" => { "operation-requires-reload" => true, "process-state" => "reload-required" } }
We need to reload the services for these changes to take effect:
[standalone@localhost:9999 /] :reload { "outcome" => "success", "response-headers" => {"process-state" => "reload-required"} } [standalone@localhost:9999 /] :reload {"outcome" => "success"}
JBoss Wildfly supports multiple kinds of security domains, including integration with LDAP and even single sign-on using the local OS. Consult the JBoss Wildfly documentation for details.
Now that we've finished defining the services that our repository will use, we can define our ModeShape "sample" repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:add(security-domain="modeshape-security") {"outcome" => "success"}
This command configures the repository to use the "modeshape-security" security domain we created earlier.
We actually didn't need to define the security-domain="modeshape-security" attribute because the repository would use a security domain with that name by default. Specifying it doesn't hurt, but any attributes that match the default value will not be serialized to the XML configuration file.
Note that defining a repository doesn't require restart. In fact, quite a few of the ModeShape administrative operations can take effect immediately, even when applications are actively using the repository.
The repository created in the previous step will only store data in memory. To make it store data on disk, we add a file persistent store
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/file-persistence=file-persistence:add {"outcome" => "success"}
With just a few commands, you can add a repository that will persist content locally. However, more advanced configuration options are available.
At any point, we can see the complete definition of a repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:read-resource(recursive=true) { "outcome" => "success", "result" => { "allow-workspace-creation" => true, "anonymous-roles" => undefined, "anonymous-username" => "<anonymous>", "binary-storage" => undefined, "cluster-name" => undefined, "cluster-stack" => undefined, "default-workspace" => "default", "enable-monitoring" => true, "jndi-name" => undefined, "minimum-binary-size" => 4096, "predefined-workspace-names" => undefined, "security-domain" => "modeshape-security", "sequencer" => undefined, "use-anonymous-upon-failed-authentication" => false } }
This shows all of the attributes, including those that are not set or set to their default values. To see more detail about each attribute and child, use the ":read-resource-description()" command:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:read-resource-description(recursive=true) { "outcome" => "success", "result" => { "description" => "ModeShape repository", "attributes" => { "jndi-name" => { "type" => STRING, "description" => "The optional alias in JNDI where this repository is to be registered, in addition to 'jcr/{repositoryName}", "expressions-allowed" => false, "nillable" => true, "min-length" => 1L, "max-length" => 2147483647L, "access-type" => "read-write", "storage" => "configuration", "restart-required" => "resource-services" }, ...
We didn't show all of the output, since it's quite long. But each attribute is described and shows the criteria for valid values, whether expressions (e.g., system variables) are allowed, and whether a restart will be required before changes take effect.
Most of the attributes do have defaults, but some of these defaults are not listed in the descriptions because the defaults are functions of other attributes. For example, every repository is registered in JNDI under "jcr/repositoryName", and also under the JNDI name explicitly set with the "jndi-name" attribute.
At this point, any deployed application can use the repository (see the the chapter) for details).
You can use the CLI to dynamically add and remove sequencers. Here's an example that adds to the "sample" repository a sequencer that operates against comma-separated value (CSV) files uploaded under the "/files" node:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:add( classname="org.modeshape.sequencer.text.DelimitedTextSequencer", module="org.modeshape.sequencer.text", path-expressions=["/files(//*.csv[*])/jcr:content[@jcr:data] => /derived/text/delimited/$1"], properties=[{ "splitPattern"=>"," }]) {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:read-resource() { "outcome" => "success", "result" => { "classname" => "org.modeshape.sequencer.text.DelimitedTextSequencer", "module" => "org.modeshape.sequencer.text", "path-expressions" => ["/files(//*.csv[*])/jcr:content[@jcr:data] => /derived/text/delimited/$1"], "properties" => [{"splitPattern" => ","}] } }
Note how this particular sequencer has an additional "splitPattern" property that specifies the delimiter.
To remove a sequencer, simply invoke the "remove" operation on the appropriate item:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:remove() {"outcome" => "success"}
TODO
In the same way you specify index storage above, you first need to add the binary storage resource to your configuration:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage:add() {"outcome" => "success"}
Once the binary storage node is added, you can add the storage type with required/optional parameters:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=file-binary-storage:add(path=/somepath) {"outcome" => "success"}
If you configure binaries to be stored on disk, the path attribute from above always represents *a relative path* to the jboss.data.dir by default. You can specify another root directory by using the relative-to attribute.
Composite binary stores are different from the rest of the standard binary stores, because they can aggregate any number of standard binary stores. Therefore configuring them via CLI is a bit different.
First, you need to configure the composite binary store in similar fashion to any other binary store:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage:add()
After this, you need to make sure that each nested store has a store-name property which is unique within the composite store and that the appropriate resource-container is used when adding the store.
Corresponding to each of the standard binary stores, the following resource-containers are available:
nested-storage-type-file - for file system binary stores
nested-storage-type-db - for database binary stores
nested-storage-type-custom - for custom (user defined) binary stores
For example, if you wanted to add a file system binary store to a composite store, you would run:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage/nested-storage-type-file=filesystem1:add(store-name=filesystem1, path="/somepath")
If you wanted to remove this store, you would run:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage/nested-storage-type-file=filesystem1:remove()
You can use the CLI to dynamically add and remove custom authentication and authorization providers. For example, if your org.modeshape.jcr.security.AuthorizationProvider implementation were named "org.example.MyAuthProvider" and were added to a new "org.example.auth" module, then the following command would add this provider to the "sample" repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:add(classname="org.example.MyAuthProvider", module="org.example.auth") {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=jaas:read-resource() { "outcome" => "success", "result" => { "classname" => "org.modeshape.jcr.security.JaasProvider", "module" => "org.modeshape", "properties" => undefined } }
To remove an authentication provider, simply invoke the "remove" operation on the appropriate item:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:remove() {"outcome" => "success"}
ModeShape can set instance-level fields on the provider instances. For example, you might want to set the "auth-domain" field on the MyAuthProvider instance to the String value "global". To do this, simply add them via the "properties" parameter (which is a list of documents that each contain a single name-value pair):
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:add(classname="org.example.MyAuthProvider", module="org.example.auth", properties=[ {"foo"=>"bar"}, {"baz"=>"bam"} ] ) {"outcome" => "success"} /subsystem=modeshape/repository=sample/authenticator=custom:read-resource() { "outcome" => "success", "result" => "org.example.MyAuthProvider", "module" => "org.example.auth", "properties" => [ {"foo" => "bar"}, {"baz" => "bam"} ] } }
When running in JBoss AS, ModeShape will always use some built-in security providers required in order to integrate with the application server's security domain (see Step 4a: Add a security domain). This means that these providers will always be invoked during the authentication / authorization process for any given user. However, when adding custom providers to the configuration, ModeShape will place those first in the list of authentication providers. So if you want to avoid defaulting to the built-in security providers, make sure your custom providers always decide if a user is authenticated or not.
First, you need to add the driver:
[standalone@localhost:9999 /] /subsystem=datasources/jdbc-driver=modeshape-driver:add(driver-name="modeshape-driver", driver-module-name="org.modeshape.jdbc", driver-class-name="org.modeshape.jdbc.LocalJcrDriver") {"outcome" => "success"}
Then, the actual datasource:
[standalone@localhost:9999 /] /subsystem=datasources/data-source="java:/datasources/ModeShapeDS":add(jndi-name="java:/datasources/ModeShapeDS",driver-name="modeshape-driver",connection-url="jdbc:jcr:jndi:jcr?repositoryName=artifacts",user-name="admin",password="admin") {"outcome" => "success"}
To enable federation, one or more external sources can be added to an existing repository.
The following example show how using the CLI an external file system source (via the FileSytemConnector) can be linked to the sample repository:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:add(classname="org.modeshape.connector.filesystem.FileSystemConnector",properties=[{"directoryPath"=>"."}], readonly="true", projections=["default:/projection1 => /"]) {"outcome" => "success"} [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:read-resource() "result" => 1", "classname" => "org.modeshape.connector.filesystem.FileSystemConnector", "module" => undefined, "projections" => ["default:/projection1 => /"], "properties" => [{"directoryPath" => "."}], "queryable" => undefined, "readonly" => "true" } }
Notice that there are several attributes that can be specified when adding an external source:
classname (mandatory) - the fully qualified name of the Connector class which allows content to be retrieved and written to that external source
module (optional) - the name of the Wildfly module where the above class can be found
projections (optional) - a list of projection expressions representing predefined projection paths for the source; projections can either be defined here or programmatically using the FederationManager.createProjection(...) method.
queryable (optional) - a flag indicating if the content exposed from the external source should be indexed by the repository or not. By default, all content is queryable.
readonly (optional) - a flag indicating if only reads or both reads and writes are possible on the source
properties (optional) - an array of key - value pairs which allow any custom attributes to be passed down on the Connector implementation class.
To remove an external source, just invoke remove on that source:
[standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:remove() {"outcome" => "success"}
When resolving configuration options which refer to external files and resources, ModeShape will use at runtime the class loader of the org.modeshape.main module. However, this class loader is isolated (cannot access) any resources which are available to another server module on which ModeShape does not explicitly depend.
In these particular cases, you can add a depends-on repository attribute which is a comma-separated list of module names which ModeShape will use in addition to its default class loader when attempting to load external files and resources.
For example, with the following configuration:
<repository name="externalDependenciesRepository" anonymous-roles="admin" depends-on="deployment.external-dependencies.war"> <workspaces default-workspace="default" allow-workspace-creation="false"> <workspace name="default"> <initial-content>config/initial-content-cars.xml</initial-content> </workspace> </workspaces> <node-types> <node-type>config/cars.cnd</node-type> </node-types> </repository>
the repository externalDependenciesRepository will be able to load the files initial-content-cars.xml and cars.cnd from the deployed external-dependencies.war, when those files are packaged inside the war file under the WEB-INF/classes/config folder.
You can combine all these commands (except for the initial /extension=org.modeshape:add() command) into a batch operation:
[standalone@localhost:9999 /] /extension=org.modeshape:add() {"outcome" => "success"} [standalone@localhost:9999 /] batch [standalone@localhost:9999 / #] (paste the commands here) [standalone@localhost:9999 / #] run-batch The batch executed successfully.
Batches can be stashed or edited before they are run, and multiple commands can be easily pasted into a batch.
The same rules apply here as for the clustering configuration in standalone Java applications with the only difference being the attribute names.
You can choose whether to use the JGroups stacks defined in JBoss AS or provide an external JGroups configuration file (identical to the one from the standalone example).
In the former case, your clustering configuration would look like:
<repository name="sample" anonymous-roles="admin" cluster-name="sample-cluster" cluster-stack="tcp"> <db-persistence datasource-jndi="java:jboss/datasources/sampleDS"/> </repository>
In this case, before configuring ModeShape to run in a cluster, make sure the JGroups subsystem is present in the Wildfly configuration:
<subsystem xmlns="urn:jboss:domain:jgroups:3.0"> <channels default="ee"> <channel name="ee"/> </channels> <stacks default="tcp"> <stack name="tcp"> <transport type="TCP" socket-binding="jgroups-tcp"/> <protocol type="MPING" socket-binding="jgroups-mping"/> <protocol type="MERGE3"/> <protocol type="FD_SOCK" socket-binding="jgroups-tcp-fd"/> <protocol type="FD"/> <protocol type="VERIFY_SUSPECT"/> <protocol type="pbcast.NAKACK2"/> <protocol type="UNICAST3"/> <protocol type="pbcast.STABLE"/> <protocol type="pbcast.GMS"/> <protocol type="MFC"/> <protocol type="FRAG2"/> <protocol type="RSVP"/> </stack> </stacks> </subsystem>
In the latter case, your configuration would point to an external JGroups file:
<repository name="repo-clustered1" anonymous-roles="admin" cluster-name="modeshape-wf-it1" cluster-config="${jboss.server.config.dir}/modeshape/jgroups-test-config.xml"> <db-persistence datasource-jndi="java:jboss/datasources/ModeshapeClusterDS1"/> </repository>
To configure a cluster repository via CLI, you could run the following commands in order:
1) Main repository
/subsystem=modeshape/repository=sample:add(cluster-stack="tcp", cluster-name="sample-cluster") /subsystem=modeshape/repository=sample/db-persistence=db-persistence:add(datasource-jndi="java:jboss/datasources/sampleDS")
This configuration uses the tcp JGroups stack defined inside the application server.
2) Binary Storage
/subsystem=modeshape/repository=sample/configuration=binary-storage:add() /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=db-binary-storage:add(data-source-jndi-name="java:jboss/datasources/sampleDS")