/**
*
*/
package net.frontlinesms.data.domain;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.*;
import net.frontlinesms.FrontlineUtils;
import net.frontlinesms.messaging.sms.internet.SmsInternetService;
import net.frontlinesms.messaging.sms.properties.OptionalRadioSection;
import net.frontlinesms.messaging.sms.properties.OptionalSection;
import net.frontlinesms.messaging.sms.properties.PasswordString;
import net.frontlinesms.messaging.sms.properties.PhoneSection;
/**
* Class encapsulating settings of a {@link SmsInternetService}.
* @author Alex
*/
@Entity
public class SmsInternetServiceSettings {
//> INSTANCE PROPERTIES
/** Unique id for this entity. This is for hibernate usage. */
@SuppressWarnings("unused")
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(unique=true,nullable=false,updatable=false)
private long id;
/** The name of the class of the {@link SmsInternetService} these settings apply to. */
private String serviceClassName;
/** The properties for a {@link SmsInternetService} */
@OneToMany(targetEntity=SmsInternetServiceSettingValue.class, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private final Map<String, SmsInternetServiceSettingValue> properties = new HashMap<String, SmsInternetServiceSettingValue>();
//> CONSTRUCTORS
/** Empty constructor for hibernate */
SmsInternetServiceSettings() {}
/**
* Create a new instance of service settings for the supplied service.
* @param service
*/
public SmsInternetServiceSettings(SmsInternetService service) {
this.serviceClassName = service.getClass().getCanonicalName();
}
//> ACCESSOR METHODS
/**
* Sets the value of a setting.
* FIXME value should not just be an OBJECT - some interface at least i would expect!
* @param key The key of the property to save
* @param value The value of the property to save
*/
public void set(String key, Object value) {
this.properties.put(key, toValue(value));
}
/**
* @param key the key of the property to fetch
* @return the value stored for the supplied key, or <code>null</code> if no value is stored.
*/
public SmsInternetServiceSettingValue get(String key) {
return this.properties.get(key);
}
/** @return the class name of {@link SmsInternetService} implementation that these settings apply to */
public String getServiceClassName() {
return this.serviceClassName;
}
/**
* Get an ordered list of the properties set on this object.
* @return
*/
public Map<String, SmsInternetServiceSettingValue> getProperties() {
return this.properties;
}
//> STATIC HELPER METHODS
/**
* Converts the supplied property value to the string representation of it.
* @param value
* @return
* TODO move to {@link SmsInternetServiceSettingValue}
*/
public static SmsInternetServiceSettingValue toValue(Object value) {
String stringValue;
if (value instanceof String) stringValue = (String)value;
else if (value instanceof Boolean) stringValue = Boolean.toString((Boolean)value);
else if (value instanceof Integer) stringValue = Integer.toString((Integer)value);
else if (value instanceof PasswordString) stringValue = FrontlineUtils.encodeBase64(((PasswordString)value).getValue());
else if (value instanceof OptionalSection) stringValue = Boolean.toString(((OptionalSection)value).getValue());
else if (value instanceof Enum<?>) stringValue = ((Enum<?>)value).name();
else if (value instanceof PhoneSection) stringValue = ((PhoneSection)value).getValue();
else if (value instanceof OptionalRadioSection<?>) {
OptionalRadioSection<?> ors = (OptionalRadioSection<?>) value;
stringValue = ors.getValue().name();
}
else throw new RuntimeException("Unsupported property type: " + value.getClass());
return new SmsInternetServiceSettingValue(stringValue);
}
/**
* Gets a property value from a string, and the canonical name of that class.
* @param property
* @param value
* @return
* TODO move to {@link SmsInternetServiceSettingValue}
*/
@SuppressWarnings("unchecked")
public static Object fromValue(Object property, SmsInternetServiceSettingValue value) {
String stringValue = value.getValue();
if (property.getClass().equals(String.class))
return stringValue;
if (property.getClass().equals(Boolean.class))
return Boolean.parseBoolean(stringValue);
if (property.getClass().equals(Integer.class))
return Integer.parseInt(stringValue);
if (property.getClass().equals(PasswordString.class))
return new PasswordString(FrontlineUtils.decodeBase64(stringValue));
if (property.getClass().equals(OptionalSection.class)) {
return Boolean.parseBoolean(stringValue);
}
if (property.getClass().equals(PhoneSection.class))
return new PhoneSection(stringValue);
if (property.getClass().equals(OptionalRadioSection.class)) {
try {
OptionalRadioSection section = (OptionalRadioSection) property;
Method getValueOf = section.getValue().getClass().getMethod("valueOf", String.class);
Enum enumm = (Enum) getValueOf.invoke(null, stringValue);
return new OptionalRadioSection(enumm);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
try {
if (property.getClass().isEnum()) {
Method getValueOf = property.getClass().getMethod("valueOf", String.class);
Enum enumm = (Enum) getValueOf.invoke(null, stringValue);
return enumm;
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
throw new RuntimeException("Unsupported property type: " + property.getClass());
}
//> GENERATED METHODS
/** @see java.lang.Object#hashCode() */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime
* result
+ ((serviceClassName == null) ? 0 : serviceClassName.hashCode());
return result;
}
/** @see java.lang.Object#equals(java.lang.Object) */
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SmsInternetServiceSettings other = (SmsInternetServiceSettings) obj;
if (serviceClassName == null) {
if (other.serviceClassName != null)
return false;
} else if (!serviceClassName.equals(other.serviceClassName))
return false;
return true;
}
}