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