/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Cyclos 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.services.settings; import java.util.LinkedHashMap; import java.util.Map; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.accounts.transactions.TransferListener; import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException; import nl.strohalm.cyclos.entities.settings.LocalSettings; import nl.strohalm.cyclos.entities.settings.LocalSettings.CsvRecordSeparator; import nl.strohalm.cyclos.entities.settings.LocalSettings.CsvStringQuote; import nl.strohalm.cyclos.entities.settings.LocalSettings.CsvValueSeparator; import nl.strohalm.cyclos.entities.settings.LocalSettings.DatePattern; import nl.strohalm.cyclos.entities.settings.LocalSettings.DecimalInputMethod; import nl.strohalm.cyclos.entities.settings.LocalSettings.Language; import nl.strohalm.cyclos.entities.settings.LocalSettings.MemberResultDisplay; import nl.strohalm.cyclos.entities.settings.LocalSettings.NumberLocale; import nl.strohalm.cyclos.entities.settings.LocalSettings.Precision; import nl.strohalm.cyclos.entities.settings.LocalSettings.SortOrder; import nl.strohalm.cyclos.entities.settings.LocalSettings.TimePattern; import nl.strohalm.cyclos.entities.settings.LocalSettings.TransactionNumber; import nl.strohalm.cyclos.entities.settings.Setting; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsChangeListener; import nl.strohalm.cyclos.entities.settings.events.LocalSettingsEvent; import nl.strohalm.cyclos.services.access.ChannelServiceLocal; import nl.strohalm.cyclos.services.customization.MemberCustomFieldServiceLocal; import nl.strohalm.cyclos.utils.FileUnits; import nl.strohalm.cyclos.utils.TextFormat; import nl.strohalm.cyclos.utils.TimePeriod.Field; import nl.strohalm.cyclos.utils.conversion.CoercionConverter; import nl.strohalm.cyclos.utils.conversion.Converter; import nl.strohalm.cyclos.utils.conversion.IdConverter; import nl.strohalm.cyclos.utils.conversion.TimeZoneConverter; import nl.strohalm.cyclos.utils.validation.CompareToValidation; import nl.strohalm.cyclos.utils.validation.InvalidError; import nl.strohalm.cyclos.utils.validation.PropertyValidation; import nl.strohalm.cyclos.utils.validation.RequiredError; import nl.strohalm.cyclos.utils.validation.RequiredValidation; import nl.strohalm.cyclos.utils.validation.ValidationError; import nl.strohalm.cyclos.utils.validation.Validator; import org.apache.commons.lang.StringUtils; /** * Local settings handler * @author luis */ public class LocalSettingsHandler extends BaseSettingsHandler<LocalSettings, LocalSettingsChangeListener> { private ChannelServiceLocal channelService; private MemberCustomFieldServiceLocal memberCustomFieldService; protected LocalSettingsHandler() { super(Setting.Type.LOCAL, LocalSettings.class); } public void setChannelServiceLocal(final ChannelServiceLocal channelService) { this.channelService = channelService; } public void setMemberCustomFieldServiceLocal(final MemberCustomFieldServiceLocal memberCustomFieldService) { this.memberCustomFieldService = memberCustomFieldService; } @Override protected Map<String, Converter<?>> createConverters() { final Map<String, Converter<?>> localConverters = new LinkedHashMap<String, Converter<?>>(); localConverters.put("applicationName", CoercionConverter.instance(String.class)); localConverters.put("applicationUsername", CoercionConverter.instance(String.class)); localConverters.put("rootUrl", CoercionConverter.instance(String.class)); localConverters.put("language", CoercionConverter.instance(Language.class)); localConverters.put("numberLocale", CoercionConverter.instance(NumberLocale.class)); localConverters.put("precision", CoercionConverter.instance(Precision.class)); localConverters.put("highPrecision", CoercionConverter.instance(Precision.class)); localConverters.put("decimalInputMethod", CoercionConverter.instance(DecimalInputMethod.class)); localConverters.put("datePattern", CoercionConverter.instance(DatePattern.class)); localConverters.put("timePattern", CoercionConverter.instance(TimePattern.class)); localConverters.put("timeZone", TimeZoneConverter.instance()); localConverters.put("containerUrl", CoercionConverter.instance(String.class)); localConverters.put("maxIteratorResults", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxPageResults", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxAjaxResults", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxUploadSize", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxUploadUnits", CoercionConverter.instance(FileUnits.class)); localConverters.put("maxImageWidth", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxImageHeight", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxThumbnailWidth", CoercionConverter.instance(Integer.TYPE)); localConverters.put("maxThumbnailHeight", CoercionConverter.instance(Integer.TYPE)); localConverters.put("referenceLevels", CoercionConverter.instance(Integer.TYPE)); localConverters.put("smsEnabled", CoercionConverter.instance(Boolean.TYPE)); localConverters.put("csvUseHeader", CoercionConverter.instance(Boolean.TYPE)); localConverters.put("csvRecordSeparator", CoercionConverter.instance(CsvRecordSeparator.class)); localConverters.put("csvValueSeparator", CoercionConverter.instance(CsvValueSeparator.class)); localConverters.put("csvStringQuote", CoercionConverter.instance(CsvStringQuote.class)); localConverters.put("cyclosId", CoercionConverter.instance(String.class)); localConverters.put("sendSmsWebServiceUrl", CoercionConverter.instance(String.class)); localConverters.put("smsChannelName", CoercionConverter.instance(String.class)); localConverters.put("smsCustomFieldId", IdConverter.instance()); localConverters.put("transactionNumber.prefix", CoercionConverter.instance(String.class)); localConverters.put("transactionNumber.padLength", CoercionConverter.instance(Integer.TYPE)); localConverters.put("transactionNumber.suffix", CoercionConverter.instance(String.class)); localConverters.put("emailRequired", CoercionConverter.instance(Boolean.TYPE)); localConverters.put("emailUnique", CoercionConverter.instance(Boolean.TYPE)); localConverters.put("brokeringExpirationPeriod.number", CoercionConverter.instance(Integer.class)); localConverters.put("brokeringExpirationPeriod.field", CoercionConverter.instance(Field.class)); localConverters.put("deleteMessagesOnTrashAfter.number", CoercionConverter.instance(Integer.class)); localConverters.put("deleteMessagesOnTrashAfter.field", CoercionConverter.instance(Field.class)); localConverters.put("deletePendingRegistrationsAfter.number", CoercionConverter.instance(Integer.class)); localConverters.put("deletePendingRegistrationsAfter.field", CoercionConverter.instance(Field.class)); localConverters.put("memberSortOrder", CoercionConverter.instance(SortOrder.class)); localConverters.put("memberResultDisplay", CoercionConverter.instance(MemberResultDisplay.class)); localConverters.put("adDescriptionFormat", CoercionConverter.instance(TextFormat.class)); localConverters.put("messageFormat", CoercionConverter.instance(TextFormat.class)); localConverters.put("schedulingHour", CoercionConverter.instance(Integer.TYPE)); localConverters.put("schedulingMinute", CoercionConverter.instance(Integer.TYPE)); localConverters.put("transferListenerClass", CoercionConverter.instance(String.class)); localConverters.put("maxChargebackTime.number", CoercionConverter.instance(Integer.class)); localConverters.put("maxChargebackTime.field", CoercionConverter.instance(Field.class)); localConverters.put("chargebackDescription", CoercionConverter.instance(String.class)); localConverters.put("showCountersInAdCategories", CoercionConverter.instance(Boolean.TYPE)); return localConverters; } @Override protected Validator createValidator() { final Validator localValidator = new Validator("settings.local"); localValidator.property("applicationName").required().length(1, 100); localValidator.property("applicationUsername").required().length(1, 100); localValidator.property("rootUrl").required().url(); localValidator.property("language").required(); localValidator.property("numberLocale").required(); localValidator.property("precision").required().between(0, 6); localValidator.property("highPrecision").required().between(0, 6); localValidator.property("decimalInputMethod").required(); localValidator.property("datePattern").required(); localValidator.property("timePattern").required(); localValidator.property("containerUrl").url(); localValidator.property("maxIteratorResults").required().positive(); localValidator.property("maxPageResults").required().positiveNonZero(); localValidator.property("maxAjaxResults").required().positiveNonZero(); localValidator.property("maxUploadSize").required().positiveNonZero(); localValidator.property("maxUploadUnits").required(); localValidator.property("maxImageWidth").required().between(10, 10000); localValidator.property("maxImageHeight").required().between(10, 10000); localValidator.property("maxThumbnailWidth").required().between(10, 200); localValidator.property("maxThumbnailHeight").required().between(10, 200); localValidator.property("referenceLevels").required().anyOf(3, 5); localValidator.property("csvRecordSeparator").required(); localValidator.property("csvValueSeparator").required(); localValidator.property("csvStringQuote").required(); localValidator.property("cyclosId").length(0, 100); localValidator.property("transactionNumber.prefix").length(0, 50); localValidator.property("transactionNumber.padLength").add(new PropertyValidation() { private static final long serialVersionUID = -6756132904303474845L; @Override public ValidationError validate(final Object object, final Object property, final Object value) { LocalSettings settings = (LocalSettings) object; if (settings.getTransactionNumber() != null && settings.getTransactionNumber().isEnabled()) { ValidationError required = RequiredValidation.instance().validate(object, property, value); if (required != null) { return required; } ValidationError greaterThan = CompareToValidation.greaterEquals(1).validate(object, property, value); if (greaterThan != null) { return greaterThan; } ValidationError lessThan = CompareToValidation.lessEquals(20).validate(object, property, value); if (lessThan != null) { return lessThan; } } return null; } }); localValidator.property("transactionNumber.suffix").length(0, 50); localValidator.property("brokeringExpirationPeriod.number").between(0, 999); localValidator.property("brokeringExpirationPeriod.field").required(); localValidator.property("deleteMessagesOnTrashAfter.number").between(0, 999); localValidator.property("deleteMessagesOnTrashAfter.field").required(); localValidator.property("deletePendingRegistrationsAfter.number").between(0, 999); localValidator.property("deletePendingRegistrationsAfter.field").required(); localValidator.property("memberSortOrder").required(); localValidator.property("memberResultDisplay").required(); localValidator.property("adDescriptionFormat").required(); localValidator.property("messageFormat").required(); localValidator.property("schedulingHour").required().between(0, 23); localValidator.property("schedulingMinute").required().between(0, 59); localValidator.property("transferListenerClass").instanceOf(TransferListener.class); localValidator.property("maxChargebackTime.number").between(0, 999); localValidator.property("maxChargebackTime.field").required(); localValidator.property("chargebackDescription").required(); localValidator.property("sendSmsWebServiceUrl").key("settings.local.sms.sendSmsWebServiceUrl").length(0, 256).add(new PropertyValidation() { private static final long serialVersionUID = 0L; @Override public ValidationError validate(final Object object, final Object name, final Object value) { final LocalSettings settings = (LocalSettings) object; if (StringUtils.isEmpty((String) value) && settings.isSmsEnabled()) { return new RequiredError(); } else { return null; } } }); localValidator.property("smsChannelName").key("settings.local.sms.channel").add(new PropertyValidation() { private static final long serialVersionUID = 0L; @Override public ValidationError validate(final Object object, final Object name, final Object value) { final LocalSettings settings = (LocalSettings) object; if (!settings.isSmsEnabled()) { return null; } if (StringUtils.isEmpty((String) value) && settings.isSmsEnabled()) { return new RequiredError(); } boolean channelFound = false; for (final Channel channel : channelService.listNonBuiltin()) { if (channel.getInternalName().equals(value)) { channelFound = true; break; } } return channelFound ? null : new InvalidError(); } }); localValidator.property("smsCustomFieldId").key("settings.local.sms.customField").add(new PropertyValidation() { private static final long serialVersionUID = 0L; @Override public ValidationError validate(final Object object, final Object property, final Object value) { final LocalSettings settings = (LocalSettings) object; final Long id = (Long) value; if (!settings.isSmsEnabled()) { return null; } if (id == null || id.intValue() < 0 && settings.isSmsEnabled()) { return new RequiredError(); } try { // Load and ensure it's a valid member custom field memberCustomFieldService.load(id); return null; } catch (final EntityNotFoundException e) { return new InvalidError(); } } }); return localValidator; } @Override protected void notifyListener(final LocalSettingsChangeListener listener, final LocalSettings settings) { listener.onLocalSettingsUpdate(new LocalSettingsEvent(settings)); } @Override protected LocalSettings read() { final LocalSettings localSettings = super.read(); // Validate the transaction number TransactionNumber transactionNumber = localSettings.getTransactionNumber(); if (transactionNumber != null) { if (transactionNumber.getPadLength() <= 0) { localSettings.setTransactionNumber(null); } else { transactionNumber.setEnabled(true); } } return localSettings; } }