public static void updateRegionHappenings( Connection conn, DatabaseAccess access, int nationId, int happeningId, String happening, HappeningType type) throws SQLException, ExecutionException { String region1Happening = type.transformToRegion1Happening(happening); String region2Happening = type.transformToRegion2Happening(happening); List<Integer> regionIds = new ArrayList<Integer>(2); Matcher regions = Utils.REGION_PATTERN.matcher(happening); while (regions.find()) { regionIds.add( access .getRegionIdCache() .get(happening.substring(regions.start() + 2, regions.end() - 2))); } if (regionIds.size() == 0 && nationId > -1) { PreparedStatement select = conn.prepareStatement("SELECT region FROM assembly.nation WHERE id = ?"); select.setInt(1, nationId); ResultSet result = select.executeQuery(); if (result.next()) { regionIds.add(result.getInt(1)); } DbUtils.closeQuietly(result); DbUtils.closeQuietly(select); } PreparedStatement insert = conn.prepareStatement( "INSERT INTO assembly.regional_happenings (global_id, region, happening) VALUES (?, ?, ?)"); if (region1Happening != null && regionIds.size() > 0) { insert.setInt(1, happeningId); insert.setInt(2, regionIds.get(0)); insert.setString(3, region1Happening); insert.executeUpdate(); } if (region2Happening != null && regionIds.size() > 1) { insert.setInt(1, happeningId); insert.setInt(2, regionIds.get(1)); insert.setString(3, region2Happening); insert.executeUpdate(); } DbUtils.closeQuietly(insert); }
public void runImpl() { if (monitor != null) monitor.happeningHeartbeat(); HappeningData data; synchronized (api) { // Throttle the happening queries based on how many new happenings occurred last run if (lastRun + Duration.standardSeconds(10).getMillis() > System.currentTimeMillis()) { final int activity = this.highActivity.get(); if (newEvents >= 50 || activity > 0) { Logger.info("Very high happenings activity, running at 2s intervals"); this.highActivity.set(newEvents >= 50 ? 10 : activity - 1); } else { Logger.debug( "Skipping happening run, little activity, last run was " + (System.currentTimeMillis() - lastRun) + " ms ago"); return; } } lastRun = System.currentTimeMillis() + Duration.standardSeconds(1).getMillis(); newEvents = 0; Logger.info("Executing global happenings run. Max Event ID: " + maxEventId); try { data = api.getHappeningInfo(null, -1, maxEventId); } catch (RateLimitReachedException e) { Logger.warn("Happenings monitoring rate limited!"); return; } final int oldEventId = maxEventId; for (EventHappening happening : data.happenings) { if (maxEventId < happening.eventId) { maxEventId = happening.eventId; } if (oldEventId < happening.eventId) { newEvents++; } } } Connection conn = null; PreparedStatement happeningInsert = null; try { conn = pool.getConnection(); PreparedStatement state = conn.prepareStatement("UPDATE assembly.settings SET last_event_id = ? WHERE id = 1"); state.setInt(1, maxEventId); state.executeUpdate(); DbUtils.closeQuietly(state); happeningInsert = conn.prepareStatement( "INSERT INTO assembly.global_happenings (nation, happening, timestamp, type) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); for (EventHappening happening : data.happenings) { final String text = happening.text; final long timestamp = happening.timestamp * 1000; Matcher match = Utils.NATION_PATTERN.matcher(text); int nationId = -1; String nation = ""; if (match.find()) { String title = text.substring(match.start() + 2, match.end() - 2); nation = Utils.sanitizeName(title); nationId = access.getNationIdCache().get(nation); if (nationId == -1) { PreparedStatement insert = conn.prepareStatement( "INSERT INTO assembly.nation (name, title, full_name, region, first_seen, wa_member) VALUES (?, ?, ?, ?, ?, 2)", Statement.RETURN_GENERATED_KEYS); insert.setString(1, nation); insert.setString(2, title); insert.setString(3, WordUtils.capitalizeFully(nation.replaceAll("_", " "))); insert.setInt(4, -1); insert.setLong(5, happening.timestamp); insert.executeUpdate(); ResultSet keys = insert.getGeneratedKeys(); keys.next(); nationId = keys.getInt(1); access.getNationIdCache().put(nation, nationId); DbUtils.closeQuietly(keys); DbUtils.closeQuietly(insert); } } final int happeningType = HappeningType.match(text); final HappeningType type = HappeningType.getType(happeningType); if (happeningType == HappeningType.getType("ENDORSEMENT").getId()) { if (match.find()) { String title = text.substring(match.start() + 2, match.end() - 2); String otherNation = Utils.sanitizeName(title); addEndorsement(conn, access.getNationIdCache().get(otherNation), nationId); // Add *was endorsed by* to db happeningInsert.setInt(1, access.getNationIdCache().get(otherNation)); happeningInsert.setString( 2, "@@" + otherNation + "@@ was endorsed by @@" + nation + "@@."); happeningInsert.setLong(3, timestamp); happeningInsert.setInt(4, happeningType); happeningInsert.executeUpdate(); } } else if (happeningType == HappeningType.getType("WITHDREW_ENDORSEMENT").getId()) { if (match.find()) { String title = text.substring(match.start() + 2, match.end() - 2); String otherNation = Utils.sanitizeName(title); removeEndorsement(conn, access.getNationIdCache().get(otherNation), nationId); } } else if (happeningType == HappeningType.getType("LOST_ENDORSEMENT").getId()) { if (match.find()) { String title = text.substring(match.start() + 2, match.end() - 2); String otherNation = Utils.sanitizeName(title); removeEndorsement(conn, nationId, access.getNationIdCache().get(otherNation)); } } else if (happeningType == HappeningType.getType("RESIGNED_FROM_WORLD_ASSEMBLY").getId()) { resignFromWorldAssembly(conn, nationId, false); } else if (happeningType == HappeningType.getType("ADMITTED_TO_WORLD_ASSEMBLY").getId()) { joinWorldAssembly(conn, nationId); } else if (happeningType == HappeningType.getType("EJECTED_FOR_RULE_VIOLATIONS").getId()) { resignFromWorldAssembly(conn, nationId, true); } else if (happeningType == HappeningType.getType("ABOLISHED_REGIONAL_FLAG").getId()) { abolishRegionFlag(conn, access, text); } else if (happeningType == HappeningType.getType("RELOCATED").getId()) { relocateNation(conn, nationId, nation, text); } else if (updateCache.getIfPresent(nationId) == null && happeningType == HappeningType.getType("NEW_LEGISLATION").getId()) { setRegionUpdateTime(conn, nationId, timestamp); updateCache.put(nationId, true); } else if (nationId > -1 && (happeningType == HappeningType.getType("REFOUNDED").getId() || happeningType == HappeningType.getType("FOUNDED").getId())) { if (happeningType == HappeningType.getType("REFOUNDED").getId()) { // Ensure nation is dead access.markNationDead(nationId, conn); // Only erase flag if it was user uploaded PreparedStatement flag = conn.prepareStatement("SELECT flag FROM assembly.nation WHERE id = ?"); flag.setInt(1, nationId); ResultSet set = flag.executeQuery(); boolean eraseFlag = set.next() && set.getString(1).contains("/uploads/"); DbUtils.closeQuietly(set); DbUtils.closeQuietly(flag); PreparedStatement alive = conn.prepareStatement( "UPDATE assembly.nation SET alive = 1, wa_member = 2" + (eraseFlag ? ", flag = ?" : "") + " WHERE id = ?"); if (eraseFlag) { alive.setString(1, "http://nationstates.net/images/flags/Default.png"); alive.setInt(2, nationId); } else { alive.setInt(1, nationId); } alive.executeUpdate(); DbUtils.closeQuietly(alive); } // Update region Matcher regions = Utils.REGION_PATTERN.matcher(text); if (regions.find()) { final int regionId = access .getRegionIdCache() .get(text.substring(regions.start() + 2, regions.end() - 2)); if (regionId > -1) { PreparedStatement update = conn.prepareStatement( "UPDATE assembly.nation SET region = ?, wa_member = 2, puppet = ? WHERE id = ?"); update.setInt(1, regionId); update.setInt(2, puppetCache.getIfPresent(nation) != null ? 1 : 0); update.setInt(3, nationId); update.executeUpdate(); DbUtils.closeQuietly(update); if (puppetCache.getIfPresent(nation) != null) { String defaultSettings = "{\"settings\":{\"show_gameplay_news\":false,\"show_roleplay_news\":false,\"show_regional_news\":false,\"show_irc\":false,\"show_world_census\":false,\"show_regional_population\":false,},\"last_update\":" + System.currentTimeMillis() + "}"; PreparedStatement insert = conn.prepareStatement( "INSERT INTO assembly.ns_settings (id, settings, last_settings_update) VALUES (?, ?, ?)"); insert.setInt(1, nationId); insert.setString(2, defaultSettings); insert.setLong(3, System.currentTimeMillis()); insert.executeUpdate(); DbUtils.closeQuietly(insert); puppetCache.invalidate(nation); } } } } else if (nationId > -1 && happeningType == HappeningType.getType("CEASED_TO_EXIST").getId()) { access.markNationDead(nationId, conn); } happeningInsert.setInt(1, nationId); happeningInsert.setString(2, parseHappening(text)); happeningInsert.setLong(3, timestamp); happeningInsert.setInt(4, happeningType); happeningInsert.executeUpdate(); ResultSet keys = happeningInsert.getGeneratedKeys(); keys.next(); int happeningId = keys.getInt(1); if (type != null) { updateRegionHappenings(conn, access, nationId, happeningId, text, type); } DbUtils.closeQuietly(keys); } } catch (SQLException e) { Logger.error("Unable to update happenings", e); } catch (ExecutionException e) { Logger.error("Unable to update happenings", e); } finally { DbUtils.closeQuietly(happeningInsert); DbUtils.closeQuietly(conn); } }