controllers.base.SareTransactionalAction.java Source code

Java tutorial

Introduction

Here is the source code for controllers.base.SareTransactionalAction.java

Source

/*
 * Sentilab SARE: a Sentiment Analysis Research Environment
 * Copyright (C) 2013 Sabanci University Sentilab
 * http://sentilab.sabanciuniv.edu
 * 
 * This file is part of SARE.
 * 
 * SARE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *  
 * SARE 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
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SARE. If not, see <http://www.gnu.org/licenses/>.
 */

package controllers.base;

import java.security.AccessControlException;
import java.util.UUID;

import javax.persistence.*;

import models.web.ResourceFetchError;

import org.apache.commons.lang3.*;

import edu.sabanciuniv.sentilab.core.models.UserInaccessibleModel;
import edu.sabanciuniv.sentilab.sare.controllers.entitymanagers.SareEntityManagerFactory;
import edu.sabanciuniv.sentilab.sare.models.base.*;
import edu.sabanciuniv.sentilab.utils.UuidUtils;

import play.*;
import play.libs.Json;
import play.mvc.*;
import play.mvc.Http.Context;

public class SareTransactionalAction extends Action.Simple {

    public interface SareTxRunnable<T> {
        public T run(EntityManager em) throws Throwable;
    }

    private static ThreadLocal<EntityManager> currentEntityManager = new ThreadLocal<>();

    public static EntityManager createEntityManager() {
        return SareEntityManagerFactory
                .createEntityManager(Play.application().getWrappedApplication().mode().toString());
    }

    public static boolean hasEntityManager() {
        return currentEntityManager.get() != null;
    }

    public static void bindEntityManager(EntityManager em) {
        Validate.notNull(em);
        currentEntityManager.set(em);
    }

    public static void unbindEntityManager() {
        currentEntityManager.remove();
    }

    public static EntityManager em() {
        if (!hasEntityManager()) {
            throw new RuntimeException("No EntityManager bound to this thread. "
                    + "Try annotating your action method with @With(controllers.base.SareTransactionalAction)");
        }
        return currentEntityManager.get();
    }

    public static <T extends PersistentObject> T fetchResource(Context ctx, UUID id, Class<T> clazz,
            boolean bypassAccessibility) {
        Validate.notNull(clazz);

        Logger.info(LoggedAction.getLogEntry(ctx,
                String.format("attempting to fetch resource: %s of type: %s", id, clazz.getName())));

        T object = null;
        try {
            byte[] uuid = UuidUtils.toBytes(id);
            object = em().find(clazz, uuid);

            if (object != null && (!SessionedAction.isOwnerOf(object)
                    || (!bypassAccessibility && object instanceof UserInaccessibleModel))) {
                throw new AccessControlException(UuidUtils.normalize(id));
            }
        } catch (EntityNotFoundException e) {
            object = null;
        }

        if (object == null) {
            throw new EntityNotFoundException(UuidUtils.normalize(id));
        }

        Logger.info(LoggedAction.getLogEntry(ctx,
                String.format("found resource: %s of type: %s", id, clazz.getName())));
        return object;
    }

    public static <T extends PersistentObject> T fetchResource(Context ctx, UUID id, Class<T> clazz) {
        return fetchResource(ctx, id, clazz, false);
    }

    public static <T extends PersistentObject> T fetchResource(UUID id, Class<T> clazz) {
        return fetchResource(null, id, clazz);
    }

    public static <T extends PersistentObject> T fetchResourceQuietly(Context ctx, UUID id, Class<T> clazz,
            boolean bypassAccessibility) {
        try {
            return fetchResource(ctx, id, clazz, bypassAccessibility);
        } catch (Throwable e) {
            return null;
        }
    }

    public static <T extends PersistentObject> T fetchResourceQuietly(Context ctx, UUID id, Class<T> clazz) {
        return fetchResourceQuietly(ctx, id, clazz, false);
    }

    public static <T extends PersistentObject> T fetchResourceQuietly(UUID id, Class<T> clazz) {
        return fetchResourceQuietly(null, id, clazz);
    }

    public static Status notFoundEntity(Context ctx, String id, Throwable e) {
        Logger.warn(LoggedAction.getLogEntry(ctx, "non-existent resource"), e);
        return notFound(Json.toJson(ResourceFetchError.nonExistentResourceError(id)));
    }

    public static Status notFoundEntity(Context ctx, String id) {
        return notFoundEntity(ctx, id, null);
    }

    public static Status notFoundEntity(String id, Throwable e) {
        return notFoundEntity(null, id, e);
    }

    public static Status notFoundEntity(String id) {
        return notFoundEntity(id, null);
    }

    public static Status forbiddenEntity(Context ctx, String id, Throwable e) {
        Logger.warn(LoggedAction.getLogEntry(ctx, "forbidden resource"), e);
        return forbidden(Json.toJson(ResourceFetchError.forbiddenResourceError(id)));
    }

    public static Status forbiddenEntity(Context ctx, String id) {
        return forbiddenEntity(ctx, id, null);
    }

    public static Status forbiddenEntity(String id, Throwable e) {
        return forbiddenEntity(null, id, e);
    }

    public static Status forbiddenEntity(String id) {
        return forbiddenEntity(id, null);
    }

    public static <T> T execute(SareTxRunnable<T> action) throws Throwable {
        return execute(action, null);
    }

    public static <T> T execute(SareTxRunnable<T> action, Context ctx) throws Throwable {
        Validate.notNull(action);

        T result = null;
        EntityManager em = null;
        try {
            // create entity manager, add it to args, and begin transaction before the call.
            Logger.info(LoggedAction.getLogEntry(ctx, "creating entity manager"));
            em = createEntityManager();
            em.getTransaction().begin();

            // call the actual action.
            result = action.run(em);

            // commit active transaction after the call.
            if (em.isOpen() && em.getTransaction().isActive()) {
                em.getTransaction().commit();
            }
        } catch (Throwable e) {
            // rollback on error.
            if (em.isOpen() && em.getTransaction().isActive()) {
                Logger.info(LoggedAction.getLogEntry(ctx, "rolling back transaction"));
                em.getTransaction().rollback();
            }

            // rethrow.
            throw e;
        } finally {
            // close entity manager.
            if (em != null && em.isOpen()) {
                em.close();
            }
        }

        return result;
    }

    @Override
    public Result call(final Context ctx) throws Throwable {
        return execute(new SareTxRunnable<Result>() {
            @Override
            public Result run(EntityManager em) throws Throwable {
                bindEntityManager(em);
                return delegate.call(ctx);
            }
        }, ctx);
    }
}