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

Last change on this file since 16008 was 15251, checked in by Don-vip, 5 years ago

fix #17929 - see #17722 - don't display random network or API issues, just log them

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