Red Hat Training

A Red Hat training course is available for Red Hat JBoss Data Virtualization

Chapter 4. Using the Hierarchical Database with Red Hat JBoss EAP

4.1. Configuring the Hierarchical Database

4.1.1. Hierarchical Database Configuration

Although JBoss Data Virtualization comes with a hierarchical database already configured, this topic describes the steps required to configure another if so desired.

Procedure 4.1. Task

  1. Start the JBoss EAP server

    Start JBoss EAP in standalone mode with the configuration of your choice. For example, the following starts with the standalone.xml configuration file:
    $ bin/standalone.sh -c=standalone.xml
  2. Start the JBoss EAP Management CLI

    You can use the JBoss EAP command line interface (CLI) tool to directly manipulate the configuration of the running server. If the server is running in domain mode, the CLI immediately propagates the changes to all the servers. Start the CLI and connect to your server as shown below:
    $ ./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 /]
  3. Add a hierarchical database subsystem

    Add the subsystem to the current configuration as shown below:
    [standalone@localhost:9999 /] /extension=org.modeshape:add()
    {"outcome" => "success"}
    [standalone@localhost:9999 /] ./subsystem=modeshape:add
    {"outcome" => "success"}
    This updates the configuration's XML file (in this case standalone.xml) immediately.
  4. Add a hierarchical database repository

    Before adding a repository, add or configure the JBoss EAP resources for the repository to use.
    1. Add an Infinispan cache

      Each hierarchical database repository stores its content in an Infinispan cache. The following steps show how to put this cache in a new cache container called modeshape, which you can use for other repositories:
      [standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape:add
      {"outcome" => "success"}
      Once you have your container, here is how you can define a local cache named sample that uses non-XA transactions and persists all content immediately to the modeshape/store/sample directory under the standalone/data directory:
      						[standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample:add
      {"outcome" => "success"}
      [standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample/transaction=TRANSACTION:add(mode=NON_XA)
      {
          "outcome" => "success",
          "response-headers" => {
              "operation-requires-reload" => true,
              "process-state" => "reload-required"
          }
      }
      [standalone@localhost:9999 /] /subsystem=infinispan/cache-container=modeshape/local-cache=sample/file-store=FILE_STORE:add(path="modeshape/store/sample",relative-to="jboss.server.data.dir",passivation=false,purge=false)
      {
          "outcome" => "success",
          "response-headers" => {"process-state" => "reload-required"}
      }
      
      These commands run successfully, however, the last few may require a reload of the Infinispan service. This means that your changes are saved to the configuration, but these few may not take effect until the next restart or until you explicitly perform the reload:
      [standalone@localhost:9999 /] :reload
      {
          "outcome" => "success",
          "response-headers" => {"process-state" => "reload-required"}
      }
      [standalone@localhost:9999 /] :reload
      {"outcome" => "success"}
    2. Add the repository

      After defining the services for the repository to use, here is how you can define a repository called sample:
      [standalone@localhost:9999 /] ./subsystem=modeshape/repository=sample:add(security-domain="modeshape-security",cache-name="sample",cache-container="modeshape")
      {"outcome" => "success"}
      This command configures the sample repository to use the sample Infinispan cache in the modeshape cache container, and to use the modeshape-security security domain created earlier. Restart is not required after defining a repository. Most of the administrative operations take effect immediately even when applications are actively using the repository.
      You need not define the security-domain="modeshape-security" attribute because the repository uses a security domain with that name by default. Also, by default the repository tries to use an Infinispan cache with the name "modeshape" which is same as the repository in the cache container. You can specify these, but any attributes that match the default value will not be serialized to the XML configuration file.

4.1.2. Advanced Repository Configuration

Procedure 4.2. Task

  1. You can view the complete definition of a repository at any point by running the following command in the Management CLI:
    	
    [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,
            "cache-container" => "modeshape",
            "cluster-name" => undefined,
            "cluster-stack" => undefined,
            "default-workspace" => "default",
            "enable-monitoring" => true,
            "index-storage" => undefined,
            "indexing-analyzer-classname" => "org.apache.lucene.analysis.standard.StandardAnalyzer",
            "indexing-analyzer-module" => undefined,
            "indexing-async-max-queue-size" => 0,
            "indexing-async-thread-pool-size" => 1,
            "indexing-batch-size" => -1,
            "indexing-mode" => "SYNC",
            "indexing-reader-strategy" => "SHARED",
            "indexing-thread-pool" => "modeshape-workers",
            "jndi-name" => undefined,
            "minimum-binary-size" => 4096,
            "predefined-workspace-names" => undefined,
            "rebuild-indexes-upon-startup" => "IF_MISSING",
            "security-domain" => "modeshape-security",
            "sequencer" => undefined,
            "use-anonymous-upon-failed-authentication" => false
        }
    }
    
    This shows all the attributes including the ones that are not set, or set to their default values.
  2. To view details about each attribute and child, use the :read-resource-description() command. For example:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample:read-resource-description(recursive=true)
    {
        "outcome" => "success",
        "result" => {
            "description" => "ModeShape repository",
            "attributes" => {
                "cache-name" => {
                    "type" => STRING,
                    "description" => "The name of the cache that is to be used for storing this repository's content",
                    "expressions-allowed" => false,
                    "nillable" => true,
                    "min-length" => 1L,
                    "max-length" => 2147483647L,
                    "access-type" => "read-write",
                    "storage" => "configuration",
                    "restart-required" => "resource-services"
                },
                "cache-container" => {
                    "type" => STRING,
                    "description" => "The name of the cache container that contains the cache to be used for storing this repository's content",
                    "expressions-allowed" => false,
                    "nillable" => true,
                    "min-length" => 1L,
                    "max-length" => 2147483647L,
                    "access-type" => "read-write",
                    "storage" => "configuration",
                    "restart-required" => "resource-services"
                },
                "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"
                },
    ...
    
    Here, the output shows the description of each attribute, the criteria for valid values, whether expressions such as system variables are allowed or not, and whether a restart is required or not before changes take effect.
    Most of the attributes have defaults, but the descriptions do not list some of the defaults 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.

4.1.3. Repository Attributes

The following table contains the list of all the attributes for a hierarchical database repository:

Table 4.1. Repository Attributes

Attribute Name Description
allow-workspace-creation Specifies whether authenticated and authorized JCR users can create additional workspaces beyond the predefined, system, and default workspaces. The default value is 'true'. Set this to 'false' when you need to fix the workspaces.
anonymous-roles The list of names (of type String) of the roles for all anonymous users. An empty String in the role name results in disabling the logins. By default, anonymous users are given all roles: 'connect', 'readonly', 'readwrite', and 'admin'.
anonymous-username The username for all anonymous users. The username <anonymous> is used by default.
cache-container The name of the Infinispan cache container containing the cache. If not provided, the "modeshape" cache container is used.
cache-name The name of the Infinispan cache where repository content is stored. If not provided, the repository name is used for the cache name.
cluster-name Defines the name of the communication channel used to share events amongst all repository instances in the cluster. By default there is no value. This means that the repository is not participating in a cluster.
cluster-stack Specifies the name of the JGroups stack used by the repository to create a channel for events when the repository is clustered. By default there is no value. This means that the repository is not participating in a cluster.
default-workspace The name of the workspace to be used when sessions are created without specifying an explicit workspace name. By default, the "default" workspace name is used.
enable-monitoring Specifies whether the repository is to maintain the metrics that can be used to monitor the performance and activities. The default value is 'true', which means that the monitoring is enabled.
indexing-analyzer-classname The fully-qualified name of the Lucene analyzer implementation class. The default value is org.apache.lucene.analysis.standard.StandardAnalyzer.
indexing-analyzer-module The name of the module that contains the specified analyzer class. No value is specified by default, which means that the class is visible to the hierarchical database engine.
indexing-async-max-queue-size The maximum size of the queue used for asynchronous indexing. By default the value is '0'. The value is ignored if synchronous indexing is enabled.
indexing-async-thread-pool-size The size of the thread pool used for asynchronous indexing. By default the value is '1'. The value is ignored if synchronous indexing is enabled.
indexing-batch-size The size of the indexing batches. The default value is '-1', which means the batch sizes are unlimited.
indexing-mode The concurrency mode for indexing. The valid values are 'SYNC' and 'ASYNC'.
indexing-reader-strategy The strategy for sharing (or not sharing) index readers. The valid values are 'SHARED' and 'NOT_SHARED'.
indexing-thread-pool The name of the thread pool that the repository indexing system should use. The default value is 'modeshape-workers'.
jndi-name The repository is always bound in JNDI to the name 'jcr/{repositoryName}', however you can use this attribute to specify an additional location in JNDI where the repository is to be registered.
minimum-binary-size The size threshold that dictates whether String and binary values should be stored in the binary store. String and binary values smaller than this value are stored with the node, whereas String and binary values with a size equal to or greater than this limit are stored separately from the node in the binary store, keyed by the SHA-1 hash of the value. This is a space and performance optimization that stores each unique large value only once. The default value is '4096' bytes, or 4 kilobytes.
predefined-workspace-names The names of the workspaces that the repository ensures exist (or create if necessary) when the repository starts up.
rebuild-indexes-upon-startup Specifies whether the indexes need to be rebuilt immediately when each process starts up. Valid values are 'IF_MISSING' , 'ALWAYS' or 'NEVER. By default the value is 'IF_MISSING'.
rebuild-upon-startup-mode Specifies whether index rebuilding at startup should be synchronous or asynchronous. Valid values are 'SYNC' and 'ASYNC'. The default value is 'SYNC'.
rebuild-upon-startup-include-system-content Specifies whether the system content area (the nodes below /jcr:system) should be indexed or not when rebuilding indexes at startup. The default value is 'FALSE'
security-domain The name of the security domain that should be used for JAAS authentication. The default value is 'modeshape-security'
use-anonymous-upon-failed-authentication Indicates that the failed authentication attempts will not result in a javax.jcr.LoginException, but will instead fall back to anonymous access. If anonymous access is not enabled, then failed login attempts throw a LoginException. The default value is 'false'.
default-initial-content The file which should be treated as the default initial content imported into all workspace.
workspaces-initial-content A set of (workspaceName, initial content file) pairs, which defines the custom initial content files for each workspace.
node-types A sequence of node-type elements, where the value of each element represents a path to a CND file. This file should be imported at repository startup.
external-sources A sequence of source elements, where each element contains the definition of an external source

4.1.4. Sequencers

Sequencers are POJOs that implement a specific interface. Sequencers allow a hierarchical database repository to help you extract more meaning from the artifacts you already are managing, and makes it much easier for applications to find and use all that valuable information. You can configure a repository with any number of sequencers and each one applies to content in the repository matching specific patterns. When content in the repository changes, it is automatically checked to see which sequencers might be able to run on the changed content. If any of the sequencers match, the hierarchical database automatically calls them by supplying the changed content. At that point, the sequencer's job is to process the supplied input, extract meaningful information, and write that derived information back into the repository where it can be accessed, searched and used by your client applications.
The derived information can take almost any form, and it typically varies for each sequencer. For example, an image sequencer is provided that extracts the simple metadata from different kinds of image files (such as JPEG, GIF, and PNG).
Another example is the Compact Node Definition (CND) sequencer that processes the CND files to extract and produce a structured representation of the node type definitions, property definitions, and child node definitions contained within the file.

4.1.5. Adding and Removing Sequencers

You can use the CLI to dynamically add and remove sequencers.

Procedure 4.3. Task

  1. Add a sequencer to the sample repository that operates against comma-separated value (CSV) files uploaded under the /files node as shown below:
    [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" => ","}]
        }
    }
    This sequencer has an additional splitPattern property that specifies the delimiter.
  2. To remove a sequencer, invoke the remove operation on the appropriate item as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/sequencer=delimited-text-sequencer:remove()
    {"outcome" => "success"}

4.1.6. Specify Index Storage

Procedure 4.4. Task

  1. To specify where indexes are stored, add the index storage resource to your configuration as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=index-storage:add()   
    {"outcome" => "success"}
  2. Once you add the index storage node, add the storage type with required optional parameters as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=index-storage/storage-type=master-file-index-storage:add(connection-factory-jndi-name=conn-name,queue-jndi-name=queue-name, path=/somepath, source-path=/someotherpath)                                       
    {"outcome" => "success"}

4.1.7. Specify Binary Storage

Procedure 4.5. Task

  1. To specify where large binary values are stored, you need to first add the binary storage resource to your configuration as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage:add()   
    {"outcome" => "success"}
  2. Once you add the binary storage node, add the storage type with the required optional parameters as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=file-binary-storage:add(path=/somepath)
    {"outcome" => "success"}

4.1.8. Configure Composite Binary Stores

Composite binary stores are different from the rest of the standard binary stores, as they can aggregate any number of standard binary stores.

Procedure 4.6. Task

  1. Configure composite binary stores via CLI as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage:add()
    Ensure that each nested store has a store-name property that 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-cache - for cache binary stores
    • nested-storage-type-db - for database binary stores
    • nested-storage-type-custom - for custom (user defined) binary stores
  2. Add a file system binary store to a composite store as shown below:
    [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")
    You can remove a file system binary store from a composite store as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=composite-binary-storage/nested-storage-type-file=filesystem1:remove()

4.1.9. Add and Remove Authentication and Authorization Providers

You can use the CLI to dynamically add and remove custom authentication and authorization providers.

Procedure 4.7. Task

  1. If your org.modeshape.jcr.security.AuthorizationProvider implementation is named org.example.MyAuthProvider and is added to a new org.example.auth module, then use the following command to 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
        }
    }
  2. To remove an authentication provider, invoke the "remove" operation on the appropriate item as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/authenticator=custom:remove()
    {"outcome" => "success"}
    

4.1.10. Set Instance-Level Fields on Provider Instances

Instance-level fields can be set on the provider instances.

Procedure 4.8. Task

  • You can set the auth-domain field on the MyAuthProvider instance to the String value "global". To do this, 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" => {
            "classname" => "org.example.MyAuthProvider",
            "module" => "org.example.auth",
            "properties" => [
                {"foo" => "bar"},
                {"baz" => "bam"}
            ]
        }
    }

4.1.11. Add JDBC Data Source

Prerequisities

  • Before adding a data source, add the driver as shown below:
    [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"}

Procedure 4.9. Task

  • Add the JDBC Data Source as shown below:
    [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"}

Note

A preconfigured datasource java:/datasources/ModeShapeDS already exists by default.

4.1.12. Add and Remove External Sources

Procedure 4.10. Task

  1. You can add one or more external sources to an existing repository to enable federation. Here is an example on how you can link an external file system source(via the FileSytemConnector) to the sample repository using the CLI:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:add(classname="org.modeshape.connector.filesystem.FileSystemConnector",properties=[{"directoryPath"=>"."}], readonly="true",
     projections=["default:/projection1 => /"], cacheTtlSeconds="1")
    {"outcome" => "success"}
     
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:read-resource()
    {
        "outcome" => "success",
        "result" => {
            "cacheTtlSeconds" => "1",
            "classname" => "org.modeshape.connector.filesystem.FileSystemConnector",
            "module" => undefined,
            "projections" => ["default:/projection1 => /"],
            "properties" => [{"directoryPath" => "."}],
            "queryable" => undefined,
            "readonly" => "true"
        }
    }
    
  2. Specify the following attributes when adding an external source:
    • classname (mandatory) - The fully qualified name of the Connector class that allows content to be retrieved and written to that external source.
    • module (optional) - The name of the JBoss EAP module where the above class is 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, this flag is set.
    • readonly (optional) - A flag indicating if only read or both read and write is possible on the source.
    • cacheTtlSeconds (optional) - The number of seconds any given node is to be held in the cache of the corresponding workspace from the external source.
    • properties (optional) - An array of key-value pairs that allow any custom attributes to be passed down on the Connector implementation class.
  3. To remove an external source, invoke the remove method on the source as shown below:
    [standalone@localhost:9999 /] /subsystem=modeshape/repository=sample/source=fsSource:remove()
    {"outcome" => "success"}

4.1.13. Working with Batch Mode

You can combine all 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.
You can edit the batches before runnning them and paste multiple commands into a batch.

4.1.14. Clustering Configuration

Before configuring the hierarchical database to run in a cluster, ensure the JGroups subsystem is present in the JBoss EAP configuration.
Then the following parts need to be configured.
  1. Replicated Infinispan caches for the repository store and the binary store:
    /subsystem=infinispan/cache-container=modeshape:add(module="org.modeshape")
    /subsystem=infinispan/cache-container=modeshape/transport=TRANSPORT:add(lock-timeout="60000")
    /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample:add(mode="SYNC", batching="true")
    /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample/transaction=TRANSACTION:add(mode=NON_XA)
    /subsystem=infinispan/cache-container=modeshape/replicated-cache=sample/file-store=FILE_STORE:add(path="modeshape/store/sample-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false)
    /subsystem=infinispan/cache-container=modeshape-binary-store:add(module="org.modeshape")
    /subsystem=infinispan/cache-container=modeshape-binary-store/transport=TRANSPORT:add(lock-timeout="60000")
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data:add(mode="SYNC", batching="true")
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data/transaction=TRANSACTION:add(mode=NON_XA)
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-data/file-store=FILE_STORE:add(path="modeshape/binary-store/sample-data-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false)
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata:add(mode="SYNC", batching="true")
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata/transaction=TRANSACTION:add(mode=NON_XA)
    /subsystem=infinispan/cache-container=modeshape-binary-store/replicated-cache=sample-binary-metadata/file-store=FILE_STORE:add(path="modeshape/binary-store/sample-metadata-${jboss.node.name}",relative-to="jboss.server.data.dir",passivation=false,purge=false)
  2. The main repository:
    /subsystem=modeshape/repository=sample:add(cache-container="modeshape",cache-name="sample",cluster-name="modeshape-sample",cluster-stack="tcp",security-domain="modeshape-security")
  3. Indexing:
    /subsystem=modeshape/repository=sample/configuration=index-storage:add()
    /subsystem=modeshape/repository=sample/configuration=index-storage/storage-type=local-file-index-storage:add(path="modeshape/indexes/sample-indexes-${jboss.node.name}")
  4. Binary Storage:
    /subsystem=modeshape/repository=sample/configuration=binary-storage:add()
    /subsystem=modeshape/repository=sample/configuration=binary-storage/storage-type=cache-binary-storage:add(data-cache-name="sample-binary-data", metadata-cache-name="sample-binary-metadata", cache-container="modeshape-binary-store")