001package com.box.sdk;
002
003import java.net.URL;
004import java.util.ArrayList;
005import java.util.List;
006
007import com.eclipsesource.json.JsonArray;
008import com.eclipsesource.json.JsonObject;
009import com.eclipsesource.json.JsonValue;
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://docs.box.com/reference#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     * Constructs an empty metadata template.
099     */
100    public MetadataTemplate() {
101        super();
102    }
103
104    /**
105     * Constructs a metadata template from a JSON string.
106     * @param json the json encoded metadate template.
107     */
108    public MetadataTemplate(String json) {
109        super(json);
110    }
111
112    /**
113     * Constructs a metadate template from a JSON object.
114     * @param jsonObject the json encoded metadate template.
115     */
116    MetadataTemplate(JsonObject jsonObject) {
117        super(jsonObject);
118    }
119
120    /**
121     * Gets the ID of the template.
122     * @return the template ID.
123     */
124    public String getID() {
125        return this.id;
126    }
127
128    /**
129     * Gets the unique template key to identify the metadata template.
130     * @return the unique template key to identify the metadata template.
131     */
132    public String getTemplateKey() {
133        return this.templateKey;
134    }
135
136    /**
137     * Gets the metadata template scope.
138     * @return the metadata template scope.
139     */
140    public String getScope() {
141        return this.scope;
142    }
143
144    /**
145     * Gets the displayed metadata template name.
146     * @return the displayed metadata template name.
147     */
148    public String getDisplayName() {
149        return this.displayName;
150    }
151
152    /**
153     * Gets is the metadata template hidden.
154     * @return is the metadata template hidden.
155     */
156    public Boolean getIsHidden() {
157        return this.isHidden;
158    }
159
160    /**
161     * Gets the iterable with all fields the metadata template contains.
162     * @return the iterable with all fields the metadata template contains.
163     */
164    public List<Field> getFields() {
165        return this.fields;
166    }
167
168    /**
169     * {@inheritDoc}
170     */
171    @Override
172    void parseJSONMember(JsonObject.Member member) {
173        JsonValue value = member.getValue();
174        String memberName = member.getName();
175        if (memberName.equals("templateKey")) {
176            this.templateKey = value.asString();
177        } else if (memberName.equals("scope")) {
178            this.scope = value.asString();
179        } else if (memberName.equals("displayName")) {
180            this.displayName = value.asString();
181        } else if (memberName.equals("hidden")) {
182            this.isHidden = value.asBoolean();
183        } else if (memberName.equals("fields")) {
184            this.fields = new ArrayList<Field>();
185            for (JsonValue field: value.asArray()) {
186                this.fields.add(new Field(field.asObject()));
187            }
188        } else if (memberName.equals("id")) {
189            this.id = value.asString();
190        }
191    }
192
193    /**
194     * Creates new metadata template.
195     * @param api the API connection to be used.
196     * @param scope the scope of the object.
197     * @param templateKey a unique identifier for the template.
198     * @param displayName the display name of the field.
199     * @param hidden whether this template is hidden in the UI.
200     * @param fields the ordered set of fields for the template
201     * @return the metadata template returned from the server.
202     */
203    public static MetadataTemplate createMetadataTemplate(BoxAPIConnection api, String scope, String templateKey,
204            String displayName, boolean hidden, List<Field> fields) {
205
206        JsonObject jsonObject = new JsonObject();
207        jsonObject.add("scope", scope);
208        jsonObject.add("displayName", displayName);
209        jsonObject.add("hidden", hidden);
210
211        if (templateKey != null) {
212            jsonObject.add("templateKey", templateKey);
213        }
214
215        JsonArray fieldsArray = new JsonArray();
216        if (fields != null && !fields.isEmpty()) {
217            for (Field field : fields) {
218                JsonObject fieldObj = getFieldJsonObject(field);
219
220                fieldsArray.add(fieldObj);
221            }
222
223            jsonObject.add("fields", fieldsArray);
224        }
225
226        URL url = METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE.build(api.getBaseURL());
227        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
228        request.setBody(jsonObject.toString());
229
230        BoxJSONResponse response = (BoxJSONResponse) request.send();
231        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
232
233        return new MetadataTemplate(responseJSON);
234    }
235
236    /**
237     * Gets the JsonObject representation of the given field object.
238     * @param field represents a template field
239     * @return the json object
240     */
241    private static JsonObject getFieldJsonObject(Field field) {
242        JsonObject fieldObj = new JsonObject();
243        fieldObj.add("type", field.getType());
244        fieldObj.add("key", field.getKey());
245        fieldObj.add("displayName", field.getDisplayName());
246
247        String fieldDesc = field.getDescription();
248        if (fieldDesc != null) {
249            fieldObj.add("description", field.getDescription());
250        }
251
252        Boolean fieldIsHidden = field.getIsHidden();
253        if (fieldIsHidden != null) {
254            fieldObj.add("hidden", field.getIsHidden());
255        }
256
257        JsonArray array = new JsonArray();
258        List<String> options = field.getOptions();
259        if (options != null && !options.isEmpty()) {
260            for (String option : options) {
261                JsonObject optionObj = new JsonObject();
262                optionObj.add("key", option);
263
264                array.add(optionObj);
265            }
266            fieldObj.add("options", array);
267        }
268
269        return fieldObj;
270    }
271
272    /**
273     * Updates the schema of an existing metadata template.
274     *
275     * @param api the API connection to be used
276     * @param scope the scope of the object
277     * @param template Unique identifier of the template
278     * @param fieldOperations the fields that needs to be updated / added in the template
279     * @return the updated metadata template
280     */
281    public static MetadataTemplate updateMetadataTemplate(BoxAPIConnection api, String scope, String template,
282            List<FieldOperation> fieldOperations) {
283
284        JsonArray array = new JsonArray();
285
286        for (FieldOperation fieldOperation : fieldOperations) {
287            JsonObject jsonObject = getFieldOperationJsonObject(fieldOperation);
288            array.add(jsonObject);
289        }
290
291        QueryStringBuilder builder = new QueryStringBuilder();
292        URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlpha(api.getBaseURL(), scope, template);
293        BoxJSONRequest request = new BoxJSONRequest(api, url, "PUT");
294        request.setBody(array.toString());
295
296        BoxJSONResponse response = (BoxJSONResponse) request.send();
297        JsonObject responseJson = JsonObject.readFrom(response.getJSON());
298
299        return new MetadataTemplate(responseJson);
300    }
301
302    /**
303     * Deletes the schema of an existing metadata template.
304     *
305     * @param api the API connection to be used
306     * @param scope the scope of the object
307     * @param template Unique identifier of the template
308     */
309    public static void deleteMetadataTemplate(BoxAPIConnection api, String scope, String template) {
310
311        URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlpha(api.getBaseURL(), scope, template);
312        BoxJSONRequest request = new BoxJSONRequest(api, url, "DELETE");
313
314        request.send();
315    }
316
317    /**
318     * Executes a metadata query.
319     *
320     * @param api The API connection to be used
321     * @param from The template used in the query. Must be in the form scope.templateKey
322     * @param ancestorFolderId The folder_id to which to restrain the query
323     * @return An iterable of BoxMetadataQueryItem search results
324     */
325    public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery(final BoxAPIConnection api,
326                                                            String from, String ancestorFolderId) {
327        return executeMetadataQuery(api, from, null, null, ancestorFolderId, null, null, 100, null);
328    }
329
330    /**
331      * Executes a metadata query.
332      *
333      * @param api The API connection to be used
334      * @param from The template used in the query. Must be in the form scope.templateKey
335      * @param query The logical expression of the query
336      * @param queryParameters Required if query present. The arguments for the query
337      * @param ancestorFolderId The folder_id to which to restrain the query
338      * @return An iterable of BoxMetadataQueryItem search results
339      */
340    public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery(final BoxAPIConnection api,
341                                                            String from, String query, JsonObject queryParameters,
342                                                            String ancestorFolderId) {
343        return executeMetadataQuery(api, from, query, queryParameters, 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 query The logical expression of the query
352      * @param queryParameters Required if query present. The arguments for the query
353      * @param ancestorFolderId The folder_id to which to restrain the query
354      * @param indexName The name of the Index to use
355      * @param orderBy The field_key(s) to order on and the corresponding direction(s)
356      * @return An iterable of BoxMetadataQueryItem search results
357      */
358    public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery(final BoxAPIConnection api,
359                                                            String from, String query, JsonObject queryParameters,
360                                                            String ancestorFolderId, String indexName,
361                                                            JsonArray orderBy) {
362        return executeMetadataQuery(api, from, query, queryParameters, ancestorFolderId, indexName, orderBy, 100, null);
363    }
364
365    /**
366     * Executes a metadata query.
367     *
368     * @param api The API connection to be used
369     * @param from The template used in the query. Must be in the form scope.templateKey
370     * @param query The logical expression of the query
371     * @param queryParameters Required if query present. The arguments for the query
372     * @param ancestorFolderId The folder_id to which to restrain the query
373     * @param indexName The name of the Index to use
374     * @param orderBy The field_key(s) to order on and the corresponding direction(s)
375     * @param limit Max results to return for a single request (0-100 inclusive)
376     * @param marker The marker to use for requesting the next page
377     * @return An iterable of BoxMetadataQueryItem search results
378     */
379    public static BoxResourceIterable<BoxMetadataQueryItem> executeMetadataQuery(final BoxAPIConnection api,
380                                                            String from, String query, JsonObject queryParameters,
381                                                            String ancestorFolderId, String indexName,
382                                                            JsonArray orderBy, int limit, String marker) {
383
384        JsonObject jsonObject = new JsonObject().add("from", from);
385        if (query != null) {
386            jsonObject.add("query", query);
387        }
388        if (queryParameters != null) {
389            jsonObject.add("query_params", queryParameters);
390        }
391        if (ancestorFolderId != null) {
392            jsonObject.add("ancestor_folder_id", ancestorFolderId);
393        }
394        if (indexName != null) {
395            jsonObject.add("use_index", indexName);
396        }
397        if (orderBy != null) {
398            jsonObject.add("order_by", orderBy);
399        }
400        jsonObject.add("limit", limit);
401        if (marker != null) {
402            jsonObject.add("marker", marker);
403        }
404
405        URL url = METADATA_QUERIES_URL_TEMPLATE.build(api.getBaseURL());
406        return new BoxResourceIterable<BoxMetadataQueryItem>(api, url, limit, jsonObject, marker) {
407
408            @Override
409            protected BoxMetadataQueryItem factory(JsonObject jsonObject) {
410                return new BoxMetadataQueryItem(jsonObject, api);
411            }
412        };
413    }
414
415    /**
416     * Gets the JsonObject representation of the Field Operation.
417     * @param fieldOperation represents the template update operation
418     * @return the json object
419     */
420    private static JsonObject getFieldOperationJsonObject(FieldOperation fieldOperation) {
421        JsonObject jsonObject = new JsonObject();
422        jsonObject.add("op", fieldOperation.getOp().toString());
423
424        String fieldKey = fieldOperation.getFieldKey();
425        if (fieldKey != null) {
426            jsonObject.add("fieldKey", fieldKey);
427        }
428
429        Field field = fieldOperation.getData();
430        if (field != null) {
431            JsonObject fieldObj = new JsonObject();
432
433            String type = field.getType();
434            if (type != null) {
435                fieldObj.add("type", type);
436            }
437
438            String key = field.getKey();
439            if (key != null) {
440                fieldObj.add("key", key);
441            }
442
443            String displayName = field.getDisplayName();
444            if (displayName != null) {
445                fieldObj.add("displayName", displayName);
446            }
447
448            String description = field.getDescription();
449            if (description != null) {
450                fieldObj.add("description", description);
451            }
452
453            Boolean hidden = field.getIsHidden();
454            if (hidden != null) {
455                fieldObj.add("hidden", hidden);
456            }
457
458            List<String> options = field.getOptions();
459            if (options != null) {
460                JsonArray array = new JsonArray();
461                for (String option: options) {
462                    JsonObject optionObj = new JsonObject();
463                    optionObj.add("key", option);
464
465                    array.add(optionObj);
466                }
467
468                fieldObj.add("options", array);
469            }
470
471            jsonObject.add("data", fieldObj);
472        }
473
474        List<String> fieldKeys = fieldOperation.getFieldKeys();
475        if (fieldKeys != null) {
476            jsonObject.add("fieldKeys", getJsonArray(fieldKeys));
477        }
478
479        List<String> enumOptionKeys = fieldOperation.getEnumOptionKeys();
480        if (enumOptionKeys != null) {
481            jsonObject.add("enumOptionKeys", getJsonArray(enumOptionKeys));
482        }
483
484        String enumOptionKey = fieldOperation.getEnumOptionKey();
485        if (enumOptionKey != null) {
486            jsonObject.add("enumOptionKey", enumOptionKey);
487        }
488
489        String multiSelectOptionKey = fieldOperation.getMultiSelectOptionKey();
490        if (multiSelectOptionKey != null) {
491            jsonObject.add("multiSelectOptionKey", multiSelectOptionKey);
492        }
493
494        List<String> multiSelectOptionKeys = fieldOperation.getMultiSelectOptionKeys();
495        if (multiSelectOptionKeys != null) {
496            jsonObject.add("multiSelectOptionKeys", getJsonArray(multiSelectOptionKeys));
497        }
498
499        return jsonObject;
500    }
501
502    /**
503     * Gets the Json Array representation of the given list of strings.
504     * @param keys List of strings
505     * @return the JsonArray represents the list of keys
506     */
507    private static JsonArray getJsonArray(List<String> keys) {
508        JsonArray array = new JsonArray();
509        for (String key : keys) {
510            array.add(key);
511        }
512
513        return array;
514    }
515
516    /**
517     * Gets the metadata template of properties.
518     * @param api the API connection to be used.
519     * @return the metadata template returned from the server.
520     */
521    public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api) {
522        return getMetadataTemplate(api, DEFAULT_METADATA_TYPE);
523    }
524
525    /**
526     * Gets the metadata template of specified template type.
527     * @param api the API connection to be used.
528     * @param templateName the metadata template type name.
529     * @return the metadata template returned from the server.
530     */
531    public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api, String templateName) {
532        String scope = scopeBasedOnType(templateName);
533        return getMetadataTemplate(api, templateName, scope);
534    }
535
536    /**
537     * Gets the metadata template of specified template type.
538     * @param api the API connection to be used.
539     * @param templateName the metadata template type name.
540     * @param scope the metadata template scope (global or enterprise).
541     * @param fields the fields to retrieve.
542     * @return the metadata template returned from the server.
543     */
544    public static MetadataTemplate getMetadataTemplate(
545            BoxAPIConnection api, String templateName, String scope, String ... fields) {
546        QueryStringBuilder builder = new QueryStringBuilder();
547        if (fields.length > 0) {
548            builder.appendParam("fields", fields);
549        }
550        URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildAlphaWithQuery(
551                api.getBaseURL(), builder.toString(), scope, templateName);
552        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
553        BoxJSONResponse response = (BoxJSONResponse) request.send();
554        return new MetadataTemplate(response.getJSON());
555    }
556
557    /**
558     * Geta the specified metadata template by its ID.
559     * @param api the API connection to be used.
560     * @param templateID the ID of the template to get.
561     * @return the metadata template object.
562     */
563    public static MetadataTemplate getMetadataTemplateByID(BoxAPIConnection api, String templateID) {
564
565        URL url = METADATA_TEMPLATE_BY_ID_URL_TEMPLATE.buildAlpha(api.getBaseURL(), templateID);
566        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
567        BoxJSONResponse response = (BoxJSONResponse) request.send();
568        return new MetadataTemplate(response.getJSON());
569    }
570
571    /**
572     * Returns all metadata templates within a user's enterprise.
573     * @param api the API connection to be used.
574     * @param fields the fields to retrieve.
575     * @return the metadata template returned from the server.
576     */
577    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(BoxAPIConnection api, String ... fields) {
578        return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, api, fields);
579    }
580
581    /**
582     * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported.
583     * @param scope the scope of the metadata templates.
584     * @param api the API connection to be used.
585     * @param fields the fields to retrieve.
586     * @return the metadata template returned from the server.
587     */
588    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(
589            String scope, BoxAPIConnection api, String ... fields) {
590        return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, DEFAULT_ENTRIES_LIMIT, api, fields);
591    }
592
593    /**
594     * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported.
595     * @param scope the scope of the metadata templates.
596     * @param limit maximum number of entries per response.
597     * @param api the API connection to be used.
598     * @param fields the fields to retrieve.
599     * @return the metadata template returned from the server.
600     */
601    public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(
602            String scope, int limit, BoxAPIConnection api, String ... fields) {
603        QueryStringBuilder builder = new QueryStringBuilder();
604        if (fields.length > 0) {
605            builder.appendParam("fields", fields);
606        }
607        return new BoxResourceIterable<MetadataTemplate>(
608                api, ENTERPRISE_METADATA_URL_TEMPLATE.buildAlphaWithQuery(
609                        api.getBaseURL(), builder.toString(), scope), limit) {
610
611            @Override
612            protected MetadataTemplate factory(JsonObject jsonObject) {
613                return new MetadataTemplate(jsonObject);
614            }
615        };
616    }
617
618    /**
619     * Determines the metadata scope based on type.
620     * @param typeName type of the metadata.
621     * @return scope of the metadata.
622     */
623    private static String scopeBasedOnType(String typeName) {
624        return typeName.equals(DEFAULT_METADATA_TYPE) ? GLOBAL_METADATA_SCOPE : ENTERPRISE_METADATA_SCOPE;
625    }
626
627    /**
628     * Class contains information about the metadata template field.
629     */
630    public static class Field extends BoxJSONObject {
631
632        /**
633         * @see #getID()
634         */
635        private String id;
636
637        /**
638         * @see #getType()
639         */
640        private String type;
641
642        /**
643         * @see #getKey()
644         */
645        private String key;
646
647        /**
648         * @see #getDisplayName()
649         */
650        private String displayName;
651
652        /**
653         * @see #getIsHidden()
654         */
655        private Boolean isHidden;
656
657        /**
658         * @see #getDescription()
659         */
660        private String description;
661
662        /**
663         * @see #getOptionsObject()
664         */
665        private List<Option> options;
666
667        /**
668         * Constructs an empty metadata template.
669         */
670        public Field() {
671            super();
672        }
673
674        /**
675         * Constructs a metadate template field from a JSON string.
676         * @param json the json encoded metadate template field.
677         */
678        public Field(String json) {
679            super(json);
680        }
681
682        /**
683         * Constructs a metadate template field from a JSON object.
684         * @param jsonObject the json encoded metadate template field.
685         */
686        Field(JsonObject jsonObject) {
687            super(jsonObject);
688        }
689
690        /**
691         * Gets the ID of the template field.
692         * @return the template field ID.
693         */
694        public String getID() {
695            return this.id;
696        }
697
698        /**
699         * Gets the data type of the field's value.
700         * @return the data type of the field's value.
701         */
702        public String getType() {
703            return this.type;
704        }
705
706        /**
707         * Sets the data type of the field's value.
708         * @param type the data type of the field's value.
709         */
710        public void setType(String type) {
711            this.type = type;
712        }
713
714        /**
715         * Gets the key of the field.
716         * @return the key of the field.
717         */
718        public String getKey() {
719            return this.key;
720        }
721
722        /**
723         * Sets the key of the field.
724         * @param key the key of the field.
725         */
726        public void setKey(String key) {
727            this.key = key;
728        }
729
730        /**
731         * Gets the display name of the field.
732         * @return the display name of the field.
733         */
734        public String getDisplayName() {
735            return this.displayName;
736        }
737
738        /**
739         * Sets the display name of the field.
740         * @param displayName the display name of the field.
741         */
742        public void setDisplayName(String displayName) {
743            this.displayName = displayName;
744        }
745
746        /**
747         * Gets is metadata template field hidden.
748         * @return is metadata template field hidden.
749         */
750        public Boolean getIsHidden() {
751            return this.isHidden;
752        }
753
754        /**
755         * Sets is metadata template field hidden.
756         * @param isHidden is metadata template field hidden?
757         */
758        public void setIsHidden(boolean isHidden) {
759            this.isHidden = isHidden;
760        }
761
762        /**
763         * Gets the description of the field.
764         * @return the description of the field.
765         */
766        public String getDescription() {
767            return this.description;
768        }
769
770        /**
771         * Sets the description of the field.
772         * @param description the description of the field.
773         */
774        public void setDescription(String description) {
775            this.description = description;
776        }
777
778        /**
779         * Gets list of possible options for enum type of the field.
780         * @return list of possible options for enum type of the field.
781         */
782        public List<String> getOptions() {
783            if (this.options == null) {
784                return null;
785            }
786            List<String> optionsList = new ArrayList<String>();
787            for (Option option : this.options) {
788                optionsList.add(option.getKey());
789            }
790            return optionsList;
791        }
792
793        /**
794         * Gets list of possible options for options type of the field.
795         * @return list of possible options for option type of the field.
796         */
797        public List<Option> getOptionsObjects() {
798            return this.options;
799        }
800
801        /**
802         * Sets list of possible options for enum type of the field.
803         * @param options list of possible options for enum type of the field.
804         */
805        public void setOptions(List<String> options) {
806            if (options == null) {
807                this.options = null;
808            }
809            List<Option> optionList = new ArrayList<Option>();
810            for (String key : options) {
811                JsonObject optionObject = new JsonObject();
812                optionObject.add("key", key);
813                Option newOption = new Option(optionObject);
814                optionList.add(newOption);
815            }
816            this.options = optionList;
817        }
818
819        /**
820         * {@inheritDoc}
821         */
822        @Override
823        void parseJSONMember(JsonObject.Member member) {
824            JsonValue value = member.getValue();
825            String memberName = member.getName();
826            if (memberName.equals("type")) {
827                this.type = value.asString();
828            } else if (memberName.equals("key")) {
829                this.key = value.asString();
830            } else if (memberName.equals("displayName")) {
831                this.displayName = value.asString();
832            } else if (memberName.equals("hidden")) {
833                this.isHidden = value.asBoolean();
834            } else if (memberName.equals("description")) {
835                this.description = value.asString();
836            } else if (memberName.equals("options")) {
837                this.options = new ArrayList<Option>();
838                for (JsonValue option : value.asArray()) {
839                    this.options.add(new Option(option.asObject()));
840                }
841            } else if (memberName.equals("id")) {
842                this.id = value.asString();
843            }
844        }
845    }
846
847    /**
848     * Class contains information about the metadata template option.
849     */
850    public static class Option extends BoxJSONObject {
851        /**
852         * @see #getID()
853         */
854        private String id;
855         /**
856         * @see #getKey()
857         */
858        private String key;
859         /**
860         * Constructs an empty metadata template.
861         */
862        public Option() {
863            super();
864        }
865         /**
866         * Constructs a metadate template option from a JSON string.
867         * @param json the json encoded metadata template option.
868         */
869        public Option(String json) {
870            super(json);
871        }
872
873         /**
874         * Constructs a metadate template option from a JSON object.
875         * @param jsonObject the json encoded metadate template option.
876         */
877        Option(JsonObject jsonObject) {
878            super(jsonObject);
879        }
880         /**
881         * Gets the ID of the template field.
882         * @return the template field ID.
883         */
884        public String getID() {
885            return this.id;
886        }
887         /**
888         * Gets the key of the field.
889         * @return the key of the field.
890         */
891        public String getKey() {
892            return this.key;
893        }
894
895        /**
896         * {@inheritDoc}
897         */
898        @Override
899        void parseJSONMember(JsonObject.Member member) {
900            JsonValue value = member.getValue();
901            String memberName = member.getName();
902            if (memberName.equals("id")) {
903                this.id = value.asString();
904            } else if (memberName.equals("key")) {
905                this.key = value.asString();
906            }
907        }
908    }
909
910    /**
911     * Posssible operations that can be performed in a Metadata template.
912     *  <ul>
913     *      <li>Add an enum option</li>
914     *      <li>Edit an enum option</li>
915     *      <li>Remove an enum option</li>
916     *      <li>Add a field</li>
917     *      <li>Edit a field</li>
918     *      <li>Remove a field</li>
919     *      <li>Edit template</li>
920     *      <li>Reorder the enum option</li>
921     *      <li>Reorder the field list</li>
922     *  </ul>
923     */
924    public static class FieldOperation extends BoxJSONObject {
925
926        private Operation op;
927        private Field data;
928        private String fieldKey;
929        private List<String> fieldKeys;
930        private List<String> enumOptionKeys;
931        private String enumOptionKey;
932        private String multiSelectOptionKey;
933        private List<String> multiSelectOptionKeys;
934
935        /**
936         * Constructs an empty FieldOperation.
937         */
938        public FieldOperation() {
939            super();
940        }
941
942        /**
943         * Constructs a Field operation from a JSON string.
944         * @param json the json encoded metadate template field.
945         */
946        public FieldOperation(String json) {
947            super(json);
948        }
949
950        /**
951         * Constructs a Field operation from a JSON object.
952         * @param jsonObject the json encoded metadate template field.
953         */
954        FieldOperation(JsonObject jsonObject) {
955            super(jsonObject);
956        }
957
958        /**
959         * Gets the operation.
960         * @return the operation
961         */
962        public Operation getOp() {
963            return this.op;
964        }
965
966        /**
967         * Gets the data associated with the operation.
968         * @return the field object representing the data
969         */
970        public Field getData() {
971            return this.data;
972        }
973
974        /**
975         * Gets the field key.
976         * @return the field key
977         */
978        public String getFieldKey() {
979            return this.fieldKey;
980        }
981
982        /**
983         * Gets the list of field keys.
984         * @return the list of Strings
985         */
986        public List<String> getFieldKeys() {
987            return this.fieldKeys;
988        }
989
990        /**
991         * Gets the list of keys of the Enum options.
992         * @return the list of Strings
993         */
994        public List<String> getEnumOptionKeys() {
995            return this.enumOptionKeys;
996        }
997
998        /**
999         * Sets the operation.
1000         * @param op the operation
1001         */
1002        public void setOp(Operation op) {
1003            this.op = op;
1004        }
1005
1006        /**
1007         * Sets the data.
1008         * @param data the Field object representing the data
1009         */
1010        public void setData(Field data) {
1011            this.data = data;
1012        }
1013
1014        /**
1015         * Sets the field key.
1016         * @param fieldKey the key of the field
1017         */
1018        public void setFieldKey(String fieldKey) {
1019            this.fieldKey = fieldKey;
1020        }
1021
1022        /**
1023         * Sets the list of the field keys.
1024         * @param fieldKeys the list of strings
1025         */
1026        public void setFieldKeys(List<String> fieldKeys) {
1027            this.fieldKeys = fieldKeys;
1028        }
1029
1030        /**
1031         * Sets the list of the enum option keys.
1032         * @param enumOptionKeys the list of Strings
1033         */
1034        public void setEnumOptionKeys(List<String> enumOptionKeys) {
1035            this.enumOptionKeys = enumOptionKeys;
1036        }
1037
1038        /**
1039         * Gets the enum option key.
1040         * @return the enum option key
1041         */
1042        public String getEnumOptionKey() {
1043            return this.enumOptionKey;
1044        }
1045
1046        /**
1047         * Sets the enum option key.
1048         * @param enumOptionKey the enum option key
1049         */
1050        public void setEnumOptionKey(String enumOptionKey) {
1051            this.enumOptionKey = enumOptionKey;
1052        }
1053
1054        /**
1055         * Gets the multi-select option key.
1056         * @return the key.
1057         */
1058        public String getMultiSelectOptionKey() {
1059            return this.multiSelectOptionKey;
1060        }
1061
1062        /**
1063         * Sets the multi-select option key.
1064         * @param key the key.
1065         */
1066        public void setMultiSelectOptionKey(String key) {
1067            this.multiSelectOptionKey = key;
1068        }
1069
1070        /**
1071         * Gets the list of multiselect option keys.
1072         * @return the list of keys.
1073         */
1074        public List<String> getMultiSelectOptionKeys() {
1075            return this.multiSelectOptionKeys;
1076        }
1077
1078        /**
1079         * Sets the multi-select option keys.
1080         * @param keys the list of keys.
1081         */
1082        public void setMultiSelectOptionKeys(List<String> keys) {
1083            this.multiSelectOptionKeys = keys;
1084        }
1085
1086        /**
1087         * {@inheritDoc}
1088         */
1089        @Override
1090        void parseJSONMember(JsonObject.Member member) {
1091            JsonValue value = member.getValue();
1092            String memberName = member.getName();
1093            if (memberName.equals("op")) {
1094                this.op = Operation.valueOf(value.asString());
1095            } else if (memberName.equals("data")) {
1096                this.data = new Field(value.asObject());
1097            } else if (memberName.equals("fieldKey")) {
1098                this.fieldKey = value.asString();
1099            } else if (memberName.equals("fieldKeys")) {
1100                if (this.fieldKeys == null) {
1101                    this.fieldKeys = new ArrayList<String>();
1102                } else {
1103                    this.fieldKeys.clear();
1104                }
1105
1106                JsonArray array = value.asArray();
1107                for (JsonValue jsonValue: array) {
1108                    this.fieldKeys.add(jsonValue.asString());
1109                }
1110            } else if (memberName.equals("enumOptionKeys")) {
1111                if (this.enumOptionKeys == null) {
1112                    this.enumOptionKeys = new ArrayList<String>();
1113                } else {
1114                    this.enumOptionKeys.clear();
1115                }
1116
1117                JsonArray array = value.asArray();
1118                for (JsonValue jsonValue: array) {
1119                    this.enumOptionKeys.add(jsonValue.asString());
1120                }
1121            } else if (memberName.equals("enumOptionKey")) {
1122                this.enumOptionKey = value.asString();
1123            } else if (memberName.equals("multiSelectOptionKey")) {
1124                this.multiSelectOptionKey = value.asString();
1125            } else if (memberName.equals("multiSelectOptionKeys")) {
1126                this.multiSelectOptionKeys = new ArrayList<String>();
1127                for (JsonValue key : value.asArray()) {
1128                    this.multiSelectOptionKeys.add(key.asString());
1129                }
1130            }
1131        }
1132    }
1133
1134    /**
1135     * Possible template operations.
1136     */
1137    public enum Operation {
1138
1139        /**
1140         * Adds an enum option at the end of the enum option list for the specified field.
1141         */
1142        addEnumOption,
1143
1144        /**
1145         * Edits the enum option.
1146         */
1147        editEnumOption,
1148
1149        /**
1150         * Removes the specified enum option from the specified enum field.
1151         */
1152        removeEnumOption,
1153
1154        /**
1155         * Adds a field at the end of the field list for the template.
1156         */
1157        addField,
1158
1159        /**
1160         * Edits any number of the base properties of a field: displayName, hidden, description.
1161         */
1162        editField,
1163
1164        /**
1165         * Removes the specified field from the template.
1166         */
1167        removeField,
1168
1169        /**
1170         * Edits any number of the base properties of a template: displayName, hidden.
1171         */
1172        editTemplate,
1173
1174        /**
1175         * Reorders the enum option list to match the requested enum option list.
1176         */
1177        reorderEnumOptions,
1178
1179        /**
1180         * Reorders the field list to match the requested field list.
1181         */
1182        reorderFields,
1183
1184        /**
1185         * Adds a new option to a multiselect field.
1186         */
1187        addMultiSelectOption,
1188
1189        /**
1190         * Edits an existing option in a multiselect field.
1191         */
1192        editMultiSelectOption,
1193
1194        /**
1195         * Removes an option from a multiselect field.
1196         */
1197        removeMultiSelectOption,
1198
1199        /**
1200         * Changes the display order of options in a multiselect field.
1201         */
1202        reorderMultiSelectOptions
1203    }
1204}