com.unboundid.scim2.client.requests.SearchRequestBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.unboundid.scim2.client.requests.SearchRequestBuilder.java

Source

/*
 * Copyright 2015-2017 UnboundID Corp.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses>.
 */

package com.unboundid.scim2.client.requests;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.unboundid.scim2.client.ScimService;
import com.unboundid.scim2.client.SearchResultHandler;
import com.unboundid.scim2.common.ScimResource;
import com.unboundid.scim2.common.exceptions.ScimException;
import com.unboundid.scim2.common.messages.ListResponse;
import com.unboundid.scim2.common.messages.SearchRequest;
import com.unboundid.scim2.common.messages.SortOrder;
import com.unboundid.scim2.common.utils.ApiConstants;
import com.unboundid.scim2.common.utils.JsonUtils;
import com.unboundid.scim2.common.utils.SchemaUtils;
import com.unboundid.scim2.common.utils.StaticUtils;

import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.unboundid.scim2.common.utils.ApiConstants.QUERY_PARAMETER_FILTER;
import static com.unboundid.scim2.common.utils.ApiConstants.QUERY_PARAMETER_PAGE_SIZE;
import static com.unboundid.scim2.common.utils.ApiConstants.QUERY_PARAMETER_PAGE_START_INDEX;
import static com.unboundid.scim2.common.utils.ApiConstants.QUERY_PARAMETER_SORT_BY;
import static com.unboundid.scim2.common.utils.ApiConstants.QUERY_PARAMETER_SORT_ORDER;

/**
 * A builder for SCIM search requests.
 */
public final class SearchRequestBuilder extends ResourceReturningRequestBuilder<SearchRequestBuilder> {
    private String filter;
    private String sortBy;
    private SortOrder sortOrder;
    private Integer startIndex;
    private Integer count;

    /**
     * Create a new  search request builder.
     *
     * @param target The WebTarget to search.
     */
    public SearchRequestBuilder(final WebTarget target) {
        super(target);
    }

    /**
     * Request filtering of resources.
     *
     * @param filter the filter string used to request a subset of resources.
     * @return This builder.
     */
    public SearchRequestBuilder filter(final String filter) {
        this.filter = filter;
        return this;
    }

    /**
     * Request sorting of resources.
     *
     * @param sortBy the string indicating the attribute whose value shall be used
     *               to order the returned responses.
     * @param sortOrder the order in which the sortBy parameter is applied.
     * @return This builder.
     */
    public SearchRequestBuilder sort(final String sortBy, final SortOrder sortOrder) {
        this.sortBy = sortBy;
        this.sortOrder = sortOrder;
        return this;
    }

    /**
     * Request pagination of resources.
     *
     * @param startIndex the 1-based index of the first query result.
     * @param count the desired maximum number of query results per page.
     * @return This builder.
     */
    public SearchRequestBuilder page(final int startIndex, final int count) {
        this.startIndex = startIndex;
        this.count = count;
        return this;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    WebTarget buildTarget() {
        WebTarget target = super.buildTarget();
        if (filter != null) {
            target = target.queryParam(QUERY_PARAMETER_FILTER, filter);
        }
        if (sortBy != null && sortOrder != null) {
            target = target.queryParam(QUERY_PARAMETER_SORT_BY, sortBy);
            target = target.queryParam(QUERY_PARAMETER_SORT_ORDER, sortOrder.getName());
        }
        if (startIndex != null && count != null) {
            target = target.queryParam(QUERY_PARAMETER_PAGE_START_INDEX, startIndex);
            target = target.queryParam(QUERY_PARAMETER_PAGE_SIZE, count);
        }
        return target;
    }

    /**
     * Invoke the SCIM retrieve request using GET.
     *
     * @param <T> The type of objects to return.
     * @param cls The Java class object used to determine the type to return.
     * @return The ListResponse containing the search results.
     * @throws ScimException If an error occurred.
     */
    public <T> ListResponse<T> invoke(final Class<T> cls) throws ScimException {
        ListResponseBuilder<T> listResponseBuilder = new ListResponseBuilder<T>();
        invoke(false, listResponseBuilder, cls);
        return listResponseBuilder.build();
    }

    /**
     * Invoke the SCIM retrieve request using GET.
     *
     * @param <T> The type of objects to return.
     * @param resultHandler The search result handler that should be used to
     *                      process the resources.
     * @param cls The Java class object used to determine the type to return.
     * @throws ScimException If an error occurred.
     */
    public <T> void invoke(final SearchResultHandler<T> resultHandler, final Class<T> cls) throws ScimException {
        invoke(false, resultHandler, cls);
    }

    /**
     * Invoke the SCIM retrieve request using POST.
     *
     * @param <T> The type of objects to return.
     * @param cls The Java class object used to determine the type to return.
     * @return The ListResponse containing the search results.
     * @throws ScimException If an error occurred.
     */
    public <T extends ScimResource> ListResponse<T> invokePost(final Class<T> cls) throws ScimException {
        ListResponseBuilder<T> listResponseBuilder = new ListResponseBuilder<T>();
        invoke(true, listResponseBuilder, cls);
        return listResponseBuilder.build();
    }

    /**
     * Invoke the SCIM retrieve request using POST.
     *
     * @param <T> The type of objects to return.
     * @param resultHandler The search result handler that should be used to
     *                      process the resources.
     * @param cls The Java class object used to determine the type to return.
     * @throws ScimException If an error occurred.
     */
    public <T> void invokePost(final SearchResultHandler<T> resultHandler, final Class<T> cls)
            throws ScimException {
        invoke(true, resultHandler, cls);
    }

    /**
     * Invoke the SCIM retrieve request.
     *
     * @param post {@code true} to send the request using POST or {@code false}
     *             to send the request using GET.
     * @param <T> The type of objects to return.
     * @param resultHandler The search result handler that should be used to
     *                      process the resources.
     * @param cls The Java class object used to determine the type to return.
     * @throws ScimException If an error occurred.
     */
    private <T> void invoke(final boolean post, final SearchResultHandler<T> resultHandler, final Class<T> cls)
            throws ScimException {
        Response response;
        if (post) {
            Set<String> attributeSet = null;
            Set<String> excludedAttributeSet = null;
            if (attributes != null && attributes.size() > 0) {
                if (!excluded) {
                    attributeSet = attributes;
                } else {
                    excludedAttributeSet = attributes;
                }
            }

            SearchRequest searchRequest = new SearchRequest(attributeSet, excludedAttributeSet, filter, sortBy,
                    sortOrder, startIndex, count);

            Invocation.Builder builder = target().path(ApiConstants.SEARCH_WITH_POST_PATH_EXTENSION)
                    .request(ScimService.MEDIA_TYPE_SCIM_TYPE, MediaType.APPLICATION_JSON_TYPE);
            for (Map.Entry<String, List<Object>> header : headers.entrySet()) {
                builder = builder.header(header.getKey(), StaticUtils.listToString(header.getValue(), ", "));
            }
            response = builder.post(Entity.entity(searchRequest, getContentType()));
        } else {
            response = buildRequest().get();
        }

        try {
            if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
                InputStream inputStream = response.readEntity(InputStream.class);
                try {
                    JsonParser parser = JsonUtils.getObjectReader().getFactory().createParser(inputStream);
                    try {
                        parser.nextToken();
                        boolean stop = false;
                        while (!stop && parser.nextToken() != JsonToken.END_OBJECT) {
                            String field = parser.getCurrentName();
                            parser.nextToken();
                            if (field.equals("schemas")) {
                                parser.skipChildren();
                            } else if (field.equals("totalResults")) {
                                resultHandler.totalResults(parser.getIntValue());
                            } else if (field.equals("startIndex")) {
                                resultHandler.startIndex(parser.getIntValue());
                            } else if (field.equals("itemsPerPage")) {
                                resultHandler.itemsPerPage(parser.getIntValue());
                            } else if (field.equals("Resources")) {
                                while (parser.nextToken() != JsonToken.END_ARRAY) {
                                    if (!resultHandler.resource(parser.readValueAs(cls))) {
                                        stop = true;
                                        break;
                                    }
                                }
                            } else if (SchemaUtils.isUrn(field)) {
                                resultHandler.extension(field, parser.<ObjectNode>readValueAsTree());
                            } else {
                                // Just skip this field
                                parser.nextToken();
                            }
                        }
                    } finally {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        parser.close();
                    }
                } catch (IOException e) {
                    throw new ResponseProcessingException(response, e);
                }
            } else {
                throw toScimException(response);
            }
        } finally {
            response.close();
        }
    }
}