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