/* * RHQ Management Platform * Copyright (C) 2005-2014 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also 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 and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.enterprise.server.rest.helper; import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.ws.rs.core.MultivaluedMap; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.enterprise.server.rest.BadArgumentException; /** * this helper class builds {@link ResourceCriteria based on query parameters map} * @author lzoubek * */ public class ResourceCriteriaHelper { /** * special parameters are either ignored or handled specialy */ private static final List<String> SPECIAL_PARAMS = Arrays.asList("page", "ps", "strict"); /** * mapping param shortcutName to param full name (this map gets filled in class constructor) */ private static final Map<String, String> PARAM_SHORTCUTS = new LinkedHashMap<String, String>(); /** * we store parameter name shortcuts as text for API documentation purposes */ public static final String PARAM_SHORTCUTS_TEXT = "status=inventoryStatus, availability=currentAvailability, category=resourceCategories, plugin=pluginName, parentId=parentResourceId, parentName=parentResourceName, type=resourceTypeName"; static { String[] pairs = PARAM_SHORTCUTS_TEXT.split(", "); for (int i = 0; i < pairs.length; i++) { String[] pair = pairs[i].split("="); PARAM_SHORTCUTS.put(pair[0], pair[1]); } } /** * creates new criteria instance based on given params. Currently we support single value addFilterXXX functions, and strict parameter. Paging is ignored. * @param params query parameters * @return resource criteria */ public static ResourceCriteria create(MultivaluedMap<String,String> params) { ResourceCriteria criteria = new ResourceCriteria(); criteria.clearPaging(); Method[] methods = ResourceCriteria.class.getMethods(); for (Entry<String, List<String>> e : params.entrySet()) { String value = params.getFirst(e.getKey()); if (value == null) { continue; } String paramName = paramName(e.getKey()); if (SPECIAL_PARAMS.contains(e.getKey())) { try { handleSpecialParam(criteria, e.getKey(), value); } catch (Exception ex) { throw new BadArgumentException("Unable to parse [" + e.getKey() + "] value [" + value + "] is not valid"); } } else { String filterName = "addFilter" + paramName.substring(0, 1).toUpperCase() + paramName.substring(1); Method m = findMethod(methods, filterName); if (m != null) { try { m.invoke(criteria, getValue(m, paramName, value)); } catch (BadArgumentException bae) { throw bae; } catch (Exception ex) { throw new BadArgumentException("Unable to filter by [" + paramName + "] value [" + value + "] is not valid for this filter"); } } else { throw new BadArgumentException("Unable to filter by [" + paramName + "] : filter does not exist"); } } } return criteria; } private static String paramName(String name) { String newName = PARAM_SHORTCUTS.get(name); return newName == null ? name : newName; } private static void handleSpecialParam(ResourceCriteria criteria, String filter, String value) { if ("strict".equals(filter)) { criteria.setStrict(Boolean.parseBoolean(value)); return; } // skip ps and page .. we ignore those } private static Object getValue(Method m, String filter, String value) { Class<?> parameterType = m.getParameterTypes()[0]; if (parameterType.isArray()) { parameterType = parameterType.getComponentType(); } if (parameterType.isEnum()) { return enumParamValue(filter, value); } if (parameterType.isAssignableFrom(Integer.class) || (parameterType.isPrimitive() && "int".equals(parameterType.getName()))) { return Integer.parseInt(value); } if (parameterType.isAssignableFrom(Long.class) || (parameterType.isPrimitive() && "long".equals(parameterType.getName()))) { return Long.parseLong(value); } return value; } private static Object enumParamValue(String filter, String value) { if ("inventoryStatus".equals(filter)) { try { return InventoryStatus.valueOf(value.toUpperCase()); } catch (Exception ex) { throw new BadArgumentException(filter, "Value " + value + " is not in the list of allowed values: " + Arrays.toString(InventoryStatus.values())); } } if ("currentAvailability".equals(filter)) { try { return AvailabilityType.valueOf(value.toUpperCase()); } catch (Exception ex) { throw new BadArgumentException(filter, "Value " + value + " is not in the list of allowed values: " + Arrays.toString(AvailabilityType.values())); } } if ("resourceCategories".equals(filter)) { try { return new ResourceCategory[] { ResourceCategory.valueOf(value.toUpperCase()) }; } catch (Exception ex) { throw new BadArgumentException(filter, "Value " + value + " is not in the list of allowed values: " + Arrays.toString(ResourceCategory.values())); } } return null; } private static Method findMethod(Method[] methods, String name) { for (Method m : methods) { if (m.getName().equals(name)) { return m; } } return null; } }