ubic.gemma.core.util.AbstractSpringAwareCLI.java Source code

Java tutorial

Introduction

Here is the source code for ubic.gemma.core.util.AbstractSpringAwareCLI.java

Source

/*
 * The Gemma project
 *
 * Copyright (c) 2006 University of British Columbia
 *
 * 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 ubic.gemma.core.util;

import gemma.gsec.authentication.ManualAuthenticationService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import ubic.gemma.model.common.Auditable;
import ubic.gemma.model.common.auditAndSecurity.AuditEvent;
import ubic.gemma.model.common.auditAndSecurity.curation.Curatable;
import ubic.gemma.model.common.auditAndSecurity.eventType.AuditEventType;
import ubic.gemma.model.expression.arrayDesign.ArrayDesign;
import ubic.gemma.model.expression.experiment.ExpressionExperiment;
import ubic.gemma.persistence.persister.Persister;
import ubic.gemma.persistence.service.common.auditAndSecurity.AuditEventService;
import ubic.gemma.persistence.service.common.auditAndSecurity.AuditTrailService;
import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService;
import ubic.gemma.persistence.util.SpringContextUtil;

import java.util.Date;
import java.util.List;

/**
 * Subclass this to create command line interface (CLI) tools that need a Spring context. A standard set of CLI options
 * are provided to manage authentication.
 *
 * @author pavlidis
 */
public abstract class AbstractSpringAwareCLI extends AbstractCLI {

    protected AuditTrailService auditTrailService;
    protected AuditEventService auditEventService;
    protected BeanFactory ctx;

    @SuppressWarnings({ "unused", "WeakerAccess" }) // Possible external use
    public AbstractSpringAwareCLI() {
        super();
    }

    @Override
    public String getShortDesc() {
        return "No description provided";
    }

    @Override
    protected void buildStandardOptions() {
        super.buildStandardOptions();
        this.addUserNameAndPasswordOptions();
    }

    /**
     * You must override this method to process any options you added.
     */
    @Override
    protected void processOptions() {
        this.createSpringContext();
        this.authenticate();
        this.auditTrailService = this.getBean(AuditTrailService.class);
        this.auditEventService = this.getBean(AuditEventService.class);
    }

    @SuppressWarnings("unused") // Possible external use
    public void setCtx(BeanFactory ctx) {
        this.ctx = ctx;
    }

    /**
     * Override this method in your subclass to provide additional Spring configuration files that will be merged with
     * the Gemma spring context. See SpringContextUtil; an example path is
     * "classpath*:/myproject/applicationContext-mine.xml".
     *
     * @return string[]
     */
    protected String[] getAdditionalSpringConfigLocations() {
        return null;
    }

    /**
     * Convenience method to obtain instance of any bean by name.
     *
     * @param  <T>  the bean class type
     * @param  clz  class
     * @param  name name
     * @return      bean
     */
    @SuppressWarnings("SameParameterValue") // Better for general use
    protected <T> T getBean(String name, Class<T> clz) {
        assert ctx != null : "Spring context was not initialized";
        return ctx.getBean(name, clz);
    }

    protected <T> T getBean(Class<T> clz) {
        assert ctx != null : "Spring context was not initialized";
        return ctx.getBean(clz);
    }

    protected Persister getPersisterHelper() {
        assert ctx != null : "Spring context was not initialized";
        return (Persister) ctx.getBean("persisterHelper");
    }

    /**
     * @param  auditable  auditable
     * @param  eventClass can be null
     * @return            boolean
     */
    protected boolean noNeedToRun(Auditable auditable, Class<? extends AuditEventType> eventClass) {
        boolean needToRun = true;
        Date skipIfLastRunLaterThan = this.getLimitingDate();
        List<AuditEvent> events = this.auditEventService.getEvents(auditable);

        boolean okToRun = true; // assume okay unless indicated otherwise

        // figure out if we need to run it by date; or if there is no event of the given class; "Fail" type events don't
        // count.
        for (int j = events.size() - 1; j >= 0; j--) {
            AuditEvent event = events.get(j);
            if (event == null) {
                continue; // legacy of ordered-list which could end up with gaps; should not be needed any more
            }
            AuditEventType eventType = event.getEventType();
            if (eventType != null && eventClass != null && eventClass.isAssignableFrom(eventType.getClass())
                    && !eventType.getClass().getSimpleName().startsWith("Fail")) {
                if (skipIfLastRunLaterThan != null) {
                    if (event.getDate().after(skipIfLastRunLaterThan)) {
                        AbstractCLI.log
                                .info(auditable + ": " + " run more recently than " + skipIfLastRunLaterThan);
                        errorObjects.add(auditable + ": " + " run more recently than " + skipIfLastRunLaterThan);
                        needToRun = false;
                    }
                } else {
                    needToRun = false; // it has been run already at some point
                }
            }
        }

        /*
         * Always skip if the object is curatable and troubled
         */
        if (auditable instanceof Curatable) {
            Curatable curatable = (Curatable) auditable;
            okToRun = !curatable.getCurationDetails().getTroubled(); //not ok if troubled

            // special case for expression experiments - check associated ADs.
            if (okToRun && curatable instanceof ExpressionExperiment) {
                ExpressionExperimentService ees = this.getBean(ExpressionExperimentService.class);
                for (ArrayDesign ad : ees.getArrayDesignsUsed((ExpressionExperiment) auditable)) {
                    if (ad.getCurationDetails().getTroubled()) {
                        okToRun = false; // not ok if even one parent AD is troubled, no need to check the remaining ones.
                        break;
                    }
                }
            }

            if (!okToRun) {
                AbstractCLI.log.info(auditable + ": has an active 'trouble' flag");
                errorObjects.add(auditable + ": has an active 'trouble' flag");
            }
        }

        return !needToRun || !okToRun;
    }

    /**
     * check if using test or production contexts
     */
    protected void createSpringContext() {

        ctx = SpringContextUtil.getApplicationContext(this.hasOption("testing"), false /* webapp */,
                this.getAdditionalSpringConfigLocations());

        /*
         * Guarantee that the security settings are uniform throughout the application (all threads).
         */
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
    }

    /**
     * check username and password.
     */
    private void authenticate() {

        /*
         * Allow security settings (authorization etc) in a given context to be passed into spawned threads
         */
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);

        ManualAuthenticationService manAuthentication = ctx.getBean(ManualAuthenticationService.class);
        if (this.hasOption('u') && this.hasOption('p')) {
            username = this.getOptionValue('u');
            password = this.getOptionValue('p');

            if (StringUtils.isBlank(username)) {
                System.err.println("Not authenticated. Username was blank");
                AbstractCLI.log.debug("Username=" + username);
                exitwithError();
            }

            if (StringUtils.isBlank(password)) {
                System.err.println("Not authenticated. You didn't enter a password");
                exitwithError();
            }

            boolean success = manAuthentication.validateRequest(username, password);
            if (!success) {
                System.err.println("Not authenticated. Make sure you entered a valid username (got '" + username
                        + "') and/or password");
                exitwithError();
            } else {
                AbstractCLI.log.info("Logged in as " + username);
            }
        } else {
            AbstractCLI.log.info("Logging in as anonymous guest with limited privileges");
            manAuthentication.authenticateAnonymously();
        }

    }

}