001package com.box.sdk;
002
003import com.eclipsesource.json.Json;
004import com.eclipsesource.json.JsonArray;
005import com.eclipsesource.json.JsonObject;
006import com.eclipsesource.json.JsonValue;
007import java.net.URL;
008import java.util.ArrayList;
009import java.util.Date;
010import java.util.List;
011
012/**
013 * Represents a retention policy.
014 * A retention policy blocks permanent deletion of content for a specified amount of time.
015 * Admins can create retention policies and then later assign them to specific folders or their entire enterprise.
016 *
017 * @see <a href="https://developer.box.com/reference/resources/retention-policy/">Box retention policy</a>
018 *
019 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
020 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
021 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
022 */
023@BoxResourceType("retention_policy")
024public class BoxRetentionPolicy extends BoxResource {
025    /**
026     * The URL template used for operation with retention policies.
027     */
028    public static final URLTemplate RETENTION_POLICIES_URL_TEMPLATE = new URLTemplate("retention_policies");
029
030    /**
031     * The URL template used for operation with retention policy with given ID.
032     */
033    public static final URLTemplate POLICY_URL_TEMPLATE = new URLTemplate("retention_policies/%s");
034
035    /**
036     * The URL template used for operation with retention policy assignments.
037     */
038    public static final URLTemplate ASSIGNMENTS_URL_TEMPLATE = new URLTemplate("retention_policies/%s/assignments");
039
040    /**
041     * Will cause the content retained by the policy to be permanently deleted.
042     */
043    public static final String ACTION_PERMANENTLY_DELETE = "permanently_delete";
044
045    /**
046     * Will lift the retention policy from the content, allowing it to be deleted by users.
047     */
048    public static final String ACTION_REMOVE_RETENTION = "remove_retention";
049
050    /**
051     * Status corresponding to active retention policy.
052     */
053    public static final String STATUS_ACTIVE = "active";
054
055    /**
056     * Status corresponding to retired retention policy.
057     */
058    public static final String STATUS_RETIRED = "retired";
059
060    /**
061     * Type for finite retention policies. Finite retention policies has the duration.
062     */
063    private static final String TYPE_FINITE = "finite";
064
065    /**
066     * Type for indefinite retention policies. Indefinite retention policies can have only "remove_retention"
067     * assigned action.
068     */
069    private static final String TYPE_INDEFINITE = "indefinite";
070
071    /**
072     * The default limit of entries per response.
073     */
074    private static final int DEFAULT_LIMIT = 100;
075
076    /**
077     * Constructs a retention policy for a resource with a given ID.
078     *
079     * @param api the API connection to be used by the resource.
080     * @param id  the ID of the resource.
081     */
082    public BoxRetentionPolicy(BoxAPIConnection api, String id) {
083        super(api, id);
084    }
085
086    /**
087     * Used to create a new indefinite retention policy.
088     *
089     * @param api  the API connection to be used by the created user.
090     * @param name the name of the retention policy.
091     * @return the created retention policy's info.
092     */
093    public static BoxRetentionPolicy.Info createIndefinitePolicy(BoxAPIConnection api, String name) {
094        return createRetentionPolicy(api, name, TYPE_INDEFINITE, 0, ACTION_REMOVE_RETENTION);
095    }
096
097    /**
098     * Used to create a new indefinite retention policy with optional parameters.
099     *
100     * @param api            the API connection to be used by the created user.
101     * @param name           the name of the retention policy.
102     * @param optionalParams the optional parameters.
103     * @return the created retention policy's info.
104     */
105    public static BoxRetentionPolicy.Info createIndefinitePolicy(BoxAPIConnection api, String name,
106                                                                 RetentionPolicyParams optionalParams) {
107        return createRetentionPolicy(api, name, TYPE_INDEFINITE, 0, ACTION_REMOVE_RETENTION, optionalParams);
108    }
109
110    /**
111     * Used to create a new finite retention policy.
112     *
113     * @param api    the API connection to be used by the created user.
114     * @param name   the name of the retention policy.
115     * @param length the duration in days that the retention policy will be active for after being assigned to content.
116     * @param action the disposition action can be "permanently_delete" or "remove_retention".
117     * @return the created retention policy's info.
118     */
119    public static BoxRetentionPolicy.Info createFinitePolicy(BoxAPIConnection api, String name, int length,
120                                                             String action) {
121        return createRetentionPolicy(api, name, TYPE_FINITE, length, action);
122    }
123
124    /**
125     * Used to create a new finite retention policy with optional parameters.
126     *
127     * @param api            the API connection to be used by the created user.
128     * @param name           the name of the retention policy.
129     * @param length         the duration in days that the retention policy will be active for after being assigned to content.
130     * @param action         the disposition action can be "permanently_delete" or "remove_retention".
131     * @param optionalParams the optional parameters.
132     * @return the created retention policy's info.
133     */
134    public static BoxRetentionPolicy.Info createFinitePolicy(
135        BoxAPIConnection api,
136        String name,
137        int length,
138        String action,
139        RetentionPolicyParams optionalParams
140    ) {
141        return createRetentionPolicy(api, name, TYPE_FINITE, length, action, optionalParams);
142    }
143
144    /**
145     * Used to create a new retention policy.
146     *
147     * @param api    the API connection to be used by the created user.
148     * @param name   the name of the retention policy.
149     * @param type   the type of the retention policy. Can be "finite" or "indefinite".
150     * @param length the duration in days that the retention policy will be active for after being assigned to content.
151     * @param action the disposition action can be "permanently_delete" or "remove_retention".
152     * @return the created retention policy's info.
153     */
154    private static BoxRetentionPolicy.Info createRetentionPolicy(BoxAPIConnection api, String name, String type,
155                                                                 int length, String action) {
156        return createRetentionPolicy(api, name, type, length, action, null);
157    }
158
159    /**
160     * Used to create a new retention policy with optional parameters.
161     *
162     * @param api            the API connection to be used by the created user.
163     * @param name           the name of the retention policy.
164     * @param type           the type of the retention policy. Can be "finite" or "indefinite".
165     * @param length         the duration in days that the retention policy will be active for after being assigned to content.
166     * @param action         the disposition action can be "permanently_delete" or "remove_retention".
167     * @param optionalParams the optional parameters.
168     * @return the created retention policy's info.
169     */
170    private static BoxRetentionPolicy.Info createRetentionPolicy(
171        BoxAPIConnection api,
172        String name,
173        String type,
174        int length,
175        String action,
176        RetentionPolicyParams optionalParams
177    ) {
178        URL url = RETENTION_POLICIES_URL_TEMPLATE.build(api.getBaseURL());
179        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
180        JsonObject requestJSON = new JsonObject()
181            .add("policy_name", name)
182            .add("policy_type", type)
183            .add("disposition_action", action);
184        if (!type.equals(TYPE_INDEFINITE)) {
185            requestJSON.add("retention_length", length);
186        }
187        if (optionalParams != null) {
188            requestJSON.add("can_owner_extend_retention", optionalParams.getCanOwnerExtendRetention());
189            requestJSON.add("are_owners_notified", optionalParams.getAreOwnersNotified());
190
191            List<BoxUser.Info> customNotificationRecipients = optionalParams.getCustomNotificationRecipients();
192            if (customNotificationRecipients.size() > 0) {
193                JsonArray users = new JsonArray();
194                for (BoxUser.Info user : customNotificationRecipients) {
195                    JsonObject userJSON = new JsonObject()
196                        .add("type", "user")
197                        .add("id", user.getID());
198                    users.add(userJSON);
199                }
200                requestJSON.add("custom_notification_recipients", users);
201            }
202        }
203        request.setBody(requestJSON.toString());
204        BoxJSONResponse response = (BoxJSONResponse) request.send();
205        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
206        BoxRetentionPolicy createdPolicy = new BoxRetentionPolicy(api, responseJSON.get("id").asString());
207        return createdPolicy.new Info(responseJSON);
208    }
209
210    /**
211     * Returns all the retention policies.
212     *
213     * @param api    the API connection to be used by the resource.
214     * @param fields the fields to retrieve.
215     * @return an iterable with all the retention policies.
216     */
217    public static Iterable<BoxRetentionPolicy.Info> getAll(final BoxAPIConnection api, String... fields) {
218        return getAll(null, null, null, DEFAULT_LIMIT, api, fields);
219    }
220
221    /**
222     * Returns all the retention policies with specified filters.
223     *
224     * @param name   a name to filter the retention policies by. A trailing partial match search is performed.
225     *               Set to null if no name filtering is required.
226     * @param type   a policy type to filter the retention policies by. Set to null if no type filtering is required.
227     * @param userID a user id to filter the retention policies by. Set to null if no type filtering is required.
228     * @param limit  the limit of items per single response. The default value is 100.
229     * @param api    the API connection to be used by the resource.
230     * @param fields the fields to retrieve.
231     * @return an iterable with all the retention policies met search conditions.
232     */
233    public static Iterable<BoxRetentionPolicy.Info> getAll(
234        String name, String type, String userID, int limit, final BoxAPIConnection api, String... fields) {
235        QueryStringBuilder queryString = new QueryStringBuilder();
236        if (name != null) {
237            queryString.appendParam("policy_name", name);
238        }
239        if (type != null) {
240            queryString.appendParam("policy_type", type);
241        }
242        if (userID != null) {
243            queryString.appendParam("created_by_user_id", userID);
244        }
245        if (fields.length > 0) {
246            queryString.appendParam("fields", fields);
247        }
248        URL url = RETENTION_POLICIES_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), queryString.toString());
249        return new BoxResourceIterable<BoxRetentionPolicy.Info>(api, url, limit) {
250
251            @Override
252            protected BoxRetentionPolicy.Info factory(JsonObject jsonObject) {
253                BoxRetentionPolicy policy = new BoxRetentionPolicy(api, jsonObject.get("id").asString());
254                return policy.new Info(jsonObject);
255            }
256
257        };
258    }
259
260    /**
261     * Returns iterable with all folder assignments of this retention policy.
262     *
263     * @param fields the fields to retrieve.
264     * @return an iterable containing all folder assignments.
265     */
266    public Iterable<BoxRetentionPolicyAssignment.Info> getFolderAssignments(String... fields) {
267        return this.getFolderAssignments(DEFAULT_LIMIT, fields);
268    }
269
270    /**
271     * Returns iterable with all folder assignments of this retention policy.
272     *
273     * @param limit  the limit of entries per response. The default value is 100.
274     * @param fields the fields to retrieve.
275     * @return an iterable containing all folder assignments.
276     */
277    public Iterable<BoxRetentionPolicyAssignment.Info> getFolderAssignments(int limit, String... fields) {
278        return this.getAssignments(BoxRetentionPolicyAssignment.TYPE_FOLDER, limit, fields);
279    }
280
281    /**
282     * Returns iterable with all enterprise assignments of this retention policy.
283     *
284     * @param fields the fields to retrieve.
285     * @return an iterable containing all enterprise assignments.
286     */
287    public Iterable<BoxRetentionPolicyAssignment.Info> getEnterpriseAssignments(String... fields) {
288        return this.getEnterpriseAssignments(DEFAULT_LIMIT, fields);
289    }
290
291    /**
292     * Returns iterable with all enterprise assignments of this retention policy.
293     *
294     * @param limit  the limit of entries per response. The default value is 100.
295     * @param fields the fields to retrieve.
296     * @return an iterable containing all enterprise assignments.
297     */
298    public Iterable<BoxRetentionPolicyAssignment.Info> getEnterpriseAssignments(int limit, String... fields) {
299        return this.getAssignments(BoxRetentionPolicyAssignment.TYPE_ENTERPRISE, limit, fields);
300    }
301
302    /**
303     * Returns iterable with all assignments of this retention policy.
304     *
305     * @param fields the fields to retrieve.
306     * @return an iterable containing all assignments.
307     */
308    public Iterable<BoxRetentionPolicyAssignment.Info> getAllAssignments(String... fields) {
309        return this.getAllAssignments(DEFAULT_LIMIT, fields);
310    }
311
312    /**
313     * Returns iterable with all assignments of this retention policy.
314     *
315     * @param limit  the limit of entries per response. The default value is 100.
316     * @param fields the fields to retrieve.
317     * @return an iterable containing all assignments.
318     */
319    public Iterable<BoxRetentionPolicyAssignment.Info> getAllAssignments(int limit, String... fields) {
320        return this.getAssignments(null, limit, fields);
321    }
322
323    /**
324     * Returns iterable with all assignments of given type of this retention policy.
325     *
326     * @param type   the type of the retention policy assignment to retrieve. Can either be "folder" or "enterprise".
327     * @param limit  the limit of entries per response. The default value is 100.
328     * @param fields the fields to retrieve.
329     * @return an iterable containing all assignments of given type.
330     */
331    private Iterable<BoxRetentionPolicyAssignment.Info> getAssignments(String type, int limit, String... fields) {
332        QueryStringBuilder queryString = new QueryStringBuilder();
333        if (type != null) {
334            queryString.appendParam("type", type);
335        }
336        if (fields.length > 0) {
337            queryString.appendParam("fields", fields);
338        }
339        URL url = ASSIGNMENTS_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), queryString.toString(), getID());
340        return new BoxResourceIterable<BoxRetentionPolicyAssignment.Info>(getAPI(), url, limit) {
341
342            @Override
343            protected BoxRetentionPolicyAssignment.Info factory(JsonObject jsonObject) {
344                BoxRetentionPolicyAssignment assignment
345                    = new BoxRetentionPolicyAssignment(getAPI(), jsonObject.get("id").asString());
346                return assignment.new Info(jsonObject);
347            }
348
349        };
350    }
351
352    /**
353     * Assigns this retention policy to folder.
354     *
355     * @param folder the folder to assign policy to.
356     * @return info about created assignment.
357     */
358    public BoxRetentionPolicyAssignment.Info assignTo(BoxFolder folder) {
359        return BoxRetentionPolicyAssignment.createAssignmentToFolder(this.getAPI(), this.getID(), folder.getID());
360    }
361
362    /**
363     * Assigns this retention policy to the current enterprise.
364     *
365     * @return info about created assignment.
366     */
367    public BoxRetentionPolicyAssignment.Info assignToEnterprise() {
368        return BoxRetentionPolicyAssignment.createAssignmentToEnterprise(this.getAPI(), this.getID());
369    }
370
371    /**
372     * Assigns this retention policy to a metadata template, optionally with certain field values.
373     *
374     * @param templateID   the ID of the metadata template to apply to.
375     * @param fieldFilters optional field value filters.
376     * @return info about the created assignment.
377     */
378    public BoxRetentionPolicyAssignment.Info assignToMetadataTemplate(String templateID,
379                                                                      MetadataFieldFilter... fieldFilters) {
380        return BoxRetentionPolicyAssignment.createAssignmentToMetadata(this.getAPI(), this.getID(), templateID,
381            fieldFilters);
382    }
383
384    /**
385     * Updates the information about this retention policy with any info fields that have been modified locally.
386     *
387     * @param info the updated info.
388     */
389    public void updateInfo(BoxRetentionPolicy.Info info) {
390        URL url = POLICY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
391        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
392        request.setBody(info.getPendingChanges());
393        BoxJSONResponse response = (BoxJSONResponse) request.send();
394        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
395        info.update(responseJSON);
396    }
397
398    /**
399     * Returns information about this retention policy.
400     *
401     * @param fields the fields to retrieve.
402     * @return information about this retention policy.
403     */
404    public BoxRetentionPolicy.Info getInfo(String... fields) {
405        QueryStringBuilder builder = new QueryStringBuilder();
406        if (fields.length > 0) {
407            builder.appendParam("fields", fields);
408        }
409        URL url = POLICY_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID());
410        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
411        BoxJSONResponse response = (BoxJSONResponse) request.send();
412        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
413        return new Info(responseJSON);
414    }
415
416    /**
417     * Contains information about the retention policy.
418     */
419    public class Info extends BoxResource.Info {
420
421        /**
422         * @see #getPolicyName()
423         */
424        private String policyName;
425
426        /**
427         * @see #getPolicyType()
428         */
429        private String policyType;
430
431        /**
432         * @see #getRetentionLength()
433         */
434        private int retentionLength;
435
436        /**
437         * @see #getDispositionAction()
438         */
439        private String dispositionAction;
440
441        /**
442         * @see #getStatus()
443         */
444        private String status;
445
446        /**
447         * @see #getCreatedBy()
448         */
449        private BoxUser.Info createdBy;
450
451        /**
452         * @see #getCreatedAt()
453         */
454        private Date createdAt;
455
456        /**
457         * @see #getModifiedAt()
458         */
459        private Date modifiedAt;
460
461        /**
462         * @see #getCanOwnerExtendRetention()
463         */
464        private boolean canOwnerExtendRetention;
465
466        /**
467         * @see #getAreOwnersNotified()
468         */
469        private boolean areOwnersNotified;
470
471        private List<BoxUser.Info> customNotificationRecipients;
472
473        /**
474         * Constructs an empty Info object.
475         */
476        public Info() {
477            super();
478        }
479
480        /**
481         * Constructs an Info object by parsing information from a JSON string.
482         *
483         * @param json the JSON string to parse.
484         */
485        public Info(String json) {
486            super(json);
487        }
488
489        /**
490         * Constructs an Info object using an already parsed JSON object.
491         *
492         * @param jsonObject the parsed JSON object.
493         */
494        Info(JsonObject jsonObject) {
495            super(jsonObject);
496        }
497
498        /**
499         * {@inheritDoc}
500         */
501        @Override
502        public BoxResource getResource() {
503            return BoxRetentionPolicy.this;
504        }
505
506        /**
507         * Gets the name given to the retention policy.
508         *
509         * @return name given to the retention policy.
510         */
511        public String getPolicyName() {
512            return this.policyName;
513        }
514
515        /**
516         * Update the policy name to a new value.
517         *
518         * @param policyName the new policy name.
519         */
520        public void setPolicyName(String policyName) {
521            this.policyName = policyName;
522            this.addPendingChange("policy_name", policyName);
523        }
524
525        /**
526         * Gets the type of the retention policy.
527         * A retention policy type can either be "finite",
528         * where a specific amount of time to retain the content is known upfront,
529         * or "indefinite", where the amount of time to retain the content is still unknown.
530         *
531         * @return the type of the retention policy.
532         */
533        public String getPolicyType() {
534            return this.policyType;
535        }
536
537        /**
538         * Gets the length of the retention policy. This length specifies the duration
539         * in days that the retention policy will be active for after being assigned to content.
540         *
541         * @return the length of the retention policy.
542         */
543        public int getRetentionLength() {
544            return this.retentionLength;
545        }
546
547        /**
548         * Gets the disposition action of the retention policy.
549         * This action can be "permanently_delete", or "remove_retention".
550         *
551         * @return the disposition action of the retention policy.
552         */
553        public String getDispositionAction() {
554            return this.dispositionAction;
555        }
556
557        /**
558         * Set the action to take when retention period ends.
559         *
560         * @param dispositionAction the new action.
561         */
562        public void setDispositionAction(String dispositionAction) {
563            this.dispositionAction = dispositionAction;
564            this.addPendingChange("disposition_action", dispositionAction);
565        }
566
567        /**
568         * Gets the status of the retention policy.
569         * The status can be "active" or "retired".
570         *
571         * @return the status of the retention policy.
572         */
573        public String getStatus() {
574            return this.status;
575        }
576
577        /**
578         * Set the policy status.
579         *
580         * @param status the new status value.
581         */
582        public void setStatus(String status) {
583            this.status = status;
584            this.addPendingChange("status", status);
585        }
586
587        /**
588         * Gets info about the user created the retention policy.
589         *
590         * @return info about the user created the retention policy.
591         */
592        public BoxUser.Info getCreatedBy() {
593            return this.createdBy;
594        }
595
596        /**
597         * Gets the time that the retention policy was created.
598         *
599         * @return the time that the retention policy was created.
600         */
601        public Date getCreatedAt() {
602            return this.createdAt;
603        }
604
605        /**
606         * Gets the time that the retention policy was last modified.
607         *
608         * @return the time that the retention policy was last modified.
609         */
610        public Date getModifiedAt() {
611            return this.modifiedAt;
612        }
613
614        /**
615         * Gets the flag to denote that the owner of a retained file can extend the retention when near expiration.
616         *
617         * @return the boolean flag.
618         */
619        public boolean getCanOwnerExtendRetention() {
620            return this.canOwnerExtendRetention;
621        }
622
623        /**
624         * Gets the flag to denote that owners and co-owners of a retained file will get notified when near expiration.
625         *
626         * @return the boolean flag.
627         */
628        public boolean getAreOwnersNotified() {
629            return this.areOwnersNotified;
630        }
631
632        /**
633         * Gets the list of users to be notified of a retained file when near expiration.
634         *
635         * @return the list of users to be notified.
636         */
637        public List<BoxUser.Info> getCustomNotificationRecipients() {
638            return this.customNotificationRecipients;
639        }
640
641        /**
642         * {@inheritDoc}
643         */
644        @Override
645        void parseJSONMember(JsonObject.Member member) {
646            super.parseJSONMember(member);
647            String memberName = member.getName();
648            JsonValue value = member.getValue();
649            try {
650                if (memberName.equals("policy_name")) {
651                    this.policyName = value.asString();
652                } else if (memberName.equals("policy_type")) {
653                    this.policyType = value.asString();
654                } else if (memberName.equals("retention_length")) {
655                    int intVal;
656                    if (value.asString().equals(TYPE_INDEFINITE)) {
657                        intVal = -1;
658                    } else {
659                        intVal = Integer.parseInt(value.asString());
660                    }
661
662                    this.retentionLength = intVal;
663                } else if (memberName.equals("disposition_action")) {
664                    this.dispositionAction = value.asString();
665                } else if (memberName.equals("status")) {
666                    this.status = value.asString();
667                } else if (memberName.equals("created_by")) {
668                    JsonObject userJSON = value.asObject();
669                    if (this.createdBy == null) {
670                        String userID = userJSON.get("id").asString();
671                        BoxUser user = new BoxUser(getAPI(), userID);
672                        this.createdBy = user.new Info(userJSON);
673                    } else {
674                        this.createdBy.update(userJSON);
675                    }
676                } else if (memberName.equals("created_at")) {
677                    this.createdAt = BoxDateFormat.parse(value.asString());
678                } else if (memberName.equals("modified_at")) {
679                    this.modifiedAt = BoxDateFormat.parse(value.asString());
680                } else if (memberName.equals("can_owner_extend_retention")) {
681                    this.canOwnerExtendRetention = value.asBoolean();
682                } else if (memberName.equals("are_owners_notified")) {
683                    this.areOwnersNotified = value.asBoolean();
684                } else if (memberName.equals("custom_notification_recipients")) {
685                    List<BoxUser.Info> recipients = new ArrayList<BoxUser.Info>();
686                    for (JsonValue userJSON : value.asArray()) {
687                        String userID = userJSON.asObject().get("id").asString();
688                        BoxUser user = new BoxUser(getAPI(), userID);
689                        recipients.add(user.new Info(userJSON.asObject()));
690                    }
691                    this.customNotificationRecipients = recipients;
692                }
693            } catch (Exception e) {
694                throw new BoxDeserializationException(memberName, value.toString(), e);
695            }
696        }
697    }
698}