private void writeTextExtraction(XMLExtendedStreamWriter writer, ModelNode repository)
      throws XMLStreamException {
    if (has(repository, ModelKeys.TEXT_EXTRACTOR)) {
      writer.writeStartElement(Element.TEXT_EXTRACTORS.getLocalName());
      if (repository.hasDefined(ModelKeys.TEXT_EXTRACTORS_THREAD_POOL_NAME)) {
        writer.writeAttribute(
            Attribute.THREAD_POOL_NAME.getLocalName(),
            repository.get(ModelKeys.TEXT_EXTRACTORS_THREAD_POOL_NAME).asString());
      }
      if (repository.hasDefined(ModelKeys.TEXT_EXTRACTORS_MAX_POOL_SIZE)) {
        writer.writeAttribute(
            Attribute.MAX_POOL_SIZE.getLocalName(),
            repository.get(ModelKeys.TEXT_EXTRACTORS_MAX_POOL_SIZE).asString());
      }
      for (Property extractor : repository.get(ModelKeys.TEXT_EXTRACTOR).asPropertyList()) {
        writer.writeStartElement(Element.TEXT_EXTRACTOR.getLocalName());
        writer.writeAttribute(Attribute.NAME.getLocalName(), extractor.getName());
        ModelNode prop = extractor.getValue();
        ModelAttributes.TEXT_EXTRACTOR_CLASSNAME.marshallAsAttribute(prop, writer);
        ModelAttributes.MODULE.marshallAsAttribute(prop, writer);

        // Write out the extra properties ...
        if (has(prop, ModelKeys.PROPERTIES)) {
          ModelNode properties = prop.get(ModelKeys.PROPERTIES);
          for (Property property : properties.asPropertyList()) {
            writer.writeAttribute(property.getName(), property.getValue().asString());
          }
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
  }
 private void parseAuthenticator(final XMLExtendedStreamReader reader, final ModelNode repository)
     throws XMLStreamException {
   if (reader.getAttributeCount() > 0) {
     ModelNode authenticator = new ModelNode();
     for (int i = 0; i < reader.getAttributeCount(); i++) {
       String attrName = reader.getAttributeLocalName(i);
       String attrValue = reader.getAttributeValue(i);
       Attribute attribute = Attribute.forName(attrName);
       switch (attribute) {
           // Set these as properties on the repository ModelNode ...
         case NAME:
           ModelAttributes.NAME.parseAndSetParameter(attrValue, authenticator, reader);
           break;
         case CLASSNAME:
           ModelAttributes.CLASSNAME.parseAndSetParameter(attrValue, authenticator, reader);
           if (!authenticator.has(ModelKeys.NAME)) {
             ModelAttributes.NAME.parseAndSetParameter(attrValue, authenticator, reader);
           }
           break;
         case MODULE:
           ModelAttributes.MODULE.parseAndSetParameter(attrValue, authenticator, reader);
           break;
         default:
           authenticator.get(attrName).set(attrValue);
           break;
       }
     }
     if (authenticator.has(ModelKeys.NAME))
       repository.get(ModelKeys.AUTHENTICATORS).add(authenticator);
   }
   requireNoElements(reader);
 }
  private void writeIndexProviders(XMLExtendedStreamWriter writer, ModelNode repository)
      throws XMLStreamException {
    if (has(repository, ModelKeys.INDEX_PROVIDER)) {
      writer.writeStartElement(Element.INDEX_PROVIDERS.getLocalName());
      ModelNode providerNode = repository.get(ModelKeys.INDEX_PROVIDER);
      for (Property provider : providerNode.asPropertyList()) {
        writer.writeStartElement(Element.INDEX_PROVIDER.getLocalName());
        writer.writeAttribute(Attribute.NAME.getLocalName(), provider.getName());
        ModelNode prop = provider.getValue();
        ModelAttributes.CLASSNAME.marshallAsAttribute(prop, writer);
        ModelAttributes.MODULE.marshallAsAttribute(prop, writer);
        ModelAttributes.RELATIVE_TO.marshallAsAttribute(prop, writer);
        ModelAttributes.PATH.marshallAsAttribute(prop, writer);

        // Write out the extra properties ...
        if (has(prop, ModelKeys.PROPERTIES)) {
          ModelNode properties = prop.get(ModelKeys.PROPERTIES);
          for (Property property : properties.asPropertyList()) {
            writer.writeAttribute(property.getName(), property.getValue().asString());
          }
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
  }
  private void parseSequencer(
      XMLExtendedStreamReader reader, String repositoryName, final List<ModelNode> sequencers)
      throws XMLStreamException {

    final ModelNode sequencer = new ModelNode();
    sequencer.get(OP).set(ADD);
    String name = null;

    sequencers.add(sequencer);

    if (reader.getAttributeCount() > 0) {
      for (int i = 0; i < reader.getAttributeCount(); i++) {
        String attrName = reader.getAttributeLocalName(i);
        String attrValue = reader.getAttributeValue(i);
        Attribute attribute = Attribute.forName(attrName);
        switch (attribute) {
          case NAME:
            name = attrValue;
            break;
          case PATH_EXPRESSION:
            ModelAttributes.PATH_EXPRESSIONS.parseAndAddParameterElement(
                attrValue, sequencer, reader);
            break;
          case CLASSNAME:
            ModelAttributes.SEQUENCER_CLASSNAME.parseAndSetParameter(attrValue, sequencer, reader);
            if (name == null) name = attrValue;
            break;
          case MODULE:
            ModelAttributes.MODULE.parseAndSetParameter(attrValue, sequencer, reader);
            break;
          default:
            // extra attributes are allowed to set sequencer-specific properties ...
            sequencer.get(ModelKeys.PROPERTIES).add(attrName, attrValue);
            break;
        }
      }
    }

    while (reader.hasNext() && (reader.nextTag() != XMLStreamConstants.END_ELEMENT)) {
      final Element element = Element.forName(reader.getLocalName());
      switch (element) {
        case PATH_EXPRESSION:
          String value = reader.getElementText();
          ModelAttributes.PATH_EXPRESSIONS.parseAndAddParameterElement(value, sequencer, reader);
          break;
        default:
          throw ParseUtils.unexpectedElement(reader);
      }
    }

    sequencer
        .get(OP_ADDR)
        .add(SUBSYSTEM, ModeShapeExtension.SUBSYSTEM_NAME)
        .add(ModelKeys.REPOSITORY, repositoryName)
        .add(ModelKeys.SEQUENCER, name);
  }
  private void writeSequencing(XMLExtendedStreamWriter writer, ModelNode repository)
      throws XMLStreamException {
    if (has(repository, ModelKeys.SEQUENCER)) {
      writer.writeStartElement(Element.SEQUENCERS.getLocalName());
      if (repository.hasDefined(ModelKeys.SEQUENCERS_THREAD_POOL_NAME)) {
        writer.writeAttribute(
            Attribute.THREAD_POOL_NAME.getLocalName(),
            repository.get(ModelKeys.SEQUENCERS_THREAD_POOL_NAME).asString());
      }
      if (repository.hasDefined(ModelKeys.SEQUENCERS_MAX_POOL_SIZE)) {
        writer.writeAttribute(
            Attribute.MAX_POOL_SIZE.getLocalName(),
            repository.get(ModelKeys.SEQUENCERS_MAX_POOL_SIZE).asString());
      }

      ModelNode sequencerNode = repository.get(ModelKeys.SEQUENCER);

      for (Property sequencer : sequencerNode.asPropertyList()) {
        writer.writeStartElement(Element.SEQUENCER.getLocalName());
        writer.writeAttribute(Attribute.NAME.getLocalName(), sequencer.getName());
        ModelNode prop = sequencer.getValue();
        ModelAttributes.SEQUENCER_CLASSNAME.marshallAsAttribute(prop, writer);
        ModelAttributes.MODULE.marshallAsAttribute(prop, writer);

        // Write out the extra properties ...
        if (has(prop, ModelKeys.PROPERTIES)) {
          ModelNode properties = prop.get(ModelKeys.PROPERTIES);
          for (Property property : properties.asPropertyList()) {
            writer.writeAttribute(property.getName(), property.getValue().asString());
          }
        }
        if (has(prop, ModelKeys.PATH_EXPRESSIONS)) {
          List<ModelNode> pathExpressions = prop.get(ModelKeys.PATH_EXPRESSIONS).asList();
          switch (pathExpressions.size()) {
            case 0:
              break;
            case 1:
              ModelNode pathExpression = pathExpressions.iterator().next();
              writer.writeAttribute(
                  Attribute.PATH_EXPRESSION.getLocalName(), pathExpression.asString());
              break;
            default:
              for (ModelNode pathExpr : pathExpressions) {
                writer.writeStartElement(Element.PATH_EXPRESSION.getLocalName());
                writer.writeCharacters(pathExpr.asString());
                writer.writeEndElement();
              }
          }
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
  }
  private void parseTextExtractor(
      XMLExtendedStreamReader reader, String repositoryName, final List<ModelNode> extractors)
      throws XMLStreamException {

    final ModelNode extractor = new ModelNode();
    extractor.get(OP).set(ADD);
    String name = null;

    extractors.add(extractor);

    if (reader.getAttributeCount() > 0) {
      for (int i = 0; i < reader.getAttributeCount(); i++) {
        String attrName = reader.getAttributeLocalName(i);
        String attrValue = reader.getAttributeValue(i);
        Attribute attribute = Attribute.forName(attrName);
        switch (attribute) {
          case NAME:
            name = attrValue;
            break;
          case CLASSNAME:
            ModelAttributes.TEXT_EXTRACTOR_CLASSNAME.parseAndSetParameter(
                attrValue, extractor, reader);
            if (name == null) name = attrValue;
            break;
          case MODULE:
            ModelAttributes.MODULE.parseAndSetParameter(attrValue, extractor, reader);
            break;
          default:
            // extra attributes are allowed to set extractor-specific properties ...
            extractor.get(ModelKeys.PROPERTIES).add(attrName, attrValue);
            break;
        }
      }
    }

    extractor
        .get(OP_ADDR)
        .add(SUBSYSTEM, ModeShapeExtension.SUBSYSTEM_NAME)
        .add(ModelKeys.REPOSITORY, repositoryName)
        .add(ModelKeys.TEXT_EXTRACTOR, name);

    requireNoElements(reader);
  }
  private void writeExternalSources(XMLExtendedStreamWriter writer, ModelNode repository)
      throws XMLStreamException {
    if (has(repository, ModelKeys.SOURCE)) {
      writer.writeStartElement(Element.EXTERNAL_SOURCES.getLocalName());
      ModelNode externalSourceNode = repository.get(ModelKeys.SOURCE);
      for (Property externalSource : externalSourceNode.asPropertyList()) {
        writer.writeStartElement(Element.SOURCE.getLocalName());
        writer.writeAttribute(Attribute.NAME.getLocalName(), externalSource.getName());

        ModelNode prop = externalSource.getValue();
        ModelAttributes.CONNECTOR_CLASSNAME.marshallAsAttribute(prop, writer);
        ModelAttributes.MODULE.marshallAsAttribute(prop, writer);
        ModelAttributes.CACHE_TTL_SECONDS.marshallAsAttribute(prop, writer);
        ModelAttributes.QUERYABLE.marshallAsAttribute(prop, writer);
        ModelAttributes.READONLY.marshallAsAttribute(prop, writer);
        ModelAttributes.EXPOSE_AS_WORKSPACE.marshallAsAttribute(prop, writer);

        // Write out the extra properties ...
        if (has(prop, ModelKeys.PROPERTIES)) {
          ModelNode properties = prop.get(ModelKeys.PROPERTIES);
          for (Property property : properties.asPropertyList()) {
            writer.writeAttribute(property.getName(), property.getValue().asString());
          }
        }

        if (has(prop, ModelKeys.PROJECTIONS)) {
          List<ModelNode> projections = prop.get(ModelKeys.PROJECTIONS).asList();
          for (ModelNode projection : projections) {
            writer.writeStartElement(Element.PROJECTION.getLocalName());
            writer.writeCharacters(projection.asString());
            writer.writeEndElement();
          }
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
  }
  private void writeAuthenticators(XMLExtendedStreamWriter writer, ModelNode repository)
      throws XMLStreamException {
    if (has(repository, ModelKeys.AUTHENTICATOR)) {
      writer.writeStartElement(Element.AUTHENTICATORS.getLocalName());
      for (Property authenticator : repository.get(ModelKeys.AUTHENTICATOR).asPropertyList()) {
        writer.writeStartElement(Element.AUTHENTICATOR.getLocalName());
        writer.writeAttribute(Attribute.NAME.getLocalName(), authenticator.getName());
        ModelNode prop = authenticator.getValue();
        ModelAttributes.AUTHENTICATOR_CLASSNAME.marshallAsAttribute(prop, writer);
        ModelAttributes.MODULE.marshallAsAttribute(prop, writer);

        // Write out the extra properties ...
        if (has(prop, ModelKeys.PROPERTIES)) {
          ModelNode properties = prop.get(ModelKeys.PROPERTIES);
          for (Property property : properties.asPropertyList()) {
            writer.writeAttribute(property.getName(), property.getValue().asString());
          }
        }
        writer.writeEndElement();
      }
      writer.writeEndElement();
    }
  }
  private ModelNode parseCustomBinaryStorage(
      final XMLExtendedStreamReader reader, final String repositoryName) throws XMLStreamException {
    final ModelNode storageType = new ModelNode();
    storageType.get(OP).set(ADD);
    storageType
        .get(OP_ADDR)
        .add(SUBSYSTEM, ModeShapeExtension.SUBSYSTEM_NAME)
        .add(ModelKeys.REPOSITORY, repositoryName)
        .add(ModelKeys.CONFIGURATION, ModelKeys.BINARY_STORAGE)
        .add(ModelKeys.STORAGE_TYPE, ModelKeys.CUSTOM_BINARY_STORAGE);

    if (reader.getAttributeCount() > 0) {
      for (int i = 0; i < reader.getAttributeCount(); i++) {
        String attrName = reader.getAttributeLocalName(i);
        String attrValue = reader.getAttributeValue(i);
        Attribute attribute = Attribute.forName(attrName);
        switch (attribute) {
          case CLASSNAME:
            ModelAttributes.CLASSNAME.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case MODULE:
            ModelAttributes.MODULE.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case MIN_VALUE_SIZE:
            ModelAttributes.MINIMUM_BINARY_SIZE.parseAndSetParameter(
                attrValue, storageType, reader);
            break;
          default:
            storageType.get(attrName).set(attrValue);
            break;
        }
      }
    }
    requireNoElements(reader);

    return storageType;
  }
  private ModelNode parseCustomIndexStorage(
      final XMLExtendedStreamReader reader, final String repositoryName) throws XMLStreamException {
    final ModelNode storageType = new ModelNode();
    storageType.get(OP).set(ADD);
    storageType
        .get(OP_ADDR)
        .add(SUBSYSTEM, ModeShapeExtension.SUBSYSTEM_NAME)
        .add(ModelKeys.REPOSITORY, repositoryName)
        .add(ModelKeys.CONFIGURATION, ModelKeys.INDEX_STORAGE)
        .add(ModelKeys.STORAGE_TYPE, ModelKeys.CUSTOM_INDEX_STORAGE);

    if (reader.getAttributeCount() > 0) {
      for (int i = 0; i < reader.getAttributeCount(); i++) {
        String attrName = reader.getAttributeLocalName(i);
        String attrValue = reader.getAttributeValue(i);
        Attribute attribute = Attribute.forName(attrName);
        switch (attribute) {
            // Set these as properties on the repository ModelNode ...
          case FORMAT:
            ModelAttributes.INDEX_FORMAT.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case REBUILD_UPON_STARTUP:
            ModelAttributes.REBUILD_INDEXES_UPON_STARTUP.parseAndSetParameter(
                attrValue, storageType, reader);
            break;
          case THREAD_POOL:
            ModelAttributes.THREAD_POOL.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case BATCH_SIZE:
            ModelAttributes.BATCH_SIZE.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case READER_STRATEGY:
            ModelAttributes.READER_STRATEGY.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case MODE:
            ModelAttributes.MODE.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case ASYNC_THREAD_POOL_SIZE:
            ModelAttributes.ASYNC_THREAD_POOL_SIZE.parseAndSetParameter(
                attrValue, storageType, reader);
            break;
          case ASYNC_MAX_QUEUE_SIZE:
            ModelAttributes.ASYNC_MAX_QUEUE_SIZE.parseAndSetParameter(
                attrValue, storageType, reader);
            break;
          case ANALYZER_CLASSNAME:
            ModelAttributes.ANALYZER_CLASSNAME.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case ANALYZER_MODULE:
            ModelAttributes.ANALYZER_MODULE.parseAndSetParameter(attrValue, storageType, reader);
            break;
            // The rest go on the ModelNode for the type ...
          case CLASSNAME:
            ModelAttributes.CLASSNAME.parseAndSetParameter(attrValue, storageType, reader);
            break;
          case MODULE:
            ModelAttributes.MODULE.parseAndSetParameter(attrValue, storageType, reader);
            break;
          default:
            storageType.get(attrName).set(attrValue);
            break;
        }
      }
    }
    requireNoElements(reader);

    return storageType;
  }
  private void writeBinaryStorageModel(
      XMLExtendedStreamWriter writer, String storageType, ModelNode storage)
      throws XMLStreamException {
    if (ModelKeys.FILE_BINARY_STORAGE.equals(storageType)) {
      // This is the default, but there is no default value for the ModelAttributes.PATH (which is
      // required),
      // which means we always have to write this out. If it is the default binary storage, then
      // there
      // won't even be a 'binary-storage=BINARIES' model node.
      writer.writeStartElement(Element.FILE_BINARY_STORAGE.getLocalName());
      ModelAttributes.MINIMUM_BINARY_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MINIMUM_STRING_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.PATH.marshallAsAttribute(storage, false, writer);
      ModelAttributes.RELATIVE_TO.marshallAsAttribute(storage, false, writer);
      ModelAttributes.STORE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MIME_TYPE_DETECTION.marshallAsAttribute(storage, false, writer);
      writer.writeEndElement();
    } else if (ModelKeys.CACHE_BINARY_STORAGE.equals(storageType)) {
      writer.writeStartElement(Element.CACHE_BINARY_STORAGE.getLocalName());
      ModelAttributes.MINIMUM_BINARY_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MINIMUM_STRING_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.DATA_CACHE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.METADATA_CACHE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.CHUNK_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.CACHE_CONFIG.marshallAsAttribute(storage, false, writer);
      ModelAttributes.STORE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MIME_TYPE_DETECTION.marshallAsAttribute(storage, false, writer);
      writer.writeEndElement();
    } else if (ModelKeys.DB_BINARY_STORAGE.equals(storageType)) {
      writer.writeStartElement(Element.DB_BINARY_STORAGE.getLocalName());
      ModelAttributes.MINIMUM_BINARY_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MINIMUM_STRING_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.DATA_SOURCE_JNDI_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.STORE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MIME_TYPE_DETECTION.marshallAsAttribute(storage, false, writer);
      writer.writeEndElement();
    } else if (ModelKeys.COMPOSITE_BINARY_STORAGE.equals(storageType)) {
      writer.writeStartElement(Element.COMPOSITE_BINARY_STORAGE.getLocalName());
      ModelAttributes.MINIMUM_BINARY_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MINIMUM_STRING_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.STORE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MIME_TYPE_DETECTION.marshallAsAttribute(storage, false, writer);

      writeNestedStoresOfType(
          storage, ModelKeys.NESTED_STORAGE_TYPE_FILE, ModelKeys.FILE_BINARY_STORAGE, writer);
      writeNestedStoresOfType(
          storage, ModelKeys.NESTED_STORAGE_TYPE_CACHE, ModelKeys.CACHE_BINARY_STORAGE, writer);
      writeNestedStoresOfType(
          storage, ModelKeys.NESTED_STORAGE_TYPE_DB, ModelKeys.DB_BINARY_STORAGE, writer);
      writeNestedStoresOfType(
          storage, ModelKeys.NESTED_STORAGE_TYPE_CUSTOM, ModelKeys.CUSTOM_BINARY_STORAGE, writer);

      writer.writeEndElement();
    } else if (ModelKeys.CUSTOM_BINARY_STORAGE.equals(storageType)) {
      writer.writeStartElement(Element.CUSTOM_BINARY_STORAGE.getLocalName());
      ModelAttributes.MINIMUM_BINARY_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MINIMUM_STRING_SIZE.marshallAsAttribute(storage, false, writer);
      ModelAttributes.STORE_NAME.marshallAsAttribute(storage, false, writer);
      ModelAttributes.MIME_TYPE_DETECTION.marshallAsAttribute(storage, false, writer);
      for (String key : storage.keys()) {
        if (key.equals(ModelKeys.CLASSNAME)) {
          ModelAttributes.CLASSNAME.marshallAsAttribute(storage, false, writer);
        } else if (key.equals(ModelKeys.MODULE)) {
          ModelAttributes.MODULE.marshallAsAttribute(storage, false, writer);
        } else {
          writer.writeAttribute(key, storage.get(key).asString());
        }
      }
      writer.writeEndElement();
    }
  }