/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* 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.constellation.util;
import org.apache.sis.util.logging.Logging;
import org.geotoolkit.util.StringUtilities;
import org.opengis.annotation.UML;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Guilhem Legal (Geomatys)
*/
public final class ReflectionUtilities {
private static final Logger LOGGER = Logging.getLogger("org.constellation.util");
private static final String INCLASS = " in the class ";
/**
* A map of getters to avoid to search the same getters many times.
*/
private static final Map<String, Method> GETTERS = new HashMap<>();
private ReflectionUtilities() {}
/**
* Call the empty constructor on the specified class and return the result,
* handling most errors which could be expected by logging the cause and
* returning {@code null}.
*
* @param classe An arbitrary class, expected to be instantiable with a
* {@code null} argument constructor.
* @return The instantiated instance of the given class, or {@code null}.
*/
public static Object newInstance(final Class<?> classe) {
try {
if (classe == null) {
return null;
}
final Constructor<?> constructor = classe.getDeclaredConstructor();
constructor.setAccessible(true);
//we execute the constructor
return constructor.newInstance();
} catch (InstantiationException ex) {
LOGGER.log(Level.WARNING, "Unable to instantiate the class: {0}()", classe.getName());
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "Unable to access the constructor in class: {0}", classe.getName());
} catch (IllegalArgumentException ex) {//TODO: this cannot possibly happen.
LOGGER.log(Level.WARNING, "Illegal Argument in empty constructor for class: {0}", classe.getName());
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Invocation Target Exception in empty constructor for class: {0}" + classe.getName(), ex);
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "There is no empty constructor for class: {0}", classe.getName());
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, "Security exception while instantiating class: {0}", classe.getName());
}
return null;
}
/**
* Call the empty constructor on the specified class and return the result,
* handling most errors which could be expected by logging the cause and
* returning {@code null}.
*
* @param classe An arbitrary class, expected to be instantiable with a
* {@code null} argument constructor.
* @return The instantiated instance of the given class, or {@code null}.
*/
public static Object newInstance(final Class<?> classe, final Object... parameters) {
try {
if (classe == null) {
return null;
}
final Constructor<?> constructor;
if (parameters != null && parameters.length > 1) {
final Class[] parametersTypes = new Class[parameters.length];
for (int i = 0; i < parameters.length; i++) {
parametersTypes[i] = parameters[i].getClass();
}
constructor = classe.getConstructor(parametersTypes);
} else {
constructor = classe.getConstructor();
}
constructor.setAccessible(true);
//we execute the constructor
return constructor.newInstance(parameters);
} catch (InstantiationException ex) {
LOGGER.log(Level.WARNING, "Unable to instantiate the class: {0}()", classe.getName());
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "Unable to access the constructor in class: {0}", classe.getName());
} catch (IllegalArgumentException ex) {//TODO: this cannot possibly happen.
LOGGER.log(Level.WARNING, "Illegal Argument in constructor for class: {0}", classe.getName());
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Invocation Target Exception in empty constructor for class: "+ classe.getName(), ex);
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "There is no such constructor for class: {0}", classe.getName());
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, "Security exception while instantiating class: {0}", classe.getName());
}
return null;
}
/**
* Call the constructor which uses a {@code String} parameter for the given
* class and return the result, handling most errors which could be expected
* by logging the cause and returning {@code null}.
*
* @param classe An arbitrary class, expected to be instantiable with a
* single {@code String} argument.
* @param parameter The {@code String} to use as an argument to the
* constructor.
* @return The instantiated instance of the given class, or {@code null}.
*/
public static Object newInstance(final Class<?> classe, final String parameter) {
try {
if (classe == null) {
return null;
}
final Constructor<?> constructor = classe.getConstructor(String.class);
//we execute the constructor
return constructor.newInstance(parameter);
} catch (InstantiationException ex) {
LOGGER.log(Level.WARNING, "Unable to instantiate the class: {0}(string)", classe.getName());
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "Unable to access the constructor in class: {0}", classe.getName());
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Illegal Argument in string constructor for class: {0}", classe.getName());
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Invocation target exception in string constructor for class: " + classe.getName() + " for parameter: " + parameter, ex);
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "No single string constructor in class: {0}", classe.getName());
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, "Security exception while instantiating class: {0}", classe.getName());
}
return null;
}
/**
* Call the constructor which uses two {@code String} parameters for the
* given class and return the result, handling most errors which could be
* expected by logging the cause and returning {@code null}.
*
* @param classe An arbitrary class, expected to be instantiable with a
* single {@code String} argument.
* @param parameter1 The first {@code String} to use as an argument to the
* constructor.
* @param parameter2 The second {@code String} to use as an argument to the
* constructor.
* @return The instantiated instance of the given class, or {@code null}.
*/
public static Object newInstance(final Class<?> classe, final String parameter1, final String parameter2) {
try {
if (classe == null) {return null;}
final Constructor<?> constructor = classe.getConstructor(String.class, String.class);
//we execute the constructor
return constructor.newInstance(parameter1, parameter2);
} catch (InstantiationException ex) {
LOGGER.log(Level.WARNING, "The service can't instantiate the class: {0}(string, string)", classe.getName());
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "The service can not access the constructor in class: {0}", classe.getName());
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Illegal Argument in double string constructor for class: {0}", classe.getName());
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Invocation target exception in double string constructor for class: {0}", classe.getName());
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "No double string constructor in class: {0}", classe.getName());
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, "Security exception while instantiating class: {0}", classe.getName());
}
return null;
}
/**
* Call the constructor which uses a character sequence parameter for the
* given class and return the result, handling most errors which could be
* expected by logging the cause and returning {@code null}.
*
* @param classe An arbitrary class, expected to be instantiable with a
* single {@code String} argument.
* @param parameter The character sequence to use as an argument to the
* constructor.
* @return The instantiated instance of the given class, or {@code null}.
*/
public static Object newInstance(final Class<?> classe, final CharSequence parameter) {
try {
if (classe == null) {return null;}
final Constructor<?> constructor = classe.getConstructor(CharSequence.class);
//we execute the constructor
return constructor.newInstance(parameter);
} catch (InstantiationException ex) {
LOGGER.log(Level.WARNING, "The service can''t instantiate the class: {0}(CharSequence)", classe.getName());
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "The service can not access the constructor in class: {0}", classe.getName());
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Illegal Argument in CharSequence constructor for class: {0}", classe.getName());
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Invocation target exception in CharSequence constructor for class: {0}", classe.getName());
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "No such CharSequence constructor in class: {0}", classe.getName());
} catch (SecurityException ex) {
LOGGER.log(Level.WARNING, "Security exception while instantiating class: {0}", classe.getName());
}
return null;
}
/**
* Invoke the given method on the specified object, handling most errors
* which could be expected by logging the cause and returning {@code null}.
*
* <p>
* TODO: what happens if the method returns {@code void}?
* </p>
*
* @param object The object on which the method will be invoked.
* @param method The method to invoke.
* @return The {@code Object} generated by the method call, or, if the
* method call resulted in a primitive, the auto-boxing
* equivalent, or {@code null}.
*/
public static Object invokeMethod(final Object object, final Method method) {
Object result = null;
final String baseMessage = "Unable to invoke the method " + method + ": ";
try {
if (method != null) {
result = method.invoke(object);
} else {
LOGGER.log(Level.WARNING, "{0}the method reference is null.", baseMessage);
}
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "{0}the class is not accessible.", baseMessage);
} catch (IllegalArgumentException ex) {//TODO: this cannot happen
LOGGER.log(Level.WARNING, "{0}the argument does not match with the method.", baseMessage);
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, baseMessage + "an Exception was thrown by the invoked method.", ex);
}
return result;
}
/**
* Invoke a method with the specified parameter on the specified object,
* handling most errors which could be expected by logging the cause and
* returning {@code null}.
*
* <p>
* TODO: what happens if the method returns {@code void}?
* </p>
*
* @param object The object on which the method will be invoked.
* @param method The method to invoke.
* @param parameter The parameter of the method.
* @return The {@code Object} generated by the method call, or, if the
* method call resulted in a primitive, the auto-boxing
* equivalent, or {@code null}.
*/
public static Object invokeMethod(final Method method, final Object object, final Object... parameter) {
Object result = null;
final String baseMessage = "Unable to invoke the method " + method + ": ";
try {
if (method != null) {
if (parameter.length == 1) {
result = method.invoke(object, parameter[0]);
} else {
result = method.invoke(object, parameter);
}
} else {
LOGGER.log(Level.WARNING, "{0}the method reference is null.", baseMessage);
}
} catch (IllegalAccessException ex) {
LOGGER.log(Level.WARNING, "{0}the class is not accessible.", baseMessage);
} catch (IllegalArgumentException ex) {
String param = "null";
if (parameter != null) {
param = parameter.getClass().getSimpleName();
}
LOGGER.warning(baseMessage + "the given argument does not match that required by the method.( argument type was " + param + ")" + '\n' +
"cause:" + ex.getMessage());
} catch (InvocationTargetException ex) {
String errorMsg = ex.getMessage();
if (errorMsg == null && ex.getCause() != null) {
errorMsg = ex.getCause().getMessage();
}
if (errorMsg == null && ex.getTargetException() != null) {
errorMsg = ex.getTargetException().getMessage();
}
LOGGER.log(Level.WARNING, baseMessage + "an Exception was thrown in the invoked method:" + errorMsg, ex);
}
return result;
}
/**
* Invoke a method with the specified parameter on the specified object,
* the errors are throws (not like the method invokeMethod(...).
*
*
* @param object The object on which the method will be invoked.
* @param method The method to invoke.
* @param parameter The parameter of the method.
* @return The {@code Object} generated by the method call, or, if the
* method call resulted in a primitive, the auto-boxing
* equivalent, or {@code null}.
*/
public static Object invokeMethodEx(final Method method, final Object object, final Object parameter) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Object result = null;
if (method != null) {
result = method.invoke(object, parameter);
} else {
LOGGER.warning("Unable to invoke the method reference is null.");
}
return result;
}
/**
* Return a setter Method for the specified attribute (propertyName) of the type "classe"
* in the class rootClass.
*
* @param propertyName The attribute name.
* @param classe The attribute type.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getMethod(final String propertyName, final Class<?> classe) {
Method method = null;
try {
method = classe.getMethod(propertyName);
} catch (IllegalArgumentException ex) {
LOGGER.warning("illegal argument exception while invoking the method " + propertyName + INCLASS + classe.getName());
} catch (NoSuchMethodException ex) {
LOGGER.warning("The method " + propertyName + " does not exists in the classe " + classe.getName());
} catch (SecurityException ex) {
LOGGER.warning("Security exception while getting the method " + propertyName + INCLASS + classe.getName());
}
return method;
}
/**
* Return a setter Method for the specified attribute (propertyName) of the type "classe"
* in the class rootClass.
*
* @param propertyName The attribute name.
* @param classe The attribute type.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getMethod(final String propertyName, final Class<?> classe, final Class<?> parameterClass) {
Method method = null;
try {
method = classe.getMethod(propertyName, parameterClass);
} catch (IllegalArgumentException ex) {
LOGGER.warning("illegal argument exception while invoking the method " + propertyName + INCLASS + classe.getName());
} catch (NoSuchMethodException ex) {
LOGGER.warning("The method " + propertyName + " does not exists in the classe " + classe.getName());
} catch (SecurityException ex) {
LOGGER.warning("Security exception while getting the method " + propertyName + INCLASS + classe.getName());
}
return method;
}
/**
* Return a setter Method for the specified attribute (propertyName) of the type "classe"
* in the class rootClass.
*
* @param propertyName The attribute name.
* @param classe The attribute type.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getMethod(final String propertyName, final Class<?> classe, final Class<?>... parameterClass) {
Method method = null;
try {
method = classe.getMethod(propertyName, parameterClass);
} catch (IllegalArgumentException ex) {
LOGGER.warning("illegal argument exception while invoking the method " + propertyName + INCLASS + classe.getName());
} catch (NoSuchMethodException ex) {
LOGGER.warning("The method " + propertyName + " does not exists in the classe " + classe.getName());
} catch (SecurityException ex) {
LOGGER.warning("Security exception while getting the method " + propertyName + INCLASS + classe.getName());
}
return method;
}
/**
* Return a getter Method for the specified attribute (propertyName)
*
* @param propertyName The attribute name.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getGetterFromName(String propertyName, final Class<?> rootClass) {
Method getter = getGetterFromAnnotation(propertyName, rootClass);
if (getter != null) {return getter;}
final String rootClassName = rootClass.getName();
//special case and corrections TODO remove
if ("beginPosition".equals(propertyName) && !"org.geotoolkit.gml.xml.v311.TimePeriodType".equals(rootClassName)) {
propertyName = "beginning";
} else if ("endPosition".equals(propertyName) && !"org.geotoolkit.gml.xml.v311.TimePeriodType".equals(rootClassName)) {
propertyName = "ending";
} else if (propertyName.indexOf("geographicElement") != -1) {
propertyName = "geographicElements";
} else if ("value".equals(propertyName) && ("org.geotoolkit.temporal.object.DefaultPosition".equals(rootClassName))) {
propertyName = "date";
}
final String methodName = "get" + StringUtilities.firstToUpper(propertyName);
final String methodName2 = "is" + StringUtilities.firstToUpper(propertyName);
final String methodName3 = propertyName;
int occurenceType = 0;
while (occurenceType < 3) {
try {
switch (occurenceType) {
case 0: {
getter = rootClass.getMethod(methodName);
break;
}
case 1: {
getter = rootClass.getMethod(methodName2);
break;
}
case 2: {
getter = rootClass.getMethod(methodName3);
break;
}
default: break;
}
return getter;
} catch (NoSuchMethodException e) {
occurenceType++;
}
}
// look for private method
if (getter == null) {
Class superC = rootClass;
while (superC != null) {
try { getter = superC.getDeclaredMethod(methodName);} catch (NoSuchMethodException ex) {}
if (getter == null) {
superC = superC.getSuperclass();
} else {
getter.setAccessible(true);
break;
}
}
}
return getter;
}
/**
* Return a getter Method by looking the annotation on the method of the specified class.
* first it look the {@link XmlElement} name otherwise he search for the GeoAPI interface
* and look th {@link UML} identifier.
*
* @param propertyName The attribute name.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getGetterFromAnnotation(final String propertyName, final Class<?> rootClass) {
for (Method method : rootClass.getMethods()) {
final XmlElement annotation = method.getAnnotation(XmlElement.class);
if (annotation != null && annotation.name().equals(propertyName)) {
return method;
}
}
final Class[] interfaces = rootClass.getInterfaces();
for (Class interf : interfaces) {
if (interf.getName().startsWith("org.opengis")) {
for (Method method : interf.getMethods()) {
final UML annotation = method.getAnnotation(UML.class);
if (annotation != null && annotation.identifier().equals(propertyName)) {
return method;
}
}
}
}
return null;
}
/**
* Return a setter Method for the specified attribute (propertyName) of the type "paramClass"
* in the class rootClass.
*
* @param propertyName The attribute name.
* @param classe The attribute type.
* @param rootClass The class which owe this attribute
*
* @return a setter to this attribute or {@code null}.
*/
public static Method getSetterFromName(String propertyName, final Class<?> paramClass, final Class<?> rootClass) {
LOGGER.finer("search for a setter in " + rootClass.getName() + " of type :" + paramClass.getName());
if ("dataSetURI".equals(propertyName)) {
propertyName = "dataSetUri";
}
final String methodName = "set" + StringUtilities.firstToUpper(propertyName);
int occurenceType = 0;
//TODO look all interfaces
Class<?> interfacee = null;
if (paramClass.getInterfaces().length != 0) {
interfacee = paramClass.getInterfaces()[0];
}
Class<?> argumentSuperClass = paramClass;
Class<?> argumentSuperInterface = null;
if (argumentSuperClass.getInterfaces().length > 0) {
argumentSuperInterface = argumentSuperClass.getInterfaces()[0];
}
while (occurenceType < 7) {
try {
Method setter = null;
switch (occurenceType) {
case 0: {
setter = rootClass.getMethod(methodName, paramClass);
break;
}
case 1: {
if (paramClass.equals(Integer.class)) {
setter = rootClass.getMethod(methodName, long.class);
break;
} else {
occurenceType = 2;
}
}
case 2: {
setter = rootClass.getMethod(methodName, interfacee);
break;
}
case 3: {
setter = rootClass.getMethod(methodName, Collection.class);
break;
}
case 4: {
setter = rootClass.getMethod(methodName + "s", Collection.class);
break;
}
case 5: {
setter = rootClass.getMethod(methodName , argumentSuperClass);
break;
}
case 6: {
setter = rootClass.getMethod(methodName , argumentSuperInterface);
break;
}
default: break;
}
return setter;
} catch (NoSuchMethodException e) {
final String msg = "The setter ";
/**
* This switch is for debugging purpose
*/
switch (occurenceType) {
case 0: {
LOGGER.finer(msg + methodName + "(" + paramClass.getName() + ") does not exist");
occurenceType = 1;
break;
}
case 1: {
LOGGER.finer(msg + methodName + "(long) does not exist");
occurenceType = 2;
break;
}
case 2: {
if (interfacee != null) {
LOGGER.finer(msg + methodName + "(" + interfacee.getName() + ") does not exist");
}
occurenceType = 3;
break;
}
case 3: {
LOGGER.finer(msg + methodName + "(Collection<" + paramClass.getName() + ">) does not exist");
occurenceType = 4;
break;
}
case 4: {
LOGGER.finer(msg + methodName + "s(Collection<" + paramClass.getName() + ">) does not exist");
occurenceType = 5;
break;
}
case 5: {
if (argumentSuperClass != null) {
LOGGER.finer(msg + methodName + "(" + argumentSuperClass.getName() + ") does not exist");
argumentSuperClass = argumentSuperClass.getSuperclass();
occurenceType = 5;
} else {
occurenceType = 6;
}
break;
}
case 6: {
if (argumentSuperInterface != null) {
LOGGER.finer(msg + methodName + "(" + argumentSuperInterface.getName() + ") does not exist");
}
occurenceType = 7;
break;
}
default:
occurenceType = 7;
}
}
}
return null;
}
/**
* Return a java field from the specified class(or any of its super class)
* or {@code null} if it does not exist.
*
* @param attribName
* @param classe
* @return
*/
public static Field getFieldFromName(String attribName, Class classe) {
Field field = null;
Class tempClasse = classe;
while (field == null && tempClasse != null) {
try {
field = tempClasse.getDeclaredField(attribName);
} catch (NoSuchFieldException ex) {
field = null;
}
tempClasse = tempClasse.getSuperclass();
}
return field;
}
/**
* Return an object value extract from the specified object by using the string path specified.
* example : getValuesFromPath("ISO 19115:MD_Metadata:identificationInfo:citation:title", (MetatadataImpl) obj)
* will execute obj.getIdentificationInfo().getTitle() and return the result.
*
* @param pathID A String path using MDWeb pattern.
* @param metadata An Object.
* @return A Object value.
*/
public static Object getValuesFromPath(String pathID, Object metadata) {
Object result = null;
if (pathMatchObjectType(metadata, pathID)) {
/*
* we remove the prefix path part the path always start with STANDARD:TYPE:
*/
pathID = pathID.substring(pathID.indexOf(':') + 1);
pathID = pathID.substring(pathID.indexOf(':') + 1);
//for each part of the path we execute a (many) getter
while (!pathID.isEmpty()) {
//we extract the current attributeName
String attributeName;
if (pathID.indexOf(':') != -1) {
attributeName = pathID.substring(0, pathID.indexOf(':'));
pathID = pathID.substring(pathID.indexOf(':') + 1);
} else {
attributeName = pathID;
pathID = "";
}
if (metadata instanceof Collection) {
final List<Object> tmp = new ArrayList<>();
for (Object subMeta: (Collection) metadata) {
final Object obj = getAttributeValue(subMeta, attributeName);
if (obj instanceof Collection) {
for (Object o : (Collection)obj) {
if (o != null) {tmp.add(o);}
}
} else {
if (obj != null) {tmp.add(obj);}
}
}
metadata = tmp;
} else {
metadata = getAttributeValue(metadata, attributeName);
}
}
result = metadata;
}
return result;
}
/**
* Return true if the path is applicable to the specified metadata type.
*
* @param metadata A metadata object.
* @param pathID A path on the form Standard:Type:attribute1:attribute2
*
* @return True if the specified path starts with the type of the metadata
*/
public static boolean pathMatchObjectType(Object metadata, String pathID) {
if (metadata == null) {return false;}
return (pathID.startsWith("ISO 19115:MD_Metadata") && "DefaultMetadata".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("ISO 19115-2:MI_Metadata") && "MI_Metadata".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("ISO 19115:CI_ResponsibleParty") && "DefaultResponsibleParty".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("Catalog Web Service:Record") && "RecordType".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("ISO 19110:FC_FeatureCatalogue") && "FeatureCatalogueImpl".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("SensorML:SensorML") && "SensorML".equals(metadata.getClass().getSimpleName())) ||
(pathID.startsWith("Ebrim v2.5:*") && metadata.getClass().getName().startsWith("org.geotoolkit.ebrim.xml.v250")||
(pathID.startsWith("Ebrim v3.0:*") && metadata.getClass().getName().startsWith("org.geotoolkit.ebrim.xml.v300")));
}
/**
* Call a get method on the specified object named get'AttributeName'() and return the result.
* This method handle the attributeName on the form "attributeName[i]" when you want a specific values in a collection.
*
* @param object An object.
* @param attributeName The name of the attribute that you want the value.
* @return
*/
public static Object getAttributeValue(Object object, String attributeName) {
Object result = null;
int ordinal = -1;
if (attributeName.indexOf('[') != -1){
final String tmp = attributeName.substring(attributeName.indexOf('[') + 1, attributeName.length() - 1);
attributeName = attributeName.substring(0, attributeName.indexOf('['));
try {
ordinal = Integer.parseInt(tmp);
} catch (NumberFormatException ex) {
LOGGER.log(Level.WARNING, "Unable to parse the ordinal {0}", tmp);
}
}
if (object != null) {
if (object instanceof JAXBElement) {
object = ((JAXBElement)object).getValue();
}
final String getterId = object.getClass().getName() + ':' + attributeName;
Method getter = GETTERS.get(getterId);
if (getter != null) {
result = invokeMethod(object, getter);
} else {
if (attributeName.equalsIgnoreCase("referenceSystemIdentifier")) {
attributeName = "name";
}
getter = getGetterFromName(attributeName, object.getClass());
if (getter != null) {
GETTERS.put(object.getClass().getName() + ':' + attributeName, getter);
result = invokeMethod(object, getter);
} else {
LOGGER.finer("No getter have been found for attribute " + attributeName + " in the class " + object.getClass().getName());
}
}
}
if (result instanceof JAXBElement) {
result = ((JAXBElement)result).getValue();
}
if (ordinal != -1 && result instanceof Collection) {
final Collection c = (Collection) result;
final Iterator t = c.iterator();
int i = 0;
while (t.hasNext()) {
result = t.next();
if (i == ordinal) {return result;}
i++;
}
}
return result;
}
/**
*
* @param pathID
* @param conditionalAttribute
* @param conditionalValue
* @param metadata
* @return
*/
public static Object getConditionalValuesFromPath(String pathID, String conditionalAttribute, String conditionalValue, Object metadata) {
Object result = null;
if (ReflectionUtilities.pathMatchObjectType(metadata, pathID)) {
/*
* we remove the prefix path part the path always start with STANDARD:TYPE:
*/
pathID = pathID.substring(pathID.indexOf(':') + 1);
pathID = pathID.substring(pathID.indexOf(':') + 1);
//for each part of the path we execute a (many) getter
while (!pathID.isEmpty()) {
//we extract the current attributeName
String attributeName;
if (pathID.indexOf(':') != -1) {
attributeName = pathID.substring(0, pathID.indexOf(':'));
pathID = pathID.substring(pathID.indexOf(':') + 1);
} else {
attributeName = pathID;
pathID = "";
}
if (metadata instanceof Collection) {
final List<Object> tmp = new ArrayList<>();
if (pathID.isEmpty()) {
for (Object subMeta: (Collection)metadata) {
if (matchCondition(subMeta, conditionalAttribute, conditionalValue)) {
tmp.add(ReflectionUtilities.getAttributeValue(subMeta, attributeName));
}
}
} else {
for (Object subMeta: (Collection)metadata) {
final Object obj = ReflectionUtilities.getAttributeValue(subMeta, attributeName);
if (obj instanceof Collection) {
for (Object o : (Collection)obj) {
if (o != null) {tmp.add(o);}
}
} else {
if (obj != null) {tmp.add(obj);}
}
}
}
if (tmp.size() == 1) {
metadata = tmp.get(0);
} else {
metadata = tmp;
}
} else {
if (pathID.isEmpty()) {
if (matchCondition(metadata, conditionalAttribute, conditionalValue)) {
metadata = ReflectionUtilities.getAttributeValue(metadata, attributeName);
} else {
metadata = null;
}
} else {
metadata = ReflectionUtilities.getAttributeValue(metadata, attributeName);
}
}
}
result = metadata;
}
return result;
}
/**
*
* @param metadata
* @param conditionalAttribute
* @param conditionalValue
* @return
*/
private static boolean matchCondition(Object metadata, String conditionalAttribute, String conditionalValue) {
final Object conditionalObj = ReflectionUtilities.getAttributeValue(metadata, conditionalAttribute);
final String attributValue;
if (conditionalObj instanceof org.opengis.util.CodeList) {
attributValue = ((org.opengis.util.CodeList)conditionalObj).name();
} else if (conditionalObj != null) {
attributValue = conditionalObj.toString();
} else {
attributValue = "null";
}
final boolean result;
// if we a have a pattern matching
if (conditionalValue.contains("[")) {
result = attributValue.matches(conditionalValue);
} else {
result = conditionalValue.equalsIgnoreCase(attributValue);
}
LOGGER.finer("contionalObj: " + attributValue +
"\nconditionalValue: " + conditionalValue +
"\nmatch? " + result);
return result;
}
/**
* Return true if the specified class or on of its superClass is equals to the specified name.
*
* @param fullClassName
* @param c
* @return
*/
public static boolean instanceOf(final String fullClassName, Class c) {
if (c != null) {
Class currentClass = c;
do {
if (currentClass.getName().equals(fullClassName)) {
return true;
}
currentClass = currentClass.getSuperclass();
} while (currentClass != null);
}
return false;
}
/**
*
* @param enumeration
* @return
*/
public static String getElementNameFromEnum(final Object enumeration) {
String value = "";
try {
final Method getValue = enumeration.getClass().getDeclaredMethod("value");
value = (String) getValue.invoke(enumeration);
} catch (IllegalAccessException ex) {
LOGGER.warning("The class is not accessible");
} catch (IllegalArgumentException ex) {
LOGGER.warning("IllegalArgument exeption in value()");
} catch (InvocationTargetException ex) {
LOGGER.log(Level.WARNING, "Exception throw in the invokated getter value() \nCause: {0}", ex.getMessage());
} catch (NoSuchMethodException ex) {
LOGGER.log(Level.WARNING, "no such method value() in {0}", enumeration.getClass().getSimpleName());
} catch (SecurityException ex) {
LOGGER.warning("security Exception while getting the codelistElement in value() method");
}
return value;
}
}