/*
* Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved.
*
* This file is part of the Jspresso framework.
*
* Jspresso 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, either version 3 of the License, or
* (at your option) any later version.
*
* Jspresso 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Jspresso. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jspresso.framework.model.descriptor.basic;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jspresso.framework.model.descriptor.ICollectionDescriptor;
import org.jspresso.framework.model.descriptor.IComponentDescriptor;
import org.jspresso.framework.util.collection.ESort;
import org.jspresso.framework.util.descriptor.DefaultDescriptor;
/**
* This descriptor is used to describe a collection of components (entities,
* interfaces or components). This descriptor is mainly used to qualify the
* collection referenced by a collection property descriptor. As of now,
* Jspresso supports :
* <ul>
* <li>collections with {@code Set} semantic: do not allow for duplicates
* and do not preserve the order of the elements in the data store</li>
* <li>collections with {@code List} semantic: allows for duplicates and
* preserves the order of the elements in the data store through an implicit
* index column</li>
* </ul>
*
* @author Vincent Vandenschrick
* @param <E>
* the concrete collection component element type.
*/
public class BasicCollectionDescriptor<E> extends DefaultDescriptor implements
ICollectionDescriptor<E> {
private Class<?> collectionInterface;
private IComponentDescriptor<? extends E> elementDescriptor;
private Map<String, ESort> orderingProperties;
private boolean nullElementAllowed;
/**
* {@inheritDoc}
*/
@Override
public ICollectionDescriptor<E> getCollectionDescriptor() {
return this;
}
/**
* {@inheritDoc}
*/
@Override
public Class<?> getCollectionInterface() {
if (Set.class.equals(collectionInterface) || List.class.equals(collectionInterface)) {
return collectionInterface;
}
return Set.class;
}
/**
* {@inheritDoc}
*/
@Override
public IComponentDescriptor<? extends E> getElementDescriptor() {
return elementDescriptor;
}
/**
* {@inheritDoc}
*/
@Override
public Class<?> getModelType() {
return getCollectionInterface();
}
/**
* {@inheritDoc}
*/
@Override
public String getModelTypeName() {
return getModelType().getName() + "<" + getElementDescriptor().getModelTypeName() + ">";
}
/**
* Gets the orderingProperties.
*
* @return the orderingProperties.
*/
@Override
public Map<String, ESort> getOrderingProperties() {
if (orderingProperties != null) {
return orderingProperties;
}
if (getElementDescriptor() != null) {
return getElementDescriptor().getOrderingProperties();
}
return null;
}
/**
* Allows to choose between the supported collection semantics. The incoming
* class property value must be one of :
* <ul>
* <li>{@code java.util.Set}</li>
* <li>{@code java.util.List}</li>
* </ul>
* Any other value is not supported and make the descriptor fall back to its
* default. A {@code null} value (default) is equivalent to setting
* {@code java.util.Set}. Alternatively, you can use descriptor
* sub-types, i.e. {@code BasicSetDescriptor} and
* {@code BasicListDescriptor} that make this property usage useless
* since they enforce their collection interface.
*
* @param collectionInterface
* the collectionInterface to set.
*/
public void setCollectionInterface(Class<?> collectionInterface) {
this.collectionInterface = collectionInterface;
}
/**
* Describes the elements contained in this collection. It can be any of
* entity, interface or component descriptor.
*
* @param elementDescriptor
* the elementDescriptor to set.
*/
public void setElementDescriptor(
IComponentDescriptor<? extends E> elementDescriptor) {
this.elementDescriptor = elementDescriptor;
}
/**
* Ordering properties are used to sort this collection if and only if it is
* un-indexed (not a {@code List}). The sort order set on the collection
* can refine the default one that might have been set on the element type
* level. This property consist of a {@code Map} whose entries are
* composed with :
* <ul>
* <li>the property name as key</li>
* <li>the sort order for this property as value. This is either a value of
* the {@code ESort} enum (<i>ASCENDING</i> or <i>DESCENDING</i>) or its
* equivalent string representation.</li>
* </ul>
* Ordering properties are considered following their order in the map
* iterator. A {@code null} value (default) will not give any indication
* for the collection sort order and thus, will delegate to higher
* specification levels (e.g. the element type sort order).
*
* @param untypedOrderingProperties
* the orderingProperties to set.
*/
public void setOrderingProperties(Map<String, ?> untypedOrderingProperties) {
if (untypedOrderingProperties != null) {
orderingProperties = new LinkedHashMap<>();
for (Map.Entry<String, ?> untypedOrderingProperty : untypedOrderingProperties
.entrySet()) {
if (untypedOrderingProperty.getValue() instanceof ESort) {
orderingProperties.put(untypedOrderingProperty.getKey(),
(ESort) untypedOrderingProperty.getValue());
} else if (untypedOrderingProperty.getValue() instanceof String) {
orderingProperties.put(untypedOrderingProperty.getKey(),
ESort.valueOf((String) untypedOrderingProperty.getValue()));
} else {
orderingProperties.put(untypedOrderingProperty.getKey(),
ESort.ASCENDING);
}
}
} else {
orderingProperties = null;
}
}
/**
* Is null element allowed.
*
* @return the boolean
*/
@Override
public boolean isNullElementAllowed() {
return nullElementAllowed;
}
/**
* Configures the collection to accept null element values or not. If the collection does not allows for null
* values, it forbids to have holes in lists, i.e. all elements have consecutive indices.
*
* @param nullElementAllowed {@code true} if the collection accepts {@code null} elements.
*/
public void setNullElementAllowed(boolean nullElementAllowed) {
this.nullElementAllowed = nullElementAllowed;
}
}