source: josm/trunk/src/org/openstreetmap/josm/io/MessageNotifier.java@ 14653

Last change on this file since 14653 was 14326, checked in by Don-vip, 6 years ago

fix #4535, fix #16780 - detect changesets closed on server side after 1 hour

  • Property svn:eol-style set to native
File size: 6.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.net.Authenticator.RequestorType;
7import java.util.concurrent.Executors;
8import java.util.concurrent.ScheduledExecutorService;
9import java.util.concurrent.ScheduledFuture;
10import java.util.concurrent.TimeUnit;
11
12import org.openstreetmap.josm.data.UserIdentityManager;
13import org.openstreetmap.josm.data.osm.UserInfo;
14import org.openstreetmap.josm.data.preferences.BooleanProperty;
15import org.openstreetmap.josm.data.preferences.IntegerProperty;
16import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
17import org.openstreetmap.josm.io.auth.CredentialsAgentException;
18import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
19import org.openstreetmap.josm.io.auth.CredentialsManager;
20import org.openstreetmap.josm.io.auth.JosmPreferencesCredentialAgent;
21import org.openstreetmap.josm.spi.preferences.Config;
22import org.openstreetmap.josm.tools.Logging;
23import org.openstreetmap.josm.tools.Utils;
24
25/**
26 * Notifies user periodically of new received (unread) messages
27 * @since 6349
28 */
29public final class MessageNotifier {
30
31 private MessageNotifier() {
32 // Hide default constructor for utils classes
33 }
34
35 /**
36 * Called when new new messages are detected.
37 * @since 12766
38 */
39 @FunctionalInterface
40 public interface NotifierCallback {
41 /**
42 * Perform the actual notification of new messages.
43 * @param userInfo the new user information, that includes the number of unread messages
44 */
45 void notifyNewMessages(UserInfo userInfo);
46 }
47
48 private static volatile NotifierCallback callback;
49
50 /**
51 * Sets the {@link NotifierCallback} responsible of notifying the user when new messages are received.
52 * @param notifierCallback the new {@code NotifierCallback}
53 */
54 public static void setNotifierCallback(NotifierCallback notifierCallback) {
55 callback = notifierCallback;
56 }
57
58 /** Property defining if this task is enabled or not */
59 public static final BooleanProperty PROP_NOTIFIER_ENABLED = new BooleanProperty("message.notifier.enabled", true);
60 /** Property defining the update interval in minutes */
61 public static final IntegerProperty PROP_INTERVAL = new IntegerProperty("message.notifier.interval", 5);
62
63 private static final ScheduledExecutorService EXECUTOR =
64 Executors.newSingleThreadScheduledExecutor(Utils.newThreadFactory("message-notifier-%d", Thread.NORM_PRIORITY));
65
66 private static final Runnable WORKER = new Worker();
67
68 private static volatile ScheduledFuture<?> task;
69
70 private static class Worker implements Runnable {
71
72 private int lastUnreadCount;
73 private long lastTimeInMillis;
74
75 @Override
76 public void run() {
77 try {
78 long currentTime = System.currentTimeMillis();
79 // See #14671 - Make sure we don't run the API call many times after system wakeup
80 if (currentTime >= lastTimeInMillis + TimeUnit.MINUTES.toMillis(PROP_INTERVAL.get())) {
81 lastTimeInMillis = currentTime;
82 final UserInfo userInfo = new OsmServerUserInfoReader().fetchUserInfo(NullProgressMonitor.INSTANCE,
83 tr("get number of unread messages"));
84 final int unread = userInfo.getUnreadMessages();
85 if (unread > 0 && unread != lastUnreadCount) {
86 callback.notifyNewMessages(userInfo);
87 lastUnreadCount = unread;
88 }
89 }
90 } catch (OsmTransferException e) {
91 Logging.warn(e);
92 }
93 }
94 }
95
96 /**
97 * Starts the message notifier task if not already started and if user is fully identified
98 */
99 public static void start() {
100 int interval = PROP_INTERVAL.get();
101 if (NetworkManager.isOffline(OnlineResource.OSM_API)) {
102 Logging.info(tr("{0} not available (offline mode)", tr("Message notifier")));
103 } else if (!isRunning() && interval > 0 && isUserEnoughIdentified()) {
104 task = EXECUTOR.scheduleAtFixedRate(WORKER, 0, interval, TimeUnit.MINUTES);
105 Logging.info("Message notifier active (checks every "+interval+" minute"+(interval > 1 ? "s" : "")+')');
106 }
107 }
108
109 /**
110 * Stops the message notifier task if started
111 */
112 public static void stop() {
113 if (isRunning()) {
114 task.cancel(false);
115 Logging.info("Message notifier inactive");
116 task = null;
117 }
118 }
119
120 /**
121 * Determines if the message notifier is currently running
122 * @return {@code true} if the notifier is running, {@code false} otherwise
123 */
124 public static boolean isRunning() {
125 return task != null;
126 }
127
128 /**
129 * Determines if user set enough information in JOSM preferences to make the request to OSM API without
130 * prompting him for a password.
131 * @return {@code true} if user chose an OAuth token or supplied both its username and password, {@code false otherwise}
132 */
133 public static boolean isUserEnoughIdentified() {
134 UserIdentityManager identManager = UserIdentityManager.getInstance();
135 if (identManager.isFullyIdentified()) {
136 return true;
137 } else {
138 CredentialsManager credManager = CredentialsManager.getInstance();
139 try {
140 if (JosmPreferencesCredentialAgent.class.equals(credManager.getCredentialsAgentClass())) {
141 if (OsmApi.isUsingOAuth()) {
142 return credManager.lookupOAuthAccessToken() != null;
143 } else {
144 String username = Config.getPref().get("osm-server.username", null);
145 String password = Config.getPref().get("osm-server.password", null);
146 return username != null && !username.isEmpty() && password != null && !password.isEmpty();
147 }
148 } else {
149 CredentialsAgentResponse credentials = credManager.getCredentials(
150 RequestorType.SERVER, OsmApi.getOsmApi().getHost(), false);
151 if (credentials != null) {
152 String username = credentials.getUsername();
153 char[] password = credentials.getPassword();
154 return username != null && !username.isEmpty() && password != null && password.length > 0;
155 }
156 }
157 } catch (CredentialsAgentException e) {
158 Logging.log(Logging.LEVEL_WARN, "Unable to get credentials:", e);
159 }
160 }
161 return false;
162 }
163}
Note: See TracBrowser for help on using the repository browser.