• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

box / box-java-sdk / #4584

29 Apr 2025 07:23AM UTC coverage: 72.058% (-0.002%) from 72.06%
#4584

push

github

web-flow
fix: use `Locale.ROOT` to prevent issues with non-US locales (#1306)

14 of 23 new or added lines in 16 files covered. (60.87%)

1 existing line in 1 file now uncovered.

8216 of 11402 relevant lines covered (72.06%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.43
/src/main/java/com/box/sdk/BoxFolder.java
1
package com.box.sdk;
2

3
import static com.box.sdk.PagingParameters.DEFAULT_LIMIT;
4
import static com.box.sdk.PagingParameters.marker;
5
import static com.box.sdk.PagingParameters.offset;
6
import static com.box.sdk.http.ContentType.APPLICATION_JSON_PATCH;
7

8
import com.box.sdk.internal.utils.Parsers;
9
import com.box.sdk.sharedlink.BoxSharedLinkRequest;
10
import com.eclipsesource.json.Json;
11
import com.eclipsesource.json.JsonArray;
12
import com.eclipsesource.json.JsonObject;
13
import com.eclipsesource.json.JsonValue;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.net.URL;
17
import java.util.ArrayList;
18
import java.util.Collection;
19
import java.util.Date;
20
import java.util.EnumSet;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Map;
24
import java.util.Optional;
25
import java.util.concurrent.TimeUnit;
26

27
/**
28
 * <p>Represents a folder on Box. This class can be used to iterate through a folder's contents, collaborate a folder with
29
 * another user or group, and perform other common folder operations (move, copy, delete, etc.).
30
 * </p>
31
 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
32
 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
33
 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
34
 */
35
@BoxResourceType("folder")
36
public class BoxFolder extends BoxItem implements Iterable<BoxItem.Info> {
37
    /**
38
     * An array of all possible folder fields that can be requested when calling {@link #getInfo(String...)}.
39
     */
40
    public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "name", "created_at", "modified_at",
1✔
41
        "description", "size", "path_collection", "created_by", "modified_by", "trashed_at", "purged_at",
42
        "content_created_at", "content_modified_at", "owned_by", "shared_link", "folder_upload_email", "parent",
43
        "item_status", "item_collection", "sync_state", "has_collaborations", "permissions", "tags",
44
        "can_non_owners_invite", "collections", "watermark_info", "metadata", "is_externally_owned",
45
        "is_collaboration_restricted_to_enterprise", "allowed_shared_link_access_levels", "allowed_invitee_roles",
46
        "is_accessible_via_shared_link", "can_non_owners_view_collaborators"
47
    };
48
    /**
49
     * Create Folder URL Template.
50
     */
51
    public static final URLTemplate CREATE_FOLDER_URL = new URLTemplate("folders");
1✔
52
    /**
53
     * Create Web Link URL Template.
54
     */
55
    public static final URLTemplate CREATE_WEB_LINK_URL = new URLTemplate("web_links");
1✔
56
    /**
57
     * Copy Folder URL Template.
58
     */
59
    public static final URLTemplate COPY_FOLDER_URL = new URLTemplate("folders/%s/copy");
1✔
60
    /**
61
     * Delete Folder URL Template.
62
     */
63
    public static final URLTemplate DELETE_FOLDER_URL = new URLTemplate("folders/%s?recursive=%b");
1✔
64
    /**
65
     * Folder Info URL Template.
66
     */
67
    public static final URLTemplate FOLDER_INFO_URL_TEMPLATE = new URLTemplate("folders/%s");
1✔
68
    /**
69
     * Upload File URL Template.
70
     */
71
    public static final URLTemplate UPLOAD_FILE_URL = new URLTemplate("files/content");
1✔
72
    /**
73
     * Add Collaboration URL Template.
74
     */
75
    public static final URLTemplate ADD_COLLABORATION_URL = new URLTemplate("collaborations");
1✔
76
    /**
77
     * Get Collaborations URL Template.
78
     */
79
    public static final URLTemplate GET_COLLABORATIONS_URL = new URLTemplate("folders/%s/collaborations");
1✔
80
    /**
81
     * Get Items URL Template.
82
     */
83
    public static final URLTemplate GET_ITEMS_URL = new URLTemplate("folders/%s/items/");
1✔
84
    /**
85
     * Search URL Template.
86
     */
87
    public static final URLTemplate SEARCH_URL_TEMPLATE = new URLTemplate("search");
1✔
88
    /**
89
     * Metadata URL Template.
90
     */
91
    public static final URLTemplate METADATA_URL_TEMPLATE = new URLTemplate("folders/%s/metadata/%s/%s");
1✔
92
    /**
93
     * Upload Session URL Template.
94
     */
95
    public static final URLTemplate UPLOAD_SESSION_URL_TEMPLATE = new URLTemplate("files/upload_sessions");
1✔
96
    /**
97
     * Folder Locks URL Template.
98
     */
99
    public static final URLTemplate FOLDER_LOCK_URL_TEMPLATE = new URLTemplate("folder_locks");
1✔
100
    /**
101
     * Describes folder item type.
102
     */
103
    static final String TYPE = "folder";
104

105
    /**
106
     * Constructs a BoxFolder for a folder with a given ID.
107
     *
108
     * @param api the API connection to be used by the folder.
109
     * @param id  the ID of the folder.
110
     */
111
    public BoxFolder(BoxAPIConnection api, String id) {
112
        super(api, id);
1✔
113
    }
1✔
114

115
    /**
116
     * Gets the current user's root folder.
117
     *
118
     * @param api the API connection to be used by the folder.
119
     * @return the user's root folder.
120
     */
121
    public static BoxFolder getRootFolder(BoxAPIConnection api) {
122
        return new BoxFolder(api, "0");
1✔
123
    }
124

125
    /**
126
     * {@inheritDoc}
127
     */
128
    @Override
129
    protected URL getItemURL() {
130
        return FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
1✔
131
    }
132

133
    /**
134
     * Adds a collaborator to this folder.
135
     *
136
     * @param collaborator the collaborator to add.
137
     * @param role         the role of the collaborator.
138
     * @return info about the new collaboration.
139
     */
140
    public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role) {
141
        JsonObject accessibleByField = new JsonObject();
×
142
        accessibleByField.add("id", collaborator.getID());
×
143

144
        if (collaborator instanceof BoxUser) {
×
145
            accessibleByField.add("type", "user");
×
146
        } else if (collaborator instanceof BoxGroup) {
×
147
            accessibleByField.add("type", "group");
×
148
        } else {
149
            throw new IllegalArgumentException("The given collaborator is of an unknown type.");
×
150
        }
151

152
        return this.collaborate(accessibleByField, role, null, null, null, null);
×
153
    }
154

155
    /**
156
     * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box
157
     * account.
158
     *
159
     * @param email the email address of the collaborator to add.
160
     * @param role  the role of the collaborator.
161
     * @return info about the new collaboration.
162
     */
163
    public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role) {
164
        JsonObject accessibleByField = new JsonObject();
×
165
        accessibleByField.add("login", email);
×
166
        accessibleByField.add("type", "user");
×
167

168
        return this.collaborate(accessibleByField, role, null, null, null, null);
×
169
    }
170

171
    /**
172
     * Adds a collaborator to this folder.
173
     *
174
     * @param collaborator the collaborator to add.
175
     * @param role         the role of the collaborator.
176
     * @param notify       the user/group should receive email notification of the collaboration or not.
177
     * @param canViewPath  the view path collaboration feature is enabled or not.
178
     *                     View path collaborations allow the invitee to see the entire ancestral path to the associated
179
     *                     folder. The user will not gain privileges in any ancestral folder.
180
     * @param expiresAt    when the collaboration should expire.
181
     * @param isAccessOnly whether the collaboration is access only or not.
182
     * @return info about the new collaboration.
183
     */
184
    public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role,
185
                                             Boolean notify, Boolean canViewPath,
186
                                             Date expiresAt, Boolean isAccessOnly) {
187
        JsonObject accessibleByField = new JsonObject();
×
188
        accessibleByField.add("id", collaborator.getID());
×
189

190
        if (collaborator instanceof BoxUser) {
×
191
            accessibleByField.add("type", "user");
×
192
        } else if (collaborator instanceof BoxGroup) {
×
193
            accessibleByField.add("type", "group");
×
194
        } else {
195
            throw new IllegalArgumentException("The given collaborator is of an unknown type.");
×
196
        }
197

198
        return this.collaborate(accessibleByField, role, notify, canViewPath, expiresAt, isAccessOnly);
×
199
    }
200

201
    /**
202
     * Adds a collaborator to this folder.
203
     *
204
     * @param collaborator the collaborator to add.
205
     * @param role         the role of the collaborator.
206
     * @param notify       the user/group should receive email notification of the collaboration or not.
207
     * @param canViewPath  the view path collaboration feature is enabled or not.
208
     *                     View path collaborations allow the invitee to see the entire ancestral path to the associated
209
     *                     folder. The user will not gain privileges in any ancestral folder.
210
     * @return info about the new collaboration.
211
     */
212
    public BoxCollaboration.Info collaborate(BoxCollaborator collaborator, BoxCollaboration.Role role,
213
                                             Boolean notify, Boolean canViewPath) {
214
        return this.collaborate(collaborator, role, notify, canViewPath, null, null);
×
215
    }
216

217
    /**
218
     * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box
219
     * account.
220
     *
221
     * @param email       the email address of the collaborator to add.
222
     * @param role        the role of the collaborator.
223
     * @param notify      the user/group should receive email notification of the collaboration or not.
224
     * @param canViewPath the view path collaboration feature is enabled or not.
225
     *                    View path collaborations allow the invitee to see the entire ancestral path to the associated
226
     *                    folder. The user will not gain privileges in any ancestral folder.
227
     * @param expiresAt    when the collaboration should expire.
228
     * @param isAccessOnly whether the collaboration is access only or not.
229
     * @return info about the new collaboration.
230
     */
231
    public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role,
232
                                             Boolean notify, Boolean canViewPath,
233
                                             Date expiresAt, Boolean isAccessOnly) {
234
        JsonObject accessibleByField = new JsonObject();
1✔
235
        accessibleByField.add("login", email);
1✔
236
        accessibleByField.add("type", "user");
1✔
237

238
        return this.collaborate(accessibleByField, role, notify, canViewPath, expiresAt, isAccessOnly);
1✔
239
    }
240

241
    /**
242
     * Adds a collaborator to this folder. An email will be sent to the collaborator if they don't already have a Box
243
     * account.
244
     *
245
     * @param email       the email address of the collaborator to add.
246
     * @param role        the role of the collaborator.
247
     * @param notify      the user/group should receive email notification of the collaboration or not.
248
     * @param canViewPath the view path collaboration feature is enabled or not.
249
     *                    View path collaborations allow the invitee to see the entire ancestral path to the associated
250
     *                    folder. The user will not gain privileges in any ancestral folder.
251
     * @return info about the new collaboration.
252
     */
253
    public BoxCollaboration.Info collaborate(String email, BoxCollaboration.Role role,
254
                                             Boolean notify, Boolean canViewPath) {
255
        return this.collaborate(email, role, notify, canViewPath, null, null);
×
256
    }
257

258
    private BoxCollaboration.Info collaborate(JsonObject accessibleByField, BoxCollaboration.Role role,
259
                                              Boolean notify, Boolean canViewPath,
260
                                              Date expiresAt, Boolean isAccessOnly) {
261

262
        JsonObject itemField = new JsonObject();
1✔
263
        itemField.add("id", this.getID());
1✔
264
        itemField.add("type", "folder");
1✔
265

266
        return BoxCollaboration.create(this.getAPI(), accessibleByField, itemField, role, notify, canViewPath,
1✔
267
                expiresAt, isAccessOnly);
268
    }
269

270
    /**
271
     * Creates a shared link.
272
     *
273
     * @param sharedLinkRequest Shared link to create
274
     * @return Created shared link.
275
     */
276
    public BoxSharedLink createSharedLink(BoxSharedLinkRequest sharedLinkRequest) {
277
        return createSharedLink(sharedLinkRequest.asSharedLink());
1✔
278
    }
279

280
    private BoxSharedLink createSharedLink(BoxSharedLink sharedLink) {
281
        BoxFolder.Info info = new BoxFolder.Info();
1✔
282
        info.setSharedLink(removeCanEditPermissionIfSet(sharedLink));
1✔
283

284
        this.updateInfo(info);
1✔
285
        return info.getSharedLink();
1✔
286
    }
287

288
    private BoxSharedLink removeCanEditPermissionIfSet(BoxSharedLink sharedLink) {
289
        if (sharedLink.getPermissions() != null && sharedLink.getPermissions().getCanEdit()) {
1✔
290
            BoxSharedLink.Permissions permissions = sharedLink.getPermissions();
1✔
291
            sharedLink.setPermissions(
1✔
292
                new BoxSharedLink.Permissions(permissions.getCanPreview(), permissions.getCanDownload(), false)
1✔
293
            );
294
        }
295
        return sharedLink;
1✔
296
    }
297

298
    /**
299
     * Gets information about all of the collaborations for this folder.
300
     *
301
     * @return a collection of information about the collaborations for this folder.
302
     */
303
    public Collection<BoxCollaboration.Info> getCollaborations(String... fields) {
304
        BoxAPIConnection api = this.getAPI();
1✔
305
        QueryStringBuilder queryBuilder = new QueryStringBuilder();
1✔
306
        if (fields.length > 0) {
1✔
307
            queryBuilder.appendParam("fields", fields);
1✔
308
        }
309
        URL url = GET_COLLABORATIONS_URL.buildWithQuery(api.getBaseURL(), queryBuilder.toString(), this.getID());
1✔
310

311

312
        BoxJSONRequest request = new BoxJSONRequest(api, url, "GET");
1✔
313
        try (BoxJSONResponse response = request.send()) {
1✔
314
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
315

316
            int entriesCount = responseJSON.get("total_count").asInt();
1✔
317
            Collection<BoxCollaboration.Info> collaborations = new ArrayList<>(entriesCount);
1✔
318
            JsonArray entries = responseJSON.get("entries").asArray();
1✔
319
            for (JsonValue entry : entries) {
1✔
320
                JsonObject entryObject = entry.asObject();
1✔
321
                BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString());
1✔
322
                BoxCollaboration.Info info = collaboration.new Info(entryObject);
1✔
323
                collaborations.add(info);
1✔
324
            }
1✔
325

326
            return collaborations;
1✔
327
        }
328
    }
329

330
    @Override
331
    public BoxFolder.Info getInfo(String... fields) {
332
        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
1✔
333
        if (fields.length > 0) {
1✔
334
            String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
×
335
            url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
×
336
        }
337

338
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
1✔
339
        try (BoxJSONResponse response = request.send()) {
1✔
340
            return new Info(response.getJSON());
1✔
341
        }
342
    }
343

344
    /**
345
     * Updates the information about this folder with any info fields that have been modified locally.
346
     *
347
     * @param info the updated info.
348
     */
349
    public void updateInfo(BoxFolder.Info info) {
350
        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
1✔
351
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
1✔
352
        request.setBody(info.getPendingChanges());
1✔
353
        try (BoxJSONResponse response = request.send()) {
1✔
354
            JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
1✔
355
            info.update(jsonObject);
1✔
356
        }
357
    }
1✔
358

359
    @Override
360
    public BoxFolder.Info copy(BoxFolder destination) {
361
        return this.copy(destination, null);
1✔
362
    }
363

364
    @Override
365
    public BoxFolder.Info copy(BoxFolder destination, String newName) {
366
        URL url = COPY_FOLDER_URL.build(this.getAPI().getBaseURL(), this.getID());
1✔
367
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
1✔
368

369
        JsonObject parent = new JsonObject();
1✔
370
        parent.add("id", destination.getID());
1✔
371

372
        JsonObject copyInfo = new JsonObject();
1✔
373
        copyInfo.add("parent", parent);
1✔
374
        if (newName != null) {
1✔
375
            copyInfo.add("name", newName);
×
376
        }
377

378
        request.setBody(copyInfo.toString());
1✔
379
        try (BoxJSONResponse response = request.send()) {
1✔
380
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
381
            BoxFolder copiedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
1✔
382
            return copiedFolder.new Info(responseJSON);
1✔
383
        }
384
    }
385

386
    /**
387
     * Creates a new child folder inside this folder.
388
     *
389
     * @param name the new folder's name.
390
     * @return the created folder's info.
391
     */
392
    public BoxFolder.Info createFolder(String name) {
393
        JsonObject parent = new JsonObject();
1✔
394
        parent.add("id", this.getID());
1✔
395

396
        JsonObject newFolder = new JsonObject();
1✔
397
        newFolder.add("name", name);
1✔
398
        newFolder.add("parent", parent);
1✔
399

400
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), CREATE_FOLDER_URL.build(this.getAPI().getBaseURL()),
1✔
401
            "POST");
402
        request.setBody(newFolder.toString());
1✔
403
        try (BoxJSONResponse response = request.send()) {
1✔
404
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
405

406
            BoxFolder createdFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
1✔
407
            return createdFolder.new Info(responseJSON);
1✔
408
        }
409
    }
410

411
    /**
412
     * Deletes this folder, optionally recursively deleting all of its contents.
413
     *
414
     * @param recursive true to recursively delete this folder's contents; otherwise false.
415
     */
416
    public void delete(boolean recursive) {
417
        URL url = DELETE_FOLDER_URL.buildAlpha(this.getAPI().getBaseURL(), this.getID(), recursive);
1✔
418
        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
1✔
419
        request.send().close();
1✔
420
    }
1✔
421

422
    @Override
423
    public BoxItem.Info move(BoxFolder destination) {
424
        return this.move(destination, null);
1✔
425
    }
426

427
    @Override
428
    public BoxItem.Info move(BoxFolder destination, String newName) {
429
        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
1✔
430
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
1✔
431

432
        JsonObject parent = new JsonObject();
1✔
433
        parent.add("id", destination.getID());
1✔
434

435
        JsonObject updateInfo = new JsonObject();
1✔
436
        updateInfo.add("parent", parent);
1✔
437
        if (newName != null) {
1✔
438
            updateInfo.add("name", newName);
×
439
        }
440

441
        request.setBody(updateInfo.toString());
1✔
442
        try (BoxJSONResponse response = request.send()) {
1✔
443
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
444
            BoxFolder movedFolder = new BoxFolder(this.getAPI(), responseJSON.get("id").asString());
1✔
445
            return movedFolder.new Info(responseJSON);
1✔
446
        }
447
    }
448

449
    /**
450
     * Renames this folder.
451
     *
452
     * @param newName the new name of the folder.
453
     */
454
    public void rename(String newName) {
455
        URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
1✔
456
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
1✔
457

458
        JsonObject updateInfo = new JsonObject();
1✔
459
        updateInfo.add("name", newName);
1✔
460

461
        request.setBody(updateInfo.toString());
1✔
462
        try (BoxJSONResponse response = request.send()) {
1✔
463
            response.getJSON();
1✔
464
        }
465
    }
1✔
466

467
    /**
468
     * Checks if the file can be successfully uploaded by using the preflight check.
469
     *
470
     * @param name     the name to give the uploaded file.
471
     * @param fileSize the size of the file used for account capacity calculations.
472
     */
473
    public void canUpload(String name, long fileSize) {
474
        URL url = UPLOAD_FILE_URL.build(this.getAPI().getBaseURL());
1✔
475
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "OPTIONS");
1✔
476

477
        JsonObject parent = new JsonObject();
1✔
478
        parent.add("id", this.getID());
1✔
479

480
        JsonObject preflightInfo = new JsonObject();
1✔
481
        preflightInfo.add("parent", parent);
1✔
482
        preflightInfo.add("name", name);
1✔
483

484
        preflightInfo.add("size", fileSize);
1✔
485

486
        request.setBody(preflightInfo.toString());
1✔
487
        try (BoxJSONResponse response = request.send()) {
1✔
488
            response.getJSON();
1✔
489
        }
490
    }
1✔
491

492
    /**
493
     * Uploads a new file to this folder.
494
     *
495
     * @param fileContent a stream containing the contents of the file to upload.
496
     * @param name        the name to give the uploaded file.
497
     * @return the uploaded file's info.
498
     */
499
    public BoxFile.Info uploadFile(InputStream fileContent, String name) {
500
        FileUploadParams uploadInfo = new FileUploadParams()
1✔
501
            .setContent(fileContent)
1✔
502
            .setName(name);
1✔
503
        return this.uploadFile(uploadInfo);
1✔
504
    }
505

506
    /**
507
     * Uploads a new file to this folder.
508
     *
509
     * @param callback the callback which allows file content to be written on output stream.
510
     * @param name     the name to give the uploaded file.
511
     * @return the uploaded file's info.
512
     */
513
    public BoxFile.Info uploadFile(UploadFileCallback callback, String name) {
514
        FileUploadParams uploadInfo = new FileUploadParams()
×
515
            .setUploadFileCallback(callback)
×
516
            .setName(name);
×
517
        return this.uploadFile(uploadInfo);
×
518
    }
519

520
    /**
521
     * Uploads a new file to this folder while reporting the progress to a ProgressListener.
522
     *
523
     * @param fileContent a stream containing the contents of the file to upload.
524
     * @param name        the name to give the uploaded file.
525
     * @param fileSize    the size of the file used for determining the progress of the upload.
526
     * @param listener    a listener for monitoring the upload's progress.
527
     * @return the uploaded file's info.
528
     */
529
    public BoxFile.Info uploadFile(InputStream fileContent, String name, long fileSize, ProgressListener listener) {
530
        FileUploadParams uploadInfo = new FileUploadParams()
×
531
            .setContent(fileContent)
×
532
            .setName(name)
×
533
            .setSize(fileSize)
×
534
            .setProgressListener(listener);
×
535
        return this.uploadFile(uploadInfo);
×
536
    }
537

538
    /**
539
     * Uploads a new file to this folder with a specified file description.
540
     *
541
     * @param fileContent a stream containing the contents of the file to upload.
542
     * @param name        the name to give the uploaded file.
543
     * @param description the description to give the uploaded file.
544
     * @return the uploaded file's info.
545
     */
546
    public BoxFile.Info uploadFile(InputStream fileContent, String name, String description) {
547
        FileUploadParams uploadInfo = new FileUploadParams()
1✔
548
            .setContent(fileContent)
1✔
549
            .setName(name)
1✔
550
            .setDescription(description);
1✔
551
        return this.uploadFile(uploadInfo);
1✔
552
    }
553

554
    /**
555
     * Uploads a new file to this folder with custom upload parameters.
556
     *
557
     * @param uploadParams the custom upload parameters.
558
     * @return the uploaded file's info.
559
     */
560
    public BoxFile.Info uploadFile(FileUploadParams uploadParams) {
561
        URL uploadURL = UPLOAD_FILE_URL.build(this.getAPI().getBaseUploadURL());
1✔
562
        BoxMultipartRequest request = new BoxMultipartRequest(getAPI(), uploadURL);
1✔
563

564
        JsonObject fieldJSON = new JsonObject();
1✔
565
        JsonObject parentIdJSON = new JsonObject();
1✔
566
        parentIdJSON.add("id", getID());
1✔
567
        fieldJSON.add("name", uploadParams.getName());
1✔
568
        fieldJSON.add("parent", parentIdJSON);
1✔
569

570
        if (uploadParams.getCreated() != null) {
1✔
571
            fieldJSON.add("content_created_at", BoxDateFormat.format(uploadParams.getCreated()));
×
572
        }
573

574
        if (uploadParams.getModified() != null) {
1✔
575
            fieldJSON.add("content_modified_at", BoxDateFormat.format(uploadParams.getModified()));
×
576
        }
577

578
        if (uploadParams.getSHA1() != null && !uploadParams.getSHA1().isEmpty()) {
1✔
579
            request.setContentSHA1(uploadParams.getSHA1());
×
580
        }
581

582
        if (uploadParams.getDescription() != null) {
1✔
583
            fieldJSON.add("description", uploadParams.getDescription());
1✔
584
        }
585

586
        request.putField("attributes", fieldJSON.toString());
1✔
587

588
        if (uploadParams.getSize() > 0) {
1✔
589
            request.setFile(uploadParams.getContent(), uploadParams.getName(), uploadParams.getSize());
×
590
        } else if (uploadParams.getContent() != null) {
1✔
591
            request.setFile(uploadParams.getContent(), uploadParams.getName());
1✔
592
        } else {
593
            request.setUploadFileCallback(uploadParams.getUploadFileCallback(), uploadParams.getName());
×
594
        }
595

596
        BoxJSONResponse response = null;
1✔
597
        try {
598
            if (uploadParams.getProgressListener() == null) {
1✔
599
                // upload files sends multipart request but response is JSON
600
                response = (BoxJSONResponse) request.send();
1✔
601
            } else {
602
                // upload files sends multipart request but response is JSON
603
                response = (BoxJSONResponse) request.send(uploadParams.getProgressListener());
×
604
            }
605
            JsonObject collection = Json.parse(response.getJSON()).asObject();
1✔
606
            JsonArray entries = collection.get("entries").asArray();
1✔
607
            JsonObject fileInfoJSON = entries.get(0).asObject();
1✔
608
            String uploadedFileID = fileInfoJSON.get("id").asString();
1✔
609

610
            BoxFile uploadedFile = new BoxFile(getAPI(), uploadedFileID);
1✔
611
            return uploadedFile.new Info(fileInfoJSON);
1✔
612
        } finally {
613
            Optional.ofNullable(response).ifPresent(BoxAPIResponse::close);
1✔
614
        }
615
    }
616

617
    /**
618
     * Uploads a new weblink to this folder.
619
     *
620
     * @param linkURL the URL the weblink points to.
621
     * @return the uploaded weblink's info.
622
     */
623
    public BoxWebLink.Info createWebLink(URL linkURL) {
624
        return this.createWebLink(null, linkURL,
×
625
            null);
626
    }
627

628
    /**
629
     * Uploads a new weblink to this folder.
630
     *
631
     * @param name    the filename for the weblink.
632
     * @param linkURL the URL the weblink points to.
633
     * @return the uploaded weblink's info.
634
     */
635
    public BoxWebLink.Info createWebLink(String name, URL linkURL) {
636
        return this.createWebLink(name, linkURL,
×
637
            null);
638
    }
639

640
    /**
641
     * Uploads a new weblink to this folder.
642
     *
643
     * @param linkURL     the URL the weblink points to.
644
     * @param description the weblink's description.
645
     * @return the uploaded weblink's info.
646
     */
647
    public BoxWebLink.Info createWebLink(URL linkURL, String description) {
648
        return this.createWebLink(null, linkURL, description);
×
649
    }
650

651
    /**
652
     * Uploads a new weblink to this folder.
653
     *
654
     * @param name        the filename for the weblink.
655
     * @param linkURL     the URL the weblink points to.
656
     * @param description the weblink's description.
657
     * @return the uploaded weblink's info.
658
     */
659
    public BoxWebLink.Info createWebLink(String name, URL linkURL, String description) {
660
        JsonObject parent = new JsonObject();
1✔
661
        parent.add("id", this.getID());
1✔
662

663
        JsonObject newWebLink = new JsonObject();
1✔
664
        newWebLink.add("name", name);
1✔
665
        newWebLink.add("parent", parent);
1✔
666
        newWebLink.add("url", linkURL.toString());
1✔
667

668
        if (description != null) {
1✔
669
            newWebLink.add("description", description);
1✔
670
        }
671

672
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(),
1✔
673
            CREATE_WEB_LINK_URL.build(this.getAPI().getBaseURL()), "POST");
1✔
674
        request.setBody(newWebLink.toString());
1✔
675
        try (BoxJSONResponse response = request.send()) {
1✔
676
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
677

678
            BoxWebLink createdWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString());
1✔
679
            return createdWebLink.new Info(responseJSON);
1✔
680
        }
681
    }
682

683
    /**
684
     * Returns an iterable containing the items in this folder. Iterating over the iterable returned by this method is
685
     * equivalent to iterating over this BoxFolder directly.
686
     *
687
     * @return an iterable containing the items in this folder.
688
     */
689
    public Iterable<BoxItem.Info> getChildren() {
690
        return this;
×
691
    }
692

693
    /**
694
     * Returns an iterable containing the items in this folder and specifies which child fields to retrieve from the
695
     * API.
696
     *
697
     * @param fields the fields to retrieve.
698
     * @return an iterable containing the items in this folder.
699
     */
700
    public Iterable<BoxItem.Info> getChildren(final String... fields) {
701
        return () -> {
×
702
            String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
×
703
            URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), queryString, getID());
×
704
            return new BoxItemIterator(getAPI(), url, marker(DEFAULT_LIMIT));
×
705
        };
706
    }
707

708
    /**
709
     * Returns an iterable containing the items in this folder sorted by name and direction.
710
     *
711
     * @param sort      the field to sort by, can be set as `name`, `id`, and `date`.
712
     * @param direction the direction to display the item results.
713
     * @param fields    the fields to retrieve.
714
     * @return an iterable containing the items in this folder.
715
     */
716
    public Iterable<BoxItem.Info> getChildren(String sort, SortDirection direction, final String... fields) {
717
        QueryStringBuilder builder = new QueryStringBuilder()
1✔
718
            .appendParam("sort", sort)
1✔
719
            .appendParam("direction", direction.toString());
1✔
720

721
        if (fields.length > 0) {
1✔
722
            builder.appendParam("fields", fields);
1✔
723
        }
724
        final String query = builder.toString();
1✔
725
        return () -> {
1✔
726
            URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID());
1✔
727
            return new BoxItemIterator(getAPI(), url, offset(0, DEFAULT_LIMIT));
1✔
728
        };
729
    }
730

731
    /**
732
     * Returns an iterable containing the items in this folder sorted by name and direction.
733
     *
734
     * @param sort      the field to sort by, can be set as `name`, `id`, and `date`.
735
     * @param direction the direction to display the item results.
736
     * @param offset    the index of the first child item to retrieve.
737
     * @param limit     the maximum number of children to retrieve after the offset.
738
     * @param fields    the fields to retrieve.
739
     * @return an iterable containing the items in this folder.
740
     */
741
    public Iterable<BoxItem.Info> getChildren(String sort, SortDirection direction, final long offset, final long limit,
742
                                              final String... fields) {
743
        QueryStringBuilder builder = new QueryStringBuilder()
1✔
744
            .appendParam("sort", sort)
1✔
745
            .appendParam("direction", direction.toString());
1✔
746

747
        if (fields.length > 0) {
1✔
748
            builder.appendParam("fields", fields);
1✔
749
        }
750
        final String query = builder.toString();
1✔
751
        return () -> {
1✔
752
            URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID());
1✔
753
            return new BoxItemIterator(getAPI(), url, limit, offset);
1✔
754
        };
755
    }
756

757
    /**
758
     * Retrieves a specific range of child items in this folder.
759
     *
760
     * @param offset the index of the first child item to retrieve.
761
     * @param limit  the maximum number of children to retrieve after the offset.
762
     * @param fields the fields to retrieve.
763
     * @return a partial collection containing the specified range of child items.
764
     */
765
    public PartialCollection<BoxItem.Info> getChildrenRange(long offset, long limit, String... fields) {
766
        QueryStringBuilder builder = new QueryStringBuilder()
×
767
            .appendParam("limit", limit)
×
768
            .appendParam("offset", offset);
×
769

770
        if (fields.length > 0) {
×
771
            builder.appendParam("fields", fields);
×
772
        }
773

774
        URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), builder.toString(), getID());
×
775
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
×
776
        try (BoxJSONResponse response = request.send()) {
×
777
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
×
778

779
            String totalCountString = responseJSON.get("total_count").toString();
×
780
            long fullSize = Double.valueOf(totalCountString).longValue();
×
781
            PartialCollection<BoxItem.Info> children = new PartialCollection<>(offset, limit, fullSize);
×
782
            JsonArray jsonArray = responseJSON.get("entries").asArray();
×
783
            for (JsonValue value : jsonArray) {
×
784
                JsonObject jsonObject = value.asObject();
×
785
                BoxItem.Info parsedItemInfo = (BoxItem.Info) BoxResource.parseInfo(this.getAPI(), jsonObject);
×
786
                if (parsedItemInfo != null) {
×
787
                    children.add(parsedItemInfo);
×
788
                }
789
            }
×
790
            return children;
×
791
        }
792
    }
793

794
    /**
795
     * Returns an iterable containing the items in this folder sorted by name and direction.
796
     *
797
     * @param sortParameters   describes sorting parameters.
798
     *                         Sort parameters are supported only with offset based pagination.
799
     *                         Use {@link SortParameters#none()} to ignore sorting.
800
     * @param pagingParameters describes paging parameters.
801
     * @param fields           the fields to retrieve.
802
     * @return an iterable containing the items in this folder.
803
     */
804
    public Iterable<BoxItem.Info> getChildren(
805
        final SortParameters sortParameters, final PagingParameters pagingParameters, String... fields
806
    ) {
807
        QueryStringBuilder builder = sortParameters.asQueryStringBuilder();
1✔
808
        validateSortIsSelectedWithOffsetPaginationOnly(pagingParameters, builder);
1✔
809

810
        if (fields.length > 0) {
1✔
811
            builder.appendParam("fields", fields);
×
812
        }
813
        final String query = builder.toString();
1✔
814
        return () -> {
1✔
815
            URL url = GET_ITEMS_URL.buildWithQuery(getAPI().getBaseURL(), query, getID());
1✔
816
            return new BoxItemIterator(getAPI(), url, pagingParameters);
1✔
817
        };
818
    }
819

820
    /**
821
     * Returns an iterator over the items in this folder.
822
     *
823
     * @return an iterator over the items in this folder.
824
     */
825
    @Override
826
    public Iterator<BoxItem.Info> iterator() {
827
        URL url = GET_ITEMS_URL.build(this.getAPI().getBaseURL(), BoxFolder.this.getID());
1✔
828
        return new BoxItemIterator(BoxFolder.this.getAPI(), url, marker(DEFAULT_LIMIT));
1✔
829
    }
830

831
    /**
832
     * Adds new {@link BoxWebHook} to this {@link BoxFolder}.
833
     *
834
     * @param address  {@link BoxWebHook.Info#getAddress()}
835
     * @param triggers {@link BoxWebHook.Info#getTriggers()}
836
     * @return created {@link BoxWebHook.Info}
837
     */
838
    public BoxWebHook.Info addWebHook(URL address, BoxWebHook.Trigger... triggers) {
839
        return BoxWebHook.create(this, address, triggers);
×
840
    }
841

842
    /**
843
     * Used to retrieve the watermark for the folder.
844
     * If the folder does not have a watermark applied to it, a 404 Not Found will be returned by API.
845
     *
846
     * @param fields the fields to retrieve.
847
     * @return the watermark associated with the folder.
848
     */
849
    public BoxWatermark getWatermark(String... fields) {
850
        return this.getWatermark(FOLDER_INFO_URL_TEMPLATE, fields);
1✔
851
    }
852

853
    /**
854
     * Used to apply or update the watermark for the folder.
855
     *
856
     * @return the watermark associated with the folder.
857
     */
858
    public BoxWatermark applyWatermark() {
859
        return this.applyWatermark(FOLDER_INFO_URL_TEMPLATE, BoxWatermark.WATERMARK_DEFAULT_IMPRINT);
1✔
860
    }
861

862
    /**
863
     * Removes a watermark from the folder.
864
     * If the folder did not have a watermark applied to it, a 404 Not Found will be returned by API.
865
     */
866
    public void removeWatermark() {
867
        this.removeWatermark(FOLDER_INFO_URL_TEMPLATE);
1✔
868
    }
1✔
869

870
    /**
871
     * Used to retrieve all metadata associated with the folder.
872
     *
873
     * @param fields the optional fields to retrieve.
874
     * @return An iterable of metadata instances associated with the folder
875
     */
876
    public Iterable<Metadata> getAllMetadata(String... fields) {
877
        return Metadata.getAllMetadata(this, fields);
1✔
878
    }
879

880
    @Override
881
    public BoxFolder.Info setCollections(BoxCollection... collections) {
882
        JsonArray jsonArray = new JsonArray();
1✔
883
        for (BoxCollection collection : collections) {
1✔
884
            JsonObject collectionJSON = new JsonObject();
1✔
885
            collectionJSON.add("id", collection.getID());
1✔
886
            jsonArray.add(collectionJSON);
1✔
887
        }
888
        JsonObject infoJSON = new JsonObject();
1✔
889
        infoJSON.add("collections", jsonArray);
1✔
890

891
        String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString();
1✔
892
        URL url = FOLDER_INFO_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
1✔
893
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
1✔
894
        request.setBody(infoJSON.toString());
1✔
895
        try (BoxJSONResponse response = request.send()) {
1✔
896
            JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
1✔
897
            return new Info(jsonObject);
1✔
898
        }
899
    }
900

901
    /**
902
     * Creates global property metadata on this folder.
903
     *
904
     * @param metadata the new metadata values.
905
     * @return the metadata returned from the server.
906
     */
907
    public Metadata createMetadata(Metadata metadata) {
908
        return this.createMetadata(Metadata.DEFAULT_METADATA_TYPE, metadata);
1✔
909
    }
910

911
    /**
912
     * Creates metadata on this folder using a specified template.
913
     *
914
     * @param templateName the name of the metadata template.
915
     * @param metadata     the new metadata values.
916
     * @return the metadata returned from the server.
917
     */
918
    public Metadata createMetadata(String templateName, Metadata metadata) {
919
        String scope = Metadata.scopeBasedOnType(templateName);
1✔
920
        return this.createMetadata(templateName, scope, metadata);
1✔
921
    }
922

923
    /**
924
     * Creates metadata on this folder using a specified scope and template.
925
     *
926
     * @param templateName the name of the metadata template.
927
     * @param scope        the scope of the template (usually "global" or "enterprise").
928
     * @param metadata     the new metadata values.
929
     * @return the metadata returned from the server.
930
     */
931
    public Metadata createMetadata(String templateName, String scope, Metadata metadata) {
932
        URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName);
1✔
933
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
1✔
934
        request.setBody(metadata.toString());
1✔
935
        try (BoxJSONResponse response = request.send()) {
1✔
936
            return new Metadata(Json.parse(response.getJSON()).asObject());
1✔
937
        }
938
    }
939

940
    /**
941
     * Sets the provided metadata on the folder. If metadata has already been created on this folder,
942
     * it overwrites metadata keys specified in the `metadata` param.
943
     *
944
     * @param templateName the name of the metadata template.
945
     * @param scope        the scope of the template (usually "global" or "enterprise").
946
     * @param metadata     the new metadata values.
947
     * @return the metadata returned from the server.
948
     */
949
    public Metadata setMetadata(String templateName, String scope, Metadata metadata) {
950
        try {
951
            return this.createMetadata(templateName, scope, metadata);
×
952
        } catch (BoxAPIException e) {
1✔
953
            if (e.getResponseCode() == 409) {
1✔
954
                if (metadata.getOperations().isEmpty()) {
1✔
955
                    return getMetadata();
1✔
956
                } else {
957
                    return updateExistingTemplate(templateName, scope, metadata);
1✔
958
                }
959
            } else {
960
                throw e;
×
961
            }
962
        }
963
    }
964

965
    /**
966
     * Throws IllegalArgumentException exception when sorting and marker pagination is selected.
967
     *
968
     * @param pagingParameters paging definition to check
969
     * @param sortQuery        builder containing sort query
970
     */
971
    private void validateSortIsSelectedWithOffsetPaginationOnly(
972
        PagingParameters pagingParameters,
973
        QueryStringBuilder sortQuery
974
    ) {
975
        if (pagingParameters != null && pagingParameters.isMarkerBasedPaging() && sortQuery.toString().length() > 0) {
1✔
976
            throw new IllegalArgumentException("Sorting is not supported when using marker based pagination.");
1✔
977
        }
978
    }
1✔
979

980
    private Metadata updateExistingTemplate(String templateName, String scope, Metadata metadata) {
981
        Metadata metadataToUpdate = new Metadata(scope, templateName);
1✔
982
        for (JsonValue value : metadata.getOperations()) {
1✔
983
            if (value.asObject().get("value").isNumber()) {
1✔
984
                metadataToUpdate.add(value.asObject().get("path").asString(),
1✔
985
                    value.asObject().get("value").asDouble());
1✔
986
            } else if (value.asObject().get("value").isString()) {
1✔
987
                metadataToUpdate.add(value.asObject().get("path").asString(),
1✔
988
                    value.asObject().get("value").asString());
1✔
989
            } else if (value.asObject().get("value").isArray()) {
1✔
990
                ArrayList<String> list = new ArrayList<>();
1✔
991
                for (JsonValue jsonValue : value.asObject().get("value").asArray()) {
1✔
992
                    list.add(jsonValue.asString());
1✔
993
                }
1✔
994
                metadataToUpdate.add(value.asObject().get("path").asString(), list);
1✔
995
            }
996
        }
1✔
997
        return this.updateMetadata(metadataToUpdate);
1✔
998
    }
999

1000
    /**
1001
     * Gets the global properties metadata on this folder.
1002
     *
1003
     * @return the metadata returned from the server.
1004
     */
1005
    public Metadata getMetadata() {
1006
        return this.getMetadata(Metadata.DEFAULT_METADATA_TYPE);
1✔
1007
    }
1008

1009
    /**
1010
     * Gets the metadata on this folder associated with a specified template.
1011
     *
1012
     * @param templateName the metadata template type name.
1013
     * @return the metadata returned from the server.
1014
     */
1015
    public Metadata getMetadata(String templateName) {
1016
        String scope = Metadata.scopeBasedOnType(templateName);
1✔
1017
        return this.getMetadata(templateName, scope);
1✔
1018
    }
1019

1020
    /**
1021
     * Gets the metadata on this folder associated with a specified scope and template.
1022
     *
1023
     * @param templateName the metadata template type name.
1024
     * @param scope        the scope of the template (usually "global" or "enterprise").
1025
     * @return the metadata returned from the server.
1026
     */
1027
    public Metadata getMetadata(String templateName, String scope) {
1028
        URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName);
1✔
1029
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
1✔
1030
        try (BoxJSONResponse response = request.send()) {
1✔
1031
            return new Metadata(Json.parse(response.getJSON()).asObject());
1✔
1032
        }
1033
    }
1034

1035
    /**
1036
     * Updates the folder metadata.
1037
     *
1038
     * @param metadata the new metadata values.
1039
     * @return the metadata returned from the server.
1040
     */
1041
    public Metadata updateMetadata(Metadata metadata) {
1042
        URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), metadata.getScope(),
1✔
1043
            metadata.getTemplateName());
1✔
1044
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT", APPLICATION_JSON_PATCH);
1✔
1045
        request.setBody(metadata.getPatch());
1✔
1046
        try (BoxJSONResponse response = request.send()) {
1✔
1047
            return new Metadata(Json.parse(response.getJSON()).asObject());
1✔
1048
        }
1049
    }
1050

1051
    /**
1052
     * Deletes the global properties metadata on this folder.
1053
     */
1054
    public void deleteMetadata() {
1055
        this.deleteMetadata(Metadata.DEFAULT_METADATA_TYPE);
×
1056
    }
×
1057

1058
    /**
1059
     * Deletes the metadata on this folder associated with a specified template.
1060
     *
1061
     * @param templateName the metadata template type name.
1062
     */
1063
    public void deleteMetadata(String templateName) {
1064
        String scope = Metadata.scopeBasedOnType(templateName);
×
1065
        this.deleteMetadata(templateName, scope);
×
1066
    }
×
1067

1068
    /**
1069
     * Deletes the metadata on this folder associated with a specified scope and template.
1070
     *
1071
     * @param templateName the metadata template type name.
1072
     * @param scope        the scope of the template (usually "global" or "enterprise").
1073
     */
1074
    public void deleteMetadata(String templateName, String scope) {
1075
        URL url = METADATA_URL_TEMPLATE.buildAlpha(this.getAPI().getBaseURL(), this.getID(), scope, templateName);
1✔
1076
        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
1✔
1077
        request.send().close();
1✔
1078
    }
1✔
1079

1080
    /**
1081
     * Adds a metadata classification to the specified file.
1082
     *
1083
     * @param classificationType the metadata classification type.
1084
     * @return the metadata classification type added to the file.
1085
     */
1086
    public String addClassification(String classificationType) {
1087
        Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType);
1✔
1088
        Metadata classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY,
1✔
1089
            "enterprise", metadata);
1090

1091
        return classification.getString(Metadata.CLASSIFICATION_KEY);
1✔
1092
    }
1093

1094
    /**
1095
     * Updates a metadata classification on the specified file.
1096
     *
1097
     * @param classificationType the metadata classification type.
1098
     * @return the new metadata classification type updated on the file.
1099
     */
1100
    public String updateClassification(String classificationType) {
1101
        Metadata metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY);
1✔
1102
        metadata.replace(Metadata.CLASSIFICATION_KEY, classificationType);
1✔
1103
        Metadata classification = this.updateMetadata(metadata);
1✔
1104

1105
        return classification.getString(Metadata.CLASSIFICATION_KEY);
1✔
1106
    }
1107

1108
    /**
1109
     * Attempts to add classification to a file. If classification already exists then do update.
1110
     *
1111
     * @param classificationType the metadata classification type.
1112
     * @return the metadata classification type on the file.
1113
     */
1114
    public String setClassification(String classificationType) {
1115
        Metadata metadata = new Metadata().add(Metadata.CLASSIFICATION_KEY, classificationType);
1✔
1116
        Metadata classification;
1117

1118
        try {
1119
            classification = this.createMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise", metadata);
×
1120
        } catch (BoxAPIException e) {
1✔
1121
            if (e.getResponseCode() == 409) {
1✔
1122
                metadata = new Metadata("enterprise", Metadata.CLASSIFICATION_TEMPLATE_KEY);
1✔
1123
                metadata.replace(Metadata.CLASSIFICATION_KEY, classificationType);
1✔
1124
                classification = this.updateMetadata(metadata);
1✔
1125
            } else {
1126
                throw e;
1✔
1127
            }
1128
        }
×
1129

1130
        return classification.getString("/Box__Security__Classification__Key");
1✔
1131
    }
1132

1133
    /**
1134
     * Gets the classification type for the specified file.
1135
     *
1136
     * @return the metadata classification type on the file.
1137
     */
1138
    public String getClassification() {
1139
        Metadata metadata = this.getMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY);
1✔
1140
        return metadata.getString(Metadata.CLASSIFICATION_KEY);
1✔
1141
    }
1142

1143
    /**
1144
     * Deletes the classification on the file.
1145
     */
1146
    public void deleteClassification() {
1147
        this.deleteMetadata(Metadata.CLASSIFICATION_TEMPLATE_KEY, "enterprise");
1✔
1148
    }
1✔
1149

1150
    /**
1151
     * Creates an upload session to create a new file in chunks.
1152
     * This will first verify that the file can be created and then open a session for uploading pieces of the file.
1153
     *
1154
     * @param fileName the name of the file to be created
1155
     * @param fileSize the size of the file that will be uploaded
1156
     * @return the created upload session instance
1157
     */
1158
    public BoxFileUploadSession.Info createUploadSession(String fileName, long fileSize) {
1159

1160
        URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL());
×
1161
        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
×
1162

1163
        JsonObject body = new JsonObject();
×
1164
        body.add("folder_id", this.getID());
×
1165
        body.add("file_name", fileName);
×
1166
        body.add("file_size", fileSize);
×
1167
        request.setBody(body.toString());
×
1168

1169
        try (BoxJSONResponse response = request.send()) {
×
1170
            JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
×
1171

1172
            String sessionId = jsonObject.get("id").asString();
×
1173
            BoxFileUploadSession session = new BoxFileUploadSession(this.getAPI(), sessionId);
×
1174

1175
            return session.new Info(jsonObject);
×
1176
        }
1177
    }
1178

1179
    /**
1180
     * Creates a new file.
1181
     *
1182
     * @param inputStream the stream instance that contains the data.
1183
     * @param fileName    the name of the file to be created.
1184
     * @param fileSize    the size of the file that will be uploaded.
1185
     * @return the created file instance.
1186
     * @throws InterruptedException when a thread execution is interrupted.
1187
     * @throws IOException          when reading a stream throws exception.
1188
     */
1189
    public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize)
1190
        throws InterruptedException, IOException {
1191
        URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL());
1✔
1192
        this.canUpload(fileName, fileSize);
1✔
1193
        return new LargeFileUpload().
1✔
1194
            upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize);
1✔
1195
    }
1196

1197
    /**
1198
     * Creates a new file.  Also sets file attributes.
1199
     *
1200
     * @param inputStream    the stream instance that contains the data.
1201
     * @param fileName       the name of the file to be created.
1202
     * @param fileSize       the size of the file that will be uploaded.
1203
     * @param fileAttributes file attributes to set
1204
     * @return the created file instance.
1205
     * @throws InterruptedException when a thread execution is interrupted.
1206
     * @throws IOException          when reading a stream throws exception.
1207
     */
1208
    public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize,
1209
                                        Map<String, String> fileAttributes)
1210
        throws InterruptedException, IOException {
1211
        URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL());
1✔
1212
        this.canUpload(fileName, fileSize);
1✔
1213
        return new LargeFileUpload().
1✔
1214
            upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize, fileAttributes);
1✔
1215
    }
1216

1217
    /**
1218
     * Creates a new file using specified number of parallel http connections.
1219
     *
1220
     * @param inputStream          the stream instance that contains the data.
1221
     * @param fileName             the name of the file to be created.
1222
     * @param fileSize             the size of the file that will be uploaded.
1223
     * @param nParallelConnections number of parallel http connections to use
1224
     * @param timeOut              time to wait before killing the job
1225
     * @param unit                 time unit for the time wait value
1226
     * @return the created file instance.
1227
     * @throws InterruptedException when a thread execution is interrupted.
1228
     * @throws IOException          when reading a stream throws exception.
1229
     */
1230
    public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize,
1231
                                        int nParallelConnections, long timeOut, TimeUnit unit)
1232
        throws InterruptedException, IOException {
1233
        URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL());
×
1234
        this.canUpload(fileName, fileSize);
×
1235
        return new LargeFileUpload(nParallelConnections, timeOut, unit).
×
1236
            upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize);
×
1237
    }
1238

1239
    /**
1240
     * Creates a new file using specified number of parallel http connections.  Also sets file attributes.
1241
     *
1242
     * @param inputStream          the stream instance that contains the data.
1243
     * @param fileName             the name of the file to be created.
1244
     * @param fileSize             the size of the file that will be uploaded.
1245
     * @param nParallelConnections number of parallel http connections to use
1246
     * @param timeOut              time to wait before killing the job
1247
     * @param unit                 time unit for the time wait value
1248
     * @param fileAttributes       file attributes to set
1249
     * @return the created file instance.
1250
     * @throws InterruptedException when a thread execution is interrupted.
1251
     * @throws IOException          when reading a stream throws exception.
1252
     */
1253
    public BoxFile.Info uploadLargeFile(InputStream inputStream, String fileName, long fileSize,
1254
                                        int nParallelConnections, long timeOut, TimeUnit unit,
1255
                                        Map<String, String> fileAttributes)
1256
        throws InterruptedException, IOException {
1257
        URL url = UPLOAD_SESSION_URL_TEMPLATE.build(this.getAPI().getBaseUploadURL());
1✔
1258
        this.canUpload(fileName, fileSize);
1✔
1259
        return new LargeFileUpload(nParallelConnections, timeOut, unit).
1✔
1260
            upload(this.getAPI(), this.getID(), inputStream, url, fileName, fileSize, fileAttributes);
1✔
1261
    }
1262

1263
    /**
1264
     * Creates a new Metadata Cascade Policy on a folder.
1265
     *
1266
     * @param scope       the scope of the metadata cascade policy.
1267
     * @param templateKey the key of the template.
1268
     * @return information about the Metadata Cascade Policy.
1269
     */
1270
    public BoxMetadataCascadePolicy.Info addMetadataCascadePolicy(String scope, String templateKey) {
1271

1272
        return BoxMetadataCascadePolicy.create(this.getAPI(), this.getID(), scope, templateKey);
1✔
1273
    }
1274

1275
    /**
1276
     * Retrieves all Metadata Cascade Policies on a folder.
1277
     *
1278
     * @param fields optional fields to retrieve for cascade policies.
1279
     * @return the Iterable of Box Metadata Cascade Policies in your enterprise.
1280
     */
1281
    public Iterable<BoxMetadataCascadePolicy.Info> getMetadataCascadePolicies(String... fields) {
1282
        return BoxMetadataCascadePolicy.getAll(this.getAPI(), this.getID(), fields);
1✔
1283
    }
1284

1285
    /**
1286
     * Retrieves all Metadata Cascade Policies on a folder.
1287
     *
1288
     * @param enterpriseID the ID of the enterprise to retrieve cascade policies for.
1289
     * @param limit        the number of entries of cascade policies to retrieve.
1290
     * @param fields       optional fields to retrieve for cascade policies.
1291
     * @return the Iterable of Box Metadata Cascade Policies in your enterprise.
1292
     */
1293
    public Iterable<BoxMetadataCascadePolicy.Info> getMetadataCascadePolicies(String enterpriseID,
1294
                                                                              int limit, String... fields) {
1295

1296
        return BoxMetadataCascadePolicy.getAll(this.getAPI(), this.getID(), enterpriseID, limit, fields);
1✔
1297
    }
1298

1299
    /**
1300
     * Lock this folder.
1301
     *
1302
     * @return a created folder lock object.
1303
     */
1304
    public BoxFolderLock.Info lock() {
1305
        JsonObject folderObject = new JsonObject();
1✔
1306
        folderObject.add("type", "folder");
1✔
1307
        folderObject.add("id", this.getID());
1✔
1308

1309
        JsonObject lockedOperations = new JsonObject();
1✔
1310
        lockedOperations.add("move", true);
1✔
1311
        lockedOperations.add("delete", true);
1✔
1312

1313

1314
        JsonObject body = new JsonObject();
1✔
1315
        body.add("folder", folderObject);
1✔
1316
        body.add("locked_operations", lockedOperations);
1✔
1317

1318
        BoxJSONRequest request =
1✔
1319
            new BoxJSONRequest(this.getAPI(), FOLDER_LOCK_URL_TEMPLATE.build(this.getAPI().getBaseURL()),
1✔
1320
                "POST");
1321
        request.setBody(body.toString());
1✔
1322
        try (BoxJSONResponse response = request.send()) {
1✔
1323
            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
1✔
1324

1325
            BoxFolderLock createdFolderLock = new BoxFolderLock(this.getAPI(), responseJSON.get("id").asString());
1✔
1326
            return createdFolderLock.new Info(responseJSON);
1✔
1327
        }
1328
    }
1329

1330
    /**
1331
     * Get the lock on this folder.
1332
     *
1333
     * @return a folder lock object.
1334
     */
1335
    public Iterable<BoxFolderLock.Info> getLocks() {
1336
        String queryString = new QueryStringBuilder().appendParam("folder_id", this.getID()).toString();
1✔
1337
        final BoxAPIConnection api = this.getAPI();
1✔
1338
        return new BoxResourceIterable<BoxFolderLock.Info>(api,
1✔
1339
            FOLDER_LOCK_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), queryString), 100) {
1✔
1340
            @Override
1341
            protected BoxFolderLock.Info factory(JsonObject jsonObject) {
1342
                BoxFolderLock folderLock =
1✔
1343
                    new BoxFolderLock(api, jsonObject.get("id").asString());
1✔
1344
                return folderLock.new Info(jsonObject);
1✔
1345
            }
1346
        };
1347
    }
1348

1349
    /**
1350
     * Used to specify what direction to sort and display results.
1351
     */
1352
    public enum SortDirection {
1✔
1353
        /**
1354
         * ASC for ascending order.
1355
         */
1356
        ASC,
1✔
1357

1358
        /**
1359
         * DESC for descending order.
1360
         */
1361
        DESC
1✔
1362
    }
1363

1364
    /**
1365
     * Enumerates the possible sync states that a folder can have.
1366
     */
1367
    public enum SyncState {
×
1368
        /**
1369
         * The folder is synced.
1370
         */
1371
        SYNCED("synced"),
×
1372

1373
        /**
1374
         * The folder is not synced.
1375
         */
1376
        NOT_SYNCED("not_synced"),
×
1377

1378
        /**
1379
         * The folder is partially synced.
1380
         */
1381
        PARTIALLY_SYNCED("partially_synced");
×
1382

1383
        private final String jsonValue;
1384

1385
        SyncState(String jsonValue) {
×
1386
            this.jsonValue = jsonValue;
×
1387
        }
×
1388

1389
        static SyncState fromJSONValue(String jsonValue) {
NEW
1390
            return SyncState.valueOf(jsonValue.toUpperCase(java.util.Locale.ROOT));
×
1391
        }
1392

1393
        String toJSONValue() {
1394
            return this.jsonValue;
×
1395
        }
1396
    }
1397

1398
    /**
1399
     * Enumerates the possible permissions that a user can have on a folder.
1400
     */
1401
    public enum Permission {
1✔
1402
        /**
1403
         * The user can download the folder.
1404
         */
1405
        CAN_DOWNLOAD("can_download"),
1✔
1406

1407
        /**
1408
         * The user can upload to the folder.
1409
         */
1410
        CAN_UPLOAD("can_upload"),
1✔
1411

1412
        /**
1413
         * The user can rename the folder.
1414
         */
1415
        CAN_RENAME("can_rename"),
1✔
1416

1417
        /**
1418
         * The user can delete the folder.
1419
         */
1420
        CAN_DELETE("can_delete"),
1✔
1421

1422
        /**
1423
         * The user can share the folder.
1424
         */
1425
        CAN_SHARE("can_share"),
1✔
1426

1427
        /**
1428
         * The user can invite collaborators to the folder.
1429
         */
1430
        CAN_INVITE_COLLABORATOR("can_invite_collaborator"),
1✔
1431

1432
        /**
1433
         * The user can set the access level for shared links to the folder.
1434
         */
1435
        CAN_SET_SHARE_ACCESS("can_set_share_access");
1✔
1436

1437
        private final String jsonValue;
1438

1439
        Permission(String jsonValue) {
1✔
1440
            this.jsonValue = jsonValue;
1✔
1441
        }
1✔
1442

1443
        static Permission fromJSONValue(String jsonValue) {
1444
            return Permission.valueOf(jsonValue.toUpperCase(java.util.Locale.ROOT));
1✔
1445
        }
1446

1447
        String toJSONValue() {
1448
            return this.jsonValue;
×
1449
        }
1450
    }
1451

1452
    /**
1453
     * Contains information about a BoxFolder.
1454
     */
1455
    public class Info extends BoxItem.Info {
1456
        private BoxUploadEmail uploadEmail;
1457
        private boolean hasCollaborations;
1458
        private SyncState syncState;
1459
        private EnumSet<Permission> permissions;
1460
        private boolean canNonOwnersInvite;
1461
        private boolean isWatermarked;
1462
        private boolean isCollaborationRestrictedToEnterprise;
1463
        private boolean isExternallyOwned;
1464
        private Map<String, Map<String, Metadata>> metadataMap;
1465
        private List<String> allowedSharedLinkAccessLevels;
1466
        private List<String> allowedInviteeRoles;
1467
        private BoxClassification classification;
1468

1469
        private boolean isAccessibleViaSharedLink;
1470
        private boolean canNonOwnersViewCollaborators;
1471

1472
        /**
1473
         * Constructs an empty Info object.
1474
         */
1475
        public Info() {
1✔
1476
            super();
1✔
1477
        }
1✔
1478

1479
        /**
1480
         * Constructs an Info object by parsing information from a JSON string.
1481
         *
1482
         * @param json the JSON string to parse.
1483
         */
1484
        public Info(String json) {
1✔
1485
            super(json);
1✔
1486
        }
1✔
1487

1488
        /**
1489
         * Constructs an Info object using an already parsed JSON object.
1490
         *
1491
         * @param jsonObject the parsed JSON object.
1492
         */
1493
        public Info(JsonObject jsonObject) {
1✔
1494
            super(jsonObject);
1✔
1495
        }
1✔
1496

1497
        /**
1498
         * Gets the upload email for the folder.
1499
         *
1500
         * @return the upload email for the folder.
1501
         */
1502
        public BoxUploadEmail getUploadEmail() {
1503
            return this.uploadEmail;
×
1504
        }
1505

1506
        /**
1507
         * Sets the upload email for the folder.
1508
         *
1509
         * @param uploadEmail the upload email for the folder.
1510
         */
1511
        public void setUploadEmail(BoxUploadEmail uploadEmail) {
1512
            if (this.uploadEmail == uploadEmail) {
×
1513
                return;
×
1514
            }
1515

1516
            this.removeChildObject("folder_upload_email");
×
1517
            this.uploadEmail = uploadEmail;
×
1518

1519
            if (uploadEmail == null) {
×
1520
                this.addPendingChange("folder_upload_email", (String) null);
×
1521
            } else {
1522
                this.addChildObject("folder_upload_email", uploadEmail);
×
1523
            }
1524
        }
×
1525

1526
        /**
1527
         * Gets whether or not the folder has any collaborations.
1528
         *
1529
         * @return true if the folder has collaborations; otherwise false.
1530
         */
1531
        public boolean getHasCollaborations() {
1532
            return this.hasCollaborations;
×
1533
        }
1534

1535
        /**
1536
         * Gets the sync state of the folder.
1537
         *
1538
         * @return the sync state of the folder.
1539
         */
1540
        public SyncState getSyncState() {
1541
            return this.syncState;
×
1542
        }
1543

1544
        /**
1545
         * Sets the sync state of the folder.
1546
         *
1547
         * @param syncState the sync state of the folder.
1548
         */
1549
        public void setSyncState(SyncState syncState) {
1550
            this.syncState = syncState;
×
1551
            this.addPendingChange("sync_state", syncState.toJSONValue());
×
1552
        }
×
1553

1554
        /**
1555
         * Gets the permissions that the current user has on the folder.
1556
         *
1557
         * @return the permissions that the current user has on the folder.
1558
         */
1559
        public EnumSet<Permission> getPermissions() {
1560
            return this.permissions;
1✔
1561
        }
1562

1563
        /**
1564
         * Gets whether or not the non-owners can invite collaborators to the folder.
1565
         *
1566
         * @return [description]
1567
         */
1568
        public boolean getCanNonOwnersInvite() {
1569
            return this.canNonOwnersInvite;
×
1570
        }
1571

1572
        /**
1573
         * Sets whether or not non-owners can invite collaborators to the folder.
1574
         *
1575
         * @param canNonOwnersInvite indicates non-owners can invite collaborators to the folder.
1576
         */
1577
        public void setCanNonOwnersInvite(boolean canNonOwnersInvite) {
1578
            this.canNonOwnersInvite = canNonOwnersInvite;
×
1579
            this.addPendingChange("can_non_owners_invite", canNonOwnersInvite);
×
1580
        }
×
1581

1582
        /**
1583
         * Gets whether future collaborations should be restricted to within the enterprise only.
1584
         *
1585
         * @return indicates whether collaboration is restricted to enterprise only.
1586
         */
1587
        public boolean getIsCollaborationRestrictedToEnterprise() {
1588
            return this.isCollaborationRestrictedToEnterprise;
1✔
1589
        }
1590

1591
        /**
1592
         * Sets whether future collaborations should be restricted to within the enterprise only.
1593
         *
1594
         * @param isRestricted indicates whether there is collaboration restriction within enterprise.
1595
         */
1596
        public void setIsCollaborationRestrictedToEnterprise(boolean isRestricted) {
1597
            this.isCollaborationRestrictedToEnterprise = isRestricted;
1✔
1598
            this.addPendingChange("is_collaboration_restricted_to_enterprise", isRestricted);
1✔
1599
        }
1✔
1600

1601
        /**
1602
         * Retrieves the allowed roles for collaborations.
1603
         *
1604
         * @return the roles allowed for collaboration.
1605
         */
1606
        public List<String> getAllowedInviteeRoles() {
1607
            return this.allowedInviteeRoles;
1✔
1608
        }
1609

1610
        /**
1611
         * Retrieves the allowed access levels for a shared link.
1612
         *
1613
         * @return the allowed access levels for a shared link.
1614
         */
1615
        public List<String> getAllowedSharedLinkAccessLevels() {
1616
            return this.allowedSharedLinkAccessLevels;
1✔
1617
        }
1618

1619
        /**
1620
         * Gets flag indicating whether this file is Watermarked.
1621
         *
1622
         * @return whether the file is watermarked or not
1623
         */
1624
        public boolean getIsWatermarked() {
1625
            return this.isWatermarked;
×
1626
        }
1627

1628
        /**
1629
         * Gets the metadata on this folder associated with a specified scope and template.
1630
         * Makes an attempt to get metadata that was retrieved using getInfo(String ...) method.
1631
         *
1632
         * @param templateName the metadata template type name.
1633
         * @param scope        the scope of the template (usually "global" or "enterprise").
1634
         * @return the metadata returned from the server.
1635
         */
1636
        public Metadata getMetadata(String templateName, String scope) {
1637
            try {
1638
                return this.metadataMap.get(scope).get(templateName);
1✔
1639
            } catch (NullPointerException e) {
×
1640
                return null;
×
1641
            }
1642
        }
1643

1644
        /**
1645
         * Get the field is_externally_owned determining whether this folder is owned by a user outside of the
1646
         * enterprise.
1647
         *
1648
         * @return a boolean indicating whether this folder is owned by a user outside the enterprise.
1649
         */
1650
        public boolean getIsExternallyOwned() {
1651
            return this.isExternallyOwned;
1✔
1652
        }
1653

1654
        /**
1655
         * Gets the metadata classification type of this folder.
1656
         *
1657
         * @return the metadata classification type of this folder.
1658
         */
1659
        public BoxClassification getClassification() {
1660
            return this.classification;
1✔
1661
        }
1662

1663
        /**
1664
         * Returns the flag indicating whether the folder is accessible via a shared link.
1665
         *
1666
         * @return boolean flag indicating whether the folder is accessible via a shared link.
1667
         */
1668
        public boolean getIsAccessibleViaSharedLink() {
1669
            return this.isAccessibleViaSharedLink;
1✔
1670
        }
1671

1672
        /**
1673
         * Returns the flag indicating if collaborators who are not owners of this folder
1674
         * are restricted from viewing other collaborations on this folder.
1675
         *
1676
         * @return boolean flag indicating if collaborators who are not owners of this folder
1677
         * are restricted from viewing other collaborations on this folder.
1678
         */
1679
        public boolean getCanNonOwnersViewCollaborators() {
1680
            return this.canNonOwnersViewCollaborators;
1✔
1681
        }
1682

1683
        /**
1684
         * Sets whether collaborators who are not owners of this folder
1685
         * are restricted from viewing other collaborations on this folder.
1686
         *
1687
         * @param canNonOwnersViewCollaborators indicates if collaborators who are not owners of this folder
1688
         * are restricted from viewing other collaborations on this folderr.
1689
         */
1690
        public void setCanNonOwnersViewCollaborators(boolean canNonOwnersViewCollaborators) {
1691
            this.canNonOwnersViewCollaborators = canNonOwnersViewCollaborators;
×
1692
            this.addPendingChange("can_non_owners_view_collaborators", canNonOwnersViewCollaborators);
×
1693
        }
×
1694

1695

1696
        @Override
1697
        public BoxFolder getResource() {
1698
            return BoxFolder.this;
1✔
1699
        }
1700

1701
        @Override
1702
        protected void parseJSONMember(JsonObject.Member member) {
1703
            super.parseJSONMember(member);
1✔
1704

1705
            String memberName = member.getName();
1✔
1706
            JsonValue value = member.getValue();
1✔
1707
            try {
1708
                switch (memberName) {
1✔
1709
                    case "folder_upload_email":
1710
                        if (this.uploadEmail == null) {
×
1711
                            this.uploadEmail = new BoxUploadEmail(value.asObject());
×
1712
                        } else {
1713
                            this.uploadEmail.update(value.asObject());
×
1714
                        }
1715
                        break;
×
1716
                    case "has_collaborations":
1717
                        this.hasCollaborations = value.asBoolean();
×
1718
                        break;
×
1719
                    case "sync_state":
1720
                        this.syncState = SyncState.fromJSONValue(value.asString());
×
1721
                        break;
×
1722
                    case "permissions":
1723
                        this.permissions = this.parsePermissions(value.asObject());
1✔
1724
                        break;
1✔
1725
                    case "can_non_owners_invite":
1726
                        this.canNonOwnersInvite = value.asBoolean();
×
1727
                        break;
×
1728
                    case "allowed_shared_link_access_levels":
1729
                        this.allowedSharedLinkAccessLevels = this.parseSharedLinkAccessLevels(value.asArray());
1✔
1730
                        break;
1✔
1731
                    case "allowed_invitee_roles":
1732
                        this.allowedInviteeRoles = this.parseAllowedInviteeRoles(value.asArray());
1✔
1733
                        break;
1✔
1734
                    case "is_collaboration_restricted_to_enterprise":
1735
                        this.isCollaborationRestrictedToEnterprise = value.asBoolean();
1✔
1736
                        break;
1✔
1737
                    case "is_externally_owned":
1738
                        this.isExternallyOwned = value.asBoolean();
1✔
1739
                        break;
1✔
1740
                    case "watermark_info":
1741
                        this.isWatermarked = value.asObject().get("is_watermarked").asBoolean();
×
1742
                        break;
×
1743
                    case "metadata":
1744
                        this.metadataMap = Parsers.parseAndPopulateMetadataMap(value.asObject());
1✔
1745
                        break;
1✔
1746
                    case "classification":
1747
                        if (value.isNull()) {
1✔
1748
                            this.classification = null;
×
1749
                        } else {
1750
                            this.classification = new BoxClassification(value.asObject());
1✔
1751
                        }
1752
                        break;
1✔
1753
                    case "is_accessible_via_shared_link":
1754
                        this.isAccessibleViaSharedLink = value.asBoolean();
1✔
1755
                        break;
1✔
1756
                    case "can_non_owners_view_collaborators":
1757
                        this.canNonOwnersViewCollaborators = value.asBoolean();
1✔
1758
                        break;
1✔
1759
                    default:
1760
                        break;
1761
                }
1762
            } catch (Exception e) {
×
1763
                throw new BoxDeserializationException(memberName, value.toString(), e);
×
1764
            }
1✔
1765
        }
1✔
1766

1767
        private EnumSet<Permission> parsePermissions(JsonObject jsonObject) {
1768
            EnumSet<Permission> permissions = EnumSet.noneOf(Permission.class);
1✔
1769
            for (JsonObject.Member member : jsonObject) {
1✔
1770
                JsonValue value = member.getValue();
1✔
1771
                if (value.isNull() || !value.asBoolean()) {
1✔
1772
                    continue;
×
1773
                }
1774

1775
                try {
1776
                    permissions.add(BoxFolder.Permission.fromJSONValue(member.getName()));
1✔
1777
                } catch (IllegalArgumentException ignored) {
×
1778
                    // If the permission is not recognized, we ignore it.
1779
                }
1✔
1780
            }
1✔
1781

1782
            return permissions;
1✔
1783
        }
1784

1785
        private List<String> parseSharedLinkAccessLevels(JsonArray jsonArray) {
1786
            List<String> accessLevels = new ArrayList<>(jsonArray.size());
1✔
1787
            for (JsonValue value : jsonArray) {
1✔
1788
                accessLevels.add(value.asString());
1✔
1789
            }
1✔
1790

1791
            return accessLevels;
1✔
1792
        }
1793

1794
        private List<String> parseAllowedInviteeRoles(JsonArray jsonArray) {
1795
            List<String> roles = new ArrayList<>(jsonArray.size());
1✔
1796
            for (JsonValue value : jsonArray) {
1✔
1797
                roles.add(value.asString());
1✔
1798
            }
1✔
1799

1800
            return roles;
1✔
1801
        }
1802
    }
1803
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc