package com.im.imjutil.config;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import com.im.imjutil.dao.DAO;
import com.im.imjutil.dao.jpa.JPADAO;
import com.im.imjutil.exception.ValidationException;
import com.im.imjutil.query.Query;
import com.im.imjutil.query.QueryAdapter;
import com.im.imjutil.util.Albums;
import com.im.imjutil.util.Pair;
import com.im.imjutil.validation.Convert;
import com.im.imjutil.validation.Format;
import com.im.imjutil.validation.Validator;
/**
* Classe que define um {@link Properties} em banco de dados utilizando JPA.
* <br>
* Esta utiliza o modelo JPA {@link DatabaseProperty} para persistir
* as propriedades, sendo necessaria a configuracao da mesma no arquivo
* {@code persistence.xml} do projeto de utilizacao.
*
* @author Felipe Zappala
*/
public class DatabaseConfig implements Serializable,
Comparable<DatabaseConfig>, Iterable<Pair<String, String>> {
/** Nome do mapa de propriedades. */
private String map;
/** DAO do modelo de propriedades {@link DatabaseProperty}. */
private DAO<DatabaseProperty> dao;
/** Map das propriedades {@link DatabaseProperty} desse mapa. */
private Map<String, DatabaseProperty> properties;
/** Lista de propriedades excluidas. */
private List<DatabaseProperty> removedProperties;
private static final long serialVersionUID = -7859679267723660812L;
/**
* Construtor padrao do {@link DatabaseConfig}.
*
* @param map O nome do mapa de propriedades.
*/
public DatabaseConfig(String map) {
if (!Validator.isValid(map)) {
throw new ValidationException("Mapa nulo ou invalido");
}
this.map = map;
this.properties = new LinkedHashMap<String, DatabaseProperty>();
this.dao = new JPADAO<DatabaseProperty>(DatabaseProperty.class);
this.removedProperties = new LinkedList<DatabaseProperty>();
}
/**
* Carrega o mapa de propriedades do banco de dados.
*/
public void load() {
this.removedProperties.clear();
this.properties.clear();
Query query = new QueryAdapter(Convert.toString(
"SELECT p FROM DatabaseProperty AS p ",
"WHERE p.map LIKE '", this.map, "' ",
"ORDER BY p.key, p.value"
));
List<DatabaseProperty> propertyList;
propertyList = dao.executeAll(query);
for (DatabaseProperty dp : propertyList) {
this.properties.put(dp.getKey(), dp);
}
}
/**
* Persiste no banco de dados o mapa de propriedades.
*/
public void save() {
dao.removeAll(removedProperties);
dao.addAll(Albums.toList(this.properties.values()));
removedProperties.clear();
}
/**
* Obtem o valor da chave passada. Caso nao encontrado, retorna nulo.
*/
public String get(String key) {
if (Validator.isValid(key)) {
DatabaseProperty dp = properties.get(key);
if (dp != null) {
return dp.getValue();
}
}
return null;
}
/**
* Obtem o valor da chave passada. Caso nao encontrado, retorna nulo.
*/
public String getProperty(String key) {
return get(key);
}
protected static void setDatabaseProperty(DatabaseProperty dp) {
DAO<DatabaseProperty> dao;
dao = new JPADAO<DatabaseProperty>(DatabaseProperty.class);
dao.add(dp);
}
protected static DatabaseProperty getDatabaseProperty(String map, String key) {
DAO<DatabaseProperty> dao;
dao = new JPADAO<DatabaseProperty>(DatabaseProperty.class);
Query query = new QueryAdapter(Convert.toString(
"SELECT p FROM DatabaseProperty AS p ",
"WHERE p.map LIKE '", map, "' AND p.key LIKE '", key, "'"
));
DatabaseProperty dp = dao.execute(query);
if (dp == null) {
dp = new DatabaseProperty();
dp.setMap(map);
dp.setKey(key);
}
return dp;
}
/**
* Obtem estaticamente o valor da chave passada para o mapa indicado.
* Caso nao encontrado, retorna nulo.
*/
public static String getProperty(String map, String key) {
return getDatabaseProperty(map, key).getValue();
}
/**
* Configura estaticamente o valor da chave passada para o mapa indicado.
*/
public static void setProperty(String map, String key, String value) {
DatabaseProperty dp = getDatabaseProperty(map, key);
dp.setValue(value);
setDatabaseProperty(dp);
}
/**
* Obtem estaticamente o valor da chave passada para o mapa indicado.
* Caso nao encontrado, retorna nulo.
*/
public static Properties getProperties(String map) {
if (Validator.isValid(map)) {
DatabaseConfig dc = new DatabaseConfig(map);
dc.load();
return dc.getProperties();
}
return new Properties();
}
/**
* Configura estaticamente as propriedades da chave passada para o
* mapa indicado. Caso as propriedades for nulas, nada sera feito.
*/
public static void setProperties(String map, Properties properties) {
if (Validator.isValid(map, properties)) {
DatabaseConfig dc = new DatabaseConfig(map);
dc.load();
dc.setProperties(properties);
dc.save();
}
}
/**
* Coloca no mapa de propriedades um par de chave e valor.
* Caso a chave for nula esta sera ignorada.
*/
public DatabaseConfig put(String key, String value) {
if (Validator.isValid(key)) {
DatabaseProperty dp = properties.get(key);
if (dp == null) {
dp = new DatabaseProperty();
}
dp.set(map, key, value);
properties.put(key, dp);
}
return this;
}
/**
* Remove a propriedade do mapa da chave passada.
*/
public DatabaseConfig remove(String key) {
if (Validator.isValid(key)) {
removedProperties.add(properties.remove(key));
}
return this;
}
/**
* Remove todas as propridades do mapa.
*/
public void clear() {
this.removedProperties.addAll(this.properties.values());
this.properties.clear();
}
/**
* Retorna um {@link Properties} com as propriedades do mapa.
*/
public Properties getProperties() {
Properties properties = new Properties();
properties.putAll(getMap());
return properties;
}
/**
* Configura um {@link Properties} como as propriedades do mapa.
*/
public void setProperties(Properties properties) {
if (properties != null) {
for (String key : properties.stringPropertyNames()) {
this.put(key, properties.getProperty(key));
}
}
}
/**
* Retorna um {@link Map} com as propriedades do mapa.
*/
public Map<String, String> getMap() {
Map<String, String> map = new LinkedHashMap<String, String>();
for (DatabaseProperty dp : properties.values()) {
map.put(dp.getKey(), dp.getValue());
}
return map;
}
/**
* Configura um {@link Map} como as propriedades do mapa.
*/
public void setMap(Map<String, String> map) {
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
}
/**
* Retorna um {@link SortedMap} com as propriedades do mapa ordenadas.
*/
public SortedMap<String, String> getSortedMap() {
return Albums.sort(getMap());
}
/**
* Retorna uma colecao dos valores do mapa de propriedades.
*/
public Collection<String> values() {
return getMap().values();
}
/**
* Retorna o conjunto das chaves do mapa de propriedades.
*/
public Set<String> keySet() {
return getMap().keySet();
}
/**
* Retorna um iterador em pares {@link Pair} para o mapa de propriedades.
*/
@Override
public Iterator<Pair<String, String>> iterator() {
return Albums.pairIterator(getMap());
}
@Override
public int compareTo(DatabaseConfig another) {
if (another != null) {
return this.map.compareTo(another.map);
}
return -1;
}
public boolean isEmpty() {
return properties.isEmpty();
}
@Override
public int hashCode() {
return this.map.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj != null) {
DatabaseConfig another = (DatabaseConfig) obj;
return this.map.equals(another.map);
}
return false;
}
@Override
public String toString() {
return Format.toString(this);
}
}