@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(templateIdParamName)) {
          final Long ugdTemplateId = command.longValueOfParameterNamed(templateIdParamName);
          final Template ugdTemplate = this.ugdTemplateRepository.findOne(ugdTemplateId);
          if (ugdTemplate == null) {
            changes.remove(templateIdParamName);
            throw new TemplateNotFoundException(ugdTemplateId);
          }
          hook.updateUgdTemplate(ugdTemplate);
        }

        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;
    }
  }