Introduce ancestor interface for entities with attributes

This commit is contained in:
Michal Hajas 2021-12-08 12:56:55 +01:00 committed by Hynek Mlnařík
parent bf0f3d605c
commit fc237a8b63
11 changed files with 105 additions and 39 deletions

View file

@ -47,6 +47,7 @@ import java.util.stream.Stream;
import static org.keycloak.models.map.processor.FieldAccessorType.GETTER;
import static org.keycloak.models.map.processor.Util.getGenericsDeclaration;
import static org.keycloak.models.map.processor.Util.isMapType;
public abstract class AbstractGenerateEntityImplementationsProcessor extends AbstractProcessor {
@ -157,7 +158,7 @@ public abstract class AbstractGenerateEntityImplementationsProcessor extends Abs
protected boolean isKnownCollectionOfImmutableFinalTypes(TypeMirror fieldType) {
List<TypeMirror> res = getGenericsDeclaration(fieldType);
return isCollection(fieldType) && res.stream().allMatch(tm -> isImmutableFinalType(tm) || isKnownCollectionOfImmutableFinalTypes(tm));
return isCollection(fieldType) && res.stream().allMatch(this::isImmutableFinalType);
}
protected boolean isCollection(TypeMirror fieldType) {
@ -175,12 +176,24 @@ public abstract class AbstractGenerateEntityImplementationsProcessor extends Abs
}
protected String deepClone(TypeMirror fieldType, String parameterName) {
if (isKnownCollectionOfImmutableFinalTypes(fieldType)) {
TypeElement typeElement = elements.getTypeElement(types.erasure(fieldType).toString());
if (isKnownCollectionOfImmutableFinalTypes(fieldType)) {
return parameterName + " == null ? null : " + interfaceToImplementation(typeElement, parameterName);
} else {
return "deepClone(" + parameterName + ")";
} else if (isMapType(typeElement)) {
List<TypeMirror> mapTypes = getGenericsDeclaration(fieldType);
boolean isKeyImmutable = isImmutableFinalType(mapTypes.get(0));
boolean isValueImmutable = isImmutableFinalType(mapTypes.get(1));
return parameterName + " == null ? null : " + parameterName + ".entrySet().stream().collect(" +
"java.util.stream.Collectors.toMap(" +
(isKeyImmutable ? "java.util.Map.Entry::getKey" : "entry -> " + deepClone(mapTypes.get(0), "entry.getKey()")) +
", " +
(isValueImmutable ? "java.util.Map.Entry::getValue" : "entry -> " + deepClone(mapTypes.get(1), "entry.getValue()")) +
", (o1, o2) -> o1" +
", java.util.HashMap::new" +
"))";
}
return "deepClone(" + parameterName + ")";
}
protected boolean isPrimitiveType(TypeMirror fieldType) {

View file

@ -44,6 +44,10 @@ public class HotRodTypesUtils {
return new HotRodPair<>(entry.getKey(), entry.getValue());
}
public static HotRodAttributeEntity createHotRodAttributeEntityFromMapEntry(Map.Entry<String, List<String>> entry) {
return new HotRodAttributeEntity(entry.getKey(), entry.getValue());
}
public static <SetType, KeyType> boolean removeFromSetByMapKey(Set<SetType> set, KeyType key, Function<SetType, KeyType> keyGetter) {
if (set == null || set.isEmpty()) { return false; }
return set.stream()

View file

@ -136,7 +136,8 @@ public class MapResourceAdapter extends AbstractResourceModel<MapResourceEntity>
@Override
public String getSingleAttribute(String name) {
return entity.getSingleAttribute(name);
List<String> attributeValues = entity.getAttribute(name);
return attributeValues == null || attributeValues.isEmpty() ? null : attributeValues.get(0);
}
@Override

View file

@ -19,6 +19,7 @@ package org.keycloak.models.map.authorization.entity;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
import java.util.HashMap;
import java.util.HashSet;
@ -27,7 +28,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
public class MapResourceEntity extends UpdatableEntity.Impl implements AbstractEntity {
public class MapResourceEntity extends UpdatableEntity.Impl implements AbstractEntity, EntityWithAttributes {
private String id;
private String name;
@ -156,23 +157,29 @@ public class MapResourceEntity extends UpdatableEntity.Impl implements AbstractE
return policyIds;
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.updated |= ! Objects.equals(this.attributes, attributes);
this.attributes.clear();
this.attributes.putAll(attributes);
}
@Override
public List<String> getAttribute(String name) {
return attributes.get(name);
}
public String getSingleAttribute(String name) {
List<String> attributeValues = attributes.get(name);
return attributeValues == null || attributeValues.isEmpty() ? null : attributeValues.get(0);
}
@Override
public void setAttribute(String name, List<String> value) {
this.updated |= !Objects.equals(this.attributes.put(name, value), value);
}
@Override
public void removeAttribute(String name) {
this.updated |= this.attributes.remove(name) != null;
}

View file

@ -17,9 +17,9 @@
package org.keycloak.models.map.client;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@ -36,7 +36,7 @@ import org.keycloak.models.map.common.DeepCloner;
inherits = "org.keycloak.models.map.client.MapClientEntity.AbstractClientEntity"
)
@DeepCloner.Root
public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
public interface MapClientEntity extends AbstractEntity, UpdatableEntity, EntityWithAttributes {
public abstract class AbstractClientEntity extends UpdatableEntity.Impl implements MapClientEntity {
@ -87,11 +87,6 @@ public interface MapClientEntity extends AbstractEntity, UpdatableEntity {
void removeWebOrigin(String webOrigin);
void setWebOrigins(Set<String> webOrigins);
default List<String> getAttribute(String name) { return getAttributes() == null ? null : getAttributes().get(name); }
Map<String, List<String>> getAttributes();
void removeAttribute(String name);
void setAttribute(String name, List<String> values);
String getAuthenticationFlowBindingOverride(String binding);
Map<String, String> getAuthenticationFlowBindingOverrides();
void removeAuthenticationFlowBindingOverride(String binding);

View file

@ -29,9 +29,10 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
public class MapClientScopeEntity extends UpdatableEntity.Impl implements AbstractEntity {
public class MapClientScopeEntity extends UpdatableEntity.Impl implements AbstractEntity, EntityWithAttributes {
private String id;
private String realmId;
@ -94,10 +95,19 @@ public class MapClientScopeEntity extends UpdatableEntity.Impl implements Abstra
this.protocol = protocol;
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.attributes.clear();
this.attributes.putAll(attributes);
this.updated = true;
}
@Override
public void setAttribute(String name, List<String> values) {
this.updated |= ! Objects.equals(this.attributes.put(name, values), values);
}
@ -132,10 +142,12 @@ public class MapClientScopeEntity extends UpdatableEntity.Impl implements Abstra
return id == null ? null : protocolMappers.get(id);
}
@Override
public void removeAttribute(String name) {
this.updated |= this.attributes.remove(name) != null;
}
@Override
public List<String> getAttribute(String name) {
return attributes.getOrDefault(name, Collections.EMPTY_LIST);
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2021 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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 org.keycloak.models.map.common;
import java.util.List;
import java.util.Map;
public interface EntityWithAttributes {
Map<String, List<String>> getAttributes();
void setAttributes(Map<String, List<String>> attributes);
List<String> getAttribute(String name);
void setAttribute(String name, List<String> value);
void removeAttribute(String name);
}

View file

@ -20,17 +20,16 @@ package org.keycloak.models.map.group;
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.DeepCloner;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
import java.util.List;
import java.util.Map;
import java.util.Set;
@GenerateEntityImplementations(
inherits = "org.keycloak.models.map.group.MapGroupEntity.AbstractGroupEntity"
)
@DeepCloner.Root
public interface MapGroupEntity extends UpdatableEntity, AbstractEntity {
public interface MapGroupEntity extends UpdatableEntity, AbstractEntity, EntityWithAttributes {
public abstract class AbstractGroupEntity extends UpdatableEntity.Impl implements MapGroupEntity {
@ -50,12 +49,6 @@ public interface MapGroupEntity extends UpdatableEntity, AbstractEntity {
}
Map<String, List<String>> getAttributes();
void setAttributes(Map<String, List<String>> attributes);
List<String> getAttribute(String name);
void setAttribute(String name, List<String> value);
void removeAttribute(String name);
String getName();
void setName(String name);

View file

@ -30,6 +30,7 @@ import org.keycloak.common.util.Time;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.OTPPolicy;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
import org.keycloak.models.map.realm.entity.MapAuthenticationExecutionEntity;
import org.keycloak.models.map.realm.entity.MapAuthenticationFlowEntity;
@ -43,7 +44,7 @@ import org.keycloak.models.map.realm.entity.MapRequiredActionProviderEntity;
import org.keycloak.models.map.realm.entity.MapRequiredCredentialEntity;
import org.keycloak.models.map.realm.entity.MapWebAuthnPolicyEntity;
public class MapRealmEntity extends UpdatableEntity.Impl implements AbstractEntity {
public class MapRealmEntity extends UpdatableEntity.Impl implements AbstractEntity, EntityWithAttributes {
private String id;
private String name;
@ -669,22 +670,33 @@ public class MapRealmEntity extends UpdatableEntity.Impl implements AbstractEnti
this.webAuthnPolicyPasswordless = webAuthnPolicyPasswordless;
}
@Override
public void setAttribute(String name, List<String> values) {
this.updated |= ! Objects.equals(this.attributes.put(name, values), values);
}
@Override
public void removeAttribute(String name) {
this.updated |= attributes.remove(name) != null;
}
@Override
public List<String> getAttribute(String name) {
return attributes.getOrDefault(name, Collections.EMPTY_LIST);
}
@Override
public Map<String, List<String>> getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.attributes.clear();
this.attributes.putAll(attributes);
this.updated = true;
}
public void addDefaultClientScope(String scopeId) {
this.updated |= this.defaultClientScopes.add(scopeId);
}

View file

@ -22,13 +22,14 @@ import java.util.Set;
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.DeepCloner;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
@GenerateEntityImplementations(
inherits = "org.keycloak.models.map.role.MapRoleEntity.AbstractRoleEntity"
)
@DeepCloner.Root
public interface MapRoleEntity extends AbstractEntity, UpdatableEntity {
public interface MapRoleEntity extends AbstractEntity, UpdatableEntity, EntityWithAttributes {
public abstract class AbstractRoleEntity extends UpdatableEntity.Impl implements MapRoleEntity {
@ -76,10 +77,4 @@ public interface MapRoleEntity extends AbstractEntity, UpdatableEntity {
void setCompositeRoles(Set<String> compositeRoles);
void addCompositeRole(String roleId);
void removeCompositeRole(String roleId);
Map<String, List<String>> getAttributes();
void setAttributes(Map<String, List<String>> attributes);
void setAttribute(String name, List<String> values);
void removeAttribute(String name);
}

View file

@ -19,12 +19,12 @@ package org.keycloak.models.map.user;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.map.common.AbstractEntity;
import org.keycloak.models.map.common.EntityWithAttributes;
import org.keycloak.models.map.common.UpdatableEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@ -40,7 +40,7 @@ import java.util.stream.Stream;
*
* @author mhajas
*/
public class MapUserEntity extends UpdatableEntity.Impl implements AbstractEntity {
public class MapUserEntity extends UpdatableEntity.Impl implements AbstractEntity, EntityWithAttributes {
private String id;
private String realmId;
@ -183,19 +183,23 @@ public class MapUserEntity extends UpdatableEntity.Impl implements AbstractEntit
return attributes;
}
@Override
public List<String> getAttribute(String name) {
return attributes.getOrDefault(name, Collections.emptyList());
}
@Override
public void setAttributes(Map<String, List<String>> attributes) {
this.updated |= !Objects.equals(this.attributes, attributes);
this.attributes = attributes;
}
@Override
public void setAttribute(String name, List<String> value) {
this.updated |= !Objects.equals(this.attributes.put(name, value), value);
}
@Override
public void removeAttribute(String name) {
this.updated |= this.attributes.remove(name) != null;
}