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.
pl.edu.icm.unity.webadmin.identities.IdentitiesGrid Maven / Gradle / Ivy
/*
* Copyright (c) 2018 Bixbit - Krzysztof Benedyczak All rights reserved.
* See LICENCE.txt file for licensing information.
*/
package pl.edu.icm.unity.webadmin.identities;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import com.vaadin.data.TreeData;
import com.vaadin.data.provider.HierarchicalQuery;
import com.vaadin.data.provider.TreeDataProvider;
import com.vaadin.server.SerializablePredicate;
import com.vaadin.shared.ui.dnd.EffectAllowed;
import com.vaadin.ui.TreeGrid;
import com.vaadin.ui.components.grid.GridDragSource;
import com.vaadin.ui.components.grid.MultiSelectionModel;
import io.imunity.webadmin.identities.BaseColumn;
import io.imunity.webadmin.identities.EntitiesLoader;
import io.imunity.webadmin.identities.EntityChangedEvent;
import io.imunity.webadmin.identities.EntityFilter;
import io.imunity.webadmin.identities.IdentitiesGridColumnConstans;
import io.imunity.webadmin.identities.IdentitiesTablePreferences;
import io.imunity.webadmin.identities.IdentityEntry;
import io.imunity.webadmin.identities.ResolvedEntity;
import pl.edu.icm.unity.MessageSource;
import pl.edu.icm.unity.base.utils.Log;
import pl.edu.icm.unity.engine.api.CredentialManagement;
import pl.edu.icm.unity.engine.api.PreferencesManagement;
import pl.edu.icm.unity.engine.api.attributes.AttributeSupport;
import pl.edu.icm.unity.engine.api.identity.IdentityTypeDefinition;
import pl.edu.icm.unity.engine.api.identity.IdentityTypeSupport;
import pl.edu.icm.unity.engine.api.utils.PrototypeComponent;
import pl.edu.icm.unity.exceptions.EngineException;
import pl.edu.icm.unity.exceptions.InternalException;
import pl.edu.icm.unity.stdext.utils.EntityNameMetadataProvider;
import pl.edu.icm.unity.types.authn.CredentialDefinition;
import pl.edu.icm.unity.types.basic.Attribute;
import pl.edu.icm.unity.types.basic.AttributeType;
import pl.edu.icm.unity.types.basic.Entity;
import pl.edu.icm.unity.types.basic.Identity;
import pl.edu.icm.unity.webui.WebSession;
import pl.edu.icm.unity.webui.bus.EventsBus;
import pl.edu.icm.unity.webui.common.EntityWithLabel;
import pl.edu.icm.unity.webui.common.GridContextMenuSupport;
import pl.edu.icm.unity.webui.common.GridSelectionSupport;
import pl.edu.icm.unity.webui.common.NotificationPopup;
import pl.edu.icm.unity.webui.common.SingleActionHandler;
import pl.edu.icm.unity.webui.common.Styles;
import pl.edu.icm.unity.webui.common.attributes.AttributeHandlerRegistry;
import pl.edu.icm.unity.webui.common.attributes.CachedAttributeHandlers;
/**
* Displays a tree grid with identities. Can present contents in two modes:
* - flat, where each identity is a fully separate table row
* - grouped by entity, where each entity has all its entities as children
* @author K. Benedyczak
*/
@PrototypeComponent
public class IdentitiesGrid extends TreeGrid
{
private static final Logger log = Log.getLogger(Log.U_SERVER_WEB, IdentitiesGrid.class);
public static final String ENTITY_DND_TYPE = "entity";
private final AttributeSupport attributeSupport;
private final CredentialManagement credentialManagement;
private final IdentityTypeSupport idTypeSupport;
private final MessageSource msg;
private final EntitiesLoader entitiesLoader;
private final AttributeHandlerRegistry attrHandlerRegistry;
private boolean groupByEntity;
private boolean showTargeted;
private String group;
private String entityNameAttribute = null;
private Map typeDefinitionsMap;
private Map credentialDefinitions;
private List cachedEntitites;
private TreeData treeData;
private TreeDataProvider dataProvider;
private List filters;
private GridContextMenuSupport contextMenuSupp;
private EventsBus bus;
private IdentityEntry lastSelected;
private PreferencesManagement preferencesMan;
@SuppressWarnings("unchecked")
@Autowired
public IdentitiesGrid(MessageSource msg, AttributeSupport attributeSupport,
IdentityTypeSupport idTypeSupport, EntitiesLoader entitiesLoader,
AttributeHandlerRegistry attrHandlerRegistry, PreferencesManagement preferencesMan,
CredentialManagement credentialManagement)
{
this.msg = msg;
this.attributeSupport = attributeSupport;
this.idTypeSupport = idTypeSupport;
this.entitiesLoader = entitiesLoader;
this.attrHandlerRegistry = attrHandlerRegistry;
this.preferencesMan = preferencesMan;
this.credentialManagement = credentialManagement;
createBaseColumns();
cachedEntitites = new ArrayList<>(200);
dataProvider = (TreeDataProvider) getDataProvider();
treeData = dataProvider.getTreeData();
filters = new ArrayList<>();
contextMenuSupp = new GridContextMenuSupport<>(this);
this.bus = WebSession.getCurrent().getEventBus();
setSelectionMode(SelectionMode.MULTI);
GridSelectionSupport.installClickListener(this);
((MultiSelectionModel)getSelectionModel())
.addMultiSelectionListener(event -> selectionChanged(event.getAllSelectedItems()));
setSizeFull();
setColumnReorderingAllowed(true);
setStyleName(Styles.denseTreeGrid.toString());
updateCredentialStatusColumns();
loadPreferences();
addColumnVisibilityChangeListener(event -> savePreferences());
addColumnResizeListener(event -> savePreferences());
addColumnReorderListener(event -> savePreferences());
GridDragSource drag = new GridDragSource<>(this);
drag.setEffectAllowed(EffectAllowed.MOVE);
drag.setDragDataGenerator(ENTITY_DND_TYPE, entity -> "{}");
drag.addGridDragStartListener(event ->
{
drag.setDragData(event.getDraggedItems().stream().map(
i -> i.getSourceEntity()).collect(Collectors.toSet()));
});
drag.addGridDragEndListener(event -> drag.setDragData(null));
}
private void createBaseColumns()
{
for (BaseColumn column: BaseColumn.values())
{
addColumn(ie -> ie.getBaseValue(column))
.setCaption(msg.getMessage(column.captionKey))
.setExpandRatio(column.defWidth)
.setHidable(column.collapsingAllowed)
.setHidden(column.initiallyCollapsed)
.setId(column.name());
}
}
public void addActionHandler(SingleActionHandler actionHandler)
{
contextMenuSupp.addActionHandler(actionHandler);
}
public List> getActionHandlers()
{
return contextMenuSupp.getActionHandlers();
}
public void setMode(boolean groupByEntity)
{
this.groupByEntity = groupByEntity;
reloadTableContentsFromData();
savePreferences();
}
public void setShowTargeted(boolean showTargeted) throws EngineException
{
this.showTargeted = showTargeted;
showGroup(group);
savePreferences();
}
public String getGroup()
{
return this.group;
}
public void showGroup(String group) throws EngineException
{
this.group = group;
AttributeType nameAt = attributeSupport.getAttributeTypeWithSingeltonMetadata(
EntityNameMetadataProvider.NAME);
this.entityNameAttribute = nameAt == null ? null : nameAt.getName();
typeDefinitionsMap = idTypeSupport.getTypeDefinitionsMap();
updateCredentialStatusColumns();
updateAttributeColumnHeaders();
Set selected = getSelectedItems();
treeData.clear();
dataProvider.refreshAll();
cachedEntitites.clear();
getSelectionModel().deselectAll();
if (group != null)
entitiesLoader.reload(selected, group, showTargeted,
this::addAndCacheResolvedEntities);
}
private void reloadTableContentsFromData()
{
Set selected = getSelectedItems();
treeData.clear();
dataProvider.refreshAll();
addResolvedEntities(cachedEntitites, selected, -1);
}
private void addAndCacheResolvedEntities(List entities, Set selected,
float progress)
{
cachedEntitites.addAll(entities);
addResolvedEntities(entities, selected, progress);
}
private void addResolvedEntities(List entities, Set selected,
float progress)
{
CachedAttributeHandlers attributeHandlers = new CachedAttributeHandlers(attrHandlerRegistry);
for (ResolvedEntity entity: entities)
{
if (groupByEntity)
addGroupedEntriesToTable(entity, selected, attributeHandlers);
else
addFlatEntriesToTable(entity, selected, attributeHandlers);
}
dataProvider.refreshAll();
}
private void addGroupedEntriesToTable(ResolvedEntity resolvedEntity,
Set savedSelection, CachedAttributeHandlers attributeHandlers)
{
Entity entity = resolvedEntity.getEntity();
IdentityEntry parentEntry = createEntry(null, entity,
resolvedEntity.getRootAttributes(),
resolvedEntity.getCurrentAttributes(), attributeHandlers);
treeData.addItem(null, parentEntry);
restoreSelectionIfMatching(savedSelection, parentEntry);
for (Identity id: resolvedEntity.getIdentities())
{
IdentityEntry childEntry = createEntry(id, entity,
resolvedEntity.getRootAttributes(),
resolvedEntity.getCurrentAttributes(), attributeHandlers);
treeData.addItem(parentEntry, childEntry);
restoreSelectionIfMatching(savedSelection, childEntry);
}
}
private void restoreSelectionIfMatching(Set savedSelection, IdentityEntry currentEntry)
{
if (savedSelection.contains(currentEntry) && getSelectedItems().isEmpty())
select(currentEntry);
}
private void addFlatEntriesToTable(ResolvedEntity resolvedEntity,
Set savedSelection, CachedAttributeHandlers attributeHandlers)
{
for (Identity id: resolvedEntity.getIdentities())
{
IdentityEntry idEntry = createEntry(id, resolvedEntity.getEntity(),
resolvedEntity.getRootAttributes(),
resolvedEntity.getCurrentAttributes(), attributeHandlers);
treeData.addItem(null, idEntry);
restoreSelectionIfMatching(savedSelection, idEntry);
}
}
private IdentityEntry createEntry(Identity id, Entity ent, Map rootAttributes,
Map curAttributes, CachedAttributeHandlers attributeHandlers)
{
String label = null;
if (entityNameAttribute != null && rootAttributes.containsKey(entityNameAttribute))
label = rootAttributes.get(entityNameAttribute).getValues().get(0).toString() + " ";
EntityWithLabel entWithLabel = new EntityWithLabel(ent, label);
Map attributesByColumnId = new HashMap<>();
List> columns = getColumns();
for (Column column: columns)
{
String columnId = column.getId();
if (columnId == null || !columnId.startsWith(IdentitiesGridColumnConstans.ATTR_COL_PREFIX))
continue;
Attribute attribute = getAttributeForColumnProperty(columnId, rootAttributes, curAttributes);
String val;
if (attribute == null)
val = msg.getMessage("Identities.attributeUndefined");
else
val = attributeHandlers.getSimplifiedAttributeValuesRepresentation(attribute);
attributesByColumnId.put(columnId, val);
}
return id == null ?
new IdentityEntry(entWithLabel, attributesByColumnId, msg) :
new IdentityEntry(entWithLabel, attributesByColumnId, id,
typeDefinitionsMap.get(id.getTypeId()), msg);
}
private void updateCredentialStatusColumns()
{
try
{
credentialDefinitions = credentialManagement.getCredentialDefinitions().stream()
.collect(Collectors.toMap(credDef -> credDef.getName(), cd -> cd));
} catch (EngineException e)
{
throw new InternalException("Can not load credentials", e);
}
for (Map.Entry cd: credentialDefinitions.entrySet())
{
String colKey = IdentitiesGridColumnConstans.CRED_STATUS_COL_PREFIX + cd.getKey();
if (getColumn(colKey) == null)
{
addColumn(ie -> ie.getCredentialStatus(cd.getKey()))
.setId(colKey)
.setCaption(cd.getValue().getName())
.setExpandRatio(IdentitiesGridColumnConstans.CRED_STATUS_COL_RATIO)
.setHidable(true)
.setHidden(true);
}
}
getColumnIds().stream()
.filter(colId -> colId.startsWith(IdentitiesGridColumnConstans.CRED_STATUS_COL_PREFIX))
.map(colId -> colId.substring(IdentitiesGridColumnConstans.CRED_STATUS_COL_PREFIX.length()))
.filter(credId -> !credentialDefinitions.containsKey(credId))
.forEach(credId -> removeColumn(IdentitiesGridColumnConstans.CRED_STATUS_COL_PREFIX + credId));
}
/**
* Adds a new attribute column.
*
* @param attribute
* @param group group from where the attribute's value should be displayed. If it is null then the current
* group is used. Otherwise root group is assumed (in future other 'fixed' groups might be supported,
* but it isn't implemented yet)
*/
void addAttributeColumn(String attribute, String group)
{
String key = (group == null) ? IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX + attribute
: IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX + attribute;
if (getColumn(key) != null)
{
NotificationPopup.showError(msg.getMessage("Identities.customColumnExists"), "");
return;
}
addColumn(ie -> ie.getAttribute(key))
.setCaption(attribute + (group == null ? "@" + this.group : "@/"))
.setExpandRatio(IdentitiesGridColumnConstans.ATTR_COL_RATIO)
.setHidable(true)
.setHidden(false)
.setId(key);
savePreferences();
try
{
showGroup(this.group);
} catch (EngineException e)
{
NotificationPopup.showError(msg,
msg.getMessage("Identities.internalError", e.getMessage()), e);
}
}
void removeAttributeColumn(String group, String attribute)
{
if (Strings.isEmpty(group))
removeColumn(IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX + attribute);
else if (group.equals(this.group))
removeColumn(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX + attribute);
reloadTableContentsFromData();
savePreferences();
}
Set getAttributeColumns(boolean root)
{
List> columns = getColumns();
Set ret = new HashSet();
for (Column column: columns)
{
String property = column.getId();
if (root)
{
if (property.startsWith(IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX))
ret.add(property.substring(IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX.length()));
} else
{
if (property.startsWith(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX))
ret.add(property.substring(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX.length()));
}
}
return ret;
}
private void updateAttributeColumnHeaders()
{
List> columns = getColumns();
for (Column column: columns)
{
String property = column.getId();
if (property.startsWith(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX))
{
String attrName = property.substring(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX.length());
column.setCaption(attrName + "@" + this.group);
}
}
}
private Attribute getAttributeForColumnProperty(String propId, Map rootAttributes,
Map curAttributes)
{
if (propId.startsWith(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX))
{
String attributeName = propId.substring(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX.length());
return curAttributes.get(attributeName);
} else
{
String attributeName = propId.substring(IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX.length());
return rootAttributes.get(attributeName);
}
}
public void addFilter(EntityFilter filter)
{
dataProvider.addFilter(filter);
filters.add(filter);
}
public void removeFilter(EntityFilter filter)
{
filters.remove(filter);
setFilters();
}
private void setFilters()
{
dataProvider.clearFilters();
for (EntityFilter filter: filters)
dataProvider.addFilter(filter);
}
public List getColumnIds()
{
return getColumns().stream()
.map(column -> column.getId())
.collect(Collectors.toList());
}
public Set getVisibleColumnIds()
{
return getColumns().stream()
.filter(column -> !column.isHidden())
.map(column -> column.getId())
.collect(Collectors.toSet());
}
public Boolean isGroupByEntity()
{
return groupByEntity;
}
public Boolean isShowTargeted()
{
return showTargeted;
}
void removeIdentity(IdentityEntry entry)
{
Set selected = getSelectedItems();
for (ResolvedEntity cached: cachedEntitites)
{
if (cached.getEntity().getId() == entry.getSourceEntity().getEntity().getId())
{
cached.getIdentities().remove(entry.getSourceIdentity());
break;
}
}
if (selected.contains(entry))
{
deselect(entry);
}
treeData.removeItem(entry);
dataProvider.refreshAll();
}
void removeEntity(EntityWithLabel removed)
{
Set selected = getSelectedItems();
long removedId = removed.getEntity().getId();
for (int i = 0; i> query =
new HierarchicalQuery<>(
ie -> ie.getSourceEntity().getEntity().getId() == removedId,
null);
List fetched = dataProvider.fetch(query).collect(Collectors.toList());
for (IdentityEntry ie: fetched)
{
if (selected.contains(ie))
{
deselect(ie);
}
treeData.removeItem(ie);
}
} else
{
HierarchicalQuery> query =
new HierarchicalQuery<>(
ie -> ie.getSourceEntity().getEntity().getId() == removedId,
null);
List fetched = dataProvider.fetch(query).collect(Collectors.toList());
//should be only one entry - parent node
for (IdentityEntry ie: fetched)
{
if (selected.contains(ie))
{
deselect(ie);
}
treeData.removeItem(ie);
}
}
dataProvider.refreshAll();
}
private void selectionChanged(Set selectedItems)
{
IdentityEntry selected = null;
if (selectedItems.size() == 1)
{
selected = selectedItems.iterator().next();
}
if (selected == null)
{
lastSelected = null;
bus.fireEvent(new EntityChangedEvent(null, group));
} else if (selected.getSourceIdentity() == null)
{
if (selected.equals(lastSelected))
return;
lastSelected = selected;
bus.fireEvent(new EntityChangedEvent(selected.getSourceEntity(), group));
} else
{
if (lastSelected != null && selected.getSourceEntity().getEntity().equals(
lastSelected.getSourceEntity().getEntity()))
return;
lastSelected = selected;
bus.fireEvent(new EntityChangedEvent(selected.getSourceEntity(), group));
}
}
private void savePreferences()
{
IdentitiesTablePreferences preferences = new IdentitiesTablePreferences();
List columns = getColumnIds();
for (String column : columns)
{
IdentitiesTablePreferences.ColumnSettings settings = new IdentitiesTablePreferences.ColumnSettings();
settings.setCollapsed(getColumn(column).isHidden());
settings.setWidth(getColumn(column).getWidth());
Iterator> iterator = getColumns().iterator();
int i = 0;
while (iterator.hasNext())
{
if (iterator.next().getId().equals(column))
{
settings.setOrder(i);
break;
}
i++;
}
preferences.addColumneSettings(column, settings);
}
preferences.setGroupByEntitiesSetting(groupByEntity);
preferences.setShowTargetedSetting(showTargeted);
try
{
preferences.savePreferences(preferencesMan);
} catch (EngineException e)
{
NotificationPopup.showError(msg.getMessage("error"),
msg.getMessage("Identities.cannotSavePrefernces"));
return;
}
}
private void loadPreferences()
{
IdentitiesTablePreferences preferences = null;
try
{
preferences = IdentitiesTablePreferences.getPreferences(preferencesMan);
} catch (EngineException e)
{
log.debug("Can not load preferences for identities table", e);
return;
}
groupByEntity = preferences.getGroupByEntitiesSetting();
showTargeted = preferences.getShowTargetedSetting();
Set columns = new HashSet<>();
columns.addAll(getColumnIds());
if (preferences != null && preferences.getColumnSettings().size() > 0)
{
Map columnsOrder = new HashMap<>();
for (Map.Entry entry : preferences
.getColumnSettings().entrySet())
{
if (!columns.contains(entry.getKey().toString()))
{
if (entry.getKey().startsWith(IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX))
{
addAttributeColumn(entry.getKey().substring(
IdentitiesGridColumnConstans.ATTR_ROOT_COL_PREFIX.length()),
"/");
} else if (entry.getKey().startsWith(IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX))
{
addAttributeColumn(entry.getKey().substring(
IdentitiesGridColumnConstans.ATTR_CURRENT_COL_PREFIX.length()),
null);
} else
{
continue;
}
getColumn(entry.getKey())
.setHidden(entry.getValue().isCollapsed());
if (entry.getValue().getWidth() > 0)
getColumn(entry.getKey()).setWidth(
entry.getValue().getWidth());
} else
{
if (!entry.getKey().equals(BaseColumn.entity.toString()))
{
getColumn(entry.getKey()).setHidden(
entry.getValue().isCollapsed());
}
if (entry.getValue().getWidth() > 0)
getColumn(entry.getKey()).setWidth(
entry.getValue().getWidth());
}
columnsOrder.put(entry.getKey(), entry.getValue().getOrder());
}
//all which are not in prefs land at the end. Important for prefs from older version.
List orderedColumns = new ArrayList<>(columns);
orderedColumns.sort((a, b) ->
Integer.compare(columnsOrder.getOrDefault(a, Integer.MAX_VALUE),
columnsOrder.getOrDefault(b, Integer.MAX_VALUE)));
setColumnOrder(orderedColumns.toArray(new String[orderedColumns.size()]));
}
}
}