CloudStack的VO在調用setRemoved方法拋異常的緣由

今天在開發中發現一個問題,原本想對一個VO對象的removed值賦值,而後去update一下這條記錄,一個最簡單的set方法,可是在調用時直接拋異常了。數據庫

  1: public void setRemoved(Date removed) {
  2:     this.removed = removed;
  3: }

當時很詫異,沒有想到這地方會出問題,後來看代碼才發現原來cs在這裏有攔截器,com.cloud.utils.db.UpdateBuilder#interceptide

  1: @Override
  2: public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  3:     String name = method.getName();
  4:     if (name.startsWith("set")) {
  5:         String field = methodToField(name, 3);
  6:         makeChange(field, args[0]);
  7:     } else if (name.startsWith("incr")) {
  8:         makeIncrChange(name, args);
  9:     } else if (name.startsWith("decr")) {
 10:         makeDecrChange(name, args);
 11:     }
 12:     return methodProxy.invokeSuper(object, args);
 13: }

全部set開頭的方法都被攔截,轉調com.cloud.utils.db.UpdateBuilder#makeChangeui

  1: protected Attribute makeChange(String field, Object value) {
  2:     Attribute attr = _dao._allAttributes.get(field);
  3: 
  4:     assert (attr == null || attr.isUpdatable()) : "Updating an attribute that's not updatable: " + field;
  5:     if (attr != null) {
  6:         if (attr.attache == null) {
  7:             _changes.put(field, new Ternary<Attribute, Boolean, Object>(attr, null, value));
  8:         } else {
  9:             if (_collectionChanges == null) {
 10:                 _collectionChanges = new HashMap<Attribute, Object>();
 11:             }
 12:             _collectionChanges.put(attr, value);
 13:         }
 14:     }
 15:     return attr;
 16: }

 

在那句assert那裏,會判斷attr是否能夠update。this

Attribute是cloudstack的基類GenericDaoBase中保存的對象屬性集合,是一個保存了數據表的列名以及列屬性的Map對象,這個對象經過Java JPA來進行持久化。spa

每個幹活的DAO對象都會繼承於GenericDaoBase,而且實現本身這類對象的接口,以下圖:對象

image 

 

剛纔說的那個isUpdatable()是我的認爲cloudstack中有關數據庫權限作的很精巧的地方blog

  1: public final boolean isUpdatable() {
  2:     return Flag.Updatable.check(flags);
  3: }

 

這裏面會調用Flag這個enum對象的check方法,那個flags一樣也是在調用Attribute的構造方法時生成的,它根據數據庫表的每一列的屬性,按照一個邏輯去計算相關的權限,flags的初始值爲0,而後針對每一種權限依次去作或運算,最後保存爲一個值,遇到須要校驗權限的地方,就用下面的check方法,看傳進來的權限,好比Flag.Updatable,與flags去與運算,若是與完了的結果與傳進來的權限值同樣,那麼能夠繼續進行,不然就會因爲assert計算表達式的結果爲false而退出去。繼承

  1: public boolean check(int value) {
  2:     return (value & place) == place;
  3: }

今天的問題就在這,Attribute.flags的值致使assert的表達式結果爲false,在初始化時,flags的值明明爲135(128+4+2+1),可是在實際計算時卻不是這個值,一度很不解。可是爲了解決生產環境的問題,不能在這個細節上耽擱過久,因而換了個思路,嘗試着調用DAO的remove方法,也能實現針對數據庫表的removed字段賦值。具體到爲何flags的值變了,還須要抽時間好好研究一下。接口

不過值得欣慰的是,若是不是set時拋異常了,本身可能也不會去啃這部分代碼來了解。開發

附1,計算flags時的代碼(com.cloud.utils.db.Attribute#setupColumnInfo):

  1: protected void setupColumnInfo(Class<?> clazz, AttributeOverride[] overrides, String tableName, boolean isEmbedded, boolean isId) {
  2:     flags = Flag.Selectable.setTrue(flags);
  3:     GeneratedValue gv = field.getAnnotation(GeneratedValue.class);
  4:     if (gv != null) {
  5:         if (gv.strategy() == GenerationType.IDENTITY) {
  6:             flags = Flag.DbGenerated.setTrue(flags);
  7:         } else if (gv.strategy() == GenerationType.SEQUENCE) {
  8:             assert (false) : "Sequence generation not supported.";
  9:             flags = Flag.DaoGenerated.setTrue(flags);
 10:             flags = Flag.Insertable.setTrue(flags);
 11:             flags = Flag.SequenceGV.setTrue(flags);
 12:         } else if (gv.strategy() == GenerationType.TABLE) {
 13:             flags = Flag.DaoGenerated.setTrue(flags);
 14:             flags = Flag.Insertable.setTrue(flags);
 15:             flags = Flag.TableGV.setTrue(flags);
 16:         } else if (gv.strategy() == GenerationType.AUTO) {
 17:             flags = Flag.DaoGenerated.setTrue(flags);
 18:             flags = Flag.Insertable.setTrue(flags);
 19:             flags = Flag.AutoGV.setTrue(flags);
 20:         }
 21:     }
 22: 
 23:     if (isEmbedded) {
 24:         flags = Flag.Embedded.setTrue(flags);
 25:     }
 26: 
 27:     if (isId) {
 28:         flags = Flag.Id.setTrue(flags);
 29:     } else {
 30:         Id id = field.getAnnotation(Id.class);
 31:         if (id != null) {
 32:             flags = Flag.Id.setTrue(flags);
 33:         }
 34:     }
 35:     column = field.getAnnotation(Column.class);
 36:     if (gv == null) {
 37:         if (column == null || (column.insertable() && column.table().length() == 0)) {
 38:             flags = Flag.Insertable.setTrue(flags);
 39:         }
 40:         if (column == null || (column.updatable() && column.table().length() == 0)) {
 41:             flags = Flag.Updatable.setTrue(flags);
 42:         }
 43:         if (column == null || column.nullable()) {
 44:             flags = Flag.Nullable.setTrue(flags);
 45:         }
 46:         Encrypt encrypt = field.getAnnotation(Encrypt.class);
 47:         if (encrypt != null && encrypt.encrypt()) {
 48:             flags = Flag.Encrypted.setTrue(flags);
 49:         }
 50:     }
 51:     ElementCollection ec = field.getAnnotation(ElementCollection.class);
 52:     if (ec != null) {
 53:         flags = Flag.Insertable.setFalse(flags);
 54:         flags = Flag.Selectable.setFalse(flags);
 55:     }
 56: 
 57:     Temporal temporal = field.getAnnotation(Temporal.class);
 58:     if (temporal != null) {
 59:         if (temporal.value() == TemporalType.DATE) {
 60:             flags = Flag.Date.setTrue(flags);
 61:         } else if (temporal.value() == TemporalType.TIME) {
 62:             flags = Flag.Time.setTrue(flags);
 63:         } else if (temporal.value() == TemporalType.TIMESTAMP) {
 64:             flags = Flag.TimeStamp.setTrue(flags);
 65:         }
 66:     }
 67: 
 68:     if (column != null && column.table().length() > 0) {
 69:         table = column.table();
 70:     }
 71: 
 72:     columnName = DbUtil.getColumnName(field, overrides);
 73: }

 

附2,數據庫表每一列可能的全部權限列表:

image

相關文章
相關標籤/搜索