Java tutorial
/* * Copyright (C) 2005-2012 BetaCONCEPT Limited * * This file is part of Astroboa. * * Astroboa 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. * * Astroboa 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 Astroboa. If not, see <http://www.gnu.org/licenses/>. */ package org.betaconceptframework.astroboa.model.impl; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.collections.CollectionUtils; import org.betaconceptframework.astroboa.api.model.ComplexCmsProperty; import org.betaconceptframework.astroboa.api.model.SimpleCmsProperty; import org.betaconceptframework.astroboa.api.model.definition.ComplexCmsPropertyDefinition; import org.betaconceptframework.astroboa.api.model.definition.SimpleCmsPropertyDefinition; import org.betaconceptframework.astroboa.api.model.exception.CmsException; import org.betaconceptframework.astroboa.api.model.exception.MultipleOccurenceException; import org.betaconceptframework.astroboa.api.model.exception.SingleOccurenceException; import org.betaconceptframework.astroboa.api.model.io.ResourceRepresentationType; import org.betaconceptframework.astroboa.context.AstroboaClientContextHolder; import org.betaconceptframework.astroboa.model.lazy.LazyLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Gregory Chomatas (gchomatas@betaconcept.com) * @author Savvas Triantafyllou (striantafyllou@betaconcept.com) * */ public abstract class SimpleCmsPropertyImpl<T, D extends SimpleCmsPropertyDefinition<T>, P extends ComplexCmsProperty<? extends ComplexCmsPropertyDefinition, ? extends ComplexCmsProperty<?, ?>>> extends CmsPropertyImpl<D, P> implements SimpleCmsProperty<T, D, P>, Serializable { /** * */ private static final long serialVersionUID = 2691160236131731929L; // Real data for simple value protected List<T> values = new ArrayList<T>(); @Override public void setPropertyDefinition(D propertyDefinition) { super.setPropertyDefinition(propertyDefinition); if (this.propertyDefinition != null) { if (this.propertyDefinition.getValueType() != getValueType()) throw new CmsException("Incompatible value types. Definition " + this.propertyDefinition.getValueType() + " , Simple Cms Property : " + getValueType()); } } public void addSimpleTypeValue(T value) { if (propertyDefinition != null) { //In case this property is single value call method setSimpleTypeValue if (CollectionUtils.isNotEmpty(values) && isSingle()) { setSimpleTypeValue(value); return; } //In case value is null value it will not be added //in the list. Savvas was adding null values in the list and we should check whether // this is required for some reason if (value != null) { if (values == null) { values = new ArrayList<T>(); } if (propertyDefinition.isMultiple()) { values.add(value); } else { // allows only one value if (values.size() > 0) { values.set(0, value); } else { values.add(value); } } } } else { throw new CmsException( "Definition of property: '" + getFullPath() + "' is null. Value will not be added"); } } /** * In cases where this property is an enumeration then all values must * be within the provided value range * @param asList */ public void checkValues() { if (CollectionUtils.isNotEmpty(values)) { if (getPropertyDefinition() == null) { throw new CmsException("Found no property definition attached to this property " + getName()); } for (T value : values) { if (!getPropertyDefinition().isValueValid(value)) { throw new CmsException(generateMessageForInvalidValue(value)); } } } } abstract protected String generateMessageForInvalidValue(T value); public T getSimpleTypeValue() throws MultipleOccurenceException { throwExceptionIfPropertyIsMultiple(); if (CollectionUtils.isEmpty(values)) return null; return values.get(0); } public List<T> getSimpleTypeValues() throws SingleOccurenceException { //Throw an exception only if property is single value and list contains //more than one values. if (CollectionUtils.isNotEmpty(values) && values.size() > 1) throwExceptionIfPropertyIsSingleValue(); return values; } /** * Remove value located in index provided * @param index */ public void removeSimpleTypeValue(int index) throws SingleOccurenceException { //Check if property is single value //and index is not 0 if (index != 0) throwExceptionIfPropertyIsSingleValue(); if (values != null) { values.remove(index); } } /** * Property is considered single valued. In any case * just update or insert ONLY the first value in list * @param value */ public void setSimpleTypeValue(T value) throws MultipleOccurenceException { throwExceptionIfPropertyIsMultiple(); if (value != null) { if (values == null) { values = new ArrayList<T>(); } if (values.size() > 0) { values.set(0, value); } else { values.add(value); } } else { if (values != null) { values.clear(); } } } public void setSimpleTypeValues(List<T> values) throws SingleOccurenceException { if (values == null) { //Throw and catch an exception to log the stack trace in order to //be able to check who provided a null list try { throw new Exception(); } catch (Exception e) { final Logger logger = LoggerFactory.getLogger(getClass()); logger.warn( "A null list is provided as values for property {}. An empty list will be created instead " + getFullPath(), e); this.values.clear(); } } else { this.values = values; } //Check if list contains more than value //and this property is single value if (CollectionUtils.isNotEmpty(this.values) && this.values.size() > 1) throwExceptionIfPropertyIsSingleValue(); } public boolean hasNoValues() { return values == null || values.isEmpty(); } public boolean hasValues() { return !hasNoValues(); } @Override public void removeValues() { if (values != null) { values.clear(); } } //Override deserialization process to inject //property definition private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { //Deserialize bean normally ois.defaultReadObject(); //Inject Property definition LazyLoader lazyLoader = AstroboaClientContextHolder.getLazyLoaderForClient(authenticationToken); if (lazyLoader != null) { lazyLoader.activateClientContextForAuthenticationToken(authenticationToken); setPropertyDefinition((D) lazyLoader.getDefinitionService().getCmsDefinition(fullPropertyDefinitionPath, ResourceRepresentationType.DEFINITION_INSTANCE, false)); } } @Override public boolean swapValues(int from, int to) { if (values == null) { return false; } if (from == to || from < 0 || to < 0) { return false; } try { Collections.swap(values, from, to); resetPaths(); return true; } catch (Exception e) { //Ignore exception return false; } } @Override public boolean changePositionOfValue(int from, int to) { if (values == null) { return false; } if (from == to || from < 0 || to < 0 || from > values.size() - 1 || to > values.size()) { return false; } try { values.add(to, values.get(from)); if (from > to) { from++; } values.remove(from); resetPaths(); return true; } catch (Exception e) { //Ignore exception return false; } } @Override public T getFirstValue() { if (values == null || values.isEmpty()) { return null; } return values.get(0); } /** * Useful for retrieving all values, * regardless of the cardinality of the property. * * This way you do not have to know apriori property cardinality, * as in cases of {@link #getSimpleTypeValue()} or {@link #getSimpleTypeValues()}, * if you do not want an exception to be thrown * * @return */ public List<T> getValues() { return values; } }