/*
* 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.query.internal;
import org.picketlink.common.properties.Property;
import org.picketlink.common.properties.query.NamedPropertyCriteria;
import org.picketlink.common.properties.query.PropertyQueries;
import org.picketlink.common.properties.query.TypedPropertyCriteria;
import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.OperationNotSupportedException;
import org.picketlink.idm.internal.ContextualRelationshipManager;
import org.picketlink.idm.internal.RelationshipReference;
import org.picketlink.idm.internal.util.IdentityTypeUtil;
import org.picketlink.idm.model.IdentityType;
import org.picketlink.idm.model.Partition;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.query.QueryParameter;
import org.picketlink.idm.query.RelationshipQuery;
import org.picketlink.idm.spi.AttributeStore;
import org.picketlink.idm.spi.IdentityContext;
import org.picketlink.idm.spi.IdentityStore;
import org.picketlink.idm.spi.StoreSelector;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.picketlink.common.properties.query.TypedPropertyCriteria.MatchOption;
import static org.picketlink.idm.IDMInternalMessages.MESSAGES;
import static org.picketlink.idm.util.IDMUtil.configureDefaultPartition;
/**
* Default IdentityQuery implementation.
*
* @param <T>
*
* @author Shane Bryzak
*/
public class DefaultRelationshipQuery<T extends Relationship> implements RelationshipQuery<T> {
private final ContextualRelationshipManager relationshipManager;
private Map<QueryParameter, Object[]> parameters = new LinkedHashMap<QueryParameter, Object[]>();
private final IdentityContext context;
private final Class<T> relationshipClass;
private int offset;
private int limit;
public DefaultRelationshipQuery(IdentityContext context, Class<T> relationshipClass, ContextualRelationshipManager relationshipManager) {
this.context = context;
this.relationshipClass = relationshipClass;
this.relationshipManager = relationshipManager;
}
@Override
public RelationshipQuery<T> setParameter(QueryParameter param, Object... value) {
parameters.put(param, value);
return this;
}
@Override
public Class<T> getRelationshipClass() {
return relationshipClass;
}
@Override
public Map<QueryParameter, Object[]> getParameters() {
return parameters;
}
@Override
public Object[] getParameter(QueryParameter queryParameter) {
return this.parameters.get(queryParameter);
}
@Override
public int getLimit() {
return limit;
}
@Override
public int getOffset() {
return offset;
}
@Override
public List<T> getResultList() {
List<T> result = new ArrayList<T>();
try {
AttributeStore<?> attributeStore = getStoreSelector().getStoreForAttributeOperation(this.context);
for (IdentityStore<?> store : getStores()) {
List<T> references = store.fetchQueryResults(context, this);
for (T relationship : references) {
List<Property<IdentityType>> identityTypes = PropertyQueries
.<IdentityType>createQuery(relationship.getClass())
.addCriteria(new TypedPropertyCriteria(IdentityType.class, MatchOption.ALL))
.getResultList();
for (Property<IdentityType> identityTypeProperty : identityTypes) {
IdentityType identityType = identityTypeProperty.getValue(relationship);
configureDefaultPartition(this.context, identityType, store, getPartitionManager());
}
if (RelationshipReference.class.isInstance(relationship)) {
RelationshipReference reference = (RelationshipReference) relationship;
resolveIdentityTypes(reference);
relationship = (T) reference.getRelationship();
}
if (attributeStore != null) {
attributeStore.loadAttributes(context, relationship);
}
result.add(relationship);
}
}
} catch (Exception e) {
throw MESSAGES.queryRelationshipFailed(this, e);
}
return result;
}
private PartitionManager getPartitionManager() {
return this.relationshipManager.getPartitionManager();
}
private void resolveIdentityTypes(RelationshipReference reference) {
Relationship relationship = reference.getRelationship();
for (String descriptor : reference.getIdentityTypeReference().keySet()) {
String identifier = reference.getIdentityTypeReference().get(descriptor);
IdentityType identityType = IdentityTypeUtil.resolveIdentityType(identifier, relationship, getPartitionManager());
Property<Object> property = PropertyQueries
.createQuery(relationship.getClass())
.addCriteria(new NamedPropertyCriteria(descriptor))
.getSingleResult();
property.setValue(relationship, identityType);
}
}
@Override
public int getResultCount() {
int count = 0;
try {
for (IdentityStore<?> store : getStores()) {
count += store.countQueryResults(context, this);
}
} catch (Exception e) {
throw MESSAGES.queryRelationshipFailed(this, e);
}
return count;
}
@Override
public RelationshipQuery<T> setOffset(int offset) {
this.offset = offset;
return this;
}
@Override
public RelationshipQuery<T> setLimit(int limit) {
this.limit = limit;
return this;
}
private Set<IdentityStore<?>> getStores() {
Set<Partition> partitions = new HashSet<Partition>();
for (Object param : parameters.values()) {
if (IdentityType.class.isInstance(param)) {
partitions.add(((IdentityType) param).getPartition());
}
}
try {
return getStoreSelector().getStoresForRelationshipQuery(context, relationshipClass, partitions);
} catch (OperationNotSupportedException onse) {
return Collections.EMPTY_SET;
}
}
private StoreSelector getStoreSelector() {
return this.relationshipManager.getStoreSelector();
}
}