org.icgc.dcc.portal.resource.Resource.java Source code

Java tutorial

Introduction

Here is the source code for org.icgc.dcc.portal.resource.Resource.java

Source

/*
 * Copyright (c) 2016 The Ontario Institute for Cancer Research. All rights reserved.                             
 *                                                                                                               
 * This program and the accompanying materials are made available under the terms of the GNU Public License v3.0.
 * You should have received a copy of the GNU General Public License along with                                  
 * this program. If not, see <http://www.gnu.org/licenses/>.                                                     
 *                                                                                                               
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY                           
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES                          
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT                           
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,                                
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED                          
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;                               
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER                              
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN                         
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.icgc.dcc.portal.resource;

import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
import static org.apache.commons.collections.CollectionUtils.isEmpty;

import java.net.URI;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Supplier;

import javax.validation.Validation;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import org.icgc.dcc.common.core.json.JsonNodeBuilders.ObjectNodeBuilder;
import org.icgc.dcc.common.core.util.Joiners;
import org.icgc.dcc.common.core.util.Splitters;
import org.icgc.dcc.portal.model.Error;
import org.icgc.dcc.portal.model.Query;
import org.icgc.dcc.portal.model.Query.QueryBuilder;
import org.icgc.dcc.portal.model.param.FiltersParam;
import org.icgc.dcc.portal.resource.entity.MutationResource;
import org.icgc.dcc.portal.service.BadRequestException;
import org.icgc.dcc.portal.util.JsonUtils;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Maps;
import com.yammer.dropwizard.jersey.params.IntParam;

import lombok.NonNull;
import lombok.val;
import lombok.extern.slf4j.Slf4j;

/**
 * Base classes for all API resources.
 */
@Slf4j
public abstract class Resource {

    /**
     * Default constants.
     */
    protected static final String DEFAULT_FIELDS = "";
    protected static final String DEFAULT_FILTERS = "{}";
    protected static final String DEFAULT_FACETS = "true";
    protected static final String DEFAULT_SIZE = "10";
    protected static final String DEFAULT_FROM = "1";
    protected static final String DEFAULT_SORT = "_score";
    protected static final String DEFAULT_ORDER = "desc";
    protected static final String DEFAULT_MIN_SCORE = "0";

    protected static final String DEFAULT_PROJECT_SORT = "totalLiveDonorCount";
    protected static final String DEFAULT_OCCURRENCE_SORT = "donorId";
    protected static final String DEFAULT_DONOR_SORT = "ssmAffectedGenes";
    protected static final String DEFAULT_GENE_MUTATION_SORT = "affectedDonorCountFiltered";

    /**
     * Logging template constants.
     */
    protected static final String COUNT_TEMPLATE = "Request for a count of {} with filters '{}'";
    protected static final String FIND_ALL_TEMPLATE = "Request for '{}' {} from index '{}', sorted by '{}' in '{}' order with filters '{}'";
    protected static final String FIND_ONE_TEMPLATE = "Request for '{}'";
    protected static final String NESTED_FIND_TEMPLATE = "Request {} for '{}'";
    protected static final String NESTED_COUNT_TEMPLATE = "Request {} count for '{}'";
    protected static final String NESTED_NESTED_COUNT_TEMPLATE = "Request count of '{}' in '{}' affected by '{}'";

    /**
     * Other constants.
     */
    protected static final Joiner COMMA_JOINER = Joiners.COMMA.skipNulls();
    protected static final Splitter COMMA_SPLITTER = Splitters.COMMA.omitEmptyStrings().trimResults();

    /**
     * JAX-RS URI information for building mutation links.
     */
    @Context
    protected UriInfo uriInfo;

    /**
     * Creates a mutation URL from the supplied mutation id.
     * 
     * @param mutationId - the mutation id
     * @return the mutation URL
     */
    protected URI mutationUrl(String mutationId) {
        return uriInfo.getBaseUriBuilder().path(MutationResource.class).path(mutationId).build();
    }

    protected boolean hasParam(String name) {
        return uriInfo.getQueryParameters().containsKey(name);
    }

    /**
     * Readability methods for map building.
     * 
     * @return the map builder
     */
    protected static Builder<String, Object> response() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static Builder<String, Object> hit() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static Builder<String, Object> record() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static Builder<String, Object> mutation() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static Builder<String, Object> consequence() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static Builder<String, Object> fields() {
        return ImmutableMap.<String, Object>builder();
    }

    protected static FiltersParam filtersParam(ObjectNode objectNode) {
        return new FiltersParam(objectNode.toString());
    }

    protected static FiltersParam filtersParam(ObjectNodeBuilder builder) {
        return filtersParam(builder.end());
    }

    protected static ObjectNode mergeFilters(ObjectNode filters, String template, Object... objects) {
        return JsonUtils.merge(filters, (new FiltersParam(String.format(template, objects)).get()));
    }

    protected static List<String> commaValues(String text) {
        return COMMA_SPLITTER.splitToList(text);
    }

    protected static QueryBuilder query() {
        return Query.builder();
    }

    protected static Query query(FiltersParam filters) {
        return query(filters.get());
    }

    protected static Query query(ObjectNode filters) {
        return query().filters(filters).build();
    }

    protected static Query query(List<String> fields, List<String> include, ObjectNode filters, IntParam from,
            IntParam size, String sort, String order) {
        val query = query().fields(fields).filters(filters).from(from.get()).size(size.get()).sort(sort)
                .order(order);

        clean(include);
        if (!include.isEmpty()) {
            query.includes(include);
        }

        return query.build();
    }

    protected static LinkedHashMap<String, Query> queries(ObjectNode filters, String filterTemplate,
            List<String> ids) {
        val queries = Maps.<String, Query>newLinkedHashMap();

        for (String id : ids) {
            val filter = mergeFilters(filters, filterTemplate, id);
            queries.put(id, query().filters(filter).build());
        }
        return queries;
    }

    protected static LinkedHashMap<String, Query> queries(ObjectNode filters, String filterTemplate,
            List<String> ids, String anchorId) {
        val queries = Maps.<String, Query>newLinkedHashMap();

        for (String id : ids) {
            val filter = mergeFilters(filters, filterTemplate, id, anchorId);
            queries.put(id, query().filters(filter).build());
        }
        return queries;
    }

    protected static LinkedHashMap<String, LinkedHashMap<String, Query>> queries(ObjectNode filters,
            String filterTemplate, List<String> ids, List<String> anchorIds) {
        val queries = Maps.<String, LinkedHashMap<String, Query>>newLinkedHashMap();

        for (String anchorId : anchorIds) {
            queries.put(anchorId, queries(filters, filterTemplate, ids, anchorId));
        }

        return queries;
    }

    /**
     * @see http://stackoverflow.com/questions/23704616/how-to-validate-a-single-parameter-in-dropwizard
     */
    protected static void validate(@NonNull Object object) {
        val errorMessages = new ArrayList<String>();
        val validator = Validation.buildDefaultValidatorFactory().getValidator();

        val violations = validator.validate(object);
        if (!violations.isEmpty()) {
            for (val violation : violations) {
                errorMessages.add("'" + violation.getPropertyPath() + "' " + violation.getMessage());
            }

            throw new BadRequestException(COMMA_JOINER.join(errorMessages));
        }
    }

    protected static Response error(Status status, String message) {
        return Response.status(status).type(APPLICATION_JSON_TYPE).entity(new Error(status, message)).build();
    }

    protected static <E extends Enum<E>> boolean isValidEnum(Class<E> enumClass, String enumName) {
        if (enumName == null) {
            return false;
        }
        try {
            Enum.valueOf(enumClass, enumName);
            return true;
        } catch (final IllegalArgumentException ex) {
            return false;
        }
    }

    protected static void checkRequest(boolean errorCondition, String formatTemplate, Object... args) {
        if (errorCondition) {
            // We don't want exception within an exception-handling routine.
            final Supplier<String> errorMessageProvider = () -> {
                try {
                    return format(formatTemplate, args);
                } catch (Exception e) {
                    final String errorDetails = "message: '" + formatTemplate + "', parameters: '"
                            + COMMA_JOINER.join(args) + "'";
                    log.error("Error while formatting message - " + errorDetails, e);

                    return "Invalid web request - " + errorDetails;
                }
            };

            throw new BadRequestException(errorMessageProvider.get());
        }
    }

    protected static List<String> clean(List<String> source) {
        if (isEmpty(source)) {
            return source;
        }

        source.removeAll(newArrayList("", null));

        return source;
    }

    protected CacheControl noCache() {
        val cacheControl = new CacheControl();
        cacheControl.setNoCache(true);

        return cacheControl;
    }

}