Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
de.aservo.ldap.adapter.sql.impl.QueryGenerator Maven / Gradle / Ivy
/*
* Copyright (c) 2019 ASERVO Software GmbH
* [email protected]
*
* Licensed 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 de.aservo.ldap.adapter.sql.impl;
import de.aservo.ldap.adapter.api.LdapUtils;
import de.aservo.ldap.adapter.api.database.QueryDef;
import de.aservo.ldap.adapter.api.database.QueryDefFactory;
import de.aservo.ldap.adapter.api.entity.EntityType;
import de.aservo.ldap.adapter.api.query.*;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.schema.SchemaManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class QueryGenerator {
private static final int GROUP_MEMBER_OF_FLAG = 1;
private static final int USER_MEMBER_OF_FLAG = 2;
private static final int GROUP_MEMBER_GROUP_FLAG = 4;
private static final int GROUP_MEMBER_USER_FLAG = 8;
private final SchemaManager schemaManager;
private final String dcId;
private final boolean flattening;
private final boolean activeUsersOnly;
private final boolean useMaterializedViews;
public QueryGenerator(SchemaManager schemaManager, String dcId, boolean flattening, boolean activeUsersOnly,
boolean useMaterializedViews) {
this.schemaManager = schemaManager;
this.dcId = dcId;
this.flattening = flattening;
this.activeUsersOnly = activeUsersOnly;
this.useMaterializedViews = useMaterializedViews;
}
public QueryDef generate(EntityType entityType, QueryDefFactory factory, QueryExpression expression) {
if (entityType == EntityType.GROUP)
expression = LdapUtils.preEvaluateExpressionForGroup(expression);
else if (entityType == EntityType.USER)
expression = LdapUtils.preEvaluateExpressionForUser(expression);
else
throw new IllegalArgumentException("Expect supported entity type.");
expression = LdapUtils.removeNotExpressions(LdapUtils.removeValueExpressions(expression));
StringBuilder builder = new StringBuilder();
List arguments = new ArrayList<>();
int joinPlan = createJoinPlan(entityType);
generateSelectClause(builder, entityType, joinPlan, arguments);
generateJoinClauses(builder, entityType, joinPlan);
generateWhereClause(builder, entityType, joinPlan, expression, arguments);
generateOrderByClause(builder, entityType);
return factory.query(builder.toString()).on(arguments);
}
private int createJoinPlan(EntityType entityType) {
int mask = 0;
if (entityType == EntityType.GROUP)
mask |= GROUP_MEMBER_USER_FLAG;
if (entityType == EntityType.GROUP && !flattening)
mask |= GROUP_MEMBER_OF_FLAG | GROUP_MEMBER_GROUP_FLAG;
if (entityType == EntityType.USER)
mask |= USER_MEMBER_OF_FLAG;
return mask;
}
private void generateSelectClause(StringBuilder builder, EntityType entityType, int joinPlan,
List arguments) {
if (entityType == EntityType.GROUP) {
builder.append("select ? as type, g.*");
arguments.add(EntityType.GROUP.toString().toLowerCase());
if ((joinPlan & GROUP_MEMBER_OF_FLAG) != 0)
builder.append(", gp.name as parent_group_name");
if ((joinPlan & GROUP_MEMBER_GROUP_FLAG) != 0)
builder.append(", gc.name as member_group_name");
if ((joinPlan & GROUP_MEMBER_USER_FLAG) != 0)
builder.append(", u.username as member_user_username");
builder.append(" from _Group g ");
} else if (entityType == EntityType.USER) {
builder.append("select ? as type, u.*");
arguments.add(EntityType.USER.toString().toLowerCase());
if ((joinPlan & USER_MEMBER_OF_FLAG) != 0)
builder.append(", g.name as parent_group_name");
builder.append(" from _User u ");
}
}
private void generateJoinClauses(StringBuilder builder, EntityType entityType, int joinPlan) {
if (entityType == EntityType.GROUP) {
if ((joinPlan & GROUP_MEMBER_OF_FLAG) != 0) {
if (flattening)
if (useMaterializedViews)
builder.append("left outer join _Group_Membership_Transitive mp ");
else
builder.append("left outer join _Group_Membership_Transitive_Non_Materialized mp ");
else
builder.append("left outer join _Group_Membership mp ");
builder.append("on mp.member_group_id = g.id ");
builder.append("left outer join _Group gp on gp.id = mp.parent_group_id ");
}
if ((joinPlan & GROUP_MEMBER_GROUP_FLAG) != 0) {
if (flattening)
if (useMaterializedViews)
builder.append("left outer join _Group_Membership_Transitive mc ");
else
builder.append("left outer join _Group_Membership_Transitive_Non_Materialized mc ");
else
builder.append("left outer join _Group_Membership mc ");
builder.append("on mc.parent_group_id = g.id ");
builder.append("left outer join _Group gc on gc.id = mc.member_group_id ");
}
if ((joinPlan & GROUP_MEMBER_USER_FLAG) != 0) {
if (flattening)
if (useMaterializedViews)
builder.append("left outer join _User_Membership_Transitive mu ");
else
builder.append("left outer join _User_Membership_Transitive_Non_Materialized mu ");
else
builder.append("left outer join _User_Membership mu ");
builder.append("on mu.parent_group_id = g.id ");
builder.append("left outer join _User u on u.id = mu.member_user_id ");
}
} else if (entityType == EntityType.USER) {
if ((joinPlan & USER_MEMBER_OF_FLAG) != 0) {
if (flattening)
if (useMaterializedViews)
builder.append("left outer join _User_Membership_Transitive mu ");
else
builder.append("left outer join _User_Membership_Transitive_Non_Materialized mu ");
else
builder.append("left outer join _User_Membership mu ");
builder.append("on mu.member_user_id = u.id ");
builder.append("left outer join _Group g on g.id = mu.parent_group_id ");
}
}
}
private void generateWhereClause(StringBuilder builder, EntityType entityType, int joinPlan,
QueryExpression expression, List arguments) {
builder.append("where ");
if ((joinPlan & (USER_MEMBER_OF_FLAG | GROUP_MEMBER_USER_FLAG)) != 0) {
builder.append("( ");
}
transformQueryExpressionToSql(builder, entityType, joinPlan, expression, arguments);
if ((joinPlan & (USER_MEMBER_OF_FLAG | GROUP_MEMBER_USER_FLAG)) != 0) {
builder.append(") and ( u.active is null or u.active or ? = 'false' ) ");
arguments.add(activeUsersOnly);
}
}
private void generateOrderByClause(StringBuilder builder, EntityType entityType) {
if (entityType == EntityType.GROUP)
builder.append("order by g.id");
else if (entityType == EntityType.USER)
builder.append("order by u.id");
}
private void transformQueryExpressionToSql(StringBuilder builder, EntityType entityType, int joinPlan,
QueryExpression expression, List arguments) {
if (expression instanceof BooleanValue) {
builder.append("? = 'true' ");
arguments.add(((BooleanValue) expression).getValue());
} else if (expression instanceof AndLogicExpression) {
Iterator iter = ((AndLogicExpression) expression).getChildren().iterator();
if (!iter.hasNext()) {
builder.append("? = 'true' ");
arguments.add(AndLogicExpression.EMPTY_SEQ_BOOLEAN);
} else {
QueryExpression first = iter.next();
if (!iter.hasNext()) {
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
} else {
builder.append("( ");
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
while (iter.hasNext()) {
builder.append(" and ");
transformQueryExpressionToSql(builder, entityType, joinPlan, iter.next(), arguments);
}
builder.append(") ");
}
}
} else if (expression instanceof OrLogicExpression) {
Iterator iter = ((OrLogicExpression) expression).getChildren().iterator();
if (!iter.hasNext()) {
builder.append("? = 'true' ");
arguments.add(OrLogicExpression.EMPTY_SEQ_BOOLEAN);
} else {
QueryExpression first = iter.next();
if (!iter.hasNext()) {
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
} else {
builder.append("( ");
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
while (iter.hasNext()) {
builder.append(" or ");
transformQueryExpressionToSql(builder, entityType, joinPlan, iter.next(), arguments);
}
builder.append(") ");
}
}
} else if (expression instanceof NotLogicExpression) {
Iterator iter = ((NotLogicExpression) expression).getChildren().iterator();
if (!iter.hasNext()) {
builder.append("? = 'true' ");
arguments.add(NotLogicExpression.EMPTY_SEQ_BOOLEAN);
} else {
QueryExpression first = iter.next();
if (!iter.hasNext()) {
builder.append("not ");
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
} else {
// De Morgan's laws:
// ¬x ∧ ¬y ≡ ¬(x ∨ y)
// ¬x ∨ ¬y ≡ ¬(x ∧ y)
builder.append("not ( ");
transformQueryExpressionToSql(builder, entityType, joinPlan, first, arguments);
while (iter.hasNext()) {
builder.append(" or ");
transformQueryExpressionToSql(builder, entityType, joinPlan, iter.next(), arguments);
}
builder.append(") ");
}
}
} else if (expression instanceof OperatorExpression) {
processOperator(builder, arguments, entityType, joinPlan, ((OperatorExpression) expression));
} else
throw new IllegalArgumentException("Cannot process unexpected query expression " +
expression.getClass().getName());
}
private void processOperator(StringBuilder builder, List arguments, EntityType entityType, int joinPlan,
OperatorExpression expression) {
switch (LdapUtils.normalizeAttribute(expression.getAttribute())) {
case SchemaConstants.UID_AT_OID:
if (entityType == EntityType.USER) {
builder.append("u.id ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.CN_AT_OID:
if (entityType == EntityType.GROUP) {
builder.append("lower(g.name) ");
handleOperator(builder, arguments, expression);
} else if (entityType == EntityType.USER) {
builder.append("lower(u.username) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.SN_AT_OID:
if (entityType == EntityType.USER) {
builder.append("lower(u.last_name) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.GN_AT_OID:
if (entityType == EntityType.USER) {
builder.append("lower(u.first_name) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.DISPLAY_NAME_AT_OID:
if (entityType == EntityType.USER) {
builder.append("lower(u.display_name) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.MAIL_AT_OID:
if (entityType == EntityType.USER) {
builder.append("lower(u.email) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.DESCRIPTION_AT_OID:
if (entityType == EntityType.GROUP) {
builder.append("lower(g.description) ");
handleOperator(builder, arguments, expression);
}
break;
case SchemaConstants.MEMBER_AT_OID:
case SchemaConstants.UNIQUE_MEMBER_AT_OID:
if (entityType == EntityType.GROUP) {
if (expression instanceof EqualOperator) {
String groupId = null;
String userId = null;
if ((joinPlan & GROUP_MEMBER_GROUP_FLAG) != 0)
groupId =
LdapUtils.getGroupIdFromDn(schemaManager,
((EqualOperator) expression).getValue(), dcId);
if ((joinPlan & GROUP_MEMBER_USER_FLAG) != 0)
userId =
LdapUtils.getUserIdFromDn(schemaManager,
((EqualOperator) expression).getValue(), dcId);
if (groupId != null) {
if (expression.isNegated())
builder.append("g.id not in ( select parent_group_id ");
else
builder.append("g.id in ( select parent_group_id ");
if (flattening)
if (useMaterializedViews)
builder.append("from _Group_Membership_Transitive ");
else
builder.append("from _Group_Membership_Transitive_Non_Materialized ");
else
builder.append("from _Group_Membership ");
builder.append("where member_group_id = ? ");
arguments.add(groupId.toLowerCase());
builder.append(") ");
}
if (userId != null) {
if (expression.isNegated())
builder.append("g.id not in ( select parent_group_id ");
else
builder.append("g.id in ( select parent_group_id ");
if (flattening)
if (useMaterializedViews)
builder.append("from _User_Membership_Transitive ");
else
builder.append("from _User_Membership_Transitive_Non_Materialized ");
else
builder.append("from _User_Membership ");
builder.append("where member_user_id = ? ");
arguments.add(userId.toLowerCase());
builder.append(") ");
}
if (groupId == null && userId == null) {
builder.append("? = 'true' ");
arguments.add(false);
}
} else if (expression instanceof PresenceOperator) {
if (expression.isNegated())
builder.append("( mc.member_group_id is null and mu.member_user_id is null ) ");
else
builder.append("( mc.member_group_id is not null or mu.member_user_id is not null ) ");
}
}
break;
case LdapUtils.MEMBER_OF_AT_OID:
if (entityType == EntityType.GROUP) {
if (expression instanceof EqualOperator) {
String groupId = null;
if ((joinPlan & GROUP_MEMBER_OF_FLAG) != 0)
groupId =
LdapUtils.getGroupIdFromDn(schemaManager,
((EqualOperator) expression).getValue(), dcId);
if (groupId == null) {
builder.append("? = 'true' ");
arguments.add(false);
} else {
if (expression.isNegated())
builder.append("g.id not in ( select member_group_id ");
else
builder.append("g.id in ( select member_group_id ");
if (flattening)
if (useMaterializedViews)
builder.append("from _Group_Membership_Transitive ");
else
builder.append("from _Group_Membership_Transitive_Non_Materialized ");
else
builder.append("from _Group_Membership ");
builder.append("where parent_group_id = ? ");
arguments.add(groupId.toLowerCase());
builder.append(") ");
}
} else if (expression instanceof PresenceOperator) {
builder.append("mp.parent_group_id ");
builder.append(getOperator(expression));
}
} else if (entityType == EntityType.USER) {
if (expression instanceof EqualOperator) {
String groupId = null;
if ((joinPlan & USER_MEMBER_OF_FLAG) != 0)
groupId =
LdapUtils.getGroupIdFromDn(schemaManager,
((EqualOperator) expression).getValue(), dcId);
if (groupId == null) {
builder.append("? = 'true' ");
arguments.add(false);
} else {
if (expression.isNegated())
builder.append("u.id not in ( select member_user_id ");
else
builder.append("u.id in ( select member_user_id ");
if (flattening)
if (useMaterializedViews)
builder.append("from _User_Membership_Transitive ");
else
builder.append("from _User_Membership_Transitive_Non_Materialized ");
else
builder.append("from _User_Membership ");
builder.append("where parent_group_id = ? ");
arguments.add(groupId.toLowerCase());
builder.append(") ");
}
} else if (expression instanceof PresenceOperator) {
builder.append("mu.parent_group_id ");
builder.append(getOperator(expression));
}
}
break;
default:
throw new IllegalArgumentException("Cannot process unexpected query expression " +
expression.getClass().getName());
}
}
private void handleOperator(StringBuilder builder, List arguments, OperatorExpression expression) {
builder.append(getOperator(expression));
if (expression instanceof BinaryOperator) {
builder.append("? ");
if (expression instanceof WildcardOperator)
arguments.add(((WildcardOperator) expression).getValue(WildcardOperator.Format.SQL));
else
arguments.add(((BinaryOperator) expression).getValue().toLowerCase());
}
}
private String getOperator(OperatorExpression expression) {
if (expression instanceof EqualOperator)
if (expression.isNegated())
return "<> ";
else
return "= ";
if (expression instanceof WildcardOperator)
if (expression.isNegated())
return "not like ";
else
return "like ";
if (expression instanceof PresenceOperator)
if (expression.isNegated())
return "is null ";
else
return "is not null ";
throw new IllegalArgumentException("Cannot handle unexpected operator " +
expression.getClass().getSimpleName());
}
}