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

Last change on this file was 19050, checked in by taylor.smock, 2 days ago

Revert most var changes from r19048, fix most new compile warnings and checkstyle issues

Also, document why various ErrorProne checks were originally disabled and fix
generic SonarLint issues.

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