diff --git a/src/java/org/jivesoftware/spark/SoundManager.java b/src/java/org/jivesoftware/spark/SoundManager.java index 5adac831..280b6b63 100644 --- a/src/java/org/jivesoftware/spark/SoundManager.java +++ b/src/java/org/jivesoftware/spark/SoundManager.java @@ -11,6 +11,7 @@ package org.jivesoftware.spark; import org.jivesoftware.resource.SoundsRes; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.spark.util.log.Log; import java.applet.Applet; @@ -59,13 +60,20 @@ public class SoundManager { * * @param clip the audioclip to play. */ - public void playClip(AudioClip clip) { - try { - clip.play(); - } - catch (Exception ex) { - System.err.println("Unable to load sound file"); - } + public void playClip(final AudioClip clip) { + + final Runnable playThread = new Runnable() { + public void run() { + try { + clip.play(); + } + catch (Exception ex) { + System.err.println("Unable to load sound file"); + } + } + }; + + TaskEngine.getInstance().submit(playThread); } /** @@ -89,7 +97,7 @@ public class SoundManager { * @param soundFile the File object representing the wav file. */ public void playClip(final File soundFile) { - Thread soundThread = new Thread(new Runnable() { + final Runnable playThread = new Runnable() { public void run() { try { final URL url = soundFile.toURL(); @@ -104,9 +112,9 @@ public class SoundManager { Log.error(e); } } - }); + }; - soundThread.start(); + TaskEngine.getInstance().submit(playThread); } /** diff --git a/src/java/org/jivesoftware/spark/Workspace.java b/src/java/org/jivesoftware/spark/Workspace.java index dd035a74..25e3079b 100644 --- a/src/java/org/jivesoftware/spark/Workspace.java +++ b/src/java/org/jivesoftware/spark/Workspace.java @@ -23,6 +23,7 @@ import org.jivesoftware.smackx.debugger.EnhancedDebuggerWindow; import org.jivesoftware.smackx.packet.DelayInformation; import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPane; import org.jivesoftware.spark.filetransfer.SparkTransferManager; +import org.jivesoftware.spark.phone.PhoneManager; import org.jivesoftware.spark.search.SearchManager; import org.jivesoftware.spark.ui.ChatContainer; import org.jivesoftware.spark.ui.ChatRoom; @@ -32,9 +33,8 @@ import org.jivesoftware.spark.ui.ContactItem; import org.jivesoftware.spark.ui.ContactList; import org.jivesoftware.spark.ui.conferences.ConferencePlugin; import org.jivesoftware.spark.ui.status.StatusBar; -import org.jivesoftware.spark.util.SwingWorker; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.spark.util.log.Log; -import org.jivesoftware.spark.phone.PhoneManager; import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; import org.jivesoftware.sparkimpl.plugin.transcripts.ChatTranscriptPlugin; @@ -45,9 +45,7 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Timer; import java.util.TimerTask; import javax.swing.AbstractAction; @@ -236,32 +234,17 @@ public class Workspace extends JPanel implements PacketListener { final Presence presence = SparkManager.getWorkspace().getStatusBar().getPresence(); SparkManager.getSessionManager().changePresence(presence); - // Load Plugins - SwingWorker worker = new SwingWorker() { - public Object construct() { - try { - Thread.sleep(2000); - } - catch (InterruptedException e) { - Log.error("Unable to sleep thread.", e); - } - return "ok"; - } - - public void finished() { + // Schedule loading of the plugins after two seconds. + TaskEngine.getInstance().schedule(new TimerTask() { + public void run() { final PluginManager pluginManager = PluginManager.getInstance(); pluginManager.loadPlugins(); pluginManager.initializePlugins(); } - }; - worker.start(); + }, 2000); - - int numberOfMillisecondsInTheFuture = 10000; // 5 sec - Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture); - Timer timer = new Timer(); - - timer.schedule(new TimerTask() { + // Load the offline messages after 10 seconds. + TaskEngine.getInstance().schedule(new TimerTask() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { @@ -273,7 +256,7 @@ public class Workspace extends JPanel implements PacketListener { } }); } - }, timeToRun); + }, 10000); } diff --git a/src/java/org/jivesoftware/spark/ui/ContactItem.java b/src/java/org/jivesoftware/spark/ui/ContactItem.java index 129a8169..216f6659 100644 --- a/src/java/org/jivesoftware/spark/ui/ContactItem.java +++ b/src/java/org/jivesoftware/spark/ui/ContactItem.java @@ -23,6 +23,7 @@ import org.jivesoftware.spark.PresenceManager; import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.util.GraphicUtils; import org.jivesoftware.spark.util.ModelUtil; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.profile.VCardManager; @@ -295,7 +296,7 @@ public class ContactItem extends JPanel { * @param hash the new hash. */ private void updateAvatar(final String hash) { - Thread updateAvatarThread = new Thread(new Runnable() { + Runnable updateRunnable = new Runnable() { public void run() { contactsDir.mkdirs(); @@ -318,9 +319,9 @@ public class ContactItem extends JPanel { Log.error("Unable to update avatar in Contact Item.", e); } } - }); + }; - updateAvatarThread.start(); + TaskEngine.getInstance().submit(updateRunnable); } public String toString() { diff --git a/src/java/org/jivesoftware/spark/util/TaskEngine.java b/src/java/org/jivesoftware/spark/util/TaskEngine.java new file mode 100644 index 00000000..a9de0dd5 --- /dev/null +++ b/src/java/org/jivesoftware/spark/util/TaskEngine.java @@ -0,0 +1,307 @@ +/** + * $Revision: 4005 $ + * $Date: 2006-06-16 08:58:27 -0700 (Fri, 16 Jun 2006) $ + * + * Copyright (C) 2006 Jive Software. All rights reserved. + * + * This software is published under the terms of the GNU Public License (GPL), + * a copy of which is included in this distribution. + */ + +package org.jivesoftware.spark.util; + +import java.util.Date; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Performs tasks using worker threads. It also allows tasks to be scheduled to be + * run at future dates. This class mimics relevant methods in both + * {@link ExecutorService} and {@link Timer}. Any {@link TimerTask} that's + * scheduled to be run in the future will automatically be run using the thread + * executor's thread pool. This means that the standard restriction that TimerTasks + * should run quickly does not apply. + * + * @author Matt Tucker + */ +public class TaskEngine { + + private static TaskEngine instance = new TaskEngine(); + + /** + * Returns a task engine instance (singleton). + * + * @return a task engine. + */ + public static TaskEngine getInstance() { + return instance; + } + + private Timer timer; + private ExecutorService executor; + private Map wrappedTasks = new ConcurrentHashMap(); + + /** + * Constructs a new task engine. + */ + private TaskEngine() { + timer = new Timer("timer-spark", true); + executor = Executors.newCachedThreadPool(new ThreadFactory() { + + final AtomicInteger threadNumber = new AtomicInteger(1); + + public Thread newThread(Runnable runnable) { + // Use our own naming scheme for the threads. + Thread thread = new Thread(Thread.currentThread().getThreadGroup(), runnable, + "pool-spark" + threadNumber.getAndIncrement(), 0); + // Make workers daemon threads. + thread.setDaemon(true); + if (thread.getPriority() != Thread.NORM_PRIORITY) { + thread.setPriority(Thread.NORM_PRIORITY); + } + return thread; + } + }); + } + + /** + * Submits a Runnable task for execution and returns a Future + * representing that task. + * + * @param task the task to submit. + * @return a Future representing pending completion of the task, + * and whose get() method will return null + * upon completion. + * @throws java.util.concurrent.RejectedExecutionException + * if task cannot be scheduled + * for execution. + * @throws NullPointerException if task null. + */ + public Future submit(Runnable task) { + return executor.submit(task); + } + + + /** + * Schedules the specified task for execution after the specified delay. + * + * @param task task to be scheduled. + * @param delay delay in milliseconds before task is to be executed. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, or timer was cancelled. + */ + public void schedule(TimerTask task, long delay) { + timer.schedule(new TimerTaskWrapper(task), delay); + } + + /** + * Schedules the specified task for execution at the specified time. If + * the time is in the past, the task is scheduled for immediate execution. + * + * @param task task to be scheduled. + * @param time time at which task is to be executed. + * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, timer was cancelled, or timer thread terminated. + */ + public void schedule(TimerTask task, Date time) { + timer.schedule(new TimerTaskWrapper(task), time); + } + + /** + * Schedules the specified task for repeated fixed-delay execution, + * beginning after the specified delay. Subsequent executions take place + * at approximately regular intervals separated by the specified period. + *

+ *

In fixed-delay execution, each execution is scheduled relative to + * the actual execution time of the previous execution. If an execution + * is delayed for any reason (such as garbage collection or other + * background activity), subsequent executions will be delayed as well. + * In the long run, the frequency of execution will generally be slightly + * lower than the reciprocal of the specified period (assuming the system + * clock underlying Object.wait(long) is accurate). + *

+ *

Fixed-delay execution is appropriate for recurring activities + * that require "smoothness." In other words, it is appropriate for + * activities where it is more important to keep the frequency accurate + * in the short run than in the long run. This includes most animation + * tasks, such as blinking a cursor at regular intervals. It also includes + * tasks wherein regular activity is performed in response to human + * input, such as automatically repeating a character as long as a key + * is held down. + * + * @param task task to be scheduled. + * @param delay delay in milliseconds before task is to be executed. + * @param period time in milliseconds between successive task executions. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, timer was cancelled, or timer thread terminated. + */ + public void schedule(TimerTask task, long delay, long period) { + TimerTaskWrapper taskWrapper = new TimerTaskWrapper(task); + wrappedTasks.put(task, taskWrapper); + timer.schedule(taskWrapper, delay, period); + } + + /** + * Schedules the specified task for repeated fixed-delay execution, + * beginning at the specified time. Subsequent executions take place at + * approximately regular intervals, separated by the specified period. + *

+ *

In fixed-delay execution, each execution is scheduled relative to + * the actual execution time of the previous execution. If an execution + * is delayed for any reason (such as garbage collection or other + * background activity), subsequent executions will be delayed as well. + * In the long run, the frequency of execution will generally be slightly + * lower than the reciprocal of the specified period (assuming the system + * clock underlying Object.wait(long) is accurate). + *

+ *

Fixed-delay execution is appropriate for recurring activities + * that require "smoothness." In other words, it is appropriate for + * activities where it is more important to keep the frequency accurate + * in the short run than in the long run. This includes most animation + * tasks, such as blinking a cursor at regular intervals. It also includes + * tasks wherein regular activity is performed in response to human + * input, such as automatically repeating a character as long as a key + * is held down. + * + * @param task task to be scheduled. + * @param firstTime First time at which task is to be executed. + * @param period time in milliseconds between successive task executions. + * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, timer was cancelled, or timer thread terminated. + */ + public void schedule(TimerTask task, Date firstTime, long period) { + TimerTaskWrapper taskWrapper = new TimerTaskWrapper(task); + wrappedTasks.put(task, taskWrapper); + timer.schedule(taskWrapper, firstTime, period); + } + + /** + * Schedules the specified task for repeated fixed-rate execution, + * beginning after the specified delay. Subsequent executions take place + * at approximately regular intervals, separated by the specified period. + *

+ *

In fixed-rate execution, each execution is scheduled relative to the + * scheduled execution time of the initial execution. If an execution is + * delayed for any reason (such as garbage collection or other background + * activity), two or more executions will occur in rapid succession to + * "catch up." In the long run, the frequency of execution will be + * exactly the reciprocal of the specified period (assuming the system + * clock underlying Object.wait(long) is accurate). + *

+ *

Fixed-rate execution is appropriate for recurring activities that + * are sensitive to absolute time, such as ringing a chime every + * hour on the hour, or running scheduled maintenance every day at a + * particular time. It is also appropriate for recurring activities + * where the total time to perform a fixed number of executions is + * important, such as a countdown timer that ticks once every second for + * ten seconds. Finally, fixed-rate execution is appropriate for + * scheduling multiple repeating timer tasks that must remain synchronized + * with respect to one another. + * + * @param task task to be scheduled. + * @param delay delay in milliseconds before task is to be executed. + * @param period time in milliseconds between successive task executions. + * @throws IllegalArgumentException if delay is negative, or + * delay + System.currentTimeMillis() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, timer was cancelled, or timer thread terminated. + */ + public void scheduleAtFixedRate(TimerTask task, long delay, long period) { + TimerTaskWrapper taskWrapper = new TimerTaskWrapper(task); + wrappedTasks.put(task, taskWrapper); + timer.scheduleAtFixedRate(taskWrapper, delay, period); + } + + /** + * Schedules the specified task for repeated fixed-rate execution, + * beginning at the specified time. Subsequent executions take place at + * approximately regular intervals, separated by the specified period. + *

+ *

In fixed-rate execution, each execution is scheduled relative to the + * scheduled execution time of the initial execution. If an execution is + * delayed for any reason (such as garbage collection or other background + * activity), two or more executions will occur in rapid succession to + * "catch up." In the long run, the frequency of execution will be + * exactly the reciprocal of the specified period (assuming the system + * clock underlying Object.wait(long) is accurate). + *

+ *

Fixed-rate execution is appropriate for recurring activities that + * are sensitive to absolute time, such as ringing a chime every + * hour on the hour, or running scheduled maintenance every day at a + * particular time. It is also appropriate for recurring activities + * where the total time to perform a fixed number of executions is + * important, such as a countdown timer that ticks once every second for + * ten seconds. Finally, fixed-rate execution is appropriate for + * scheduling multiple repeating timer tasks that must remain synchronized + * with respect to one another. + * + * @param task task to be scheduled. + * @param firstTime First time at which task is to be executed. + * @param period time in milliseconds between successive task executions. + * @throws IllegalArgumentException if time.getTime() is negative. + * @throws IllegalStateException if task was already scheduled or + * cancelled, timer was cancelled, or timer thread terminated. + */ + public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) { + TimerTaskWrapper taskWrapper = new TimerTaskWrapper(task); + wrappedTasks.put(task, taskWrapper); + timer.scheduleAtFixedRate(taskWrapper, firstTime, period); + } + + /** + * Cancels the execution of a scheduled task. {@link java.util.TimerTask#cancel()} + * + * @param task the scheduled task to cancel. + */ + public void cancelScheduledTask(TimerTask task) { + TaskEngine.TimerTaskWrapper taskWrapper = wrappedTasks.remove(task); + if (taskWrapper != null) { + taskWrapper.cancel(); + } + } + + /** + * Shuts down the task engine service. + */ + public void shutdown() { + if (executor != null) { + executor.shutdownNow(); + executor = null; + } + + if (timer != null) { + timer.cancel(); + timer = null; + } + } + + /** + * Wrapper class for a standard TimerTask. It simply executes the TimerTask + * using the executor's thread pool. + */ + private class TimerTaskWrapper extends TimerTask { + + private TimerTask task; + + public TimerTaskWrapper(TimerTask task) { + this.task = task; + } + + public void run() { + executor.submit(task); + } + } +} \ No newline at end of file diff --git a/src/java/org/jivesoftware/sparkimpl/plugin/gateways/transports/TransportUtils.java b/src/java/org/jivesoftware/sparkimpl/plugin/gateways/transports/TransportUtils.java index 9dcd3e6e..6f91d0e5 100644 --- a/src/java/org/jivesoftware/sparkimpl/plugin/gateways/transports/TransportUtils.java +++ b/src/java/org/jivesoftware/sparkimpl/plugin/gateways/transports/TransportUtils.java @@ -23,6 +23,7 @@ import org.jivesoftware.smackx.ServiceDiscoveryManager; import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.spark.SparkManager; import org.jivesoftware.spark.util.log.Log; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.sparkimpl.plugin.gateways.GatewayPrivateData; import java.util.Collection; @@ -43,13 +44,19 @@ public class TransportUtils { static { PrivateDataManager.addPrivateDataProvider(GatewayPrivateData.ELEMENT, GatewayPrivateData.NAMESPACE, new GatewayPrivateData.ConferencePrivateDataProvider()); - PrivateDataManager pdm = SparkManager.getSessionManager().getPersonalDataManager(); - try { - gatewayPreferences = (GatewayPrivateData)pdm.getPrivateData(GatewayPrivateData.ELEMENT, GatewayPrivateData.NAMESPACE); - } - catch (XMPPException e) { - Log.error("Unable to load private data for Gateways", e); - } + final Runnable loadGateways = new Runnable() { + public void run() { + try { + PrivateDataManager pdm = SparkManager.getSessionManager().getPersonalDataManager(); + gatewayPreferences = (GatewayPrivateData)pdm.getPrivateData(GatewayPrivateData.ELEMENT, GatewayPrivateData.NAMESPACE); + } + catch (XMPPException e) { + Log.error("Unable to load private data for Gateways", e); + } + } + }; + + TaskEngine.getInstance().submit(loadGateways); } public static boolean autoJoinService(String serviceName) { @@ -178,7 +185,7 @@ public class TransportUtils { public String toXML() { StringBuilder builder = new StringBuilder(); builder.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( - "\"/>"); + "\"/>"); return builder.toString(); } } diff --git a/src/java/org/jivesoftware/sparkimpl/plugin/phone/PhonePlugin.java b/src/java/org/jivesoftware/sparkimpl/plugin/phone/PhonePlugin.java index e5ba1c02..37d407ff 100644 --- a/src/java/org/jivesoftware/sparkimpl/plugin/phone/PhonePlugin.java +++ b/src/java/org/jivesoftware/sparkimpl/plugin/phone/PhonePlugin.java @@ -35,9 +35,16 @@ import org.jivesoftware.spark.ui.rooms.ChatRoomImpl; import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.plugin.alerts.SparkToaster; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFrame; @@ -45,12 +52,6 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseEvent; - public class PhonePlugin implements Plugin { public static PhoneClient phoneClient; private DialPanel dialPanel; @@ -260,7 +261,7 @@ public class PhonePlugin implements Plugin { } public void callExtension(final String number) { - Thread thread = new Thread(new Runnable() { + final Runnable caller = new Runnable() { public void run() { try { phoneClient.dialByExtension(number); @@ -269,13 +270,13 @@ public class PhonePlugin implements Plugin { Log.error(e); } } - }); + }; - thread.start(); + TaskEngine.getInstance().submit(caller); } public void callJID(final String jid) { - Thread thread = new Thread(new Runnable() { + final Runnable caller = new Runnable() { public void run() { try { phoneClient.dialByJID(jid); @@ -284,11 +285,9 @@ public class PhonePlugin implements Plugin { Log.error(e); } } - }); - - thread.start(); - - + }; + + TaskEngine.getInstance().submit(caller); } diff --git a/src/java/org/jivesoftware/sparkimpl/preference/sounds/SoundPlugin.java b/src/java/org/jivesoftware/sparkimpl/preference/sounds/SoundPlugin.java index 0672a56a..8d99bb13 100644 --- a/src/java/org/jivesoftware/sparkimpl/preference/sounds/SoundPlugin.java +++ b/src/java/org/jivesoftware/sparkimpl/preference/sounds/SoundPlugin.java @@ -25,6 +25,7 @@ import org.jivesoftware.spark.plugin.Plugin; import org.jivesoftware.spark.ui.ChatRoom; import org.jivesoftware.spark.ui.ChatRoomListener; import org.jivesoftware.spark.ui.MessageListener; +import org.jivesoftware.spark.util.TaskEngine; import java.io.File; @@ -53,13 +54,14 @@ public class SoundPlugin implements Plugin, MessageListener, ChatRoomListener { } }, new PacketTypeFilter(Presence.class)); - Thread thread = new Thread(new Runnable() { + // Load sound preferences. + final Runnable soundLoader = new Runnable() { public void run() { soundPreference.loadFromFile(); } - }); - thread.start(); + }; + TaskEngine.getInstance().submit(soundLoader); MultiUserChat.addInvitationListener(SparkManager.getConnection(), new InvitationListener() { public void invitationReceived(XMPPConnection xmppConnection, String string, String string1, String string2, String string3, Message message) { diff --git a/src/java/org/jivesoftware/sparkimpl/profile/VCardManager.java b/src/java/org/jivesoftware/sparkimpl/profile/VCardManager.java index d1bcc228..f1cda243 100644 --- a/src/java/org/jivesoftware/sparkimpl/profile/VCardManager.java +++ b/src/java/org/jivesoftware/sparkimpl/profile/VCardManager.java @@ -30,6 +30,7 @@ import org.jivesoftware.spark.util.GraphicUtils; import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; +import org.jivesoftware.spark.util.TaskEngine; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; import org.jivesoftware.sparkimpl.profile.ext.JabberAvatarExtension; @@ -38,13 +39,6 @@ import org.xmlpull.mxp1.MXParser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import javax.imageio.ImageIO; -import javax.swing.ImageIcon; -import javax.swing.JComponent; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; - import java.awt.Image; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -63,6 +57,13 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; + /** * VCardManager handles all VCard loading/caching within Spark. * @@ -154,7 +155,7 @@ public class VCardManager { * Listens for new VCards to lookup in a queue. */ private void startQueueListener() { - final Thread thread = new Thread(new Runnable() { + final Runnable queueListener = new Runnable() { public void run() { while (true) { try { @@ -165,10 +166,10 @@ public class VCardManager { e.printStackTrace(); } } - } - }); - thread.start(); + }; + + TaskEngine.getInstance().submit(queueListener); } /** @@ -449,7 +450,7 @@ public class VCardManager { vcard.setError(new XMPPError(409)); vcards.put(jid, vcard); } - + // Persist XML persistVCard(jid, vcard); @@ -537,8 +538,8 @@ public class VCardManager { String query = getNumbersFromPhone(phoneNumber); if ((homePhone != null && homePhone.contains(query)) || - (workPhone != null && workPhone.contains(query)) || - (cellPhone != null && cellPhone.contains(query))) { + (workPhone != null && workPhone.contains(query)) || + (cellPhone != null && cellPhone.contains(query))) { return vcard; } }