Package org.mifosplatform.infrastructure.hooks.service

Source Code of org.mifosplatform.infrastructure.hooks.service.HookWritePlatformServiceJpaRepositoryImpl

/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.hooks.service;

import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.actionNameParamName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.configParamName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.contentTypeName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.entityNameParamName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.eventsParamName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.nameParamName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.payloadURLName;
import static org.mifosplatform.infrastructure.hooks.api.HookApiConstants.webTemplateName;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.hooks.domain.Hook;
import org.mifosplatform.infrastructure.hooks.domain.HookConfiguration;
import org.mifosplatform.infrastructure.hooks.domain.HookRepository;
import org.mifosplatform.infrastructure.hooks.domain.HookResource;
import org.mifosplatform.infrastructure.hooks.domain.HookTemplate;
import org.mifosplatform.infrastructure.hooks.domain.HookTemplateRepository;
import org.mifosplatform.infrastructure.hooks.domain.Schema;
import org.mifosplatform.infrastructure.hooks.exception.HookNotFoundException;
import org.mifosplatform.infrastructure.hooks.exception.HookTemplateNotFoundException;
import org.mifosplatform.infrastructure.hooks.processor.ProcessorHelper;
import org.mifosplatform.infrastructure.hooks.processor.WebHookService;
import org.mifosplatform.infrastructure.hooks.serialization.HookCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import retrofit.RetrofitError;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

@Service
public class HookWritePlatformServiceJpaRepositoryImpl implements
    HookWritePlatformService {

  private final PlatformSecurityContext context;
  private final HookRepository hookRepository;
  private final HookTemplateRepository hookTemplateRepository;
  private final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer;
  private final FromJsonHelper fromApiJsonHelper;

  @Autowired
  public HookWritePlatformServiceJpaRepositoryImpl(
      final PlatformSecurityContext context,
      final HookRepository hookRepository,
      final HookTemplateRepository hookTemplateRepository,
      final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer,
      final FromJsonHelper fromApiJsonHelper) {
    this.context = context;
    this.hookRepository = hookRepository;
    this.hookTemplateRepository = hookTemplateRepository;
    this.fromApiJsonDeserializer = fromApiJsonDeserializer;
    this.fromApiJsonHelper = fromApiJsonHelper;
  }

  @Transactional
  @Override
  @CacheEvict(value = "hooks", allEntries = true)
  public CommandProcessingResult createHook(final JsonCommand command) {

    try {
      this.context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForCreate(command.json());

      final HookTemplate template = retrieveHookTemplateBy(command
          .stringValueOfParameterNamed(nameParamName));
      final String configJson = command.jsonFragment(configParamName);
      final Set<HookConfiguration> config = assembleConfig(
          command.mapValueOfParameterNamed(configJson), template);
      final JsonArray events = command
          .arrayOfParameterNamed(eventsParamName);
      final Set<HookResource> allEvents = assembleSetOfEvents(events);
      final Hook hook = Hook.fromJson(command, template, config,
          allEvents);

      validateHookRules(template, config, allEvents);

      this.hookRepository.save(hook);

      return new CommandProcessingResultBuilder()
          .withCommandId(command.commandId())
          .withEntityId(hook.getId()).build();
    } catch (final DataIntegrityViolationException dve) {
      handleHookDataIntegrityIssues(command, dve);
      return CommandProcessingResult.empty();
    }
  }

  @Transactional
  @Override
  @CacheEvict(value = "hooks", allEntries = true)
  public CommandProcessingResult updateHook(final Long hookId,
      final JsonCommand command) {

    try {
      this.context.authenticatedUser();

      this.fromApiJsonDeserializer.validateForUpdate(command.json());

      final Hook hook = retrieveHookBy(hookId);
      final HookTemplate template = hook.getHookTemplate();
      final Map<String, Object> changes = hook.update(command);

      if (!changes.isEmpty()) {

        if (changes.containsKey(eventsParamName)) {
          final Set<HookResource> events = assembleSetOfEvents(command
              .arrayOfParameterNamed(eventsParamName));
          final boolean updated = hook.updateEvents(events);
          if (!updated) {
            changes.remove(eventsParamName);
          }
        }

        if (changes.containsKey(configParamName)) {
          final String configJson = command
              .jsonFragment(configParamName);
          final Set<HookConfiguration> config = assembleConfig(
              command.mapValueOfParameterNamed(configJson),
              template);
          final boolean updated = hook.updateConfig(config);
          if (!updated) {
            changes.remove(configParamName);
          }
        }

        this.hookRepository.saveAndFlush(hook);
      }

      return new CommandProcessingResultBuilder() //
          .withCommandId(command.commandId()) //
          .withEntityId(hookId) //
          .with(changes) //
          .build();
    } catch (final DataIntegrityViolationException dve) {
      handleHookDataIntegrityIssues(command, dve);
      return null;
    }
  }

  @Transactional
  @Override
  @CacheEvict(value = "hooks", allEntries = true)
  public CommandProcessingResult deleteHook(final Long hookId) {

    this.context.authenticatedUser();

    final Hook hook = retrieveHookBy(hookId);

    try {
      this.hookRepository.delete(hook);
      this.hookRepository.flush();
    } catch (final DataIntegrityViolationException e) {
      throw new PlatformDataIntegrityException(
          "error.msg.unknown.data.integrity.issue",
          "Unknown data integrity issue with resource: "
              + e.getMostSpecificCause());
    }
    return new CommandProcessingResultBuilder().withEntityId(hookId)
        .build();
  }

  private Hook retrieveHookBy(final Long hookId) {
    final Hook hook = this.hookRepository.findOne(hookId);
    if (hook == null) {
      throw new HookNotFoundException(hookId.toString());
    }
    return hook;
  }

  private HookTemplate retrieveHookTemplateBy(final String templateName) {
    final HookTemplate template = this.hookTemplateRepository
        .findOne(templateName);
    if (template == null) {
      throw new HookTemplateNotFoundException(templateName);
    }
    return template;
  }

  private Set<HookConfiguration> assembleConfig(
      final Map<String, String> hookConfig, final HookTemplate template) {

    final Set<HookConfiguration> configuration = new HashSet<>();
    final Set<Schema> fields = template.getSchema();

    for (final Entry<String, String> configEntry : hookConfig.entrySet()) {
      for (final Schema field : fields) {
        final String fieldName = field.getFieldName();
        if (fieldName.equalsIgnoreCase(configEntry.getKey())) {

          final HookConfiguration config = HookConfiguration
              .createNewWithoutHook(field.getFieldType(),
                  configEntry.getKey(),
                  configEntry.getValue());
          configuration.add(config);
          break;
        }
      }

    }

    return configuration;
  }

  private Set<HookResource> assembleSetOfEvents(final JsonArray eventsArray) {

    final Set<HookResource> allEvents = new HashSet<>();

    for (int i = 0; i < eventsArray.size(); i++) {

      final JsonObject eventElement = eventsArray.get(i)
          .getAsJsonObject();

      final String entityName = this.fromApiJsonHelper
          .extractStringNamed(entityNameParamName, eventElement);
      final String actionName = this.fromApiJsonHelper
          .extractStringNamed(actionNameParamName, eventElement);
      final HookResource event = HookResource.createNewWithoutHook(
          entityName, actionName);
      allEvents.add(event);
    }

    return allEvents;
  }

  private void validateHookRules(final HookTemplate template,
      final Set<HookConfiguration> config, Set<HookResource> events) {

    final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
    final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(
        dataValidationErrors).resource("hook");

    if (!template.getName().equalsIgnoreCase(webTemplateName)
        && this.hookRepository.findOneByTemplateId(template.getId()) != null) {
      final String errorMessage = "multiple.non.web.template.hooks.not.supported";
      baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
          errorMessage);
    }

    for (final HookConfiguration conf : config) {
      final String fieldValue = conf.getFieldValue();
      if (conf.getFieldName().equals(contentTypeName)) {
        if (!(fieldValue.equalsIgnoreCase("json") || fieldValue
            .equalsIgnoreCase("form"))) {
          final String errorMessage = "content.type.must.be.json.or.form";
          baseDataValidator.reset()
              .failWithCodeNoParameterAddedToErrorCode(
                  errorMessage);
        }
      }

      if (conf.getFieldName().equals(payloadURLName)) {
        try {
          final WebHookService service = ProcessorHelper
              .createWebHookService(fieldValue);
          service.sendEmptyRequest();
        } catch (RetrofitError re) {
          // Swallow error if it's because of method not supported or
          // if url throws 404 - required for integration test,
          // url generated on 1st POST request
          if (re.getResponse() == null) {
            String errorMessage = "url.invalid";
            baseDataValidator.reset()
            .failWithCodeNoParameterAddedToErrorCode(
                errorMessage);
          }
        }
      }
    }

    if (events == null || events.isEmpty()) {
      final String errorMessage = "registered.events.cannot.be.empty";
      baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
          errorMessage);
    }

    final Set<Schema> fields = template.getSchema();
    for (final Schema field : fields) {
      if (!field.isOptional()) {
        boolean found = false;
        for (final HookConfiguration conf : config) {
          if (field.getFieldName().equals(conf.getFieldName())) {
            found = true;
          }
        }
        if (!found) {
          final String errorMessage = "required.config.field."
              + "not.provided";
          baseDataValidator.reset().value(field.getFieldName())
              .failWithCodeNoParameterAddedToErrorCode(
                  errorMessage);
        }
      }
    }

    if (!dataValidationErrors.isEmpty()) {
      throw new PlatformApiDataValidationException(dataValidationErrors);
    }
  }

  private void handleHookDataIntegrityIssues(final JsonCommand command,
      final DataIntegrityViolationException dve) {
    final Throwable realCause = dve.getMostSpecificCause();
    if (realCause.getMessage().contains("hook_name")) {
      final String name = command.stringValueOfParameterNamed("name");
      throw new PlatformDataIntegrityException(
          "error.msg.hook.duplicate.name", "A hook with name '"
              + name + "' already exists", "name", name);
    }

    throw new PlatformDataIntegrityException(
        "error.msg.unknown.data.integrity.issue",
        "Unknown data integrity issue with resource: "
            + realCause.getMessage());
  }
}
TOP

Related Classes of org.mifosplatform.infrastructure.hooks.service.HookWritePlatformServiceJpaRepositoryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.