blob: c533e7dd945cb603c3723adced19c6411d412bde [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.unomi.rest;
import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
import org.apache.unomi.api.Item;
import org.apache.unomi.api.conditions.Condition;
import org.apache.unomi.api.query.AggregateQuery;
import org.apache.unomi.api.services.QueryService;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Map;
/**
* A JAX-RS endpoint to perform queries against context-server data.
*/
@WebService
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@CrossOriginResourceSharing(
allowAllOrigins = true,
allowCredentials = true
)
@Path("/query")
@Component(service=QueryServiceEndPoint.class,property = "osgi.jaxrs.resource=true")
public class QueryServiceEndPoint {
private static final Logger logger = LoggerFactory.getLogger(QueryServiceEndPoint.class.getName());
@Reference
private QueryService queryService;
@Reference
private LocalizationHelper localizationHelper;
@WebMethod(exclude = true)
public void setQueryService(QueryService queryService) {
this.queryService = queryService;
}
@WebMethod(exclude = true)
public void setLocalizationHelper(LocalizationHelper localizationHelper) {
this.localizationHelper = localizationHelper;
}
/**
* Retrieves the number of items with the specified type as defined by the Item subclass public field {@code ITEM_TYPE} and aggregated by possible values of the specified
* property.
*
* @param type the String representation of the item type we want to retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
* @param property the property we're aggregating on, i.e. for each possible value of this property, we are counting how many items of the specified type have that value
* @return a Map associating a specific value of the property to the cardinality of items with that value
* @see Item Item for a discussion of {@code ITEM_TYPE}
*/
@GET
@Path("/{type}/{property}")
public Map<String, Long> getAggregate(@PathParam("type") String type, @PathParam("property") String property) {
return queryService.getAggregate(type, property);
}
/**
* TODO: rework, this method is confusing since it either behaves like {@link #getAggregate(String, String)} if query is null but completely differently if it isn't
*
* Retrieves the number of items with the specified type as defined by the Item subclass public field {@code ITEM_TYPE} and aggregated by possible values of the specified
* property or, if the specified query is not {@code null}, perform that aggregate query.
* Also return the global count of document matching the {@code ITEM_TYPE} if you don't use {@code optimizedQuery} or set it to false,
* otherwise if {@code optimizedQuery} is set to true then it won't return the global count but the query will be executed much faster.
*
* @param type the String representation of the item type we want to retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
* @param property the property we're aggregating on, i.e. for each possible value of this property, we are counting how many items of the specified type have that value
* @param aggregateQuery the {@link AggregateQuery} specifying the aggregation that should be performed
* @param optimizedQuery the {@code optimizedQuery} specifying if we should optimized the aggregate query or not
* @return a Map associating a specific value of the property to the cardinality of items with that value
* @see Item Item for a discussion of {@code ITEM_TYPE}
*/
@POST
@Path("/{type}/{property}")
public Map<String, Long> getAggregate(@PathParam("type") String type, @PathParam("property") String property,
@QueryParam("optimizedQuery") boolean optimizedQuery, AggregateQuery aggregateQuery) {
if (optimizedQuery) {
return queryService.getAggregateWithOptimizedQuery(type, property, aggregateQuery);
} else {
return queryService.getAggregate(type, property, aggregateQuery);
}
}
/**
* Retrieves the specified metrics for the specified field of items of the specified type as defined by the Item subclass public field {@code ITEM_TYPE} and matching the
* specified {@link Condition}.
*
* @param condition the condition the items must satisfy
* @param metricsType a String specifying which metrics should be computed, separated by a slash ({@code /}) (possible values: {@code sum} for the sum of the
* values, {@code avg} for the average of the values, {@code min} for the minimum value and {@code max} for the maximum value)
* @param property the name of the field for which the metrics should be computed
* @param type the String representation of the item type we want to retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
* @return a Map associating computed metric name as key to its associated value
* @see Item Item for a discussion of {@code ITEM_TYPE}
*/
@POST
@Path("/{type}/{property}/{metricTypes:((sum|avg|min|max)/?)*}")
public Map<String, Double> getMetric(@PathParam("type") String type, @PathParam("property") String property, @PathParam("metricTypes") String metricsType, Condition condition) {
return queryService.getMetric(type, property, metricsType, condition);
}
/**
* Retrieves the number of items of the specified type as defined by the Item subclass public field {@code ITEM_TYPE} and matching the specified {@link Condition}.
*
* @param condition the condition the items must satisfy
* @param validate optional parameter, in case of draft condition that have missing required parameters an IllegalArgumentException is throw
* and this end point will return status code 400, to avoid that you can set validate to false.
* @param type the String representation of the item type we want to retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
* @param response the httpServletResponse
* @return the number of items of the specified type.
* 0 and status code 400 in case of IllegalArgumentException (bad condition) and validate null or true
* 0 and status code 200 in case of IllegalArgumentException (bad condition) and validate false
* @see Item Item for a discussion of {@code ITEM_TYPE}
*/
@POST
@Path("/{type}/count")
public long getQueryCount(@PathParam("type") String type, @QueryParam("validate") Boolean validate, Condition condition, @Context final HttpServletResponse response) {
long count = 0;
try {
count = queryService.getQueryCount(type, condition);
} catch (IllegalArgumentException e) {
if(validate == null || validate) {
logger.error(e.getMessage(), e);
response.setStatus(Response.Status.BAD_REQUEST.getStatusCode());
}
}
return count;
}
}