001package com.box.sdk; 002 003import java.net.URL; 004import java.text.ParseException; 005import java.util.Date; 006 007import com.eclipsesource.json.JsonObject; 008import com.eclipsesource.json.JsonValue; 009 010/** 011 * Represents a legal hold policy. Legal Hold Policy information describes the basic characteristics of the Policy, such 012 * as name, description, and filter dates. 013 * 014 * @see <a href="https://docs.box.com/reference#legal-holds-object">Box legal holds</a> 015 * 016 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked 017 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error 018 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p> 019 */ 020@BoxResourceType("legal_hold") 021public class BoxLegalHoldPolicy extends BoxResource { 022 /** 023 * Legal Hold URL Template. 024 */ 025 public static final URLTemplate LEGAL_HOLD_URL_TEMPLATE = new URLTemplate("legal_hold_policies/%s"); 026 /** 027 * All Legal Hold URL Template. 028 */ 029 public static final URLTemplate ALL_LEGAL_HOLD_URL_TEMPLATE = new URLTemplate("legal_hold_policies"); 030 /** 031 * Legal Hold Assignments URL Template. 032 */ 033 public static final URLTemplate LEGAL_HOLD_ASSIGNMENTS_URL_TEMPLATE 034 = new URLTemplate("legal_hold_policies/%s/assignments"); 035 /** 036 * List of File Version Holds URL Template. 037 */ 038 public static final URLTemplate LIST_OF_FILE_VERSION_HOLDS_URL_TEMPLATE 039 = new URLTemplate("file_version_legal_holds"); 040 private static final int DEFAULT_LIMIT = 100; 041 042 /** 043 * Constructs a BoxLegalHoldPolicy for a resource with a given ID. 044 * @param api the API connection to be used by the resource. 045 * @param id the ID of the resource. 046 */ 047 public BoxLegalHoldPolicy(BoxAPIConnection api, String id) { 048 super(api, id); 049 } 050 051 /** 052 * Gets information about the Legal Hold. 053 * @param fields the fields to retrieve. 054 * @return information about this legal hold policy. 055 */ 056 public Info getInfo(String ... fields) { 057 QueryStringBuilder builder = new QueryStringBuilder(); 058 if (fields.length > 0) { 059 builder.appendParam("fields", fields); 060 } 061 URL url = LEGAL_HOLD_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID()); 062 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET"); 063 BoxJSONResponse response = (BoxJSONResponse) request.send(); 064 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 065 return new Info(responseJSON); 066 } 067 068 /** 069 * Creates a new Legal Hold Policy. 070 * @param api the API connection to be used by the resource. 071 * @param name the name of Legal Hold Policy. 072 * @return information about the Legal Hold Policy created. 073 */ 074 public static BoxLegalHoldPolicy.Info create(BoxAPIConnection api, String name) { 075 return createOngoing(api, name, null); 076 } 077 078 /** 079 * Creates a new Legal Hold Policy. 080 * @param api the API connection to be used by the resource. 081 * @param name the name of Legal Hold Policy. 082 * @param description the description of Legal Hold Policy. 083 * @param filterStartedAt optional date filter applies to Custodian assignments only. 084 * @param filterEndedAt optional date filter applies to Custodian assignments only. 085 * @return information about the Legal Hold Policy created. 086 */ 087 public static BoxLegalHoldPolicy.Info create(BoxAPIConnection api, String name, String description, 088 Date filterStartedAt, Date filterEndedAt) { 089 URL url = ALL_LEGAL_HOLD_URL_TEMPLATE.build(api.getBaseURL()); 090 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 091 JsonObject requestJSON = new JsonObject() 092 .add("policy_name", name); 093 if (description != null) { 094 requestJSON.add("description", description); 095 } 096 if (filterStartedAt != null) { 097 requestJSON.add("filter_started_at", BoxDateFormat.format(filterStartedAt)); 098 } 099 if (filterEndedAt != null) { 100 requestJSON.add("filter_ended_at", BoxDateFormat.format(filterEndedAt)); 101 } 102 request.setBody(requestJSON.toString()); 103 BoxJSONResponse response = (BoxJSONResponse) request.send(); 104 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 105 BoxLegalHoldPolicy createdPolicy = new BoxLegalHoldPolicy(api, responseJSON.get("id").asString()); 106 return createdPolicy.new Info(responseJSON); 107 } 108 109 /** 110 * Creates a new ongoing Legal Hold Policy. 111 * @param api the API connection to be used by the resource. 112 * @param name the name of Legal Hold Policy. 113 * @param description the description of Legal Hold Policy. 114 * @return information about the Legal Hold Policy created. 115 */ 116 public static BoxLegalHoldPolicy.Info createOngoing(BoxAPIConnection api, String name, String description) { 117 URL url = ALL_LEGAL_HOLD_URL_TEMPLATE.build(api.getBaseURL()); 118 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 119 JsonObject requestJSON = new JsonObject() 120 .add("policy_name", name) 121 .add("is_ongoing", true); 122 if (description != null) { 123 requestJSON.add("description", description); 124 } 125 request.setBody(requestJSON.toString()); 126 BoxJSONResponse response = (BoxJSONResponse) request.send(); 127 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 128 BoxLegalHoldPolicy createdPolicy = new BoxLegalHoldPolicy(api, responseJSON.get("id").asString()); 129 return createdPolicy.new Info(responseJSON); 130 } 131 132 /** 133 * Deletes the legal hold policy. 134 */ 135 public void delete() { 136 URL url = LEGAL_HOLD_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 137 BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE"); 138 BoxAPIResponse response = request.send(); 139 response.disconnect(); 140 } 141 142 /** 143 * Updates the information about this retention policy with modified locally info. 144 * Only policy_name, description and release_notes can be modified. 145 * @param info the updated info. 146 */ 147 public void updateInfo(BoxLegalHoldPolicy.Info info) { 148 URL url = LEGAL_HOLD_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); 149 BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT"); 150 request.setBody(info.getPendingChanges()); 151 BoxJSONResponse response = (BoxJSONResponse) request.send(); 152 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 153 info.update(responseJSON); 154 } 155 156 /** 157 * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable. 158 * @param api api the API connection to be used by the resource. 159 * @return the Iterable of Legal Hold Policies in your Enterprise. 160 */ 161 public static Iterable<BoxLegalHoldPolicy.Info> getAll(final BoxAPIConnection api) { 162 return getAll(api, null, DEFAULT_LIMIT); 163 } 164 165 /** 166 * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable. 167 * @param api api the API connection to be used by the resource. 168 * @param policyName case insensitive prefix-match filter on Policy name. 169 * @param limit the limit of retrieved entries per page. 170 * @param fields the optional fields to retrieve. 171 * @return the Iterable of Legal Hold Policies in your Enterprise that match the filter parameters. 172 */ 173 public static Iterable<BoxLegalHoldPolicy.Info> getAll( 174 final BoxAPIConnection api, String policyName, int limit, String ... fields) { 175 QueryStringBuilder builder = new QueryStringBuilder(); 176 if (policyName != null) { 177 builder.appendParam("policy_name", policyName); 178 } 179 if (fields.length > 0) { 180 builder.appendParam("fields", fields); 181 } 182 return new BoxResourceIterable<BoxLegalHoldPolicy.Info>(api, 183 ALL_LEGAL_HOLD_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString()), 184 limit) { 185 186 @Override 187 protected BoxLegalHoldPolicy.Info factory(JsonObject jsonObject) { 188 BoxLegalHoldPolicy policy = new BoxLegalHoldPolicy(api, jsonObject.get("id").asString()); 189 return policy.new Info(jsonObject); 190 } 191 }; 192 } 193 194 /** 195 * Assigns this legal holds policy to the given box resource. 196 * Currently only {@link BoxFile}, {@link BoxFileVersion}, {@link BoxFolder} and {@link BoxUser} are supported. 197 * @param resource the box resource to assign legal hold policy to. 198 * @return info about created legal hold policy assignment. 199 */ 200 public BoxLegalHoldAssignment.Info assignTo(BoxResource resource) { 201 return BoxLegalHoldAssignment.create( 202 this.getAPI(), this.getID(), BoxResource.getResourceType(resource.getClass()), resource.getID()); 203 } 204 205 /** 206 * Returns iterable containing assignments for this single legal hold policy. 207 * @param fields the fields to retrieve. 208 * @return an iterable containing assignments for this single legal hold policy. 209 */ 210 public Iterable<BoxLegalHoldAssignment.Info> getAssignments(String ... fields) { 211 return this.getAssignments(null, null, DEFAULT_LIMIT, fields); 212 } 213 214 /** 215 * Returns iterable containing assignments for this single legal hold policy. 216 * Parameters can be used to filter retrieved assignments. 217 * @param type filter assignments of this type only. 218 * Can be "file_version", "file", "folder", "user" or null if no type filter is necessary. 219 * @param id filter assignments to this ID only. Can be null if no id filter is necessary. 220 * @param limit the limit of entries per page. Default limit is 100. 221 * @param fields the fields to retrieve. 222 * @return an iterable containing assignments for this single legal hold policy. 223 */ 224 public Iterable<BoxLegalHoldAssignment.Info> getAssignments(String type, String id, int limit, String ... fields) { 225 QueryStringBuilder builder = new QueryStringBuilder(); 226 if (type != null) { 227 builder.appendParam("assign_to_type", type); 228 } 229 if (id != null) { 230 builder.appendParam("assign_to_id", id); 231 } 232 if (fields.length > 0) { 233 builder.appendParam("fields", fields); 234 } 235 return new BoxResourceIterable<BoxLegalHoldAssignment.Info>( 236 this.getAPI(), LEGAL_HOLD_ASSIGNMENTS_URL_TEMPLATE.buildWithQuery( 237 this.getAPI().getBaseURL(), builder.toString(), this.getID()), limit) { 238 239 @Override 240 protected BoxLegalHoldAssignment.Info factory(JsonObject jsonObject) { 241 BoxLegalHoldAssignment assignment = new BoxLegalHoldAssignment( 242 BoxLegalHoldPolicy.this.getAPI(), jsonObject.get("id").asString()); 243 return assignment.new Info(jsonObject); 244 } 245 }; 246 } 247 248 /** 249 * Returns iterable with all non-deleted file version legal holds for this legal hold policy. 250 * @param fields the fields to retrieve. 251 * @return an iterable containing file version legal holds info. 252 */ 253 public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(String ... fields) { 254 return this.getFileVersionHolds(DEFAULT_LIMIT, fields); 255 } 256 257 /** 258 * Returns iterable with all non-deleted file version legal holds for this legal hold policy. 259 * @param limit the limit of entries per response. The default value is 100. 260 * @param fields the fields to retrieve. 261 * @return an iterable containing file version legal holds info. 262 */ 263 public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(int limit, String ... fields) { 264 QueryStringBuilder queryString = new QueryStringBuilder().appendParam("policy_id", this.getID()); 265 if (fields.length > 0) { 266 queryString.appendParam("fields", fields); 267 } 268 URL url = LIST_OF_FILE_VERSION_HOLDS_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), queryString.toString()); 269 return new BoxResourceIterable<BoxFileVersionLegalHold.Info>(getAPI(), url, limit) { 270 271 @Override 272 protected BoxFileVersionLegalHold.Info factory(JsonObject jsonObject) { 273 BoxFileVersionLegalHold assignment 274 = new BoxFileVersionLegalHold(getAPI(), jsonObject.get("id").asString()); 275 return assignment.new Info(jsonObject); 276 } 277 278 }; 279 } 280 281 /** 282 * Contains information about the legal hold policy. 283 */ 284 public class Info extends BoxResource.Info { 285 286 /** 287 * @see #getPolicyName() 288 */ 289 private String policyName; 290 291 /** 292 * @see #getDescription() 293 */ 294 private String description; 295 296 /** 297 * @see #getStatus() 298 */ 299 private String status; 300 301 /** 302 * @see #getAssignmentCountUser() 303 */ 304 private int assignmentCountUser; 305 306 /** 307 * @see #getAssignmentCountFolder() 308 */ 309 private int assignmentCountFolder; 310 311 /** 312 * @see #getAssignmentCountFile() 313 */ 314 private int assignmentCountFile; 315 316 /** 317 * @see #getAssignmentCountFileVersion() 318 */ 319 private int assignmentCountFileVersion; 320 321 /** 322 * @see #getCreatedAt() 323 */ 324 private BoxUser.Info createdBy; 325 326 /** 327 * @see #getCreatedAt() 328 */ 329 private Date createdAt; 330 331 /** 332 * @see #getModifiedAt() 333 */ 334 private Date modifiedAt; 335 336 /** 337 * @see #getDeletedAt() 338 */ 339 private Date deletedAt; 340 341 /** 342 * @see #getFilterStartedAt() 343 */ 344 private Date filterStartedAt; 345 346 /** 347 * @see #getFilterEndedAt() 348 */ 349 private Date filterEndedAt; 350 351 /** 352 * @see #getReleaseNotes() 353 */ 354 private String releaseNotes; 355 356 /** 357 * @see #getIsOngoing() 358 */ 359 private Boolean isOngoing; 360 361 /** 362 * Constructs an empty Info object. 363 */ 364 public Info() { 365 super(); 366 } 367 368 /** 369 * Constructs an Info object by parsing information from a JSON string. 370 * @param json the JSON string to parse. 371 */ 372 public Info(String json) { 373 super(json); 374 } 375 376 /** 377 * Constructs an Info object using an already parsed JSON object. 378 * @param jsonObject the parsed JSON object. 379 */ 380 Info(JsonObject jsonObject) { 381 super(jsonObject); 382 } 383 384 /** 385 * {@inheritDoc} 386 */ 387 @Override 388 public BoxResource getResource() { 389 return BoxLegalHoldPolicy.this; 390 } 391 392 /** 393 * @return the name of the policy. 394 */ 395 public String getPolicyName() { 396 return this.policyName; 397 } 398 399 /** 400 * @return the description of the policy. 401 */ 402 public String getDescription() { 403 return this.description; 404 } 405 406 /** 407 * Status can be "active", "applying", "releasing" or "released". 408 * @return the status of the policy. 409 */ 410 public String getStatus() { 411 return this.status; 412 } 413 414 /** 415 * @return count of users this policy assigned to. 416 */ 417 public int getAssignmentCountUser() { 418 return this.assignmentCountUser; 419 } 420 421 /** 422 * @return count of folders this policy assigned to. 423 */ 424 public int getAssignmentCountFolder() { 425 return this.assignmentCountFolder; 426 } 427 428 /** 429 * @return count of files this policy assigned to. 430 */ 431 public int getAssignmentCountFile() { 432 return this.assignmentCountFile; 433 } 434 435 /** 436 * @return count of file versions this policy assigned to. 437 */ 438 public int getAssignmentCountFileVersion() { 439 return this.assignmentCountFileVersion; 440 } 441 442 /** 443 * @return info about the user who created this policy. 444 */ 445 public BoxUser.Info getCreatedBy() { 446 return this.createdBy; 447 } 448 449 /** 450 * @return time the policy was created. 451 */ 452 public Date getCreatedAt() { 453 return this.createdAt; 454 } 455 456 /** 457 * @return time the policy was modified. 458 */ 459 public Date getModifiedAt() { 460 return this.modifiedAt; 461 } 462 463 /** 464 * @return time that the policy release request was sent. 465 */ 466 public Date getDeletedAt() { 467 return this.deletedAt; 468 } 469 470 /** 471 * @return optional date filter applies to Custodian assignments only. 472 */ 473 public Date getFilterStartedAt() { 474 return this.filterStartedAt; 475 } 476 477 /** 478 * @return optional date filter applies to Custodian assignments only. 479 */ 480 public Date getFilterEndedAt() { 481 return this.filterEndedAt; 482 } 483 484 /** 485 * @return notes around why the policy was released. 486 */ 487 public String getReleaseNotes() { 488 return this.releaseNotes; 489 } 490 491 /** 492 * @return boolean indicating whether the policy will continue applying to files based on events, indefinitely. 493 */ 494 public Boolean getIsOngoing() { 495 return this.isOngoing; 496 } 497 498 /** 499 * {@inheritDoc} 500 */ 501 @Override 502 void parseJSONMember(JsonObject.Member member) { 503 super.parseJSONMember(member); 504 String memberName = member.getName(); 505 JsonValue value = member.getValue(); 506 try { 507 if (memberName.equals("policy_name")) { 508 this.policyName = value.asString(); 509 } else if (memberName.equals("description")) { 510 this.description = value.asString(); 511 } else if (memberName.equals("status")) { 512 this.status = value.asString(); 513 } else if (memberName.equals("release_notes")) { 514 this.releaseNotes = value.asString(); 515 } else if (memberName.equals("assignment_counts")) { 516 JsonObject countsJSON = value.asObject(); 517 this.assignmentCountUser = countsJSON.get("user").asInt(); 518 this.assignmentCountFolder = countsJSON.get("folder").asInt(); 519 this.assignmentCountFile = countsJSON.get("file").asInt(); 520 this.assignmentCountFileVersion = countsJSON.get("file_version").asInt(); 521 } else if (memberName.equals("created_by")) { 522 JsonObject userJSON = value.asObject(); 523 if (this.createdBy == null) { 524 String userID = userJSON.get("id").asString(); 525 BoxUser user = new BoxUser(getAPI(), userID); 526 this.createdBy = user.new Info(userJSON); 527 } else { 528 this.createdBy.update(userJSON); 529 } 530 } else if (memberName.equals("created_at")) { 531 this.createdAt = BoxDateFormat.parse(value.asString()); 532 } else if (memberName.equals("modified_at")) { 533 this.modifiedAt = BoxDateFormat.parse(value.asString()); 534 } else if (memberName.equals("deleted_at")) { 535 this.deletedAt = BoxDateFormat.parse(value.asString()); 536 } else if (memberName.equals("filter_started_at")) { 537 this.filterStartedAt = BoxDateFormat.parse(value.asString()); 538 } else if (memberName.equals("filter_ended_at")) { 539 this.filterEndedAt = BoxDateFormat.parse(value.asString()); 540 } else if (memberName.equals("is_ongoing")) { 541 this.isOngoing = value.asBoolean(); 542 } 543 } catch (ParseException e) { 544 assert false : "A ParseException indicates a bug in the SDK."; 545 } 546 } 547 } 548}