Package br.com.objectos.way.ui.form

Source Code of br.com.objectos.way.ui.form.EntityFormImpl$ToError

/*
* Copyright 2012 Objectos, Fábrica de Software LTDA.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package br.com.objectos.way.ui.form;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;

import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.ConstraintViolation;

import br.com.objectos.way.relational.Crud;
import br.com.objectos.way.ui.BaseUrl;
import br.com.objectos.way.ui.Context;
import br.com.objectos.way.ui.form.FormResponse.Error;
import br.com.objectos.way.ui.json.EntityJson;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.inject.Provider;
import com.google.sitebricks.client.transport.Json;
import com.google.sitebricks.headless.Reply;
import com.google.sitebricks.headless.Request;

/**
* @author marcio.endo@objectos.com.br (Marcio Endo)
*/
class EntityFormImpl<T extends EntityJson> implements EntityForm<T> {

  private final Class<T> type;

  private final BaseUrl baseUrl;
  private final Crud crud;
  private final Provider<Request> requests;
  private final Validator javaxValidator;

  private MethodFilter<T> filter = new AlwaysMethodFilter<T>();
  private ActionListener<T> listener = new EmptyActionListener<T>();
  private ContextDecorator<T> decorator;
  private Redirect<T> redirect;
  private AbstractValidator<T> validator;

  private final Map<Method, Action<T>> actionMap;
  private final Map<Method, Redirect<T>> redirectMap = newHashMap();
  private final Map<Method, AbstractValidator<T>> validatorMap = newHashMap();

  public EntityFormImpl(Class<T> type,
                        BaseUrl baseUrl,
                        Crud crud,
                        Provider<Request> requests,
                        Validator validator) {
    this.type = type;
    this.baseUrl = baseUrl;
    this.crud = crud;
    this.requests = requests;
    this.javaxValidator = validator;

    actionMap = newHashMap();
    actionMap.put(Method.POST, new DefaultCreateAction());
    actionMap.put(Method.PUT, new DefaultUpdateAction());
    actionMap.put(Method.DELETE, new DefaultDeleteAction());
  }

  @Override
  public EntityForm<T> withMethodFilter(MethodFilter<T> filter) {
    this.filter = filter;
    return this;
  }

  @Override
  public EntityForm<T> withActionListener(ActionListener<T> listener) {
    this.listener = listener;
    return this;
  }

  @Override
  public EntityForm<T> withContextDecorator(ContextDecorator<T> decorator) {
    Preconditions.checkArgument(redirect == null,
        "You cannot use a decorator and a redirect at the same time");
    this.decorator = decorator;
    return this;
  }

  @Override
  public EntityForm<T> withRedirect(Redirect<T> redirect) {
    Preconditions.checkArgument(decorator == null,
        "You cannot use a decorator and a redirect at the same time");
    this.redirect = redirect;
    return this;
  }

  @Override
  public EntityForm<T> withValidator(AbstractValidator<T> validator) {
    this.validator = validator;
    return this;
  }

  @Override
  public OnMethod<T> on(final Class<? extends Annotation> methodAnnotation) {
    Preconditions.checkArgument(decorator == null,
        "You cannot use a decorator and a redirect at the same time");

    return new OnMethod<T>() {
      @Override
      public EntityForm<T> execute(Action<T> action) {
        Method method = Method.parse(methodAnnotation);
        actionMap.put(method, action);
        return EntityFormImpl.this;
      }

      @Override
      public EntityForm<T> redirect(Redirect<T> redirect) {
        Method method = Method.parse(methodAnnotation);
        redirectMap.put(method, redirect);
        return EntityFormImpl.this;
      }

      @Override
      public EntityForm<T> validate(AbstractValidator<T> validator) {
        Method method = Method.parse(methodAnnotation);
        validatorMap.put(method, validator);
        return EntityFormImpl.this;
      }
    };
  }

  @Override
  public Reply<?> reply() {
    Request request = requests.get();
    T pojo = request.read(type).as(Json.class);

    Method method = Method.parse(request);

    List<Error> errors = newArrayList();

    List<Error> javaxErrors = javaxValidation(pojo);
    errors.addAll(javaxErrors);

    if (validator != null) {
      List<Error> validatorErrors = formValidation(validator, pojo);
      errors.addAll(validatorErrors);
    }

    if (validatorMap.containsKey(method)) {
      AbstractValidator<T> methodValidator = validatorMap.get(method);
      List<Error> validatorErrors = formValidation(methodValidator, pojo);
      errors.addAll(validatorErrors);
    }

    if (errors.isEmpty()) {
      try {
        tryToExecute(method, pojo);
      } catch (Throwable e) {
        errors.add(Errors.toForm(e));
      }
    }

    Context context = null;
    String redirectUrl = null;

    if (errors.isEmpty()) {
      if (decorator != null) {
        context = Context.of();
        decorator.decorate(context, pojo);
      }

      if (redirect != null) {
        redirectUrl = redirect.getUrl(baseUrl, pojo);
      }

      if (redirectMap.containsKey(method)) {
        Redirect<T> methodRedirect = redirectMap.get(method);
        redirectUrl = methodRedirect.getUrl(baseUrl, pojo);
      }
    }

    FormResponse json = FormJson.of(context, errors, redirectUrl);
    return Reply.with(json).as(Json.class);
  }

  private List<Error> javaxValidation(T pojo) {
    Set<ConstraintViolation<T>> violations = javaxValidator.validate(pojo);
    Iterable<FormResponse.Error> iter = Iterables.transform(violations, new ToError());
    return ImmutableList.copyOf(iter);
  }

  private List<Error> formValidation(AbstractValidator<T> validator, T pojo) {
    validator.validate(pojo);
    return validator.getErrors();
  }

  private void tryToExecute(Method method, T pojo) {
    switch (method) {
    case POST:
      if (filter.shouldCreate(pojo)) {
        pojo = actionMap.get(method).execute(pojo);
        listener.onCreate(pojo);
      }
      break;

    case PUT:
      if (filter.shouldUpdate(pojo)) {
        pojo = actionMap.get(method).execute(pojo);
        listener.onUpdate(pojo);
      }
      break;

    case DELETE:
      if (filter.shouldDelete(pojo)) {
        pojo = actionMap.get(method).execute(pojo);
        listener.onDelete(pojo);
      }

      break;
    }
  }

  private static class AlwaysMethodFilter<T extends EntityJson> extends AbstractMethodFilter<T> {}

  private class DefaultCreateAction extends AbstractAction<T> {
    @Override
    public T execute(T pojo) {
      crud.create(pojo);
      return pojo;
    }
  }
  private class DefaultUpdateAction extends AbstractAction<T> {
    @Override
    public T execute(T pojo) {
      crud.update(pojo);
      return pojo;
    }
  }
  private class DefaultDeleteAction extends AbstractAction<T> {
    @Override
    public T execute(T pojo) {
      crud.delete(pojo);
      return pojo;
    }
  }
  private class ToError implements Function<ConstraintViolation<T>, FormResponse.Error> {
    @Override
    public FormResponse.Error apply(ConstraintViolation<T> input) {
      return Errors.toField(input);
    }
  }

  private enum Method {

    POST,
    PUT,
    DELETE;

    public static Method parse(Request request) {
      String method = request.method();
      return Method.valueOf(method.toUpperCase());
    }

    public static Method parse(Class<? extends Annotation> annotation) {
      String method = annotation.getSimpleName();
      return Method.valueOf(method.toUpperCase());
    }

  }

}
TOP

Related Classes of br.com.objectos.way.ui.form.EntityFormImpl$ToError

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.