/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2013, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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
* Lesser General Public License for more details.
*/
package org.geotoolkit.utility.parameter;
import java.util.*;
import org.apache.sis.measure.Range;
import org.apache.sis.parameter.DefaultParameterDescriptor;
import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.util.ArgumentChecks;
import org.opengis.parameter.*;
import org.opengis.referencing.IdentifiedObject;
import org.opengis.util.InternationalString;
import javax.measure.Unit;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.UnconvertibleObjectException;
import org.apache.sis.util.logging.Logging;
/**
* Utility methods for parameters.
* @author Johann Sorel (Geomatys)
* @author QuentinBoileau (Geomatys)
*/
public final class ParametersExt {
private ParametersExt(){}
/**
* List of all parameters, ParameterValue AND ParameterGroups.
* Live list modifiable.
*/
public static List<GeneralParameterValue> getParameters(ParameterValueGroup group){
return group.values();
}
/**
* Get the first parameter for this name, do not create parameter if missing.
*/
public static GeneralParameterValue getParameter(ParameterValueGroup group,String name){
final List<GeneralParameterValue> params = getParameters(group);
for(GeneralParameterValue p : params){
if(p.getDescriptor().getName().getCode().equalsIgnoreCase(name)){
return p;
}
}
return null;
}
/**
* Get all parameters recursively for this class, do not create parameter if missing.
*/
public static List<ParameterValue> getParameters(ParameterValueGroup group, Class type){
final List<ParameterValue> result = new ArrayList<ParameterValue>();
getParameters(group, type, result);
return result;
}
private static void getParameters(ParameterValueGroup group, Class type, List<ParameterValue> result) {
final List<GeneralParameterValue> params = getParameters(group);
for(GeneralParameterValue p : params) {
if(p instanceof ParameterValue) {
final Class clazz = ((ParameterDescriptor)p.getDescriptor()).getValueClass();
if (type.isAssignableFrom(clazz)) {
result.add((ParameterValue)p);
}
} else if (p instanceof ParameterValueGroup) {
getParameters((ParameterValueGroup)p, type, result);
}
}
}
/**
* List of all parameters, ParameterValue OR ParameterGroups of this name.
*/
public static List<GeneralParameterValue> getParameters(ParameterValueGroup group,String name){
final List<GeneralParameterValue> params = getParameters(group);
final List<GeneralParameterValue> result = new ArrayList<GeneralParameterValue>();
for(GeneralParameterValue p : params){
if(p.getDescriptor().getName().getCode().equalsIgnoreCase(name)){
result.add(p);
}
}
return result;
}
/**
* Get the first parameter for this name, create parameter if missing.
*/
public static GeneralParameterValue getOrCreateParameter(ParameterValueGroup group,String name){
GeneralParameterValue param = getParameter(group, name);
if(param != null) return param;
//create it
param = group.getDescriptor().descriptor(name).createValue();
getParameters(group).add(param);
return param;
}
/**
* Get parameter value, do not create parameter if missing.
*/
public static ParameterValue<?> getValue(ParameterValueGroup group,String name){
final List<GeneralParameterValue> params = getParameters(group);
for(GeneralParameterValue p : params){
if(p instanceof ParameterValue && p.getDescriptor().getName().getCode().equalsIgnoreCase(name)){
return (ParameterValue<?>) p;
}
}
return null;
}
/**
* Get parameter value, create parameter if missing.
*/
public static ParameterValue<?> getOrCreateValue(ParameterValueGroup group,String name){
ParameterValue param = getValue(group, name);
if(param != null) return param;
//create it
param = (ParameterValue) group.getDescriptor().descriptor(name).createValue();
getParameters(group).add(param);
return param;
}
/**
* Get parameter group, do not create parameter if missing.
*/
public static ParameterValueGroup getGroup(ParameterValueGroup group,String name){
final List<GeneralParameterValue> params = getParameters(group);
for(GeneralParameterValue p : params){
if(p instanceof ParameterValueGroup && p.getDescriptor().getName().getCode().equalsIgnoreCase(name)){
return (ParameterValueGroup) p;
}
}
return null;
}
/**
* Get parameter group list, do not create parameter if missing.
*/
public static List<ParameterValueGroup> getGroups(ParameterValueGroup group,String name){
final List<GeneralParameterValue> params = getParameters(group);
final List<ParameterValueGroup> result = new ArrayList<ParameterValueGroup>();
for(GeneralParameterValue p : params){
if(p instanceof ParameterValueGroup && p.getDescriptor().getName().getCode().equalsIgnoreCase(name)){
result.add((ParameterValueGroup)p);
}
}
return result;
}
/**
* Get parameter group, create if missing, return first one otherwise !
*/
public static ParameterValueGroup getOrCreateGroup(ParameterValueGroup group,String name){
ParameterValueGroup param = getGroup(group, name);
if(param != null) return param;
//create it
param = (ParameterValueGroup) group.getDescriptor().descriptor(name).createValue();
getParameters(group).add(param);
return param;
}
/**
* create and return a parameter group.
*/
public static ParameterValueGroup createGroup(ParameterValueGroup group,String name){
ParameterValueGroup param = (ParameterValueGroup) group.getDescriptor().descriptor(name).createValue();
getParameters(group).add(param);
return param;
}
/**
* Search recursively all GeneralParameterDescriptors which have the requested name.
* @param parameter Root GeneralParameterDescriptors
* @param name parameter name to search
* @param maxDepth the max depth to search for.
* @return
*/
public static List<GeneralParameterDescriptor> search(final GeneralParameterDescriptor parameter,
final String name, int maxDepth)
{
final List<GeneralParameterDescriptor> list = new ArrayList<GeneralParameterDescriptor>();
search(parameter, name, maxDepth, list);
return list;
}
/**
* Implementation of the search algorithm. The result is stored in the supplied set.
*/
private static void search(final GeneralParameterDescriptor parameter, final String name,
final int maxDepth, final Collection<GeneralParameterDescriptor> list)
{
if (maxDepth >= 0) {
if (IdentifiedObjects.isHeuristicMatchForName(parameter, name)) {
list.add(parameter);
}
if ((maxDepth != 0) && (parameter instanceof ParameterDescriptorGroup)) {
for (final GeneralParameterDescriptor value : ((ParameterDescriptorGroup) parameter).descriptors()) {
search(value, name, maxDepth-1, list);
}
}
}
}
/**
* Search a GeneralParameterDescriptor in a path.
* Exemple : if separator is ':' and path is "input:group1:parameter"
* the methode will search the GeneralParameterDescriptor named "parameter"
* in ParameterDescriptorGroup "input" -> "group1".
*
* @param parameter root ParameterDescriptorGroup
* @param path path to GeneralParameterDescriptor
* @param separator string used to separate groups and parameter names.
* @return GeneralParameterDescriptor or null if not found
*/
public static GeneralParameterDescriptor searchPath(final ParameterDescriptorGroup parameter,
final String path, final String separator) {
final String[] pathParts = path.split(separator);
//only one part, the parameter must be at first depth level.
if (pathParts.length == 1) {
return search(parameter, path, 1).get(0);
}
return searchPath(parameter, pathParts, 0);
}
/**
*
* @param parameter
* @param codes
* @param index
* @return
*/
private static GeneralParameterDescriptor searchPath(final ParameterDescriptorGroup parameter,
final String[] codes, int index) {
GeneralParameterDescriptor result = null;
final String codePart = codes[index];
for (GeneralParameterDescriptor param : parameter.descriptors()) {
if (result != null) break;
if (IdentifiedObjects.isHeuristicMatchForName(param, codePart)) {
if (index == codes.length-1) {
result = param;
} else {
if (param instanceof ParameterDescriptorGroup) {
result = searchPath((ParameterDescriptorGroup)param, codes, index+1);
}
}
}
}
return result;
}
/**
* Add a GeneralParameterDescriptor to a ParameterDescriptorGroup.
*
* @param root ParameterDescriptorGroup. Will not be modified.
* @param newParam GeneralParameterDescriptor to add
* @return the new ParameterDescriptorGroup
*/
public static ParameterDescriptorGroup addParameterToDescriptorGroup(final ParameterDescriptorGroup root, final GeneralParameterDescriptor newParam) {
ArgumentChecks.ensureNonNull("root", root);
ArgumentChecks.ensureNonNull("newParam", newParam);
final List<GeneralParameterDescriptor> parameters = new ArrayList<GeneralParameterDescriptor> (root.descriptors());
parameters.add(newParam);
int minOccurs = root.getMinimumOccurs();
int maxOccurs = root.getMaximumOccurs();
return createParameterDescriptorGroup(root.getName().getCode(), root.getRemarks(), minOccurs, maxOccurs, parameters);
}
/**
* Remove a GeneralParameterDescriptor from a ParameterDescriptorGroup.
*
* @param root
* @param toRemove GeneralParameterDescriptor to remove
* @return the new ParameterDescriptorGroup
*/
public static ParameterDescriptorGroup removeParameterToDescriptorGroup(final ParameterDescriptorGroup root, final GeneralParameterDescriptor toRemove) {
ArgumentChecks.ensureNonNull("root", root);
ArgumentChecks.ensureNonNull("toRemove", toRemove);
final List<GeneralParameterDescriptor> parameters = new ArrayList<GeneralParameterDescriptor> (root.descriptors());
parameters.remove(toRemove);
int minOccurs = root.getMinimumOccurs();
int maxOccurs = root.getMaximumOccurs();
return createParameterDescriptorGroup(root.getName().getCode(), root.getRemarks(), minOccurs, maxOccurs, parameters);
}
/**
* Regroup all parameters used to create a ParameterDescriptor.
*
* @param code parameter code String
* @param remarks parameter description
* @param valueClass parametrer type
* @param validValues array of valids values
* @param defaultValue default value Object
* @param minValue min value Object
* @param maxValue max value Object
* @param unit parameter unit
* @param required mandatory or not
* @return a ParameterDescriptor
* @deprecated Use org.apache.sis.parameter.ParameterBuilder
*/
@Deprecated
public static ParameterDescriptor createParameterDescriptor(final String code, final InternationalString remarks,
final Class valueClass, final Object[] validValues, final Object defaultValue, final Comparable minValue,
final Comparable maxValue, final Unit unit, final boolean required) {
final Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put(IdentifiedObject.NAME_KEY, code);
paramMap.put(IdentifiedObject.REMARKS_KEY, remarks);
Range range = null;
if(minValue!=null || maxValue!=null){
range = new Range(valueClass, minValue, true, maxValue, true);
}
return new DefaultParameterDescriptor(paramMap, required?1:0, 1, valueClass, range, validValues, defaultValue);
}
/**
* Regroup all parameters used to create a ParameterDescriptorGroup.
*
* @param code parameter code String
* @param remarks parameter description
* @param min min occurences
* @param max max occurences
* @param parameters list of children parameters.
* @return a ParameterDescriptorGroup
*/
public static ParameterDescriptorGroup createParameterDescriptorGroup(final String code, final InternationalString remarks,
final int min, final int max, final List<GeneralParameterDescriptor> parameters) {
final Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put(IdentifiedObject.NAME_KEY, code);
paramMap.put(IdentifiedObject.REMARKS_KEY, remarks);
return new DefaultParameterDescriptorGroup(paramMap, min, max, parameters.toArray(new GeneralParameterDescriptor[parameters.size()]));
}
/**
* Deep copy from a ParameterValueGroup source to a target ParameterValueGroup.
*
* @param source
* @param target
*/
public static void deepCopy(ParameterValueGroup source, ParameterValueGroup target) {
for (GeneralParameterDescriptor paramDesc : source.getDescriptor().descriptors()) {
final String paramCode = paramDesc.getName().getCode();
if (paramDesc instanceof ParameterDescriptor) {
final ParameterValue paramValue = source.parameter(paramCode);
target.parameter(paramCode).setValue(paramValue.getValue());
} else {
final List<ParameterValueGroup> sourceValues = source.groups(paramCode);
int targetValuesSize = target.groups(paramCode).size();
if (targetValuesSize < sourceValues.size()) {
int toAdd = sourceValues.size() - targetValuesSize;
for (int i = 0; i < toAdd; i++) {
target.addGroup(paramCode);
}
}
final List<ParameterValueGroup> targetValues = target.groups(paramCode);
for (int i = 0; i < targetValues.size(); i++) {
deepCopy(sourceValues.get(i), targetValues.get(i));
}
}
}
}
/**
* Transform a Map in a ParameterValueGroup.
* A default parameter is first created and all key found in the map
* that match the descriptor will be completed.
*
* @param params
* @param desc
* @return
*
* @deprecated Use method {@link Parameters#toParameter(java.util.Map, org.opengis.parameter.ParameterDescriptorGroup)} instead.
*/
public static ParameterValueGroup toParameter(final Map<String, ?> params, final ParameterDescriptorGroup desc) {
ArgumentChecks.ensureNonNull("params", params);
ArgumentChecks.ensureNonNull("desc", desc);
return toParameter(params, desc, true);
}
/**
* Transform a Map in a ParameterValueGroup.
* A default parameter is first created and all key found in the map
* that match the descriptor will be completed.
*
* @param params
* @param desc
* @param checkMandatory : will return a parameter only if all mandatory values
* have been found in the map.
* @return
*
* @deprecated Use method {@link Parameters#toParameter(java.util.Map, org.opengis.parameter.ParameterDescriptorGroup, boolean)} instead.
*/
public static ParameterValueGroup toParameter(final Map<String, ?> params,
final ParameterDescriptorGroup desc, final boolean checkMandatory) {
ArgumentChecks.ensureNonNull("params", params);
ArgumentChecks.ensureNonNull("desc", desc);
if(checkMandatory){
for(GeneralParameterDescriptor de : desc.descriptors()){
if(de.getMinimumOccurs()>0 && !(params.containsKey(de.getName().getCode()))){
//a mandatory parameter is not present
return null;
}
}
}
final ParameterValueGroup parameter = desc.createValue();
for(final Map.Entry<String, ?> entry : params.entrySet()){
final GeneralParameterDescriptor subdesc;
try{
subdesc = desc.descriptor(entry.getKey());
}catch(ParameterNotFoundException ex){
//do nothing, the map may contain other values for other uses
continue;
}
if(!(subdesc instanceof ParameterDescriptor)){
//we can not recreate value groups
continue;
}
final ParameterDescriptor pd = (ParameterDescriptor) subdesc;
final ParameterValue param;
try{
param = getOrCreateValue(parameter, pd.getName().getCode());
}catch(ParameterNotFoundException ex){
//do nothing, the map may contain other values for other uses
continue;
}
Object val = entry.getValue();
try {
val = ObjectConverters.convert(val, pd.getValueClass());
param.setValue(val);
} catch (UnconvertibleObjectException e) {
Logging.recoverableException(null, ParametersExt.class, "toParameter", e);
// TODO - do we really want to ignore?
}
}
return parameter;
}
}