blob: 6dc5f13ff60db4d4eaca7b28a418d4226a0d8715 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.usergrid.android.sdk.entities;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.getUUIDProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.setBooleanProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.setFloatProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.setLongProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.setStringProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.setUUIDProperty;
import static org.apache.usergrid.android.sdk.utils.JsonUtils.toJsonString;
import static org.apache.usergrid.android.sdk.utils.MapUtils.newMapWithoutKeys;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.usergrid.android.sdk.UGClient;
import org.apache.usergrid.android.sdk.UGClient.Query;
import org.apache.usergrid.android.sdk.response.ApiResponse;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.JsonNode;
/**
* Models an entity of any type as a local object. Type-specific
* classes are extended from this class.
*
* @see <a href="http://apigee.com/docs/app-services/content/app-services-data-model-1">Usergrid data model documentation</a>
*/
public class Entity {
public final static String PROPERTY_UUID = "uuid";
public final static String PROPERTY_TYPE = "type";
public final static String PROPERTY_NAME = "name";
public final static String PROPERTY_METADATA = "metadata";
public final static String PROPERTY_CREATED = "created";
public final static String PROPERTY_MODIFIED = "modified";
public final static String PROPERTY_ACTIVATED = "activated";
protected Map<String, JsonNode> properties = new HashMap<String, JsonNode>();
private UGClient client;
public static Map<String, Class<? extends Entity>> CLASS_FOR_ENTITY_TYPE = new HashMap<String, Class<? extends Entity>>();
static {
CLASS_FOR_ENTITY_TYPE.put(User.ENTITY_TYPE, User.class);
}
/**
* Default constructor for instantiating an Entity object.
*/
public Entity() {
}
/**
* Constructor for instantiating an Entity with a UGClient.
* @param UGClient a UGClient object
*/
public Entity(UGClient client) {
this.client = client;
}
/**
* Constructor for instantiating an Entity with a UGClient
* and entity type. Normally this is the constructor that should
* be used to model an entity locally.
* @param UGClient a UGClient object
* @param type the 'type' property of the entity
*/
public Entity(UGClient client, String type) {
this.client = client;
setType(type);
}
/**
* Gets the UGClient currently saved in the Entity object.
* @return the UGClient instance
*/
public UGClient getUGClient() {
return client;
}
/**
* Sets the UGClient in the Entity object.
* @param UGClient the UGClient instance
*/
public void setUGClient(UGClient client) {
this.client = client;
}
/**
* Gets the 'type' of the Entity object.
* @return the 'type' of the entity
*/
@JsonIgnore
public String getNativeType() {
return getType();
}
/**
* Adds the type and UUID properties to the Entity object, then
* returns all object properties.
* @return a List object with the entity UUID and type
*/
@JsonIgnore
public List<String> getPropertyNames() {
List<String> properties = new ArrayList<String>();
properties.add(PROPERTY_TYPE);
properties.add(PROPERTY_UUID);
return properties;
}
/**
* Gets the String value of the specified Entity property.
* @param name the name of the property
* @return the property value. Returns null if the property has no value
*/
public String getStringProperty(String name) {
JsonNode val = this.properties.get(name);
return val != null ? val.textValue() : null;
}
/**
* Gets the boolean value of the specified Entity property.
* @param name the name of the property
* @return the property value
*/
public boolean getBoolProperty(String name) {
return this.properties.get(name).booleanValue();
}
/**
* Gets the Int value of the specified Entity property.
* @param name the name of the property
* @return the property value
*/
public int getIntProperty(String name) {
return this.properties.get(name).intValue();
}
/**
* Gets the Double value of the specified Entity property.
* @param name the name of the property
* @return the property value
*/
public double getDoubleProperty(String name) {
return this.properties.get(name).doubleValue();
}
/**
* Gets the long value of the specified Entity property.
* @param name the name of the property
* @return the property value
*/
public long getLongProperty(String name) {
return this.properties.get(name).longValue();
}
/**
* Gets the 'type' property of the Entity object.
* @return the Entity type
*/
public String getType() {
return getStringProperty(PROPERTY_TYPE);
}
/**
* Sets the 'type' property of the Entity object.
* @param type the entity type
*/
public void setType(String type) {
setStringProperty(properties, PROPERTY_TYPE, type);
}
/**
* Gets the 'uuid' property of the Entity object.
* @return the Entity UUID
*/
public UUID getUuid() {
return getUUIDProperty(properties, PROPERTY_UUID);
}
/**
* Sets the 'uuid' property of the Entity object.
* @param uuid the entity UUID
*/
public void setUuid(UUID uuid) {
setUUIDProperty(properties, PROPERTY_UUID, uuid);
}
/**
* Returns a HashMap of the Entity properties without keys.
*
* @return a HashMap object with no keys and the value of the Entity properties
*/
@JsonAnyGetter
public Map<String, JsonNode> getProperties() {
return newMapWithoutKeys(properties, getPropertyNames());
}
/**
* Adds a property to the Entity object.
*
* @param name the name of the property to be set
* @param value the value of the property as a JsonNode object.
* If the value is null, the property will be removed from the object.
* @see <a href="http://jackson.codehaus.org/1.0.1/javadoc/org/codehaus/jackson/JsonNode.html">JsonNode</a>
*/
@JsonAnySetter
public void setProperty(String name, JsonNode value) {
if (value == null) {
properties.remove(name);
} else {
properties.put(name, value);
}
}
/**
* Removes all properties from the Entity object, then adds multiple properties.
*
* @param newProperties a Map object that contains the
* property names as keys and their values as values.
* Property values must be JsonNode objects. If the value
* is null, the property will be removed from the object.
* @see <a href="http://jackson.codehaus.org/1.0.1/javadoc/org/codehaus/jackson/JsonNode.html">JsonNode</a>
*/
public void setProperties(Map<String,JsonNode> newProperties) {
properties.clear();
Set<String> keySet = newProperties.keySet();
Iterator<String> keySetIter = keySet.iterator();
while( keySetIter.hasNext() ) {
String key = keySetIter.next();
setProperty(key, newProperties.get(key));
}
}
/**
* Adds a property to the Entity object with a String value.
*
* @param name the name of the property to be set
* @param value the String value of the property
*/
public void setProperty(String name, String value) {
setStringProperty(properties, name, value);
}
/**
* Adds a property to the Entity object with a boolean value.
*
* @param name the name of the property to be set
* @param value the boolean value of the property
*/
public void setProperty(String name, boolean value) {
setBooleanProperty(properties, name, value);
}
/**
* Adds a property to the Entity object with a long value.
*
* @param name the name of the property to be set
* @param value the long value of the property
*/
public void setProperty(String name, long value) {
setLongProperty(properties, name, value);
}
/**
* Adds a property to the Entity object with a int value.
*
* @param name the name of the property to be set
* @param value the int value of the property
*/
public void setProperty(String name, int value) {
setProperty(name, (long) value);
}
/**
* Adds a property to the Entity object with a float value.
*
* @param name the name of the property to be set
* @param value the float value of the property
*/
public void setProperty(String name, float value) {
setFloatProperty(properties, name, value);
}
/**
* Returns the Entity object as a JSON-formatted string
*/
@Override
public String toString() {
return toJsonString(this);
}
/**
* @y.exclude
*/
public <T extends Entity> T toType(Class<T> t) {
return toType(this, t);
}
/**
* @y.exclude
*/
public static <T extends Entity> T toType(Entity entity, Class<T> t) {
if (entity == null) {
return null;
}
T newEntity = null;
if (entity.getClass().isAssignableFrom(t)) {
try {
newEntity = (t.newInstance());
if ((newEntity.getNativeType() != null)
&& newEntity.getNativeType().equals(entity.getType())) {
newEntity.properties = entity.properties;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return newEntity;
}
/**
* @y.exclude
*/
public static <T extends Entity> List<T> toType(List<Entity> entities,
Class<T> t) {
List<T> l = new ArrayList<T>(entities != null ? entities.size() : 0);
if (entities != null) {
for (Entity entity : entities) {
T newEntity = entity.toType(t);
if (newEntity != null) {
l.add(newEntity);
}
}
}
return l;
}
/**
* Fetches the current state of the entity from the server and saves
* it in the Entity object. Runs synchronously.
*
* @return an ApiResponse object
*/
public ApiResponse fetch() {
ApiResponse response = new ApiResponse();
String type = this.getType();
UUID uuid = this.getUuid(); // may be NULL
String entityId = null;
if ( uuid != null ) {
entityId = uuid.toString();
} else {
if (User.isSameType(type)) {
String username = this.getStringProperty(User.PROPERTY_USERNAME);
if ((username != null) && (username.length() > 0)) {
entityId = username;
} else {
String error = "no_username_specified";
this.client.writeLog(error);
response.setError(error);
//response.setErrorCode(error);
return response;
}
} else {
String name = this.getStringProperty(PROPERTY_NAME);
if ((name != null) && (name.length() > 0)) {
entityId = name;
} else {
String error = "no_name_specified";
this.client.writeLog(error);
response.setError(error);
//response.setErrorCode(error);
return response;
}
}
}
Query q = this.client.queryEntitiesRequest("GET", null, null,
this.client.getOrganizationId(), this.client.getApplicationId(), type, entityId);
response = q.getResponse();
if (response.getError() != null) {
this.client.writeLog("Could not get entity.");
} else {
if ( response.getUser() != null ) {
this.addProperties(response.getUser().getProperties());
} else if ( response.getEntityCount() > 0 ) {
Entity entity = response.getFirstEntity();
this.setProperties(entity.getProperties());
}
}
return response;
}
/**
* Saves the Entity object as an entity on the server. Any
* conflicting properties on the server will be overwritten. Runs synchronously.
*
* @return an ApiResponse object
*/
public ApiResponse save() {
ApiResponse response = null;
UUID uuid = this.getUuid();
boolean entityAlreadyExists = false;
if (client.isUuidValid(uuid)) {
entityAlreadyExists = true;
}
// copy over all properties except some specific ones
Map<String,Object> data = new HashMap<String,Object>();
Set<String> keySet = this.properties.keySet();
Iterator<String> keySetIter = keySet.iterator();
while(keySetIter.hasNext()) {
String key = keySetIter.next();
if (!key.equals(PROPERTY_METADATA) &&
!key.equals(PROPERTY_CREATED) &&
!key.equals(PROPERTY_MODIFIED) &&
!key.equals(PROPERTY_ACTIVATED) &&
!key.equals(PROPERTY_UUID)) {
data.put(key, this.properties.get(key));
}
}
if (entityAlreadyExists) {
// update it
response = this.client.updateEntity(uuid.toString(), data);
} else {
// create it
response = this.client.createEntity(data);
}
if ( response.getError() != null ) {
this.client.writeLog("Could not save entity.");
} else {
if (response.getEntityCount() > 0) {
Entity entity = response.getFirstEntity();
this.setProperties(entity.getProperties());
}
}
return response;
}
/**
* Deletes the entity on the server.
*
* @return an ApiResponse object
*/
public ApiResponse destroy() {
ApiResponse response = new ApiResponse();
String type = getType();
String uuidAsString = null;
UUID uuid = getUuid();
if ( uuid != null ) {
uuidAsString = uuid.toString();
} else {
String error = "Error trying to delete object: No UUID specified.";
this.client.writeLog(error);
response.setError(error);
//response.setErrorCode(error);
return response;
}
response = this.client.removeEntity(type, uuidAsString);
if( (response != null) && (response.getError() != null) ) {
this.client.writeLog("Entity could not be deleted.");
} else {
this.properties.clear();
}
return response;
}
/**
* Adds multiple properties to the Entity object. Pre-existing properties will
* be preserved, unless there is a conflict, then the pre-existing property
* will be overwritten.
*
* @param properties a Map object that contains the
* property names as keys and their values as values.
* Property values must be JsonNode objects. If the value
* is null, the property will be removed from the object.
* @see <a href="http://jackson.codehaus.org/1.0.1/javadoc/org/codehaus/jackson/JsonNode.html">JsonNode</a>
*/
public void addProperties(Map<String, JsonNode> properties) {
Set<String> keySet = properties.keySet();
Iterator<String> keySetIter = keySet.iterator();
while( keySetIter.hasNext() ) {
String key = keySetIter.next();
setProperty(key, properties.get(key));
}
}
/**
* Creates a connection between two entities.
*
* @param connectType the type of connection
* @param targetEntity the UUID of the entity to connect to
* @return an ApiResponse object
*/
public ApiResponse connect(String connectType, Entity targetEntity) {
return this.client.connectEntities(this.getType(),
this.getUuid().toString(),
connectType,
targetEntity.getUuid().toString());
}
/**
* Destroys a connection between two entities.
*
* @param connectType the type of connection
* @param targetEntity the UUID of the entity to disconnect from
* @return an ApiResponse object
*/
public ApiResponse disconnect(String connectType, Entity targetEntity) {
return this.client.disconnectEntities(this.getType(),
this.getUuid().toString(),
connectType,
targetEntity.getUuid().toString());
}
}