zoukankan      html  css  js  c++  java
  • CloudStack的VO在调用setRemoved方法抛异常的原因

    今天在开发中发现一个问题,本来想对一个VO对象的removed值赋值,然后去update一下这条记录,一个最简单的set方法,但是在调用时直接抛异常了。

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

    当时很诧异,没有想到这地方会出问题,后来看代码才发现原来cs在这里有拦截器,com.cloud.utils.db.UpdateBuilder#intercept

      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#makeChange

      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。

    Attribute是cloudstack的基类GenericDaoBase中保存的对象属性集合,是一个保存了数据表的列名以及列属性的Map对象,这个对象通过Java JPA来进行持久化。

    每一个干活的DAO对象都会继承于GenericDaoBase,并且实现自己这类对象的接口,如下图:

    image 

    刚才说的那个isUpdatable()是个人认为cloudstack中有关数据库权限做的很精巧的地方

      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

  • 相关阅读:
    [转] packagelock.json
    前端框架和技术
    typescript
    微信小程序登陆流程
    Introduction to my galaxy engine 4: Test on local light model
    Introduction to my galaxy engine 3: Local light model
    Introduction to my galaxy engine 5: Differed Lighting
    Introduction to my galaxy engine 2: Depth of field
    自己整理的一些国外免费3D模型网站,以后还会陆续添加
    Introduction to my galaxy engine 6: Differed Lighting 2
  • 原文地址:https://www.cnblogs.com/Cratical/p/3185175.html
Copyright © 2011-2022 走看看