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.List; 010 011/** 012 * The MetadataTemplate class represents the Box metadata template object. 013 * Templates allow the metadata service to provide a multitude of services, 014 * such as pre-defining sets of key:value pairs or schema enforcement on specific fields. 015 * 016 * @see <a href="https://developer.box.com/reference/resources/metadata-templates/">Box metadata templates</a> 017 */ 018public class MetadataTemplate extends BoxJSONObject { 019 020 /** 021 * @see #getMetadataTemplate(BoxAPIConnection) 022 */ 023 public static final URLTemplate METADATA_TEMPLATE_URL_TEMPLATE 024 = new URLTemplate("metadata_templates/%s/%s/schema"); 025 026 /** 027 * @see #getMetadataTemplateByID(BoxAPIConnection, String) 028 */ 029 public static final URLTemplate METADATA_TEMPLATE_BY_ID_URL_TEMPLATE = new URLTemplate("metadata_templates/%s"); 030 031 /** 032 * @see #createMetadataTemplate(BoxAPIConnection, String, String, String, boolean, List) 033 */ 034 public static final URLTemplate METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE 035 = new URLTemplate("metadata_templates/schema"); 036 037 /** 038 * @see #getEnterpriseMetadataTemplates(String, int, BoxAPIConnection, String...) 039 */ 040 public static final URLTemplate ENTERPRISE_METADATA_URL_TEMPLATE = new URLTemplate("metadata_templates/%s"); 041 042 /** 043 * 044 */ 045 private static final URLTemplate METADATA_QUERIES_URL_TEMPLATE = new URLTemplate("metadata_queries/execute_read"); 046 047 /** 048 * Default metadata type to be used in query. 049 */ 050 private static final String DEFAULT_METADATA_TYPE = "properties"; 051 052 /** 053 * Global metadata scope. Used by default if the metadata type is "properties". 054 */ 055 private static final String GLOBAL_METADATA_SCOPE = "global"; 056 057 /** 058 * Enterprise metadata scope. Used by default if the metadata type is not "properties". 059 */ 060 private static final String ENTERPRISE_METADATA_SCOPE = "enterprise"; 061 062 /** 063 * Default number of entries per page. 064 */ 065 private static final int DEFAULT_ENTRIES_LIMIT = 100; 066 067 /** 068 * @see #getID() 069 */ 070 private String id; 071 072 /** 073 * @see #getTemplateKey() 074 */ 075 private String templateKey; 076 077 /** 078 * @see #getScope() 079 */ 080 private String scope; 081 082 /** 083 * @see #getDisplayName() 084 */ 085 private String displayName; 086 087 /** 088 * @see #getIsHidden() 089 */ 090 private Boolean isHidden; 091 092 /** 093 * @see #getFields() 094 */ 095 private List<Field> fields; 096 097 /** 098 * @see #getCopyInstanceOnItemCopy() 099 */ 100 private Boolean copyInstanceOnItemCopy; 101 102 /** 103 * Constructs an empty metadata template. 104 */ 105 public MetadataTemplate() { 106 super(); 107 } 108 109 /** 110 * Constructs a metadata template from a JSON string. 111 * 112 * @param json the json encoded metadate template. 113 */ 114 public MetadataTemplate(String json) { 115 super(json); 116 } 117 118 /** 119 * Constructs a metadate template from a JSON object. 120 * 121 * @param jsonObject the json encoded metadate template. 122 */ 123 MetadataTemplate(JsonObject jsonObject) { 124 super(jsonObject); 125 } 126 127 /** 128 * Creates new metadata template. 129 * 130 * @param api the API connection to be used. 131 * @param scope the scope of the object. 132 * @param templateKey a unique identifier for the template. 133 * @param displayName the display name of the field. 134 * @param hidden whether this template is hidden in the UI. 135 * @param fields the ordered set of fields for the template 136 * @return the metadata template returned from the server. 137 */ 138 public static MetadataTemplate createMetadataTemplate( 139 BoxAPIConnection api, 140 String scope, 141 String templateKey, 142 String displayName, 143 boolean hidden, 144 List<Field> fields 145 ) { 146 return createMetadataTemplate(api, scope, templateKey, displayName, hidden, fields, null); 147 } 148 149 /** 150 * Creates new metadata template. 151 * 152 * @param api the API connection to be used. 153 * @param scope the scope of the object. 154 * @param templateKey a unique identifier for the template. 155 * @param displayName the display name of the field. 156 * @param hidden whether this template is hidden in the UI. 157 * @param fields the ordered set of fields for the template 158 * @param copyInstanceOnItemCopy determines whether the copy operation should copy the metadata along with the item. 159 * @return the metadata template returned from the server. 160 */ 161 public static MetadataTemplate createMetadataTemplate( 162 BoxAPIConnection api, 163 String scope, 164 String templateKey, 165 String displayName, 166 Boolean hidden, 167 List<Field> fields, 168 Boolean copyInstanceOnItemCopy 169 ) { 170 171 JsonObject jsonObject = new JsonObject(); 172 jsonObject.add("scope", scope); 173 jsonObject.add("displayName", displayName); 174 175 if (hidden != null) { 176 jsonObject.add("hidden", hidden); 177 } 178 179 if (copyInstanceOnItemCopy != null) { 180 jsonObject.add("copyInstanceOnItemCopy", copyInstanceOnItemCopy); 181 } 182 183 if (templateKey != null) { 184 jsonObject.add("templateKey", templateKey); 185 } 186 187 JsonArray fieldsArray = new JsonArray(); 188 if (fields != null && !fields.isEmpty()) { 189 for (Field field : fields) { 190 JsonObject fieldObj = getFieldJsonObject(field); 191 192 fieldsArray.add(fieldObj); 193 } 194 195 jsonObject.add("fields", fieldsArray); 196 } 197 198 URL url = METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE.build(api.getBaseURL()); 199 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 200 request.setBody(jsonObject.toString()); 201 202 BoxJSONResponse response = (BoxJSONResponse) request.send(); 203 JsonObject responseJSON = Json.parse(response.getJSON()).asObject(); 204 205 return new MetadataTemplate(responseJSON); 206 } 207 208 /** 209 * Gets the JsonObject representation of the given field object. 210 * 211 * @param field represents a template field 212 * @return the json object 213 */ 214 private static JsonObject getFieldJsonObject(Field field) { 215 JsonObject fieldObj = new JsonObject(); 216 fieldObj.add("type", field.getType()); 217 fieldObj.add("key", field.getKey()); 218 fieldObj.add("displayName", field.getDisplayName()); 219 220 String fieldDesc = field.getDescription(); 221 if (fieldDesc != null) { 222 fieldObj.add("description", field.getDescription()); 223 } 224 225 Boolean fieldIsHidden = field.getIsHidden(); 226 if (fieldIsHidden != null) { 227 fieldObj.add("hidden", field.getIsHidden()); 228 } 229 230 JsonArray array = new JsonArray(); 231 List<String> options = field.getOptions(); 232 if (options != null && !options.isEmpty()) { 233 for (String option : options) { 234 JsonObject optionObj = new JsonObject(); 235 optionObj.add("key", option); 236 237 array.add(optionObj); 238 } 239 fieldObj.add("options", array); 240 } 241 242 return fieldObj; 243 } 244 245 /** 246 * Updates the schema of an existing metadata template. 247 * 248 * @param api the API connection to be used 249 * @param scope the scope of the object 250 * @param template Unique identifier of the template 251 * @param fieldOperations the fields that needs to be updated / added in the template 252 * @return the updated metadata template 253 */ 254 public static MetadataTemplate updateMetadataTemplate(BoxAPIConnection api, String scope, String template, 255 List<FieldOperation> fieldOperations) { 256 257 JsonArray array = new JsonArray(); 258 259 for (FieldOperation fieldOperation : fieldOperations) { 260 JsonObject jsonObject = getFieldOperationJsonObject(fieldOperation); 261 array.add(jsonObject); 262 } 263 264 URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlpha(api.getBaseURL(), scope, template); 265 BoxJSONRequest request = new BoxJSONRequest(api, url, "PUT"); 266 request.setBody(array.toString()); 267 268 BoxJSONResponse response = (BoxJSONResponse) request.send(); 269 JsonObject responseJson = Json.parse(response.getJSON()).asObject(); 270 271 return new MetadataTemplate(responseJson); 272 } 273 274 /** 275 * Deletes the schema of an existing metadata template. 276 * 277 * @param api the API connection to be used 278 * @param scope the scope of the object 279 * @param template Unique identifier of the template 280 */ 281 public static void deleteMetadataTemplate(BoxAPIConnection api, String scope, String template) { 282 283 URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlpha(api.getBaseURL(), scope, template); 284 BoxJSONRequest request = new BoxJSONRequest(api, url, "DELETE"); 285 286 request.send(); 287 } 288 289 /** 290 * Executes a metadata query. 291 * 292 * @param api The API connection to be used 293 * @param queryBody The query 294 * @return An iterable of BoxItem.Info search results 295 */ 296 public static BoxResourceIterable<BoxItem.Info> executeMetadataQuery( 297 final BoxAPIConnection api, 298 final MetadataQuery queryBody 299 ) { 300 301 URL url = METADATA_QUERIES_URL_TEMPLATE.build(api.getBaseURL()); 302 return new BoxResourceIterable<BoxItem.Info>( 303 api, url, queryBody.getLimit(), queryBody.toJsonObject(), queryBody.getMarker() 304 ) { 305 306 @Override 307 protected BoxItem.Info factory(JsonObject jsonObject) { 308 String type = jsonObject.get("type").asString(); 309 String id = jsonObject.get("id").asString(); 310 311 BoxItem.Info nextItemInfo; 312 if (type.equals("folder")) { 313 BoxFolder folder = new BoxFolder(api, id); 314 nextItemInfo = folder.new Info(jsonObject); 315 } else if (type.equals("file")) { 316 BoxFile file = new BoxFile(api, id); 317 nextItemInfo = file.new Info(jsonObject); 318 } else if (type.equals("web_link")) { 319 BoxWebLink link = new BoxWebLink(api, id); 320 nextItemInfo = link.new Info(jsonObject); 321 } else { 322 assert false : "Unsupported item type: " + type; 323 throw new BoxAPIException("Unsupported item type: " + type); 324 } 325 326 return nextItemInfo; 327 } 328 }; 329 } 330 331 /** 332 * Executes a metadata query. 333 * 334 * @param api The API connection to be used 335 * @param from The template used in the query. Must be in the form scope.templateKey 336 * @param ancestorFolderId The folder_id to which to restrain the query 337 * @return An iterable of BoxMetadataQueryItem search results 338 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 339 */ 340 @Deprecated 341 public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery(final BoxAPIConnection api, 342 String from, String ancestorFolderId) { 343 return executeMetadataQuery(api, from, null, null, ancestorFolderId, null, null, 100, null); 344 } 345 346 /** 347 * Executes a metadata query. 348 * 349 * @param api The API connection to be used 350 * @param from The template used in the query. Must be in the form scope.templateKey 351 * @param ancestorFolderId The folder_id to which to restrain the query 352 * @param fields The fields to retrieve. 353 * @return An iterable of BoxItem.Info search results 354 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 355 */ 356 @Deprecated 357 public static BoxResourceIterable<BoxItem.Info> executeMetadataQuery( 358 final BoxAPIConnection api, 359 String from, 360 String ancestorFolderId, 361 String... fields 362 ) { 363 return executeMetadataQuery(api, from, null, null, ancestorFolderId, null, null, 100, null, fields); 364 } 365 366 /** 367 * Executes a metadata query. 368 * 369 * @param api The API connection to be used 370 * @param from The template used in the query. Must be in the form scope.templateKey 371 * @param query The logical expression of the query 372 * @param queryParameters Required if query present. The arguments for the query 373 * @param ancestorFolderId The folder_id to which to restrain the query 374 * @return An iterable of BoxMetadataQueryItem search results 375 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 376 */ 377 @Deprecated 378 public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery( 379 final BoxAPIConnection api, 380 String from, 381 String query, 382 JsonObject queryParameters, 383 String ancestorFolderId 384 ) { 385 return executeMetadataQuery(api, from, query, queryParameters, ancestorFolderId, null, null, 100, null); 386 } 387 388 /** 389 * Executes a metadata query. 390 * 391 * @param api The API connection to be used 392 * @param from The template used in the query. Must be in the form scope.templateKey 393 * @param query The logical expression of the query 394 * @param queryParameters Required if query present. The arguments for the query 395 * @param ancestorFolderId The folder_id to which to restrain the query 396 * @param fields The fields to retrieve. 397 * @return An iterable of BoxItem.Info search results 398 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 399 */ 400 @Deprecated 401 public static BoxResourceIterable<BoxItem.Info> executeMetadataQuery( 402 final BoxAPIConnection api, 403 String from, 404 String query, 405 JsonObject queryParameters, 406 String ancestorFolderId, 407 String... fields 408 ) { 409 return executeMetadataQuery(api, from, query, queryParameters, ancestorFolderId, null, null, 100, null, fields); 410 } 411 412 /** 413 * Executes a metadata query. 414 * We no longer require the use_index for queries that leverage indexes, 415 * internal analysis engine determines which existing index will satisfy the query. 416 * 417 * @param api The API connection to be used 418 * @param from The template used in the query. Must be in the form scope.templateKey 419 * @param query The logical expression of the query 420 * @param queryParameters Required if query present. The arguments for the query 421 * @param ancestorFolderId The folder_id to which to restrain the query 422 * @param indexName The name of the Index to use. <b>This parameter is ignored.</b> 423 * @param orderBy The field_key(s) to order on and the corresponding direction(s) 424 * @return An iterable of BoxMetadataQueryItem search results 425 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 426 */ 427 @Deprecated 428 public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery( 429 final BoxAPIConnection api, 430 String from, 431 String query, 432 JsonObject queryParameters, 433 String ancestorFolderId, 434 @Deprecated String indexName, 435 JsonArray orderBy 436 ) { 437 return executeMetadataQuery(api, from, query, queryParameters, ancestorFolderId, null, orderBy, 100, null); 438 } 439 440 /** 441 * Executes a metadata query. 442 * We no longer require the use_index for queries that leverage indexes, 443 * internal analysis engine determines which existing index will satisfy the query. 444 * 445 * @param api The API connection to be used 446 * @param from The template used in the query. Must be in the form scope.templateKey 447 * @param query The logical expression of the query 448 * @param queryParameters Required if query present. The arguments for the query 449 * @param ancestorFolderId The folder_id to which to restrain the query 450 * @param indexName The name of the Index to use. <b>This parameter is ignored.</b> 451 * @param orderBy The field_key(s) to order on and the corresponding direction(s) 452 * @param fields The fields to retrieve. 453 * @return An iterable of BoxItem.Info search results 454 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 455 */ 456 @Deprecated 457 public static BoxResourceIterable<BoxItem.Info> executeMetadataQuery( 458 final BoxAPIConnection api, 459 String from, 460 String query, 461 JsonObject queryParameters, 462 String ancestorFolderId, 463 String indexName, 464 JsonArray orderBy, 465 String... fields 466 ) { 467 return executeMetadataQuery( 468 api, from, query, queryParameters, ancestorFolderId, null, orderBy, 100, null, fields 469 ); 470 } 471 472 /** 473 * Executes a metadata query. 474 * We no longer require the use_index for queries that leverage indexes, 475 * internal analysis engine determines which existing index will satisfy the query. 476 * 477 * @param api The API connection to be used 478 * @param from The template used in the query. Must be in the form scope.templateKey 479 * @param query The logical expression of the query 480 * @param queryParameters Required if query present. The arguments for the query 481 * @param ancestorFolderId The folder_id to which to restrain the query 482 * @param indexName The name of the Index to use. <b>This parameter is ignored.</b> 483 * @param orderBy The field_key(s) to order on and the corresponding direction(s) 484 * @param limit Max results to return for a single request (0-100 inclusive) 485 * @param marker The marker to use for requesting the next page 486 * @return An iterable of BoxMetadataQueryItem search results 487 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 488 */ 489 @Deprecated 490 public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery( 491 final BoxAPIConnection api, 492 String from, 493 String query, 494 JsonObject queryParameters, 495 String ancestorFolderId, 496 String indexName, 497 JsonArray orderBy, 498 int limit, 499 String marker 500 ) { 501 JsonObject jsonObject = new MetadataQuery(from, limit) 502 .setQuery(query) 503 .setAncestorFolderId(ancestorFolderId) 504 .setMarker(marker) 505 .setOrderBy(orderBy) 506 .setFields() 507 .setQueryParams(queryParameters) 508 .toJsonObject(); 509 510 URL url = METADATA_QUERIES_URL_TEMPLATE.build(api.getBaseURL()); 511 return new BoxResourceIterable<BoxMetadataQueryItem>(api, url, limit, jsonObject, marker) { 512 513 @Override 514 protected BoxMetadataQueryItem factory(JsonObject jsonObject) { 515 return new BoxMetadataQueryItem(jsonObject, api); 516 } 517 }; 518 } 519 520 /** 521 * Executes a metadata query. 522 * We no longer require the use_index for queries that leverage indexes, 523 * internal analysis engine determines which existing index will satisfy the query. 524 * 525 * @param api The API connection to be used 526 * @param from The template used in the query. Must be in the form scope.templateKey 527 * @param query The logical expression of the query 528 * @param queryParameters Required if query present. The arguments for the query 529 * @param ancestorFolderId The folder_id to which to restrain the query 530 * @param indexName The name of the Index to use. <b>This parameter is ignored.</b> 531 * @param orderBy The field_key(s) to order on and the corresponding direction(s) 532 * @param limit Max results to return for a single request (0-100 inclusive) 533 * @param marker The marker to use for requesting the next page 534 * @param fields The fields to retrieve. 535 * @return An iterable of BoxItem.Info search results 536 * @deprecated Use {@link MetadataTemplate#executeMetadataQuery(BoxAPIConnection, MetadataQuery)} 537 */ 538 @Deprecated 539 //CHECKSTYLE:OFF 540 public static BoxResourceIterable<BoxItem.Info> executeMetadataQuery( 541 final BoxAPIConnection api, 542 String from, 543 String query, 544 JsonObject queryParameters, 545 String ancestorFolderId, 546 String indexName, 547 JsonArray orderBy, 548 int limit, 549 String marker, 550 String... fields 551 ) { 552 //CHECKSTYLE:ON 553 MetadataQuery queryBody = new MetadataQuery(from, limit) 554 .setQuery(query) 555 .setAncestorFolderId(ancestorFolderId) 556 .setMarker(marker) 557 .setOrderBy(orderBy) 558 .setFields(fields) 559 .setQueryParams(queryParameters); 560 561 return executeMetadataQuery(api, queryBody); 562 } 563 564 /** 565 * Gets the JsonObject representation of the Field Operation. 566 * 567 * @param fieldOperation represents the template update operation 568 * @return the json object 569 */ 570 private static JsonObject getFieldOperationJsonObject(FieldOperation fieldOperation) { 571 JsonObject jsonObject = new JsonObject(); 572 jsonObject.add("op", fieldOperation.getOp().toString()); 573 574 String fieldKey = fieldOperation.getFieldKey(); 575 if (fieldKey != null) { 576 jsonObject.add("fieldKey", fieldKey); 577 } 578 579 Field field = fieldOperation.getData(); 580 if (field != null) { 581 JsonObject fieldObj = new JsonObject(); 582 583 String type = field.getType(); 584 if (type != null) { 585 fieldObj.add("type", type); 586 } 587 588 String key = field.getKey(); 589 if (key != null) { 590 fieldObj.add("key", key); 591 } 592 593 String displayName = field.getDisplayName(); 594 if (displayName != null) { 595 fieldObj.add("displayName", displayName); 596 } 597 598 String description = field.getDescription(); 599 if (description != null) { 600 fieldObj.add("description", description); 601 } 602 603 Boolean hidden = field.getIsHidden(); 604 if (hidden != null) { 605 fieldObj.add("hidden", hidden); 606 } 607 608 List<String> options = field.getOptions(); 609 if (options != null) { 610 JsonArray array = new JsonArray(); 611 for (String option : options) { 612 JsonObject optionObj = new JsonObject(); 613 optionObj.add("key", option); 614 615 array.add(optionObj); 616 } 617 618 fieldObj.add("options", array); 619 } 620 621 Boolean copyInstanceOnItemCopy = field.getCopyInstanceOnItemCopy(); 622 if (copyInstanceOnItemCopy != null) { 623 fieldObj.add("copyInstanceOnItemCopy", copyInstanceOnItemCopy); 624 } 625 626 jsonObject.add("data", fieldObj); 627 } 628 629 List<String> fieldKeys = fieldOperation.getFieldKeys(); 630 if (fieldKeys != null) { 631 jsonObject.add("fieldKeys", getJsonArray(fieldKeys)); 632 } 633 634 List<String> enumOptionKeys = fieldOperation.getEnumOptionKeys(); 635 if (enumOptionKeys != null) { 636 jsonObject.add("enumOptionKeys", getJsonArray(enumOptionKeys)); 637 } 638 639 String enumOptionKey = fieldOperation.getEnumOptionKey(); 640 if (enumOptionKey != null) { 641 jsonObject.add("enumOptionKey", enumOptionKey); 642 } 643 644 String multiSelectOptionKey = fieldOperation.getMultiSelectOptionKey(); 645 if (multiSelectOptionKey != null) { 646 jsonObject.add("multiSelectOptionKey", multiSelectOptionKey); 647 } 648 649 List<String> multiSelectOptionKeys = fieldOperation.getMultiSelectOptionKeys(); 650 if (multiSelectOptionKeys != null) { 651 jsonObject.add("multiSelectOptionKeys", getJsonArray(multiSelectOptionKeys)); 652 } 653 654 return jsonObject; 655 } 656 657 /** 658 * Gets the Json Array representation of the given list of strings. 659 * 660 * @param keys List of strings 661 * @return the JsonArray represents the list of keys 662 */ 663 private static JsonArray getJsonArray(List<String> keys) { 664 JsonArray array = new JsonArray(); 665 for (String key : keys) { 666 array.add(key); 667 } 668 669 return array; 670 } 671 672 /** 673 * Gets the metadata template of properties. 674 * 675 * @param api the API connection to be used. 676 * @return the metadata template returned from the server. 677 */ 678 public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api) { 679 return getMetadataTemplate(api, DEFAULT_METADATA_TYPE); 680 } 681 682 /** 683 * Gets the metadata template of specified template type. 684 * 685 * @param api the API connection to be used. 686 * @param templateName the metadata template type name. 687 * @return the metadata template returned from the server. 688 */ 689 public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api, String templateName) { 690 String scope = scopeBasedOnType(templateName); 691 return getMetadataTemplate(api, templateName, scope); 692 } 693 694 /** 695 * Gets the metadata template of specified template type. 696 * 697 * @param api the API connection to be used. 698 * @param templateName the metadata template type name. 699 * @param scope the metadata template scope (global or enterprise). 700 * @param fields the fields to retrieve. 701 * @return the metadata template returned from the server. 702 */ 703 public static MetadataTemplate getMetadataTemplate( 704 BoxAPIConnection api, String templateName, String scope, String... fields) { 705 QueryStringBuilder builder = new QueryStringBuilder(); 706 if (fields.length > 0) { 707 builder.appendParam("fields", fields); 708 } 709 URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlphaWithQuery( 710 api.getBaseURL(), builder.toString(), scope, templateName); 711 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 712 BoxJSONResponse response = (BoxJSONResponse) request.send(); 713 return new MetadataTemplate(response.getJSON()); 714 } 715 716 /** 717 * Geta the specified metadata template by its ID. 718 * 719 * @param api the API connection to be used. 720 * @param templateID the ID of the template to get. 721 * @return the metadata template object. 722 */ 723 public static MetadataTemplate getMetadataTemplateByID(BoxAPIConnection api, String templateID) { 724 725 URL url = METADATA_TEMPLATE_BY_ID_URL_TEMPLATE.buildAlpha(api.getBaseURL(), templateID); 726 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 727 BoxJSONResponse response = (BoxJSONResponse) request.send(); 728 return new MetadataTemplate(response.getJSON()); 729 } 730 731 /** 732 * Returns all metadata templates within a user's enterprise. 733 * 734 * @param api the API connection to be used. 735 * @param fields the fields to retrieve. 736 * @return the metadata template returned from the server. 737 */ 738 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(BoxAPIConnection api, String... fields) { 739 return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, api, fields); 740 } 741 742 /** 743 * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported. 744 * 745 * @param scope the scope of the metadata templates. 746 * @param api the API connection to be used. 747 * @param fields the fields to retrieve. 748 * @return the metadata template returned from the server. 749 */ 750 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates( 751 String scope, BoxAPIConnection api, String... fields 752 ) { 753 return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, DEFAULT_ENTRIES_LIMIT, api, fields); 754 } 755 756 /** 757 * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported. 758 * 759 * @param scope the scope of the metadata templates. 760 * @param limit maximum number of entries per response. 761 * @param api the API connection to be used. 762 * @param fields the fields to retrieve. 763 * @return the metadata template returned from the server. 764 */ 765 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates( 766 String scope, int limit, BoxAPIConnection api, String... fields) { 767 QueryStringBuilder builder = new QueryStringBuilder(); 768 if (fields.length > 0) { 769 builder.appendParam("fields", fields); 770 } 771 return new BoxResourceIterable<MetadataTemplate>( 772 api, ENTERPRISE_METADATA_URL_TEMPLATE.buildAlphaWithQuery( 773 api.getBaseURL(), builder.toString(), scope), limit) { 774 775 @Override 776 protected MetadataTemplate factory(JsonObject jsonObject) { 777 return new MetadataTemplate(jsonObject); 778 } 779 }; 780 } 781 782 /** 783 * Determines the metadata scope based on type. 784 * 785 * @param typeName type of the metadata. 786 * @return scope of the metadata. 787 */ 788 private static String scopeBasedOnType(String typeName) { 789 return typeName.equals(DEFAULT_METADATA_TYPE) ? GLOBAL_METADATA_SCOPE : ENTERPRISE_METADATA_SCOPE; 790 } 791 792 /** 793 * Gets the ID of the template. 794 * 795 * @return the template ID. 796 */ 797 public String getID() { 798 return this.id; 799 } 800 801 /** 802 * Gets the unique template key to identify the metadata template. 803 * 804 * @return the unique template key to identify the metadata template. 805 */ 806 public String getTemplateKey() { 807 return this.templateKey; 808 } 809 810 /** 811 * Gets the metadata template scope. 812 * 813 * @return the metadata template scope. 814 */ 815 public String getScope() { 816 return this.scope; 817 } 818 819 /** 820 * Gets the displayed metadata template name. 821 * 822 * @return the displayed metadata template name. 823 */ 824 public String getDisplayName() { 825 return this.displayName; 826 } 827 828 /** 829 * Gets is the metadata template hidden. 830 * 831 * @return is the metadata template hidden. 832 */ 833 public Boolean getIsHidden() { 834 return this.isHidden; 835 } 836 837 /** 838 * Gets the iterable with all fields the metadata template contains. 839 * 840 * @return the iterable with all fields the metadata template contains. 841 */ 842 public List<Field> getFields() { 843 return this.fields; 844 } 845 846 /** 847 * Gets whether the copy operation should copy the metadata along with the item. 848 * 849 * @return whether the copy operation should copy the metadata along with the item. 850 */ 851 public Boolean getCopyInstanceOnItemCopy() { 852 return this.copyInstanceOnItemCopy; 853 } 854 855 /** 856 * {@inheritDoc} 857 */ 858 @Override 859 void parseJSONMember(JsonObject.Member member) { 860 JsonValue value = member.getValue(); 861 String memberName = member.getName(); 862 if (memberName.equals("templateKey")) { 863 this.templateKey = value.asString(); 864 } else if (memberName.equals("scope")) { 865 this.scope = value.asString(); 866 } else if (memberName.equals("displayName")) { 867 this.displayName = value.asString(); 868 } else if (memberName.equals("hidden")) { 869 this.isHidden = value.asBoolean(); 870 } else if (memberName.equals("fields")) { 871 this.fields = new ArrayList<>(); 872 for (JsonValue field : value.asArray()) { 873 this.fields.add(new Field(field.asObject())); 874 } 875 } else if (memberName.equals("id")) { 876 this.id = value.asString(); 877 } else if (memberName.equals("copyInstanceOnItemCopy")) { 878 this.copyInstanceOnItemCopy = value.asBoolean(); 879 } 880 } 881 882 /** 883 * Possible template operations. 884 */ 885 public enum Operation { 886 887 /** 888 * Adds an enum option at the end of the enum option list for the specified field. 889 */ 890 addEnumOption, 891 892 /** 893 * Edits the enum option. 894 */ 895 editEnumOption, 896 897 /** 898 * Removes the specified enum option from the specified enum field. 899 */ 900 removeEnumOption, 901 902 /** 903 * Adds a field at the end of the field list for the template. 904 */ 905 addField, 906 907 /** 908 * Edits any number of the base properties of a field: displayName, hidden, description. 909 */ 910 editField, 911 912 /** 913 * Removes the specified field from the template. 914 */ 915 removeField, 916 917 /** 918 * Edits any number of the base properties of a template: displayName, hidden. 919 */ 920 editTemplate, 921 922 /** 923 * Reorders the enum option list to match the requested enum option list. 924 */ 925 reorderEnumOptions, 926 927 /** 928 * Reorders the field list to match the requested field list. 929 */ 930 reorderFields, 931 932 /** 933 * Adds a new option to a multiselect field. 934 */ 935 addMultiSelectOption, 936 937 /** 938 * Edits an existing option in a multiselect field. 939 */ 940 editMultiSelectOption, 941 942 /** 943 * Removes an option from a multiselect field. 944 */ 945 removeMultiSelectOption, 946 947 /** 948 * Changes the display order of options in a multiselect field. 949 */ 950 reorderMultiSelectOptions 951 } 952 953 /** 954 * Class contains information about the metadata template field. 955 */ 956 public static class Field extends BoxJSONObject { 957 958 /** 959 * @see #getID() 960 */ 961 private String id; 962 963 /** 964 * @see #getType() 965 */ 966 private String type; 967 968 /** 969 * @see #getKey() 970 */ 971 private String key; 972 973 /** 974 * @see #getDisplayName() 975 */ 976 private String displayName; 977 978 /** 979 * @see #getIsHidden() 980 */ 981 private Boolean isHidden; 982 983 /** 984 * @see #getDescription() 985 */ 986 private String description; 987 988 /** 989 * @see #getOptionsObjects() 990 */ 991 private List<Option> options; 992 993 /** 994 * @see #getCopyInstanceOnItemCopy() 995 */ 996 private Boolean copyInstanceOnItemCopy; 997 998 /** 999 * Constructs an empty metadata template. 1000 */ 1001 public Field() { 1002 super(); 1003 } 1004 1005 /** 1006 * Constructs a metadate template field from a JSON string. 1007 * 1008 * @param json the json encoded metadate template field. 1009 */ 1010 public Field(String json) { 1011 super(json); 1012 } 1013 1014 /** 1015 * Constructs a metadate template field from a JSON object. 1016 * 1017 * @param jsonObject the json encoded metadate template field. 1018 */ 1019 Field(JsonObject jsonObject) { 1020 super(jsonObject); 1021 } 1022 1023 /** 1024 * Gets the ID of the template field. 1025 * 1026 * @return the template field ID. 1027 */ 1028 public String getID() { 1029 return this.id; 1030 } 1031 1032 /** 1033 * Gets the data type of the field's value. 1034 * 1035 * @return the data type of the field's value. 1036 */ 1037 public String getType() { 1038 return this.type; 1039 } 1040 1041 /** 1042 * Sets the data type of the field's value. 1043 * 1044 * @param type the data type of the field's value. 1045 */ 1046 public void setType(String type) { 1047 this.type = type; 1048 } 1049 1050 /** 1051 * Gets the key of the field. 1052 * 1053 * @return the key of the field. 1054 */ 1055 public String getKey() { 1056 return this.key; 1057 } 1058 1059 /** 1060 * Sets the key of the field. 1061 * 1062 * @param key the key of the field. 1063 */ 1064 public void setKey(String key) { 1065 this.key = key; 1066 } 1067 1068 /** 1069 * Gets the display name of the field. 1070 * 1071 * @return the display name of the field. 1072 */ 1073 public String getDisplayName() { 1074 return this.displayName; 1075 } 1076 1077 /** 1078 * Sets the display name of the field. 1079 * 1080 * @param displayName the display name of the field. 1081 */ 1082 public void setDisplayName(String displayName) { 1083 this.displayName = displayName; 1084 } 1085 1086 /** 1087 * Gets is metadata template field hidden. 1088 * 1089 * @return is metadata template field hidden. 1090 */ 1091 public Boolean getIsHidden() { 1092 return this.isHidden; 1093 } 1094 1095 /** 1096 * Sets is metadata template field hidden. 1097 * 1098 * @param isHidden is metadata template field hidden? 1099 */ 1100 public void setIsHidden(boolean isHidden) { 1101 this.isHidden = isHidden; 1102 } 1103 1104 /** 1105 * Gets the description of the field. 1106 * 1107 * @return the description of the field. 1108 */ 1109 public String getDescription() { 1110 return this.description; 1111 } 1112 1113 /** 1114 * Sets the description of the field. 1115 * 1116 * @param description the description of the field. 1117 */ 1118 public void setDescription(String description) { 1119 this.description = description; 1120 } 1121 1122 /** 1123 * Gets list of possible options for enum type of the field. 1124 * 1125 * @return list of possible options for enum type of the field. 1126 */ 1127 public List<String> getOptions() { 1128 if (this.options == null) { 1129 return null; 1130 } 1131 List<String> optionsList = new ArrayList<>(); 1132 for (Option option : this.options) { 1133 optionsList.add(option.getKey()); 1134 } 1135 return optionsList; 1136 } 1137 1138 /** 1139 * Sets list of possible options for enum type of the field. 1140 * 1141 * @param options list of possible options for enum type of the field. 1142 */ 1143 public void setOptions(List<String> options) { 1144 if (options == null) { 1145 this.options = null; 1146 return; 1147 } 1148 List<Option> optionList = new ArrayList<>(); 1149 for (String key : options) { 1150 JsonObject optionObject = new JsonObject(); 1151 optionObject.add("key", key); 1152 Option newOption = new Option(optionObject); 1153 optionList.add(newOption); 1154 } 1155 this.options = optionList; 1156 } 1157 1158 /** 1159 * Gets list of possible options for options type of the field. 1160 * 1161 * @return list of possible options for option type of the field. 1162 */ 1163 public List<Option> getOptionsObjects() { 1164 return this.options; 1165 } 1166 1167 /** 1168 * Gets whether the copy operation should copy the metadata along with the item. 1169 * 1170 * @return whether the copy operation should copy the metadata along with the item. 1171 */ 1172 public Boolean getCopyInstanceOnItemCopy() { 1173 return this.copyInstanceOnItemCopy; 1174 } 1175 1176 /** 1177 * Sets whether the copy operation should copy the metadata along with the item. 1178 * 1179 * @param copyInstanceOnItemCopy whether the copy operation should copy the metadata along with the item. 1180 */ 1181 public void setCopyInstanceOnItemCopy(Boolean copyInstanceOnItemCopy) { 1182 this.copyInstanceOnItemCopy = copyInstanceOnItemCopy; 1183 } 1184 1185 /** 1186 * {@inheritDoc} 1187 */ 1188 @Override 1189 void parseJSONMember(JsonObject.Member member) { 1190 JsonValue value = member.getValue(); 1191 String memberName = member.getName(); 1192 if (memberName.equals("type")) { 1193 this.type = value.asString(); 1194 } else if (memberName.equals("key")) { 1195 this.key = value.asString(); 1196 } else if (memberName.equals("displayName")) { 1197 this.displayName = value.asString(); 1198 } else if (memberName.equals("hidden")) { 1199 this.isHidden = value.asBoolean(); 1200 } else if (memberName.equals("description")) { 1201 this.description = value.asString(); 1202 } else if (memberName.equals("options")) { 1203 this.options = new ArrayList<>(); 1204 for (JsonValue option : value.asArray()) { 1205 this.options.add(new Option(option.asObject())); 1206 } 1207 } else if (memberName.equals("id")) { 1208 this.id = value.asString(); 1209 } else if (memberName.equals("copyInstanceOnItemCopy")) { 1210 this.copyInstanceOnItemCopy = value.asBoolean(); 1211 } 1212 } 1213 } 1214 1215 /** 1216 * Class contains information about the metadata template option. 1217 */ 1218 public static class Option extends BoxJSONObject { 1219 /** 1220 * @see #getID() 1221 */ 1222 private String id; 1223 /** 1224 * @see #getKey() 1225 */ 1226 private String key; 1227 1228 /** 1229 * Constructs an empty metadata template. 1230 */ 1231 public Option() { 1232 super(); 1233 } 1234 1235 /** 1236 * Constructs a metadate template option from a JSON string. 1237 * 1238 * @param json the json encoded metadata template option. 1239 */ 1240 public Option(String json) { 1241 super(json); 1242 } 1243 1244 /** 1245 * Constructs a metadate template option from a JSON object. 1246 * 1247 * @param jsonObject the json encoded metadate template option. 1248 */ 1249 Option(JsonObject jsonObject) { 1250 super(jsonObject); 1251 } 1252 1253 /** 1254 * Gets the ID of the template field. 1255 * 1256 * @return the template field ID. 1257 */ 1258 public String getID() { 1259 return this.id; 1260 } 1261 1262 /** 1263 * Gets the key of the field. 1264 * 1265 * @return the key of the field. 1266 */ 1267 public String getKey() { 1268 return this.key; 1269 } 1270 1271 /** 1272 * {@inheritDoc} 1273 */ 1274 @Override 1275 void parseJSONMember(JsonObject.Member member) { 1276 JsonValue value = member.getValue(); 1277 String memberName = member.getName(); 1278 if (memberName.equals("id")) { 1279 this.id = value.asString(); 1280 } else if (memberName.equals("key")) { 1281 this.key = value.asString(); 1282 } 1283 } 1284 } 1285 1286 /** 1287 * Posssible operations that can be performed in a Metadata template. 1288 * <ul> 1289 * <li>Add an enum option</li> 1290 * <li>Edit an enum option</li> 1291 * <li>Remove an enum option</li> 1292 * <li>Add a field</li> 1293 * <li>Edit a field</li> 1294 * <li>Remove a field</li> 1295 * <li>Edit template</li> 1296 * <li>Reorder the enum option</li> 1297 * <li>Reorder the field list</li> 1298 * </ul> 1299 */ 1300 public static class FieldOperation extends BoxJSONObject { 1301 1302 private Operation op; 1303 private Field data; 1304 private String fieldKey; 1305 private List<String> fieldKeys; 1306 private List<String> enumOptionKeys; 1307 private String enumOptionKey; 1308 private String multiSelectOptionKey; 1309 private List<String> multiSelectOptionKeys; 1310 1311 /** 1312 * Constructs an empty FieldOperation. 1313 */ 1314 public FieldOperation() { 1315 super(); 1316 } 1317 1318 /** 1319 * Constructs a Field operation from a JSON string. 1320 * 1321 * @param json the json encoded metadate template field. 1322 */ 1323 public FieldOperation(String json) { 1324 super(json); 1325 } 1326 1327 /** 1328 * Constructs a Field operation from a JSON object. 1329 * 1330 * @param jsonObject the json encoded metadate template field. 1331 */ 1332 FieldOperation(JsonObject jsonObject) { 1333 super(jsonObject); 1334 } 1335 1336 /** 1337 * Gets the operation. 1338 * 1339 * @return the operation 1340 */ 1341 public Operation getOp() { 1342 return this.op; 1343 } 1344 1345 /** 1346 * Sets the operation. 1347 * 1348 * @param op the operation 1349 */ 1350 public void setOp(Operation op) { 1351 this.op = op; 1352 } 1353 1354 /** 1355 * Gets the data associated with the operation. 1356 * 1357 * @return the field object representing the data 1358 */ 1359 public Field getData() { 1360 return this.data; 1361 } 1362 1363 /** 1364 * Sets the data. 1365 * 1366 * @param data the Field object representing the data 1367 */ 1368 public void setData(Field data) { 1369 this.data = data; 1370 } 1371 1372 /** 1373 * Gets the field key. 1374 * 1375 * @return the field key 1376 */ 1377 public String getFieldKey() { 1378 return this.fieldKey; 1379 } 1380 1381 /** 1382 * Sets the field key. 1383 * 1384 * @param fieldKey the key of the field 1385 */ 1386 public void setFieldKey(String fieldKey) { 1387 this.fieldKey = fieldKey; 1388 } 1389 1390 /** 1391 * Gets the list of field keys. 1392 * 1393 * @return the list of Strings 1394 */ 1395 public List<String> getFieldKeys() { 1396 return this.fieldKeys; 1397 } 1398 1399 /** 1400 * Sets the list of the field keys. 1401 * 1402 * @param fieldKeys the list of strings 1403 */ 1404 public void setFieldKeys(List<String> fieldKeys) { 1405 this.fieldKeys = fieldKeys; 1406 } 1407 1408 /** 1409 * Gets the list of keys of the Enum options. 1410 * 1411 * @return the list of Strings 1412 */ 1413 public List<String> getEnumOptionKeys() { 1414 return this.enumOptionKeys; 1415 } 1416 1417 /** 1418 * Sets the list of the enum option keys. 1419 * 1420 * @param enumOptionKeys the list of Strings 1421 */ 1422 public void setEnumOptionKeys(List<String> enumOptionKeys) { 1423 this.enumOptionKeys = enumOptionKeys; 1424 } 1425 1426 /** 1427 * Gets the enum option key. 1428 * 1429 * @return the enum option key 1430 */ 1431 public String getEnumOptionKey() { 1432 return this.enumOptionKey; 1433 } 1434 1435 /** 1436 * Sets the enum option key. 1437 * 1438 * @param enumOptionKey the enum option key 1439 */ 1440 public void setEnumOptionKey(String enumOptionKey) { 1441 this.enumOptionKey = enumOptionKey; 1442 } 1443 1444 /** 1445 * Gets the multi-select option key. 1446 * 1447 * @return the key. 1448 */ 1449 public String getMultiSelectOptionKey() { 1450 return this.multiSelectOptionKey; 1451 } 1452 1453 /** 1454 * Sets the multi-select option key. 1455 * 1456 * @param key the key. 1457 */ 1458 public void setMultiSelectOptionKey(String key) { 1459 this.multiSelectOptionKey = key; 1460 } 1461 1462 /** 1463 * Gets the list of multiselect option keys. 1464 * 1465 * @return the list of keys. 1466 */ 1467 public List<String> getMultiSelectOptionKeys() { 1468 return this.multiSelectOptionKeys; 1469 } 1470 1471 /** 1472 * Sets the multi-select option keys. 1473 * 1474 * @param keys the list of keys. 1475 */ 1476 public void setMultiSelectOptionKeys(List<String> keys) { 1477 this.multiSelectOptionKeys = keys; 1478 } 1479 1480 /** 1481 * {@inheritDoc} 1482 */ 1483 @Override 1484 void parseJSONMember(JsonObject.Member member) { 1485 JsonValue value = member.getValue(); 1486 String memberName = member.getName(); 1487 if (memberName.equals("op")) { 1488 this.op = Operation.valueOf(value.asString()); 1489 } else if (memberName.equals("data")) { 1490 this.data = new Field(value.asObject()); 1491 } else if (memberName.equals("fieldKey")) { 1492 this.fieldKey = value.asString(); 1493 } else if (memberName.equals("fieldKeys")) { 1494 if (this.fieldKeys == null) { 1495 this.fieldKeys = new ArrayList<>(); 1496 } else { 1497 this.fieldKeys.clear(); 1498 } 1499 1500 JsonArray array = value.asArray(); 1501 for (JsonValue jsonValue : array) { 1502 this.fieldKeys.add(jsonValue.asString()); 1503 } 1504 } else if (memberName.equals("enumOptionKeys")) { 1505 if (this.enumOptionKeys == null) { 1506 this.enumOptionKeys = new ArrayList<>(); 1507 } else { 1508 this.enumOptionKeys.clear(); 1509 } 1510 1511 JsonArray array = value.asArray(); 1512 for (JsonValue jsonValue : array) { 1513 this.enumOptionKeys.add(jsonValue.asString()); 1514 } 1515 } else if (memberName.equals("enumOptionKey")) { 1516 this.enumOptionKey = value.asString(); 1517 } else if (memberName.equals("multiSelectOptionKey")) { 1518 this.multiSelectOptionKey = value.asString(); 1519 } else if (memberName.equals("multiSelectOptionKeys")) { 1520 this.multiSelectOptionKeys = new ArrayList<>(); 1521 for (JsonValue key : value.asArray()) { 1522 this.multiSelectOptionKeys.add(key.asString()); 1523 } 1524 } 1525 } 1526 } 1527}