package org.zstack.tag; import org.apache.commons.lang.StringUtils; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.query.APIQueryMessage; import org.zstack.header.query.QueryCondition; import org.zstack.header.query.QueryOp; import org.zstack.query.AbstractMysqlQuerySubQueryExtension; import org.zstack.query.QueryUtils; import org.zstack.utils.CollectionDSL; import org.zstack.utils.gson.JSONObjectUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** */ public class TagSubQueryExtension extends AbstractMysqlQuerySubQueryExtension { public static String USER_TAG_NAME = "__userTag__"; public static String SYS_TAG_NAME = "__systemTag__"; private static List<String> IN_CONDITIONS; private static List<String> NOT_IN_CONDITIONS; static { IN_CONDITIONS = CollectionDSL.list( QueryOp.EQ.toString(), QueryOp.GT.toString(), QueryOp.GT_AND_EQ.toString(), QueryOp.LT.toString(), QueryOp.LT_AND_EQ.toString(), QueryOp.IN.toString(), QueryOp.LIKE.toString(), QueryOp.NOT_NULL.toString() ); NOT_IN_CONDITIONS = CollectionDSL.list( QueryOp.NOT_EQ.toString(), QueryOp.NOT_IN.toString(), QueryOp.IS_NULL.toString(), QueryOp.NOT_LIKE.toString() ); } private String reverseOpIfNeed(QueryCondition cond) { if (QueryOp.NOT_EQ.equals(cond.getOp())) { return QueryOp.EQ.toString(); } else if (QueryOp.NOT_IN.equals(cond.getOp())) { return QueryOp.IN.toString(); } else if (QueryOp.IS_NULL.equals(cond.getOp())) { return QueryOp.NOT_NULL.toString(); } else if (QueryOp.NOT_LIKE.equals(cond.getOp())) { return QueryOp.LIKE.toString(); } else { return cond.getOp(); } } private String buildCondition(String field, QueryCondition cond) { if (QueryOp.IN.equals(cond.getOp()) || QueryOp.NOT_IN.equals(cond.getOp())) { String[] values = cond.getValue().split(","); List<String> vals = new ArrayList<String>(); for (String val : values) { vals.add(String.format("'%s'", val)); } return String.format("%s %s (%s)", field, reverseOpIfNeed(cond), StringUtils.join(vals, ",")); } else if (QueryOp.IS_NULL.equals(cond.getOp()) || QueryOp.NOT_NULL.equals(cond.getOp())) { return String.format("%s %s", field, reverseOpIfNeed(cond)); } else { return String.format("%s %s '%s'", field, reverseOpIfNeed(cond), cond.getValue()); } } private String chooseOp (QueryCondition cond) { if (IN_CONDITIONS.contains(cond.getOp())) { return "in"; } if (NOT_IN_CONDITIONS.contains(cond.getOp())) { return "not in"; } throw new CloudRuntimeException(String.format("invalid comparison operator[%s]; %s", cond.getOp(), JSONObjectUtil.toJsonString(cond))); } private String getResourceTypeString(Class entityClass) { List<String> rtypes = new ArrayList<String>(); while (entityClass != Object.class) { rtypes.add(String.format("'%s'", entityClass.getSimpleName())); entityClass = entityClass.getSuperclass(); } return StringUtils.join(rtypes, ","); } @Override public String makeSubquery(APIQueryMessage msg, Class inventoryClass) { List<String> resultQuery = new ArrayList<String>(); Class entityClass = QueryUtils.getEntityClassFromInventoryClass(inventoryClass); String primaryKey = QueryUtils.getPrimaryKeyNameFromEntityClass(entityClass); String typeString = getResourceTypeString(entityClass); String invname = inventoryClass.getSimpleName().toLowerCase(); for (QueryCondition cond : msg.getConditions()) { if (cond.getName().equals(USER_TAG_NAME)) { List<String> condStrs = new ArrayList<String>(); condStrs.add(buildCondition("user.tag", cond)); condStrs.add(String.format("user.resourceType in (%s)", typeString)); resultQuery.add(String.format("%s.%s %s (select user.resourceUuid from UserTagVO user where %s)", invname, primaryKey, chooseOp(cond), StringUtils.join(condStrs, " and "))); } else if (cond.getName().equals(SYS_TAG_NAME)) { List<String> condStrs = new ArrayList<String>(); condStrs.add(buildCondition("sys.tag", cond)); condStrs.add(String.format("sys.resourceType in (%s)", typeString)); resultQuery.add(String.format("%s.%s %s (select sys.resourceUuid from SystemTagVO sys where %s)", invname, primaryKey, chooseOp(cond), StringUtils.join(condStrs, " and "))); } } if (resultQuery.isEmpty()) { return null; } else { return StringUtils.join(resultQuery, " and "); } } @Override public List<String> getEscapeConditionNames() { return Arrays.asList(USER_TAG_NAME, SYS_TAG_NAME); } }