/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* 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.picketlink.idm.internal;
import org.picketlink.idm.IdGenerator;
import org.picketlink.idm.IdentityManagementException;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.PermissionManager;
import org.picketlink.idm.RelationshipManager;
import org.picketlink.idm.config.IdentityConfiguration;
import org.picketlink.idm.config.IdentityStoreConfiguration.IdentityOperation;
import org.picketlink.idm.config.OperationNotSupportedException;
import org.picketlink.idm.event.EventBridge;
import org.picketlink.idm.event.PartitionCreatedEvent;
import org.picketlink.idm.event.PartitionDeletedEvent;
import org.picketlink.idm.event.PartitionUpdatedEvent;
import org.picketlink.idm.model.IdentityType;
import org.picketlink.idm.model.Partition;
import org.picketlink.idm.model.basic.Realm;
import org.picketlink.idm.permission.acl.spi.PermissionHandler;
import org.picketlink.idm.query.IdentityQuery;
import org.picketlink.idm.query.IdentityQueryBuilder;
import org.picketlink.idm.spi.AttributeStore;
import org.picketlink.idm.spi.IdentityContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.picketlink.common.util.StringUtil.isNullOrEmpty;
import static org.picketlink.idm.IDMInternalMessages.MESSAGES;
/**
* <p>Provides partition management functionality, and partition-specific {@link IdentityManager} instances.</p>
*
* <p>Before using this factory you need a valid {@link IdentityConfiguration}, usually created using the
* {@link org.picketlink.idm.config.IdentityConfigurationBuilder}.</p>
*
* <p>This class is thread safe, and is intended to be used as an application-scoped component.</p>
*
* @author Shane Bryzak
*/
public class DefaultPartitionManager extends AbstractAttributedTypeManager<Partition> implements PartitionManager {
private static final long serialVersionUID = 1L;
private static final Realm DEFAULT_REALM = new Realm(Realm.DEFAULT_REALM);
public DefaultPartitionManager(IdentityConfiguration configuration) {
this(Arrays.asList(configuration));
}
public DefaultPartitionManager(Collection<IdentityConfiguration> configurations) {
this(configurations, null, null);
}
public DefaultPartitionManager(Collection<IdentityConfiguration> configurations, EventBridge eventBridge,
Collection<PermissionHandler> permissionHandlers) {
this(configurations, eventBridge, permissionHandlers, null);
}
public DefaultPartitionManager(Collection<IdentityConfiguration> configurations, EventBridge eventBridge,
Collection<PermissionHandler> permissionHandlers, IdGenerator idGenerator) {
super(new PartitionManagerConfiguration(configurations, permissionHandlers, eventBridge, idGenerator));
}
@Override
public IdentityManager createIdentityManager() throws IdentityManagementException {
return createIdentityManager(DEFAULT_REALM);
}
@Override
public IdentityManager createIdentityManager(Partition partition) throws IdentityManagementException {
if (partition == null) {
if (!getConfiguration().supportsPartition()) {
return createIdentityManager();
}
throw MESSAGES.nullArgument("Partition");
}
Partition storedPartition = getStoredPartition(partition);
try {
return new ContextualIdentityManager(storedPartition, this);
} catch (Exception e) {
throw MESSAGES.partitionCouldNotCreateIdentityManager(storedPartition, e);
}
}
@Override
public PermissionManager createPermissionManager() {
return createPermissionManager(DEFAULT_REALM);
}
@Override
public PermissionManager createPermissionManager(Partition partition) throws IdentityManagementException {
if (partition == null) {
throw MESSAGES.nullArgument("Partition");
}
Partition storedPartition = getStoredPartition(partition);
try {
return new ContextualPermissionManager(storedPartition, this);
} catch (Exception ex) {
throw MESSAGES.partitionCouldNotCreatePermissionManager(storedPartition);
}
}
@Override
public RelationshipManager createRelationshipManager() {
return new ContextualRelationshipManager(this);
}
@Override
public <T extends Partition> T getPartition(Class<T> partitionClass, String name) {
if (partitionClass == null) {
throw MESSAGES.nullArgument("Partition class");
}
if (isNullOrEmpty(name)) {
throw MESSAGES.nullArgument("Partition name");
}
if (!getConfiguration().supportsPartition()) {
return (T) createDefaultPartition();
}
try {
IdentityContext identityContext = getIdentityContext();
T partition = getStoreSelector().getStoreForPartitionOperation(identityContext, partitionClass).<T>get(identityContext, partitionClass, name);
if (partition != null) {
loadAttributes(identityContext, (T) partition);
}
return partition;
} catch (Exception e) {
throw MESSAGES.partitionGetFailed(partitionClass, name, e);
}
}
@Override
public <T extends Partition> List<T> getPartitions(Class<T> partitionClass) {
if (partitionClass == null) {
throw MESSAGES.nullArgument("Partition class");
}
List<T> partitions = new ArrayList<T>();
if (!getConfiguration().supportsPartition()) {
partitions.add((T) createDefaultPartition());
} else {
try {
IdentityContext identityContext = getIdentityContext();
partitions.addAll(getStoreSelector().getStoreForPartitionOperation(identityContext, partitionClass).<T>get(identityContext, partitionClass));
for (T partition : partitions) {
loadAttributes(identityContext, partition);
}
} catch (Exception e) {
throw MESSAGES.partitionGetFailed(partitionClass, "not specified", e);
}
}
return partitions;
}
@Override
public <T extends Partition> T lookupById(final Class<T> partitionClass, final String id) {
if (partitionClass == null) {
throw MESSAGES.nullArgument("Partition class");
}
if (isNullOrEmpty(id)) {
throw MESSAGES.nullArgument("Partition identifier");
}
if (!getConfiguration().supportsPartition()) {
return (T) createDefaultPartition();
}
try {
IdentityContext identityContext = getIdentityContext();
T partition = getStoreSelector().getStoreForPartitionOperation(identityContext, partitionClass).<T>lookupById(identityContext, partitionClass, id);
if (partition != null) {
loadAttributes(identityContext, (T) partition);
}
return partition;
} catch (Exception e) {
throw MESSAGES.partitionGetFailed(partitionClass, id, e);
}
}
@Override
protected void fireAttributedTypeAddedEvent(Partition attributedType) {
}
@Override
protected void doAdd(Partition attributedType) {
}
@Override
public void add(Partition attributedType) throws IdentityManagementException {
add(attributedType, null);
}
@Override
public void add(Partition partition, String configurationName) throws IdentityManagementException {
checkPartitionManagementSupported();
if (partition == null) {
throw MESSAGES.nullArgument("Partition");
}
if (isNullOrEmpty(configurationName)) {
configurationName = getConfiguration().getDefaultConfigurationName();
}
if (getConfiguration().getConfigurationByName(configurationName) != null) {
checkUniqueness(partition);
try {
IdentityContext identityContext = getIdentityContext();
getStoreSelector().getStoreForPartitionOperation(identityContext, partition.getClass()).add(identityContext, partition, configurationName);
addAttributes(identityContext, partition);
fireEvent(new PartitionCreatedEvent(partition, this));
} catch (Exception e) {
throw MESSAGES.partitionAddFailed(partition, configurationName, e);
}
}
}
@Override
protected void fireAttributedTypeUpdatedEvent(Partition attributedType) {
fireEvent(new PartitionUpdatedEvent(attributedType, this));
}
@Override
protected void doUpdate(Partition attributedType) {
checkPartitionManagementSupported();
IdentityContext identityContext = getIdentityContext();
getStoreSelector().getStoreForPartitionOperation(identityContext, attributedType.getClass()).update(identityContext, attributedType);
}
@Override
protected void fireAttributedTypeRemovedEvent(Partition attributedType) {
fireEvent(new PartitionDeletedEvent(attributedType, this));
}
@Override
protected void doRemove(Partition attributedType) {
checkPartitionManagementSupported();
IdentityManager identityManager = createIdentityManager(attributedType);
IdentityQueryBuilder queryBuilder = identityManager.getQueryBuilder();
IdentityQuery<IdentityType> query = queryBuilder.createIdentityQuery(IdentityType.class);
for (IdentityType identityType : query.getResultList()) {
identityManager.remove(identityType);
}
IdentityContext identityContext = getIdentityContext();
getStoreSelector().getStoreForPartitionOperation(identityContext, attributedType.getClass()).remove(identityContext, attributedType);
}
@Override
protected void checkUniqueness(Partition attributedType) throws IdentityManagementException {
Partition storedPartition = getPartition(attributedType.getClass(), attributedType.getName());
if (storedPartition != null) {
throw MESSAGES.partitionAlreadyExistsWithName(attributedType.getClass(), storedPartition.getName());
}
}
@Override
protected void checkIfExists(Partition partition) throws IdentityManagementException {
if (partition == null) {
throw MESSAGES.nullArgument("Partition");
}
if (lookupById(partition.getClass(), partition.getId()) == null) {
throw MESSAGES.partitionNotFoundWithName(partition.getClass(), partition.getName());
}
}
@Override
public Collection<IdentityConfiguration> getConfigurations() {
return getConfiguration().getConfigurations();
}
private void checkPartitionManagementSupported() throws OperationNotSupportedException {
if (!getConfiguration().supportsPartition()) {
throw MESSAGES.partitionManagementNoSupported(Partition.class, IdentityOperation.create);
}
}
private Partition createDefaultPartition() {
Partition storedPartition = new Realm(Realm.DEFAULT_REALM);
storedPartition.setId(Realm.DEFAULT_REALM);
return storedPartition;
}
private Partition getStoredPartition(final Partition partition) {
Partition storedPartition;
if (getConfiguration().supportsPartition()) {
storedPartition = getPartition(partition.getClass(), partition.getName());
} else {
storedPartition = createDefaultPartition();
}
if (storedPartition == null) {
throw MESSAGES.partitionNotFoundWithName(partition.getClass(), partition.getName());
}
return storedPartition;
}
private <T extends Partition> void loadAttributes(final IdentityContext context, final T partition) {
AttributeStore<?> attributeStore = getStoreSelector().getStoreForAttributeOperation(context);
if (attributeStore != null) {
attributeStore.loadAttributes(context, partition);
}
}
@Override
public IdentityContext getIdentityContext() {
return createIdentityContext(null, getConfiguration().getEventBridge(), getConfiguration().getIdGenerator());
}
}