/*
* Copyright (c) 2013 Fraunhofer IGD
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Fraunhofer IGD
*/
package eu.esdihumboldt.hale.app.bgis.ade.defaults;
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import eu.esdihumboldt.hale.app.bgis.ade.common.BGISAppConstants;
import eu.esdihumboldt.hale.app.bgis.ade.common.BGISAppUtil;
import eu.esdihumboldt.hale.app.bgis.ade.common.EntityVisitor;
import eu.esdihumboldt.hale.app.bgis.ade.defaults.config.DefaultValues;
import eu.esdihumboldt.hale.common.align.model.Entity;
import eu.esdihumboldt.hale.common.align.model.MutableCell;
import eu.esdihumboldt.hale.common.align.model.ParameterValue;
import eu.esdihumboldt.hale.common.align.model.Priority;
import eu.esdihumboldt.hale.common.align.model.functions.AssignFunction;
import eu.esdihumboldt.hale.common.align.model.functions.GenerateUIDFunction;
import eu.esdihumboldt.hale.common.align.model.impl.DefaultCell;
import eu.esdihumboldt.hale.common.align.model.impl.DefaultProperty;
import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.constraint.property.Cardinality;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.Binding;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.Enumeration;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.HasValueFlag;
import eu.esdihumboldt.hale.functions.bgis.capturespec.DataCaptureSpecFunction;
import eu.esdihumboldt.hale.functions.bgis.sourcedesc.SourceDescriptionFunction;
/**
* Entity visitor that creates cells assigning default values.
*
* @author Simon Templer
*/
public class DefaultsVisitor extends EntityVisitor implements BGISAppConstants {
/**
* The created cells.
*/
private final List<MutableCell> cells = new ArrayList<MutableCell>();
private final DefaultValues defaultValues;
/**
* Create a default value visitor creating assignment cells.
*
* @param defaultValues the custom default value configuration, may be
* <code>null</code>
*/
public DefaultsVisitor(DefaultValues defaultValues) {
this.defaultValues = defaultValues;
}
@Override
protected boolean visit(PropertyEntityDefinition ped) {
if (ADE_NS.equals(ped.getDefinition().getName().getNamespaceURI())) {
// property is from ADE
if (ped.getDefinition().getPropertyType().getConstraint(HasValueFlag.class).isEnabled()) {
/*
* Property is represented by a simple type (only there it makes
* sense to assign defaults)
*/
// special handling allowing defaults
if ("dataCaptureSpec".equals(ped.getDefinition().getName().getLocalPart())) {
addAugmentationCell(ped, DataCaptureSpecFunction.ID, Priority.LOW);
}
// special handling allowing no defaults
if ("sourceDescription".equals(ped.getDefinition().getName().getLocalPart())) {
addAugmentationCell(ped, SourceDescriptionFunction.ID, Priority.LOWEST);
}
// default values
else {
String value = null;
// check config for default value
value = defaultValues.getDefaultValue(ped);
/*
* Assign custom default value for any property or generic
* default value for mandatory property
*/
if (value != null
|| ped.getDefinition().getConstraint(Cardinality.class).getMinOccurs() > 0) {
addDefaultCell(ped, value);
}
}
}
return true;
}
else {
// property not from ADE
// handle mandatory XML IDs in complex properties
if (ped.getPropertyPath().size() > 1 // ignore feature ID
&& ped.getDefinition().getConstraint(Cardinality.class).getMinOccurs() > 0
&& BGISAppUtil.isID(ped.getDefinition().getPropertyType())) {
// TODO also check the wrapping property actually is mandatory?
addAugmentationCell(ped, GenerateUIDFunction.ID, Priority.LOWEST);
}
}
return false;
}
/**
* Add a cell assigning a default value to the given entity.
*
* @param ped the property entity definition
* @param value the value to assign or <code>null</code> if it should be
* auto-detected
*/
private void addDefaultCell(PropertyEntityDefinition ped, String value) {
String note;
// determine value to assign
if (value == null) {
value = determineDefaultValue(ped.getDefinition().getPropertyType());
note = "Generated default value based on property type.";
}
else {
note = "Generated cell with specified default value.";
}
if (value == null) {
return;
}
// create cell template
MutableCell cell = new DefaultCell();
cell.setPriority(Priority.LOWEST);
ListMultimap<String, Entity> target = ArrayListMultimap.create();
cell.setTarget(target);
ListMultimap<String, ParameterValue> parameters = ArrayListMultimap.create();
cell.setTransformationParameters(parameters);
// set transformation identifier (Assign)
cell.setTransformationIdentifier(AssignFunction.ID);
// set cell target (Property)
target.put(null, new DefaultProperty(ped));
// set cell parameters (Value)
parameters.put(AssignFunction.PARAMETER_VALUE, new ParameterValue(value));
BGISAppUtil.appendNote(cell, note);
cells.add(cell);
}
/**
* Add a simple cell using an augmentation w/o parameters.
*
* @param ped the property entity definition
* @param functionId the function identifier
* @param priority the cell priority
*/
private void addAugmentationCell(PropertyEntityDefinition ped, String functionId,
Priority priority) {
// create cell template
MutableCell cell = new DefaultCell();
cell.setPriority(priority);
ListMultimap<String, Entity> target = ArrayListMultimap.create();
cell.setTarget(target);
// set transformation identifier (Function ID)
cell.setTransformationIdentifier(functionId);
// set cell target (Property)
target.put(null, new DefaultProperty(ped));
BGISAppUtil.appendNote(cell, "Generated default mapping.");
cells.add(cell);
}
/**
* Determine the default value to use for the given property type.
*
* @param propertyType the type definition
* @return the value or <code>null</code>
*/
private String determineDefaultValue(TypeDefinition propertyType) {
// check for enumeration
Enumeration<?> vals = propertyType.getConstraint(Enumeration.class);
if (vals.getValues() != null) {
if (vals.getValues().contains(ENUMERATION_DEFAULT)) {
return ENUMERATION_DEFAULT;
}
}
// check for a number binding
Class<?> binding = propertyType.getConstraint(Binding.class).getBinding();
if (Number.class.isAssignableFrom(binding)) {
return NUMBER_DEFAULT;
}
return DEFAULT;
// TODO convert/validate the value to check?
}
/**
* Get the created cells.
*
* @return the cells assigning default values
*/
public List<MutableCell> getCells() {
return cells;
}
}