From e453ed27571e7acf16657ad9d7172fb87dc3468c Mon Sep 17 00:00:00 2001 From: Evgeny Gryaznov Date: Sun, 17 Jan 2010 21:15:31 +0000 Subject: [PATCH] add MibewAgent, offline/online icon git-svn-id: https://webim.svn.sourceforge.net/svnroot/webim/trunk@732 c66351dc-e62f-0410-b875-e3a5c0b9693f --- .../src/org/mibew/api/MibewAgent.java | 143 ++++++++++++++++++ .../src/org/mibew/api/MibewAgentListener.java | 10 ++ .../src/org/mibew/api/MibewAgentOptions.java | 40 +++++ .../src/org/mibew/api/MibewTracker.java | 62 ++++---- .../src/org/mibew/jabber/Application.java | 2 +- .../src/org/mibew/notifier/ConsoleApp.java | 24 +++ .../src/org/mibew/notifier/NotifyApp.java | 6 + .../src/org/mibew/notifier/TrayNotifier.java | 31 +++- .../src/org/mibew/notifier/tray_off.png | Bin 0 -> 2166 bytes .../mibew/notifier/{tray.png => tray_on.png} | Bin 10 files changed, 281 insertions(+), 37 deletions(-) create mode 100644 src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java create mode 100644 src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java create mode 100644 src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java create mode 100644 src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java create mode 100644 src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png rename src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/{tray.png => tray_on.png} (100%) diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java new file mode 100644 index 00000000..5a8de298 --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgent.java @@ -0,0 +1,143 @@ +package org.mibew.api; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.security.NoSuchAlgorithmException; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; + +/** + * @author inspirer + */ +public class MibewAgent { + + private final MibewAgentOptions fOptions; + private final MibewAgentListener fListener; + private final MibewUpdateThread fThread; + private volatile boolean started; + + public MibewAgent(MibewAgentOptions options, MibewAgentListener listener) { + fOptions = options; + fListener = listener; + fThread = new MibewUpdateThread(); + started = false; + } + + public synchronized void launch() { + if(!started) { + fThread.start(); + started = true; + } + } + + public synchronized void stop() { + if(started) { + fThread.disconnect(); + started = false; + } + } + + public boolean isOnline() { + return fThread.isOnline(); + } + + private void logError(String message, Throwable th) { + System.err.println(message); + } + + private class MibewUpdateThread extends Thread { + + private volatile boolean fExiting; + private volatile boolean isOnline = false; + private final Object fSync = new Object(); + + public MibewUpdateThread() { + setName("Mibew Connection thread"); + fExiting = false; + } + + public void disconnect() { + synchronized (fSync) { + fExiting = true; + fSync.notifyAll(); + } + } + + @Override + public void run() { + while(!fExiting) { + try { + connectAndTrack(); + } catch(InterruptedException ex) { + /* ignore */ + } catch(Throwable th) { + logError(th.getMessage(), th); + } + } + setOnline(false); + } + + private void setOnline(boolean online) { + if(isOnline != online) { + isOnline = online; + fListener.onlineStateChanged(online); + } + } + + public boolean isOnline() { + return isOnline; + } + + private void connectAndTrack() throws InterruptedException, UnsupportedEncodingException, NoSuchAlgorithmException, MalformedURLException, ParserConfigurationException, SAXException { + setOnline(false); + MibewConnection conn = new MibewConnection(fOptions.getUrl(), fOptions.getLogin(), fOptions.getPassword()) { + @Override + protected void handleError(String message, Exception ex) { + logError(message, ex); + } + }; + if(!conn.connect()) { + logError("Wrong server, login or password.", null); + interruptableSleep(fOptions.getPollingInterval() * 3); + return; + } + final List createdThreads = new LinkedList(); + MibewTracker mt = new MibewTracker(conn, new MibewTrackerListener(){ + @Override + public void threadCreated(MibewThread thread) { + createdThreads.add(thread); + } + }); + long maxTime = System.currentTimeMillis() + fOptions.getConnectionRefreshTimeout()*1000; + + while(!fExiting && (System.currentTimeMillis() < maxTime)) { + try { + createdThreads.clear(); + mt.update(); + fListener.updated(mt.getThreads(), createdThreads.toArray(new MibewThread[createdThreads.size()])); + } catch (Exception e) { + setOnline(false); + interruptableSleep(fOptions.getPollingInterval() / 2); + continue; + } + setOnline(true); + interruptableSleep(fOptions.getPollingInterval()); + } + + conn.disconnect(); + } + + private void interruptableSleep(long millis) throws InterruptedException { + synchronized (fSync ) { + if(fExiting) { + return; + } + fSync.wait(millis); + } + } + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java new file mode 100644 index 00000000..78df236e --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentListener.java @@ -0,0 +1,10 @@ +package org.mibew.api; + +public abstract class MibewAgentListener { + + protected void onlineStateChanged(boolean isOnline) { + } + + protected void updated(MibewThread[] all, MibewThread[] created) { + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java new file mode 100644 index 00000000..ecea7a04 --- /dev/null +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewAgentOptions.java @@ -0,0 +1,40 @@ +package org.mibew.api; + +/** + * @author inspirer + */ +public class MibewAgentOptions { + + private String fUrl; + private String fLogin; + private String fPassword; + private int fConnectionRefreshTimeout = 900; // 15 minutes + private int fPollingInterval = 3000; // 2 sec + + public MibewAgentOptions(String fUrl, String fLogin, String fPassword) { + super(); + this.fUrl = fUrl; + this.fLogin = fLogin; + this.fPassword = fPassword; + } + + public String getLogin() { + return fLogin; + } + + public String getPassword() { + return fPassword; + } + + public String getUrl() { + return fUrl; + } + + public int getConnectionRefreshTimeout() { + return fConnectionRefreshTimeout; + } + + public int getPollingInterval() { + return fPollingInterval; + } +} diff --git a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java index 96aa3188..6a391ad1 100644 --- a/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java +++ b/src/mibewjava/org.mibew.api/src/org/mibew/api/MibewTracker.java @@ -1,75 +1,70 @@ package org.mibew.api; import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.mibew.api.handlers.UpdateHandler; +import org.xml.sax.SAXException; /** - * @author inspirer + * @author inspirer */ public class MibewTracker { - + private final MibewConnection fConnection; private final MibewTrackerListener fListener; private long fSince = 0; private long fLastUpdate = 0; - - private final Map fThreads; + + private final Map fThreads; public MibewTracker(MibewConnection conn, MibewTrackerListener listener) { this.fConnection = conn; this.fListener = listener; this.fThreads = new HashMap(); } - - public void track() throws InterruptedException { - for(int i = 0; i < 5; i++) { - try { - MibewResponse response = fConnection.request("operator/update.php", "since="+fSince); - SAXParser sp = SAXParserFactory.newInstance().newSAXParser(); - UpdateHandler handler = new UpdateHandler(); - sp.parse(new ByteArrayInputStream(response.getResponse()), handler); - handleResponse(response, handler); - } catch(Exception e) { - System.err.println("update exception: " + e.getMessage()); - } - Thread.sleep(1000); - } + + public void update() throws IOException, SAXException, ParserConfigurationException { + MibewResponse response = fConnection.request("operator/update.php", "since=" + fSince); + SAXParser sp = SAXParserFactory.newInstance().newSAXParser(); + UpdateHandler handler = new UpdateHandler(); + sp.parse(new ByteArrayInputStream(response.getResponse()), handler); + handleResponse(response, handler); } - private void handleResponse(MibewResponse response, UpdateHandler handler) { - if(handler.getResponse() == UpdateHandler.UPD_ERROR) { - System.out.println("Update error: " + handler.getMessage()); - } else if(handler.getResponse() == UpdateHandler.UPD_THREADS) { - System.out.println("Updated.... " + handler.getRevision()); + private void handleResponse(MibewResponse response, UpdateHandler handler) throws IOException { + if (handler.getResponse() == UpdateHandler.UPD_ERROR) { + throw new IOException("Update error: " + handler.getMessage()); + } else if (handler.getResponse() == UpdateHandler.UPD_THREADS) { fSince = handler.getRevision(); fLastUpdate = handler.getTime(); List threads = handler.getThreads(); - if(threads != null && threads.size() > 0) { + if (threads != null && threads.size() > 0) { processUpdate(threads); } } else { - System.out.println("Update error"); - System.out.println(response.getResponseText()); + throw new IOException("Update error: " + response.getResponseText()); } } - + private void processUpdate(List updated) { - for(MibewThread mt : updated) { + for (MibewThread mt : updated) { MibewThread existing = fThreads.get(mt.fId); boolean isClosed = mt.fState.equals("closed"); - if(existing == null) { - if(!isClosed) { + if (existing == null) { + if (!isClosed) { fThreads.put(mt.fId, mt); fListener.threadCreated(mt); } - } else if(isClosed) { + } else if (isClosed) { fThreads.remove(mt.fId); fListener.threadClosed(existing); } else { @@ -82,4 +77,9 @@ public class MibewTracker { public long getLastUpdate() { return fLastUpdate; } + + public MibewThread[] getThreads() { + Collection values = fThreads.values(); + return values.toArray(new MibewThread[values.size()]); + } } diff --git a/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java b/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java index 4ba649b1..072ab3c1 100644 --- a/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java +++ b/src/mibewjava/org.mibew.jabber/src/org/mibew/jabber/Application.java @@ -56,7 +56,7 @@ public class Application { } }); - mt.track(); + //mt.track(); connection.disconnect(); } diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java new file mode 100644 index 00000000..ec0d85dd --- /dev/null +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/ConsoleApp.java @@ -0,0 +1,24 @@ +package org.mibew.notifier; + +import org.mibew.api.MibewAgent; +import org.mibew.api.MibewAgentListener; +import org.mibew.api.MibewAgentOptions; + +public class ConsoleApp { + + public static void main(String[] args) { + MibewAgent agent = new MibewAgent(new MibewAgentOptions("http://localhost:8080/webim/", "admin", "1"), new MibewAgentListener() { + @Override + protected void onlineStateChanged(boolean isOnline) { + System.out.println("now " + (isOnline ? "online" : "offline")); + } + }); + agent.launch(); + try { + Thread.sleep(3500); + } catch (InterruptedException e) { + } + + agent.stop(); + } +} diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java index 142e0526..2c914609 100644 --- a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/NotifyApp.java @@ -1,11 +1,17 @@ package org.mibew.notifier; +import org.mibew.api.MibewAgent; +import org.mibew.api.MibewAgentOptions; + public class NotifyApp { public static void main(String[] args) { TrayNotifier tn = new TrayNotifier(); tn.init(); + MibewAgent agent = new MibewAgent(new MibewAgentOptions("http://localhost:8080/webim/", "admin", "1"), tn); + agent.launch(); + tn.setAgent(agent); } } diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/TrayNotifier.java b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/TrayNotifier.java index 1548744b..85a92368 100644 --- a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/TrayNotifier.java +++ b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/TrayNotifier.java @@ -13,9 +13,17 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.net.URL; -public class TrayNotifier { +import org.mibew.api.MibewAgent; +import org.mibew.api.MibewAgentListener; +import org.mibew.api.MibewThread; + +public class TrayNotifier extends MibewAgentListener { private TrayIcon trayIcon; + private MibewAgent agent; + + private Image online; + private Image offline; public TrayNotifier() { } @@ -24,19 +32,22 @@ public class TrayNotifier { if (SystemTray.isSupported()) { SystemTray tray = SystemTray.getSystemTray(); - URL url = this.getClass().getResource("tray.png"); - Image image = Toolkit.getDefaultToolkit().getImage(url); + online = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("tray_on.png")); + offline = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("tray_off.png")); PopupMenu popup = new PopupMenu(); MenuItem exitItem = new MenuItem("Exit", new MenuShortcut(KeyEvent.VK_X)); exitItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + if(agent != null) { + agent.stop(); + } System.exit(0); } }); popup.add(exitItem); - trayIcon = new TrayIcon(image, "Mibew Notifier", popup); + trayIcon = new TrayIcon(offline, "Mibew Notifier", popup); trayIcon.setImageAutoSize(true); try { @@ -50,7 +61,17 @@ public class TrayNotifier { System.exit(1); } } + + @Override + protected void onlineStateChanged(boolean isOnline) { + trayIcon.setImage(isOnline ? online : offline); + } + + @Override + protected void updated(MibewThread[] all, MibewThread[] created) { + } - public void setStatus(boolean online) { + public void setAgent(MibewAgent agent) { + this.agent = agent; } } diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_off.png new file mode 100644 index 0000000000000000000000000000000000000000..daf8251b3e8b8782da5d0af64b2b57452893fd84 GIT binary patch literal 2166 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 literal 0 HcmV?d00001 diff --git a/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray.png b/src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_on.png similarity index 100% rename from src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray.png rename to src/mibewjava/org.mibew.notifier/src/org/mibew/notifier/tray_on.png