001/*
002 * Copyright 2015-2019 Ping Identity Corporation
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the GNU General Public License (GPLv2 only)
006 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
007 * as published by the Free Software Foundation.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012 * GNU General Public License for more details.
013 *
014 * You should have received a copy of the GNU General Public License
015 * along with this program; if not, see <http://www.gnu.org/licenses>.
016 */
017
018package com.unboundid.scim2.server.providers;
019
020import com.fasterxml.jackson.core.JsonParser;
021import com.fasterxml.jackson.databind.ObjectReader;
022import com.unboundid.scim2.common.messages.SearchRequest;
023import com.unboundid.scim2.common.utils.JsonUtils;
024import com.unboundid.scim2.common.utils.StaticUtils;
025import com.unboundid.scim2.server.utils.ServerUtils;
026
027import javax.annotation.Priority;
028import javax.ws.rs.BadRequestException;
029import javax.ws.rs.HttpMethod;
030import javax.ws.rs.NotSupportedException;
031import javax.ws.rs.Priorities;
032import javax.ws.rs.container.ContainerRequestContext;
033import javax.ws.rs.container.ContainerRequestFilter;
034import javax.ws.rs.container.PreMatching;
035import javax.ws.rs.core.MediaType;
036import javax.ws.rs.core.NoContentException;
037import javax.ws.rs.core.PathSegment;
038import javax.ws.rs.core.UriBuilder;
039import javax.ws.rs.ext.Provider;
040import java.io.IOException;
041import java.util.List;
042
043import static com.unboundid.scim2.common.utils.ApiConstants.*;
044
045/**
046 * A ContainerRequestFilter implementation to convert a search request using
047 * HTTP POST combine with the "{@code .search}" path extension to a regular search
048 * using HTTP GET.
049 */
050@Provider
051@PreMatching
052@Priority(Priorities.ENTITY_CODER)
053public class DotSearchFilter implements ContainerRequestFilter
054{
055  /**
056   * {@inheritDoc}
057   */
058  public void filter(final ContainerRequestContext requestContext)
059      throws IOException
060  {
061    if(requestContext.getMethod().equals(HttpMethod.POST) &&
062        requestContext.getUriInfo().getPath().endsWith(
063            SEARCH_WITH_POST_PATH_EXTENSION))
064
065    {
066      if(requestContext.getMediaType() == null ||
067          !(requestContext.getMediaType().isCompatible(
068              ServerUtils.MEDIA_TYPE_SCIM_TYPE) ||
069              requestContext.getMediaType().isCompatible(
070                  MediaType.APPLICATION_JSON_TYPE)))
071      {
072        throw new NotSupportedException();
073      }
074
075      ObjectReader reader =
076          JsonUtils.getObjectReader().forType(SearchRequest.class);
077      JsonParser p = reader.getFactory().createParser(
078          requestContext.getEntityStream());
079      if(p.nextToken() == null)
080      {
081        throw new BadRequestException(
082            new NoContentException("Empty Entity"));
083      }
084      SearchRequest searchRequest = reader.readValue(p);
085      UriBuilder builder = requestContext.getUriInfo().getBaseUriBuilder();
086      List<PathSegment> pathSegments =
087          requestContext.getUriInfo().getPathSegments();
088      for(int i = 0; i < pathSegments.size() - 1; i ++)
089      {
090        builder.path(pathSegments.get(i).getPath());
091      }
092      if(searchRequest.getAttributes() != null)
093      {
094        builder.queryParam(QUERY_PARAMETER_ATTRIBUTES,
095            StaticUtils.collectionToString(searchRequest.getAttributes(), ","));
096      }
097      if(searchRequest.getExcludedAttributes() != null)
098      {
099        builder.queryParam(QUERY_PARAMETER_EXCLUDED_ATTRIBUTES,
100            StaticUtils.collectionToString(
101                searchRequest.getExcludedAttributes(), ","));
102      }
103      if(searchRequest.getFilter() != null)
104      {
105        builder.queryParam(QUERY_PARAMETER_FILTER,
106            searchRequest.getFilter());
107      }
108      if(searchRequest.getSortBy() != null)
109      {
110        builder.queryParam(QUERY_PARAMETER_SORT_BY,
111            searchRequest.getSortBy());
112      }
113      if(searchRequest.getSortOrder() != null)
114      {
115        builder.queryParam(QUERY_PARAMETER_SORT_ORDER,
116            searchRequest.getSortOrder().getName());
117      }
118      if(searchRequest.getStartIndex() != null)
119      {
120        builder.queryParam(QUERY_PARAMETER_PAGE_START_INDEX,
121            searchRequest.getStartIndex());
122      }
123      if(searchRequest.getCount() != null)
124      {
125        builder.queryParam(QUERY_PARAMETER_PAGE_SIZE,
126            searchRequest.getCount());
127      }
128      requestContext.setRequestUri(builder.build());
129      requestContext.setMethod(HttpMethod.GET);
130    }
131  }
132}