`
iamlotus
  • 浏览: 108516 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

如何自动备份删除的对象(2)

阅读更多

自动删除,我们要作的事有三件

 1) 如何从要删除的Domain对象中获得需要备份的信息M

 2) 这个信息M如何持久化

 3) 持久化的数据如何查询。

 

后两者其实有多种选择,比如可以持久化到文件、数据库或者数据库+文件,随着持久化介质的不同,查询机制也不一样。这里首先讨论第一个方面。

为了作一个通用的框架,希望能通过meta data的方式简化收集信息的过程。那么就有三种方式可供选择:interface,annotation && XML,这也是目前广泛应用的各种框架如Spring,Hibernate等提供的方式。这其中,interface可以实现比较复杂的逻辑,annotation使用相对简便,而XML是最没有倾入的。手上的项目暂时不考虑移植,所以先实现了interface+annotation方式

 

首先来看annotation, 我定义个一个叫Record的Annotation。

 

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <code>Record</code> is an annotation used on bean object to specify that bean can be recorded automatically at some
 * stage (for example, deletion). Generally speaking, the bean can produce a <code>java.util.Map</code> and record
 * itself into it. The key of that map is property name, and the value is the object gotten by getter.
 * <p>
 * You may use <code>Record</code> on class or method level, but any <code>Record</code> on a method which is not getter
 * will be ignored. And, if an object is not marked as <code>Record</code> on class level, all <code>Record</code>
 * annotations on method level will be <b>IGNORED</b> either, e.g. it will not be recorded automatically at all. So,
 * make sure to use this annotation on class level.
 * <p>
 * You can specify <code>ignore</code> when using <code>Record</code>. On class level, <code>@Record(ignore=true)</code>
 * means all getters will be ignored unless it is marked as <code>@Record</code> explicitly, vice versa. On method
 * level, <code>@Record</code> impact its host only. The default value of <code>ignore</code> is false.
 * <p>
 * If the bean implements <code>Recordable</code>, you are able to edit the <code>java.util.Map</code> returned by
 * <code>Record</code>.
 * 
 * @author JINLO
 * @see Recordable
 * @since 3.1
 */
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface Record {
    boolean ignore() default false;
}

    以及一个叫Recordable的interface

 

import java.util.Map;

/**
 * <code>Recordable</code> is used to specify a Object can be recorded at some stage(for example,deletion), a object can
 * record itself by implements <code>void record(Map<String, Object> content)</code> function.
 * 
 * @author JINLO
 * @since 3.1
 * @see Record
 */
public interface Recordable {
    /**
     * Write information you want to backup. This function is something like {@code toString()} function but with
     * slightly difference.
     * <p>
     * {@code toString()} is designed for display purpose, but {@code record} is designed for backup, and the backup
     * information is organized by &lt;key,value&gt; format. For example, when implement toString() for an {@code Item},
     * ItemId may be enough for displaying:
     * 
     * <pre>
     * public String toString() {
     *     return &quot;itemId=&quot; + this.getItemId();
     * }
     * </pre>
     * 
     * But for <code>Recordable</code>, you need to backup more attributes:
     * 
     * <pre>
     * public void record(Map&lt;String, Object&gt; content) {
     *     content.put(&quot;UPDATER&quot;, getUpdater().getUserID());
     *     content.put(&quot;CREATOR&quot;, getCreator().getUserID());
     *     content.put(&quot;CATEGORY&quot;, getCategory().getName());
     *     content.put(&quot;CATEGORY1&quot;, getCategory1().getName());
     *     content.put(&quot;CATEGORY2&quot;, getCategory2().getName());
     *     StringBuffer uomBuffer = new StringBuffer();
     *     for (UnitOfMeasure uom : this.getUnitOfMeasure()) {
     *         if (uom != null) {
     *             uomBuffer.append(&quot;,&quot;);
     *             uomBuffer.append(uom.getUom());
     *         }
     *     }
     *     content.put(&quot;UOM&quot;, uomBuffer.toString().substring(2));
     * }
     * </pre>
     * 
     * @param writer
     */
    void record(Map<String, Object> content);
}
 

 

     这里说明一下,Record是希望放在Class或者Getter上的。一旦一个Class被加上Record,缺省记录所有的可读属性,除非在某个Getter上声明 Record( ignore=true)。当然也可以把Class设为Record (ignore=true),这样缺省不会记录任何属性,除非某一个Getter被声明为Record。这样对String,primitive type或boxing type,不需要太多标注就可以搞定一个Class了。

 

     Recordable用来实现自定义抓取过程,把需删除的对象信息记录在一个Map中传给record方法。比如对于Order对象的orderItems,如果你只想记录这个Order有多少Item,而不想记录具体的Item,就可以这么写

 

@Record
class Order implements Recordable{
    //orderNo will be recorded 
    public String getOrderNo(){
        //..
    
    }
    
    @Record(ignore=true)
    public List<OrderItem> getOrderItems(){
        //...
    }
    
    void record(Map<String, Object> content){
        content.put("itemSize", getOrderItems.size());
    }
    
}
 

    当然,还要有一个相应的工具类来处理annotation和interface

 

 

import java.lang.reflect.Method;

/**
 * A helper class for <code>Record</code> annotation. It contains information retrieved by reflection which can be used
 * to record a class. This class may be cached for performance consideration
 * 
 * @author JINLO
 * @see Record
 * @since 3.1
 * 
 */
public class RecordDescriptor {
    public static class RecordMethod {
        public RecordMethod(Method readMethod, String propertyName) {
            if (readMethod == null) {
                throw new IllegalArgumentException("readMethod is null");
            }

            if (propertyName == null) {
                throw new IllegalArgumentException("propertyName is null");
            }

            this.readMethod = readMethod;
            this.propertyName = propertyName;
        }

        private Method readMethod;

        private String propertyName;

        public Method getReadMethod() {
            return readMethod;
        }

        public String getPropertyName() {
            return propertyName;
        }

        public int hashCode() {
            return readMethod.hashCode() + 31 * propertyName.hashCode();
        }

        public boolean equals(Object o) {
            if (o == this) {
                return true;
            }

            if (o == null) {
                return false;
            }

            if (o instanceof RecordMethod) {
                RecordMethod target = (RecordMethod) o;
                return this.readMethod.equals(target.readMethod) && this.propertyName.equals(target.propertyName);
            }

            return false;
        }

        public String toString() {
            return "readMethod=" + readMethod + ",propertyName=" + propertyName;
        }
    }

    public RecordDescriptor(Class<?> referenceClass, boolean enable, RecordMethod[] getters) {
        this.referenceClass = referenceClass;
        this.enable = enable;
        this.getters = getters;
    }

    private Class<?> referenceClass;

    private boolean enable;

    private RecordMethod[] getters;

    /**
     * The reference class this <code>RecordDescriptor</code> describes
     * 
     * @return
     */
    public Class<?> getReferenceClass() {
        return referenceClass;
    }

    /**
     * Is the reference class marked <code>Record</code>
     * 
     * @return
     */
    public boolean isEnable() {
        return enable;
    }

    /**
     * Get all get methods should be recorded of reference class, including <code>Method</code> and propertyName
     * 
     * @return empty array if no valid get method
     */
    public RecordMethod[] getGetters() {
        return getters;
    }

}
 

 

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.oocl.wos.frm.domain.record.RecordDescriptor.RecordMethod;
import com.oocl.wos.frm.utils.BeanUtils;

/**
 * Some utilities for implement <code>Recode</code>
 * 
 * @author JINLO
 * @since 3.1
 */
public class RecordUtils {
    private final static RecordUtils instance = new RecordUtils();

    private static Map<Class<?>, RecordDescriptor> descriptorCache = new HashMap<Class<?>, RecordDescriptor>();

    private final static RecordMethod[] RECORD_METHOD_ARRAY = new RecordMethod[] {};

    private final static RecordDescriptor NULL_DESCRIPTOR = new RecordDescriptor(null, false, RECORD_METHOD_ARRAY);

    public final static RecordUtils instance() {
        return instance;
    }

    private RecordUtils() {

    }

    /**
     * Get all <code>RecordeDescriptor</code> for given class, this function will cache result for performance
     * consideration.
     * 
     * @param clz
     * @return
     */
    public synchronized RecordDescriptor getRecordDescriptors(Class<?> clz) {
        if (clz == null) {
            throw new NullPointerException("can not get read methods of class <null>");
        }
        RecordDescriptor result = descriptorCache.get(clz);
        if (result == null) {
            Record classAnnotation = clz.getAnnotation(Record.class);
            if (classAnnotation != null) {
                List<RecordMethod> readProperties = new ArrayList<RecordMethod>();
                for (PropertyDescriptor readableProperty : BeanUtils.instance().getReadableProperties(clz)) {
                    Record methodAnnotation = readableProperty.getReadMethod().getAnnotation(Record.class);
                    boolean ignore = (methodAnnotation == null) ? classAnnotation.ignore() : methodAnnotation
                            .ignore();

                    if (!ignore) {
                        readProperties.add(new RecordMethod(readableProperty.getReadMethod(), readableProperty
                                .getName()));
                    }
                }

                result = new RecordDescriptor(clz, true, readProperties.toArray(RECORD_METHOD_ARRAY));
            } else {
                result = NULL_DESCRIPTOR;
            }
            descriptorCache.put(clz, result);
        }
        return result;
    }

    /**
     * Record an object into Map in two steps:
     * <ol>
     * <li>If it is marked with<code>Record</code>, all valid get methods on that object will be recorded in a format
     * like &lt;property name,getter value &gt;
     * <li>Then, if it implements <code>Recordable</code>, the map filled in above setp will be passed to {@code
     * Recordable.record(Map<String, Object>)} function, process in a customized way.
     * </ol>
     * 
     * @param obj
     * @return null - obj is null or obj should not be recorded
     */
    public Map<String, Object> toContent(Object obj) {

        if (obj == null) {
            return null;
        }
        Map<String, Object> result = null;
        RecordDescriptor delDesc = getRecordDescriptors(obj.getClass());
        if (delDesc.isEnable()) {
            result = new HashMap<String, Object>();
            for (RecordMethod getter : delDesc.getGetters()) {
                String name = getter.getPropertyName();
                Object value = BeanUtils.instance().executeReadMethod(obj, getter.getReadMethod());
                result.put(name, value == null ? null : value.toString());
            }
        }

        if (obj instanceof Recordable) {
            Recordable dr = (Recordable) obj;
            if (result == null) {
                result = new HashMap<String, Object>();
            }
            dr.record(result);
        }

        return result;
    }

}

 

    RecordUtils类使用了apache的BeanUitls,并且在自己内部缓存了每个类的RecordDescriptor对象,以避免过多的反射。

 

     至此,对于任意obj,只要调用

Map<String,Object> content=RecordUtils.toContent(obj);

    就可以得到其中所有的信息了,下面所要作的就是将这些信息持久化而已,这将在下一篇描述。

 

    采用interface+annotation的方法,我们成功的将“如何记录自己”这件事交给了对象自身。这已经有了点rich domain的意味。相对来说 rich domain意味着更好/更符合直觉的控制,对于record这种与对象自身紧密相关的行为,采用rich domain是很合适的。

0
0
分享到:
评论

相关推荐

    sql2008自动备份数据库和定期删除数据库备份

    SQLServer 2008 自动备份数据库和定期删除数据库备份 SQLServer 2008 通过创建维护计划可以实现自动备份数据库和定期删除备份。为了实现这个功能,必须开启 SQLServer 的 SQLServer Agent 服务,因为这个服务默认是...

    在SQL Server 2005数据库中实现自动备份自动删除备份文件

    在SQL Server 2005中,为了确保数据的安全性和可恢复性,自动备份和自动删除备份文件是非常关键的操作。以下是如何在SQL Server 2005中实现这两个功能的详细步骤: 一、创建自动备份 1. **打开SQL Server ...

    sql自动备份(如何自动备份)

    在SQL Server中,数据库的自动备份是确保数据安全和防止数据丢失的重要措施。本文将详细介绍如何设置SQL Server的自动定时备份功能,以便在无需人工干预的情况下定期执行备份任务。 首先,确保您的计算机已经安装了...

    windows下oracle11g数据泵自动备份脚本

    windows下oracle11g数据泵自动备份脚本含删除过期备份和使用方法 1、先建备份用的路径对象:(注:此处认为用来做备份的用户backupuser已经建好了,且已经有连接数据库的相应权限) sqlplus / as sysdba CREATE OR ...

    pb 12.5编写自动备份工具

    PB 12.5 编写的自动备份工具是一款利用PowerBuilder 12.5开发的应用程序,主要用于自动化SQL Server数据库的备份过程。该工具能够按照预设的时间计划执行数据库备份,并将生成的备份文件安全地复制到网络共享位置,...

    自动备份和按日期删除程序

    在IT领域,自动备份和按日期删除程序是保持数据安全和系统整洁的重要工具。VBScript(Visual Basic Script)是一种轻量级的脚本语言,常用于Windows系统的自动化任务,如批处理、网页交互等。本程序就是利用VBScript...

    oracle自动备份工具

    2. **自动备份策略**:在Oracle中,可以通过RMAN配置自动备份策略,例如设置每天或每周的特定时间执行备份,以及指定备份存储位置。这可以通过RMAN的`RUN`块和`BACKUP`命令实现,结合`CONFIGURE`命令设置备份参数,...

    oracle数据库自动备份

    "Oracle数据库自动备份"指的是利用Oracle提供的工具和策略,设定定期自动执行数据库备份,以确保数据的安全性。 Oracle数据库提供了多种备份方式,包括物理备份和逻辑备份。物理备份主要是通过RMAN(恢复管理器)...

    oracle自动备份脚本的

    在IT行业中,数据库的备份是至关重要的,尤其是对于企业级应用来说,Oracle数据库的自动备份是确保数据安全的重要环节。本文将围绕“Oracle自动备份脚本”这一主题,详细讲解如何利用脚本来实现Oracle数据库的定时...

    sql2008自动备份

    本篇文章将深入探讨如何在SQL Server 2008中设置自动备份,这对于数据库管理员以及对数据库操作有一定了解的初学者来说,是一项基础但关键的操作。 首先,我们从【描述】中了解到,SQL Server Management Studio...

    使用PB9做的sqlserver数据库的自动备份软件

    标题中的“使用PB9做的sqlserver数据库的自动备份软件”指的是使用PowerBuilder 9(简称PB9)开发的一款工具,该工具专为SQL Server数据库设计,目的是实现数据库的自动化备份。PowerBuilder是一款强大的可视化编程...

    excel对象清理工具/vba清理Excel对象

    excel多余对象清理工具/...删除多余对象前自动备份文件 目前删除几万个还是OK的(测试3-4万个对象处理需要2分钟左右),几十万个就另外手工处理吧,直接卡死。 还有很多不足,还有很多需要改善的地方,请大佬指点指点~

    Oracle数据库对象管理及备份与恢复.pdf

    Oracle数据库是业界广泛使用的大型关系型数据库系统,其对象管理及备份与恢复机制对于数据库管理员来说至关重要。本文将详细介绍Oracle数据库的对象管理、数据类型、触发器、索引和分区策略,以及备份与恢复的相关...

    java自动备份

    Java自动备份系统是一种高效、可靠的解决方案,用于在服务器上实现资源文件的自动化上传、下载以及备份功能。这个系统的核心在于利用Java编程语言的强大能力和灵活性,结合相关库和框架,实现文件管理的自动化流程,...

    PB实现sql数据库自动备份

    本文将详细阐述如何使用PowerBuilder(PB)实现SQL数据库的自动备份,以及涉及的相关知识点,包括数据恢复、特殊数据处理和数据上传下载。 一、SQL数据库自动备份 SQL数据库自动备份是为了防止数据丢失或系统故障...

    文件夹自动备份工具+vb源代码

    本文将围绕一款名为“文件夹自动备份工具+vb源代码”的工具进行讨论,它不仅提供了可执行的备份程序FolderBackup.exe,还附带了详细的VB源代码,让使用者能够根据自己的需求调整并学习到如何开发类似的工具。...

    SQL2008设置自动备份与删除.doc

    ### SQL Server 2008 自动备份与删除策略详解 #### 一、背景与目的 随着业务数据量的增长及重要性的提升,确保数据库的安全性和稳定性成为IT部门的一项重要职责。在SQL Server 2008中,为了保护数据安全并提供有效...

    Oracle数据库定时自动备份批处理代码(Windows)

    Oracle数据库定时自动备份对于保障数据安全至关重要,尤其是在Windows环境下,通过批处理脚本可以实现这一功能。以下是一个详细的Oracle数据库定时自动备份的步骤和相关知识点: 1. **批处理脚本**: - `...

    wxh PB数据库自动备份软件

    2. **自动备份**:该软件的核心功能是自动执行备份任务,用户可以设置定时任务,比如每天、每周或在特定时间点进行备份。这有助于防止数据丢失,尤其是在系统故障、硬件损坏或人为错误的情况下。 3. **配置文件**:...

Global site tag (gtag.js) - Google Analytics