com.formkiq.core.api.FormRestController.java Source code

Java tutorial

Introduction

Here is the source code for com.formkiq.core.api.FormRestController.java

Source

/*
 * Copyright (C) 2017 FormKiQ Inc.
 *
 * 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 com.formkiq.core.api;

import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.formkiq.core.form.FormErrorException;
import com.formkiq.core.form.JSONService;
import com.formkiq.core.form.bean.FormInterceptor;
import com.formkiq.core.form.bean.FormJSONFieldFieldInterceptor;
import com.formkiq.core.form.bean.ObjectBuilder;
import com.formkiq.core.form.dto.ArchiveDTO;
import com.formkiq.core.form.dto.FormJSON;
import com.formkiq.core.form.dto.HTMLSnippet;
import com.formkiq.core.form.service.FormCalculatorService;
import com.formkiq.core.form.service.FormService;
import com.formkiq.core.form.service.FormValidatorService;
import com.formkiq.core.form.webflow.FormFlowEventProcessor;
import com.formkiq.core.service.FormNotFoundException;
import com.formkiq.core.service.sign.PrintRenderer;
import com.formkiq.core.service.workflow.WorkflowService;
import com.formkiq.core.util.DateService;
import com.formkiq.core.util.Strings;
import com.formkiq.core.webflow.FlowState;
import com.formkiq.core.webflow.FlowStateType;
import com.formkiq.core.webflow.WebFlow;

/**
 * Flow Rest Controller that handles interacting with current Flow.
 * TODO change to use {@link FormFlowEventProcessor}
 */
@RestController
public class FormRestController extends AbstractRestController implements InitializingBean {

    /** Root URI. */
    public static final String API_ROOT = "/api/form";

    /** {@link ApplicationContext}. */
    @Autowired
    private ApplicationContext context;

    /** {@link DateService}. */
    @Autowired
    private DateService dateService;

    /** {@link FormService}. */
    @Autowired
    private FormService formService;

    /** {@link FormCalculatorService}. */
    @Autowired
    private FormCalculatorService formCalculatorService;

    /** {@link JSONService}. */
    @Autowired
    private JSONService jsonService;

    /** {@link PrintRenderer}. */
    @Autowired
    private PrintRenderer printRenderer;

    /** {@link FormValidatorService}. */
    @Autowired
    private FormValidatorService validatorService;

    /** {@link WorkflowService}. */
    @Autowired
    private WorkflowService workflowService;

    /** {@link FormJSONFieldFieldInterceptor}. */
    private Collection<FormJSONFieldFieldInterceptor> fieldInterceptors;

    /** {@link FormInterceptor}. */
    private Collection<FormInterceptor> formInterceptors;

    @Override
    public void afterPropertiesSet() throws Exception {
        this.fieldInterceptors = this.context.getBeansOfType(FormJSONFieldFieldInterceptor.class).values();

        this.formInterceptors = this.context.getBeansOfType(FormInterceptor.class).values();
    }

    /**
     * Delete the Form Data object.
     * @param request {@link HttpServletRequest}
     * @param className {@link String}
     * @param uuid {@link String}
     *
     * @throws IOException IOException
     * @throws ClassNotFoundException ClassNotFoundException
     * @throws IllegalAccessException IllegalAccessException
     * @throws InstantiationException InstantiationException
     */
    @Transactional
    @Secured({ "ROLE_ADMIN" })
    @RequestMapping(value = API_ROOT + "/{class}/{uuid}", method = DELETE)
    public void delete(final HttpServletRequest request,
            final @PathVariable(name = "class", required = true) String className,
            final @PathVariable(name = "uuid", required = true) String uuid)
            throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {

        Class<?> clazz = Class.forName(className.replaceAll(".form$", ""));
        this.formService.delete(clazz, uuid);
    }

    /**
     * Process Form Events.
     * @param request {@link HttpServletRequest}
     * @param type {@link String}
     * @param event {@link String}
     * @param entity {@link HttpEntity}
     * @return {@link FormJSON}
     * @throws IOException IOException
     */
    @RequestMapping(value = API_ROOT + "/event/{type}/{event}", method = POST)
    public FormJSON events(final HttpServletRequest request,
            final @PathVariable(name = "type", required = true) String type,
            final @PathVariable(name = "event", required = true) String event, final HttpEntity<byte[]> entity)
            throws IOException {

        FormJSON form = this.jsonService.readValue(entity.getBody(), FormJSON.class);

        return this.workflowService.handleFormEvents(form, type);
    }

    /**
     * Find {@link FormJSONFieldFieldInterceptor} for {@link Class}.
     * @param clazz {@link Class}
     * @param form {@link FormJSON}
     * @return {@link List} of {@link FormJSONFieldFieldInterceptor}
     */
    private List<FormJSONFieldFieldInterceptor> findFieldInterceptors(final Class<?> clazz, final FormJSON form) {
        return this.fieldInterceptors.stream().filter(s -> s.isSupported(clazz, form)).collect(Collectors.toList());
    }

    /**
     * Find {@link FormInterceptor} for {@link Class}.
     *
     * @param form {@link FormJSON}
     * @return {@link List} of {@link FormJSONFieldFieldInterceptor}
     */
    private List<FormInterceptor> findFormInterceptors(final FormJSON form) {
        return this.formInterceptors.stream().filter(s -> s.isSupported(form)).collect(Collectors.toList());
    }

    /**
     * Get Form.
     * @param request {@link HttpServletRequest}
     * @param response {@link HttpServletResponse}
     * @param className {@link String}
     * @param uuid {@link String}
     * @return {@link HTMLSnippet}
     * @throws IOException {@link IOException}
     * @throws ClassNotFoundException {@link ClassNotFoundException}
     * @throws ReflectiveOperationException {@link ReflectiveOperationException}
     */
    @Secured({ "ROLE_ADMIN" })
    @RequestMapping(value = { API_ROOT + "/{class}", API_ROOT + "/{class}/{uuid}" }, method = GET)
    public HTMLSnippet get(final HttpServletRequest request, final HttpServletResponse response,
            final @PathVariable(name = "class", required = true) String className,
            final @PathVariable(name = "uuid", required = false) String uuid)
            throws ClassNotFoundException, IOException, ReflectiveOperationException {

        Class<?> clazz = Class.forName(className.replaceAll(".form$", ""));
        FormJSON form = this.jsonService.loadForm(clazz);

        Date now = this.dateService.now();
        form.setUUID(UUID.randomUUID().toString());
        form.setInserteddate(now);
        form.setUpdateddate(now);

        if (!isEmpty(uuid) && Strings.isUUID(uuid)) {
            Object obj = this.formService.get(clazz, uuid);
            if (obj == null) {
                throw new FormNotFoundException(clazz.getName() + ": " + uuid + " not found.");
            }
            ObjectBuilder.populateFromObject(form, obj);
        }

        List<FormInterceptor> intercepts = findFormInterceptors(form);
        for (FormInterceptor i : intercepts) {
            i.preGet(form);
        }

        WebFlow flow = new WebFlow(1, null,
                Arrays.asList(new FlowState(FlowStateType.START), new FlowState(FlowStateType.DEFAULT, form)));

        return renderForm(request, flow, form);
    }

    /**
     * Render {@link FormJSON}.
     * @param request {@link HttpServletRequest}
     * @param flow {@link WebFlow}
     * @param form {@link FormJSON}
     * @return {@link HTMLSnippet}
     */
    public HTMLSnippet renderForm(final HttpServletRequest request, final WebFlow flow, final FormJSON form) {

        Map<String, String> errors = flow.getCurrentState().getFielderrors();
        return this.printRenderer.generateFormHTML(request, form, errors);
    }

    /**
     * Saves the Form Data object.
     * @param request {@link HttpServletRequest}
     * @param className {@link String}
     * @return {@link Map} form errors
     * @throws Exception Exception
     */
    @Transactional
    @Secured({ "ROLE_ADMIN" })
    @RequestMapping(value = { API_ROOT + "/{class}" }, method = POST)
    public Object save(final HttpServletRequest request,
            @PathVariable(name = "class", required = true) final String className) throws Exception {

        Class<?> clazz = Class.forName(className);
        FormJSON form = this.jsonService.loadForm(clazz);

        ArchiveDTO archive = new ArchiveDTO();
        archive.addForm(form);

        this.formCalculatorService.applyFieldValues(archive, form, request);

        List<FormJSONFieldFieldInterceptor> intercepts = findFieldInterceptors(clazz, form);

        for (FormJSONFieldFieldInterceptor i : intercepts) {
            i.setValue(form);
        }

        Map<String, String> errors = this.validatorService.validateFormJSON(archive, form);

        List<FormInterceptor> cpt = findFormInterceptors(form);

        if (errors.isEmpty() && !cpt.isEmpty()) {
            for (FormInterceptor i : cpt) {
                errors.putAll(i.validateFormJSON(form));
            }
        }

        if (errors.isEmpty()) {

            Object obj = clazz.newInstance();
            obj = ObjectBuilder.buildObject(form, obj);

            for (FormInterceptor i : cpt) {
                i.preSave(form, obj);
            }

            this.formService.save(obj);

            for (FormInterceptor i : cpt) {
                i.postSave(form, obj);
            }
        }

        if (!errors.isEmpty()) {
            throw new FormErrorException(errors);
        }

        return form;
    }
}