/** * Queries all the links for a given mapping, indexed by the source identifier * * <p>This method expects a {@code "links-for-linkType"} defined with a parameter of {@code * "linkType"}. * * @param mapping the mapping to look up the links for * @throws SynchronizationException if the query could not be performed. * @return the mapping from source identifier to the link object for it */ public static Map<String, Link> getLinksForMapping(ObjectMapping mapping, String linkQualifier) throws SynchronizationException { Map<String, Link> sourceIdToLink = new ConcurrentHashMap<String, Link>(); if (mapping != null) { JsonValue query = new JsonValue(new HashMap<String, Object>()); query.put( PARAM_QUERY_FILTER, QueryFilter.and( Arrays.asList( QueryFilter.equalTo("/linkType", mapping.getLinkType().getName()), QueryFilter.equalTo("/linkQualifier", linkQualifier))) .toString()); JsonValue queryResults = linkQuery( mapping.getService().getServerContext(), mapping.getService().getConnectionFactory(), query); for (JsonValue entry : queryResults) { Link link = new Link(mapping); link.fromJsonValue(entry); sourceIdToLink.put(link.sourceId, link); } } return sourceIdToLink; }
/** {@inheritDoc} */ @Override public Set<SearchFilter> visitAndFilter(Set<SearchFilter> filters, List<QueryFilter> subFilters) { for (QueryFilter queryFilter : subFilters) { queryFilter.accept(this, filters); } return filters; }
/** * Queries the links for a match on the second system (links can be bi-directional) * * <p>This method expects a {@code "links-for-targetId"} defined with a parameter of {@code * "targetId"}. * * @param targetId TODO. * @throws SynchronizationException TODO. */ void getLinkFromSecond(String id) throws SynchronizationException { clear(); if (id != null) { JsonValue query = new JsonValue(new HashMap<String, Object>()); query.put( PARAM_QUERY_FILTER, QueryFilter.and( Arrays.asList( QueryFilter.equalTo("/linkType", mapping.getLinkType().getName()), QueryFilter.equalTo("/linkQualifier", linkQualifier), QueryFilter.equalTo("/secondId", id))) .toString()); getLink(query); } }
@Test public void nameQueryShouldBeSupported() throws Exception { // Given ServerContext context = mock(ServerContext.class); QueryRequest request = mock(QueryRequest.class); given(request.getFields()).willReturn(Arrays.asList(new JsonPointer("/fred"))); QueryResultHandler handler = mock(QueryResultHandler.class); ResourceSetDescription resourceSet = mock(ResourceSetDescription.class); QueryFilter queryFilter = QueryFilter.and( QueryFilter.equalTo("/name", "NAME"), QueryFilter.equalTo("/resourceServer", "myclient"), QueryFilter.equalTo("/policy/permissions/subject", "SUBJECT")); Promise<Collection<ResourceSetDescription>, ResourceException> resourceSetsPromise = Promises.newSuccessfulPromise((Collection<ResourceSetDescription>) asSet(resourceSet)); given(contextHelper.getRealm(context)).willReturn("REALM"); given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID"); given(request.getQueryFilter()).willReturn(queryFilter); given( resourceSetService.getResourceSets( eq(context), eq("REALM"), Matchers.<ResourceSetWithPolicyQuery>anyObject(), eq("RESOURCE_OWNER_ID"), eq(false))) .willReturn(resourceSetsPromise); // When resource.queryCollection(context, request, handler); // Then ArgumentCaptor<ResourceSetWithPolicyQuery> queryCaptor = ArgumentCaptor.forClass(ResourceSetWithPolicyQuery.class); verify(resourceSetService) .getResourceSets( eq(context), eq("REALM"), queryCaptor.capture(), eq("RESOURCE_OWNER_ID"), eq(false)); assertThat(queryCaptor.getValue().getOperator()).isEqualTo(AggregateQuery.Operator.AND); assertThat(queryCaptor.getValue().getPolicyQuery()) .isEqualTo(QueryFilter.equalTo("/permissions/subject", "SUBJECT")); assertThat(queryCaptor.getValue().getResourceSetQuery()) .isEqualTo( org.forgerock.util.query.QueryFilter.and( org.forgerock.util.query.QueryFilter.equalTo("name", "NAME"), org.forgerock.util.query.QueryFilter.equalTo("clientId", "myclient"))); verify(handler).handleResult(any(QueryResult.class)); }
@Override public List<Privilege> query(QueryRequest request) throws EntitlementException { QueryFilter queryFilter = request.getQueryFilter(); if (queryFilter == null) { // Return everything queryFilter = QueryFilter.alwaysTrue(); } try { Set<SearchFilter> searchFilters = queryFilter.accept( new PrivilegeQueryBuilder(queryAttributes), new HashSet<SearchFilter>()); return privilegeManager.search(searchFilters); } catch (UnsupportedOperationException ex) { throw new EntitlementException( EntitlementException.INVALID_SEARCH_FILTER, new Object[] {ex.getMessage()}); } catch (IllegalArgumentException ex) { throw new EntitlementException( EntitlementException.INVALID_VALUE, new Object[] {ex.getMessage()}); } }
@Test public void queryShouldNotBeSupported() { // Given ServerContext context = mock(ServerContext.class); QueryRequest request = mock(QueryRequest.class); QueryResultHandler handler = mock(QueryResultHandler.class); given(request.getQueryFilter()).willReturn(QueryFilter.equalTo(new JsonPointer("/fred"), 5)); // When resource.queryCollection(context, request, handler); // Then verify(handler).handleError(Matchers.<NotSupportedException>anyObject()); }
void doGet(final HttpServletRequest req, final HttpServletResponse resp) { try { // Parse out the required API versions. final AcceptAPIVersion acceptVersion = parseAcceptAPIVersion(req); // Prepare response. prepareResponse(req, resp); // Validate request. preprocessRequest(req); rejectIfMatch(req); final Map<String, String[]> parameters = req.getParameterMap(); if (hasParameter(req, PARAM_QUERY_ID) || hasParameter(req, PARAM_QUERY_EXPRESSION) || hasParameter(req, PARAM_QUERY_FILTER)) { // Additional pre-validation for queries. rejectIfNoneMatch(req); // Query against collection. final QueryRequest request = Requests.newQueryRequest(getResourceName(req)); for (final Map.Entry<String, String[]> p : parameters.entrySet()) { final String name = p.getKey(); final String[] values = p.getValue(); if (parseCommonParameter(name, values, request)) { continue; } else if (name.equalsIgnoreCase(PARAM_SORT_KEYS)) { for (final String s : values) { try { request.addSortKey(s.split(SORT_KEYS_DELIMITER)); } catch (final IllegalArgumentException e) { // FIXME: i18n. throw new BadRequestException( "The value '" + s + "' for parameter '" + name + "' could not be parsed as a comma " + "separated list of sort keys"); } } } else if (name.equalsIgnoreCase(PARAM_QUERY_ID)) { request.setQueryId(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_QUERY_EXPRESSION)) { request.setQueryExpression(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_COOKIE)) { request.setPagedResultsCookie(asSingleValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGED_RESULTS_OFFSET)) { request.setPagedResultsOffset(asIntValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_PAGE_SIZE)) { request.setPageSize(asIntValue(name, values)); } else if (name.equalsIgnoreCase(PARAM_QUERY_FILTER)) { final String s = asSingleValue(name, values); try { request.setQueryFilter(QueryFilter.valueOf(s)); } catch (final IllegalArgumentException e) { // FIXME: i18n. throw new BadRequestException( "The value '" + s + "' for parameter '" + name + "' could not be parsed as a valid query filter"); } } else { request.setAdditionalParameter(name, asSingleValue(name, values)); } } // Check for incompatible arguments. if (request.getQueryId() != null && request.getQueryFilter() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_ID + " and " + PARAM_QUERY_FILTER + " are mutually exclusive"); } if (request.getQueryId() != null && request.getQueryExpression() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_ID + " and " + PARAM_QUERY_EXPRESSION + " are mutually exclusive"); } if (request.getQueryFilter() != null && request.getQueryExpression() != null) { // FIXME: i18n. throw new BadRequestException( "The parameters " + PARAM_QUERY_FILTER + " and " + PARAM_QUERY_EXPRESSION + " are mutually exclusive"); } doRequest(req, resp, acceptVersion, request); } else { // Read of instance within collection or singleton. final String rev = getIfNoneMatch(req); if (ETAG_ANY.equals(rev)) { // FIXME: i18n throw new PreconditionFailedException( "If-None-Match * not appropriate for " + getMethod(req) + " requests"); } final ReadRequest request = Requests.newReadRequest(getResourceName(req)); for (final Map.Entry<String, String[]> p : parameters.entrySet()) { final String name = p.getKey(); final String[] values = p.getValue(); if (parseCommonParameter(name, values, request)) { continue; } else if (PARAM_MIME_TYPE.equalsIgnoreCase(name)) { if (values.length != 1 || values[0].split(FIELDS_DELIMITER).length > 1) { // FIXME: i18n. throw new BadRequestException("Only one mime type value allowed"); } if (parameters.get(PARAM_FIELDS).length != 1) { // FIXME: i18n. throw new BadRequestException( "The mime type parameter requires only 1 field to be specified"); } } else { request.setAdditionalParameter(name, asSingleValue(name, values)); } } doRequest(req, resp, acceptVersion, request); } } catch (final Exception e) { fail(req, resp, e); } }
/** * Execute a query, either a pre-configured query by using the query ID, or a query expression * passed as part of the params. * * <p>The keys for the input parameters as well as the return map entries are in QueryConstants. * * @param type the resource component name targeted by the URI * @param params the parameters which include the query id, or the query expression, as well as * the token key/value pairs to replace in the query * @param con a handle to a database connection newBuilder for exclusive use by the query method * whilst it is executing. * @return The query result, which includes meta-data about the query, and the result set itself. * @throws BadRequestException if the passed request parameters are invalid, e.g. missing query id * or query expression or tokens. * @throws InternalServerErrorException if the preparing or executing the query fails because of * configuration or DB issues */ public List<Map<String, Object>> query( final String type, Map<String, Object> params, Connection con) throws ResourceException { List<Map<String, Object>> result = null; params.put(ServerConstants.RESOURCE_NAME, type); // If paged results are requested then decode the cookie in order to determine // the index of the first result to be returned. final int requestPageSize = (Integer) params.get(PAGE_SIZE); final String offsetParam; final String pageSizeParam; if (requestPageSize > 0) { offsetParam = String.valueOf((Integer) params.get(PAGED_RESULTS_OFFSET)); pageSizeParam = String.valueOf(requestPageSize); } else { offsetParam = "0"; pageSizeParam = String.valueOf(Integer.MAX_VALUE); } params.put(PAGED_RESULTS_OFFSET, offsetParam); params.put(PAGE_SIZE, pageSizeParam); QueryFilter queryFilter = (QueryFilter) params.get(QUERY_FILTER); String queryExpression = (String) params.get(QUERY_EXPRESSION); String queryId = (String) params.get(QUERY_ID); if (queryId == null && queryExpression == null && queryFilter == null) { throw new BadRequestException( "Either " + QUERY_ID + ", " + QUERY_EXPRESSION + ", or " + QUERY_FILTER + " to identify/define a query must be passed in the parameters. " + params); } logger.debug("Querying " + params); final PreparedStatement foundQuery; try { if (queryFilter != null) { foundQuery = parseQueryFilter(con, queryFilter, params); } else if (queryExpression != null) { foundQuery = resolveInlineQuery(con, queryExpression, params); } else if (queries.queryIdExists(queryId)) { foundQuery = queries.getQuery(con, queryId, type, params); } else { throw new BadRequestException( "The passed query identifier " + queryId + " does not match any configured queries on the JDBC repository service."); } } catch (SQLException ex) { final String queryDescription; if (queryFilter != null) { queryDescription = queryFilter.toString(); } else if (queryExpression != null) { queryDescription = queryExpression; } else { queryDescription = queries.getQueryInfo(queryId).getQueryString(); } throw new InternalServerErrorException( "DB reported failure preparing query: " + queryDescription + " with params: " + params + " error code: " + ex.getErrorCode() + " sqlstate: " + ex.getSQLState() + " message: " + ex.getMessage(), ex); } Name eventName = getEventName(queryId); EventEntry measure = Publisher.start(eventName, foundQuery, null); ResultSet rs = null; try { rs = foundQuery.executeQuery(); result = resultMapper.mapQueryToObject(rs, queryId, type, params, this); measure.setResult(result); } catch (SQLException ex) { throw new InternalServerErrorException( "DB reported failure executing query " + foundQuery.toString() + " with params: " + params + " error code: " + ex.getErrorCode() + " sqlstate: " + ex.getSQLState() + " message: " + ex.getMessage(), ex); } catch (IOException ex) { throw new InternalServerErrorException( "Failed to convert result objects for query " + foundQuery.toString() + " with params: " + params + " message: " + ex.getMessage(), ex); } finally { CleanupHelper.loggedClose(rs); CleanupHelper.loggedClose(foundQuery); measure.end(); } return result; }