org.openmrs.logic.token.impl.TokenServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.logic.token.impl.TokenServiceImpl.java

Source

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.logic.token.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Context;
import org.openmrs.api.impl.BaseOpenmrsService;
import org.openmrs.logic.LogicException;
import org.openmrs.logic.Rule;
import org.openmrs.logic.rule.ReferenceRule;
import org.openmrs.logic.rule.provider.RuleProvider;
import org.openmrs.logic.token.TokenRegistration;
import org.openmrs.logic.token.TokenService;
import org.openmrs.logic.token.db.TokenDAO;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Implementation of {@link TokenService}
 */
public class TokenServiceImpl extends BaseOpenmrsService implements TokenService {

    private final Log log = LogFactory.getLog(getClass());

    @Autowired
    private List<RuleProvider> ruleProviders;

    private TokenDAO dao;

    private Map<String, Rule> ruleCache = new HashMap<String, Rule>();

    /**
     * @param dao the TokenDAO to set
     */
    public void setDao(TokenDAO dao) {
        this.dao = dao;
    }

    /**
     * @see org.openmrs.api.impl.BaseOpenmrsService#onStartup()
     */
    public void onStartup() {
        initialize();
    }

    /**
     * @see org.openmrs.logic.token.TokenService#initialize()
     */
    public void initialize() {
        for (RuleProvider provider : ruleProviders) {
            startupProviderAsDaemon(provider);
        }
        ruleCache.clear();
    }

    /**
     * Calls provider.afterStartup() in a Daemon thread (or, if we are pre-OpenMRS 1.8 another way)
     * 
     * @param provider
     */
    private void startupProviderAsDaemon(final RuleProvider provider) {
        try {
            Method m = Class.forName("org.openmrs.api.context.Daemon").getMethod("runInNewDaemonThread");
            m.invoke(null, new Runnable() {

                public void run() {
                    log.debug("Starting " + provider.getClass());
                    provider.afterStartup();
                    log.debug("Finished starting " + provider.getClass());
                };
            });
        } catch (IllegalAccessException ex) {
            startupProviderWithoutDaemon(provider);
        } catch (IllegalArgumentException ex) {
            startupProviderWithoutDaemon(provider);
        } catch (ClassNotFoundException ex) {
            startupProviderWithoutDaemon(provider);
        } catch (NoSuchMethodException ex) {
            startupProviderWithoutDaemon(provider);
        } catch (InvocationTargetException ex) {
            log.error("Error starting " + provider.getClass(), ex.getCause());
        }
    }

    /**
     * Starts up a rule provider without using Daemon.runInNewDaemonThread (pre OpenMRS 1.8)
     * 
     * @param provider
     */
    private void startupProviderWithoutDaemon(RuleProvider provider) {
        try {
            provider.afterStartup();
        } catch (Exception ex) {
            log.error("Error starting " + provider.getClass(), ex);
        }
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokens(java.lang.String)
     */
    public List<String> getTokens(String query) {
        return dao.getTokens(query);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getCountOfTokenRegistrations(java.lang.String)
     */
    public int getCountOfTokenRegistrations(String query) {
        return dao.getCountOfTokenRegistrations(query);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getRule(java.lang.String)
     */
    public Rule getRule(String token) {
        if (token == null)
            throw new LogicException("Token cannot be null");

        if (token.startsWith("%%")) {
            return new ReferenceRule(token.substring(2));
        }

        Rule cached = ruleCache.get(token);
        if (cached != null) {
            return cached;
        }

        TokenRegistration tr = justOne(dao.getTokenRegistrations(token, null, null, null));
        if (tr == null) {
            throw new LogicException("Unregistered token: " + token);
        }

        return getRule(tr);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getRule(org.openmrs.logic.rule.provider.RuleProvider,
     *      java.lang.String)
     */
    public Rule getRule(RuleProvider provider, String providerToken) {
        TokenRegistration tr = justOne(dao.getTokenRegistrations(null, provider, providerToken, null));
        if (tr == null) {
            throw new LogicException(
                    "Cannot find token with provider=" + provider + " and providerToken=" + providerToken);
        }
        return getRule(tr);
    }

    /**
     * Instantiates a {@link Rule}, given a TokenRegistration. Results are cached.
     * 
     * @param tokenRegistration
     * @return
     */
    private Rule getRule(TokenRegistration tokenRegistration) {
        RuleProvider provider = getRuleProvider(tokenRegistration);
        if (provider == null) {
            throw new LogicException("Token registered but provider missing: " + tokenRegistration.getToken()
                    + " -> " + tokenRegistration.getProviderClassName());
        }

        String token = tokenRegistration.getToken();

        Rule cached = ruleCache.get(token);
        if (cached != null)
            return cached;

        Rule rule = provider.getRule(tokenRegistration.getConfiguration());
        if (rule != null) {
            ruleCache.put(token, rule);
        }

        return rule;
    }

    /**
     * @see org.openmrs.logic.token.TokenService#registerToken(java.lang.String,
     *      org.openmrs.logic.rule.provider.RuleProvider, java.lang.String)
     */
    public TokenRegistration registerToken(String token, RuleProvider provider, String configuration) {
        TokenRegistration existing = getTokenRegistrationByProviderAndToken(provider, token);
        if (existing == null) {
            // we haven't registered this before
            TokenRegistration registered = getTokenRegistrationByToken(token);
            if (registered == null) {
                // the requested token is available
                TokenRegistration tr = new TokenRegistration(token, provider, configuration);
                return Context.getService(TokenService.class).saveTokenRegistration(tr);
            } else {
                String newToken = findFreeToken(token);
                TokenRegistration tr = new TokenRegistration(newToken, provider, configuration, token);
                return Context.getService(TokenService.class).saveTokenRegistration(tr);
            }
        } else {
            // we've already registered this token, so we overwrite that registration
            if (existing.getConfiguration().equals(configuration)) {
                ruleCache.remove(existing.getToken());
                // don't do an unnecessary update if nothing has changed
                return existing;
            }
            existing.setConfiguration(configuration);
            return Context.getService(TokenService.class).saveTokenRegistration(existing);
        }
    }

    /**
     * Find a free token similar to the one requested. (Assumes that requested itself is
     * unavailable.)
     * 
     * @param requested
     * @return
     */
    private String findFreeToken(String requested) {
        int i = 1;
        while (true) {
            ++i;
            String candidate = requested + " " + i;
            TokenRegistration attempt = getTokenRegistrationByToken(candidate);
            if (attempt == null)
                return candidate;
        }
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistration(java.lang.Integer)
     */
    public TokenRegistration getTokenRegistration(Integer id) {
        return dao.getTokenRegistration(id);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrationByToken(java.lang.String)
     */
    public TokenRegistration getTokenRegistrationByToken(String token) {
        return justOne(dao.getTokenRegistrations(token, null, null, null));
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrationByUuid(java.lang.String)
     */
    public TokenRegistration getTokenRegistrationByUuid(String uuid) {
        return dao.getTokenRegistrationByUuid(uuid);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrationByProviderAndToken(org.openmrs.logic.rule.provider.RuleProvider,
     *      java.lang.String)
     */
    public TokenRegistration getTokenRegistrationByProviderAndToken(RuleProvider provider, String providerToken) {
        return justOne(dao.getTokenRegistrations(null, provider, providerToken, null));
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrationByProviderAndConfiguration(org.openmrs.logic.rule.provider.RuleProvider,
     *      String)
     */
    public TokenRegistration getTokenRegistrationByProviderAndConfiguration(RuleProvider provider,
            String configuration) {
        return justOne(dao.getTokenRegistrations(null, provider, null, configuration));
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrations(java.lang.String,
     *      java.lang.Integer, java.lang.Integer)
     */
    public List<TokenRegistration> getTokenRegistrations(String query, Integer start, Integer length) {
        return dao.getTokenRegistrations(query, start, length);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#removeToken(java.lang.String)
     */
    public void removeToken(String token) {
        TokenRegistration tr = getTokenRegistrationByToken(token);
        if (tr != null)
            Context.getService(TokenService.class).deleteTokenRegistration(tr);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#removeToken(org.openmrs.logic.rule.provider.RuleProvider,
     *      String)
     */
    public void removeToken(RuleProvider provider, String providerToken) {
        TokenRegistration tr = getTokenRegistrationByProviderAndToken(provider, providerToken);
        if (tr != null)
            Context.getService(TokenService.class).deleteTokenRegistration(tr);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#saveTokenRegistration(org.openmrs.logic.token.TokenRegistration)
     */
    public TokenRegistration saveTokenRegistration(TokenRegistration tokenRegistration) {
        TokenRegistration ret = dao.saveTokenRegistration(tokenRegistration);
        ruleCache.remove(tokenRegistration.getToken());
        return ret;
    }

    /**
     * @see org.openmrs.logic.token.TokenService#deleteTokenRegistration(org.openmrs.logic.token.TokenRegistration)
     */
    public void deleteTokenRegistration(TokenRegistration tokenRegistration) {
        dao.deleteTokenRegistration(tokenRegistration);
        ruleCache.remove(tokenRegistration.getToken());
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getAllTokens()
     */
    public List<String> getAllTokens() {
        return dao.getAllTokens();
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTags(java.lang.String)
     */
    public List<String> getTags(String partialTag) {
        return dao.getTags(partialTag);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokensByTag(java.lang.String)
     */
    public List<String> getTokensByTag(String tag) {
        return dao.getTokensByTag(tag);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getTokenRegistrationsByProvider(org.openmrs.logic.rule.provider.RuleProvider)
     */
    public List<TokenRegistration> getTokenRegistrationsByProvider(RuleProvider ruleProvider) {
        return dao.getTokenRegistrations(null, ruleProvider, null, null);
    }

    /**
     * Gets the provider registered for a given token registration. This will only return providers
     * that are active now, so if a module registered a token, then the module was removed, this
     * method will return null for that rule.
     * 
     * @param tokenRegistration
     * @return
     */
    private RuleProvider getRuleProvider(TokenRegistration tokenRegistration) {
        for (RuleProvider provider : ruleProviders) {
            if (provider.getClass().getName().equals(tokenRegistration.getProviderClassName())) {
                return provider;
            }
        }
        return null;
    }

    /**
     * @see org.openmrs.logic.token.TokenService#keepOnlyValidConfigurations(org.openmrs.logic.rule.provider.RuleProvider,
     *      java.util.Collection)
     */
    public void keepOnlyValidConfigurations(RuleProvider provider, Collection<?> validConfigurations) {
        List<String> validConfigsAsStrings = new ArrayList<String>();
        for (Object o : validConfigurations)
            validConfigsAsStrings.add(o.toString());
        if (CollectionUtils.isNotEmpty(validConfigsAsStrings))
            dao.deleteConfigurationsNotIn(provider, validConfigsAsStrings);
    }

    /**
     * @see org.openmrs.logic.token.TokenService#notifyRuleDefinitionChanged(org.openmrs.logic.rule.provider.RuleProvider,
     *      java.lang.String)
     */
    public void notifyRuleDefinitionChanged(RuleProvider provider, String providerToken) {
        TokenRegistration tr = getTokenRegistrationByProviderAndToken(provider, providerToken);
        if (tr == null)
            throw new LogicException("No token registered for provider=" + provider.getClass().getName()
                    + " providerToken=" + providerToken);
        ruleCache.remove(tr.getToken());
    }

    private <T> T justOne(Collection<T> collection) {
        if (collection == null || collection.size() == 0)
            return null;
        else if (collection.size() == 1)
            return collection.iterator().next();
        else
            throw new LogicException("Should not return more than one");
    }

    /**
     * @see org.openmrs.logic.token.TokenService#getRule(java.lang.String, java.lang.String)
     */
    @Override
    public Rule getRule(String ruleProviderClassName, String ruleConfiguration) {
        RuleProvider ruleProvider = getRuleProvider(ruleProviderClassName);
        if (ruleProvider == null)
            return null;
        return ruleProvider.getRule(ruleConfiguration);
    }

    /**
     * Gets the provider with a matching class name.
     * 
     * @param tokenRegistration
     * @return
     */
    private RuleProvider getRuleProvider(String ruleProviderClassName) {
        for (RuleProvider provider : ruleProviders) {
            if (provider.getClass().getName().equals(ruleProviderClassName)) {
                return provider;
            }
        }
        return null;
    }
}