PageRenderTime 54ms CodeModel.GetById 41ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 0ms

/worldguard-legacy/src/main/java/com/sk89q/worldguard/protection/managers/storage/sql/RegionUpdater.java

https://gitlab.com/igserfurtmcschulserver/CustomWorldGuard
Java | 341 lines | 262 code | 52 blank | 27 comment | 35 complexity | 64471097645f2768d236cc1098493571 MD5 | raw file
  1/*
  2 * WorldGuard, a suite of tools for Minecraft
  3 * Copyright (C) sk89q <http://www.sk89q.com>
  4 * Copyright (C) WorldGuard team and contributors
  5 *
  6 * This program is free software: you can redistribute it and/or modify it
  7 * under the terms of the GNU Lesser General Public License as published by the
  8 * Free Software Foundation, either version 3 of the License, or
  9 * (at your option) any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful, but WITHOUT
 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 14 * for more details.
 15 *
 16 * You should have received a copy of the GNU Lesser General Public License
 17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 18 */
 19
 20package com.sk89q.worldguard.protection.managers.storage.sql;
 21
 22import com.google.common.collect.Lists;
 23import com.sk89q.worldguard.domains.DefaultDomain;
 24import com.sk89q.worldguard.protection.flags.Flag;
 25import com.sk89q.worldguard.protection.regions.ProtectedRegion;
 26import com.sk89q.worldguard.util.io.Closer;
 27import com.sk89q.worldguard.util.sql.DataSourceConfig;
 28import org.yaml.snakeyaml.Yaml;
 29
 30import java.sql.Connection;
 31import java.sql.PreparedStatement;
 32import java.sql.SQLException;
 33import java.util.ArrayList;
 34import java.util.HashSet;
 35import java.util.List;
 36import java.util.Map;
 37import java.util.Set;
 38import java.util.UUID;
 39import java.util.logging.Level;
 40import java.util.logging.Logger;
 41
 42/**
 43 * Updates region data that needs to be updated for both inserts and updates.
 44 */
 45class RegionUpdater {
 46
 47    private static final Logger log = Logger.getLogger(RegionUpdater.class.getCanonicalName());
 48    private final DataSourceConfig config;
 49    private final Connection conn;
 50    private final int worldId;
 51    private final DomainTableCache domainTableCache;
 52
 53    private final Set<String> userNames = new HashSet<String>();
 54    private final Set<UUID> userUuids = new HashSet<UUID>();
 55    private final Set<String> groupNames = new HashSet<String>();
 56
 57    private final Yaml yaml = SQLRegionDatabase.createYaml();
 58
 59    private final List<ProtectedRegion> typesToUpdate = new ArrayList<ProtectedRegion>();
 60    private final List<ProtectedRegion> parentsToSet = new ArrayList<ProtectedRegion>();
 61    private final List<ProtectedRegion> flagsToReplace = new ArrayList<ProtectedRegion>();
 62    private final List<ProtectedRegion> domainsToReplace = new ArrayList<ProtectedRegion>();
 63
 64    RegionUpdater(DataUpdater updater) {
 65        this.config = updater.config;
 66        this.conn = updater.conn;
 67        this.worldId = updater.worldId;
 68        this.domainTableCache = updater.domainTableCache;
 69    }
 70
 71    public void updateRegionType(ProtectedRegion region) {
 72        typesToUpdate.add(region);
 73    }
 74
 75    public void updateRegionProperties(ProtectedRegion region) {
 76        if (region.getParent() != null) {
 77            parentsToSet.add(region);
 78        }
 79
 80        flagsToReplace.add(region);
 81        domainsToReplace.add(region);
 82
 83        addDomain(region.getOwners());
 84        addDomain(region.getMembers());
 85    }
 86
 87    private void addDomain(DefaultDomain domain) {
 88        //noinspection deprecation
 89        for (String name : domain.getPlayers()) {
 90            userNames.add(name.toLowerCase());
 91        }
 92
 93        for (UUID uuid : domain.getUniqueIds()) {
 94            userUuids.add(uuid);
 95        }
 96
 97        for (String name : domain.getGroups()) {
 98            groupNames.add(name.toLowerCase());
 99        }
100    }
101
102    private void setParents() throws SQLException {
103        Closer closer = Closer.create();
104        try {
105            PreparedStatement stmt = closer.register(conn.prepareStatement(
106                    "UPDATE " + config.getTablePrefix() + "region " +
107                    "SET parent = ? " +
108                    "WHERE id = ? AND world_id = " + worldId));
109
110            for (List<ProtectedRegion> partition : Lists.partition(parentsToSet, StatementBatch.MAX_BATCH_SIZE)) {
111                for (ProtectedRegion region : partition) {
112                    ProtectedRegion parent = region.getParent();
113                    if (parent != null) { // Parent would be null due to a race condition
114                        stmt.setString(1, parent.getId());
115                        stmt.setString(2, region.getId());
116                        stmt.addBatch();
117                    }
118                }
119
120                stmt.executeBatch();
121            }
122        } finally {
123            closer.closeQuietly();
124        }
125    }
126
127    private void replaceFlags() throws SQLException {
128        Closer closer = Closer.create();
129        try {
130            PreparedStatement stmt = closer.register(conn.prepareStatement(
131                    "DELETE FROM " + config.getTablePrefix() + "region_flag " +
132                    "WHERE region_id = ? " +
133                    "AND world_id = " + worldId));
134
135            for (List<ProtectedRegion> partition : Lists.partition(flagsToReplace, StatementBatch.MAX_BATCH_SIZE)) {
136                for (ProtectedRegion region : partition) {
137                    stmt.setString(1, region.getId());
138                    stmt.addBatch();
139                }
140
141                stmt.executeBatch();
142            }
143        } finally {
144            closer.closeQuietly();
145        }
146
147        closer = Closer.create();
148        try {
149            PreparedStatement stmt = closer.register(conn.prepareStatement(
150                    "INSERT INTO " + config.getTablePrefix() + "region_flag " +
151                    "(id, region_id, world_id, flag, value) " +
152                    "VALUES " +
153                    "(null, ?, " + worldId + ", ?, ?)"));
154
155            StatementBatch batch = new StatementBatch(stmt, StatementBatch.MAX_BATCH_SIZE);
156
157            for (ProtectedRegion region : flagsToReplace) {
158                for (Map.Entry<Flag<?>, Object> entry : region.getFlags().entrySet()) {
159                    if (entry.getValue() == null) continue;
160
161                    Object flag = marshalFlagValue(entry.getKey(), entry.getValue());
162
163                    stmt.setString(1, region.getId());
164                    stmt.setString(2, entry.getKey().getName());
165                    stmt.setObject(3, flag);
166                    batch.addBatch();
167                }
168            }
169
170            batch.executeRemaining();
171        } finally {
172            closer.closeQuietly();
173        }
174    }
175
176    private void replaceDomainUsers() throws SQLException {
177        // Remove users
178        Closer closer = Closer.create();
179        try {
180            PreparedStatement stmt = closer.register(conn.prepareStatement(
181                    "DELETE FROM " + config.getTablePrefix() + "region_players " +
182                    "WHERE region_id = ? " +
183                    "AND world_id = " + worldId));
184
185            for (List<ProtectedRegion> partition : Lists.partition(domainsToReplace, StatementBatch.MAX_BATCH_SIZE)) {
186                for (ProtectedRegion region : partition) {
187                    stmt.setString(1, region.getId());
188                    stmt.addBatch();
189                }
190
191                stmt.executeBatch();
192            }
193        } finally {
194            closer.closeQuietly();
195        }
196
197        // Add users
198        closer = Closer.create();
199        try {
200            PreparedStatement stmt = closer.register(conn.prepareStatement(
201                    "INSERT INTO " + config.getTablePrefix() + "region_players " +
202                    "(region_id, world_id, user_id, owner) " +
203                    "VALUES (?, " + worldId + ",  ?, ?)"));
204
205            StatementBatch batch = new StatementBatch(stmt, StatementBatch.MAX_BATCH_SIZE);
206
207            for (ProtectedRegion region : domainsToReplace) {
208                insertDomainUsers(stmt, batch, region, region.getMembers(), false); // owner = false
209                insertDomainUsers(stmt, batch, region, region.getOwners(), true); // owner = true
210            }
211
212            batch.executeRemaining();
213        } finally {
214            closer.closeQuietly();
215        }
216    }
217
218    private void insertDomainUsers(PreparedStatement stmt, StatementBatch batch, ProtectedRegion region, DefaultDomain domain, boolean owner) throws SQLException {
219        //noinspection deprecation
220        for (String name : domain.getPlayers()) {
221            Integer id = domainTableCache.getUserNameCache().find(name);
222            if (id != null) {
223                stmt.setString(1, region.getId());
224                stmt.setInt(2, id);
225                stmt.setBoolean(3, owner);
226                batch.addBatch();
227            } else {
228                log.log(Level.WARNING, "Did not find an ID for the user identified as '" + name + "'");
229            }
230        }
231
232        for (UUID uuid : domain.getUniqueIds()) {
233            Integer id = domainTableCache.getUserUuidCache().find(uuid);
234            if (id != null) {
235                stmt.setString(1, region.getId());
236                stmt.setInt(2, id);
237                stmt.setBoolean(3, owner);
238                batch.addBatch();
239            } else {
240                log.log(Level.WARNING, "Did not find an ID for the user identified by '" + uuid + "'");
241            }
242        }
243    }
244
245    private void replaceDomainGroups() throws SQLException {
246        // Remove groups
247        Closer closer = Closer.create();
248        try {
249            PreparedStatement stmt = closer.register(conn.prepareStatement(
250                    "DELETE FROM " + config.getTablePrefix() + "region_groups " +
251                    "WHERE region_id = ? " +
252                    "AND world_id = " + worldId));
253
254            for (List<ProtectedRegion> partition : Lists.partition(domainsToReplace, StatementBatch.MAX_BATCH_SIZE)) {
255                for (ProtectedRegion region : partition) {
256                    stmt.setString(1, region.getId());
257                    stmt.addBatch();
258                }
259
260                stmt.executeBatch();
261            }
262        } finally {
263            closer.closeQuietly();
264        }
265
266        // Add groups
267        closer = Closer.create();
268        try {
269            PreparedStatement stmt = closer.register(conn.prepareStatement(
270                    "INSERT INTO " + config.getTablePrefix() + "region_groups " +
271                    "(region_id, world_id, group_id, owner) " +
272                    "VALUES (?, " + worldId + ",  ?, ?)"));
273
274            StatementBatch batch = new StatementBatch(stmt, StatementBatch.MAX_BATCH_SIZE);
275
276            for (ProtectedRegion region : domainsToReplace) {
277                insertDomainGroups(stmt, batch, region, region.getMembers(), false); // owner = false
278                insertDomainGroups(stmt, batch, region, region.getOwners(), true); // owner = true
279            }
280
281            batch.executeRemaining();
282        } finally {
283            closer.closeQuietly();
284        }
285    }
286
287    private void insertDomainGroups(PreparedStatement stmt, StatementBatch batch, ProtectedRegion region, DefaultDomain domain, boolean owner) throws SQLException {
288        for (String name : domain.getGroups()) {
289            Integer id = domainTableCache.getGroupNameCache().find(name);
290            if (id != null) {
291                stmt.setString(1, region.getId());
292                stmt.setInt(2, id);
293                stmt.setBoolean(3, owner);
294                batch.addBatch();
295            } else {
296                log.log(Level.WARNING, "Did not find an ID for the group identified as '" + name + "'");
297            }
298        }
299    }
300
301    private void updateRegionTypes() throws SQLException {
302        Closer closer = Closer.create();
303        try {
304            PreparedStatement stmt = closer.register(conn.prepareStatement(
305                    "UPDATE " + config.getTablePrefix() + "region " +
306                    "SET type = ?, priority = ?, parent = NULL " +
307                    "WHERE id = ? AND world_id = " + worldId));
308
309            for (List<ProtectedRegion> partition : Lists.partition(typesToUpdate, StatementBatch.MAX_BATCH_SIZE)) {
310                for (ProtectedRegion region : partition) {
311                    stmt.setString(1, SQLRegionDatabase.getRegionTypeName(region));
312                    stmt.setInt(2, region.getPriority());
313                    stmt.setString(3, region.getId());
314                    stmt.addBatch();
315                }
316
317                stmt.executeBatch();
318            }
319        } finally {
320            closer.closeQuietly();
321        }
322    }
323
324    public void apply() throws SQLException {
325        domainTableCache.getUserNameCache().fetch(userNames);
326        domainTableCache.getUserUuidCache().fetch(userUuids);
327        domainTableCache.getGroupNameCache().fetch(groupNames);
328
329        updateRegionTypes();
330        setParents();
331        replaceFlags();
332        replaceDomainUsers();
333        replaceDomainGroups();
334    }
335
336    @SuppressWarnings("unchecked")
337    private <V> Object marshalFlagValue(Flag<V> flag, Object val) {
338        return yaml.dump(flag.marshal((V) val));
339    }
340
341}