/* * 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.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; 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.FieldError; import com.agiletec.aps.system.common.entity.model.IApsEntity; import com.agiletec.aps.system.common.entity.model.attribute.util.BaseAttributeValidationRules; import com.agiletec.aps.system.common.entity.model.attribute.util.IAttributeValidationRules; import com.agiletec.aps.system.common.entity.parse.attribute.AttributeHandlerInterface; import com.agiletec.aps.system.common.searchengine.IndexableAttributeInterface; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.lang.ILangManager; /** * This abstract class must be used when implementing Entity Attributes. * @author W.Ambu - E.Santoboni */ public abstract class AbstractAttribute implements AttributeInterface, Serializable { private static final Logger _logger = LoggerFactory.getLogger(AbstractAttribute.class); @Override public boolean isMultilingual() { return false; } @Override public boolean isTextAttribute() { return false; } @Override public String getName() { return _name; } @Override public String getDescription() { return _description; } @Override public void setDescription(String description) { this._description = description; } @Override public void setName(String name) { this._name = name; } /** * The returned type corresponds to the attribute code as found in the declaration * of the attribute type. */ @Override public String getType() { return _type; } @Override public void setType(String typeName) { this._type = typeName; } @Override public void setDefaultLangCode(String langCode) { this._defaultLangCode = langCode; } /** * Return the code of the default language. * @return The code of the default language. */ public String getDefaultLangCode() { return _defaultLangCode; } /** * Set up the language to use in the rendering process. * @param langCode The code of the rendering language. */ @Override public void setRenderingLang(String langCode) { _renderingLangCode = langCode; } /** * Return the code of the language used in the rendering process. * @return The code of the language used for rendering. */ public String getRenderingLang() { return _renderingLangCode; } @Override @Deprecated public boolean isSearcheable() { return this.isSearchable(); } @Override @Deprecated public void setSearcheable(boolean searchable) { this.setSearchable(searchable); } /** * Test whether the attribute is searchable (using a query on the DB) or not. The * information held by a searchable attribute is replicated in an appropriate table * used for SQL queries. * @return True if the attribute is a searchable one. */ @Override public boolean isSearchable() { return _searchable; } /** * Set up the searchable status of an attribute. When set to 'true' then the * information held by the current attribute is replicated in an appropriate table * used for SQL queries. * @param searchable True if the attribute is of searchable type, false otherwise. */ @Override public void setSearchable(boolean searchable) { this._searchable = searchable; } @Override public Object getAttributePrototype() { AbstractAttribute clone = null; try { Class attributeClass = Class.forName(this.getClass().getName()); clone = (AbstractAttribute) attributeClass.newInstance(); clone.setName(this.getName()); clone.setDescription(this.getDescription()); clone.setType(this.getType()); clone.setSearchable(this.isSearchable()); clone.setDefaultLangCode(this.getDefaultLangCode()); clone.setIndexingType(this.getIndexingType()); clone.setParentEntity(this.getParentEntity()); AttributeHandlerInterface handler = (AttributeHandlerInterface) this.getHandler().getAttributeHandlerPrototype(); clone.setHandler(handler); if (this.getDisablingCodes() != null) { String[] disablingCodes = new String[this.getDisablingCodes().length]; for (int i = 0; i < this.getDisablingCodes().length; i++) { disablingCodes[i] = this.getDisablingCodes()[i]; } clone.setDisablingCodes(disablingCodes); } if (this.getRoles() != null) { String[] roles = new String[this.getRoles().length]; for (int i = 0; i < this.getRoles().length; i++) { roles[i] = this.getRoles()[i]; } clone.setRoles(roles); } clone.setValidationRules(this.getValidationRules().clone()); clone.setLangManager(this.getLangManager()); clone.setAttributeManagerClassName(this.getAttributeManagerClassName()); } catch (Throwable t) { String message = "Error detected while creating the attribute prototype '" + this.getName() + "' type '" + this.getType() + "'"; _logger.error("Error detected while creating the attribute prototype '{}' type '{}'", this.getName(), this.getType(), t); throw new RuntimeException(message, t); } return clone; } @Override public void setAttributeConfig(Element attributeElement) throws ApsSystemException { try { String name = this.extractXmlAttribute(attributeElement, "name", true); this.setName(name); String description = this.extractXmlAttribute(attributeElement, "description", false); this.setDescription(description); String searchable = this.extractXmlAttribute(attributeElement, "searchable", false); //to guaranted compatibility with previsous version of Entando 4.0.1 *** Start Block if (null == searchable) { searchable = this.extractXmlAttribute(attributeElement, "searcheable", false); } //to guaranted compatibility with previsous version of Entando 4.0.1 *** End Block this.setSearchable(null != searchable && searchable.equalsIgnoreCase("true")); IAttributeValidationRules validationCondition = this.getValidationRules(); validationCondition.setConfig(attributeElement); //to guaranted compatibility with previsous version of jAPS 2.0.12 *** Start Block String required = this.extractXmlAttribute(attributeElement, "required", false); if (null != required && required.equalsIgnoreCase("true")) { this.setRequired(true); } //to guaranted compatibility with previsous version of jAPS 2.0.12 *** End Block String indexingType = this.extractXmlAttribute(attributeElement, "indexingtype", false); if (null != indexingType) { this.setIndexingType(indexingType); } else { this.setIndexingType(IndexableAttributeInterface.INDEXING_TYPE_NONE); } Element disablingCodesElements = attributeElement.getChild("disablingCodes"); if (null != disablingCodesElements) { String[] disablingCodes = this.extractValues(disablingCodesElements, "code"); this.setDisablingCodes(disablingCodes); } else { //to guaranted compatibility with previsous version of jAPS 2.0.12 *** Start Block String disablingCodesStr = this.extractXmlAttribute(attributeElement, "disablingCodes", false); if (disablingCodesStr != null) { String[] disablingCodes = disablingCodesStr.split(","); this.setDisablingCodes(disablingCodes); } //to guaranted compatibility with previsous version of jAPS 2.0.12 *** End Block } Element rolesElements = attributeElement.getChild("roles"); if (null != rolesElements) { String[] roles = this.extractValues(rolesElements, "role"); this.setRoles(roles); } } catch (Throwable t) { String message = "Error detected while creating the attribute config '" + this.getName() + "' type '" + this.getType() + "'"; _logger.error("Error detected while creating the attribute config '{}' type '{}'", this.getName(), this.getType(), t); throw new RuntimeException(message, t); } } private String[] extractValues(Element elements, String subElementName) { if (null == elements) { return null; } List<String> values = new ArrayList<String>(); List<Element> subElements = elements.getChildren(subElementName); if (null == subElements || subElements.isEmpty()) { return null; } for (int i = 0; i < subElements.size(); i++) { String text = subElements.get(i).getText(); if (null != text && text.trim().length() > 0) { values.add(text.trim()); } } String[] array = new String[values.size()]; for (int i = 0; i < values.size(); i++) { array[i] = values.get(i); } return array; } @Override public Element getJDOMConfigElement() { Element configElement = this.createRootElement(this.getTypeConfigElementName()); if (null != this.getDescription() && this.getDescription().trim().length() > 0) { configElement.setAttribute("description", this.getDescription()); } if (this.isSearchable()) { configElement.setAttribute("searchable", "true"); } if (null != this.getValidationRules() && !this.getValidationRules().isEmpty()) { Element validationElement = this.getValidationRules().getJDOMConfigElement(); configElement.addContent(validationElement); } if (null != this.getIndexingType() && !this.getIndexingType().equals(IndexableAttributeInterface.INDEXING_TYPE_NONE)) { configElement.setAttribute("indexingtype", this.getIndexingType()); } this.addArrayElement(configElement, this.getDisablingCodes(), "disablingCodes", "code"); this.addArrayElement(configElement, this.getRoles(), "roles", "role"); return configElement; } protected Element createRootElement(String elementName) { Element attributeElement = new Element(elementName); attributeElement.setAttribute("name", this.getName()); attributeElement.setAttribute("attributetype", this.getType()); return attributeElement; } private void addArrayElement(Element configElement, String[] values, String elementName, String subElementName) { if (null != values) { Element arrayElem = new Element(elementName); for (int i = 0; i < values.length; i++) { Element stringElem = new Element(subElementName); stringElem.setText(values[i]); arrayElem.addContent(stringElem); } configElement.addContent(arrayElem); } } protected String getTypeConfigElementName() { return "attribute"; } /** * Get the attribute matching the given criteria from a XML string. * @param currElement The element where to extract the value of the attribute from * @param attributeName Name of the requested attribute. * @param required Select a mandatory condition of the attribute to search for. * @return The value of the requested attribute. * @throws ApsSystemException when a attribute declared mandatory is not present in the given * XML element. */ protected String extractXmlAttribute(Element currElement, String attributeName, boolean required) throws ApsSystemException { String value = currElement.getAttributeValue(attributeName); if (required && value == null) { throw new ApsSystemException("Attribute '" + attributeName + "' not found in the tag <" + currElement.getName() + ">"); } return value; } @Deprecated(/** DO NOTHING : to guaranted compatibility with previsous version of jAPS 2.0.12 */) protected void addListElementTypeConfig(Element configElement) {} @Override public String getIndexingType() { return _indexingType; } @Override public void setIndexingType(String indexingType) { this._indexingType = indexingType; } @Override public boolean isSimple() { return true; } @Override public boolean isRequired() { return this.getValidationRules().isRequired(); } @Override public void setRequired(boolean required) { this.getValidationRules().setRequired(required); } @Override public IApsEntity getParentEntity() { return _parentEntity; } @Override public void setParentEntity(IApsEntity parentEntity) { this._parentEntity = parentEntity; } @Override public AttributeHandlerInterface getHandler() { return _handler; } @Override public void setHandler(AttributeHandlerInterface handler) { this._handler = handler; } @Override public void disable(String disablingCode) { if (_disablingCodes != null && disablingCode != null) { for (int i = 0; i < _disablingCodes.length; i++) { if (disablingCode.equals(_disablingCodes[i])) { this._active = false; return; } } } } @Override public void activate() { this._active = true; } @Override public boolean isActive() { return _active; } @Override public void setDisablingCodes(String[] disablingCodes) { this._disablingCodes = disablingCodes; } @Override public String[] getDisablingCodes() { return this._disablingCodes; } @Override public String[] getRoles() { return _roles; } @Override public void setRoles(String[] roles) { this._roles = roles; } protected IAttributeValidationRules getValidationRuleNewIntance() { return new BaseAttributeValidationRules(); } @Override public IAttributeValidationRules getValidationRules() { if (null == this._validationRules) { this.setValidationRules(this.getValidationRuleNewIntance()); } return _validationRules; } @Override public void setValidationRules(IAttributeValidationRules validationRules) { this._validationRules = validationRules; } protected AbstractJAXBAttribute createJAXBAttribute(String langCode) { if (null == this.getValue()) { return null; } AbstractJAXBAttribute jaxbAttribute = this.getJAXBAttributeInstance(); jaxbAttribute.setDescription(this.getDescription()); jaxbAttribute.setName(this.getName()); jaxbAttribute.setType(this.getType()); if (null != this.getRoles() && this.getRoles().length > 0) { List<String> roles = Arrays.asList(this.getRoles()); jaxbAttribute.setRoles(roles); } return jaxbAttribute; } protected abstract AbstractJAXBAttribute getJAXBAttributeInstance(); @Override public void valueFrom(AbstractJAXBAttribute jaxbAttribute) { this.setName(jaxbAttribute.getName()); } @Override public DefaultJAXBAttributeType getJAXBAttributeType() { DefaultJAXBAttributeType jaxbAttributeType = this.getJAXBAttributeTypeInstance(); jaxbAttributeType.setName(this.getName()); jaxbAttributeType.setDescription(this.getDescription()); jaxbAttributeType.setType(this.getType()); if (this.isSearchable()) { jaxbAttributeType.setSearchable(true); } if (null != this.getIndexingType() && this.getIndexingType().equalsIgnoreCase(IndexableAttributeInterface.INDEXING_TYPE_TEXT)) { jaxbAttributeType.setIndexable(true); } if (null != this.getRoles() && this.getRoles().length > 0) { List<String> roles = Arrays.asList(this.getRoles()); jaxbAttributeType.setRoles(roles); } if (null != this.getValidationRules() && !this.getValidationRules().isEmpty()) { jaxbAttributeType.setValidationRules(this.getValidationRules()); } return jaxbAttributeType; } protected DefaultJAXBAttributeType getJAXBAttributeTypeInstance() { return new DefaultJAXBAttributeType(); } @Override public List<AttributeFieldError> validate(AttributeTracer tracer) { List<AttributeFieldError> errors = new ArrayList<AttributeFieldError>(); try { if (this.getStatus().equals(Status.INCOMPLETE)) { errors.add(new AttributeFieldError(this, FieldError.INVALID, tracer)); } else { IAttributeValidationRules validationRules = this.getValidationRules(); if (null == validationRules) { return errors; } List<AttributeFieldError> validationRulesErrors = validationRules.validate(this, tracer, this.getLangManager()); if (null != validationRulesErrors) { errors.addAll(validationRulesErrors); } } } catch (Throwable t) { _logger.error("Error validating Attribute '{}'", this.getName(), t); throw new RuntimeException("Error validating Attribute '" + this.getName() + "'", t); } return errors; } @Override public String getAttributeManagerClassName() { return _attributeManagerClassName; } public void setAttributeManagerClassName(String attributeManagerClassName) { this._attributeManagerClassName = attributeManagerClassName; } protected ILangManager getLangManager() { return _langManager; } public void setLangManager(ILangManager langManager) { this._langManager = langManager; } private String _name; private String _description; private String _type; private String _defaultLangCode; private String _renderingLangCode; private boolean _searchable; private String _indexingType; private IApsEntity _parentEntity; private transient AttributeHandlerInterface _handler; private String[] _disablingCodes; private String[] _roles; private boolean _active = true; private IAttributeValidationRules _validationRules; private String _attributeManagerClassName; private ILangManager _langManager; }