private void relocateNation(Connection conn, int nationId, String nation, String happening) throws SQLException { Matcher match = Utils.REGION_PATTERN.matcher(happening); String prevRegion = null; String newRegion = null; if (match.find()) { String title = happening.substring(match.start() + 2, match.end() - 2); prevRegion = Utils.sanitizeName(title); } if (match.find()) { String title = happening.substring(match.start() + 2, match.end() - 2); newRegion = Utils.sanitizeName(title); } Logger.info("Relocating " + nation + " from " + prevRegion + " to " + newRegion); if (prevRegion != null && newRegion != null) { // Double check they are still at their prev region before setting their new region! int newRegionId = getOrCreateRegion(conn, nation, newRegion); PreparedStatement update = conn.prepareStatement( "UPDATE assembly.nation SET region = ?, wa_member = 2 WHERE id = ? AND region = ?"); update.setInt(1, newRegionId); update.setInt(2, nationId); update.setInt(3, getOrCreateRegion(conn, nation, prevRegion)); update.executeUpdate(); DbUtils.closeQuietly(update); } }
private int getOrCreateRegion(Connection conn, String nation, String region) throws SQLException { PreparedStatement select = null; ResultSet result = null; try { select = conn.prepareStatement("SELECT id FROM assembly.region WHERE name = ?"); select.setString(1, region); result = select.executeQuery(); if (result.next()) { return result.getInt(1); } PreparedStatement insert = null; ResultSet keys = null; try { insert = conn.prepareStatement( "INSERT INTO assembly.region (name, flag, founder, title) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); insert.setString(1, region); insert.setString(2, ""); insert.setString(3, nation); insert.setString(4, Utils.formatName(region)); insert.executeUpdate(); keys = insert.getGeneratedKeys(); keys.next(); int id = keys.getInt(1); access.getRegionIdCache().put(region, id); return id; } finally { DbUtils.closeQuietly(keys); DbUtils.closeQuietly(insert); } } finally { DbUtils.closeQuietly(result); DbUtils.closeQuietly(select); } }
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); } }