SPARK-2360: Isolate bugs, log improvements

There is a slew of minor issues, such as operating on non-existing images, that throw unchecked exceptions and break the application badly.

To isolate these occurrences, exception handling can be put in place, with some logging being generated. That won’t solve the underlying issue, but it should limit the impact of these issues.
This commit is contained in:
Guus der Kinderen 2025-10-10 10:12:52 +02:00
parent 05b8e82499
commit 8313e43eb4
12 changed files with 239 additions and 198 deletions

View File

@ -303,8 +303,8 @@ public class ContactInfoWindow extends JPanel {
}
avatarLabel.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1, true));
}
catch (MalformedURLException e) {
Log.error(e);
catch (Exception e) {
Log.warning("Unable to update avatar in contact info window", e);
}
// Get VCard from memory (if available)

View File

@ -601,8 +601,8 @@ public class ContactItem extends JPanel {
setSideIcon(icon);
}
}
} catch (MalformedURLException e) {
Log.error(e);
} catch (Exception e) {
Log.warning("Unable to update avatar in side icon", e);
}
}

View File

@ -77,12 +77,15 @@ public class VCardPanel extends JPanel {
add(avatarImage, new GridBagConstraints(0, 0, 1, 3, 0.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 0, 5, 0), 0, 0));
buildAvatarHover();
Image aImage = SparkRes.getImageIcon(SparkRes.BLANK_24x24).getImage();
aImage = aImage.getScaledInstance(-1, 64, Image.SCALE_SMOOTH);
ImageIcon ico = new ImageIcon(aImage);
avatarImage.setIcon(ico);
try {
Image aImage = SparkRes.getImageIcon(SparkRes.BLANK_24x24).getImage();
aImage = aImage.getScaledInstance(-1, 64, Image.SCALE_SMOOTH);
ImageIcon ico = new ImageIcon(aImage);
avatarImage.setIcon(ico);
} catch (Exception e) {
Log.error("Unable to process image in vcard!", e);
}
VCard vcard = SparkManager.getVCardManager().getVCard(jid);
@ -105,7 +108,7 @@ public class VCardPanel extends JPanel {
icon = new ImageIcon(newImage);
}
catch (Exception e) {
Log.error(e);
Log.error("Unable to fetch image in vcard!", e);
}
}
else {
@ -153,7 +156,7 @@ public class VCardPanel extends JPanel {
icon = new ImageIcon(newImage);
} catch (Exception e1) {
Log.error(e1);
Log.error("Unable to process vcard avatar", e1);
}
} else {

View File

@ -75,58 +75,61 @@ public class VCardViewer extends JPanel {
avatarImage = new JLabel();
add(avatarImage, new GridBagConstraints(0, 0, 1, 3, 0.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 0, 5, 0), 0, 0));
try {
Image aImage = SparkRes.getImageIcon(SparkRes.BLANK_24x24).getImage();
aImage = aImage.getScaledInstance(-1, 64, Image.SCALE_SMOOTH);
ImageIcon ico = new ImageIcon(aImage);
Image aImage = SparkRes.getImageIcon(SparkRes.BLANK_24x24).getImage();
aImage = aImage.getScaledInstance(-1, 64, Image.SCALE_SMOOTH);
ImageIcon ico = new ImageIcon(aImage);
avatarImage.setIcon(ico);
avatarImage.setIcon(ico);
final SwingWorker vcardLoader = new SwingWorker()
{
VCard vcard = null;
final SwingWorker vcardLoader = new SwingWorker() {
VCard vcard = null;
@Override
public Object construct() {
vcard = SparkManager.getVCardManager().getVCard(jid);
return vcard;
}
@Override
public void finished() {
if (vcard == null) {
// Do nothing.
return;
@Override
public Object construct()
{
vcard = SparkManager.getVCardManager().getVCard(jid);
return vcard;
}
ImageIcon icon = null;
byte[] bytes = vcard.getAvatar();
if (bytes != null && bytes.length > 0) {
try {
icon = new ImageIcon(bytes);
Image aImage = icon.getImage();
aImage = aImage.getScaledInstance(-1, 48, Image.SCALE_SMOOTH);
icon = new ImageIcon(aImage);
@Override
public void finished()
{
if (vcard == null) {
// Do nothing.
return;
}
catch (Exception e) {
Log.error(e);
ImageIcon icon = null;
byte[] bytes = vcard.getAvatar();
if (bytes != null && bytes.length > 0) {
try {
icon = new ImageIcon(bytes);
Image aImage = icon.getImage();
aImage = aImage.getScaledInstance(-1, 48, Image.SCALE_SMOOTH);
icon = new ImageIcon(aImage);
} catch (Exception e) {
Log.warning("Unable to get scaled avatar from vcard.", e);
}
} else {
icon = SparkRes.getImageIcon(SparkRes.DEFAULT_AVATAR_32x32_IMAGE);
}
}
else {
icon = SparkRes.getImageIcon(SparkRes.DEFAULT_AVATAR_32x32_IMAGE);
}
if (icon != null && icon.getIconWidth() > 0) {
avatarImage.setIcon(icon);
avatarImage.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1, true));
if (icon != null && icon.getIconWidth() > 0) {
avatarImage.setIcon(icon);
avatarImage.setBorder(BorderFactory.createLineBorder(Color.lightGray, 1, true));
}
vcard.setJabberId(jid);
buildUI(vcard);
}
vcard.setJabberId(jid);
buildUI(vcard);
}
};
vcardLoader.start();
};
vcardLoader.start();
} catch (Exception e) {
Log.warning("Unable to get avatar from vcard.", e);
}
}
private void buildUI(final VCard vcard) {

View File

@ -920,18 +920,29 @@ public class ConferenceRoomBrowser extends JPanel implements ActionListener,
}
if (isbookmark && ispassword) {
Image img = ImageCombiner.combine(bookmarkicon, passwordicon);
iconLabel.setIcon(new ImageIcon(img));
try {
Image img = ImageCombiner.combine(bookmarkicon, passwordicon);
if (img != null) {
iconLabel.setIcon(new ImageIcon(img));
}
} catch (Exception e) {
Log.warning("Unable to set icon for bookmarked & password-protected room " + jid, e);
}
} else if (isbookmark) {
iconLabel.setIcon(bookmarkicon);
} else if (ispassword) {
Image img = ImageCombiner.returnTransparentImage(
passwordicon.getIconWidth(), passwordicon.getIconHeight());
Image combined = ImageCombiner.combine(new ImageIcon(img),
passwordicon);
iconLabel.setIcon(new ImageIcon(combined));
try {
if (passwordicon != null) {
Image img = ImageCombiner.returnTransparentImage(
passwordicon.getIconWidth(), passwordicon.getIconHeight());
Image combined = ImageCombiner.combine(new ImageIcon(img), passwordicon);
if (combined != null) {
iconLabel.setIcon(new ImageIcon(combined));
}
}
} catch (Exception e) {
Log.warning("Unable to set icon for password-protected room " + jid, e);
}
}
String occupants = Integer.toString(numberOfOccupants);
@ -939,7 +950,7 @@ public class ConferenceRoomBrowser extends JPanel implements ActionListener,
occupants = "n/a";
}
return new Object[] { iconLabel, roomName.toString(), jid.getLocalpart().toString(), occupants };
return new Object[] { iconLabel, roomName == null ? jid.getLocalpart().toString() : roomName.toString(), jid.getLocalpart().toString(), occupants };
}
@Override

View File

@ -345,12 +345,16 @@ public class CustomMessages {
// Add Types
for (StatusItem statusItem : statusBar.getStatusList()) {
if (!PresenceManager.isOnPhone(statusItem.getPresence())) {
ImageIcon icon = (ImageIcon) statusItem.getIcon();
try {
ImageIcon icon = (ImageIcon) statusItem.getIcon();
ImageIcon newIcon = new ImageIcon(icon.getImage());
newIcon.setDescription(statusItem.getText());
ImageIcon newIcon = new ImageIcon(icon.getImage());
newIcon.setDescription(statusItem.getText());
typeBox.addItem(newIcon);
typeBox.addItem(newIcon);
} catch (Exception e) {
Log.warning("Unable to update icon on custom status bar", e);
}
}
}

View File

@ -165,19 +165,23 @@ public class StatusBar extends JPanel implements VCardListener {
}
public void setAvatar(Icon icon) {
if (icon == null) {
imageLabel.setIcon(null);
} else {
Image image = ImageCombiner.iconToImage(icon);
if (icon.getIconHeight() > 64 || icon.getIconWidth() > 64) {
imageLabel.setIcon(new ImageIcon(image.getScaledInstance(-1, 64, Image.SCALE_SMOOTH)));
try {
if (icon == null) {
imageLabel.setIcon(null);
} else {
imageLabel.setIcon(icon);
Image image = ImageCombiner.iconToImage(icon);
if (icon.getIconHeight() > 64 || icon.getIconWidth() > 64) {
imageLabel.setIcon(new ImageIcon(image.getScaledInstance(-1, 64, Image.SCALE_SMOOTH)));
} else {
imageLabel.setIcon(icon);
}
}
imageLabel.setBorder(null);
revalidate();
allowProfileEditing();
} catch (Exception e) {
Log.warning("Unable to set avatar", e);
}
imageLabel.setBorder(null);
revalidate();
allowProfileEditing();
}
public CommandPanel getCommandPanel() {
@ -506,7 +510,7 @@ public class StatusBar extends JPanel implements VCardListener {
imageLabel.validate();
imageLabel.repaint();
} catch (Exception e) {
// no issue
Log.warning("Unable to update vcard viewer with avatar data", e);
}
} else {
imageLabel.setIcon(null);

View File

@ -692,52 +692,16 @@ public final class GraphicUtils {
* @return byte[]
*/
public static byte[] getBytesFromImage(File file) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
try (FileInputStream fileInputStream = new FileInputStream(file)) {
byte[] data = new byte[(int) file.length()];
fileInputStream.read(data);
fileInputStream.close();
return data;
} catch (IOException e) {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e1) {
Log.error(e1);
}
}
} catch (Exception e) {
Log.warning("Unable to read image", e);
return null;
}
}
/**
* Returns a scaled down image if the height or width is smaller than the image size.
*
* @param icon the image icon.
* @param newHeight the preferred height.
* @param newWidth the preferred width.
* @return the icon.
*/
public static ImageIcon scaleImageIcon(ImageIcon icon, int newHeight, int newWidth) {
int height = icon.getIconHeight();
int width = icon.getIconWidth();
boolean resize = false;
if (height > newHeight) {
height = newHeight;
resize = true;
}
if (width > newWidth) {
width = newWidth;
resize = true;
}
if (!resize) {
return icon;
}
Image img = icon.getImage().getScaledInstance(width, height, Image.SCALE_SMOOTH);
return new ImageIcon(img);
}
/**
* Returns a scaled down image if the height or width is smaller than the
* image size.
@ -750,38 +714,78 @@ public final class GraphicUtils {
* the preferred width.
* @return the icon.
*/
public static ImageIcon scale(ImageIcon icon, int newHeight, int newWidth) {
Image img = icon.getImage();
int height = icon.getIconHeight();
int width = icon.getIconWidth();
boolean scaleHeight = height * newWidth > width * newHeight;
if (height > newHeight) {
// Too tall
if (width <= newWidth || scaleHeight) {
// Width is okay or height is limiting factor due to aspect
// ratio
height = newHeight;
width = -1;
} else {
// Width is limiting factor due to aspect ratio
height = -1;
width = newWidth;
}
} else if (width > newWidth) {
// Too wide and height is okay
height = -1;
width = newWidth;
} else if (scaleHeight) {
// Height is limiting factor due to aspect ratio
height = newHeight;
width = -1;
} else {
// Width is limiting factor due to aspect ratio
height = -1;
width = newWidth;
}
img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
return new ImageIcon(img);
public static ImageIcon scaleImageIcon(ImageIcon icon, int newHeight, int newWidth)
{
try {
Image img = icon.getImage();
int height = icon.getIconHeight();
int width = icon.getIconWidth();
if (height > newHeight) {
height = newHeight;
}
if (width > newWidth) {
width = newWidth;
}
img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
return new ImageIcon(img);
} catch (Exception e) {
Log.warning("Unable to scale image", e);
return null;
}
}
/**
* Returns a scaled down image if the height or width is smaller than the
* image size.
*
* @param icon
* the image icon.
* @param newHeight
* the preferred height.
* @param newWidth
* the preferred width.
* @return the icon.
*/
public static ImageIcon scale(ImageIcon icon, int newHeight, int newWidth)
{
try {
Image img = icon.getImage();
int height = icon.getIconHeight();
int width = icon.getIconWidth();
boolean scaleHeight = height * newWidth > width * newHeight;
if (height > newHeight) {
// Too tall
if (width <= newWidth || scaleHeight) {
// Width is okay or height is limiting factor due to aspect
// ratio
height = newHeight;
width = -1;
} else {
// Width is limiting factor due to aspect ratio
height = -1;
width = newWidth;
}
} else if (width > newWidth) {
// Too wide and height is okay
height = -1;
width = newWidth;
} else if (scaleHeight) {
// Height is limiting factor due to aspect ratio
height = newHeight;
width = -1;
} else {
// Width is limiting factor due to aspect ratio
height = -1;
width = newWidth;
}
img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
return new ImageIcon(img);
} catch (Exception e) {
Log.warning("Unable to scale image", e);
return null;
}
}
/**
@ -796,7 +800,7 @@ public final class GraphicUtils {
try {
return new JFileChooser().getIcon(file);
} catch (Exception e) {
Log.debug("unable to get icon");
Log.warning("unable to get icon", e);
}
return SparkRes.getImageIcon(SparkRes.DOCUMENT_INFO_32x32);
@ -833,27 +837,32 @@ public final class GraphicUtils {
* @return
*/
public static ImageIcon fitToSquare(ImageIcon icon, int newSize) {
if (newSize <= 0) {
return icon;
}
try {
if (newSize <= 0) {
return icon;
}
final int oldWidth = icon.getIconWidth();
final int oldHeight = icon.getIconHeight();
int newWidth;
int newHeight;
final int oldWidth = icon.getIconWidth();
final int oldHeight = icon.getIconHeight();
int newWidth;
int newHeight;
if (oldHeight >= oldWidth) {
newWidth = (int) ((float) oldWidth * newSize / oldHeight);
newHeight = newSize;
} else {
newWidth = newSize;
newHeight = (int) ((float) oldHeight * newSize / oldWidth);
}
if (oldHeight >= oldWidth) {
newWidth = (int) ((float) oldWidth * newSize / oldHeight);
newHeight = newSize;
} else {
newWidth = newSize;
newHeight = (int) ((float) oldHeight * newSize / oldWidth);
}
final Image img = icon.getImage().getScaledInstance(newWidth,
newHeight, Image.SCALE_SMOOTH);
final Image img = icon.getImage().getScaledInstance(newWidth,
newHeight, Image.SCALE_SMOOTH);
return new ImageIcon(img);
return new ImageIcon(img);
} catch (Exception e) {
Log.warning("Unable to fit image to square", e);
return null;
}
}
// public static void centerWindowOnScreen(Runnable runnable) {

View File

@ -15,6 +15,8 @@
*/
package org.jivesoftware.spark.util;
import org.jivesoftware.spark.util.log.Log;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
@ -34,7 +36,6 @@ import javax.swing.JComponent;
*/
public class ImageCombiner {
/**
* Combines two images into one
*
@ -59,31 +60,35 @@ public class ImageCombiner {
* @return combined Image
*/
public static Image combine(ImageIcon image1, ImageIcon image2) {
try {
ImageObserver comp = new JComponent()
{
private static final long serialVersionUID = 1L;
};
ImageObserver comp = new JComponent() {
private static final long serialVersionUID = 1L;
};
int w = image1.getIconWidth() + image2.getIconWidth();
int h = Math.max(image1.getIconHeight(), image2.getIconHeight());
int w = image1.getIconWidth() + image2.getIconWidth();
int h = Math.max(image1.getIconHeight(), image2.getIconHeight());
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
BufferedImage image = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
Graphics2D g2 = image.createGraphics();
g2.drawImage(image1.getImage(), 0, 0, comp);
g2.drawImage(image2.getImage(), image1.getIconWidth(), 0, comp);
g2.dispose();
g2.drawImage(image1.getImage(), 0, 0, comp);
g2.drawImage(image2.getImage(), image1.getIconWidth(), 0, comp);
g2.dispose();
return image;
return image;
} catch (Exception e) {
Log.warning("Unable to combine two images", e);
return null;
}
}
public static Image returnTransparentImage(int w, int h) {
return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
}
/**
* Creates an Image from the specified Icon
*
@ -107,5 +112,4 @@ public class ImageCombiner {
return image;
}
}
}

View File

@ -136,16 +136,15 @@ public abstract class SwingWorker {
Runnable doConstruct = () -> {
try {
setValue(construct());
setValue(construct());
}
catch ( Exception e ) {
Log.error( e );
catch (Exception e) {
Log.error("SwingWorker exception while async constructing value", e);
}
finally {
threadVar.clear();
}
SwingUtilities.invokeLater(this::finished);
};
Thread t = new Thread(doConstruct);

View File

@ -53,7 +53,7 @@ public class SparkMeetPlugin implements Plugin, ChatRoomListener, GlobalMessageL
private org.jivesoftware.spark.ChatManager chatManager;
private final File pluginsettings = new File( Spark.getLogDirectory().getParentFile() + System.getProperty("file.separator") + "ofmeet.properties");
private final Map<String, ChatRoomDecorator> decorators = new HashMap<>();
private final Map<String, ChatRoomDecorator> decorators = new HashMap<>();
private String electronExePath = null;
private String electronHomePath = null;
private XProcess electronThread = null;
@ -72,7 +72,7 @@ public class SparkMeetPlugin implements Plugin, ChatRoomListener, GlobalMessageL
if (pluginsettings.exists())
{
Log.warning("ofmeet-info: Properties-file does exist= " + pluginsettings.getPath());
Log.debug("ofmeet-info: Properties-file does exist= " + pluginsettings.getPath());
try {
props.load(new FileInputStream(pluginsettings));
@ -439,7 +439,7 @@ public class SparkMeetPlugin implements Plugin, ChatRoomListener, GlobalMessageL
Log.debug("Native lib folder created and natives extracted");
}
else {
Log.warning("Native lib folder already exist.");
Log.debug("Native lib folder already exist.");
}

View File

@ -643,13 +643,17 @@ public class SparkToaster {
}
public void setIcon(Icon icon) {
if (icon.getIconHeight() > 64 || icon.getIconWidth() > 64) {
Image image = ImageCombiner.iconToImage(icon);
label.setIcon(new ImageIcon(image.getScaledInstance(-1, 64,
Image.SCALE_SMOOTH)));
} else {
label.setIcon(icon);
}
try {
if (icon.getIconHeight() > 64 || icon.getIconWidth() > 64) {
Image image = ImageCombiner.iconToImage(icon);
label.setIcon(new ImageIcon(image.getScaledInstance(-1, 64,
Image.SCALE_SMOOTH)));
} else{
label.setIcon(icon);
}
} catch (Exception e) {
Log.warning("Unable to set icon in toaster", e);
}
}
public RolloverButton getCloseButton() {