Java tutorial
/* * 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); } }