Repository navigation
Expand file tree
/
Copy pathOnDisconnect.java
More file actions
261 lines (236 loc) · 10.7 KB
/
Copy pathOnDisconnect.java
File metadata and controls
261 lines (236 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.database;
import com.google.api.core.ApiFuture;
import com.google.firebase.database.DatabaseReference.CompletionListener;
import com.google.firebase.database.core.Path;
import com.google.firebase.database.core.Repo;
import com.google.firebase.database.core.ValidationPath;
import com.google.firebase.database.snapshot.Node;
import com.google.firebase.database.snapshot.NodeUtilities;
import com.google.firebase.database.snapshot.PriorityUtilities;
import com.google.firebase.database.utilities.Pair;
import com.google.firebase.database.utilities.Utilities;
import com.google.firebase.database.utilities.Validation;
import com.google.firebase.database.utilities.encoding.CustomClassMapper;
import java.util.Map;
/**
* The OnDisconnect class is used to manage operations that will be run on the server when this
* client disconnects. It can be used to add or remove data based on a client's connection status.
* It is very useful in applications looking for 'presence' functionality. <br>
* <br>
* Instances of this class are obtained by calling {@link DatabaseReference#onDisconnect()
* onDisconnect} on a Firebase Database ref.
*/
@SuppressWarnings("rawtypes")
public class OnDisconnect {
private Repo repo;
private Path path;
OnDisconnect(Repo repo, Path path) {
this.repo = repo;
this.path = path;
}
/**
* Ensure the data at this location is set to the specified value when the client is disconnected
* (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void setValue(Object value, CompletionListener listener) {
onDisconnectSetInternal(value, PriorityUtilities.NullPriority(), listener);
}
/**
* Ensure the data at this location is set to the specified value and priority when the client is
* disconnected (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param priority The priority to be set when a disconnect occurs
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void setValue(Object value, String priority, CompletionListener listener) {
onDisconnectSetInternal(value, PriorityUtilities.parsePriority(path, priority), listener);
}
/**
* Ensure the data at this location is set to the specified value and priority when the client is
* disconnected (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param priority The priority to be set when a disconnect occurs
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void setValue(Object value, double priority, CompletionListener listener) {
onDisconnectSetInternal(value, PriorityUtilities.parsePriority(path, priority), listener);
}
/**
* Ensure the data at this location is set to the specified value and priority when the client is
* disconnected (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param priority The priority to be set when a disconnect occurs
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void setValue(Object value, Map priority, CompletionListener listener) {
onDisconnectSetInternal(value, PriorityUtilities.parsePriority(path, priority), listener);
}
/**
* Ensure the data at this location is set to the specified value when the client is disconnected
* (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> setValueAsync(Object value) {
return onDisconnectSetInternal(value, PriorityUtilities.NullPriority(), null);
}
/**
* Ensure the data at this location is set to the specified value and priority when the client is
* disconnected (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param priority The priority to be set when a disconnect occurs
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> setValueAsync(Object value, String priority) {
return onDisconnectSetInternal(value, PriorityUtilities.parsePriority(path, priority), null);
}
/**
* Ensure the data at this location is set to the specified value and priority when the client is
* disconnected (due to closing the browser, navigating to a new page, or network issues). <br>
* <br>
* This method is especially useful for implementing "presence" systems, where a value should be
* changed or cleared when a user disconnects so that they appear "offline" to other users.
*
* @param value The value to be set when a disconnect occurs
* @param priority The priority to be set when a disconnect occurs
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> setValueAsync(Object value, double priority) {
return onDisconnectSetInternal(value, PriorityUtilities.parsePriority(path, priority), null);
}
private ApiFuture<Void> onDisconnectSetInternal(
Object value, Node priority, final CompletionListener optListener) {
Validation.validateWritablePath(path);
ValidationPath.validateWithObject(path, value);
Object bouncedValue = CustomClassMapper.convertToPlainJavaTypes(value);
Validation.validateWritableObject(bouncedValue);
final Node node = NodeUtilities.NodeFromJSON(bouncedValue, priority);
final Pair<ApiFuture<Void>, CompletionListener> wrapped = Utilities.wrapOnComplete(optListener);
repo.scheduleNow(
new Runnable() {
@Override
public void run() {
repo.onDisconnectSetValue(path, node, wrapped.getSecond());
}
});
return wrapped.getFirst();
}
// Update
/**
* Ensure the data has the specified child values updated when the client is disconnected
*
* @param update The paths to update, along with their desired values
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void updateChildren(final Map<String, Object> update, final CompletionListener listener) {
updateChildrenInternal(update, listener);
}
/**
* Ensure the data has the specified child values updated when the client is disconnected
*
* @param update The paths to update, along with their desired values
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> updateChildrenAsync(Map<String, Object> update) {
return updateChildrenInternal(update, null);
}
private ApiFuture<Void> updateChildrenInternal(
final Map<String, Object> update, final CompletionListener optListener) {
final Map<Path, Node> parsedUpdate = Validation.parseAndValidateUpdate(path, update);
final Pair<ApiFuture<Void>, CompletionListener> wrapped = Utilities.wrapOnComplete(optListener);
repo.scheduleNow(
new Runnable() {
@Override
public void run() {
repo.onDisconnectUpdate(path, parsedUpdate, wrapped.getSecond(), update);
}
});
return wrapped.getFirst();
}
// Remove
/**
* Remove the value at this location when the client disconnects
*
* @param listener A listener that will be triggered once the server has queued up the operation
*/
public void removeValue(CompletionListener listener) {
setValue(null, listener);
}
/**
* Remove the value at this location when the client disconnects
*
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> removeValueAsync() {
return setValueAsync(null);
}
// Cancel the operation
/**
* Cancel any disconnect operations that are queued up at this location
*
* @param listener A listener that will be triggered once the server has cancelled the operations
*/
public void cancel(final CompletionListener listener) {
cancelInternal(listener);
}
/**
* Cancel any disconnect operations that are queued up at this location
*
* @return The ApiFuture for this operation.
*/
public ApiFuture<Void> cancelAsync() {
return cancelInternal(null);
}
private ApiFuture<Void> cancelInternal(final CompletionListener optListener) {
final Pair<ApiFuture<Void>, CompletionListener> wrapped = Utilities.wrapOnComplete(optListener);
repo.scheduleNow(
new Runnable() {
@Override
public void run() {
repo.onDisconnectCancel(path, wrapped.getSecond());
}
});
return wrapped.getFirst();
}
}