/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.database.object.config;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.Id;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
public class ConfigurationPart implements Cloneable
{
@SuppressWarnings ("unchecked")
public <T extends ConfigurationPart> T completeWith(T completion)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, CloneNotSupportedException
{
T completed = (T) this.clone ();
if (completion == null) return completed;
Class<?> clazz = getClass ();
while (clazz != ConfigurationPart.class)
{
Field[] fields = clazz.getDeclaredFields ();
Method[] methods = clazz.getDeclaredMethods ();
HashMap<String, Method> getters = new HashMap<String, Method> ();
Pattern getPattern = Pattern.compile("^get([A-Z].*)");
Pattern isPattern = Pattern.compile("^is([A-Z].*)");
HashMap<String, Method> setters = new HashMap<String, Method> ();
Pattern setPattern = Pattern.compile("^set([A-Z].*)");
for (Method method : methods)
{
Matcher m;
if (method.getParameterTypes().length == 0)
{
if ((m = getPattern.matcher (method.getName ())).matches () &&
!method.getReturnType().equals(void.class))
{
getters.put (m.group(1), method);
}
else if ((m = isPattern.matcher (method.getName ())).matches ()
&& !method.getReturnType().equals(boolean.class))
{
getters.put (m.group(1), method);
}
}
else if (method.getParameterTypes().length == 1)
{
if ((m = setPattern.matcher (method.getName ())).matches () &&
method.getReturnType().equals(void.class))
{
setters.put (m.group(1), method);
}
}
}
for (Field field : fields)
{
// Do not touch to Ids
if (field.getAnnotation (Id.class) == null)
{
String fieldName = field.getName ().substring (0,1)
.toUpperCase () + field.getName ().substring (1);
Method getter = getters.get (fieldName);
Method setter = setters.get (fieldName);
if (getter == null || setter == null)
continue;
if (!Modifier.isPublic (getter.getModifiers ()))
{
getter.setAccessible (true);
}
if (!Modifier.isPublic (setter.getModifiers ()))
{
setter.setAccessible (true);
}
// ConfigurationPart fields cause a recursive call
if (ConfigurationPart.class.isAssignableFrom (field.getType ()))
{
ConfigurationPart confPart = (ConfigurationPart) getter
.invoke (completed);
ConfigurationPart completionPart = (ConfigurationPart) getter
.invoke (completion);
if (confPart == null && completionPart == null)
{
// nothing to complete
}
else
{
if (confPart == null)
{
setter.invoke(completed, completionPart);
}
else if (completionPart == null)
{
setter.invoke(completed, confPart);
}
else
{
ConfigurationPart merged = confPart
.completeWith ((ConfigurationPart)getter.invoke (
completion));
setter.invoke(completed, merged);
}
}
}
// Null value mean that we use completion value
else if (getter.invoke (completed) == null)
{
setter.invoke(completed, getter.invoke (completion));
}
}
}
clazz = clazz.getSuperclass ();
}
return completed;
}
@SuppressWarnings ("unchecked")
public <T extends ConfigurationPart> T getNotStoredPart()
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, CloneNotSupportedException
{
T notStoredPart = (T) this.clone ();
Field[] fields = getClass().getDeclaredFields ();
Method[] methods = getClass().getDeclaredMethods ();
HashMap<String, Method> getters = new HashMap<String, Method> ();
Pattern getPattern = Pattern.compile("^get([A-Z].*)");
Pattern isPattern = Pattern.compile("^is([A-Z].*)");
HashMap<String, Method> setters = new HashMap<String, Method> ();
Pattern setPattern = Pattern.compile("^set([A-Z].*)");
for (Method method : methods)
{
if (Modifier.isPublic(method.getModifiers()))
{
Matcher m;
if (method.getParameterTypes().length == 0)
{
if ((m = getPattern.matcher (method.getName ())).matches () &&
!method.getReturnType().equals(void.class))
{
getters.put (m.group(1), method);
}
else if ((m = isPattern.matcher (method.getName ())).matches ()
&& !method.getReturnType().equals(boolean.class))
{
getters.put (m.group(1), method);
}
}
else if (method.getParameterTypes().length == 1)
{
if ((m = setPattern.matcher (method.getName ())).matches () &&
method.getReturnType().equals(void.class))
{
setters.put (m.group(1), method);
}
}
}
}
for (Field field : fields)
{
// Do not touch to Ids
if (field.getAnnotation (Id.class) == null)
{
String fieldName = field.getName ().substring (0,1).toUpperCase () +
field.getName ().substring (1);
Method getter = getters.get (fieldName);
Method setter = setters.get (fieldName);
if (getter == null || setter == null)
continue;
if (!Modifier.isPublic (getter.getModifiers ()))
{
getter.setAccessible (true);
}
if (!Modifier.isPublic (setter.getModifiers ()))
{
setter.setAccessible (true);
}
// Non Transient ConfigurationPart fields cause a recursive call
if (ConfigurationPart.class.isAssignableFrom (field.getType ())
&& field.getAnnotation (Transient.class) == null)
{
ConfigurationPart fullConf = (ConfigurationPart) getter
.invoke (notStoredPart);
ConfigurationPart filteredConf = fullConf.getNotStoredPart ();
setter.invoke(notStoredPart, filteredConf);
}
// Set all non Transient fields to null
else if (field.getAnnotation (Transient.class) == null)
{
setter.invoke(notStoredPart,new Object[]{ null });
}
}
}
return notStoredPart;
}
}