package org.ff4j.commonsconf;
/*
* #%L
* ff4j-archaius
* %%
* Copyright (C) 2013 - 2016 FF4J
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
import org.ff4j.exception.InvalidPropertyTypeException;
import org.ff4j.property.Property;
import org.ff4j.property.store.InMemoryPropertyStore;
import org.ff4j.property.store.PropertyStore;
import org.ff4j.property.util.PropertyFactory;
import org.ff4j.utils.Util;
/**
* Bridge from {@link PropertyStore} to commons configuration {@link Configuration}.
*
* @author Cedrick Lunven (@clunven)</a>
*/
public class FF4jConfiguration extends AbstractConfiguration {
/** Target delimiter for multivalued. */
private static final String DELIMITER = ",";
/**
* Source
*/
private PropertyStore ff4jStore;
/**
* Default constructor.
*/
public FF4jConfiguration() {
}
/**
* Initialized with default value.
*
* @param ff4jPropertyStore
* default store.
*/
public FF4jConfiguration(PropertyStore ff4jPropertyStore) {
this.ff4jStore = ff4jPropertyStore;
}
/** {@inheritDoc} */
@Override
public Configuration subset(String prefix) {
Map < String, Property<?>> myProps = ff4jStore().readAllProperties();
PropertyStore ps = new InMemoryPropertyStore();
for (Map.Entry< String, Property<?>> prop : myProps.entrySet()) {
if (prop.getKey().startsWith(prefix)) {
ps.createProperty(prop.getValue());
}
}
return new FF4jConfiguration(ps);
}
/** {@inheritDoc} */
@Override
public Properties getProperties(String key) {
Properties props = new Properties();
if (key == null) return props;
Map < String, Property<?>> myProps = ff4jStore().readAllProperties();
for (Map.Entry< String, Property<?>> prop : myProps.entrySet()) {
if (prop.getKey().startsWith(key)) {
props.put(prop.getKey(), prop.getValue().getValue());
}
}
return props;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return ff4jStore().isEmpty();
}
/** {@inheritDoc} */
@Override
public boolean containsKey(String key) {
if (key == null) return false;
return ff4jStore().existProperty(key);
}
/** {@inheritDoc} */
@Override
public void addProperty(String key, Object value) {
ff4jStore().createProperty(PropertyFactory.createProperty(key, value));
}
/** {@inheritDoc} */
@Override
protected void addPropertyDirect(String key, Object value) {
ff4jStore().createProperty(PropertyFactory.createProperty(key, value));
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override
public void setProperty(String key, Object value) {
if (!ff4jStore.existProperty(key)) {
addProperty(key, value);
}
Property<Object> ap = (Property<Object>) ff4jStore().readProperty(key);
ap.setValue(String.valueOf(value));
ff4jStore().updateProperty(ap);
}
/** {@inheritDoc} */
@Override
public void clearProperty(String key) {
ff4jStore().deleteProperty(key);
}
/** {@inheritDoc} */
@Override
public void clear() {
ff4jStore().clear();
}
/** {@inheritDoc} */
@Override
public Object getProperty(String key) {
return ff4jStore().readProperty(key).getValue();
}
/** {@inheritDoc} */
@Override
public Iterator<String> getKeys(String prefix) {
Set< String > setOfNames = ff4jStore().listPropertyNames();
Set< String > results = new HashSet<String>();
if (setOfNames != null && setOfNames.size() > 0) {
for (String name : setOfNames) {
if (name.startsWith(prefix)) {
results.add(name);
}
}
}
return results.iterator();
}
/**
* The read will raise PropertyNotFound if not exist, null could be cast in any type.
*
* @param key
* current property name
* @return
* property value
*/
private Object getValue(String key) {
Util.assertHasLength(key);
return ff4jStore().readProperty(key).asString();
}
/** {@inheritDoc} */
@Override
public Iterator<String> getKeys() {
Set< String > init = new HashSet<String>();
Set < String > result = ff4jStore().listPropertyNames();
return (result == null) ? init.iterator() : result.iterator();
}
/**
* {@inheritDoc}
*
* Use the object :
* <li> To handle 'null' and avoid NPE on unboxing
* <li> To raise classCast if invalid property type...
*/
@Override
public boolean getBoolean(String key) {
String value = (String) getValue(key);
if (!Boolean.TRUE.toString().equals(value.toLowerCase()) &&
!Boolean.FALSE.toString().equals(value.toLowerCase()) ) {
throw new InvalidPropertyTypeException("Cannot create Boolean from " + value);
}
return new Boolean(value).booleanValue();
}
/** {@inheritDoc} */
@Override
public Boolean getBoolean(String key, Boolean defaultValue) {
return ff4jStore().existProperty(key) ? getBoolean(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return ff4jStore().existProperty(key) ? getBoolean(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public byte getByte(String key) {
String value = null;
try {
value = (String) getValue(key);
return Byte.parseByte(value);
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Byte from " + value, nbe);
}
}
/** {@inheritDoc} */
@Override
public byte getByte(String key, byte defaultValue) {
return ff4jStore().existProperty(key) ? getByte(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public Byte getByte(String key, Byte defaultValue) {
return ff4jStore().existProperty(key) ? getByte(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public double getDouble(String key) {
try {
return new Double((String) getValue(key)).doubleValue();
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Double from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public double getDouble(String key, double defaultValue) {
return ff4jStore().existProperty(key) ? getDouble(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public Double getDouble(String key, Double defaultValue) {
return ff4jStore().existProperty(key) ? getDouble(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public float getFloat(String key) {
try {
return new Float((String) getValue(key)).floatValue();
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Float from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public float getFloat(String key, float defaultValue) {
return ff4jStore().existProperty(key) ? getFloat(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public Float getFloat(String key, Float defaultValue) {
return ff4jStore().existProperty(key) ? getFloat(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public int getInt(String key) {
try {
return new Integer((String) getValue(key)).intValue();
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Integer from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public int getInt(String key, int defaultValue) {
return ff4jStore().existProperty(key) ? getInt(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public Integer getInteger(String key, Integer defaultValue) {
return ff4jStore().existProperty(key) ? getInt(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public long getLong(String key) {
try {
return new Long((String) getValue(key)).longValue();
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Long from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public Long getLong(String key, Long defaultValue) {
return ff4jStore().existProperty(key) ? getLong(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public long getLong(String key, long defaultValue) {
return ff4jStore().existProperty(key) ? getLong(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public short getShort(String key) {
try {
return new Short((String) getValue(key)).shortValue();
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create Short from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public short getShort(String key, short defaultValue) {
return ff4jStore().existProperty(key) ? getShort(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public Short getShort(String key, Short defaultValue) {
return ff4jStore().existProperty(key) ? getShort(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public BigDecimal getBigDecimal(String key) {
try {
return new BigDecimal((String) getValue(key));
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create BigDecimal from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) {
return ff4jStore().existProperty(key) ? getBigDecimal(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public BigInteger getBigInteger(String key) {
try {
return new BigInteger((String) getValue(key));
} catch(NumberFormatException nbe) {
throw new InvalidPropertyTypeException("Cannot create BigInteger from " + getValue(key), nbe);
}
}
/** {@inheritDoc} */
@Override
public BigInteger getBigInteger(String key, BigInteger defaultValue) {
return ff4jStore().existProperty(key) ? getBigInteger(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public String getString(String key) {
return (String) getValue(key);
}
/** {@inheritDoc} */
@Override
public String getString(String key, String defaultValue) {
return ff4jStore().existProperty(key) ? getString(key) : defaultValue;
}
/** {@inheritDoc} */
@Override
public List<Object> getList(String key) {
return new ArrayList<Object>(
Arrays.asList(
((String) getValue(key)).split(DELIMITER)));
}
/** {@inheritDoc} */
@Override
public List<Object> getList(String key, List<?> defaultValue) {
if (ff4jStore().existProperty(key)) return getList(key);
return new ArrayList<Object>(defaultValue);
}
/** {@inheritDoc} */
@Override
public String[] getStringArray(String key) {
return getList(key).toArray(new String[0]);
}
/**
* Read FF4J Store from its attribute.
*
* @return
* current ff4j store.
*/
public PropertyStore ff4jStore() {
if (ff4jStore == null) {
throw new IllegalStateException("Cannot load property from store as not initialized please set 'ff4jStore' property");
}
return getFf4jStore();
}
/**
* Getter accessor for attribute 'ff4jStore'.
*
* @return
* current value of 'ff4jStore'
*/
public PropertyStore getFf4jStore() {
return ff4jStore;
}
/**
* Setter accessor for attribute 'ff4jStore'.
* @param ff4jStore
* new value for 'ff4jStore '
*/
public void setFf4jStore(PropertyStore ff4jStore) {
this.ff4jStore = ff4jStore;
}
}