From 5ac975c52e7721c0cbec8a71adf53c74e33d5693 Mon Sep 17 00:00:00 2001 From: ArcadeMode Date: Thu, 22 Mar 2018 14:13:13 +0100 Subject: [PATCH] Blocker and Critical level bugfixes throughout the project (#4648) * fixed https://sonarcloud.io/project/issues?id=org.xmage%3Amage-root&issues=AWIlv32RgrzAwlaaQ7rP&open=AWIlv32RgrzAwlaaQ7rP * ensure closing of scanner if it was opened * Refactored method in EmpyrialArchAngel to not always return same value. * Refactored method in FalkenrathAristocrat to not always return same value. * Refactored method in GilderBairn to not always return the same value. * fixed left open resources, ensured quiet closing of the streams * Refactored method in IceCave to not always return same value. * Refactored method in KjeldoranRoyalGuard to not always return same value. * Refactored method in LegionsInitiative to not always return same value. * Refactored method in NaturesWill to not always return same value. * added quiet closing method in new streamutils class, used to clean up the connectdialog * Fix small typo * added quiet closing to saveobjectutil * closed resources in savegame method of gamecontroller * properly close resources in loadGame method of GameReplay class * further proper resource closing in ServerMessagesUtil * fixed unclosed resources in copy method in mage framework Copier * closed unclosed resources in copyCompressed method in Copier * ensure closing of filewriter in manasymbols * ensure proper closing of Stream in arcane UI * ensure closing of datagram socket in arcane Util * ensure resource closing in deckimport from clipboard * ensure closing of plugin classloader * ensured closing of zipinputstream resource * ensure closing of fileoutputstream in ScryfallSymbolsSource * ensure closing resources after finishing/canceling download of pictures * remove commented code * move locks to try block to ensure unlocking along all execution paths * remove dangerous instance of double-checked locking * removed dangerous instance of double checked locking in settingsmanager * Removed dangerous instance of double-checked locking in ThemePluginImpl * close resource which did not happen certainly * close another stream * ensure closing of inputstream --- .../java/mage/client/cards/ManaPieChart.java | 4 + .../DeckImportFromClipboardDialog.java | 9 +- .../mage/client/dialog/ConnectDialog.java | 18 +-- .../mage/client/util/gui/ArrowBuilder.java | 14 +- .../client/util/object/SaveObjectUtil.java | 9 +- .../org/mage/card/arcane/ManaSymbols.java | 13 +- .../main/java/org/mage/card/arcane/UI.java | 6 +- .../main/java/org/mage/card/arcane/Util.java | 10 +- .../dl/sources/ScryfallSymbolsSource.java | 8 +- .../plugins/card/images/DownloadPictures.java | 150 ++---------------- .../card/properties/SettingsManager.java | 8 +- .../mage/plugins/theme/ThemePluginImpl.java | 68 ++++---- .../src/main/java/mage/utils/StreamUtils.java | 30 ++++ .../src/mage/player/ai/ComputerPlayer6.java | 7 +- .../main/java/mage/server/ChatSession.java | 2 +- .../mage/server/ExtensionPackageLoader.java | 11 +- .../main/java/mage/server/UserManager.java | 2 +- .../java/mage/server/game/GameController.java | 19 ++- .../java/mage/server/game/GameReplay.java | 27 +++- .../mage/server/util/ServerMessagesUtil.java | 22 ++- .../src/mage/cards/e/EmpyrialArchangel.java | 1 - .../mage/cards/f/FalkenrathAristocrat.java | 2 +- Mage.Sets/src/mage/cards/g/GilderBairn.java | 11 +- Mage.Sets/src/mage/cards/i/IceCave.java | 2 +- .../src/mage/cards/k/KjeldoranRoyalGuard.java | 1 - .../src/mage/cards/l/LegionsInitiative.java | 1 - Mage.Sets/src/mage/cards/n/NaturesWill.java | 19 +-- .../magefree/update/helpers/FileHelper.java | 21 ++- .../src/main/java/mage/verify/MtgJson.java | 14 +- Mage/src/main/java/mage/util/Copier.java | 25 ++- Mage/src/main/java/mage/util/StreamUtils.java | 30 ++++ 31 files changed, 288 insertions(+), 276 deletions(-) create mode 100644 Mage.Common/src/main/java/mage/utils/StreamUtils.java create mode 100644 Mage/src/main/java/mage/util/StreamUtils.java diff --git a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java index a8d447e700..cf33d0e1e7 100644 --- a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java +++ b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java @@ -67,6 +67,10 @@ public class ManaPieChart extends JComponent { for (int i = 0; i < slices.length; i++) { total += slices[i].value; } + + if (total == 0.0D) { + return; //there are no slices or no slices with a value > 0, stop here + } double curValue = 0.0D; int startAngle = 0; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java index 1eeb251ad4..eef1987dfa 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java @@ -1,5 +1,7 @@ package mage.client.deckeditor; +import mage.util.StreamUtils; + import java.awt.*; import java.awt.event.*; import java.io.BufferedWriter; @@ -39,15 +41,16 @@ public class DeckImportFromClipboardDialog extends JDialog { } private void onOK() { + BufferedWriter bw = null; try { File temp = File.createTempFile("cbimportdeck", ".txt"); - BufferedWriter bw = new BufferedWriter(new FileWriter(temp)); + bw = new BufferedWriter(new FileWriter(temp)); bw.write(txtDeckList.getText()); - bw.close(); - tmpPath = temp.getPath(); } catch (IOException e) { e.printStackTrace(); + } finally { + StreamUtils.closeQuietly(bw); } dispose(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index e1dee12925..25164a55aa 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -43,6 +43,7 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.InputStreamReader; import java.io.Writer; +import java.io.Closeable; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.SocketException; @@ -73,6 +74,7 @@ import mage.client.util.Config; import mage.client.util.gui.countryBox.CountryItemEditor; import mage.client.util.sets.ConstructedFormats; import mage.remote.Connection; +import mage.utils.StreamUtils; import org.apache.log4j.Logger; /** @@ -565,6 +567,7 @@ public class ConnectDialog extends MageDialog { private void findPublicServerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed BufferedReader in = null; + Writer output = null; try { String serverUrl = PreferencesDialog.getCachedValue(KEY_CONNECTION_URL_SERVER_LIST, "http://xmage.de/files/server-list.txt"); if (serverUrl.contains("xmage.info/files/")) { @@ -618,7 +621,7 @@ public class ConnectDialog extends MageDialog { } List servers = new ArrayList<>(); if (in != null) { - Writer output = null; + if (!URLNotFound) { // write serverlist to be able to read if URL is not available File file = new File("serverlist.txt"); @@ -637,10 +640,6 @@ public class ConnectDialog extends MageDialog { } } - if (output != null) { - output.close(); - } - in.close(); } if (servers.isEmpty()) { JOptionPane.showMessageDialog(null, "Couldn't find any server."); @@ -668,15 +667,12 @@ public class ConnectDialog extends MageDialog { } catch (Exception ex) { logger.error(ex, ex); } finally { - if (in != null) { - try { - in.close(); - } catch (Exception e) { - } - } + StreamUtils.closeQuietly(in); + StreamUtils.closeQuietly(output); } }//GEN-LAST:event_jButton1ActionPerformed + private void jProxySettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jProxySettingsButtonActionPerformed PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_CONNECTION_TAB}); }//GEN-LAST:event_jProxySettingsButtonActionPerformed diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java index 1c19bd5eca..3520af3b4c 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/ArrowBuilder.java @@ -45,16 +45,12 @@ public class ArrowBuilder { * Get the panel where all arrows are being drawn. * @return */ - public JPanel getArrowsManagerPanel() { + public synchronized JPanel getArrowsManagerPanel() { if (arrowsManagerPanel == null) { - synchronized (ArrowBuilder.class) { - if (arrowsManagerPanel == null) { - arrowsManagerPanel = new JPanel(); - arrowsManagerPanel.setVisible(true); - arrowsManagerPanel.setOpaque(false); - arrowsManagerPanel.setLayout(null); - } - } + arrowsManagerPanel = new JPanel(); + arrowsManagerPanel.setVisible(true); + arrowsManagerPanel.setOpaque(false); + arrowsManagerPanel.setLayout(null); } return arrowsManagerPanel; } diff --git a/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java b/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java index 397da1cff0..c319f27b5b 100644 --- a/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/object/SaveObjectUtil.java @@ -1,5 +1,7 @@ package mage.client.util.object; +import mage.utils.StreamUtils; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -61,10 +63,9 @@ public final class SaveObjectUtil { oos.writeObject(object); oos.close(); - } catch (FileNotFoundException e) { - return; - } catch (IOException io) { - return; + } catch (Exception e) { + } finally { + StreamUtils.closeQuietly(oos); } } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java index f5c1af5d52..9350ff3a5b 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -41,6 +41,7 @@ import mage.client.constants.Constants.ResourceSymbolSize; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; import mage.client.util.gui.BufferedImageBuilder; +import mage.utils.StreamUtils; import org.apache.batik.dom.svg.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; @@ -249,10 +250,15 @@ public final class ManaSymbols { + "color-rendering: optimizeQuality;" + "image-rendering: optimizeQuality;" + "}"; + File cssFile = File.createTempFile("batik-default-override-", ".css"); - FileWriter w = new FileWriter(cssFile); - w.write(css); - w.close(); + FileWriter w = null; + try { + w = new FileWriter(cssFile); + w.write(css); + } finally { + StreamUtils.closeQuietly(w); + } TranscodingHints transcoderHints = new TranscodingHints(); @@ -284,7 +290,6 @@ public final class ManaSymbols { try { TranscoderInput input = new TranscoderInput(new FileInputStream(svgFile)); - ImageTranscoder t = new ImageTranscoder() { @Override diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/UI.java b/Mage.Client/src/main/java/org/mage/card/arcane/UI.java index 0b2ed25f00..d07264d8a8 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/UI.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/UI.java @@ -1,5 +1,7 @@ package org.mage.card.arcane; +import mage.utils.StreamUtils; + import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -72,8 +74,8 @@ public final class UI { } public static ImageIcon getImageIcon (String path) { + InputStream stream = null; try { - InputStream stream; stream = UI.class.getResourceAsStream(path); if (stream == null && new File(path).exists()) { stream = new FileInputStream(path); @@ -86,6 +88,8 @@ public final class UI { return new ImageIcon(data); } catch (IOException ex) { throw new RuntimeException("Error reading image: " + path); + } finally { + StreamUtils.closeQuietly(stream); } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/Util.java b/Mage.Client/src/main/java/org/mage/card/arcane/Util.java index 57f704056f..2645c314db 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/Util.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/Util.java @@ -37,9 +37,13 @@ public final class Util { } public static void broadcast(byte[] data, int port) throws IOException { - DatagramSocket socket = new DatagramSocket(); - broadcast(socket, data, port, NetworkInterface.getNetworkInterfaces()); - socket.close(); + DatagramSocket socket = null; + try { + socket = new DatagramSocket(); + broadcast(socket, data, port, NetworkInterface.getNetworkInterfaces()); + } finally { + socket.close(); + } } private static void broadcast(DatagramSocket socket, byte[] data, int port, Enumeration ifaces) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java index caef7e5d21..e90d1cf9c5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java @@ -9,6 +9,7 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import mage.util.StreamUtils; import org.mage.plugins.card.dl.DownloadJob; import static org.mage.card.arcane.ManaSymbols.getSymbolFileNameAsSVG; @@ -106,20 +107,21 @@ public class ScryfallSymbolsSource implements Iterable { if (destFile.exists() && (destFile.length() > 0)){ continue; } - + FileOutputStream stream = null; try { // base64 transform String data64 = foundedData.get(searchCode); Base64.Decoder dec = Base64.getDecoder(); byte[] fileData = dec.decode(data64); - FileOutputStream stream = new FileOutputStream(destFile); + stream = new FileOutputStream(destFile); stream.write(fileData); - stream.close(); LOGGER.info("New svg symbol downloaded: " + needCode); } catch (Exception e) { LOGGER.error("Can't decode svg icon and save to file: " + destFile.getPath() + ", reason: " + e.getMessage()); + } finally { + StreamUtils.closeQuietly(stream); } } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index 9e333430b7..5755522b1b 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -24,6 +24,7 @@ import mage.client.MageFrame; import mage.client.dialog.PreferencesDialog; import mage.client.util.sets.ConstructedFormats; import mage.remote.Connection; +import mage.util.StreamUtils; import net.java.truevfs.access.TFile; import net.java.truevfs.access.TFileOutputStream; import net.java.truevfs.access.TVFS; @@ -745,34 +746,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } - /* - if(!destFile.getParentFile().exists()){ - destFile.getParentFile().mkdirs(); - } - */ - - /* - // WTF start?! TODO: wtf - File existingFile = new File(imagePath.replaceFirst("\\w{3}.zip", "")); - if (existingFile.exists()) { - try { - new TFile(existingFile).cp_rp(outputFile); - } catch (IOException e) { - logger.error("Error while copying file " + card.getName(), e); - } - synchronized (sync) { - update(cardIndex + 1, count); - } - existingFile.delete(); - File parent = existingFile.getParentFile(); - if (parent != null && parent.isDirectory() && parent.list().length == 0) { - parent.delete(); - } - return; - } - // WTF end?! - */ - // START to download cardImageSource.doPause(url.getPath()); URLConnection httpConn = url.openConnection(p); httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); @@ -782,18 +755,18 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab if (responseCode == 200) { // download OK // save data to temp - BufferedOutputStream out; - try (BufferedInputStream in = new BufferedInputStream(httpConn.getInputStream())) { - out = new BufferedOutputStream(new TFileOutputStream(fileTempImage)); + OutputStream out = null; + OutputStream tfileout = null; + InputStream in = null; + try { + in = new BufferedInputStream(httpConn.getInputStream()); + tfileout = new TFileOutputStream(fileTempImage); + out = new BufferedOutputStream(tfileout); byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) != -1) { // user cancelled if (cancel) { - in.close(); - out.flush(); - out.close(); - // stop download, save current state and exit TFile archive = destFile.getTopLevelArchive(); ///* not need to unmout/close - it's auto action @@ -804,8 +777,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } catch (Exception e) { logger.error("Can't close archive file: " + e.getMessage(), e); } - - }//*/ + } try { TFile.rm(fileTempImage); } catch (Exception e) { @@ -816,9 +788,12 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab out.write(buf, 0, len); } } - // TODO: remove to finnaly section? - out.flush(); - out.close(); + finally { + StreamUtils.closeQuietly(in); + StreamUtils.closeQuietly(out); + StreamUtils.closeQuietly(tfileout); + } + // TODO: add two faces card correction? (WTF) // SAVE final data @@ -847,81 +822,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } - /* - // Logger.getLogger(this.getClass()).info(url.toString()); - boolean useTempFile = false; - int responseCode = 0; - URLConnection httpConn = null; - - if (temporaryFile != null && temporaryFile.length() > 100) { - useTempFile = true; - } else { - cardImageSource.doPause(url.getPath()); - httpConn = url.openConnection(p); - httpConn.connect(); - responseCode = ((HttpURLConnection) httpConn).getResponseCode(); - } - - if (responseCode == 200 || useTempFile) { - if (!useTempFile) { - BufferedOutputStream out; - try (BufferedInputStream in = new BufferedInputStream(httpConn.getInputStream())) { - //try (BufferedInputStream in = new BufferedInputStream(url.openConnection(p).getInputStream())) { - out = new BufferedOutputStream(new TFileOutputStream(temporaryFile)); - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) != -1) { - // user cancelled - if (cancel) { - in.close(); - out.flush(); - out.close(); - temporaryFile.delete(); - return; - } - out.write(buf, 0, len); - } - - } - out.flush(); - out.close(); - } - - // TODO: WTF?! start - if (card != null && card.isTwoFacedCard()) { - BufferedImage image = ImageIO.read(temporaryFile); - if (image.getHeight() == 470) { - BufferedImage renderedImage = new BufferedImage(265, 370, BufferedImage.TYPE_INT_RGB); - renderedImage.getGraphics(); - Graphics2D graphics2D = renderedImage.createGraphics(); - if (card.isTwoFacedCard() && card.isSecondSide()) { - graphics2D.drawImage(image, 0, 0, 265, 370, 313, 62, 578, 432, null); - } else { - graphics2D.drawImage(image, 0, 0, 265, 370, 41, 62, 306, 432, null); - } - graphics2D.dispose(); - writeImageToFile(renderedImage, outputFile); - } else { - outputFile.getParentFile().mkdirs(); - new TFile(temporaryFile).cp_rp(outputFile); - } - //temporaryFile.delete(); - } else { - outputFile.getParentFile().mkdirs(); - new TFile(temporaryFile).cp_rp(outputFile); - } - // WTF?! end - } else { - if (card != null && !useSpecifiedPaths) { - logger.warn("Image download for " + card.getName() - + (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "") - + '(' + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); - } - if (logger.isDebugEnabled()) { // Shows the returned html from the request to the web server - logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream())); - } - } - */ } catch (AccessDeniedException e) { logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock."); } catch (Exception e) { @@ -933,26 +833,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab update(cardIndex + 1, count); } } - -// private void writeImageToFile(BufferedImage image, TFile file) throws IOException { -// Iterator iter = ImageIO.getImageWritersByFormatName("jpg"); -// -// ImageWriter writer = (ImageWriter) iter.next(); -// ImageWriteParam iwp = writer.getDefaultWriteParam(); -// iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); -// iwp.setCompressionQuality(0.96f); -// -// File tempFile = new File(getImagesDir() + File.separator + image.hashCode() + file.getName()); -// FileImageOutputStream output = new FileImageOutputStream(tempFile); -// writer.setOutput(output); -// IIOImage image2 = new IIOImage(image, null, null); -// writer.write(null, image2, iwp); -// writer.dispose(); -// output.close(); -// -// new TFile(tempFile).cp_rp(file); -// tempFile.delete(); -// } } private void update(int card, int count) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java b/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java index 075a3d9008..c7a6b87d62 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java @@ -12,13 +12,9 @@ public class SettingsManager { private static SettingsManager settingsManager = null; - public static SettingsManager getIntance() { + public static synchronized SettingsManager getIntance() { if (settingsManager == null) { - synchronized (SettingsManager.class) { - if (settingsManager == null) { - settingsManager = new SettingsManager(); - } - } + settingsManager = new SettingsManager(); } return settingsManager; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java index 43c788e983..6f9b00879f 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java @@ -150,47 +150,43 @@ public class ThemePluginImpl implements ThemePlugin { return bgPanel; } - private ImagePanel createImagePanelInstance() { + private synchronized ImagePanel createImagePanelInstance() { if (background == null) { - synchronized (ThemePluginImpl.class) { - if (background == null) { - String filename = "/background.png"; - try { - if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE_DEFAULT, "true").equals("true")) { - InputStream is = this.getClass().getResourceAsStream(filename); - if (is == null) { - throw new FileNotFoundException("Couldn't find " + filename + " in resources."); - } - background = ImageIO.read(is); - } else { - String path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE, ""); - if (path != null && !path.isEmpty()) { - try { - File f = new File(path); - if (f != null) { - background = ImageIO.read(f); - } - } catch (Exception e) { - background = null; - } - } - } - if (background == null) { - InputStream is = this.getClass().getResourceAsStream(filename); - if (is == null) { - throw new FileNotFoundException("Couldn't find " + filename + " in resources."); - } - background = ImageIO.read(is); - } - if (background == null) { + String filename = "/background.png"; + try { + if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE_DEFAULT, "true").equals("true")) { + InputStream is = this.getClass().getResourceAsStream(filename); + if (is == null) { throw new FileNotFoundException("Couldn't find " + filename + " in resources."); } - } catch (Exception e) { - log.error(e.getMessage(), e); - return null; + background = ImageIO.read(is); + } else { + String path = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BACKGROUND_IMAGE, ""); + if (path != null && !path.isEmpty()) { + try { + File f = new File(path); + if (f != null) { + background = ImageIO.read(f); + } + } catch (Exception e) { + background = null; + } + } } + if (background == null) { + InputStream is = this.getClass().getResourceAsStream(filename); + if (is == null) { + throw new FileNotFoundException("Couldn't find " + filename + " in resources."); + } + background = ImageIO.read(is); + } + if (background == null) { + throw new FileNotFoundException("Couldn't find " + filename + " in resources."); + } + } catch (Exception e) { + log.error(e.getMessage(), e); + return null; } - } } return new ImagePanel(background, ImagePanelStyle.SCALED); } diff --git a/Mage.Common/src/main/java/mage/utils/StreamUtils.java b/Mage.Common/src/main/java/mage/utils/StreamUtils.java new file mode 100644 index 0000000000..1b228b454a --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/StreamUtils.java @@ -0,0 +1,30 @@ +package mage.utils; + +import java.io.Closeable; + +public final class StreamUtils { + + /*** + * Quietly closes the closable, ignoring nulls and exceptions + * @param c - the closable to be closed + */ + public static void closeQuietly(Closeable c) { + if (c != null) { + try { + c.close(); + } + catch (Exception e) { + } + } + } + + public static void closeQuietly(AutoCloseable ac) { + if (ac != null) { + try { + ac.close(); + } + catch (Exception e) { + } + } + } +} diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index a7c5a914c9..d3785cfa65 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -957,10 +957,11 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } protected final void getSuggestedActions() { + Scanner scanner = null; try { File file = new File(FILE_WITH_INSTRUCTIONS); if (file.exists()) { - Scanner scanner = new Scanner(file); + scanner = new Scanner(file); while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (line.startsWith("cast:") @@ -976,6 +977,10 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } catch (Exception e) { // swallow e.printStackTrace(); + } finally { + if(scanner != null) { + scanner.close(); + } } } diff --git a/Mage.Server/src/main/java/mage/server/ChatSession.java b/Mage.Server/src/main/java/mage/server/ChatSession.java index da9b897f7e..e73c0410f1 100644 --- a/Mage.Server/src/main/java/mage/server/ChatSession.java +++ b/Mage.Server/src/main/java/mage/server/ChatSession.java @@ -90,8 +90,8 @@ public class ChatSession { String userName = clients.get(userId); if (reason != DisconnectReason.LostConnection) { // for lost connection the user will be reconnected or session expire so no removeUserFromAllTablesAndChat of chat yet final Lock w = lock.writeLock(); - w.lock(); try { + w.lock(); clients.remove(userId); } finally { w.unlock(); diff --git a/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java b/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java index 6c5b3f80ad..8894ae6720 100644 --- a/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java +++ b/Mage.Server/src/main/java/mage/server/ExtensionPackageLoader.java @@ -29,6 +29,7 @@ package mage.server; import mage.server.util.PluginClassLoader; +import mage.util.StreamUtils; import java.io.File; import java.io.IOException; @@ -54,10 +55,12 @@ public final class ExtensionPackageLoader { String entryPoint = entryPointReader.nextLine().trim(); entryPointReader.close(); - PluginClassLoader classLoader = new PluginClassLoader(); - for(File f : packagesDirectory.listFiles()) classLoader.addURL(f.toURI().toURL()); - + PluginClassLoader classLoader = null; try { + classLoader = new PluginClassLoader(); + for(File f : packagesDirectory.listFiles()) { + classLoader.addURL(f.toURI().toURL()); + } return (ExtensionPackage) Class.forName(entryPoint, false, classLoader).newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); @@ -65,6 +68,8 @@ public final class ExtensionPackageLoader { throw new RuntimeException("Entry point class not found!", e); } catch (ClassCastException e) { throw new RuntimeException("Entry point not an instance of ExtensionPackage.", e); + } finally { + StreamUtils.closeQuietly(classLoader); } } } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index cd30111745..767f7bb59a 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -231,8 +231,8 @@ public enum UserManager { } logger.debug("Users to remove " + toRemove.size()); final Lock w = lock.readLock(); - w.lock(); try { + w.lock(); for (User user : toRemove) { users.remove(user.getId()); } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 8082d6576d..8bce119961 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -64,6 +64,7 @@ import mage.server.util.ConfigSettings; import mage.server.util.Splitter; import mage.server.util.SystemUtil; import mage.server.util.ThreadExecutor; +import mage.utils.StreamUtils; import mage.utils.timer.PriorityTimer; import mage.view.*; import mage.view.ChatMessage.MessageColor; @@ -902,17 +903,23 @@ public class GameController implements GameCallback { } public boolean saveGame() { + OutputStream file = null; + ObjectOutput output = null; + OutputStream buffer = null; try { - OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game"); - OutputStream buffer = new BufferedOutputStream(file); - try (ObjectOutput output = new ObjectOutputStream(new GZIPOutputStream(buffer))) { - output.writeObject(game); - output.writeObject(game.getGameStates()); - } + file = new FileOutputStream("saved/" + game.getId().toString() + ".game"); + buffer = new BufferedOutputStream(file); + output = new ObjectOutputStream(new GZIPOutputStream(buffer)); + output.writeObject(game); + output.writeObject(game.getGameStates()); logger.debug("Saved game:" + game.getId()); return true; } catch (IOException ex) { logger.fatal("Cannot save game.", ex); + } finally { + StreamUtils.closeQuietly(file); + StreamUtils.closeQuietly(output); + StreamUtils.closeQuietly(buffer); } return false; } diff --git a/Mage.Server/src/main/java/mage/server/game/GameReplay.java b/Mage.Server/src/main/java/mage/server/game/GameReplay.java index 820bc9a6d3..01a4a1dd99 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameReplay.java +++ b/Mage.Server/src/main/java/mage/server/game/GameReplay.java @@ -40,6 +40,7 @@ import mage.game.GameState; import mage.game.GameStates; import mage.server.Main; import mage.util.CopierObjectInputStream; +import mage.utils.StreamUtils; import org.apache.log4j.Logger; @@ -84,21 +85,31 @@ public class GameReplay { } private Game loadGame(UUID gameId) { + InputStream file = null; + InputStream buffer = null; + InputStream gzip = null; + ObjectInput input = null; try{ - InputStream file = new FileInputStream("saved/" + gameId.toString() + ".game"); - InputStream buffer = new BufferedInputStream(file); - try (ObjectInput input = new CopierObjectInputStream(Main.classLoader, new GZIPInputStream(buffer))) { - Game loadGame = (Game) input.readObject(); - GameStates states = (GameStates) input.readObject(); - loadGame.loadGameStates(states); - return loadGame; - } + file = new FileInputStream("saved/" + gameId.toString() + ".game"); + buffer = new BufferedInputStream(file); + gzip = new GZIPInputStream(buffer); + input = new CopierObjectInputStream(Main.classLoader, gzip); + Game loadGame = (Game) input.readObject(); + GameStates states = (GameStates) input.readObject(); + loadGame.loadGameStates(states); + return loadGame; + } catch(ClassNotFoundException ex) { logger.fatal("Cannot load game. Class not found.", ex); } catch(IOException ex) { logger.fatal("Cannot load game:" + gameId, ex); + } finally { + StreamUtils.closeQuietly(file); + StreamUtils.closeQuietly(buffer); + StreamUtils.closeQuietly(input); + StreamUtils.closeQuietly(gzip); } return null; } diff --git a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java index d596f8a653..2cedad7aa8 100644 --- a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java @@ -27,6 +27,7 @@ */ package mage.server.util; +import mage.utils.StreamUtils; import org.apache.log4j.Logger; import java.io.File; @@ -49,7 +50,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * @author nantuko */ public enum ServerMessagesUtil { -instance; + instance; private static final Logger log = Logger.getLogger(ServerMessagesUtil.class); private static final String SERVER_MSG_TXT_FILE = "server.msg.txt"; private ScheduledExecutorService updateExecutor; @@ -147,13 +148,22 @@ instance; log.warn("Couldn't find server.msg"); return null; } - Scanner scanner = new Scanner(is); + + Scanner scanner = null; List newMessages = new ArrayList<>(); - while (scanner.hasNextLine()) { - String message = scanner.nextLine(); - if (!message.trim().isEmpty()) { - newMessages.add(message.trim()); + try { + scanner = new Scanner(is); + while (scanner.hasNextLine()) { + String message = scanner.nextLine(); + if (!message.trim().isEmpty()) { + newMessages.add(message.trim()); + } } + } catch(Exception e) { + log.error(e,e); + } finally { + StreamUtils.closeQuietly(scanner); + StreamUtils.closeQuietly(is); } return newMessages; } diff --git a/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java b/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java index 133675ffb7..f622375b46 100644 --- a/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java +++ b/Mage.Sets/src/mage/cards/e/EmpyrialArchangel.java @@ -91,7 +91,6 @@ class EmpyrialArchangelEffect extends ReplacementEffectImpl { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { p.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable()); - return true; } return true; } diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java index 71962fce82..5dfba5bc4a 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathAristocrat.java @@ -105,7 +105,7 @@ class FalkenrathAristocratEffect extends OneShotEffect { Permanent sourceCreature = game.getPermanent(source.getSourceId()); if (sacrificedCreature.hasSubtype(SubType.HUMAN, game) && sourceCreature != null) { sourceCreature.addCounters(CounterType.P1P1.createInstance(), source, game); - return true; + break; } } } diff --git a/Mage.Sets/src/mage/cards/g/GilderBairn.java b/Mage.Sets/src/mage/cards/g/GilderBairn.java index 1ce8089546..7f71ffd626 100644 --- a/Mage.Sets/src/mage/cards/g/GilderBairn.java +++ b/Mage.Sets/src/mage/cards/g/GilderBairn.java @@ -95,12 +95,11 @@ class GilderBairnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent target = game.getPermanent(source.getFirstTarget()); - if (target == null) { - return false; - } - for (Counter counter : target.getCounters(game).values()) { - Counter newCounter = new Counter(counter.getName(), counter.getCount()); - target.addCounters(newCounter, source, game); + if (target != null) { + for (Counter counter : target.getCounters(game).values()) { + Counter newCounter = new Counter(counter.getName(), counter.getCount()); + target.addCounters(newCounter, source, game); + } } return false; } diff --git a/Mage.Sets/src/mage/cards/i/IceCave.java b/Mage.Sets/src/mage/cards/i/IceCave.java index 188f79f42b..bcdf7f4d6f 100644 --- a/Mage.Sets/src/mage/cards/i/IceCave.java +++ b/Mage.Sets/src/mage/cards/i/IceCave.java @@ -102,7 +102,7 @@ class IceCaveEffect extends OneShotEffect { if (cost.pay(source, game, source.getSourceId(), playerId, false, null)) { game.informPlayers(player.getLogName() + " pays" + cost.getText() + " to counter " + spell.getIdName() + '.'); game.getStack().counter(spell.getId(), source.getSourceId(), game); - return true; + break; } } } diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java index 87b1171250..0ff4c0e503 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java @@ -99,7 +99,6 @@ class KjeldoranRoyalGuardEffect extends ReplacementEffectImpl { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { p.damage(damageEvent.getAmount(), event.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable()); - return true; } return true; } diff --git a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java index 3206227ed3..e20c35f1dc 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java +++ b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java @@ -129,7 +129,6 @@ class LegionsInitiativeExileEffect extends OneShotEffect { //create delayed triggered ability AtTheBeginOfCombatDelayedTriggeredAbility delayedAbility = new AtTheBeginOfCombatDelayedTriggeredAbility(new LegionsInitiativeReturnFromExileEffect()); game.addDelayedTriggeredAbility(delayedAbility, source); - return true; } return true; } diff --git a/Mage.Sets/src/mage/cards/n/NaturesWill.java b/Mage.Sets/src/mage/cards/n/NaturesWill.java index 215999aa9b..c6a2e8bbc0 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWill.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWill.java @@ -84,19 +84,16 @@ class NaturesWillEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Set damagedPlayers = (HashSet) this.getValue("damagedPlayers"); - if (damagedPlayers == null) { - return false; - } - - List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game); - for (Permanent land : lands) { - if (damagedPlayers.contains(land.getControllerId())) { - land.tap(game); - } else if (land.getControllerId().equals(source.getControllerId())) { - land.untap(game); + if (damagedPlayers != null) { + List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game); + for (Permanent land : lands) { + if (damagedPlayers.contains(land.getControllerId())) { + land.tap(game); + } else if (land.getControllerId().equals(source.getControllerId())) { + land.untap(game); + } } } - return false; } } diff --git a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java index 63b9d873e1..d23c0bdf4c 100644 --- a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java +++ b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java @@ -4,7 +4,7 @@ import java.io.*; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.List; - +import java.io.Closeable; /** * Helper for file operations. * @@ -84,15 +84,17 @@ public final class FileHelper { */ public static void downloadFile(String filename, HttpURLConnection urlConnection) { System.out.println("Downloading " + filename); + InputStream in = null; + FileOutputStream out = null; try { - InputStream in = urlConnection.getInputStream(); + in = urlConnection.getInputStream(); File f = new File(filename); if (!f.exists() && f.getParentFile() != null) { f.getParentFile().mkdirs(); System.out.println("Directories have been created: " + f.getParentFile().getPath()); } - FileOutputStream out = new FileOutputStream(filename); + out = new FileOutputStream(filename); byte[] buf = new byte[4 * 1024]; int bytesRead; @@ -103,6 +105,19 @@ public final class FileHelper { System.out.println("File has been updated: " + filename); } catch (IOException e) { System.out.println("i/o exception - " + e.getMessage()); + } finally { + closeQuietly(in); + closeQuietly(out); + } + } + + public static void closeQuietly(Closeable s) { + if(s != null) { + try { + s.close(); + } catch (Exception e) { + System.out.println("i/o exception - " + e.getMessage()); + } } } } diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java index b187667140..287aecef3d 100644 --- a/Mage.Verify/src/main/java/mage/verify/MtgJson.java +++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java @@ -2,6 +2,7 @@ package mage.verify; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import mage.util.StreamUtils; import java.io.File; import java.io.FileInputStream; @@ -94,9 +95,16 @@ public final class MtgJson { } stream = new FileInputStream(file); } - ZipInputStream zipInputStream = new ZipInputStream(stream); - zipInputStream.getNextEntry(); - return new ObjectMapper().readValue(zipInputStream, ref); + ZipInputStream zipInputStream = null; + try { + zipInputStream = new ZipInputStream(stream); + zipInputStream.getNextEntry(); + return new ObjectMapper().readValue(zipInputStream, ref); + } finally { + StreamUtils.closeQuietly(zipInputStream); + StreamUtils.closeQuietly(stream); + } + } public static Map sets() { diff --git a/Mage/src/main/java/mage/util/Copier.java b/Mage/src/main/java/mage/util/Copier.java index e6b7aa4b49..56c2385424 100644 --- a/Mage/src/main/java/mage/util/Copier.java +++ b/Mage/src/main/java/mage/util/Copier.java @@ -50,36 +50,44 @@ public class Copier { public T copy(T obj) { T copy = null; + + FastByteArrayOutputStream fbos = null; + ObjectOutputStream out = null; + ObjectInputStream in = null; try { - FastByteArrayOutputStream fbos = new FastByteArrayOutputStream(); - ObjectOutputStream out= new ObjectOutputStream(fbos); + fbos = new FastByteArrayOutputStream(); + out = new ObjectOutputStream(fbos); // Write the object out to a byte array out.writeObject(obj); out.flush(); - out.close(); // Retrieve an input stream from the byte array and read // a copy of the object back in. - ObjectInputStream in = new CopierObjectInputStream(loader, fbos.getInputStream()); + in = new CopierObjectInputStream(loader, fbos.getInputStream()); copy = (T) in.readObject(); } catch(IOException | ClassNotFoundException e) { e.printStackTrace(); + } finally { + StreamUtils.closeQuietly(fbos); + StreamUtils.closeQuietly(out); + StreamUtils.closeQuietly(in); } return copy; } public byte[] copyCompressed(T obj) { + FastByteArrayOutputStream fbos = null; + ObjectOutputStream out = null; try { - FastByteArrayOutputStream fbos = new FastByteArrayOutputStream(); - ObjectOutputStream out= new ObjectOutputStream(new GZIPOutputStream(fbos)); + fbos = new FastByteArrayOutputStream(); + out = new ObjectOutputStream(new GZIPOutputStream(fbos)); // Write the object out to a byte array out.writeObject(obj); out.flush(); - out.close(); byte[] copy = new byte[fbos.getSize()]; System.arraycopy(fbos.getByteArray(), 0, copy, 0, fbos.getSize()); @@ -87,6 +95,9 @@ public class Copier { } catch(IOException e) { e.printStackTrace(); + } finally { + StreamUtils.closeQuietly(fbos); + StreamUtils.closeQuietly(out); } return null; } diff --git a/Mage/src/main/java/mage/util/StreamUtils.java b/Mage/src/main/java/mage/util/StreamUtils.java new file mode 100644 index 0000000000..2be62157c3 --- /dev/null +++ b/Mage/src/main/java/mage/util/StreamUtils.java @@ -0,0 +1,30 @@ +package mage.util; + +import java.io.Closeable; + +public final class StreamUtils { + + /*** + * Quietly closes the closable, ignoring nulls and exceptions + * @param c - the closable to be closed + */ + public static void closeQuietly(Closeable c) { + if (c != null) { + try { + c.close(); + } + catch (Exception e) { + } + } + } + + public static void closeQuietly(AutoCloseable ac) { + if (ac != null) { + try { + ac.close(); + } + catch (Exception e) { + } + } + } +}