io.seldon.api.resource.service.UserService.java Source code

Java tutorial

Introduction

Here is the source code for io.seldon.api.resource.service.UserService.java

Source

/*
 * Seldon -- open source prediction engine
 * =======================================
 *
 * Copyright 2011-2015 Seldon Technologies Ltd and Rummble Ltd (http://www.seldon.io/)
 *
 * ********************************************************************************************
 *
 * 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 io.seldon.api.resource.service;

import io.seldon.api.APIException;
import io.seldon.api.Constants;
import io.seldon.api.Util;
import io.seldon.api.caching.ClientIdCacheStore;
import io.seldon.api.resource.ConsumerBean;
import io.seldon.api.resource.DemographicBean;
import io.seldon.api.resource.ListBean;
import io.seldon.api.resource.UserBean;
import io.seldon.general.User;
import io.seldon.memcache.MemCacheKeys;
import io.seldon.memcache.MemCachePeer;

import java.util.Collection;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author claudio
 */

@Service
public class UserService {

    @Autowired
    private ClientIdCacheStore idCache;

    private static Logger logger = Logger.getLogger(UserService.class.getName());
    public static final int USERNAME_MAX_LENGTH = 25;

    public static UserBean getUser(ConsumerBean c, String uid, boolean full) throws APIException {
        UserBean bean = getUserSafe(c, uid, full);
        if (bean == null)
            throw new APIException(APIException.USER_NOT_FOUND);
        return bean;
    }

    public static UserBean getUserSafe(ConsumerBean c, String uid, boolean full) {
        String userBeanKey = MemCacheKeys.getUserBeanKey(c.getShort_name(), uid, full);
        UserBean bean = (UserBean) MemCachePeer.get(userBeanKey);
        if (bean == null) {
            User u = Util.getUserPeer(c).getUser(uid);
            if (u == null) {
                return null;
            }
            bean = new UserBean(u, full, c);
            if (Constants.CACHING)
                MemCachePeer.put(userBeanKey, bean, Constants.USERBEAN_CACHING_TIME);
        }
        return bean;
    }

    //Does not retrieve inactive users
    public static ListBean getUsers(ConsumerBean c, int limit, boolean full) throws APIException {
        ListBean bean = (ListBean) MemCachePeer.get(MemCacheKeys.getUsersBeanKey(c.getShort_name(), full));
        bean = Util.getLimitedBean(bean, limit);
        if (bean == null) {
            bean = new ListBean();
            Collection<User> res = Util.getUserPeer(c).getRecentUsers(limit);
            for (User u : res) {
                bean.addBean(new UserBean(u, full, c));
            }
            if (Constants.CACHING)
                MemCachePeer.put(MemCacheKeys.getUsersBeanKey(c.getShort_name(), full), bean,
                        Constants.CACHING_TIME);
        }
        return bean;
    }

    //Does not retrieve inactive users

    public static ListBean getUsersByName(ConsumerBean c, int limit, boolean full, String name)
            throws APIException {
        ListBean bean = (ListBean) MemCachePeer.get(MemCacheKeys.getUsersBeanKey(c.getShort_name(), full, name));
        bean = Util.getLimitedBean(bean, limit);
        if (bean == null) {
            bean = new ListBean();
            Collection<User> res = Util.getUserPeer(c).getUserByName(name, limit);
            for (User u : res) {
                bean.addBean(new UserBean(u, full, c));
            }
            if (Constants.CACHING)
                MemCachePeer.put(MemCacheKeys.getUsersBeanKey(c.getShort_name(), full, name), bean,
                        Constants.CACHING_TIME);
        }
        return bean;
    }

    public Long getInternalUserId(ConsumerBean c, String id) throws APIException {
        return getInternalUserId(c.getShort_name(), id);
    }

    public Long getInternalUserId(String consumerShortName, String id) throws APIException {
        Long res = null;
        res = getInternalUserIdInternal(consumerShortName, id);
        if (res == null) {
            logger.info("getInternalUserId(" + id + "): USER NOT FOUND");
            throw new APIException(APIException.USER_NOT_FOUND);

        }
        return res;
    }

    public Long getInternalUserIdInternal(String consumerShortName, String id) {
        Long res = null;
        res = idCache.getInternalUserId(consumerShortName, id);
        if (res == null) {
            String userInternalId = MemCacheKeys.getUserInternalId(consumerShortName, id);
            res = (Long) MemCachePeer.get(userInternalId);
            if (res == null) {
                User u = Util.getUserPeer(consumerShortName).getUser(id);
                if (u != null) {
                    res = u.getUserId();
                    idCache.putUserId(consumerShortName, id, res);
                    //MemCachePeer.put(userInternalId, res);
                    cacheInternalUserId(consumerShortName, id, res);
                }
            }
        }
        return res;
    }

    /**
     * Cache a user's internal ID, keyed by client ID
     * @param consumerBean -
     * @param clientId the client user ID (cache key)
     * @param internalId the internal user ID (cache value)
     */
    public static void cacheInternalUserId(String consumerBean, String clientId, Long internalId) {
        String clientIdKey = MemCacheKeys.getUserInternalId(consumerBean, clientId);
        MemCachePeer.put(clientIdKey, internalId, Constants.CACHING_TIME);
    }

    public String getClientUserId(String consumer, Long id) {
        if (id == null) {
            throw new APIException(APIException.USER_NOT_FOUND);
        }
        String res = null;
        res = idCache.getExternalUserId(consumer, id);
        if (res == null)
            res = (String) MemCachePeer.get(MemCacheKeys.getUserClientId(consumer, id));
        if (res == null) {
            User u = Util.getUserPeer(consumer).getUser(id);
            if (u != null) {
                res = u.getClientUserId();
                // users may be inferred, hence have no client id
                if (res != null) {
                    idCache.putUserId(consumer, res, id);
                    cacheClientUserId(consumer, id, res);
                }
            } else {
                logger.info("getClientUserId(" + id + "): USER NOT FOUND");
                throw new APIException(APIException.USER_NOT_FOUND);
            }
        }
        return res;
    }

    public String getClientUserId(ConsumerBean c, Long id) throws APIException {
        return getClientUserId(c.getShort_name(), id);
    }

    /**
     * Cache a user's client item ID keyed by internal user ID
     * @param consumerBean -
     * @param internalId the internal user ID (cache key)
     * @param clientId  the client user ID (cache value)
     */
    public static void cacheClientUserId(ConsumerBean consumerBean, Long internalId, String clientId) {
        cacheClientUserId(consumerBean.getShort_name(), internalId, clientId);
    }

    public static void cacheClientUserId(String consumer, Long internalId, String clientId) {
        final String internalIdKey = MemCacheKeys.getUserClientId(consumer, internalId);
        MemCachePeer.put(internalIdKey, clientId, Constants.CACHING_TIME);
    }

    /**
     * Bidirectionally cache the supplied user
     * (see {@link UserService#cacheClientUserId(io.seldon.api.resource.ConsumerBean, Long, String)}
     * and {@link UserService#cacheInternalUserId(String, String, Long)}).
     * @param consumerBean -
     * @param internalId user ID
     * @param clientId client ID
     */
    public static void cacheUser(ConsumerBean consumerBean, Long internalId, String clientId) {
        cacheClientUserId(consumerBean, internalId, clientId);
        cacheInternalUserId(consumerBean.getShort_name(), clientId, internalId);
    }

    public User addUser(ConsumerBean c, UserBean bean) {
        //check if the user is already in the system
        if (bean.getId() != null) {
            Long id = getInternalUserIdInternal(c.getShort_name(), bean.getId());
            if (id != null)
                throw new APIException(APIException.USER_DUPLICATED);
        }

        User u = bean.createUser(c);
        truncateUsername(u);
        Util.getUserPeer(c).persistUser(u);
        long userId = u.getUserId();

        //attributes
        if (bean.getAttributesName() != null && bean.getAttributesName().size() > 0) {
            Util.getUserPeer(c).addUserAttributeNames(userId, bean.getType(), bean.getAttributesName(), c);
        } else if (bean.getAttributes() != null && bean.getAttributes().size() > 0) {
            Util.getUserPeer(c).addUserAttribute(userId, bean.getType(), bean.getAttributes(), c);
        }
        cacheUser(c, bean, userId);
        return u;
    }

    private void cacheUser(ConsumerBean c, UserBean bean, long userId) {
        idCache.putUserId(c.getShort_name(), bean.getId(), userId);
        cacheInternalUserId(c.getShort_name(), bean.getId(), userId);
        MemCachePeer.put(
                MemCacheKeys.getUserBeanKey(c.getShort_name(), bean.getId(), bean.getAttributesName() != null),
                bean, Constants.USERBEAN_CACHING_TIME);
    }

    public User updateUser(ConsumerBean c, UserBean bean, boolean async) {
        UserBean user = null;
        Long userId;
        boolean fullUpdate = (bean.getAttributes() != null && bean.getAttributes().size() > 0)
                || (bean.getAttributesName() != null && bean.getAttributesName().size() > 0);

        userId = getInternalUserIdInternal(c.getShort_name(), bean.getId());
        if (userId == null) {
            try {
                return addUser(c, bean);
            } catch (APIException additionException) {
                if (additionException.getError_id() == APIException.USER_DUPLICATED) {
                    throw new APIException(APIException.CONCURRENT_USER_UPDATE);
                } else {
                    throw additionException;
                }
            }
        }
        user = locateUser(c, bean.getId(), userId, fullUpdate);

        if (user == null) {
            // something strange has happened
            logger.error("Found user id in cache but couldn't find the actual user object in caches or DB");
            throw new APIException(APIException.GENERIC_ERROR);
        }

        UserBean merged = mergeInUpdate(user, bean);
        if (merged == null) {
            return User.fromUserBean(user, userId);
        }
        //        truncateUsername(user);
        //        return Util.getUserPeer(c).persistUser(user);
        if (merged.getAttributesName() != null && merged.getAttributesName().size() > 0) {
            Util.getUserPeer(c).addUserAttributeNames(userId, merged.getType(), merged.getAttributesName(), c);
            merged.getAttributesName().putAll(merged.getAttributesName());
        } else if (merged.getAttributes() != null && merged.getAttributes().size() > 0) {
            Util.getUserPeer(c).addUserAttribute(userId, merged.getType(), merged.getAttributes(), c);
        }
        String userBeanKeyTrue = MemCacheKeys.getUserBeanKey(c.getShort_name(), bean.getId(), true);
        String userBeanKeyFalse = MemCacheKeys.getUserBeanKey(c.getShort_name(), bean.getId(), false);

        if (fullUpdate) {
            MemCachePeer.put(userBeanKeyTrue, merged, Constants.CACHING_TIME);
            MemCachePeer.delete(userBeanKeyFalse);
        } else {
            //delete memcache entries
            MemCachePeer.delete(userBeanKeyTrue);
            MemCachePeer.delete(userBeanKeyFalse);
        }
        return User.fromUserBean(merged, userId);
    }

    private static UserBean mergeInUpdate(UserBean previous, UserBean update) {
        boolean activeDifferent = previous.isActive() != update.isActive();
        boolean typeDifferent = previous.getType() != update.getType();
        boolean usernameDifferent = !previous.getUsername().equals(update.getUsername());

        Map<Integer, Integer> previousAttributes = previous.getAttributes();
        Map<Integer, Integer> updateAttributes = update.getAttributes();
        boolean attrsDifferent;
        if (previousAttributes == null) {
            attrsDifferent = updateAttributes != null;
        } else {
            attrsDifferent = !previousAttributes.equals(updateAttributes);
        }
        boolean attrsNameDifferent;

        Map<String, String> previousAttributesName = previous.getAttributesName();
        Map<String, String> updateAttributesName = update.getAttributesName();
        if (previousAttributesName == null) {
            attrsNameDifferent = updateAttributesName != null;
        } else {
            attrsNameDifferent = !previousAttributesName.equals(updateAttributesName);
        }
        if (activeDifferent || typeDifferent || usernameDifferent || attrsDifferent || attrsNameDifferent) {
            previous.setActive(update.isActive());
            previous.setType(update.getType());
            previous.setUsername(update.getUsername());
            previous.setAttributes(updateAttributes);
            previous.setAttributesName(updateAttributesName);
            return previous;
        } else
            return null;
    }

    private static UserBean locateUser(ConsumerBean c, String clientUserId, Long userId, boolean fullRequired) {
        UserBean user = null;
        String userBeanKey = MemCacheKeys.getUserBeanKey(c.getShort_name(), clientUserId, true);
        user = (UserBean) MemCachePeer.get(userBeanKey);
        if (user == null) {
            if (!fullRequired) {
                userBeanKey = MemCacheKeys.getUserBeanKey(c.getShort_name(), clientUserId, false);
                user = (UserBean) MemCachePeer.get(userBeanKey);
            }
            if (user == null) {
                User dbUser = Util.getUserPeer(c).getUser(userId);
                if (dbUser == null) {
                    return null;// can't find it anywhere so get out of here
                }
                user = new UserBean(dbUser, fullRequired, c);
            }

        }
        return user;
    }

    private static void truncateUsername(User user) {
        final String username = user.getUsername();
        final String truncated = StringUtils.left(username, USERNAME_MAX_LENGTH);
        user.setUsername(truncated);
    }

    public static DemographicBean getDemographic(ConsumerBean c, int demographic) {
        ;
        DemographicBean bean = (DemographicBean) MemCachePeer
                .get(MemCacheKeys.getDemographicBeanKey(c.getShort_name(), demographic));
        if (bean == null) {
            bean = new DemographicBean();
            bean.setDemoId(demographic);
            Integer[] attr = Util.getUserPeer(c).getAttributes(demographic);
            String[] attrName = Util.getUserPeer(c).getAttributesNames(demographic);
            bean.setAttr(attr[0]);
            bean.setVal(attr[1]);
            // TODO address this properly:
            if (attrName == null) {
                bean.setAttrName("<all>");
                bean.setValName("<all>");
            } else {
                bean.setAttrName(attrName[0]);
                bean.setValName(attrName[1]);
            }
            MemCachePeer.put(MemCacheKeys.getDemographicBeanKey(c.getShort_name(), demographic), bean,
                    Constants.CACHING_TIME);
        }
        return bean;
    }

    public static DemographicBean getDemographic(ConsumerBean c, String attrName, String valName)
            throws APIException {
        DemographicBean bean = (DemographicBean) MemCachePeer
                .get(MemCacheKeys.getDemographicBeanKey(c.getShort_name(), attrName, valName));
        if (bean == null) {
            int demoId = Util.getUserPeer(c).getDemographic(attrName, valName);
            if (demoId != Constants.DEFAULT_DEMOGRAPHIC) {
                bean = new DemographicBean();
                bean.setAttrName(attrName);
                bean.setValName(valName);
                Integer[] attr = Util.getUserPeer(c).getAttributes(demoId);
                bean.setDemoId(demoId);
                bean.setAttr(attr[0]);
                bean.setVal(attr[1]);
                MemCachePeer.put(MemCacheKeys.getDemographicBeanKey(c.getShort_name(), attrName, valName), bean,
                        Constants.CACHING_TIME);
            } else
                return null;
        }
        return bean;
    }

}