/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* 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; either version 2.1 of the License, or (at your option)
* any later version.
*
* 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 com.agiletec.aps.system.common.entity.model.attribute;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jdom.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.agiletec.aps.system.common.entity.model.AttributeFieldError;
import com.agiletec.aps.system.common.entity.model.AttributeTracer;
import com.agiletec.aps.system.common.entity.model.IApsEntity;
import com.agiletec.aps.system.common.searchengine.IndexableAttributeInterface;
import com.agiletec.aps.system.exception.ApsSystemException;
/**
* This class describes the Entity of a Composed Attribute.
* This attribute is build by one or more elementary attributes of different types.
* These elementary attributes can support multiple languages or not (and are defined
* multi or mono-language).
* The Composite Attribute is only utilized in conjunction with the 'Monolist' attribute. Please
* note that the composite attribute cannot be used as an element of the "List" attribute since
* the items in the List can support multiple languages.
* @author E.Santoboni
*/
public class CompositeAttribute extends AbstractComplexAttribute {
private static final Logger _logger = LoggerFactory.getLogger(CompositeAttribute.class);
/**
* Attribute initialization.
*/
public CompositeAttribute() {
this._attributeList = new ArrayList<AttributeInterface>();
this._attributeMap = new HashMap<String, AttributeInterface>();
}
/**
* Return the attribute prototype, that is an empty attribute.
*/
@Override
public Object getAttributePrototype() {
CompositeAttribute clone = (CompositeAttribute) super.getAttributePrototype();
Iterator<AttributeInterface> iter = this.getAttributes().iterator();
while (iter.hasNext()) {
AttributeInterface attribute = iter.next();
attribute.setParentEntity(this.getParentEntity());
clone.addAttribute((AttributeInterface) attribute.getAttributePrototype());
}
return clone;
}
@Override
public void setRenderingLang(String langCode) {
super.setRenderingLang(langCode);
Iterator<AttributeInterface> iter = this.getAttributes().iterator();
while (iter.hasNext()) {
AttributeInterface attribute = iter.next();
attribute.setRenderingLang(langCode);
}
}
@Override
public void setDefaultLangCode(String langCode) {
super.setDefaultLangCode(langCode);
Iterator<AttributeInterface> iter = this.getAttributes().iterator();
while (iter.hasNext()) {
AttributeInterface attribute = iter.next();
attribute.setDefaultLangCode(langCode);
}
}
@Override
public Element getJDOMElement() {
Element attributeElement = this.createRootElement("composite");
Iterator<AttributeInterface> iter = this.getAttributes().iterator();
while (iter.hasNext()) {
AttributeInterface attribute = iter.next();
attributeElement.addContent(attribute.getJDOMElement());
}
return attributeElement;
}
@Override
public Element getJDOMConfigElement() {
Element configElement = super.getJDOMConfigElement();
Element attributesElement = new Element("attributes");
configElement.addContent(attributesElement);
List<AttributeInterface> attributes = this.getAttributes();
for (int i = 0; i < attributes.size(); i++) {
AttributeInterface attributeElement = attributes.get(i);
Element subConfigElement = attributeElement.getJDOMConfigElement();
attributesElement.addContent(subConfigElement);
}
return configElement;
}
/**
* Return the attribute with the given name.
* @param name The name of the requested attribute
* @return The requested attribute.
*/
public AttributeInterface getAttribute(String name) {
AttributeInterface attribute = (AttributeInterface) this.getAttributeMap().get(name);
return attribute;
}
/**
* Add an attribute to the current Composite Attribute.
* @param attribute The attribute to add.
*/
protected void addAttribute(AttributeInterface attribute) {
this.getAttributes().add(attribute);
this.getAttributeMap().put(attribute.getName(), attribute);
}
@Override
public List<AttributeInterface> getAttributes() {
return this._attributeList;
}
/**
* Return the map of the elementary attributes.
* @return The requested map
*/
public Map<String, AttributeInterface> getAttributeMap() {
return this._attributeMap;
}
@Override
public void setComplexAttributeConfig(Element attributeElement, Map<String, AttributeInterface> attrTypes) throws ApsSystemException {
Element compositeAttributesElement = attributeElement.getChild("attributes");
if (null == compositeAttributesElement) {
this.setOldComplexAttributeConfig(attributeElement, attrTypes);
} else {
List<Element> compositeAttributeElements = compositeAttributesElement.getChildren();
for (int j = 0; j < compositeAttributeElements.size(); j++) {
Element currentAttrJdomElem = compositeAttributeElements.get(j);
this.extractAttributeCompositeElement(attrTypes, currentAttrJdomElem);
}
}
}
@Deprecated(/** INSERTED to guaranted compatibility with previsous version of jAPS 2.0.12 */)
private void setOldComplexAttributeConfig(Element attributeElement, Map<String, AttributeInterface> attrTypes) throws ApsSystemException {
List<Element> attributeElements = attributeElement.getChildren();
for (int j = 0; j < attributeElements.size(); j++) {
Element currentAttrJdomElem = attributeElements.get(j);
extractAttributeCompositeElement(attrTypes, currentAttrJdomElem);
}
}
private void extractAttributeCompositeElement(Map<String, AttributeInterface> attrTypes, Element currentAttrJdomElem) throws ApsSystemException {
String typeCode = this.extractXmlAttribute(currentAttrJdomElem, "attributetype", true);
AttributeInterface compositeAttrElem = (AttributeInterface) attrTypes.get(typeCode);
if (compositeAttrElem == null) {
throw new ApsSystemException("The type " + typeCode
+ " of the attribute element found in the tag <" + currentAttrJdomElem.getName() + "> of the composite attribute is not a valid one");
}
compositeAttrElem = (AttributeInterface) compositeAttrElem.getAttributePrototype();
compositeAttrElem.setAttributeConfig(currentAttrJdomElem);
compositeAttrElem.setSearchable(false);
compositeAttrElem.setDefaultLangCode(this.getDefaultLangCode());
this.addAttribute(compositeAttrElem);
}
/**
* Since this kind of attribute can never be indexable this method, which overrides
* the one of the abstract class, always returns the constant "INDEXING_TYPE_NONE"
* (defined in AttributeInterface) which explicitly declares it not indexable.
* Declaring indexable a complex attribute will make the contained element indexable.
* @return the indexing type
* @see com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface#getIndexingType()
*/
@Override
public String getIndexingType() {
return IndexableAttributeInterface.INDEXING_TYPE_NONE;
}
@Override
public Object getRenderingAttributes() {
return this.getAttributeMap();
}
@Override
public void setParentEntity(IApsEntity parentEntity) {
super.setParentEntity(parentEntity);
for (int i = 0; i < this.getAttributes().size(); i++) {
AttributeInterface attributeElement = this.getAttributes().get(i);
attributeElement.setParentEntity(parentEntity);
}
}
@Override
public Object getValue() {
return this.getAttributeMap();
}
@Override
protected AbstractJAXBAttribute getJAXBAttributeInstance() {
return new JAXBCompositeAttribute();
}
@Override
public AbstractJAXBAttribute getJAXBAttribute(String langCode) {
JAXBCompositeAttribute jaxbAttribute = (JAXBCompositeAttribute) super.createJAXBAttribute(langCode);
if (null == jaxbAttribute) return null;
List<AttributeInterface> attributes = this.getAttributes();
if (null != attributes && !attributes.isEmpty()) {
Map<String, AbstractJAXBAttribute> jaxbAttributes = new HashMap<String, AbstractJAXBAttribute>();
for (int i = 0; i < attributes.size(); i++) {
AttributeInterface attribute = attributes.get(i);
jaxbAttributes.put(attribute.getName(), attribute.getJAXBAttribute(langCode));
}
jaxbAttribute.setAttributes(jaxbAttributes);
}
return jaxbAttribute;
}
@Override
public void valueFrom(AbstractJAXBAttribute jaxbAttribute) {
super.valueFrom(jaxbAttribute);
Map<String, AbstractJAXBAttribute> jaxbAttributes = ((JAXBCompositeAttribute) jaxbAttribute).getAttributes();
if (null != jaxbAttributes) {
Iterator<String> iter = jaxbAttributes.keySet().iterator();
while (iter.hasNext()) {
String key = iter.next();
AbstractJAXBAttribute jaxbAttributeElement = jaxbAttributes.get(key);
if (null == jaxbAttributeElement) {
continue;
}
AttributeInterface attributeElement = this.getAttributeMap().get(jaxbAttributeElement.getName());
if (null != attributeElement
&& attributeElement.getType().equals(jaxbAttributeElement.getType())) {
attributeElement.valueFrom(jaxbAttributeElement);
}
}
}
}
@Override
public JAXBCompositeAttributeType getJAXBAttributeType() {
JAXBCompositeAttributeType jaxbAttribute = (JAXBCompositeAttributeType) super.getJAXBAttributeType();
List<AttributeInterface> elements = this.getAttributes();
if (null != elements) {
for (int i = 0; i < elements.size(); i++) {
AttributeInterface attributeElement = elements.get(i);
jaxbAttribute.getElementTypes().add(attributeElement.getJAXBAttributeType());
}
}
return jaxbAttribute;
}
@Override
protected DefaultJAXBAttributeType getJAXBAttributeTypeInstance() {
return new JAXBCompositeAttributeType();
}
@Override
public Status getStatus() {
List<AttributeInterface> attributes = this.getAttributes();
for (int i = 0; i < attributes.size(); i++) {
AttributeInterface attributeElement = attributes.get(i);
Status elementStatus = attributeElement.getStatus();
if (!Status.EMPTY.equals(elementStatus)) {
return Status.VALUED;
}
}
return Status.EMPTY;
}
@Override
public List<AttributeFieldError> validate(AttributeTracer tracer) {
List<AttributeFieldError> errors = super.validate(tracer);
try {
List<AttributeInterface> attributes = this.getAttributes();
for (int i = 0; i < attributes.size(); i++) {
AttributeInterface attributeElement = attributes.get(i);
AttributeTracer elementTracer = tracer.clone();
elementTracer.setCompositeElement(true);
elementTracer.setParentAttribute(this);
List<AttributeFieldError> elementErrors = attributeElement.validate(elementTracer);
if (null != elementErrors) {
errors.addAll(elementErrors);
}
}
} catch (Throwable t) {
_logger.error("Error validating composite attribute", t);
throw new RuntimeException("Error validating composite attribute", t);
}
return errors;
}
private List<AttributeInterface> _attributeList;
private Map<String, AttributeInterface> _attributeMap;
}