Package org.zanata.webtrans.server

Source Code of org.zanata.webtrans.server.SeamDispatch

package org.zanata.webtrans.server;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpSession;

import lombok.extern.slf4j.Slf4j;
import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.ActionResult;
import net.customware.gwt.dispatch.server.Dispatch;
import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.ActionException;
import net.customware.gwt.dispatch.shared.Result;
import net.customware.gwt.dispatch.shared.UnsupportedActionException;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.deployment.HotDeploymentStrategy;
import org.jboss.seam.deployment.StandardDeploymentStrategy;
import org.jboss.seam.security.AuthorizationException;
import org.jboss.seam.security.NotLoggedInException;
import org.jboss.seam.web.ServletContexts;
import org.zanata.util.ServiceLocator;
import org.zanata.webtrans.shared.auth.AuthenticationError;
import org.zanata.webtrans.shared.auth.AuthorizationError;
import org.zanata.webtrans.shared.auth.InvalidTokenError;
import org.zanata.webtrans.shared.rpc.WrappedAction;

import com.google.common.collect.Maps;

@Name("seamDispatch")
@Scope(ScopeType.APPLICATION)
@Startup
@Slf4j
public class SeamDispatch implements Dispatch {

    @SuppressWarnings("rawtypes")
    private final Map<Class<? extends Action>, Class<? extends ActionHandler<?, ?>>> handlers =
            Maps.newHashMap();

    @SuppressWarnings("rawtypes")
    public SeamDispatch() {
        // register all handlers with the @ActionHandlerFor annotation
        Set<Class<?>> annotatedClasses =
                StandardDeploymentStrategy.instance().getAnnotatedClasses()
                        .get(ActionHandlerFor.class.getName());
        if (annotatedClasses != null) {
            for (Class clazz : annotatedClasses) {
                register(clazz);
            }
        }

        // also register hot deployed handlers
        HotDeploymentStrategy hotDeploymentStrategy =
                HotDeploymentStrategy.instance();
        if (hotDeploymentStrategy != null && hotDeploymentStrategy.available()) {
            Set<Class<?>> hotAnnotatedClasses =
                    hotDeploymentStrategy.getAnnotatedClasses().get(
                            ActionHandlerFor.class.getName());
            if (hotAnnotatedClasses != null) {
                for (Class clazz : hotAnnotatedClasses) {
                    register(clazz);
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void register(Class<?> clazz) {
        log.debug("Registering ActionHandler {}", clazz.getName());
        ActionHandlerFor ahf = clazz.getAnnotation(ActionHandlerFor.class);
        handlers.put(ahf.value(), (Class<? extends ActionHandler<?, ?>>) clazz);
    }

    private static class DefaultExecutionContext implements ExecutionContext {
        private final SeamDispatch dispatch;

        private final List<ActionResult<?, ?>> actionResults;

        private DefaultExecutionContext(SeamDispatch dispatch) {
            this.dispatch = dispatch;
            this.actionResults = new java.util.ArrayList<ActionResult<?, ?>>();
        }

        public <A extends Action<R>, R extends Result> R execute(A action)
                throws ActionException {
            return execute(action, true);
        }

        public <A extends Action<R>, R extends Result> R execute(A action,
                boolean allowRollback) throws ActionException {
            R result = dispatch.doExecute(action, this);
            if (allowRollback)
                actionResults.add(new ActionResult<A, R>(action, result));
            return result;
        }

        private void rollback() throws ActionException {
            for (int i = actionResults.size() - 1; i >= 0; i--) {
                ActionResult<?, ?> actionResult = actionResults.get(i);
                rollback(actionResult);
            }
        }

        private <A extends Action<R>, R extends Result> void rollback(
                ActionResult<A, R> actionResult) throws ActionException {
            dispatch.doRollback(actionResult.getAction(),
                    actionResult.getResult(), this);
        }

    }

    @SuppressWarnings("unchecked")
    @Override
    public <A extends Action<R>, R extends Result> R execute(A action)
            throws ActionException {
        if (!(action instanceof WrappedAction<?>)) {
            throw new ActionException("Invalid (non-wrapped) action received: "
                    + action.getClass());
        }
        WrappedAction<?> a = (WrappedAction<?>) action;
        HttpSession session =
                ServletContexts.instance().getRequest().getSession();
        if (session != null && !session.getId().equals(a.getCsrfToken())) {
            log.warn("Token mismatch. Client token: {}, Expected token: {}",
                    a.getCsrfToken(), session.getId());
            throw new InvalidTokenError(
                    "The csrf token sent with this request is not valid. It may be from an expired session, or may have been forged");
        }
        DefaultExecutionContext ctx = new DefaultExecutionContext(this);
        try {
            return (R) doExecute(a.getAction(), ctx);
        } catch (ActionException e) {
            ctx.rollback();
            throw e;
        } catch (NotLoggedInException e) {
            ctx.rollback();
            throw new AuthenticationError(e);
        } catch (AuthorizationException e) {
            ctx.rollback();
            throw new AuthorizationError(e);
        } catch (Throwable e) {
            ctx.rollback();
            log.error("Error dispatching action: " + e, e);
            throw new ActionException(e);
        }
    }

    private <A extends Action<R>, R extends Result> R doExecute(A action,
            ExecutionContext ctx) throws ActionException {
        ActionHandler<A, R> handler = findHandler(action);
        return handler.execute(action, ctx);
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    private <A extends Action<R>, R extends Result> ActionHandler<A, R>
            findHandler(A action) throws UnsupportedActionException {

        Class<? extends ActionHandler> handlerClazz =
                handlers.get(action.getClass());
        final ActionHandler<A, R> handler =
                ServiceLocator.instance().getInstance(handlerClazz);

        if (handler == null)
            throw new UnsupportedActionException(action);

        return handler;
    }

    private <A extends Action<R>, R extends Result> void doRollback(A action,
            R result, ExecutionContext ctx) throws ActionException {
        ActionHandler<A, R> handler = findHandler(action);
        handler.rollback(action, result, ctx);
    }

    @SuppressWarnings("unchecked")
    public <A extends Action<R>, R extends Result> void rollback(A action,
            R result) throws ActionException {
        if (!(action instanceof WrappedAction<?>)) {
            throw new ActionException("Invalid (non-wrapped) action received: "
                    + action.getClass());
        }
        WrappedAction<?> a = (WrappedAction<?>) action;
        HttpSession session =
                ServletContexts.instance().getRequest().getSession();
        if (session != null && !session.getId().equals(a.getCsrfToken())) {
            throw new SecurityException(
                    "Blocked action without session id (CSRF attack?)");
        }
        DefaultExecutionContext ctx = new DefaultExecutionContext(this);
        try {
            doRollback((A) a.getAction(), result, ctx);
        } catch (ActionException e) {
            ctx.rollback();
            throw e;
        } catch (NotLoggedInException e) {
            ctx.rollback();
            throw new AuthenticationError(e);
        } catch (AuthorizationException e) {
            ctx.rollback();
            throw new AuthorizationError(e);
        } catch (Throwable e) {
            ctx.rollback();
            log.error("Error dispatching action: " + e, e);
            throw new ActionException(e);
        }
    }

}
TOP

Related Classes of org.zanata.webtrans.server.SeamDispatch

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.