tv.arte.resteventapi.core.services.impl.EventServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for tv.arte.resteventapi.core.services.impl.EventServiceImpl.java

Source

package tv.arte.resteventapi.core.services.impl;

/*
 * #%L
 * RestEventAPI
 * %%
 * Copyright (C) 2014 ARTE G.E.I.E
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of The MIT License (MIT) as published by the Open Source 
 * Initiative.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See The 
 * MIT License (MIT) for more details.
 * 
 * You should have received a copy of The MIT License (MIT) 
 * along with this program.  If not, see <http://opensource.org/licenses/MIT>
 * #L%
 */

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.joda.time.MutableDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import tv.arte.resteventapi.core.RestEventApiError;
import tv.arte.resteventapi.core.RestEventApiRuntimeException;
import tv.arte.resteventapi.core.clients.RestClientCallState;
import tv.arte.resteventapi.core.clients.RestClientExecutionResult;
import tv.arte.resteventapi.core.clients.RestEventApiRestClient;
import tv.arte.resteventapi.core.domain.entities.RestEvent;
import tv.arte.resteventapi.core.domain.entities.enums.RestEventStatus;
import tv.arte.resteventapi.core.domain.repositories.DomainAuthorizationRepository;
import tv.arte.resteventapi.core.domain.repositories.RestEventRepository;
import tv.arte.resteventapi.core.services.EventService;
import tv.arte.resteventapi.core.transferobjects.RestEventPostRequestParam;
import tv.arte.resteventapi.core.transferobjects.RestEventSearchRequestParam;
import tv.arte.resteventapi.core.validation.FieldValidationError;
import tv.arte.resteventapi.core.validation.RestEventApiValidationException;

/**
 * The default implementation of {@link EventService}
 * 
 * @author Simeon Petev
 * @since 0.1
 */
@Service
public class EventServiceImpl implements EventService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RestEventRepository restEventRepository;

    @Autowired
    private DomainAuthorizationRepository domainAuthorizationRepository;

    /**
     * {@inheritDoc}
     */
    public RestEvent retrieveRestEventById(String eventId) {
        return restEventRepository.findById(eventId);
    }

    /**
     * {@inheritDoc}
     */
    public List<RestEvent> retrieveRestEventForSearchParams(
            RestEventSearchRequestParam restEventSearchRequestParam) {
        return restEventRepository.findRestEventForSearchParams(restEventSearchRequestParam);
    }

    /**
     * {@inheritDoc}
     */
    public RestEvent createRestEvent(RestEventPostRequestParam restEventPostRequestParam)
            throws RestEventApiValidationException {

        /*
         * Database access validations - START
         */
        if (logger.isDebugEnabled())
            logger.debug("Start advanced validations requiring database access");
        if (restEventPostRequestParam.getId() != null
                || restEventRepository.exists(restEventPostRequestParam.getId())) {
            throw new RestEventApiValidationException(Arrays.asList(
                    new FieldValidationError(RestEventApiError.PRE_DEFINED.RIA_ERR_V_ID_NOT_AVAILABLE, "id")));
        }

        try {
            URI urlToCall = new URI(restEventPostRequestParam.getUrl());
            String domain = urlToCall.getHost();
            String wwwPrefix = "www.";
            if (domain.startsWith(wwwPrefix)) {
                domain = domain.substring(wwwPrefix.length());
            }

            if (!domainAuthorizationRepository.exists(domain)) {
                throw new RestEventApiValidationException(
                        Arrays.asList(RestEventApiError.PRE_DEFINED.RIA_ERR_V_DOMAIN_NOT_QUERYABLE));
            }
        } catch (URISyntaxException e) {
            throw new RestEventApiValidationException(Arrays.asList(new FieldValidationError(
                    RestEventApiError.PRE_DEFINED.RIA_ERR_V_URL_DOMAIN_UNEXTRACTABLE, "url")));
        }
        if (logger.isDebugEnabled())
            logger.debug("End advanced validations requiring database access. Validations passed.");
        /*
         * Database access validations - END
         */

        RestEvent newRestEvent = new RestEvent();

        if (StringUtils.isNotBlank(restEventPostRequestParam.getId())) {
            newRestEvent.setId(restEventPostRequestParam.getId());
        } else {
            String newId = UUID.randomUUID().toString();
            final int maxLoops = 10000;

            int currentLoop = 0;
            while (restEventRepository.exists(newId)) {
                newId = UUID.randomUUID().toString();
                currentLoop++;

                if (currentLoop >= maxLoops) {
                    throw new RestEventApiRuntimeException(
                            "Cannot generate id for a new rest event. The maximum number of loops has been reached.");
                }
            }

            newRestEvent.setId(newId);
        }

        newRestEvent.setBody(restEventPostRequestParam.getBody());
        newRestEvent.setHeaders(restEventPostRequestParam.getHeaders());
        newRestEvent.setInterval(restEventPostRequestParam.getInterval());
        newRestEvent.setMaxAttempts(restEventPostRequestParam.getMaxAttempts());
        newRestEvent.setMethod(restEventPostRequestParam.getMethod());
        newRestEvent.setTimeout(restEventPostRequestParam.getTimeout());
        newRestEvent.setTriggerDate(restEventPostRequestParam.getTriggerDate());
        newRestEvent.setUrl(restEventPostRequestParam.getUrl());

        newRestEvent.setCounter(0);
        newRestEvent.setStatus(RestEventStatus.BUFFER);
        newRestEvent.setNextExecution(restEventPostRequestParam.getTriggerDate());
        //TODO: Remove the automatic increment of the version once the @Version annotation is working properly
        newRestEvent.setVersion(1L);
        newRestEvent.setCreationDate(Calendar.getInstance().getTime());

        restEventRepository.save(newRestEvent);

        return newRestEvent;
    }

    /**
     * {@inheritDoc}
     */
    public void deleteRestEventForId(String eventId) throws RestEventApiValidationException {

        RestEvent eventToDelete = restEventRepository.findById(eventId);

        if (eventToDelete != null) {
            restEventRepository.delete(eventToDelete);
        } else {
            logger.error("Attempt to delete a non existing event with id: " + eventId);
            throw new RestEventApiValidationException(
                    Arrays.asList(RestEventApiError.PRE_DEFINED.RIA_ERR_V_UNEXISTING));
        }
    }

    /**
     * {@inheritDoc}
     */
    public List<RestEvent> eventsForScheduling(Date beforeDate) {
        return restEventRepository.findEventsForScheduling(beforeDate);
    }

    /**
     * {@inheritDoc}
     */
    public RestEvent processRestEvent(String id) {

        RestEvent restEvent = restEventRepository.findById(id);

        if (restEvent == null) {
            logger.warn("Unable to process event with id " + id + ". The event do not exists.");
            return restEvent;
        }

        if (RestEventStatus.SENT.equals(restEvent.getStatus())) {
            logger.info(
                    "No action will be performed for event with id " + id + ". The event has already been sent.");
            return restEvent;
        }

        if (restEvent.getMaxAttempts() <= restEvent.getCounter()) {
            logger.info("No action will be performed for event with id " + id
                    + ". The event has no more attempts left.");
            return restEvent;
        }

        if (logger.isDebugEnabled())
            logger.debug("Event scheduled for " + restEvent.getNextExecution().toString()
                    + ", is acctualy executed at " + Calendar.getInstance().getTime().toString());

        try {
            RestClientExecutionResult executionResult = RestEventApiRestClient.execute(restEvent);
            restEvent.setHttpResponseCode(executionResult.getResponseCode());

            if (RestClientCallState.OK.equals(executionResult.getState())
                    && ((executionResult.getResponseCode() >= 200 && executionResult.getResponseCode() < 300)
                            || executionResult.getResponseCode() == 304)) {
                restEvent.setStatus(RestEventStatus.SENT);
            } else {
                if (RestClientCallState.TIMEOUT.equals(executionResult.getState())) {
                    logger.info("The request for RestEvent with id " + id + " has been timed out.");
                }

                restEvent.setStatus(RestEventStatus.ERROR);
            }
        } catch (Exception e) {
            restEvent.setStatus(RestEventStatus.ERROR);
        }

        restEvent.setCounter(restEvent.getCounter() != null ? restEvent.getCounter() + 1 : 1);

        if (!RestEventStatus.SENT.equals(restEvent.getStatus())
                && restEvent.getCounter() < restEvent.getMaxAttempts()) {
            MutableDateTime nextExecution = new MutableDateTime();
            nextExecution.addSeconds(restEvent.getInterval());
            restEvent.setNextExecution(nextExecution.toDate());
        }

        restEvent.setVersion(restEvent.getVersion() != null ? restEvent.getVersion() + 1L : 1L);
        restEvent.setLastModified(Calendar.getInstance().getTime());

        restEventRepository.save(restEvent);

        return restEvent;
    }
}