/*
* Copyright (c) 2014 Data Harmonisation Panel
*
* 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:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.common.schema.model.constraint.property.factory;
import java.text.MessageFormat;
import java.util.Optional;
import eu.esdihumboldt.hale.common.core.io.Value;
import eu.esdihumboldt.hale.common.core.io.ValueList;
import eu.esdihumboldt.hale.common.core.io.ValueProperties;
import eu.esdihumboldt.hale.common.schema.model.Definition;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.constraint.factory.ClassResolver;
import eu.esdihumboldt.hale.common.schema.model.constraint.factory.TypeReferenceBuilder;
import eu.esdihumboldt.hale.common.schema.model.constraint.factory.TypeResolver;
import eu.esdihumboldt.hale.common.schema.model.constraint.factory.ValueConstraintFactory;
import eu.esdihumboldt.hale.common.schema.model.constraint.property.Reference;
/**
* Converts a {@link Reference} constraint to a {@link Value} and vice versa.
* Constraints extending {@link Reference} that override
* {@link Reference#extractId(Object)} should provide their own factories.
*
* @author Simon Templer
*/
public class ReferenceFactory implements ValueConstraintFactory<Reference> {
/**
* Name of the property specifying if the constraint represents a reference.
*/
public static final String P_IS_REF = "isReference";
/**
* Name of the property specifying the referenced types.
*/
public static final String P_TYPES = "referencedTypes";
/**
* Value for the referenced types property specifying that the types are
* unknown.
*/
public static final String V_TYPES_UNKNOWN = "unknown";
@Override
public Value store(Reference constraint, TypeReferenceBuilder typeIndex) {
ValueProperties props = new ValueProperties();
props.put(P_IS_REF, Value.of(constraint.isReference()));
if (constraint.getReferencedTypes() == null) {
// referenced types are unknown
props.put(P_TYPES, Value.of(V_TYPES_UNKNOWN));
}
else {
// store type list
ValueList types = new ValueList();
for (TypeDefinition type : constraint.getReferencedTypes()) {
// add each type index
Optional<Value> ref = typeIndex.createReference(type);
if (ref.isPresent()) {
types.add(ref.get());
}
else {
throw new IllegalStateException(MessageFormat.format(
"Type {0} could not be resolved in type index", type.getName()));
}
}
props.put(P_TYPES, types.toValue());
}
return props.toValue();
}
@Override
public Reference restore(Value value, Definition<?> definition, TypeResolver typeIndex,
ClassResolver resolver) throws Exception {
ValueProperties props = value.as(ValueProperties.class);
Reference ref = new Reference(props.get(P_IS_REF).as(Boolean.class, false));
Value types = props.get(P_TYPES);
if (types.isComplex()) {
ValueList list = types.as(ValueList.class);
if (list != null) {
for (Value entry : list) {
Optional<TypeDefinition> type = typeIndex.resolve(entry);
if (type.isPresent()) {
ref.addReferencedType(type.get());
}
else {
throw new IllegalStateException(
"Could not resolve type definition for index " + entry);
}
}
}
}
return ref;
}
}