/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cxf.jaxrs.ext.search.visitor;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.ext.ParamConverterProvider;
import org.apache.cxf.jaxrs.ext.search.DefaultParamConverterProvider;
import org.apache.cxf.jaxrs.ext.search.PrimitiveStatement;
import org.apache.cxf.jaxrs.ext.search.SearchConditionVisitor;
import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckInfo;
import org.apache.cxf.jaxrs.ext.search.collections.CollectionCheckStatement;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
public abstract class AbstractSearchConditionVisitor <T, E> implements SearchConditionVisitor<T, E> {
private Map<String, String> fieldMap;
private Map<String, Class<?>> primitiveFieldTypeMap;
private PropertyValidator<Object> validator;
private ParamConverterProvider converterProvider;
private boolean wildcardStringMatch;
protected AbstractSearchConditionVisitor(Map<String, String> fieldMap) {
this.fieldMap = fieldMap;
this.converterProvider = new DefaultParamConverterProvider();
}
protected String getRealPropertyName(String name) {
if (fieldMap != null && fieldMap.containsKey(name)) {
return fieldMap.get(name);
}
return name;
}
protected Class<?> getPrimitiveFieldClass(String name, Class<?> valueCls) {
return getPrimitiveFieldClass(name, valueCls, null).getCls();
}
protected ClassValue getPrimitiveFieldClass(String name, Class<?> valueCls, Object value) {
return getPrimitiveFieldClass(null, name, valueCls, valueCls, value);
}
protected ClassValue getPrimitiveFieldClass(PrimitiveStatement ps, String name, Class<?> valueCls,
Type type, Object value) {
return doGetPrimitiveFieldClass(ps, name, valueCls, type, value, new HashSet<>());
}
@SuppressWarnings("rawtypes")
private ClassValue doGetPrimitiveFieldClass(PrimitiveStatement ps,
String name, Class<?> valueCls, Type type, Object value,
Set<String> set) {
boolean isCollection = InjectionUtils.isSupportedCollectionOrArray(valueCls);
Class<?> actualCls = isCollection ? InjectionUtils.getActualType(type) : valueCls;
CollectionCheckInfo collInfo = null;
int index = name.indexOf(".");
if (index != -1) {
String[] names = name.split("\\.");
name = name.substring(index + 1);
if (value != null && !InjectionUtils.isPrimitive(actualCls)) {
try {
String nextPart = names[1];
if (nextPart.length() == 1) {
nextPart = nextPart.toUpperCase();
} else {
nextPart = Character.toUpperCase(nextPart.charAt(0)) + nextPart.substring(1);
}
Method m = actualCls.getMethod("get" + nextPart, new Class[]{});
if (isCollection) {
value = ((Collection)value).iterator().next();
set.add(names[0]);
}
value = m.invoke(value, new Object[]{});
valueCls = value.getClass();
type = m.getGenericReturnType();
} catch (Throwable ex) {
throw new RuntimeException(ex);
}
return doGetPrimitiveFieldClass(ps, name, valueCls, type, value, set);
}
} else if (isCollection) {
set.add(name);
Collection coll = (Collection)value;
value = coll.isEmpty() ? null : coll.iterator().next();
valueCls = actualCls;
if (ps instanceof CollectionCheckStatement) {
collInfo = ((CollectionCheckStatement)ps).getCollectionCheckInfo();
}
}
Class<?> cls = null;
if (primitiveFieldTypeMap != null) {
cls = primitiveFieldTypeMap.get(name);
}
if (cls == null) {
cls = valueCls;
}
return new ClassValue(cls, value, collInfo, set);
}
public void setPrimitiveFieldTypeMap(Map<String, Class<?>> primitiveFieldTypeMap) {
this.primitiveFieldTypeMap = primitiveFieldTypeMap;
}
public SearchConditionVisitor<T, E> visitor() {
return this;
}
protected class ClassValue {
private Class<?> cls;
private Object value;
private CollectionCheckInfo collInfo;
private Set<String> collectionProps;
public ClassValue(Class<?> cls,
Object value,
CollectionCheckInfo collInfo,
Set<String> collectionProps) {
this.cls = cls;
this.value = value;
this.collInfo = collInfo;
this.collectionProps = collectionProps;
}
public Class<?> getCls() {
return cls;
}
public void setCls(Class<?> cls) {
this.cls = cls;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public CollectionCheckInfo getCollectionCheckInfo() {
return collInfo;
}
public boolean isCollection(String name) {
return collectionProps != null && collectionProps.contains(name);
}
}
protected void validatePropertyValue(String name, Object value) {
if (validator != null) {
validator.validate(name, value);
}
}
public void setValidator(PropertyValidator<Object> validator) {
this.validator = validator;
}
public boolean isWildcardStringMatch() {
return wildcardStringMatch;
}
public void setWildcardStringMatch(boolean wildcardStringMatch) {
this.wildcardStringMatch = wildcardStringMatch;
}
public void setFieldTypeConverter(final ParamConverterProvider provider) {
this.converterProvider = provider;
}
public ParamConverterProvider getFieldTypeConverter() {
return converterProvider;
}
}