Java tutorial
/* * Copyright 2012-2015 Erwin Mller <erwin.mueller@deventm.org> * * This file is part of sscontrol-profile. * * sscontrol-profile is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * sscontrol-profile 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 Affero General Public License * for more details. * * You should have received a copy of the GNU Affero General Public License * along with sscontrol-profile. If not, see <http://www.gnu.org/licenses/>. */ package com.anrisoftware.sscontrol.profile.service; import static java.lang.String.format; import static org.apache.commons.collections.map.PredicatedMap.decorate; import groovy.lang.GString; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; import java.text.Format; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import javax.inject.Inject; import org.apache.commons.collections.functors.NotNullPredicate; import org.apache.commons.collections.set.UnmodifiableSet; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.codehaus.groovy.runtime.InvokerHelper; import org.joda.time.Duration; import com.anrisoftware.globalpom.format.duration.DurationFormatFactory; import com.anrisoftware.globalpom.format.locale.LocaleFormatFactory; import com.anrisoftware.propertiesutils.ContextProperties; import com.anrisoftware.sscontrol.core.api.ProfileProperties; import com.anrisoftware.sscontrol.core.api.ServiceException; /** * @see ProfileProperties * * @author Erwin Mueller, erwin.mueller@deventm.org * @since 1.0 */ @SuppressWarnings("serial") class ProfilePropertiesImpl implements ProfileProperties { @Inject private ProfilePropertiesImplLogger log; @Inject private DurationFormatFactory durationFormatFactory; @Inject private LocaleFormatFactory localeFormatFactory; private final Map<String, Object> properties; @SuppressWarnings("unchecked") ProfilePropertiesImpl() { this.properties = decorate(new HashMap<String, Object>(), NotNullPredicate.INSTANCE, NotNullPredicate.INSTANCE); } /** * Returns the profile property with the specified name. * * @param name * the {@link String} name. * * @return the property value. */ public Object propertyMissing(String name) { return properties.get(name); } /** * Adds the profile property with the specified name and value. * * @param name * the profile {@link String} name. * * @param args * the profile value. */ public Object methodMissing(String name, Object args) { @SuppressWarnings("unchecked") List<Object> argsList = InvokerHelper.asList(args); if (argsList.size() == 0) { putProperty(name, true); } else if (argsList.size() == 1 && argsList.get(0) instanceof GString) { putProperty(name, argsList.get(0).toString()); } else if (argsList.size() == 1) { putProperty(name, argsList.get(0)); } else { putProperty(name, argsList); } return null; } @Override public Object get(String key) { return properties.get(key); } @Override public Object get(String key, Object... args) { String value = (String) get(key); return value == null ? null : format(value, args); } @Override public List<String> getList(String key) { if (!containsKey(key)) { return null; } String value = get(key).toString(); return Arrays.asList(StringUtils.split(value, ",")); } @Override public void put(String key, Object property) { putProperty(key, property); } private void putProperty(String name, Object value) { properties.put(name, value); log.propertyAdded(this, name, value); } @SuppressWarnings("unchecked") @Override public Set<String> getKeys() { return UnmodifiableSet.decorate(properties.keySet()); } @Override public boolean containsKey(String key) { return properties.containsKey(key); } /** * Checks that the specified profile key is known for the profile. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return {@code true} if the profile key is known in the profile or the * default properties. */ public boolean containsKey(String key, ContextProperties defaults) { if (properties.containsKey(key)) { return true; } else { return defaults.getProperty(key) != null; } } /** * Returns a profile property. * * @param key * the property {@link String} key. * * @return the value of the profile property. * * @throws ServiceException * if the profile property was not found. */ public Object profileProperty(String key) throws ServiceException { Object property = get(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a profile property. If the profile property was not set return * the default value from the default properties. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return the value of the profile property. * * @throws ServiceException * if the profile property was not found. */ public Object profileProperty(String key, ContextProperties defaults) throws ServiceException { Object property = get(key); if (property != null) { return property; } property = defaults.getProperty(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a typed profile property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param format * the {@link Format} to parse the type. * * @param defaults * default {@link ContextProperties} properties. * * @return the value of the profile property. * * @throws ServiceException * if the profile property was not found. * * @throws ParseException * if the property cannot be parsed to the type. * */ @SuppressWarnings("unchecked") public <T> T profileTypedProperty(String key, Format format, ContextProperties defaults) throws ServiceException, ParseException { Object property = get(key); if (property != null) { String string = property.toString(); return (T) format.parseObject(string.toString()); } property = defaults.getTypedProperty(key, format); if (property != null) { return (T) property; } throw log.noProfileProperty(this, key); } /** * Returns a duration profile property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link Duration} value of the profile property. * * @throws ServiceException * if the profile property was not found. * * @throws ParseException * if the profile property could not be parsed to a duration. */ public Duration profileDurationProperty(String key, ContextProperties defaults) throws ServiceException, ParseException { Object property = get(key); if (property != null) { return durationFormatFactory.create().parse(property.toString()); } property = defaults.getProperty(key); if (property != null) { return durationFormatFactory.create().parse(property.toString()); } throw log.noProfileProperty(this, key); } /** * Returns a profile number property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link Number} value of the profile property. * * @throws ServiceException * if the profile property was not found. * * @throws ClassCastException * if the profile property is not a number. */ public Number profileNumberProperty(String key, ContextProperties defaults) throws ServiceException { Number property = (Number) get(key); if (property != null) { return property; } property = defaults.getNumberProperty(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a profile boolean property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link Boolean} value of the profile property. * * @throws ServiceException * if the profile property was not found. * * @throws ClassCastException * if the profile property is not a number. */ public Boolean profileBooleanProperty(String key, ContextProperties defaults) throws ServiceException { Boolean property = (Boolean) get(key); if (property != null) { return property; } property = defaults.getBooleanProperty(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a list profile property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link List} value of the profile property. * * @throws ServiceException * if the profile property was not found. */ public List<String> profileListProperty(String key, ContextProperties defaults) throws ServiceException { List<String> property = getList(key); if (property != null) { return property; } property = defaults.getListProperty(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a list profile property. If the profile property was not set * return the default value from the default properties. * * @param key * the property {@link String} key. * * @param separatorChars * the characters used as the delimiters, {@code null} splits on * whitespace. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link List} value of the profile property. * * @throws ServiceException * if the profile property was not found. */ public List<String> profileListProperty(String key, String separatorChars, ContextProperties defaults) throws ServiceException { List<String> property = getList(key); if (property != null) { return property; } property = defaults.getListProperty(key, separatorChars); if (property != null) { return property; } throw log.noProfileProperty(this, key); } /** * Returns a list profile property. If the profile property was not set * return the default value from the default properties. The specified * format is used to create the list items. * * @param key * the property {@link String} key. * * @param format * the {@link Format} that is used to parse the string properties * and create the list items. * * @param defaults * default {@link ContextProperties} properties. * * @return the {@link List} value of the profile property. * * @throws ServiceException * if the profile property was not found. * * @throws ParseException * if the profile property could not be parsed. */ public <T> List<T> profileTypedListProperty(String key, Format format, ContextProperties defaults) throws ServiceException, ParseException { List<String> values = getList(key); if (values != null) { return asTypedList(values, format); } List<T> property = defaults.getTypedListProperty(key, format, ","); if (property != null) { return property; } throw log.noProfileProperty(this, key); } @SuppressWarnings("unchecked") private <T> List<T> asTypedList(List<String> property, Format format) throws ParseException { List<T> list = new ArrayList<T>(); for (String value : property) { list.add((T) format.parseObject(value)); } return list; } /** * Returns the profile directory path property. If the profile property was * not set return the default value from the default properties. * * @param key * the key of the profile property. * * @param p * default {@link ContextProperties} properties. * * @return the profile directory {@link File} path. * * @throws ServiceException * if the profile property was not found. */ public File profileDirProperty(String key, ContextProperties defaults) throws ServiceException { Object path = profileProperty(key, defaults); if (path instanceof File) { return (File) path; } else { return new File(path.toString()); } } /** * Returns the profile path property. If the profile property was not set * return the default value from the default properties. If the path is not * absolute then it is assume to be under the specified parent directory. * * @param key * the key of the profile property. * * @param parent * the parent {@link File} directory. * * @param p * default {@link ContextProperties} properties. * * @return the profile file {@link File} path. * * @throws ServiceException * if the profile property was not found. */ public File profileFileProperty(String key, File parent, ContextProperties defaults) throws ServiceException { Object value = profileProperty(key, defaults); File path; if (value instanceof File) { path = (File) value; } else { path = new File(value.toString()); } return path.isAbsolute() ? path : new File(parent, path.getPath()); } /** * Returns the profile resource URI property. If the profile property was * not set return the default value from the default properties. * * @param key * the key of the profile property. * * @param p * default {@link ContextProperties} properties. * * @return the profile resource {@link URI}. * * @throws ServiceException * if the profile property was not found. */ public URI profileURIProperty(String key, ContextProperties defaults) throws ServiceException { Object path = profileProperty(key, defaults); if (path instanceof File) { return ((File) path).toURI(); } if (path instanceof URI) { return (URI) path; } try { return new URI(path.toString()); } catch (URISyntaxException e) { return new File(path.toString()).toURI(); } } /** * Returns the profile resource locale property. If the profile property was * not set return the default value from the default properties. * * @param key * the key of the profile property. * * @param p * default {@link ContextProperties} properties. * * @return the profile resource {@link Locale}. * * @throws ServiceException * if the profile property was not found. * * @throws ParseException * if the locale could not be parsed. */ public Locale profileLocaleProperty(String key, ContextProperties defaults) throws ServiceException, ParseException { Locale property = (Locale) get(key); if (property != null) { return property; } String tag = defaults.getProperty(key); if (tag != null) { return localeFormatFactory.create().parse(tag); } throw log.noProfileProperty(this, key); } /** * Returns the profile resource character set property. If the profile * property was not set return the default value from the default * properties. * * @param key * the key of the profile property. * * @param p * default {@link ContextProperties} properties. * * @return the profile resource {@link Charset}. * * @throws ServiceException * if the profile property was not found. */ public Charset profileCharsetProperty(String key, ContextProperties defaults) throws ServiceException { Charset property = (Charset) get(key); if (property != null) { return property; } property = defaults.getCharsetProperty(key); if (property != null) { return property; } throw log.noProfileProperty(this, key); } @Override public String toString() { return new ToStringBuilder(this).toString(); } }