001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kim.impl.common.attribute; 017 018import com.google.common.collect.Iterables; 019import org.kuali.rice.core.api.criteria.AndPredicate; 020import org.kuali.rice.core.api.criteria.CompositePredicate; 021import org.kuali.rice.core.api.criteria.CriteriaValue; 022import org.kuali.rice.core.api.criteria.MultiValuedPredicate; 023import org.kuali.rice.core.api.criteria.OrPredicate; 024import org.kuali.rice.core.api.criteria.Predicate; 025import org.kuali.rice.core.api.criteria.PropertyPathPredicate; 026import org.kuali.rice.core.api.criteria.QueryByCriteria; 027import org.kuali.rice.core.api.criteria.SingleValuedPredicate; 028import org.kuali.rice.core.api.criteria.Transform; 029 030import java.util.ArrayList; 031import java.util.HashSet; 032import java.util.List; 033import java.util.Set; 034import java.util.regex.Matcher; 035import java.util.regex.Pattern; 036 037import static org.kuali.rice.core.api.criteria.PredicateFactory.*; 038 039/** 040 * this is an internal class used by kim service implementations that have generic lookup methods for classes 041 * with "attributes". 042 */ 043public final class AttributeTransform implements Transform<QueryByCriteria, QueryByCriteria> { 044 045 private static final Transform<QueryByCriteria, QueryByCriteria> INSTANCE = new AttributeTransform(); 046 private static final String ATTRIBUTE_DETAILS_ATTRIBUTE_VALUE = "attributeDetails.attributeValue"; 047 private static final String ATTRIBUTE_DETAILS_ATTRIBUTE_NAME = "attributeDetails.kimAttribute.attributeName"; 048 private static final String ATTRIBUTES_REGEX = "^attributes\\[\\w*\\]$"; 049 private static final Pattern ATTRIBUTES_PATTERN = Pattern.compile(ATTRIBUTES_REGEX); 050 051 private AttributeTransform() { 052 053 } 054 055 @Override 056 public QueryByCriteria apply(final QueryByCriteria input) { 057 QueryByCriteria.Builder builder = QueryByCriteria.Builder.create(input); 058 builder.setPredicates(applyPredicate(input.getPredicate())); 059 return builder.build(); 060 } 061 062 private Predicate applyPredicate(final Predicate input) { 063 if (input instanceof PropertyPathPredicate) { 064 String pp = ((PropertyPathPredicate) input).getPropertyPath(); 065 if (isAttributesPredicate(pp)) { 066 final String attributeName = pp.substring(pp.indexOf('[') + 1, pp.indexOf(']')); 067 068 final Predicate attrValue; 069 if (input instanceof SingleValuedPredicate) { 070 final CriteriaValue<?> value = ((SingleValuedPredicate) input).getValue(); 071 attrValue = dynConstruct(input.getClass().getSimpleName(), ATTRIBUTE_DETAILS_ATTRIBUTE_VALUE, value.getValue()); 072 } else if (input instanceof MultiValuedPredicate) { 073 final Set<? extends CriteriaValue<?>> values = ((MultiValuedPredicate) input).getValues(); 074 List<Object> l = new ArrayList<Object>(); 075 for (CriteriaValue<?> v : values) { 076 l.add(v.getValue()); 077 } 078 079 attrValue = dynConstruct(input.getClass().getSimpleName(), ATTRIBUTE_DETAILS_ATTRIBUTE_VALUE, l.toArray()); 080 } else { 081 attrValue = dynConstruct(input.getClass().getSimpleName(), ATTRIBUTE_DETAILS_ATTRIBUTE_VALUE); 082 } 083 return and(equal(ATTRIBUTE_DETAILS_ATTRIBUTE_NAME, attributeName), attrValue); 084 } 085 } else if (input instanceof CompositePredicate) { 086 return applyCompositePredicate((CompositePredicate) input); 087 } 088 089 return input; 090 } 091 092 private Predicate applyCompositePredicate(final CompositePredicate input) { 093 Set<Predicate> appliedPredicates = new HashSet<Predicate>(); 094 095 for (Predicate predicate : input.getPredicates()) { 096 appliedPredicates.add(applyPredicate(predicate)); 097 } 098 099 Predicate[] appliedPredicatesArray = Iterables.toArray(appliedPredicates, Predicate.class); 100 101 if (input instanceof AndPredicate) { 102 return and(appliedPredicatesArray); 103 } else if (input instanceof OrPredicate) { 104 return or(appliedPredicatesArray); 105 } 106 107 return input; 108 } 109 110 private boolean isAttributesPredicate(String pp) { 111 Matcher matcher = ATTRIBUTES_PATTERN.matcher(pp); 112 return matcher.matches(); 113 } 114 115 public static Transform<QueryByCriteria, QueryByCriteria> getInstance() { 116 return INSTANCE; 117 } 118}