och.comp.ops.BillingOps.java Source code

Java tutorial

Introduction

Here is the source code for och.comp.ops.BillingOps.java

Source

/*
 * Copyright 2015 Evgeny Dolganov (evgenij.dolganov@gmail.com).
 *
 * 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 och.comp.ops;

import static och.api.model.RemoteChats.*;
import static och.api.model.tariff.Tariff.*;
import static och.comp.ops.RemoteOps.*;
import static och.comp.ops.ServersOps.*;
import static och.comp.web.JsonOps.*;
import static och.util.Util.*;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import och.api.exception.ExpectedException;
import och.api.model.billing.UserBalance;
import och.api.model.chat.account.ChatAccount;
import och.api.model.server.ServerRow;
import och.api.remote.chats.SetAccsBlockedReq;
import och.api.remote.chats.SetAccsPausedReq;
import och.comp.cache.Cache;
import och.comp.db.base.universal.UniversalQueries;
import och.comp.db.main.MainDb;
import och.comp.db.main.table.billing.GetAllBlockedUsers;
import och.comp.db.main.table.billing.SelectUserBalanceById;
import och.comp.db.main.table.billing.UpdateUserBalance;
import och.comp.db.main.table.chat.GetAllChatAccounts;
import och.service.props.Props;
import och.util.model.Pair;
import och.util.sql.ConcurrentUpdateSqlException;

import org.apache.commons.logging.Log;

public class BillingOps {

    static final Log log = getLog(BillingOps.class);

    public static SendAccsBlockedListener SEND_ACCS_BLOCKED_LISTENER;

    public static UserBalance findBalance(UniversalQueries universal, long userId) throws SQLException {
        UserBalance item = universal.selectOne(new SelectUserBalanceById(userId));
        if (item == null)
            throw new SQLException("User not found by id:" + userId);
        return item;
    }

    public static BigDecimal appendBalance(UniversalQueries universal, long userId, BigDecimal delta)
            throws ConcurrentUpdateSqlException, SQLException {

        int maxTries = 3;
        int curTry = 0;
        BigDecimal curVal;

        while (curTry < maxTries) {

            curVal = findBalance(universal, userId).balance;
            BigDecimal newVal = curVal.add(delta);
            Integer result = universal.updateOne(new UpdateUserBalance(userId, curVal, newVal));
            if (result > 0)
                return newVal;

            //already changed
            curTry++;
        }
        throw new ConcurrentUpdateSqlException("UpdateUserBalance: userId=" + userId);
    }

    public static BigDecimal appendBalanceAtomic(UniversalQueries universal, long userId, BigDecimal curVal,
            BigDecimal delta) throws ConcurrentUpdateSqlException, SQLException {

        BigDecimal newVal = curVal.add(delta);
        Integer result = universal.updateOne(new UpdateUserBalance(userId, curVal, newVal));
        if (result > 0)
            return newVal;

        throw new ConcurrentUpdateSqlException("UpdateUserBalance: userId=" + userId);
    }

    public static boolean isNeedDeblockAccsState(BigDecimal oldBalance, BigDecimal newBalance,
            BigDecimal minActiveBalance) {
        if (oldBalance.compareTo(minActiveBalance) >= 0)
            return false;
        return newBalance.compareTo(minActiveBalance) >= 0;
    }

    public static interface SendAccsBlockedListener {
        void onCall(long ownerId, boolean val);
    }

    /** ? ?      ?   */
    public static void sendAccsBlocked(Props props, MainDb db, Cache cache, long ownerId, boolean val) {

        if (SEND_ACCS_BLOCKED_LISTENER != null) {
            try {
                SEND_ACCS_BLOCKED_LISTENER.onCall(ownerId, val);
            } catch (Exception e) {
                log.error("SEND_ACCS_BLOCKED_LISTENER", e);
            }
        }

        try {

            List<ChatAccount> accs = db.chats.getOwnerAccsInfo(ownerId);
            if (isEmpty(accs))
                return;

            //send reqs
            sendBlockedReqs(props, accs, val);

            //update cache
            for (ChatAccount acc : accs) {
                String key = getBlockedAccFlag(acc.uid);
                if (val)
                    cache.tryPutCache(key, "true");
                else
                    cache.tryRemoveCache(key);
            }

        } catch (Throwable t) {
            ExpectedException.logError(log, t, "can't sendAccsBlocked: ownerId=" + ownerId + ", val=" + val);
        }

    }

    public static boolean isAccBlockedFromCache(Cache cache, String uid) {
        return tryParseBool(cache.tryGetVal(getBlockedAccFlag(uid)), false);
    }

    /** ? ?  ?       (? ? ) */
    public static Pair<Integer, Integer> reinitAccsBlocked(Props props, MainDb db, Cache cache) {
        try {

            UniversalQueries universal = db.universal;

            log.info("reinitAccsBlockedCache...");

            HashSet<ChatAccount> blockedAccs = new HashSet<>();
            HashSet<ChatAccount> unblockedAccs = new HashSet<>();

            List<ChatAccount> accs = universal.select(new GetAllChatAccounts());

            HashSet<String> blockedUids = new HashSet<>();
            List<UserBalance> blockedUsers = universal.select(new GetAllBlockedUsers());
            for (UserBalance user : blockedUsers) {
                List<String> blocked = db.chats.getOwnerAccs(user.userId);
                blockedUids.addAll(blocked);
            }

            for (ChatAccount acc : accs) {
                if (blockedUids.contains(acc.uid))
                    blockedAccs.add(acc);
                else
                    unblockedAccs.add(acc);
            }

            int unblockedCount = unblockedAccs.size();
            int blockedCount = blockedAccs.size();
            log.info("found blocked accs: " + blockedCount + ", unblocked accs: " + unblockedCount);

            Map<Long, ServerRow> servers = getServersMap(universal);

            //send reqs
            sendBlockedReqs(props, blockedAccs, servers, true);
            sendBlockedReqs(props, unblockedAccs, servers, false);

            //update cache
            for (ChatAccount acc : blockedAccs) {
                cache.tryPutCache(getBlockedAccFlag(acc.uid), "true");
            }
            for (ChatAccount acc : unblockedAccs) {
                cache.tryRemoveCache(getBlockedAccFlag(acc.uid));
            }

            log.info("done");

            return new Pair<>(unblockedCount, blockedCount);

        } catch (Exception e) {
            log.error("can't reinitAccsBlockedCache: " + e);
            return null;
        }
    }

    private static void sendBlockedReqs(Props props, Collection<ChatAccount> accsWithServers, boolean val) {
        HashSet<String> serverUrls = new HashSet<String>();
        HashSet<String> uids = new HashSet<String>();
        for (ChatAccount acc : accsWithServers) {
            uids.add(acc.uid);
            serverUrls.add(acc.server.createUrl(URL_CHAT_BLOKED));
        }

        if (isUseRemote(props)) {
            postEncryptedJsonToAny(props, serverUrls, new SetAccsBlockedReq(uids, val));
        }
    }

    private static void sendBlockedReqs(Props props, Collection<ChatAccount> accs, Map<Long, ServerRow> servers,
            boolean val) {
        HashSet<String> serverUrls = new HashSet<String>();
        HashSet<String> uids = new HashSet<String>();
        for (ChatAccount acc : accs) {
            ServerRow server = servers.get(acc.serverId);
            if (server == null)
                continue;
            uids.add(acc.uid);
            serverUrls.add(server.createUrl(URL_CHAT_BLOKED));
        }
        if (isUseRemote(props)) {
            postEncryptedJsonToAny(props, serverUrls, new SetAccsBlockedReq(uids, val));
        }
    }

    public static String getBlockedAccFlag(String uid) {
        return "acc-blocked-" + uid;
    }

    /** ? ?  ?     */
    public static Pair<Integer, Integer> reinitAccsPaused(Props props, MainDb db) {
        try {

            UniversalQueries universal = db.universal;

            log.info("reinitAccsPaused...");

            PausedStateResp state = getPausedState(universal);

            int pausedCount = state.pausedAccs.size();
            int unpausedCount = state.unpausedAccs.size();
            log.info("found paused accs: " + pausedCount + ", unpaused accs: " + unpausedCount);

            Map<Long, ServerRow> servers = getServersMap(universal);

            //send reqs
            sendPausedReqs(props, state.pausedAccs, servers, true);
            sendPausedReqs(props, state.unpausedAccs, servers, false);

            log.info("done");

            return new Pair<>(unpausedCount, pausedCount);

        } catch (Exception e) {
            log.error("can't reinitAccsBlockedCache: " + e);
            return null;
        }
    }

    private static void sendPausedReqs(Props props, Collection<ChatAccount> accs, Map<Long, ServerRow> servers,
            boolean val) {
        HashSet<String> serverUrls = new HashSet<String>();
        HashSet<String> uids = new HashSet<String>();
        for (ChatAccount acc : accs) {
            ServerRow server = servers.get(acc.serverId);
            if (server == null)
                continue;
            uids.add(acc.uid);
            serverUrls.add(server.createUrl(URL_CHAT_PAUSED));
        }
        if (isUseRemote(props)) {
            postEncryptedJsonToAny(props, serverUrls, new SetAccsPausedReq(uids, val));
        }
    }

    public static class PausedStateResp {

        public Set<ChatAccount> pausedAccs;
        public Set<ChatAccount> unpausedAccs;

        public PausedStateResp(Set<ChatAccount> pausedAccs, Set<ChatAccount> unpausedAccs) {
            this.pausedAccs = pausedAccs;
            this.unpausedAccs = unpausedAccs;
        }

    }

    public static PausedStateResp getPausedState(UniversalQueries universal) throws SQLException {

        HashSet<ChatAccount> pausedAccs = new HashSet<>();
        HashSet<ChatAccount> unpausedAccs = new HashSet<>();

        List<ChatAccount> accs = universal.select(new GetAllChatAccounts());

        for (ChatAccount acc : accs) {
            if (acc.tariffId == PAUSE_TARIFF_ID)
                pausedAccs.add(acc);
            else
                unpausedAccs.add(acc);
        }

        return new PausedStateResp(pausedAccs, unpausedAccs);

    }

}