/*****************************************************************************************
Infosistema - OpenBaas
Copyright(C) 2002-2014 Infosistema, S.A.
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
www.infosistema.com
info@openbaas.com
Av. José Gomes Ferreira, 11 3rd floor, s.34
Miraflores
1495-139 Algés Portugal
****************************************************************************************/
package infosistema.openbaas.dataaccess.models;
import infosistema.openbaas.data.Metadata;
import infosistema.openbaas.data.models.User;
import infosistema.openbaas.middleLayer.SessionMiddleLayer;
import infosistema.openbaas.utils.Const;
import infosistema.openbaas.utils.Log;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import org.apache.commons.pool.impl.GenericKeyedObjectPool.Config;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class UserModel extends ModelAbstract {
// *** CONTRUCTORS *** //
private UserModel() {
JedisPoolConfig poolConf = new JedisPoolConfig();
poolConf.setMaxActive(2);
poolConf.setMaxWait(10000);
pool = new JedisPool(poolConf, Const.getRedisGeneralServer(),Const.getRedisGeneralPort());
}
private static UserModel instance = null;
public static UserModel getInstance() {
if (instance == null) instance = new UserModel();
return instance;
}
// *** PRIVATE *** //
private JedisPool pool;
private static final String ALL = "all";
private static BasicDBObject dataProjection = null;
private static BasicDBObject dataProjectionMetadata = null;
// *** PROTECTED *** //
@Override
protected DBCollection getCollection(String appId) {
return super.getCollection(String.format(APP_DATA_COLL_FORMAT, appId));
}
@Override
protected BasicDBObject getDataProjection(boolean getMetadata, List<String> toShow, List<String> toHide) {
if (getMetadata) {
if (dataProjectionMetadata == null) {
dataProjectionMetadata = super.getDataProjection(new BasicDBObject(), true);
dataProjectionMetadata.append(_USER_ID, 0);
//Users
//TODO ERROR dataProjectionMetadata.append(_SN_SOCIALNETWORK_ID, 0);
dataProjectionMetadata.append(User.BASE_LOCATION_OPTION, 0);
dataProjectionMetadata.append(User.HASH, 0);
dataProjectionMetadata.append(User.EMAIL, 0);
dataProjectionMetadata.append(User.ALIVE, 0);
dataProjectionMetadata.append(User.SALT, 0);
}
return dataProjectionMetadata;
} else {
if (dataProjection == null) {
dataProjection = super.getDataProjection(new BasicDBObject(), false);
dataProjection.append(_USER_ID, 0);
//Users
//TODO ERROR dataProjection.append(User.SN_SOCIALNETWORK_ID, 0);
dataProjection.append(User.BASE_LOCATION_OPTION, 0);
dataProjection.append(User.HASH, 0);
dataProjection.append(User.EMAIL, 0);
dataProjection.append(User.ALIVE, 0);
dataProjection.append(User.SALT, 0);
}
return dataProjection;
}
}
// *** CONSTANTS *** //
// *** KEYS *** //
private static final String USER_FIELD_KEY_FORMAT = "app:%s:user:%s:%s";
private static final String APP_DATA_COLL_FORMAT = "app%sdata";
private String getKey(String appId, String field, String id) {
return String.format(USER_FIELD_KEY_FORMAT, appId, field, id);
}
private String getUserKey(String appId, String userId) {
return getKey(appId, ALL, userId);
}
// *** CREATE *** //
public JSONObject createUser(String appId, String userId, Map<String, String> userFields, Map<String, String> extraMetadata) {
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
try {
String userKey = getUserKey(appId, userId);
JSONObject metadata = getMetadaJSONObject(getMetadataCreate(userId, extraMetadata));
JSONObject geolocation = getGeolocation(metadata);
JSONObject obj = new JSONObject();
if (!jedis.exists(userKey)) {
for (String key : userFields.keySet()) {
if (userFields.get(key) != null) {
String value = userFields.get(key);
if (User.isIndexedField(key)) {
jedis.set(getKey(appId, key, value), userId);
}
jedis.hset(userKey, key, value);
obj.put(key, value);
}
}
obj.put(_USER_ID, userId);
obj.put(_ID, userId);
if (metadata != null){
Map<?,?> metaMap = convertJsonToMap(metadata);
obj.put(_METADATA, metaMap);
jedis.hset(userKey, _METADATA, metadata.toString());
}
if (geolocation != null){
Map<?,?> metaGeo = convertJsonToMap(geolocation);
obj.put(_GEO, metaGeo);
jedis.hset(userKey, _GEO, geolocation.toString());
}
super.insert(appId, obj, metadata, geolocation);
}
return obj;
} catch (Exception e) {
Log.error("", this, "createUser", "Error creating User", e);
} finally {
pool.returnResource(jedis);
}
return null;
}
// *** UPDATE *** //
/**
* Updates the user, depending on the fields. If the only field sent by the
* request was alive, then only the alive field is updated.
*
* @param appId
* @param userId
* @param email
* @param hash
* @param salt
* @param alive
* @throws UnsupportedEncodingException
*/
public JSONObject updateUser(String appId, String userId, Map<String, String> fields, Map<String, String> extraMetadata) {
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
try {
String userKey = getUserKey(appId, userId);
if (jedis.exists(userKey)) {
JSONObject obj = new JSONObject();
for (String key : fields.keySet()) {
if (fields.get(key) != null) {
String value = fields.get(key);
if (User.isIndexedField(key)) {
String oldValue = jedis.hget(userKey, key);
if (oldValue != null) jedis.del(getKey(appId, key, oldValue));
jedis.set(getKey(appId, key, value), userId);
}
jedis.hset(userKey, key, value);
super.updateDocumentValue(appId, userId, key, value);
obj.put(key, value);
}
}
}
updateMetadata(appId, userId, getMetadataUpdate(userId, extraMetadata));
return getUser(appId, userId, true);
} catch (Exception e) {
Log.error("", this, "updateUser", "Error updating User", e);
} finally {
pool.returnResource(jedis);
}
return null;
}
@Override
protected synchronized void updateMetadata(String appId, String userId, Map<String, String> metadata) {
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
try {
JSONObject geolocation = getGeolocation(getMetadaJSONObject(metadata));
String userKey = getUserKey(appId, userId);
if (metadata != null){
String str = null;
try {
str = jedis.hget(userKey, _METADATA);
} catch (Exception e) {
Log.error("", this, "erro", "********erro no hget************hget("+userKey+" "+_METADATA+")",e);
}
Map<String, String> m = null;
if(str!=null){
JSONObject json = new JSONObject(str);
m = convertJsonToMap2(json);
m.putAll(metadata);
}
if (m!=null){
jedis.hset(userKey, _METADATA, new JSONObject(m).toString());
}
else {
jedis.hset(userKey, _METADATA, new JSONObject(metadata).toString());
}
}
if (geolocation != null){
jedis.hset(userKey, _GEO, geolocation.toString());
}
} catch (Exception e) {
Log.error("", this, "err", "********update metadata************",e);
}
finally {
pool.returnResource(jedis);
}
super.updateMetadata(appId, userId, metadata);
}
public void updateUserLocation(String appId, String userId, String location) {
try {
if (location != null) {
super.updateDocumentValue(appId, userId, Const.LOCATION, location);
super.updateMetadata(appId, userId, Metadata.getNewMetadata(location));
}
JSONObject geolocation = getGeolocation(new JSONObject("{location: \"" + location + "\"}"));
if (geolocation != null) super.updateDocumentValue(appId, userId, _GEO, geolocation);
} catch (JSONException e) {
Log.error("", this, "updateUserLocation", "Error updating user location.", e);
}
}
// *** GET LIST *** //
// *** GET *** //
/**
* Checks if user is present in the app:{appId}:all:users and if it is returns
* its fields
*
* @param appId
* @param userId
* @return
*/
public JSONObject getUser(String appId, String userId, boolean getMetadata) {
SessionModel sessionModel = SessionModel.getInstance();
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
Map<String, String> userFields = null;
try {
String userKey = getUserKey(appId, userId);
userFields = jedis.hgetAll(userKey);
Boolean online = sessionModel.isUserOnline(userId);
userFields.put("online", online.toString());
if (!getMetadata) userFields.remove(_METADATA);
if (userFields == null || userFields.size() <= 0)
return null;
return getJSonObject(userFields);
} catch (Exception e) {
Log.error("", this, "getUser", "Error getting user", e);
return null;
} finally {
pool.returnResource(jedis);
}
}
public String getUserField(String appId, String userId, String field) {
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
try {
String userKey = getUserKey(appId, userId);
return jedis.hget(userKey, field);
} catch (Exception e) {
Log.error("", this, "getUserField", "Error getting user field", e);
return null;
} finally {
pool.returnResource(jedis);
}
}
public String getUserIdUsingSocialInfo(String appId, String socialId, String socialNetwork) {
return getUserIdUsingField(appId, User.SOCIAL_NETWORK_ID(socialNetwork), socialId);
}
public String getUserIdUsingUserName(String appId, String userName) {
return getUserIdUsingField(appId, User.USER_NAME, userName);
}
public String getUserIdUsingEmail(String appId, String email) {
return getUserIdUsingField(appId, User.EMAIL, email);
}
private String getUserIdUsingField(String appId, String field, String value) {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
} catch (Exception e){
Log.error("", this, "get jedis", "Error get jedis", e);
}
try {
return jedis.get(getKey(appId, field, value));
} catch (Exception e){
Log.error("", this, "getUserIdUsingField", "Error getting User Id", e);
} finally {
pool.returnResource(jedis);
}
return null;
}
// *** DELETE *** //
// *** EXISTS *** //
public Boolean userIdExists(String appId, String userId) {
return fieldExists(appId, ALL, userId);
}
public Boolean userEmailExists(String appId, String email) {
return fieldExists(appId, User.EMAIL, email);
}
public Boolean userNameExists(String appId, String userName) {
return fieldExists(appId, User.USER_NAME, userName);
}
public Boolean socialUserExists(String appId, String socialId, String socialNetwork) {
return fieldExists(appId, User.SOCIAL_NETWORK_ID(socialNetwork), socialId);
}
private Boolean fieldExists(String appId, String field, String value) {
Jedis jedis = pool.getResource();
jedis.auth(Const.getRedisGeneralPass());
Boolean exists = false;
try {
exists = jedis.exists(getKey(appId, field, value));
} catch (Exception e){
Log.error("", this, "userIdExistsInApp", "Error getting User", e);
} finally {
pool.returnResource(jedis);
}
return exists;
}
// *** OTHERS *** //
}