/**
   * Immediately change and apply the specified field in the current repository configuration to the
   * new value.
   *
   * @param defn the attribute definition for the value; may not be null
   * @param newValue the new string value
   * @throws RepositoryException if there is a problem obtaining the repository configuration or
   *     applying the change
   * @throws OperationFailedException if there is a problem obtaining the raw value from the
   *     supplied model node
   */
  public void changeField(MappedAttributeDefinition defn, ModelNode newValue)
      throws RepositoryException, OperationFailedException {
    ModeShapeEngine engine = getEngine();
    String repositoryName = repositoryName();

    // Get a snapshot of the current configuration ...
    RepositoryConfiguration config = engine.getRepositoryConfiguration(repositoryName);

    // Now start to make changes ...
    Editor editor = config.edit();

    // Find the Document containing the field ...
    EditableDocument fieldContainer = editor;
    for (String fieldName : defn.getPathToContainerOfField()) {
      fieldContainer = editor.getOrCreateDocument(fieldName);
    }

    // Get the raw value from the model node ...
    Object rawValue = defn.getTypedValue(newValue);

    // Change the field ...
    String fieldName = defn.getFieldName();
    fieldContainer.set(fieldName, rawValue);

    // Apply the changes to the current configuration ...
    Changes changes = editor.getChanges();
    engine.update(repositoryName, changes);
  }
 private void setRepositoryStorageConfiguration(
     String infinispanConfig, String cacheName, EditableDocument configDoc) {
   EditableDocument storage = configDoc.getOrCreateDocument(FieldName.STORAGE);
   storage.set(FieldName.CACHE_NAME, cacheName);
   // set the ISPN config relative path which will be resolved later on
   storage.set(FieldName.CACHE_CONFIGURATION, infinispanConfig);
 }
 @Override
 protected void writeBinaryStorageConfiguration(
     String repositoryName, OperationContext context, ModelNode model, EditableDocument binaries)
     throws OperationFailedException {
   binaries.set(FieldName.TYPE, FieldValue.BINARY_STORAGE_TYPE_DATABASE);
   // We don't need to add a dependency since we'll look it up by JNDI and we'll
   // not shutdown if the data source is shutdown
   String dataSource =
       ModelAttributes.DATA_SOURCE_JNDI_NAME.resolveModelAttribute(context, model).asString();
   binaries.set(FieldName.DATA_SOURCE_JNDI_NAME, dataSource);
 }
 private void parseCustomNodeTypes(ModelNode model, EditableDocument configDoc) {
   if (model.hasDefined(ModelKeys.NODE_TYPES)) {
     EditableArray nodeTypesArray = configDoc.getOrCreateArray(FieldName.NODE_TYPES);
     for (ModelNode nodeType : model.get(ModelKeys.NODE_TYPES).asList()) {
       nodeTypesArray.add(nodeType.asString());
     }
   }
 }
  @Override
  public void start(StartContext arg0) {
    // Not much to do, since we've already captured the properties for the index storage.
    // When this is injected into the RepositoryService, the RepositoryService will use the
    // properties to update the configuration.

    // All we need to do is update the relative paths and make them absolute, given the absolute
    // paths that are injected ...

    String binaryStorageBasePath = getBinaryStorageBasePath();
    if (binaryStorageBasePath != null) {
      // Set the binary storage directory ...
      String relativePath = binaryConfig.getString(FieldName.DIRECTORY);
      if (relativePath != null) {
        binaryConfig.set(FieldName.DIRECTORY, binaryStorageBasePath + relativePath);
      }
    }
  }
 @Override
 protected void writeBinaryStorageConfiguration(
     String repositoryName, OperationContext context, ModelNode model, EditableDocument binaries)
     throws OperationFailedException {
   super.writeCommonBinaryStorageConfiguration(repositoryName, context, model, binaries);
   binaries.set(FieldName.TYPE, FieldValue.BINARY_STORAGE_TYPE_FILE);
   String defaultPath = "modeshape/" + repositoryName + "/binaries";
   ModelNode pathNode = ModelAttributes.PATH.resolveModelAttribute(context, model);
   String path = pathNode.isDefined() ? pathNode.asString() : defaultPath;
   String relativeTo =
       ModelAttributes.RELATIVE_TO.resolveModelAttribute(context, model).asString();
   if (model.has(ModelKeys.RELATIVE_TO)
       && model.get(ModelKeys.RELATIVE_TO).asString().contains(DATA_DIR_VARIABLE)) {
     binaryStoragePathInDataDirectory = path;
   }
   path = relativeTo + path;
   binaries.set(FieldName.DIRECTORY, path);
 }
  @Test
  public void shouldStoreDocumentAndFetchAndModifyAndRefetch() throws Exception {
    // Store the document ...
    Document doc = Schematic.newDocument("k1", "value1", "k2", 2);
    Document metadata = Schematic.newDocument("mimeType", "text/plain");
    String key = "can be anything";
    SchematicEntry prior = db.put(key, doc, metadata);
    assert prior == null : "Should not have found a prior entry";

    // Read back from the database ...
    SchematicEntry entry = db.get(key);
    assert entry != null : "Should have found the entry";

    // Verify the content ...
    Document read = entry.getContentAsDocument();
    assert read != null;
    assert "value1".equals(read.getString("k1"));
    assert 2 == read.getInteger("k2");
    assert entry.getContentAsBinary() == null
        : "Should not have a Binary value for the entry's content";
    assert read.containsAll(doc);
    assert read.equals(doc);

    // Modify using an editor ...
    try {
      // tm.begin();
      EditableDocument editable = entry.editDocumentContent();
      editable.setBoolean("k3", true);
      editable.setNumber("k4", 3.5d);
    } finally {
      // tm.commit();
    }

    // Now re-read ...
    SchematicEntry entry2 = db.get(key);
    Document read2 = entry2.getContentAsDocument();
    assert read2 != null;
    assert "value1".equals(read2.getString("k1"));
    assert 2 == read2.getInteger("k2");
    assert true == read2.getBoolean("k3");
    assert 3.4d < read2.getDouble("k4");
  }
 private void parseTextExtraction(ModelNode model, EditableDocument configDoc) {
   if (model.hasDefined(ModelKeys.TEXT_EXTRACTORS_THREAD_POOL_NAME)) {
     EditableDocument extractors = configDoc.getOrCreateDocument(FieldName.TEXT_EXTRACTION);
     String poolName = model.get(ModelKeys.TEXT_EXTRACTORS_THREAD_POOL_NAME).asString();
     extractors.set(FieldName.THREAD_POOL, poolName);
   }
   if (model.hasDefined(ModelKeys.TEXT_EXTRACTORS_MAX_POOL_SIZE)) {
     EditableDocument sequencing = configDoc.getOrCreateDocument(FieldName.TEXT_EXTRACTION);
     int maxPoolSize = model.get(ModelKeys.TEXT_EXTRACTORS_MAX_POOL_SIZE).asInt();
     sequencing.set(FieldName.MAX_POOL_SIZE, maxPoolSize);
   }
 }
 private void parseSequencing(ModelNode model, EditableDocument configDoc) {
   if (model.hasDefined(ModelKeys.SEQUENCERS_THREAD_POOL_NAME)) {
     EditableDocument sequencing = configDoc.getOrCreateDocument(FieldName.SEQUENCING);
     String sequencingThreadPool = model.get(ModelKeys.SEQUENCERS_THREAD_POOL_NAME).asString();
     sequencing.set(FieldName.THREAD_POOL, sequencingThreadPool);
   }
   if (model.hasDefined(ModelKeys.SEQUENCERS_MAX_POOL_SIZE)) {
     EditableDocument sequencing = configDoc.getOrCreateDocument(FieldName.SEQUENCING);
     int maxPoolSize = model.get(ModelKeys.SEQUENCERS_MAX_POOL_SIZE).asInt();
     sequencing.set(FieldName.MAX_POOL_SIZE, maxPoolSize);
   }
 }
 private void parseReindexing(ModelNode model, EditableDocument configDoc) {
   if (model.hasDefined(ModelKeys.REINDEXING_ASYNC)) {
     EditableDocument reindexing = configDoc.getOrCreateDocument(FieldName.REINDEXING);
     boolean async = model.get(ModelKeys.REINDEXING_ASYNC).asBoolean();
     reindexing.set(FieldName.REINDEXING_ASYNC, async);
   }
   if (model.hasDefined(ModelKeys.REINDEXING_MODE)) {
     EditableDocument reindexing = configDoc.getOrCreateDocument(FieldName.REINDEXING);
     String mode = model.get(ModelKeys.REINDEXING_MODE).asString();
     reindexing.set(FieldName.REINDEXING_MODE, mode);
   }
 }
  /**
   * Immediately change and apply the specified sequencer field in the current repository
   * configuration to the new value.
   *
   * @param defn the attribute definition for the value; may not be null
   * @param newValue the new string value
   * @param sequencerName the name of the sequencer
   * @throws RepositoryException if there is a problem obtaining the repository configuration or
   *     applying the change
   * @throws OperationFailedException if there is a problem obtaining the raw value from the
   *     supplied model node
   */
  public void changeSequencerField(
      MappedAttributeDefinition defn, ModelNode newValue, String sequencerName)
      throws RepositoryException, OperationFailedException {
    ModeShapeEngine engine = getEngine();
    String repositoryName = repositoryName();

    // Get a snapshot of the current configuration ...
    RepositoryConfiguration config = engine.getRepositoryConfiguration(repositoryName);

    // Now start to make changes ...
    Editor editor = config.edit();

    // Find the array of sequencer documents ...
    List<String> pathToContainer = defn.getPathToContainerOfField();
    EditableDocument sequencing = editor.getOrCreateDocument(pathToContainer.get(0));
    EditableDocument sequencers = sequencing.getOrCreateArray(pathToContainer.get(1));

    // The container should be an array ...
    for (String configuredSequencerName : sequencers.keySet()) {
      // Look for the entry with a name that matches our sequencer name ...
      if (sequencerName.equals(configuredSequencerName)) {
        // All these entries should be nested documents ...
        EditableDocument sequencer = (EditableDocument) sequencers.get(configuredSequencerName);

        // Change the field ...
        String fieldName = defn.getFieldName();
        // Get the raw value from the model node ...
        Object rawValue = defn.getTypedValue(newValue);
        // And update the field ...
        sequencer.set(fieldName, rawValue);
        break;
      }
    }

    // Get and apply the changes to the current configuration. Note that the 'update' call
    // asynchronously
    // updates the configuration, and returns a Future<JcrRepository> that we could use if we wanted
    // to
    // wait for the changes to take place. But we don't want/need to wait, so we'll not use the
    // Future ...
    Changes changes = editor.getChanges();
    engine.update(repositoryName, changes);
  }
  /**
   * Immediately change and apply the specified extractor field in the current repository
   * configuration to the new value.
   *
   * @param defn the attribute definition for the value; may not be null
   * @param newValue the new string value
   * @param extractorName the name of the sequencer
   * @throws RepositoryException if there is a problem obtaining the repository configuration or
   *     applying the change
   * @throws OperationFailedException if there is a problem obtaining the raw value from the
   *     supplied model node
   */
  public void changeTextExtractorField(
      MappedAttributeDefinition defn, ModelNode newValue, String extractorName)
      throws RepositoryException, OperationFailedException {
    ModeShapeEngine engine = getEngine();
    String repositoryName = repositoryName();

    // Get a snapshot of the current configuration ...
    RepositoryConfiguration config = engine.getRepositoryConfiguration(repositoryName);

    // Now start to make changes ...
    Editor editor = config.edit();

    // Find the array of sequencer documents ...
    List<String> pathToContainer = defn.getPathToContainerOfField();
    EditableDocument textExtracting = editor.getOrCreateDocument(pathToContainer.get(1));
    EditableDocument extractors = textExtracting.getOrCreateDocument(pathToContainer.get(2));

    // The container should be an array ...
    for (String configuredExtractorName : extractors.keySet()) {
      // Look for the entry with a name that matches our extractor name ...
      if (extractorName.equals(configuredExtractorName)) {
        // All these entries should be nested documents ...
        EditableDocument extractor = (EditableDocument) extractors.get(configuredExtractorName);
        // Change the field ...
        String fieldName = defn.getFieldName();
        // Get the raw value from the model node ...
        Object rawValue = defn.getTypedValue(newValue);
        // And update the field ...
        extractor.set(fieldName, rawValue);
        break;
      }
    }

    Changes changes = editor.getChanges();
    engine.update(repositoryName, changes);
  }
  private void parseJournaling(
      RepositoryService repositoryService,
      OperationContext context,
      ModelNode model,
      EditableDocument configDoc)
      throws OperationFailedException {
    if (model.hasDefined(ModelKeys.JOURNALING)) {
      EditableDocument journaling = configDoc.getOrCreateDocument(FieldName.JOURNALING);

      // set it temporarily on the repository service because the final location needs to be
      // resolved later
      if (model.hasDefined(ModelKeys.JOURNAL_RELATIVE_TO)) {
        String relativeTo =
            attribute(context, model, ModelAttributes.JOURNAL_RELATIVE_TO).asString();
        repositoryService.setJournalRelativeTo(relativeTo);
      }

      // set it temporarily on the repository service because the final location needs to be
      // resolved later
      if (model.hasDefined(ModelKeys.JOURNAL_PATH)) {
        String path = attribute(context, model, ModelAttributes.JOURNAL_PATH).asString();
        repositoryService.setJournalPath(path);
      }

      int maxDaysToKeepRecords =
          attribute(context, model, ModelAttributes.MAX_DAYS_TO_KEEP_RECORDS).asInt();
      journaling.setNumber(FieldName.MAX_DAYS_TO_KEEP_RECORDS, maxDaysToKeepRecords);

      boolean asyncWrites = attribute(context, model, ModelAttributes.ASYNC_WRITES).asBoolean();
      journaling.setBoolean(FieldName.ASYNC_WRITES_ENABLED, asyncWrites);

      String gcThreadPool =
          attribute(context, model, ModelAttributes.JOURNAL_GC_THREAD_POOL).asString();
      journaling.setString(FieldName.THREAD_POOL, gcThreadPool);

      String gcInitialTime =
          attribute(context, model, ModelAttributes.JOURNAL_GC_INITIAL_TIME).asString();
      journaling.setString(FieldName.INITIAL_TIME, gcInitialTime);
    }
  }
  private void parseSecurity(OperationContext context, ModelNode model, EditableDocument configDoc)
      throws OperationFailedException {
    EditableDocument security = configDoc.getOrCreateDocument(FieldName.SECURITY);

    // Anonymous ...
    EditableDocument anon = security.getOrCreateDocument(FieldName.ANONYMOUS);
    String anonUsername = attribute(context, model, ModelAttributes.ANONYMOUS_USERNAME).asString();
    boolean useAnonIfFailed =
        attribute(context, model, ModelAttributes.USE_ANONYMOUS_IF_AUTH_FAILED).asBoolean();
    anon.set(FieldName.ANONYMOUS_USERNAME, anonUsername);
    anon.set(FieldName.USE_ANONYMOUS_ON_FAILED_LOGINS, useAnonIfFailed);
    List<ModelNode> modelNodes =
        model.hasDefined(ModelKeys.ANONYMOUS_ROLES)
            ? model.get(ModelKeys.ANONYMOUS_ROLES).asList()
            : ModelAttributes.ANONYMOUS_ROLES.getDefaultValue().asList();
    for (ModelNode roleNode : modelNodes) {
      EditableArray anonymousRolesArray = anon.getOrCreateArray(FieldName.ANONYMOUS_ROLES);
      String roleName = roleNode.asString();
      if (!StringUtil.isBlank(roleName)) {
        anonymousRolesArray.addString(roleName);
      }
    }

    EditableArray providers = security.getOrCreateArray(FieldName.PROVIDERS);

    // JBoss authenticator ...
    String securityDomain = attribute(context, model, ModelAttributes.SECURITY_DOMAIN).asString();
    EditableDocument jboss = Schematic.newDocument();
    jboss.set(FieldName.CLASSNAME, JBossDomainAuthenticationProvider.class.getName());
    jboss.set(FieldName.SECURITY_DOMAIN, securityDomain);
    providers.add(jboss);

    // Servlet authenticator ...
    EditableDocument servlet = Schematic.newDocument();
    servlet.set(FieldName.CLASSNAME, "servlet");
    providers.add(servlet);
  }
  @Override
  public void start(StartContext arg0) throws StartException {
    JcrEngine jcr = getEngine();
    try {
      final String repositoryName = repositoryConfiguration.getName();

      // Get the index storage configuration ...
      IndexStorage indexStorageConfig = indexStorageConfigInjector.getValue();
      Document queryConfig = null;
      if (indexStorageConfig != null) {
        queryConfig = indexStorageConfig.getQueryConfiguration();
      } else {
        // We'll use the default index storage, but this will be overwritten by the *IndexStorageAdd
        // operation
        // (that we're dependent upon). The default for non-AS7 ModeShape repositories is to use
        // RAM index storage, but in AS7 we want to by default store the indexes on the filesystem
        // in the
        // AS7 data directory.
        // We'll do this by setting a path relative to the data directory, and then injecting
        // the "${jboss.server.data.dir}/modeshape" path into the repository service
        // (which will then update the configuration prior to deployment) ...
        EditableDocument query = Schematic.newDocument();
        EditableDocument indexing = query.getOrCreateDocument(FieldName.INDEXING);
        EditableDocument indexStorage = query.getOrCreateDocument(FieldName.INDEX_STORAGE);
        EditableDocument backend = indexing.getOrCreateDocument(FieldName.INDEXING_BACKEND);
        query.set(FieldName.REBUILD_UPON_STARTUP, "if_needed");
        backend.set(FieldName.TYPE, FieldValue.INDEXING_BACKEND_TYPE_LUCENE);
        indexStorage.set(FieldName.TYPE, FieldValue.INDEX_STORAGE_FILESYSTEM);
        String dataDirPath = dataDirectoryPathInjector.getValue();
        indexStorage.set(
            FieldName.INDEX_STORAGE_LOCATION, dataDirPath + "/" + repositoryName + "/indexes");
        queryConfig = query;
      }
      assert queryConfig != null;

      // Get the binary storage configuration ...
      Document binaryConfig = null;
      BinaryStorage binaryStorageConfig = binaryStorageInjector.getValue();
      if (binaryStorageConfig != null) {
        binaryConfig = binaryStorageConfig.getBinaryConfiguration();
      } else {
        // By default, store the binaries in the data directory ...
        EditableDocument binaries = Schematic.newDocument();
        binaries.set(FieldName.TYPE, FieldValue.BINARY_STORAGE_TYPE_FILE);
        String dataDirPath = dataDirectoryPathInjector.getValue();
        binaries.set(FieldName.DIRECTORY, dataDirPath + "/" + repositoryName + "/binaries");
        binaryConfig = binaries;
      }

      // Now update the configuration ...
      Editor editor = repositoryConfiguration.edit();
      editor.setDocument(FieldName.QUERY, queryConfig);
      editor
          .getOrCreateDocument(FieldName.STORAGE)
          .setDocument(FieldName.BINARY_STORAGE, binaryConfig);

      // Apply the changes to the configuration ...
      editor.apply(editor.getChanges());

      // Deploy the repository and use this as the environment ...
      jcr.deploy(repositoryConfiguration.with(this));
    } catch (ConfigurationException e) {
      throw new StartException(e);
    } catch (RepositoryException e) {
      throw new StartException(e);
    }
  }
  @Override
  protected void performRuntime(
      final OperationContext context,
      final ModelNode operation,
      final ModelNode model,
      final ServiceVerificationHandler verificationHandler,
      final List<ServiceController<?>> newControllers)
      throws OperationFailedException {

    final ServiceTarget target = context.getServiceTarget();
    final AddressContext addressContext = AddressContext.forOperation(operation);
    final String repositoryName = addressContext.repositoryName();
    final String cacheName = attribute(context, model, ModelAttributes.CACHE_NAME, repositoryName);
    String infinispanConfig = attribute(context, model, ModelAttributes.CACHE_CONFIG, null);
    String configRelativeTo =
        attribute(context, model, ModelAttributes.CONFIG_RELATIVE_TO).asString();
    final boolean enableMonitoring =
        attribute(context, model, ModelAttributes.ENABLE_MONITORING).asBoolean();
    final String gcThreadPool =
        attribute(context, model, ModelAttributes.GARBAGE_COLLECTION_THREAD_POOL, null);
    final String gcInitialTime =
        attribute(context, model, ModelAttributes.GARBAGE_COLLECTION_INITIAL_TIME, null);
    final int gcIntervalInHours =
        attribute(context, model, ModelAttributes.GARBAGE_COLLECTION_INTERVAL).asInt();
    final String optThreadPool =
        attribute(context, model, ModelAttributes.DOCUMENT_OPTIMIZATION_THREAD_POOL, null);
    final String optInitialTime =
        attribute(context, model, ModelAttributes.DOCUMENT_OPTIMIZATION_INITIAL_TIME, null);
    final int optIntervalInHours =
        attribute(context, model, ModelAttributes.DOCUMENT_OPTIMIZATION_INTERVAL).asInt();
    final Integer optTarget =
        intAttribute(
            context, model, ModelAttributes.DOCUMENT_OPTIMIZATION_CHILD_COUNT_TARGET, null);
    final Integer eventBusSize = intAttribute(context, model, ModelAttributes.EVENT_BUS_SIZE, null);
    final Integer optTolerance =
        intAttribute(
            context, model, ModelAttributes.DOCUMENT_OPTIMIZATION_CHILD_COUNT_TOLERANCE, null);

    // Create a document for the repository configuration ...
    EditableDocument configDoc = Schematic.newDocument();
    configDoc.set(FieldName.NAME, repositoryName);

    // Determine the JNDI name ...
    configDoc.set(
        FieldName.JNDI_NAME,
        ""); // always set to empty string, since we'll register in JNDI here ...
    final String jndiName = ModeShapeJndiNames.JNDI_BASE_NAME + repositoryName;
    String jndiAlias = ModeShapeJndiNames.jndiNameFrom(model, repositoryName);
    if (jndiName.equals(jndiAlias)) {
      jndiAlias = null;
    }

    if (eventBusSize != null) {
      configDoc.setNumber(FieldName.EVENT_BUS_SIZE, eventBusSize);
    }

    // Parse the cache configuration
    if (StringUtil.isBlank(infinispanConfig)) {
      infinispanConfig = "modeshape/" + repositoryName + "-cache-config.xml";
    } else {
      // check if it's a system property
      String infinispanConfigSystemProperty = System.getProperty(infinispanConfig);
      if (!StringUtil.isBlank(infinispanConfigSystemProperty)) {
        infinispanConfig = infinispanConfigSystemProperty;
      }
    }
    // Set the storage information (that was set on the repository ModelNode) ...
    setRepositoryStorageConfiguration(infinispanConfig, cacheName, configDoc);

    // Always set whether monitoring is enabled ...
    enableMonitoring(enableMonitoring, configDoc);

    // Initial node-types if configured
    parseCustomNodeTypes(model, configDoc);

    // Workspace information is on the repository model node (unlike the XML) ...
    EditableDocument workspacesDoc = parseWorkspaces(context, model, configDoc);

    // security
    parseSecurity(context, model, configDoc);

    // Now create the repository service that manages the lifecycle of the JcrRepository instance
    // ...
    RepositoryConfiguration repositoryConfig =
        new RepositoryConfiguration(configDoc, repositoryName);
    String configRelativeToSystemProperty = System.getProperty(configRelativeTo);
    if (!StringUtil.isBlank(configRelativeToSystemProperty)) {
      configRelativeTo = configRelativeToSystemProperty;
    }
    if (!configRelativeTo.endsWith("/")) {
      configRelativeTo = configRelativeTo + "/";
    }
    RepositoryService repositoryService =
        new RepositoryService(repositoryConfig, infinispanConfig, configRelativeTo);
    ServiceName repositoryServiceName = ModeShapeServiceNames.repositoryServiceName(repositoryName);

    // Sequencing
    parseSequencing(model, configDoc);

    // Text Extraction
    parseTextExtraction(model, configDoc);

    // Reindexing
    parseReindexing(model, configDoc);

    // Journaling
    parseJournaling(repositoryService, context, model, configDoc);

    // Add the EngineService's dependencies ...
    ServiceBuilder<JcrRepository> repositoryServiceBuilder =
        target.addService(repositoryServiceName, repositoryService);

    // Add dependency to the ModeShape engine service ...
    repositoryServiceBuilder.addDependency(
        ModeShapeServiceNames.ENGINE, ModeShapeEngine.class, repositoryService.getEngineInjector());
    repositoryServiceBuilder.setInitialMode(ServiceController.Mode.ACTIVE);

    // Add garbage collection information ...
    if (gcThreadPool != null) {
      configDoc
          .getOrCreateDocument(FieldName.GARBAGE_COLLECTION)
          .setString(FieldName.THREAD_POOL, gcThreadPool);
    }
    if (gcInitialTime != null) {
      configDoc
          .getOrCreateDocument(FieldName.GARBAGE_COLLECTION)
          .setString(FieldName.INITIAL_TIME, gcInitialTime);
    }
    configDoc
        .getOrCreateDocument(FieldName.GARBAGE_COLLECTION)
        .setNumber(FieldName.INTERVAL_IN_HOURS, gcIntervalInHours);

    // Add document optimization information ...
    if (optTarget != null) {
      EditableDocument docOpt =
          configDoc
              .getOrCreateDocument(FieldName.STORAGE)
              .getOrCreateDocument(FieldName.DOCUMENT_OPTIMIZATION);
      if (optThreadPool != null) {
        docOpt.setString(FieldName.THREAD_POOL, optThreadPool);
      }
      if (optInitialTime != null) {
        docOpt.setString(FieldName.INITIAL_TIME, optInitialTime);
      }
      docOpt.setNumber(FieldName.INTERVAL_IN_HOURS, optIntervalInHours);
      docOpt.setNumber(FieldName.OPTIMIZATION_CHILD_COUNT_TARGET, optTarget.intValue());
      if (optTolerance != null) {
        docOpt.setNumber(FieldName.OPTIMIZATION_CHILD_COUNT_TOLERANCE, optTolerance.intValue());
      }
    }

    // Add the dependency to the Security Manager
    repositoryServiceBuilder.addDependency(
        SecurityManagementService.SERVICE_NAME,
        ISecurityManagement.class,
        repositoryService.getSecurityManagementServiceInjector());

    // Add dependency, if necessary, to the workspaces cache container
    String workspacesInfinispanConfig =
        attribute(context, model, ModelAttributes.WORKSPACES_CACHE_CONTAINER, null);
    if (workspacesInfinispanConfig != null
        && !workspacesInfinispanConfig.toLowerCase().equalsIgnoreCase(infinispanConfig)) {
      workspacesDoc.set(FieldName.WORKSPACE_CACHE_CONFIGURATION, workspacesInfinispanConfig);
    }

    repositoryServiceBuilder.addDependency(
        Services.JBOSS_SERVICE_MODULE_LOADER,
        ModuleLoader.class,
        repositoryService.getModuleLoaderInjector());

    // Set up the JNDI binder service ...
    final ReferenceFactoryService<JcrRepository> referenceFactoryService =
        new ReferenceFactoryService<JcrRepository>();
    ServiceName referenceFactoryServiceName =
        ModeShapeServiceNames.referenceFactoryServiceName(repositoryName);
    final ServiceBuilder<?> referenceBuilder =
        target.addService(referenceFactoryServiceName, referenceFactoryService);
    referenceBuilder.addDependency(
        repositoryServiceName, JcrRepository.class, referenceFactoryService.getInjector());
    referenceBuilder.setInitialMode(ServiceController.Mode.ACTIVE);

    ContextNames.BindInfo bindInfo = ContextNames.bindInfoFor(jndiName);
    BinderService binder = new BinderService(bindInfo.getBindName());
    ServiceBuilder<?> binderBuilder = target.addService(bindInfo.getBinderServiceName(), binder);
    if (jndiAlias != null) {
      ContextNames.BindInfo aliasInfo = ContextNames.bindInfoFor(jndiAlias);
      ServiceName alias = aliasInfo.getBinderServiceName();
      binderBuilder.addAliases(alias);
      LOG.debugv(
          "Binding repository {0} to JNDI name {1} and {2}",
          repositoryName, bindInfo.getAbsoluteJndiName(), aliasInfo.getAbsoluteJndiName());
    } else {
      LOG.debugv(
          "Binding repository {0} to JNDI name {1}",
          repositoryName, bindInfo.getAbsoluteJndiName());
    }
    binderBuilder.addDependency(
        referenceFactoryServiceName,
        ManagedReferenceFactory.class,
        binder.getManagedObjectInjector());
    binderBuilder.addDependency(
        bindInfo.getParentContextServiceName(),
        ServiceBasedNamingStore.class,
        binder.getNamingStoreInjector());
    binderBuilder.setInitialMode(ServiceController.Mode.ACTIVE);

    // Add dependency to the data directory ...
    ServiceName dataDirServiceName = ModeShapeServiceNames.dataDirectoryServiceName(repositoryName);
    ServiceController<String> dataDirServiceController =
        RelativePathService.addService(
            dataDirServiceName,
            "modeshape/" + repositoryName,
            ModeShapeExtension.JBOSS_DATA_DIR_VARIABLE,
            target);
    newControllers.add(dataDirServiceController);
    repositoryServiceBuilder.addDependency(
        dataDirServiceName, String.class, repositoryService.getDataDirectoryPathInjector());

    // Add the default binary storage service which will provide the binary configuration
    BinaryStorageService defaultBinaryService = BinaryStorageService.createDefault();
    ServiceName defaultBinaryStorageServiceName =
        ModeShapeServiceNames.binaryStorageDefaultServiceName(repositoryName);
    ServiceBuilder<BinaryStorage> binaryStorageBuilder =
        target.addService(defaultBinaryStorageServiceName, defaultBinaryService);
    binaryStorageBuilder.setInitialMode(ServiceController.Mode.ACTIVE);
    // Add dependency to the binaries storage service, which captures the properties for the
    // binaries storage
    repositoryServiceBuilder.addDependency(
        defaultBinaryStorageServiceName,
        BinaryStorage.class,
        repositoryService.getBinaryStorageInjector());

    // Add monitor service
    final MonitorService monitorService = new MonitorService();
    final ServiceBuilder<RepositoryMonitor> monitorBuilder =
        target.addService(ModeShapeServiceNames.monitorServiceName(repositoryName), monitorService);
    monitorBuilder.addDependency(
        ModeShapeServiceNames.repositoryServiceName(repositoryName),
        JcrRepository.class,
        monitorService.getJcrRepositoryInjector());
    monitorBuilder.setInitialMode(ServiceController.Mode.ACTIVE);

    // Now add the controller for the RepositoryService ...
    newControllers.add(repositoryServiceBuilder.install());
    newControllers.add(referenceBuilder.install());
    newControllers.add(binderBuilder.install());
    newControllers.add(binaryStorageBuilder.install());
    newControllers.add(monitorBuilder.install());
  }
 private void enableMonitoring(boolean enableMonitoring, EditableDocument configDoc) {
   EditableDocument monitoring = configDoc.getOrCreateDocument(FieldName.MONITORING);
   monitoring.set(FieldName.MONITORING_ENABLED, enableMonitoring);
 }
  private EditableDocument parseWorkspaces(
      OperationContext context, ModelNode model, EditableDocument configDoc)
      throws OperationFailedException {
    EditableDocument workspacesDoc = configDoc.getOrCreateDocument(FieldName.WORKSPACES);
    boolean allowWorkspaceCreation =
        attribute(context, model, ModelAttributes.ALLOW_WORKSPACE_CREATION).asBoolean();
    String defaultWorkspaceName =
        attribute(context, model, ModelAttributes.DEFAULT_WORKSPACE).asString();
    workspacesDoc.set(FieldName.ALLOW_CREATION, allowWorkspaceCreation);
    workspacesDoc.set(FieldName.DEFAULT, defaultWorkspaceName);
    if (model.hasDefined(ModelKeys.PREDEFINED_WORKSPACE_NAMES)) {
      for (ModelNode name : model.get(ModelKeys.PREDEFINED_WORKSPACE_NAMES).asList()) {
        workspacesDoc.getOrCreateArray(FieldName.PREDEFINED).add(name.asString());
      }

      if (model.hasDefined(ModelKeys.WORKSPACES_INITIAL_CONTENT)) {
        EditableDocument initialContentDocument =
            workspacesDoc.getOrCreateDocument(FieldName.INITIAL_CONTENT);
        List<ModelNode> workspacesInitialContent =
            model.get(ModelKeys.WORKSPACES_INITIAL_CONTENT).asList();
        for (ModelNode initialContent : workspacesInitialContent) {
          Property initialContentProperty = initialContent.asProperty();
          initialContentDocument.set(
              initialContentProperty.getName(), initialContentProperty.getValue().asString());
        }
      }
    }
    if (model.hasDefined(ModelKeys.DEFAULT_INITIAL_CONTENT)) {
      EditableDocument initialContentDocument =
          workspacesDoc.getOrCreateDocument(FieldName.INITIAL_CONTENT);
      initialContentDocument.set(
          FieldName.DEFAULT_INITIAL_CONTENT,
          model.get(ModelKeys.DEFAULT_INITIAL_CONTENT).asString());
    }
    return workspacesDoc;
  }
  @Override
  public void start(StartContext arg0) throws StartException {
    ModeShapeEngine engine = getEngine();

    try {
      final String repositoryName = repositoryName();

      // Get the index storage configuration ...
      IndexStorage indexStorageConfig = indexStorageConfigInjector.getValue();
      Document queryConfig = null;
      if (indexStorageConfig != null) {
        queryConfig = indexStorageConfig.getQueryConfiguration();
      } else {
        // We'll use the default index storage, but this will be overwritten by the *IndexStorageAdd
        // operation
        // (that we're dependent upon). The default for non-AS7 ModeShape repositories is to use
        // RAM index storage, but in AS7 we want to by default store the indexes on the filesystem
        // in the
        // AS7 data directory.
        // We'll do this by setting a path relative to the data directory, and then injecting
        // the "${jboss.server.data.dir}/modeshape" path into the repository service
        // (which will then update the configuration prior to deployment) ...
        EditableDocument query = Schematic.newDocument();
        EditableDocument indexing = query.getOrCreateDocument(FieldName.INDEXING);
        EditableDocument indexStorage = query.getOrCreateDocument(FieldName.INDEX_STORAGE);
        EditableDocument backend = indexing.getOrCreateDocument(FieldName.INDEXING_BACKEND);
        query.set(FieldName.REBUILD_UPON_STARTUP, QueryRebuild.IF_MISSING.toString().toLowerCase());
        backend.set(FieldName.TYPE, FieldValue.INDEXING_BACKEND_TYPE_LUCENE);
        indexStorage.set(FieldName.TYPE, FieldValue.INDEX_STORAGE_FILESYSTEM);
        String dataDirPath = dataDirectoryPathInjector.getValue();
        indexStorage.set(
            FieldName.INDEX_STORAGE_LOCATION, dataDirPath + "/" + repositoryName + "/indexes");
        queryConfig = query;
      }
      assert queryConfig != null;

      // Get the binary storage configuration ...
      Document binaryConfig = null;
      BinaryStorage binaryStorageConfig = binaryStorageInjector.getValue();
      if (binaryStorageConfig != null) {
        binaryConfig = binaryStorageConfig.getBinaryConfiguration();
      } else {
        // By default, store the binaries in the data directory ...
        EditableDocument binaries = Schematic.newDocument();
        binaries.set(FieldName.TYPE, FieldValue.BINARY_STORAGE_TYPE_FILE);
        String dataDirPath = dataDirectoryPathInjector.getValue();
        binaries.set(FieldName.DIRECTORY, dataDirPath + "/" + repositoryName + "/binaries");
        binaryConfig = binaries;
      }

      // Create a new configuration document ...
      EditableDocument config = Schematic.newDocument(repositoryConfiguration.getDocument());
      config.setDocument(FieldName.QUERY, queryConfig);
      config
          .getOrCreateDocument(FieldName.STORAGE)
          .setDocument(FieldName.BINARY_STORAGE, binaryConfig);

      if (LOG.isDebugEnabled()) {
        LOG.debugv("ModeShape configuration for '{0}' repository: {1}", repositoryName, config);
        Problems problems = repositoryConfiguration.validate();
        if (problems.isEmpty()) {
          LOG.debugv(
              "Problems with configuration for '{0}' repository: {1}", repositoryName, problems);
        }
      }

      // Create a new (updated) configuration ...
      repositoryConfiguration = new RepositoryConfiguration(config, repositoryName);

      // Deploy the repository and use this as the environment ...
      engine.deploy(repositoryConfiguration.with(this));
    } catch (ConfigurationException e) {
      throw new StartException(e);
    } catch (RepositoryException e) {
      throw new StartException(e);
    }
  }