| // 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 |
| // 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 com.cloud.utils.db; |
| |
| import java.util.UUID; |
| |
| import com.cloud.utils.db.SearchCriteria.Op; |
| |
| /** |
| * GenericSearchBuilder is used to build a search based on a VO object. It |
| * can select the result into a native type, the entity object, or a composite |
| * object depending on what's needed. |
| * |
| * The way to use GenericSearchBuilder is to use it to build a search at load |
| * time so it should be declared at class constructions. It allows queries to |
| * be constructed completely in Java and parameters have String tokens that |
| * can be replaced during runtime with SearchCriteria. Because |
| * GenericSearchBuilder is created at load time and SearchCriteria is used |
| * at runtime, the search query creation and the parameter value setting are |
| * separated in the code. While that's tougher on the coder to maintain, what |
| * you gain is that all string constructions are done at load time rather than |
| * runtime and, more importantly, the proper construction can be checked when |
| * components are being loaded. However, if you prefer to just construct |
| * the entire search at runtime, you can use GenericQueryBuilder. |
| * |
| * <code> |
| * // To specify the GenericSearchBuilder, you should do this at load time. |
| * // Note that in the following search, it selects a func COUNT to be the |
| * // return result so for the second parameterized type is long. It also |
| * // presets the type in the search and declares created to be set during |
| * // runtime. Note the entity object itself must have came from search and |
| * // it uses the getters of the object to retrieve the field used in the search. |
| * |
| * GenericSearchBuilder<HostVO, Long> CountSearch = _hostDao.createSearchBuilder(Long.class); |
| * HostVO entity = CountSearch.entity(); |
| * CountSearch.select(null, FUNC.COUNT, null, null).where(entity.getType(), Op.EQ).value(Host.Type.Routing); |
| * CountSearch.and(entity.getCreated(), Op.LT, "create_date").done(); |
| * |
| * // Later in the code during runtime |
| * SearchCriteria<Long> sc = CountSearch.create(); |
| * sc.setParameter("create_date", new Date()); |
| * Long count = _hostDao.customizedSearch(sc, null); |
| * </code> |
| * |
| * @see GenericQueryBuilder for runtime construction of search query |
| * @see SearchBuilder for returning VO objects itself |
| * |
| * @param <T> VO object this Search is build for. |
| * @param <K> Result object that should contain the results. |
| */ |
| public class GenericSearchBuilder<T, K> extends SearchBase<GenericSearchBuilder<T, K>, T, K> { |
| protected GenericSearchBuilder(Class<T> entityType, Class<K> resultType) { |
| super(entityType, resultType); |
| } |
| |
| /** |
| * Adds an AND condition to the SearchBuilder. |
| * |
| * @param name param name you will use later to set the values in this search condition. |
| * @param field SearchBuilder.entity().get*() which refers to the field that you're searching on. |
| * @param op operation to apply to the field. |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> and(String name, Object field, Op op) { |
| constructCondition(name, " AND ", _specifiedAttrs.get(0), op); |
| return this; |
| } |
| |
| /** |
| * Adds an AND condition. Some prefer this method because it looks like |
| * the actual SQL query. |
| * |
| * @param field field of entity object |
| * @param op operator of the search condition |
| * @param name param name used to later to set parameter value |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> and(Object field, Op op, String name) { |
| constructCondition(name, " AND ", _specifiedAttrs.get(0), op); |
| return this; |
| } |
| |
| /** |
| * Adds an AND condition but allows for a preset value to be set for this conditio. |
| * |
| * @param field field of the entity object |
| * @param op operator of the search condition |
| * @return Preset which allows you to set the values |
| */ |
| public Preset and(Object field, Op op) { |
| Condition condition = constructCondition(UUID.randomUUID().toString(), " AND ", _specifiedAttrs.get(0), op); |
| return new Preset(this, condition); |
| } |
| |
| /** |
| * Starts the search |
| * |
| * @param field field of the entity object |
| * @param op operator |
| * @param name param name to refer to the value later. |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> where(Object field, Op op, String name) { |
| return and(name, field, op); |
| } |
| |
| /** |
| * Starts the search but the value is already set during construction. |
| * |
| * @param field field of the entity object |
| * @param op operator of the search condition |
| * @return Preset which allows you to set the values |
| */ |
| public Preset where(Object field, Op op) { |
| return and(field, op); |
| } |
| |
| protected GenericSearchBuilder<T, K> left(Object field, Op op, String name) { |
| constructCondition(name, " ( ", _specifiedAttrs.get(0), op); |
| return this; |
| } |
| |
| protected Preset left(Object field, Op op) { |
| Condition condition = constructCondition(UUID.randomUUID().toString(), " ( ", _specifiedAttrs.get(0), op); |
| return new Preset(this, condition); |
| } |
| |
| /** |
| * Adds an condition that starts with open parenthesis. Use cp() to close |
| * the parenthesis. |
| * |
| * @param field field of the entity object |
| * @param op operator |
| * @param name parameter name used to set the value later |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> op(Object field, Op op, String name) { |
| return left(field, op, name); |
| } |
| |
| public Preset op(Object field, Op op) { |
| return left(field, op); |
| } |
| |
| /** |
| * Adds an condition that starts with open parenthesis. Use cp() to close |
| * the parenthesis. |
| * |
| * @param name parameter name used to set the parameter value later. |
| * @param field field of the entity object |
| * @param op operator |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> op(String name, Object field, Op op) { |
| return left(field, op, name); |
| } |
| |
| /** |
| * Adds an OR condition to the SearchBuilder. |
| * |
| * @param name param name you will use later to set the values in this search condition. |
| * @param field SearchBuilder.entity().get*() which refers to the field that you're searching on. |
| * @param op operation to apply to the field. |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> or(String name, Object field, Op op) { |
| constructCondition(name, " OR ", _specifiedAttrs.get(0), op); |
| return this; |
| } |
| |
| /** |
| * Adds an OR condition |
| * |
| * @param field field of the entity object |
| * @param op operator |
| * @param name parameter name |
| * @return this |
| */ |
| public GenericSearchBuilder<T, K> or(Object field, Op op, String name) { |
| constructCondition(name, " OR ", _specifiedAttrs.get(0), op); |
| return this; |
| } |
| |
| /** |
| * Adds an OR condition but the values can be preset |
| * |
| * @param field field of the entity object |
| * @param op operator |
| * @return Preset |
| */ |
| public Preset or(Object field, Op op) { |
| Condition condition = constructCondition(UUID.randomUUID().toString(), " OR ", _specifiedAttrs.get(0), op); |
| return new Preset(this, condition); |
| } |
| |
| /** |
| * Convenience method to create the search criteria and set a |
| * parameter in the search. |
| * |
| * @param name parameter name set during construction |
| * @param values values to be inserted for that parameter |
| * @return SearchCriteria |
| */ |
| public SearchCriteria<K> create(String name, Object... values) { |
| SearchCriteria<K> sc = create(); |
| sc.setParameters(name, values); |
| return sc; |
| } |
| |
| /** |
| * Marks the SearchBuilder as completed in building the search conditions. |
| */ |
| public synchronized void done() { |
| super.finalize(); |
| } |
| |
| public class Preset { |
| GenericSearchBuilder<T, K> builder; |
| Condition condition; |
| |
| protected Preset(GenericSearchBuilder<T, K> builder, Condition condition) { |
| this.builder = builder; |
| this.condition = condition; |
| } |
| |
| public GenericSearchBuilder<T, K> values(Object... params) { |
| if (condition.op.getParams() > 0 && condition.op.params != params.length) { |
| throw new RuntimeException("The # of parameters set " + params.length + " does not match # of parameters required by " + condition.op); |
| } |
| condition.setPresets(params); |
| return builder; |
| } |
| } |
| } |