/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.persistence.proxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.ontopia.utils.OntopiaRuntimeException;
/**
* INTERNAL: Class containing utility methods for processing
* descriptor information.
*/
public class FieldUtils {
//! // Define a logging category.
//! static Logger log = LoggerFactory.getLogger(FieldUtils.class.getName());
/**
* INTERNAL: Returns an array containing the tables in which the
* fields are stored.
*/
public static String[] getTables(FieldInfoIF[] fields) {
Set<String> _tables = new HashSet<String>();
for (FieldInfoIF field : fields) {
_tables.add(field.getTable());
}
String[] tables = new String[_tables.size()];
_tables.toArray(tables);
return tables;
}
/**
* INTERNAL: Returns the names of the value columns that the fields
* span.
*/
public static String[] getColumns(FieldInfoIF[] fields) {
List<String> columns = new ArrayList<String>();
addColumns(fields, columns);
String[] _columns = new String[columns.size()];
columns.toArray(_columns);
return _columns;
}
public static void addColumns(FieldInfoIF field, Collection<String> columns) {
columns.addAll(Arrays.asList(field.getValueColumns()));
}
public static void addColumns(FieldInfoIF[] fields, Collection<String> columns) {
for (FieldInfoIF field : fields) {
columns.addAll(Arrays.asList(field.getValueColumns()));
}
}
/**
* INTERNAL: Returns the number of columns that the fields span.
*/
public static int getColumnCount(FieldInfoIF[] fields) {
int columns = 0;
for (FieldInfoIF field : fields) {
columns += field.getColumnCount();
}
return columns;
}
/**
* INTERNAL: Utility method that creates an int array containing the
* result set index for which the field handler should start
* reading. Note that result set indexes are 1-indexed.
*/
public static int[] getColumnOffsets(FieldHandlerIF[] fhandlers, int start) {
int[] offsets = new int[fhandlers.length];
if (fhandlers.length > 0) {
offsets[0] = start;
for (int i=1; i< fhandlers.length; i++) {
// Offset is last offset plus column count of previous field handler
offsets[i] = offsets[i-1] + fhandlers[i-1].getColumnCount();
}
}
return offsets;
}
/**
* INTERNAL: Utility method that creates an int array containing the
* result set index for which the field handler should start
* reading. Note that result set indexes are 1-indexed.
*/
public static int[] getResultSetOffsets(FieldHandlerIF[] fhandlers) {
return getColumnOffsets(fhandlers, 1);
}
/**
* INTERNAL: Filters the field descriptors by cardinality.
*/
public static FieldDescriptor[] filterByCardinality(FieldDescriptor[] fdescs, int cardinality) {
Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
for (FieldDescriptor fdesc : fdescs) {
if (fdesc.getCardinality() == cardinality)
result.add(fdesc);
}
return toFieldDescriptorArray(result);
}
/**
* INTERNAL: Filters the field infos by cardinality.
*/
public static FieldInfoIF[] filterByCardinality(FieldInfoIF[] finfos, int cardinality) {
Collection<FieldInfoIF> result = new ArrayList<FieldInfoIF>();
for (FieldInfoIF finfo : finfos) {
if (finfo.getCardinality() == cardinality)
result.add(finfo);
}
return toFieldInfoArray(result);
}
/**
* INTERNAL: Filters out all but the aggregate field infos.
*/
public static FieldInfoIF[] filterAggregate(FieldInfoIF[] finfos) {
Collection<FieldInfoIF> result = new ArrayList<FieldInfoIF>();
for (FieldInfoIF finfo : finfos) {
if (finfo.isAggregateField())
result.add(finfo);
}
return toFieldInfoArray(result);
}
/**
* INTERNAL: Returns the field descriptors that are stored in the
* specified table.
*/
public static FieldDescriptor[] filterByTable(FieldDescriptor[] fdescs, String table) {
Collection<FieldDescriptor> result = new ArrayList<FieldDescriptor>();
for (FieldDescriptor fdesc : fdescs) {
if (table.equals(fdesc.getTable()))
result.add(fdesc);
}
return toFieldDescriptorArray(result);
}
/**
* INTERNAL: Returns the getter methods for the given field
* descriptor. This method uses reflection to locate the method.
*/
public static Method getGetterMethod(FieldDescriptor fdesc) throws Exception {
Class<?> object_class = fdesc.getClassDescriptor().getDescriptorClass();
// Getter
String getter_name = fdesc.getGetter();
if (getter_name == null) {
// Create bean getter method name
String fname = fdesc.getName();
getter_name = "get" + fname.substring(0, 1).toUpperCase() + fname.substring(1);
//! throw new OntopiaRuntimeException("Getter method for " + object_class.getName() + "." +
//! fdesc.getName() + " descriptor not specified.");
}
//! if (log.isDebugEnabled())
//! log.debug("Looking up: " + object_class.getName() + "." + getter_name + "()");
try {
// Try declared interfaces
// log.debug("Trying declared interfaces...");
if (fdesc.getClassDescriptor() != null) {
Class<?>[] interfaces = fdesc.getClassDescriptor().getInterfaces();
if (interfaces != null) {
for (Class<?> intf : interfaces) {
try {
//! if (log.isDebugEnabled())
//! log.debug("Trying declared interface: " + interfaces[i]);
return intf.getMethod(getter_name, new Class<?>[0]);
} catch (NoSuchMethodException e2) {
// Ignore
}
}
}
}
return object_class.getMethod(getter_name, new Class<?>[0]);
} catch (NoSuchMethodException e) {
throw new OntopiaRuntimeException("Cannot find getter method for field " + fdesc.getName());
}
}
/**
* INTERNAL: Returns the setter methods for the given field
* descriptor. This method uses reflection to locate the method.
*/
public static Method getSetterMethod(FieldDescriptor fdesc) throws Exception {
Class<?> object_class = fdesc.getClassDescriptor().getDescriptorClass();
Class<?> value_class;
if (fdesc.isOneToOne()) {
value_class = fdesc.getValueClass();
} else {
value_class = fdesc.getCollectionClass();
}
String setter_name = fdesc.getSetter();
if (setter_name == null)
throw new OntopiaRuntimeException("Setter method for " + object_class.getName() + "."
+ fdesc.getName() + " descriptor not specified.");
//! if (log.isDebugEnabled())
//! log.debug("Looking up: " + object_class.getName() + "." + setter_name + "(" + value_class + ")");
if (fdesc.isPrimitiveField()) {
try {
// First try the primitive wrapper class
return object_class.getMethod(setter_name, new Class<?>[] {value_class});
} catch (NoSuchMethodException e) {
// Ignore
}
try {
// Then try the actual primitive class
return object_class.getMethod(setter_name, new Class<?>[] {getPrimitiveClass(value_class)});
} catch (NoSuchMethodException e) {
// Ignore
}
}
else {
try {
// Try declared interfaces
// log.debug("Trying declared interfaces...");
if (fdesc.getValueClassDescriptor() != null) {
Class[] interfaces = fdesc.getValueClassDescriptor().getInterfaces();
if (interfaces != null) {
for (Class<?> intf : interfaces) {
try {
//! if (log.isDebugEnabled())
//! log.debug("Trying declared interface: " + interfaces[i]);
return object_class.getMethod(setter_name, new Class<?>[]{intf});
} catch (NoSuchMethodException e2) {
// Ignore
}
}
}
}
return object_class.getMethod(setter_name, new Class<?>[] {value_class});
} catch (NoSuchMethodException e) {
// Try interfaces
// log.debug("Trying interfaces...");
Class[] interfaces = getImplementedInterfaces(value_class);
for (Class<?> intf : interfaces) {
try {
//! if (log.isDebugEnabled())
//! log.debug("Trying interface: " + interfaces[i]);
return object_class.getMethod(setter_name, new Class<?>[]{intf});
} catch (NoSuchMethodException e2) {
// Ignore
}
}
}
}
throw new OntopiaRuntimeException("Cannot find setter method for field " + fdesc.getName());
}
/**
* INTERNAL: Returns the primitive class for the specified primitive
* wrapper class.
*/
public static Class<?> getPrimitiveClass(Class<?> klass) {
// Note: Only primitive wrapper classes are expected as argument.
if (klass.equals(String.class))
return klass;
else if (klass.equals(Long.class))
return Long.TYPE;
else if (klass.equals(Integer.class))
return Integer.TYPE;
else if (klass.equals(Float.class))
return Float.TYPE;
else
throw new OntopiaRuntimeException("Unsupported primitive wrapper class " + klass);
}
/**
* INTERNAL: Returns all interfaces implemented by this class and
* its superclasses.
*/
public static Class[] getImplementedInterfaces(Class<?> klass) {
Set<Class<?>> result = new HashSet<Class<?>>();
accumulateImplementedInterfaces(klass, result);
Class<?>[] interfaces = new Class<?>[result.size()];
result.toArray(interfaces);
return interfaces;
}
/**
* INTERNAL: Accumulates the interfaces implemented by this class
* and its superclasses. All recognized interfaces are added to the
* result argument collection.
*/
protected static void accumulateImplementedInterfaces(Class<?> klass, Set<Class<?>> result) {
// Interfaces
Class[] _interfaces = klass.getInterfaces();
for (Class<?> _interface : _interfaces) {
accumulateImplementedInterfaces(_interface, result);
result.add(_interface);
}
// Superclasses
Class<?> _superclass = klass.getSuperclass();
if (_superclass != null)
accumulateImplementedInterfaces(_superclass, result);
}
/**
* INTERNAL: Joins the two String arrays by producing a new composite
* string array.
*/
public static String[] joinStrings(String[] a, String[] b) {
String[] result = new String[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
/**
* INTERNAL: Joins the two FieldInfoIF arrays by producing a new
* composite string array.
*/
public static FieldInfoIF[] joinFieldInfos(FieldInfoIF[] a, FieldInfoIF[] b) {
FieldInfoIF[] result = new FieldInfoIF[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
/**
* INTERNAL: Utility method that converts a collection of strings to
* an array of strings.
*/
public static String[] toStringArray(Collection<String> strings) {
String[] _strings = new String[strings.size()];
strings.toArray(_strings);
return _strings;
}
/**
* INTERNAL: Utility method that converts a collection of field
* descriptors to an array of field descriptors.
*/
public static FieldDescriptor[] toFieldDescriptorArray(Collection<FieldDescriptor> fdescs) {
FieldDescriptor[] _fdescs = new FieldDescriptor[fdescs.size()];
fdescs.toArray(_fdescs);
return _fdescs;
}
/**
* INTERNAL: Utility method that converts a collection of field
* infos to an array of field infos.
*/
public static FieldInfoIF[] toFieldInfoArray(Collection<FieldInfoIF> finfos) {
FieldInfoIF[] _finfos = new FieldInfoIF[finfos.size()];
finfos.toArray(_finfos);
return _finfos;
}
/**
* INTERNAL: Utility method that extracts the field names of an
* array of field descriptors.
*/
public static String[] getFieldNames(FieldDescriptor[] fields) {
String[] names = new String[fields.length];
for (int i=0; i < fields.length; i++) {
names[i] = fields[i].getName();
}
return names;
}
}