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