/****************************************************************************** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * The Original Code is: Jsoda * The Initial Developer of the Original Code is: William Wong (williamw520@gmail.com) * Portions created by William Wong are Copyright (C) 2012 William Wong, All Rights Reserved. * ******************************************************************************/ package wwutil.jsoda; import java.util.*; import java.io.*; import java.lang.reflect.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import wwutil.sys.FnUtil; import wwutil.sys.FnUtil.*; import wwutil.sys.ReflectUtil; import wwutil.model.ValidationException; import wwutil.model.annotation.CachePolicy; import wwutil.model.annotation.CacheByField; import wwutil.model.annotation.DefaultGUID; import wwutil.model.annotation.DefaultComposite; import wwutil.model.annotation.VersionLocking; import wwutil.model.annotation.S3Field; /** * Entity util. Helper util methods on the model object. */ @SuppressWarnings("unchecked") public class EUtil<T> { private static Log log = LogFactory.getLog(EUtil.class); private Class<T> modelClass; private String modelName; private Jsoda jsoda; public EUtil(Class<T> modelClass, Jsoda jsoda) { this.modelClass = modelClass; this.modelName = jsoda.getModelName(modelClass); this.jsoda = jsoda; } /** Create a new initialize object instance of the model class. * Initialize with default values using the field annotations. * The following preStore steps will be called: @PrePersist, data handlers, composite data handlers. * e.g. @DefaultGUID and @DefaultComposite will be run. * Note that validations will not be run. */ public T newInitInstance() throws Exception { T dataObj = modelClass.newInstance(); jsoda.preStoreTransformSteps(dataObj); return dataObj; } /** Create a new initialize object instance of the model class. * Initialize the key field(s) with idKey and idRangeKey (optional). * Initialize with default values using the field annotations. */ public T newInitInstance(Object idKey, Object idRangeKey) throws Exception { T dataObj = modelClass.newInstance(); setIdValue(dataObj, idKey); setRangeValue(dataObj, idRangeKey); jsoda.preStoreTransformSteps(dataObj); return dataObj; } /** Dump object's fields to string, for debugging. */ public static String dump(Object obj) { return ReflectUtil.dumpObj(obj); } /** Return the Id field of the model */ public Field getIdField() { return jsoda.getIdField(modelName); } /** Return the range field of the model. Return null if range field not defined. */ public Field getRangeField() { return jsoda.getRangeField(modelName); } public Field getField(String fieldName) { Field f = jsoda.getField(modelName, fieldName); if (f == null) throw new IllegalArgumentException("Field " + fieldName + " doesn't exist on model class " + modelName); return f; } /** Check to see if field is the Id field. */ public boolean isIdField(String fieldName) { return getIdField().getName().equals(fieldName); } /** Check to see if field is an RangeKey field. */ public boolean isRangeField(String fieldName) { Field rangeField = getRangeField(); return rangeField != null && rangeField.getName().equals(fieldName); } /** Get the value of the Id field */ public Object getIdValue(T obj) throws IllegalAccessException { return getIdField().get(obj); } /** Get the value of the Range field */ public Object getRangeValue(T obj) throws IllegalAccessException { Field f = getRangeField(); return f != null ? f.get(obj) : null; } /** Get the value of the field of fieldName */ public Object getFieldValue(T obj, String fieldName) throws IllegalAccessException { return getField(fieldName).get(obj); } /** Set the value of the Id field */ public T setIdValue(T obj, Object idValue) throws IllegalAccessException { getIdField().set(obj, idValue); return obj; } /** Set the value of the RangeKey field */ public T setRangeValue(T obj, Object rangeKeyValue) throws IllegalAccessException { Field rangeField = getRangeField(); if (rangeField != null) rangeField.set(obj, rangeKeyValue); return obj; } /** Set the value of the field of fieldName */ public T setFieldValue(T obj, String fieldName, Object fieldValue) throws IllegalAccessException { getField(fieldName).set(obj, fieldValue); return obj; } /** Get the attribute value of a field annotation. * Use defaultValue's type for return type. * Use defaultValue for all exceptions. * e.g. getFieldAnnotationValue("lastName", Editable.class, "value", true); */ public boolean getAnnotationValue(String fieldName, Class annotationClass, String valueMethod, boolean defaultValue) { return ReflectUtil.getAnnotationValueEx(getField(fieldName), annotationClass, valueMethod, boolean.class, defaultValue); } public int getAnnotationValue(String fieldName, Class annotationClass, String valueMethod, int defaultValue) { return ReflectUtil.getAnnotationValueEx(getField(fieldName), annotationClass, valueMethod, int.class, defaultValue); } public String getAnnotationValue(String fieldName, Class annotationClass, String valueMethod, String defaultValue) { return ReflectUtil.getAnnotationValueEx(getField(fieldName), annotationClass, valueMethod, String.class, defaultValue); } public String[] getAnnotationValue(String fieldName, Class annotationClass, String valueMethod, String[] defaultValue) { return ReflectUtil.getAnnotationValueEx(getField(fieldName), annotationClass, valueMethod, String[].class, defaultValue); } /** Is the type of the field one of the typeClass parameters. * e.g. isTypeOf("hasAge", boolean.class) * e.g. isTypeOf("hasAge", boolean.class, Boolean.class) */ public boolean isTypeOf(String fieldName, Class typeClass, Class ...optionalTypeClasses) { Field f = getField(fieldName); if (f.getType() == typeClass) return true; for (Class type : optionalTypeClasses) { if (f.getType() == type) return true; } return false; } /** Transform the dataObj into a value map with the field names as keys. */ public Map<String, Object> asValueMap(final T dataObj) { Map<String, Field> allFields = jsoda.getAllFieldMap(modelName); return FnUtil.map(allFields, new TransformFn<Object, Field>() { public Object apply(Field f) { try { return f.get(dataObj); } catch(IllegalAccessException e) { throw new RuntimeException(e); } } }); } }