org.motechproject.server.omod.advice.RunAsUserAdvice.java Source code

Java tutorial

Introduction

Here is the source code for org.motechproject.server.omod.advice.RunAsUserAdvice.java

Source

/**
 * MOTECH PLATFORM OPENSOURCE LICENSE AGREEMENT
 *
 * Copyright (c) 2010-11 The Trustees of Columbia University in the City of
 * New York and Grameen Foundation USA.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of Grameen Foundation USA, Columbia University, or
 * their respective contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY GRAMEEN FOUNDATION USA, COLUMBIA UNIVERSITY
 * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GRAMEEN FOUNDATION
 * USA, COLUMBIA UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.motechproject.server.omod.advice;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.motechproject.server.annotation.RunAsUser;
import org.motechproject.server.annotation.RunAsUserParam;
import org.motechproject.server.service.ContextService;
import org.motechproject.server.omod.UserResolver;
import org.openmrs.User;
import org.openmrs.api.AdministrationService;
import org.openmrs.scheduler.SchedulerConstants;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * An interceptor that enables marking methods with an annotation and having the
 * method execute as a specified user. The user is specified by the value of a
 * method parameter. The method parameter used is specified by marking the
 * parameter with a parameter annotation.
 * 
 * @author batkinson
 * 
 */
public class RunAsUserAdvice implements MethodInterceptor, ApplicationContextAware {

    private ApplicationContext springContext;
    private ContextService contextService;

    public Object invoke(MethodInvocation invocation) throws Throwable {

        Method method = invocation.getMethod();
        Object[] args = invocation.getArguments();

        if (hasAuthAnnotation(method)) {

            Object returnValue = null;

            User origUser = contextService.getAuthenticatedUser();

            User userToBecome = getUserToBecome(method, args);

            // Check if we're already user, if so, just proceed
            if (origUser != null && origUser.equals(userToBecome))
                return invocation.proceed();

            // Become super user if we're not already
            if (origUser == null || !origUser.isSuperUser()) {
                becomeSuperUser();
            }

            // Become the new user
            becomeUser(userToBecome);

            try {
                // Invoke the annotated method as the new user
                returnValue = invocation.proceed();
                return returnValue;
            } finally { // Make sure we return to original state
                // Become the super user so we can switch users
                becomeSuperUser();
                // Become the original user
                becomeUser(origUser);
            }

        } else {
            return invocation.proceed();
        }
    }

    private void becomeSuperUser() {

        if (contextService.getAuthenticatedUser() != null)
            contextService.logout();

        AdministrationService adminService = contextService.getAdministrationService();
        String username = adminService.getGlobalProperty(SchedulerConstants.SCHEDULER_USERNAME_PROPERTY);
        String password = adminService.getGlobalProperty(SchedulerConstants.SCHEDULER_PASSWORD_PROPERTY);
        contextService.authenticate(username, password);
    }

    private UserResolver getResolverBean(String resolverName) {
        return (UserResolver) springContext.getBean(resolverName);
    }

    private void becomeUser(User user) {
        if (user == null) {
            contextService.logout();
        } else {
            contextService.becomeUser(user.getSystemId());
        }
    }

    private boolean hasAuthAnnotation(Method method) {
        for (Annotation annotation : method.getAnnotations()) {
            if (annotation instanceof RunAsUser) {
                return true;
            }
        }
        return false;
    }

    private User getUserToBecome(Method method, Object[] args) {

        Annotation[][] paramAnnotationsArrays = method.getParameterAnnotations();

        for (int i = 0; i < paramAnnotationsArrays.length; i++) {
            Annotation[] paramAnnotations = paramAnnotationsArrays[i];
            for (Annotation paramAnnotation : paramAnnotations) {
                if (paramAnnotation instanceof RunAsUserParam) {
                    String userResolverName = ((RunAsUserParam) paramAnnotation).resolverBean();
                    UserResolver userResolver = getResolverBean(userResolverName);
                    return userResolver.lookupUser(args[i]);
                }
            }
        }

        throw new IllegalArgumentException(
                "method " + method + " has no " + RunAsUserParam.class.getName() + " annotation");
    }

    public void setContextService(ContextService contextService) {
        this.contextService = contextService;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        springContext = applicationContext;
    }

}