com.ibm.watson.developer_cloud.visual_recognition.v3.VisualRecognition.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.watson.developer_cloud.visual_recognition.v3.VisualRecognition.java

Source

/*
 * Copyright 2017 IBM Corp. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.ibm.watson.developer_cloud.visual_recognition.v3;

import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.reflect.TypeToken;
import com.ibm.watson.developer_cloud.http.HttpMediaType;
import com.ibm.watson.developer_cloud.http.RequestBuilder;
import com.ibm.watson.developer_cloud.http.ResponseConverter;
import com.ibm.watson.developer_cloud.http.ServiceCall;
import com.ibm.watson.developer_cloud.service.WatsonService;
import com.ibm.watson.developer_cloud.util.GsonSingleton;
import com.ibm.watson.developer_cloud.util.ResponseConverterUtils;
import com.ibm.watson.developer_cloud.util.Validator;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.AddImageToCollectionOptions;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifierOptions;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.ClassifyImagesOptions;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.Collection;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.CollectionImage;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.DetectedFaces;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.FindSimilarImagesOptions;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.RecognizedText;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.VisualClassification;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.VisualClassifier;
import com.ibm.watson.developer_cloud.visual_recognition.v3.model.VisualRecognitionOptions;

import okhttp3.HttpUrl;
import okhttp3.MultipartBody;
import okhttp3.MultipartBody.Builder;
import okhttp3.RequestBody;

/**
 * Visual Recognition allows you to derive insights from an image based on its visual content. You can organize image
 * libraries, understand an individual image, and create custom classifiers for specific results that are tailored to
 * your needs.
 *
 * @version v3
 * @see <a href= "http://www.ibm.com/watson/developercloud/visual-recognition.html"> Visual Recognition</a>
 */
public class VisualRecognition extends WatsonService {

    private static final String PARAM_API_KEY = "api_key";
    private static final String PARAM_CLASSIFIERS = "classifiers";
    private static final String PARAM_IMAGES_FILE = "images_file";
    private static final String PARAM_NAME = "name";
    private static final String PARAM_NEGATIVE_EXAMPLES = "negative_examples";
    private static final String PARAM_PARAMETERS = "parameters";
    private static final String PARAM_POSITIVE_EXAMPLES = "positive_examples";
    private static final String PARAM_URL = "url";
    private static final String PARAM_CLASSIFIER_IDS = "classifier_ids";
    private static final String PARAM_THRESHOLD = "threshold";
    private static final String PARAM_COLLECTIONS = "collections";
    private static final String PARAM_IMAGE_FILE = "image_file";
    private static final String PARAM_IMAGES = "images";
    private static final String PARAM_SIMILAR_IMAGES = "similar_images";
    private static final String PARAM_LIMIT = "limit";
    private static final String PARAM_METADATA = "metadata";

    private static final String PATH_CLASSIFIER = "/v3/classifiers/%s";
    private static final String PATH_CLASSIFIERS = "/v3/classifiers";
    private static final String PATH_CLASSIFY = "/v3/classify";
    private static final String PATH_DETECT_FACES = "/v3/detect_faces";
    private static final String PATH_RECOGNIZE_TEXT = "/v3/recognize_text";
    private static final String PATH_COLLECTION = "/v3/collections/%s";
    private static final String PATH_COLLECTIONS = "/v3/collections";
    private static final String PATH_COLLECTION_IMAGES = "/v3/collections/%s/images";
    private static final String PATH_COLLECTION_IMAGE = "/v3/collections/%s/images/%s";
    private static final String PATH_FIND_SIMILAR_IMAGES = "/v3/collections/%s/find_similar";

    private static final Type TYPE_LIST_IMAGES = new TypeToken<List<CollectionImage>>() {
    }.getType();
    private static final Type TYPE_LIST_COLLECTIONS = new TypeToken<List<Collection>>() {
    }.getType();
    private static final Type TYPE_LIST_CLASSIFIERS = new TypeToken<List<VisualClassifier>>() {
    }.getType();

    private static final String SERVICE_NAME = "watson_vision_combined";
    private static final String URL = "https://gateway-a.watsonplatform.net/visual-recognition/api";
    private static final String VERBOSE = "verbose";

    /** Version date. */
    public static final String VERSION_DATE_2016_05_20 = "2016-05-20";

    private String versionDate;

    /**
     * Instantiates a new Visual Recognition V3 service.
     *
     * @param versionDate The version date (yyyy-MM-dd) of the REST API to use. Specifying this value will keep your API
     *        calls from failing when the service introduces breaking changes.
     */
    public VisualRecognition(String versionDate) {
        super(SERVICE_NAME);
        if ((getEndPoint() == null) || getEndPoint().isEmpty()) {
            setEndPoint(URL);
        }
        Validator.notNull(versionDate, "versionDate cannot be null. Use '2016-05-19'");
        this.versionDate = versionDate;
    }

    /**
     * Instantiates a new Visual Recognition V3 service with a given API key.
     *
     * @param versionDate The version date (yyyy-MM-dd) of the REST API to use. Specifying this value will keep your API
     *        calls from failing when the service introduces breaking changes.
     * @param apiKey the api key
     */
    public VisualRecognition(String versionDate, String apiKey) {
        this(versionDate);
        setApiKey(apiKey);
    }

    /**
     * Adds the Alchemy API key to HTTP request.
     *
     * @param builder the builder
     * @param apiKey the API key token
     */
    private void addApiKeyToRequest(okhttp3.Request.Builder builder, String apiKey) {
        final HttpUrl url = HttpUrl.parse(builder.build().url().toString());
        if ((url.query() == null) || url.query().isEmpty()) {
            builder.url(builder.build().url() + "?" + apiKey);
        } else {
            builder.url(builder.build().url() + "&" + apiKey);
        }
    }

    private JsonObject getParametersAsJson(ClassifyImagesOptions options) {
        JsonObject ret = new JsonObject();

        if ((options.url() != null) && (options.images() == null)) {
            ret.addProperty(PARAM_URL, options.url().toString());
        }

        if ((options.classifierIds() != null) && !options.classifierIds().isEmpty()) {
            JsonArray array = new JsonArray();
            for (String cId : options.classifierIds()) {
                array.add(new JsonPrimitive(cId));
            }
            ret.add(PARAM_CLASSIFIER_IDS, array);
        }

        if (options.threshold() != null) {
            ret.addProperty(PARAM_THRESHOLD, options.threshold());
        }

        return ret;
    }

    /**
     * Gets the request parameters as {@link JsonObject}.
     *
     * @param options the options
     * @return the parameters as {@link JsonObject}
     */
    private JsonObject getParametersAsJson(VisualRecognitionOptions options) {
        JsonObject ret = new JsonObject();
        ret.addProperty(PARAM_URL, options.url().toString());
        return ret;
    }

    /*
     * (non-Javadoc)
     *
     * @see com.ibm.watson.developer_cloud.service.WatsonService#setAuthentication(okhttp3.Request. Builder)
     */
    @Override
    protected void setAuthentication(okhttp3.Request.Builder builder) {
        if (getApiKey() == null) {
            throw new IllegalArgumentException("api_key needs to be specified. Use setApiKey()");
        }
        addApiKeyToRequest(builder, PARAM_API_KEY + "=" + getApiKey());
    }

    /**
     * Classify.
     *
     * @param options the classify options
     * @return the {@link VisualClassification}
     */
    public ServiceCall<VisualClassification> classify(ClassifyImagesOptions options) {
        Validator.notNull(options, "'options' cannot be null");

        // build body
        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        if (options.images() != null) {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.images());
            bodyBuilder.addFormDataPart(PARAM_IMAGES_FILE, options.images().getName(), requestBody);
        }

        if (options.imagesBinary() != null) {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.imagesBinary());
            bodyBuilder.addFormDataPart(PARAM_IMAGES_FILE, options.imageName(), requestBody);
        }

        bodyBuilder.addFormDataPart(PARAM_PARAMETERS, getParametersAsJson(options).toString());

        RequestBuilder requestBuilder = RequestBuilder.post(PATH_CLASSIFY);
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(),
                ResponseConverterUtils.getObject(VisualClassification.class));
    }

    /**
     * Train a new classifier on the uploaded image data. Upload a compressed (.zip) file of images (.jpg, .png, or .gif)
     * with positive examples that show your classifier and another compressed file with negative examples that are
     * similar to but do NOT show your classifier. <br>
     *
     * @param options The parameters to create a classifier
     * @return The created {@link VisualClassifier}
     * @see ClassifierOptions
     * @see VisualClassifier
     */
    public ServiceCall<VisualClassifier> createClassifier(ClassifierOptions options) {
        Validator.notNull(options, " options cannot be null");
        validateClassifierOptions(options);

        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        bodyBuilder.addFormDataPart(PARAM_NAME, options.classifierName());

        // Classes
        for (String className : options.classNames()) {
            String dataName = className + "_" + PARAM_POSITIVE_EXAMPLES;
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE,
                    options.positiveExamplesByClassName(className));
            bodyBuilder.addFormDataPart(dataName, options.positiveExamplesByClassName(className).getName(),
                    requestBody);
        }

        if (options.negativeExamples() != null) {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.negativeExamples());
            bodyBuilder.addFormDataPart(PARAM_NEGATIVE_EXAMPLES, options.negativeExamples().getName(), requestBody);
        }

        RequestBuilder requestBuilder = RequestBuilder.post(PATH_CLASSIFIERS);
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(VisualClassifier.class));
    }

    /**
     * Validates the {@link ClassifierOptions}.
     *
     * @param options the options
     */
    private void validateClassifierOptions(ClassifierOptions options) {
        String errorMessage = "To create a classifier, you must supply at least 2 zip files - "
                + "either 2 positive example sets, or 1 positive and 1 negative set";

        Validator.notNull(options.classifierName(), "'classifierName' cannot be null");
        Validator.isTrue(!options.classNames().isEmpty(), "There are no classes. " + errorMessage);

        boolean hasExamples = (options.classNames().size() > 1)
                || ((options.negativeExamples() != null) && (options.classNames().size() == 1));
        Validator.isTrue(hasExamples, errorMessage);
    }

    /**
     * Update an existing classifier by adding new classes, or by adding new images to existing classes. To update the
     * existing classifier, use several compressed (.zip) files, including files containing positive or negative images
     * (.jpg, or .png). You must supply at least one compressed file, with additional positive or negative examples. <br>
     *
     * @param classifierId the classifier id
     * @param options The parameters to create a classifier
     * @return The created {@link VisualClassifier}
     * @see ClassifierOptions
     * @see VisualClassifier
     */
    public ServiceCall<VisualClassifier> updateClassifier(String classifierId, ClassifierOptions options) {
        Validator.notNull(classifierId, "classifierId cannot be null");
        Validator.notNull(options, " options cannot be null");
        String errorMessage = "To update a classifier, you must supply at least 1 zip file - "
                + "either a positive or negative zip file.";
        Validator.isTrue(!options.classNames().isEmpty() || (options.negativeExamples() != null), errorMessage);

        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        // Classes
        for (String className : options.classNames()) {
            String dataName = className + "_" + PARAM_POSITIVE_EXAMPLES;
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE,
                    options.positiveExamplesByClassName(className));
            bodyBuilder.addFormDataPart(dataName, options.positiveExamplesByClassName(className).getName(),
                    requestBody);
        }

        if (options.negativeExamples() != null) {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.negativeExamples());
            bodyBuilder.addFormDataPart(PARAM_NEGATIVE_EXAMPLES, options.negativeExamples().getName(), requestBody);
        }

        RequestBuilder requestBuilder = RequestBuilder.post(String.format(PATH_CLASSIFIER, classifierId));
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(VisualClassifier.class));
    }

    /**
     * Deletes a classifier.
     *
     * @param classifierId the classifier ID to delete
     * @return the service call
     * @see VisualClassifier
     */
    public ServiceCall<Void> deleteClassifier(String classifierId) {
        Validator.isTrue((classifierId != null) && !classifierId.isEmpty(), "classifierId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder.delete(String.format(PATH_CLASSIFIER, classifierId));
        requestBuilder.query(VERSION, versionDate);
        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getVoid());
    }

    /**
     * Detect faces.
     *
     * @param options the recognize text options
     * @return the {@link VisualClassification}
     */
    public ServiceCall<DetectedFaces> detectFaces(VisualRecognitionOptions options) {
        // build body
        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (options.url() != null) {
            bodyBuilder.addFormDataPart(PARAM_PARAMETERS, getParametersAsJson(options).toString());
        } else {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.images());
            bodyBuilder.addFormDataPart(PARAM_IMAGES_FILE, options.images().getName(), requestBody);
        }

        RequestBuilder requestBuilder = RequestBuilder.post(PATH_DETECT_FACES);
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(DetectedFaces.class));
    }

    /**
     * Retrieve information about a specific classifier. Only user-trained classifiers may be addressed.
     *
     * @param classifierId the classifier ID
     * @return the classifier
     * @see VisualClassifier
     */
    public ServiceCall<VisualClassifier> getClassifier(String classifierId) {
        Validator.isTrue((classifierId != null) && !classifierId.isEmpty(), "classifierId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder.get(String.format(PATH_CLASSIFIER, classifierId));
        requestBuilder.query(VERSION, versionDate);
        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(VisualClassifier.class));
    }

    /**
     * Retrieve the user-trained classifiers.
     *
     * @return the classifier list
     * @see VisualClassifier
     */
    public ServiceCall<List<VisualClassifier>> getClassifiers() {
        RequestBuilder requestBuilder = RequestBuilder.get(PATH_CLASSIFIERS).query(VERSION, versionDate)
                .query(VERBOSE, true);

        ResponseConverter<List<VisualClassifier>> converter = ResponseConverterUtils
                .getGenericObject(TYPE_LIST_CLASSIFIERS, PARAM_CLASSIFIERS);
        return createServiceCall(requestBuilder.build(), converter);
    }

    /**
     * Recognize text.
     *
     * @param options the recognize text options
     * @return the {@link RecognizedText}
     */
    public ServiceCall<RecognizedText> recognizeText(VisualRecognitionOptions options) {

        // build body
        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (options.url() != null) {
            bodyBuilder.addFormDataPart(PARAM_PARAMETERS, getParametersAsJson(options).toString());
        } else {
            RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.images());
            bodyBuilder.addFormDataPart(PARAM_IMAGES_FILE, options.images().getName(), requestBody);
        }

        RequestBuilder requestBuilder = RequestBuilder.post(PATH_RECOGNIZE_TEXT);
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(RecognizedText.class));
    }

    /**
     * The Visual Recognition V3 service use an <code>api_key</code> instead of username and password. <br>
     * Use: {@link VisualRecognition#setApiKey(String)}
     *
     * @param username the username
     * @param password the password
     */
    @Override
    @Deprecated
    public void setUsernameAndPassword(String username, String password) {
        throw new IllegalArgumentException("This service requires an api_key. Use the setApiKey() method instead");
    }

    /**
     * Gets the collections.
     *
     * @return the collections
     */
    public ServiceCall<List<Collection>> getCollections() {
        RequestBuilder requestBuilder = RequestBuilder.get(PATH_COLLECTIONS).query(VERSION, versionDate);
        ResponseConverter<List<Collection>> converter = ResponseConverterUtils
                .getGenericObject(TYPE_LIST_COLLECTIONS, PARAM_COLLECTIONS);
        return createServiceCall(requestBuilder.build(), converter);
    }

    /**
     * Gets the collection information.
     *
     * @param collectionId the collection id
     * @return the collection
     */
    public ServiceCall<Collection> getCollection(String collectionId) {
        Validator.isTrue((collectionId != null) && !collectionId.isEmpty(), "collectionId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder.get(String.format(PATH_COLLECTION, collectionId));
        requestBuilder.query(VERSION, versionDate);
        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(Collection.class));
    }

    /**
     * Deletes a collection.
     *
     * @param collectionId the collection id
     * @return the service call
     */
    public ServiceCall<Void> deleteCollection(String collectionId) {
        Validator.isTrue((collectionId != null) && !collectionId.isEmpty(), "collectionId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder.delete(String.format(PATH_COLLECTION, collectionId));
        requestBuilder.query(VERSION, versionDate);
        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getVoid());
    }

    /**
     * Deletes a collection.
     *
     * @param collectionId the collection id
     * @param imageId the image id
     * @return the service call
     */
    public ServiceCall<Void> deleteCollectionImage(String collectionId, String imageId) {
        Validator.isTrue((collectionId != null) && !collectionId.isEmpty(), "collectionId cannot be null or empty");
        Validator.isTrue((imageId != null) && !imageId.isEmpty(), "imageId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder
                .delete(String.format(PATH_COLLECTION_IMAGE, collectionId, imageId));
        requestBuilder.query(VERSION, versionDate);
        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getVoid());
    }

    /**
     * Adds the image to collection.
     *
     * @param options the options
     * @return the service call
     */
    public ServiceCall<Void> addImageToCollection(AddImageToCollectionOptions options) {
        Validator.notNull(options, " options cannot be null");

        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.image());
        bodyBuilder.addFormDataPart(PARAM_IMAGE_FILE, options.image().getName(), requestBody);

        if (options.metadata() != null && !options.metadata().isEmpty()) {
            String metadata = GsonSingleton.getGsonWithoutPrettyPrinting().toJson(options.metadata());
            bodyBuilder.addFormDataPart(PARAM_METADATA, metadata);
        }

        RequestBuilder requestBuilder = RequestBuilder
                .post(String.format(PATH_COLLECTION_IMAGES, options.collectionId()));
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getVoid());
    }

    /**
     * Gets the collection images.
     *
     * @param collectionId the collection id
     * @return the collection images
     */
    public ServiceCall<List<CollectionImage>> getCollectionImages(String collectionId) {
        Validator.isTrue((collectionId != null) && !collectionId.isEmpty(), "collectionId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder.get(String.format(PATH_COLLECTION_IMAGES, collectionId))
                .query(VERSION, versionDate);

        ResponseConverter<List<CollectionImage>> converter = ResponseConverterUtils
                .getGenericObject(TYPE_LIST_IMAGES, PARAM_IMAGES);
        return createServiceCall(requestBuilder.build(), converter);
    }

    /**
     * Gets the collection image.
     *
     * @param collectionId the collection id
     * @param imageId the imageId
     * @return the collection image
     */
    public ServiceCall<CollectionImage> getCollectionImage(String collectionId, String imageId) {
        Validator.isTrue((collectionId != null) && !collectionId.isEmpty(), "collectionId cannot be null or empty");
        Validator.isTrue((imageId != null) && !imageId.isEmpty(), "imageId cannot be null or empty");

        RequestBuilder requestBuilder = RequestBuilder
                .get(String.format(PATH_COLLECTION_IMAGE, collectionId, imageId)).query(VERSION, versionDate);

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(CollectionImage.class));
    }

    /**
     * Find similar images.
     *
     * @param options the options
     * @return the service call
     */
    public ServiceCall<List<CollectionImage>> findSimilarImages(FindSimilarImagesOptions options) {
        Validator.notNull(options, "'options' cannot be null");

        Builder bodyBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        RequestBody requestBody = RequestBody.create(HttpMediaType.BINARY_FILE, options.image());
        bodyBuilder.addFormDataPart(PARAM_IMAGE_FILE, options.image().getName(), requestBody);

        RequestBuilder requestBuilder = RequestBuilder
                .post(String.format(PATH_FIND_SIMILAR_IMAGES, options.collectionId()));
        requestBuilder.query(VERSION, versionDate).body(bodyBuilder.build());

        if (options.limit() != null) {
            requestBuilder.query(PARAM_LIMIT, options.limit());
        }

        ResponseConverter<List<CollectionImage>> converter = ResponseConverterUtils
                .getGenericObject(TYPE_LIST_IMAGES, PARAM_SIMILAR_IMAGES);

        return createServiceCall(requestBuilder.build(), converter);
    }

    /**
     * Creates a collection.
     *
     * @param name the collection name
     * @return the service call
     */
    public ServiceCall<Collection> createCollection(String name) {
        Validator.isTrue((name != null) && !name.isEmpty(), "collectionId cannot be null or empty");

        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart(PARAM_NAME, name)
                .build();

        RequestBuilder requestBuilder = RequestBuilder.post(PATH_COLLECTIONS);
        requestBuilder.body(body);
        requestBuilder.query(VERSION, versionDate);
        requestBuilder.query(PARAM_NAME, name);

        return createServiceCall(requestBuilder.build(), ResponseConverterUtils.getObject(Collection.class));
    }
}