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