/************************************************************************
* Copyright (c) 2015 IoT-Solutions e.U.
*
* 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.
************************************************************************/
package iot.jcypher.domain.genericmodel;
import iot.jcypher.domain.genericmodel.internal.InternalAccess;
import iot.jcypher.domain.internal.DomainAccess;
import iot.jcypher.domain.internal.IIntDomainAccess;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
public class DomainObject {
private DOType domainObjectType;
private Object rawObject;
public DomainObject(DOType doType) {
this(doType, true);
}
DomainObject(DOType doType, boolean toNursery) {
super();
if (doType == null)
throw new RuntimeException("a domain object must be constructed with a domain object type");
this.domainObjectType = doType;
if (toNursery)
this.domainObjectType.getDomainModel().addNurseryObject(getRawObject(), this);
}
/**
* Answer the type of this generic domain object
* @return a DOType
*/
public DOType getDomainObjectType() {
return domainObjectType;
}
/**
* Set a field (attribute) value
* @param fieldName
* @param value
*/
public void setFieldValue(String fieldName, Object value) {
DOField field = this.domainObjectType.getFieldByName(fieldName);
if (field == null)
throw new RuntimeException("field: " + fieldName + " not found in: " + this.domainObjectType.getName());
if (field.getComponentTypeName() != null)
throw new RuntimeException("field: " + fieldName + " is a list field, use list field accessors instead ");
Object val = value;
if (value instanceof DomainObject)
val = ((DomainObject)value).getRawObject();
field.setValue(this.getRawObject(), val);
}
/**
* Add a value to a list or array field
* @param fieldName
* @param value
*/
public void addListFieldValue(String fieldName, Object value) {
Object val = value;
if (value instanceof DomainObject)
val = ((DomainObject)value).getRawObject();
Object lst = getFieldValue(fieldName, true); // internal
DOField fld = getDomainObjectType().getFieldByName(fieldName);
String ctn = fld.getComponentTypeName();
Class<?> clazz;
try {
clazz = getDomainObjectType().getDomainModel().getClassForName(ctn);
if (!clazz.isAssignableFrom(val.getClass()))
throw new RuntimeException("value must be of type or subtype of: [" + clazz.getName() + "]");
lst = tryInitListOrArray(lst, fld, clazz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (lst instanceof List<?>) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)lst;
list.add(val);
} else if (lst != null && lst.getClass().isArray()) {
int len = Array.getLength(lst);
Object array = Array.newInstance(clazz, len + 1);
for (int i = 0; i < len; i++) {
Array.set(array, i, Array.get(lst, i));
}
Array.set(array, len, val);
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (lst == null)
throw new RuntimeException("field: [" + fieldName + "] has not been initialized as list or array");
}
}
/**
* Add a value to a list or array field at the given index.
* <br/>Shifts the element currently at that position
* (if any) and any subsequent elements to the right (adds one to their
* indices).
* @param fieldName
* @param index
* @param value
*/
public void insertListFieldValue(String fieldName, int index, Object value) {
Object val = value;
if (value instanceof DomainObject)
val = ((DomainObject)value).getRawObject();
Object lst = getFieldValue(fieldName, true); // internal
DOField fld = getDomainObjectType().getFieldByName(fieldName);
String ctn = fld.getComponentTypeName();
Class<?> clazz;
try {
clazz = getDomainObjectType().getDomainModel().getClassForName(ctn);
if (!clazz.isAssignableFrom(val.getClass()))
throw new RuntimeException("value must be of type or subtype of: [" + clazz.getName() + "]");
lst = tryInitListOrArray(lst, fld, clazz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (lst instanceof List<?>) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)lst;
list.add(index, val);
} else if (lst != null && lst.getClass().isArray()) {
int len = Array.getLength(lst);
Object array = Array.newInstance(clazz, len + 1);
for (int i = 0; i < index; i++) {
Array.set(array, i, Array.get(lst, i));
}
Array.set(array, index, val);
for (int i = index + 1; i < len + 1; i++) {
Array.set(array, i, Array.get(lst, i - 1));
}
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (lst == null)
throw new RuntimeException("field: [" + fieldName + "] has not been initialized as list or array");
}
}
/**
* Get a field (attribute) value
* @param fieldName
* @return
*/
public Object getFieldValue(String fieldName) {
return getFieldValue(fieldName, false); // not internal
}
Object getFieldValue(String fieldName, boolean internal) {
DOField field = this.domainObjectType.getFieldByName(fieldName);
if (field == null)
throw new RuntimeException("field: " + fieldName + " not found in: " + this.domainObjectType.getName());
if (!internal && field.getComponentTypeName() != null)
throw new RuntimeException("field: " + fieldName + " is a list field, use list field accessors instead ");
Object raw = field.getValue(this.getRawObject());
DomainObject gdo = getForRawObject(raw);
if (gdo != null)
return gdo;
return raw;
}
/**
* if the field is a list or array, answer the value at the given index.
* @param fieldName
* @param index
* @return
*/
public Object getListFieldValue(String fieldName, int index) {
Object ret = null;
Object val = getFieldValue(fieldName, true); // internal
if (val instanceof List<?>) {
List<?> list = (List<?>)val;
Object cval = list.get(index);
DomainObject gdo = getForRawObject(cval);
if (gdo != null)
ret = gdo;
else
ret = cval;
} else if (val != null && val.getClass().isArray()) {
Object aval = Array.get(val, index);
DomainObject gdo = getForRawObject(aval);
if (gdo != null)
ret = gdo;
else
ret = aval;
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (val == null)
throw new RuntimeException("list or array field: [" + fieldName + "] is null");
}
return ret;
}
/**
* Returns the index of the first occurrence of the specified value
* in the list field, or -1 if the list field does not contain the value.
* @param fieldName
* @param value
* @return
*/
public int getIndexOfValue(String fieldName, Object value) {
int ret = -1;
Object val = value;
if (value instanceof DomainObject)
val = ((DomainObject)value).getRawObject();
Object lst = getFieldValue(fieldName, true); // internal
if (lst instanceof List<?>) {
List<?> list = (List<?>)lst;
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
if (obj.equals(val)) {
ret = i;
break;
}
}
} else if (lst != null && lst.getClass().isArray()) {
int len = Array.getLength(lst);
for (int i = 0; i < len; i++) {
Object obj = Array.get(lst, i);
if (obj.equals(val)) {
ret = i;
break;
}
}
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (lst == null)
throw new RuntimeException("list or array field: [" + fieldName + "] is null");
}
return ret;
}
/**
* Removes all of the elements from the list field.
* @param fieldName
*/
public void clearListField(String fieldName) {
Object val = getFieldValue(fieldName, true); // internal
if (val instanceof List<?>)
((List<?>)val).clear();
else if (val != null && val.getClass().isArray()) {
DOField fld = getDomainObjectType().getFieldByName(fieldName);
String ctn = fld.getComponentTypeName();
Class<?> clazz;
try {
clazz = getDomainObjectType().getDomainModel().getClassForName(ctn);
tryInitListOrArray(null, fld, clazz);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (val == null)
throw new RuntimeException("list or array field: [" + fieldName + "] is null");
}
}
/**
* Remove a value from a list at the given index.
* <br/>Shifts any subsequent elements to the left (subtracts one from their indices).
* @param fieldName
* @param index
*/
public void removeListFieldValue(String fieldName, int index) {
Object val = getFieldValue(fieldName, true); // internal
DOField fld = getDomainObjectType().getFieldByName(fieldName);
String ctn = fld.getComponentTypeName();
Class<?> clazz;
try {
clazz = getDomainObjectType().getDomainModel().getClassForName(ctn);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (val instanceof List<?>)
((List<?>)val).remove(index);
else if (val != null && val.getClass().isArray()) {
int len = Array.getLength(val);
Object array = Array.newInstance(clazz, len - 1);
for (int i = 0; i < index; i++) {
Array.set(array, i, Array.get(val, i));
}
for (int i = index; i < len - 1; i++) {
Array.set(array, i, Array.get(val, i - 1));
}
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (val == null)
throw new RuntimeException("list or array field: [" + fieldName + "] is null");
}
}
/**
* Answer the length of a list field
* @param fieldName
* @return
*/
public int getListFieldLength(String fieldName) {
int ret = -1;
Object val = getFieldValue(fieldName, true); // internal
if (val instanceof List<?>)
ret = ((List<?>)val).size();
else if (val != null && val.getClass().isArray()) {
ret = Array.getLength(val);
} else {
if (!getDomainObjectType().getFieldByName(fieldName).isListOrArray())
throw new RuntimeException("field: [" + fieldName + "] is neither list nor array");
if (val == null)
throw new RuntimeException("list or array field: [" + fieldName + "] is null");
}
return ret;
}
private Object tryInitListOrArray(Object list, DOField fld, Class<?> componentType) throws ClassNotFoundException {
Object ret = list;
if (list == null) { // try to initialize list or array field with empty list / array
if (fld.isBuidInType()) {
Class<?> lstClazz = getDomainObjectType().getDomainModel().getClassForName(fld.getTypeName());
if (List.class.isAssignableFrom(lstClazz))
ret = new ArrayList<Object>();
else if (lstClazz.isArray())
ret = Array.newInstance(componentType, 0);
if (ret != null)
fld.setValue(this.getRawObject(), ret);
}
}
return ret;
}
private DomainObject getForRawObject(Object raw) {
DomainObject gdo = null;
if (raw != null) {
DomainAccess da = InternalAccess.getDomainAccess(this.domainObjectType.getDomainModel());
gdo = ((IIntDomainAccess)da).getInternalDomainAccess().getGenericDomainObject(raw);
if (gdo == null)
gdo = this.domainObjectType.getDomainModel().getNurseryObject(raw);
}
return gdo;
}
void setRawObject(Object rawObject) {
this.rawObject = rawObject;
}
Object getRawObject() {
if (this.rawObject == null) {
try {
this.rawObject = this.domainObjectType.getRawType().newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
return this.rawObject;
}
}