# 逻辑流拦截器(handler-engine.xml)

与逻辑流拦截器相关的配置文件与接口类:

配置文件/关键类 路径/包名 说明
handler-engine.xml eosserver\working\应用名\config\handler- engine.xml 可以在配置文件中配置逻辑流的拦截器,实现业务开发的功能
IHandler com.eos.engine.core.IHandler 逻辑流拦截器接口类、用户需要实现该接口
IRuntimeContext com.primeton.ext.engine.core.IRuntimeContext 参数类、用于获取逻辑流上下文的参数信息
HandlerTerminateException com.eos.engine.core.exception.HandlerTerminateException 如果希望在handler中终止流程的执行,可以抛出HandlerTerminateException,引擎碰到该异常的时候,会终止流程的继续执行

说明

逻辑流和页面流共用一个配置文件handler-engine.xml;通过type属性的值来区分对页面流的拦截还是对逻辑流的拦截。

  • pageflow:表示对页面流进行拦截;
  • businesslogic:表示对逻辑流进行拦截。

# 功能描述

EOS6为逻辑流提供了Handler拦截机制,可以在执行逻辑流的某个图元之前、之后、发生异常、无论正确执行还是发生异常的情况下都会执行的finally四种情况下进行拦截;也可以对整个逻辑流执行之前、执行之后、发生异常、无论正确执行还是发生异常的情况下都会执行的finally四种情况下进行拦截;可以在Handler实现中插入用户期望执行的具体代码。

# 配置文件与关键类

配置文件:handler-engine.xml 关键类:IHandler、IRuntimeContext

# 配置文件格式说明

文件路径:eosserver\working\应用名\config\handler-access.xml handler-access.xml文件格式如下:

<handles>
    <handle
    name="aName"
    match-pattern="*[CHAR]**"
    handle-class="com.primeton.engine.handler.logHandler"
    type="pageflow,businesslogic"
    nodeType="start"
    nodeID=""/>
</handles>

说明

所有的Handler在系统运行期间都是单实例的,在实现IHandler接口时,实现类不能定义全局变量,否则,在多线程的情况下会有并发的问题。 Handler支持两种级别的拦截:对单个图元进行拦截/对整个逻辑流进行拦截。

格式说明:

  • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。

  • handler节点:

    • name属性:配置拦截器的名字,在配置文件中多个handler节点的name属性值不能重复。

    • match-pattern属性:拦截对象的匹配规则,表示对哪些逻辑流的名称进行匹配。此处的逻辑流名称是全名称,包括逻辑流的包名。支持通配符*,并且最多只能有一个*。如果match-pattern="",表示对所有的逻辑流进行拦截。通配符使用举例: [字符串] [字符串] [字符串] [字符串]*[字符串]

    • handle-class属性:拦截器的实现类,需要指定类的全名。该类必须实现com.eos.engine.core.IHandler接口。

    • type属性:拦截对象的类型,支持的拦截类型如下表所示。

type值 说明
pageflow 对页面流进行拦截
businesslogic 对逻辑流进行拦截
* 对页面流、逻辑流都进行拦截
  • nodeType属性:拦截器拦截图元的类型。逻辑流当中每种不同的图元都有不同的类型对象,可以为拦截器按照图元的类型设置拦截方式。如果有多个,可以用英文逗号","分开。 逻辑流中支持的图元类型如下表所示:
图元类型 说明
Start 对逻辑流开始图元进行拦截
End 对逻辑流结束图元进行拦截
assign 对逻辑流赋值图元进行拦截
Invoke 对逻辑流调用运算逻辑、服务图元进行拦截
subprocess 对逻辑流调用子逻辑流图元进行拦截
loopstart 对逻辑流循环开始图元进行拦截
loopend 对逻辑流循环结束图元进行拦截
transactionBegin 对逻辑流事务开始图元进行拦截
transactionCommit 对逻辑流事务提交图元进行拦截
transactionRollback 对逻辑流事务回滚图元进行拦截
Switch 对逻辑流空操作图元进行拦截
Throw 对逻辑流异常抛出图元进行拦截
webservice 对Web Service调用图元进行拦截
* 表示对所有的图元进行拦截
  • nodeID属性:拦截器可以按照图元的ID进行精确的拦截,当希望拦截多个图元ID的时候,可以用英文逗号","分开。"*"表示对所有的图元都进行拦截。

    注意

    • nodeType和nodeID是或的关系,既当nodeType和nodeID满足任何其中的一个时候,都会进行拦截;其他的元素之间是与的关系;
    • 当nodeType和nodeID同时为""的时候,表示对逻辑流进行拦截,而不是拦截某一个具体的图元。

# 关键类

  • IHandler类: 用户需要实现该接口,实现类可以在调用逻辑流特定图元的时候,执行特定的用户业务操作,达到对页面流拦截的目的。 类定义如下:
public interface IHandler {
     public static final int RET_OK = 1;
     public static final int RET_BREAK = 7;
     public static final int RET_TERMINATE = 9;
    int doBefore(IRuntimeContext context);
    int doAfter(IRuntimeContext context);
    int doException(IRuntimeContext context,Throwable t);
    int doFinalize(IRuntimeContext context);
}

IHandler类操作说明:

方法签名 功能说明
int doBefore(IRuntimeContext context) 在执行目标之前触发动作,如果发生错误应该抛出HandlerTerminateException类型异常
int doAfter(IRuntimeContext context) 在执行目标之后触发动作,如果发生错误应该抛出HandlerTerminateException类型异常
int doException(IRuntimeContext context,Throwable t) 在执行目标发生异常时触发动作,如果发生错误应该抛出HandlerTerminateException类型异常
int doFinalize(IRuntimeContext context) 在执行目标最后(无论是完成还是发生异常)触发动作,如果发生错误应该抛出HandlerTerminateException类型异常

IHandler定义了如下表所示的常量:

常量 功能说明
RET_OK 表示拦截器执行成功,继续执行逻辑流
RET_BREAK 系统保留,目前没有使用
RET_TERMINATE 在执行目标发生异常时触发动作,如果发生错误应该抛出HandlerTerminateException类型异常
  • IRuntimeContext类: 在handler执行的可以获取逻辑流执行的上下文,通过IRuntimeContext参数可以获取逻辑流上下文。 IRuntimeContext类操作说明:
方法签名 功能说明
String getCurrentActivityName() 获取当前图元的名字
String getCurrentActivityType() 获取当前图元的类型
String getCurrentActivityID() 获取当前图元的ID
String getCurrentActivityValue() 获取当前图元执行的Value值
public String getProcessName() 获取当前逻辑流的名称
  • HandlerTerminateException类: 该类没有任何方法,当用户希望Hanlder终止业务流程的时候,可以抛出该类型的异常。

# 应用示例

# 场景说明

逻辑流运行过程中,可能会出现异常。用户希望在逻辑流运行出现异常的时候,能够在日志中记录日志,便于问题的跟踪与管理。用户记录的异常希望记录到那个图元发生了异常、发生了什么异常,而且不希望记录日志的时候影响流程的执行(即不能因为记录日志而影响正常逻辑流流程的执行)。

为了达到上面记录逻辑流出错的日志记录问题,可以采用EOS6中提供的拦截器的功能。对逻辑流的每个图元进行拦截,当发生异常的时候,调用日志服务组件记录日志;对于记录日志时发生的任何异常都需要用户catch,避免影响业务的流程。

# 操作步骤

  1. 实现IHandler接口,完成ExceptionLogHandler.java的开发。 实现类的代码如下:
public class ExceptionLogHandler implements IHandler {
    private static final Logger logger = TraceLoggerFactory
            .getLogger(ExceptionLogHandler.class);
    public int doAfter(IRuntimeContext arg0) {
        return IHandler.RET_OK;
    }
 
    public int doBefore(IRuntimeContext arg0) {
        return IHandler.RET_OK;
    }
 
    //逻辑流发生异常时候执行日志记录功能
    public int doException(IRuntimeContext arg0, Throwable arg1) {
        try{
            String processorName = arg0.getProcessName();//逻辑流名称
            String currentID = arg0.getCurrentActivityID();//当前图元ID
            String currentName = arg0.getCurrentActivityName();//当前图元名字
            String currentType = arg0.getCurrentActivityType();//当前图元类型
            logger.error(processorName + " " + currentID + " " + currentName + " "
                    + currentType + " make an error "
                    + arg1.getMessage().toString());
            }catch(Throwable t){
}
        return IHandler.RET_OK;
    }
 
    public int doFinalize(IRuntimeContext arg0) {
        return IHandler.RET_OK;
    }
}
  1. 在配置文件handler-engine.xml中配置逻辑流拦截器。 下面是配置文件的信息:
<handles>
    <handle
    name="exceptionLogHandler"
    match-pattern="*"
    handle-class="com.primeton.engine.handler. ExceptionLogHandler "
    type=" businesslogic"
    nodeType="*"
    nodeID="*"/>
</handles>

参数配置说明: 例子中handler-engine.xml内容的说明:

属性 说明
name exceptionLogHandler 当前逻辑流拦截器的名字为exceptionLogHandler
match-pattern * 表示对所有的逻辑流进行拦截
handle-class com.primeton.engine.handler. ExceptionLogHandler 当前逻辑流拦截器的全称:包名+类名
type businesslogic businesslogic表示对逻辑流进行拦截
nodeType * *表示对所有类型的节点进行拦截
nodeID * *表示对所有的id进行拦截

# 命名SQL拦截器(handler-namedsql.xml

与命名SQL拦截器相关的配置文件与接口类:

配置文件/关键类 路径/包名 说明
handler- namedsql.xml eosserver\working\应用名\config\handler- namedsql.xml 可以在配置文件中配置命名SQL的拦截器,实现业务开发的功能
INamedSqlHandler com.primeton.das.sql.impl.handler.INamedSqlHandler 命名SQL拦截器接口类、用户需要实现该接口
InterceptorContext com.primeton.das.sql.impl.ibatis.sqlmap.client.InterceptorContext 命名SQL拦截器上下文,通过该上下文可以获取有关命名SQL的相关信息

# 功能描述

EOS6为命名SQL提供了Handler拦截机制,可以在命名SQL执行过程中设置拦截器。有如下的拦截时机:

  • 在查询(Query)之前;
  • 在更新(Update)之前;
  • 在插入(Insert)之前;
  • 在删除(Delete)之前。

上面的时机,是指通过EOS6提供的数据服务(DAS)功能进行命名SQL操作中发生的。开发人员可以在上述的任何一个时机,实现对命名SQL操作的拦截功能。例如:开发人员可以在对数据库表数据的任何修改的时机都记录操作人员,达到跟踪什么时间、谁修改了数据库中的数据。

# 配置文件与关键类

配置文件:handler-namedsql.xml 关键类:INamedSqlHandler、InterceptorContext

# 配置文件格式说明

文件路径:eosserver\working\应用名\config\handler- namedsql.xml handler- namedsql.xml文件格式如下:

<handlers>
    <!--命名SQL拦截器-->
    <!--
    class:拦截器实现类,必须实现com.primeton.das.sql.impl.handler.INamedSqlHandler
    matchName:匹配的命名SQL编号.isRegex:是否允许matchName使用通配符
    -->
    <!--
    <handler id="NameSQLHandler"
        class="com.primeton.server.das.namedsql.handler.Handler1">
        <match matchName="test.selectSchoolByKey"></match>
        <match matchName="test.insertSchool"></match>
        <match matchName="test.updateSchool"></match>
        <match matchName="test.deleteSchool*" isRegex="true" ></match>
    </handler>
    --> </handlers>

格式说明:

  • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。

  • handler节点:

    • id属性:配置命名SQL拦截器的名字,在配置文件中多个handler节点的id属性值不能重复。

    • class属性:命名SQL拦截器的实现类,需要指定类的全名。该类必须实现com.primeton.das.sql.impl.handler.INamedSqlHandler接口。

    • match节点:用于定义命名SQL和命名SQL拦截器的匹配规则,在一个handler节点中可以有多个match条目。

    • matchName属性:需要拦截的命名SQL名字,必须是全名,支持通配符*,需要注意通配符仅仅支持一个。 通配符使用举例: [字符串]:表示所有以[字符串]结尾的实体都能被拦截; [字符串]:表示所有以[字符串]开头的实体都能被拦截; [字符串]:表示只有和[字符串]相匹配的实体都能被拦截; [字符串1]*[字符串2]:表示所有以[字符串1]开头并且以[字符串2]结尾的实体都能被拦截。

    • isRegex属性:是否支持通配符*,取值范围为true、false,如下表所示。

isRegex值 说明
true 表示matchName属性支持通配符*,matchName属性可以按照下面的格式定义那些命名SQL需要被拦截: [字符串] [字符串] [字符串] [字符串]*[字符串]
false 表示matchName属性不支持通配符*,如果matchName中有*,表示当前的命名SQL就包含这个字符串。 举例:com.primeton.order.sql.Oder 表示当前的命名SQL本身包含*字符。

# 关键类

  • INamedSqlHandler类:

    用户需要实现该接口,实现类可以在对持久化实体操作的时候,执行特定的用户业务操作,达到对在执行持久化得时候进行拦截的目的。

    类定义如下:

public interface INamedSqlHandler {
    public void beforeQuery(InterceptorContext context);
 
    public void beforeUpdate(InterceptorContext context);
 
    public void beforeInsert(InterceptorContext context);
 
    public void beforeDelete(InterceptorContext context);
}

INamedSqlHandler类操作说明:

方法签名 功能说明
beforeQuery(InterceptorContext context) 在查询之前调用该拦截方法
beforeUpdate(InterceptorContext context) 在更新之前调用该拦截方法
beforeInsert(InterceptorContext context) 在新增之前调用该拦截方法
beforeDelete(InterceptorContext context) 在删除之前调用该拦截方法
  • InterceptorContext类:

    该类用于获取当前命名SQL的上下文信息,通过InterceptorContext可以获取如下的信息:

    Unknown macro: {span}

    • 命名SQL的ID
    • 执行的SQL语句
    • 参数信息
    • 执行Statement的类型(Insert,Update,Delete,Select,Procedure)

    InterceptorContext类操作说明:

方法签名 功能说明
String getMappedId() 获取命名SQL的ID
List<Param> getParameters() 获取参数信息
String getSql() 获取执行的SQL语句
StatementType getStatementType() 获取执行Statement的类型 有如下常量选择:
  • StatementType.UNKNOWN;
  • StatementType.INSERT;
  • StatementType.UPDATE;
  • StatementType.DELETE;
  • StatementType.SELECT;
  • StatementType.PROCEDURE;
  • # 应用示例

    # 场景说明

    用户开发的业务系统中存在一个工单表,该表中存在一个lastUpdateTime字段,在进行业务开发的时候希望每次修改工单表数据后,都要把修改时间记录到字段lastUpdateTime中。用户可以在自己的业务中自己去实现,也可以通过命名SQL拦截器的方式去实现。如果采用命名SQL拦截的方式实现,可以避免在业务逻辑中实现,大大节省了业务逻辑开发的时间。

    通过命名SQL拦截器实现原理,对工单表对应的命名SQL配置一个拦截器,在拦截器的beforeUpdate()中,修改lastUpdateTime字段的值为当前的系统时间;字段lastUpdateTime 的值会自动持久化到数据库中。

    # 操作步骤

    1. 实现INamedSqlHandler接口,完成LastUpdateTimeNamedSqlHandler.java的开发。

      在beforeUpdate操作中需要实现功能:将lastUpdateTime字段的值设置为当前的系统时间,这样可以在修改数据之前能够自动将lastUpdateTime字段值自动保存到数据库中。

      实现类的代码如下:

    public class LastUpdateTimeNamedSqlHandler implements INamedSqlHandler {
        public void beforeQuery(InterceptorContext context) {}
        public void beforeDelete(InterceptorContext context) {}
        public void beforeInsert(InterceptorContext context) {}
        public void beforeUpdate(InterceptorContext context) {
            //现在SQL语句的最后一个参数是修改时间,通过在拦截器中设置lastUpdateTime字段
    //为当前的系统时间,达到记录每次修改工单表的时间
            List<Param> list = context.getParameters();
            Param lastUpdateTimeParam = list.get(list.size());
            lastUpdateTimeParam.setValue(System.currentTimeMillis());
    }
    }
    
    1. 在配置文件handler- namedsql.xml中配置实体拦截器。

      下面是配置文件的信息:

    <handles>
        <handler id="LastUpdateTimeNamedSqlHhandler"
            class="com.primeton.server.das.handler. LastUpdateTimeNamedSqlHandler ">
            <match matchName="com.primeton.order.sql.updateSqlOrder" isRegex="true"/>
        </handler>
    </handles>
    

    该配置文件表示,对于命名SQL:com.primeton.order.sql. updateSqlOrder使用命名SQL拦截器LastUpdateTimeNamedSqlHhandler进行拦截,在对命名SQL updateSqlOrder执行更新操作的时候,会自动将lastUpdateTime字段保存到数据库中,而不需要在业务中来实现该功能。

    参数配置说明:

    例子中handler- namedsql.xml内容的说明:

    属性 说明
    id LastUpdateTimeNamedSqlHhandler 当前实体拦截器的名字为LastUpdateTimeNamedSqlHhandler
    class com.primeton.server.das.handler.LastUpdateTimeNamedSqlHandler 命名SQL拦截器的全名:包名+类名
    matchName com.primeton.order.sql.updateSqlOrder 表示对命名SQL com.primeton.order.sql.updateSqlOrder进行拦截
    isRegex true 表示matchName支持通配符*

    # 实体拦截器(handler-entity.xml)

    与实体拦截器相关的配置文件与接口类:

    配置文件/关键类 路径/包名 说明
    handler- entity.xml eosserver\working\应用名\config\handler- entity.xml 可以在配置文件中配置数据实体的拦截器,实现业务开发的功能
    IEntityHandler com.primeton.das.entity.impl.handler.IEntityHandler 实体拦截器接口类、用户需要实现该接口

    # 功能描述

    EOS6为实体持久化提供了Handler拦截机制,可以在实体持久化执行过程中设置拦截器。有如下的拦截时机:

    • 在装载数据(Load)之前;
    • 在装载数据(Load)之后;
    • 在保存数据(Save)之前;
    • 在修改数据(Update)之前;
    • 在删除数据(Delete)之后。

    上面的时机,是指通过EOS6提供的数据服务(DAS)功能进行数据库的持久化操作中发生的。开发人员可以在上述的任何一个时机,实现对持久化操作的拦截功能。例如:开发人员可以在对数据库表数据的任何修改的时机都记录操作人员,达到跟踪什么时间、谁修改了数据库中的数据。

    注意

    在通过基础构件库进行数据的批量操作(如insertEntityBatch、updateEntityBatch和deleteEntityBatch)时,配置的实体拦截器将不起作用。

    # 配置文件与关键类

    配置文件:handler-entity.xml 关键类:IIEntityHandler

    # 配置文件格式说明

    文件路径:eosserver\working\应用名\config\handler- entity.xml handler- entity.xml文件格式如下:

    <handlers>
        <!--
        实体拦截器,拦截器的执行顺序与配置定义顺序一致
        class:拦截器具体实现类名,必须实现
    com.primeton.das.entity.impl.handler.IEntityHandler
        match可以有多个,matchName,匹配的实体全名
        -->
        <!--
        <handler id="handler1"
            class="com.primeton.server.das.persistententity.handler.MyHandler">
            <match matchName="*" isRegex="true"/>
        </handler>
        -->
    </handlers>
    

    格式说明:

    • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。

    • handler节点:

      • id属性:配置实体拦截器的名字,在配置文件中多个handler节点的id属性值不能重复。

      • class属性:拦截器的实现类,需要指定类的全名。该类必须实现com.primeton.das.entity.impl.handler.IEntityHandler接口。

      • match节点:用于定义实体和拦截器的匹配规则,在一个handler节点中可以有多个match条目。

      • matchName属性:需要拦截的实体名字,必须是全名,支持通配符*,需要注意通配符仅仅支持一个。 通配符使用举例: [字符串]:表示所有以[字符串]结尾的实体都能被拦截; [字符串]:表示所有以[字符串]开头的实体都能被拦截; [字符串]:表示只有和[字符串]相匹配的实体都能被拦截; [字符串1]*[字符串2]:表示所有以[字符串1]开头并且以[字符串2]结尾的实体都能被拦截。

      • isRegex属性:是否支持通配符*,取值范围为true、false;如下表所示。

    isRegex值 说明
    true 表示matchName属性支持通配符*,matchName属性可以按照下面的格式定义那些数据实体需要被拦截: [字符串] [字符串] [字符串] [字符串]*[字符串]
    false 表示matchName属性不支持通配符*,如果matchName中有*,表示当前的数据实体就包含这个字符串。 举例:com.primeton.order.data.Oder 表示当前的数据实体本身包含*字符。

    # 关键类

    IEntityHandler类: 用户需要实现该接口,实现类可以在对持久化实体操作的时候,执行特定的用户业务操作,达到对在执行持久化得时候进行拦截的目的。 类定义如下:

    public interface IEntityHandler {
        public abstract void afterLoad(DataObject entity, Serializable primaryKey,
                String[] propertyNames, Object[] values);
     
        public abstract void beforeLoad(String entityName,IDASCriteria criteria);
     
        public abstract void beforeSave(DataObject entity, Serializable primaryKey,
                String[] propertyNames, Object[] values);
     
        public abstract void beforeUpdate(DataObject entity,
                Serializable primaryKey, String[] propertyNames,
                Object[] previousValues, Object[] currentValues);
     
        public abstract void afterDelete(DataObject entity,
                Serializable primaryKey, String[] propertyNames, Object[] values);
    }
    

    IEntityHandler类操作说明:

    方法签名 功能说明
    abstract void afterLoad() 在取出数据成为一个entity后,handler可以修改values。修改后的值仅仅是显示给用户,并不影响数据库的值。
    abstract void beforeLoad () 当查询一个entity之前,可以修改criteria,改变查询的结果。
    abstract void beforeSave() 在DAS把一个entity保存到数据库之前,handler可以修改values。修改过的属性将会持久化到数据库中。
    abstract void beforeUpdate() 在修改一个表的数据前,handler可以修改currentValues。修改过的值将会更新到数据库中。
    abstract void afterDelete() 在删掉某个记录后,可能要做配套的操作,操作实现可以写在方法中。

    # 应用示例

    # 场景说明

    用户开发的业务系统中存在一个工单表,该表中存在一个lastUpdateTime字段,在进行业务开发的时候希望每次修改工单表数据后,都要把修改时间记录到字段lastUpdateTime中。用户可以在自己的业务中自己去实现,也可以通过实体拦截器的方式去实现。如果采用实体拦截的方式实现,可以避免在业务逻辑中实现,大大节省了业务逻辑开发的时间。

    通过实体拦截器实现原理,对工单表对应的数据实体配置一个拦截器,在拦截器的beforeUpdate()中,修改lastUpdateTime字段的值为当前的系统时间;字段lastUpdateTime 的值会自动持久化到数据库中。

    # 操作步骤

    1. 实现IEntityHandler接口,完成LastUpdateTimeEntityHandler.java的开发。 在beforeUpdate操作中需要实现功能:将lastUpdateTime字段的值设置为当前的系统时间,这样可以在修改数据之前能够自动将lastUpdateTime字段值自动保存到数据库中。 实现类的代码如下:
    public class LastUpdateTimeEntityHandler implements IEntityHandler {
        public void afterLoad(DataObject entity, Serializable primaryKey,
                String[] propertyNames, Object[] values) {}
    public void beforeSave(DataObject entity, Serializable primaryKey,
                String[] propertyNames, Object[] values) {}
    public void beforeLoad(String entityName, IDASCriteria criteria) {}
    public void afterDelete(DataObject entity, Serializable primaryKey,
    String[] propertyNames, Object[] values) {}
              //在修改数据之前,将修改时间设置到字段lastUpdateTime中,
    //可以将该字段自动持久化到数据库中
    public void beforeUpdate(DataObject entity, Serializable primaryKey,
                                  String[] propertyNames, Object[] previousValues,
    Object[] currentValues) {
                   for(int i=0;i<propertyNames.length;i++){
                    if("lastUpdateTime".equals(propertyNames[i])){
                        currentValues[i]=System.currentTimeMillis();
                        break;
                    }
                  }
    }
    }
    
    1. 在配置文件handler-entity.xml中配置实体拦截器。 下面是配置文件的信息:
    <handles>
        <handler id="LastUpdateTimeEntityHhandler"
            class="com.primeton.server.das.handler. LastUpdateTimeEntityHandler ">
            <match matchName="com.primeton.order.data.salaryData" isRegex="true"/>
        </handler>
    </handles>
    

    该配置文件表示,对于数据实体com.primeton.order.data.salaryData使用实体拦截器LastUpdateTimeEntityHandler进行拦截,在对salaryData实体执行更新操作的时候,会自动将lastUpdateTime字段保存到数据库中,而不需要在业务中来实现该功能。 参数配置说明: 例子中handler-entity.xml内容的说明:

    属性 说明
    id LastUpdateTimeEntityHhandler 当前实体拦截器的名字为LastUpdateTimeEntityHhandler
    class com.primeton.server.das.handler.LastUpdateTimeEntityHandler 实体拦截器的全名:包名+类名
    matchName com.primeton.order.data.salaryData 表示对实体com.primeton.order.data.salaryData进行拦截
    isRegex true 表示matchName支持通配符*

    # Web请求拦截器(handler-web.xml)

    与Web请求拦截器相关的配置文件与接口类:

    配置文件/关键类 路径/包名 说明
    handler- web.xml eosserver\working\应用名\config\handler- web.xml web请求的拦截器配置,支持配置多个拦截器;如配置用于国际化的拦截器等。
    IWebInterceptor com.eos.access.http.IWebInterceptor 请求的拦截器,类似于filter。 用户需要实现该接口。

    # 功能描述

    在处理Web请求拦截方面,J2EE的Web容器提供了Filter的功能,用于拦截特定的请求,然后处理请求,最后将请求交给后面的Filter或者Servlet处理;为了实现该功能需要在web.xml文件中进行配置filter、filter-mapping等。在EOS6中提供了类似的功能用于拦截请求,而无须在web.xml中配置;只需要在handler-web.xml中进行配置即可,简化了web.xml的复杂度。

    # 配置文件与关键类

    配置文件:handler- web.xml 关键类:IWebInterceptor

    # 配置文件格式说明

    文件路径:eosserver\working\应用名\config\handler- web.xml handler- web.xml文件格式如下:

    <handlers>
            <!--
        请求过滤扩展注册
        国际化拦截器
        sortIdx[optional]:排序编号,数字小的先执行
        pattern:请求URL匹配模式,几种方式
        1) *.xxx,例如,*.do,*.jsp等等;
        2) /* 拦截所有请求;
        3) xxx 精确匹配,例如,/samples/test.jsp
        4) xxx/* 混合匹配,xxx必须精确匹配,例如,/samples/test/*;
        class:具体的实现类,必须实现接口com.eos.access.http.WebInterceptor
        -->
        <handler id="WSInterceptor" sortIdx="0" pattern="/*"
           class=" com.eos.access.http.UserLoginCheckedFilter "/>
    </handlers>
    

    格式说明:

    • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照sortIdx的大小先后执行,数字小的先执行。
    • handler节点:
      • id属性:请求过滤拦截器的唯一id号,多个handler之间不能重复。
      • sortIdx属性:排序编号,数字小的先执行。
      • pattern属性:请求URL匹配模式,支持如下的几种方式: .xxx,例如,.do,.jsp等等; / 拦截所有请求; xxx 精确匹配,例如,/samples/test.jsp; xxx/* 混合匹配,xxx必须精确匹配,例如,/samples/test/*。
      • class属性:具体的实现类,必须实现com.eos.access.http.WebInterceptor。

    # 关键类

    • IWebInterceptor类: Web请求拦截器必须实现接口IWebInterceptor,在实现方法中可以对请求进行处理;需要注意,在实现类的最后需要将请求的流程继续传递到后面的拦截器中,因为handler-web.xml中多个handler之间是一个链式结构。 类定义如下:
    public interface IWebInterceptor {
        /**
         * 拦截请求
         * @param request HttpServletRequest
         * @param response HttpServletResponse
         * @param interceptorChain WebInterceptorChain
         * @throws IOException
         * @throws ServletException
         */
        public void doIntercept(HttpServletRequest request,
                HttpServletResponse response, IWebInterceptorChain interceptorChain)
                throws IOException, ServletException;
    }
    

    IWebInterceptor类操作说明:

    方法签名 功能说明
    方法签名 功能说明
    doIntercept(HttpServletRequest request, HttpServletResponse response, IWebInterceptorChain interceptorChain) 拦截请求的具体操作;注意实现该方法的时候,要确保当前的拦截器处理完成后,能够传递到拦截器链上的下一个拦截器;需要实现下面的一句代码: interceptorChain.doIntercept(request, response);

    # 应用示例

    # 场景说明

    在处理Web请求的开发中,经常碰到请求编码的问题,通常的做法是实现一个filter,然后在web.xml中配置该filter;该filter负责统一处理所有请求的编码;现在我们把这一功能用EOS6提供的Web请求过滤扩展点的功能来实现。

    # 操作步骤

    1. 实现IWebInterceptor接口,完成RequestEncodingWebInterceptor.java的开发。 RequestEncodingWebInterceptor中完成请求编码的设置,将所有请求的编码设置为了"UTF-8"编码;最后将请求传递给链上的其他过滤器中。 实现类的代码如下:
    public class RequestEncodingWebInterceptor implements IWebInterceptor {
     
        //统一设置请求的编码格式为UTF-8
        public void doIntercept(HttpServletRequest request,
                HttpServletResponse response, IWebInterceptorChain interceptorChain)
                throws IOException, ServletException {
            try {
                request.setCharacterEncoding("UTF-8");
            } finally {
                //最后将请求传递到其它过滤器中
                interceptorChain.doIntercept(request, response);
            }
        }
    }
    
    1. 在配置文件handler- web.xml中配置实体拦截器。 下面是配置文件的信息:
    <handles>
        <handler id="WSInterceptor" sortIdx="0" pattern="/*"
     class="com.primeton.access. RequestEncodingWebInterceptor "/>
    </handles>
    

    因为是处理请求编码的一个拦截器,我们希望将该拦截器放在请求最入口的地方执行,因此我们配置sortIdx为"0",表示这个最优先执行。

    # 构件包加载拦截器(handler-contribution.xml)

    与构件包加载拦截器相关的配置文件与接口类:

    配置文件/关键类 路径/包名 说明
    handler- contribution.xml
  • 可以存放在应用级,位置如下:eosserver\working\应用名\config\handler- contribution.xml
  • 存放在构件包的META-INF目录下面位置如下:构件包存放路径\META-INF\handler-contribution.xml
  • 对于存放在1位置的配置文件:表示对应用中的所有构件包进行拦截;
  • 对于存放在2位置的配置文件:表示只对当前的构件包生效。
  • IContributionListener com.eos.runtime.resource.IContributionListener 用户监听接口必须实现接口IContributionListener,监听的事件类型有构件包加载事件、卸载事件和构件包加载完成事件
    IContributionEvent com.eos.runtime.resource.IContributionEvent 事件发生时,提供的事件源对象为IContributionEvent,其中包含了构件包的元数据(对应的数据文件为$构件包目录/META-INF/MANIFEST.MF)和构件包的配置信息(对应的数据文件为$构件包目录/META-INF/contribution.eosinf)
    ContributionMetaData com.eos.runtime.resource.ContributionMetaData 构件包对应的元数据对象为ContributionMetaData,构件包元数据文件为Manifest.MF格式,遵从OSGI的Bundle规范;(对应的数据文件为$构件包目录/META-INF/MANIFEST.MF)

    # 功能描述

    在构件包发生加载、卸载事件时回调用户的接口,监听构件包的变化,此监听事件是针对所对应的构件包,可以为不同构件包配置不同的监听接口。有如下的监听时机:

    • 在构件包加载(load)时;
    • 在构件包加载完成(loadFinished)时;
    • 在构件包卸载(unLoad)时。

    EOS6中默认为构件包提供了一个加载日志功能的扩展点(com.primeton.ext.common.logging.startup.ContributionLoggingStartupRuntimeListener),在每个构件包加载的时候,为构件包注册了构件包日志组件服务,用户可以在构件包中利用此处提供的日志服务记录日志。

    # 配置文件与关键类

    配置文件:handler- contribution.xml 关键类:IContributionListener、IContributionEvent、ContributionMetaData

    # 配置文件格式说明

    文件路径:

    • eosserver\working\应用名\config\handler- contribution.xml
    • 组件包目录/META-INF/handler-contribution.xml

    说明

    • 位置:eosserver\working\应用名\config\handler- contribution.xml中的扩展点会对所有的构件包起作用;
    • 位置:组件包目录/META-INF/handler-contribution.xml中的扩展点仅仅对本构件包起作用。

    handler- contribution.xml文件格式如下:

    <handlers>
        <!--
        构件运行环境(Contribution级)启动监听器,监听器的加载执行顺序按照配置的先后顺序
        该文件可以有多个,存放位置支持两种:
    1、组件包目录/META-INF/handler-contribution.xml
    2、eosserver\working\应用名\config\handler- contribution.xml
        -->
        <handler handle-class="com.primeton.ext.common.logging.startup.
    ContributionLoggingStartupRuntimeListener"/>
    </handlers>
    

    格式说明:

    • handlers节点:

      下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。

      说明

      关于执行顺序: 在同一个文件内部:按照handler的定义顺序执行; 存在应用级别配置文件和构件包级别的配置文件时候,首先执行应用级别的handler,然后执行构件包级别的handler。即:

      • 先执行:eosserver\working\应用名\config\handler- contribution.xml中的handler;
      • 后执行:组件包目录/META-INF/handler-contribution.xml中的handler
    • handler节点: handle-class属性:构件包加载、卸载扩展点的实现类,需要指定类的全名。该类必须实现com.eos.runtime.resource.IContributionListener接口。

    # 关键类

    • IContributionListener类:

      用户监听接口必须实现接口IContributionListener,监听的事件类型有构件包加载事件、卸载事件和构件包加载完成事件。

      类定义如下:

    public interface IContributionListener extends EventListener{
        /**
         * Contribution加载时执行方法.
         */
        public void load (IContributionEvent event);
         
        /**
         * Contribution加载完成时执行的任务
         */
        public void loadFinished(IContributionEvent event);
        /**
         * Contribution卸载时执行方法.
         */
        public void unLoad(IContributionEvent event);
     
    }
    

    IContributionListener类操作说明:

    方法签名 功能说明
    load (IContributionEvent event) Contribution加载时执行方法
    loadFinished(IContributionEvent event) Contribution加载完成时执行的任务
    unLoad(IContributionEvent event) Contribution卸载时执行方法
    • IContributionEvent类:

      事件发生时,提供的事件源对象为IContributionEvent,其中包含了构件包的元数据和构件包的配置信息。

      IContributionEvent类操作说明:

    方法签名 功能说明
    ContributionMetaData getContributionMetaData() 取得Contribution 元数据
    Configuration getContributionConfiguration() 取得Contribution 配置,contribution.eosinf文件内容
    • ContributionMetaData类:

      构件包元数据类,数据从构件包元数据文件Manifest.MF中获取,遵从OSGI的Bundle规范,有如下属性:

    #Manifest 默认版本
    Manifest-Version:1.0
    # Bundle-Name 构件包显示名称
    Bundle-Name: Primeton Test Composite
    #构件包的唯一标识,也就是 Bundle 的名称
    Bundle-SymbolicName: com.eos.data.simple
    # Bundle-Version构件包主版本号
    Bundle-Version: 6.0
    #构件包提供者
    Bundle-Vendor: %Primeton
    #依赖的其他构件包,可以是多个,以逗号分割
    Require-Bundle:
    #允许构件包中存在多个 jar,也可以使用相对路径作为资源加载的位置
    Bundle-ClassPath: .
    #本构件包所属的模块,
    eos-module: module1/sub_module1
    #构件包默认的名称空间
    eos-basePath: com.eos.bigbank.module1.sub_module1
    #构件包中包含所有 web 资源,相对于 web 应用根的相对目录
    eos-webCtxPath: bigbank
    

    ContributionMetaData类操作说明:

    方法签名 功能说明
    String getLabel() 获取构件包的显示名
    String getName() 获取构件包标识
    String getVersion() 获取构件包版本
    String getVendor() 获取构件包提供商
    String[] getRequired() 获取依赖的构件包标识列表
    String[] getClassPathes() 获取构件包的类路径
    String getContainingModule() 获取构件包所属的Module
    String getBasePath() 获取构件包的base path
    String getWebCtxPath() 获取构件包对应的Web Context path
    String getContributionLocation() 获取构件包的location(绝对路径)
    File getContributionDirectory() 获取构件包的location(绝对路径)

    # 应用示例

    # 场景说明

    用户期望开发一个管理组件包状态的框架,该框架包含如下功能:

    • 系统装载了那些组件包;
    • 那些组件包没有装载成功;
    • 卸载过那些组件包。

    该框架可以通过构件包加载、卸载扩展点的方式来实现:在构件包加载事件中向框架中加入装载的构件包;在构件包加载成功的事件中向框架通知构件包加载成功;在构件包卸载的事件中向框架通知该构件包已经被卸载;框架获得这些元数据信息后,框架就可以完成各种构件包状态展现的功能。

    # 操作步骤

    1. 实现IContributionListener接口,完成FrameWorkContributionListener.java的开发。

      FrameWorkContributionListener中负责完成向框架注入构件包加载、卸载、加载成功的元数据信息。

      实现类的代码如下:

    public class FrameWorkContributionListener implements IContributionListener{
        //构件包加载的时候,向统计框架注入当前构件包信息
    public void load(IContributionEvent event) {
            if (event.getContributionMetaData() != null){
            String contirbutionName = event.getContributionMetaData().getName();
            testInfo=contirbutionName;
            FrameWorkStack.addContribution("Contribution:"+contirbutionName);
            }
        }
         //构件包卸载的时候,向统计框架注入当前构件包信息
        public void unLoad(IContributionEvent event) {
            if (event.getContributionMetaData() != null){
                String contirbutionName = event.getContributionMetaData().getName();
                FrameWorkStack .addRemovedContribution("Contribution:"
    +contirbutionName);
            }
        }
         //构件包加载成功的时候,向统计框架注入当前构件包信息
        public void loadFinished(IContributionEvent event) {
            if (event.getContributionMetaData() != null){
            String contirbutionName = event.getContributionMetaData().getName();
            testInfo=contirbutionName;
            FrameWorkStack.addSuccessedContribution("Contribution:"
    +contirbutionName);
            }
        }
    }
    

    FrameWorkStack负责完成构件包各种状态的统计功能,并提供一种展现方式向用户展现。

    1. 在配置文件handler- contribution.xml中配置实体拦截器。

      由于需要拦截所有的构件包的加载,因此配置文件应该放置在应用级别的配置文件中,即位置为:eosserver\working\应用名\config\handler- contribution.xml的配置配置文件。

      下面是配置文件的信息:

    <handles>
        <handler handle-class="com.primeton.ext.contribution.framework.
    FrameWorkContributionListener "/>
    </handles>
    

    这样所有的组件包被加载、卸载的时候都能触发FrameWorkContributionListener。

    # Processor拦截器(handler-processor.xml)

    与Processor拦截器相关的配置文件与接口类:

    配置文件/关键类 路径/包名 说明
    handler- processor.xml eosserver\working\应用名\config\handler- processor.xml 请求的处理器配置文件,功能类似于在web.xml中配置不同的servlet和servlet-mapping的功能;可以为不同的请求配置不同的processor进行处理请求。
    IProcessor com.eos.access.http.IProcessor 请求处理接口类,开发者需要实现该接口。

    # 功能描述

    通常为了对不同的请求进行处理,需要在web.xml中配置多个servlet来实现;当应用中提供的servlet越来越多的时候,web.xml大的难以维护;在EOS6中提供了请求处理器的扩展配置文件,不需要在web.xml文件中进行配置,只需要在handler-processor.xml中进行配置即可;在web.xml中配置的InterceptorFilter会自动将请求根据后缀名转发给handler-processor.xml中配置的processor。

    web.xml配置的filter(InterceptorFilter)描述:

    <filter>
            <filter-name>InterceptorFilter</filter-name>
            <filter-class>com.eos.access.http.InterceptorFilter</filter-class>
     </filter>
    

    InterceptorFilter会拦截所有的请求,然后分发给不同的processor进行处理。

    # 配置文件与关键类

    配置文件:handler- processor.xml 关键类:IProcessor

    # 配置文件格式说明

    文件路径:eosserver\working\应用名\config\handler- processor.xml handler- processor.xml文件格式如下:

    <handlers>
        <!--
        processor配置扩展点
        id:编号(不能重复);
        suffix:processor匹配的后缀;
        sortIdx:排序编号,数字小的先执行;
        class:processor实现类;
        注意,即使在suffix中配置了多个后缀,但是对每一种后缀都会有不同的processor实例来对相应的请求进行处理。
        -->
        <handler id="flowProcessor" suffix=".flow,.flowx" sortIdx="0"
            class="com.primeton.ext.engine.core.processor.HttpPageFlowProcessor" /> </handlers>
    

    格式说明:

    • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照sortIdx 的顺序执行handler,数字越小越先执行。

    • handler节点:

      可以有多个handler节点,用来配置一个完成的请求处理器。

      • id属性: 表示handler的编号,在配置文件中,不同的handler之间id编号不能重复;
      • suffix属性: processor匹配的后缀名,支持多个,多个之间以","分割;
      • sortIdx属性: 排序编号,数字小的先执行;
      • class属性: 具体的实现类,必须实现com.eos.access.http.IProcessor。

    # 关键类

    IProcessor类: 用户实现接口IProcessor,需要实现关键方法process(HttpServletRequest request, HttpServletResponse response),该方法用来处理特定后缀的请求。 类定义如下:

    public interface IProcessor {
        /**
         * 设置请求的后缀名
         * 不同的后缀名的请求,会交给不同的processor进行处理
         */
        void setRequestSuffix(String requestSuffix);
         
        /**
         * 获取能处理的请求后缀名.<br>
         * @return 能处理的请求后缀名.
         */
        String getRequestSuffix();
        /**
         * 处理页面请求
         * 根据不同的后缀名,交给不同的processor进行处理
         */
        void process(HttpServletRequest request, HttpServletResponse response)
                throws IOException, ServletException;
     
        void processException(HttpServletRequest request,
                HttpServletResponse response, ExceptionObject exObj) throws IOException,
                ServletException;
    }
    

    IProcessor类操作说明:

    方法签名 功能说明
    setRequestSuffix(String requestSuffix) 设置请求的后缀名。
    String getRequestSuffix() 获取能处理的请求后缀名。
    process(HttpServletRequest request, HttpServletResponse response) 处理页面请求。 根据不同的后缀名,交给不同的processor进行处理。
    processException(HttpServletRequest request, HttpServletResponse response, ExceptionObject exObj) 处理异常情况页面请求。 根据异常对象ExceptionObject来对请求做出响应。

    # 应用示例

    # 场景说明

    我们以EOS6中的ActionProcessor为例子来介绍该扩展点的使用。EOS6中提供了页面流的概念,通常在页面中通过"_eosFlowAction"隐含域来实现请求那个action的功能。

    页面流引擎提供了一种简便的方式调用页面流,可以通过如下的方式调用:页面流名称+action名称+".action"的方式调用,这样可以在请求的url中直接写aciton的名字,而不必要在form表单中再次填写"_eosFlowAction"字段。

    为了实现上面的功能,可以通过实现一个单独的processor来完成对".action"的请求,然后在handler-processor.xml中进行配置,用ActionProcessor来完成所有的".action"的请求。

    # 操作步骤

    1. 实现IProcessor接口,完成ActionProcessor.java的开发。 ActionProcessor中处理后缀名为".action"的请求,以达到上面的场景需求。 实现类的代码如下:
    public class ActionProcessor implements IProcessor{
        private String requestSuffix;
        void setRequestSuffix(String requestSuffix){
            this.requestSuffix = requestSuffix;
        }
        String getRequestSuffix(){
            return requestSuffix;
        }
        void process(HttpServletRequest request, HttpServletResponse response)
                throws IOException, ServletException{
            //action 从请求的uri中获取
            String eosFlowAction = getRequestedActionName(request);
            ......
            //上面省略了对请求处理的代码实现
        }
        void processException(HttpServletRequest request,
                HttpServletResponse response, ExceptionObject exObj) throws IOException,
                ServletException{
            String errorPage = exObj.__getForwardPage();
            if (errorPage != null && errorPage.length() > 0) {
                if (exObj.isNeedForward()) {
                    RequestDispatcher rd = request.getRequestDispatcher(errorPage);
                    rd.forward(request, response);
                } else {
                    response.sendRedirect(errorPage);
                }
            } else {
                throw new ServletException(exObj.getThrowable());
            }
        }
    }
    
    1. 在配置文件handler- processor.xml中配置实体拦截器。 下面是配置文件的信息:
    <handles>
        <handler id="actionProcessor" suffix=".action" sortIdx="0"
            class="com.primeton.ext.engine.core.processor.ActionProcessor" /> </handles>
    

    这样所有对".action"的请求都将被转发到ActionProcessor上面进行处理,无需修改web.xml文件,就可以做到对不同请求的拦截处理。

    # 启动拦截器(handler-startup.xml)

    与启动拦截器相关的配置文件与接口类:

    配置文件/关键类 路径/包名 说明
    handler- startup.xml eosserver\working\应用名\config\handler- startup.xml 应用启动时候,需要执行的listener;达到执行回调的目的
    IRuntimeListener com.eos.runtime.core.IRuntimeListener 应用启动Listener,用户需要实现该接口
    RuntimeEvent com.eos.runtime.core.RuntimeEvent 应用启动的触发事件
    ApplicationContext com.eos.runtime.core.ApplicationContext 应用上下文信息,可以获取和应用相关的配置信息

    # 功能描述

    在应用启动、停止,构件运行环境提供了一种回调机制;当应用启动、停止事件发生时,可以回调用户定义的操作,完成其特定的功能。通常可以完成功能模块的初始化、为应用开启一种新的服务等。

    EOS在handler- startup.xml文件中配置了一系列应用启动监听器、这些默认监听器用户尽量不要修改,否则可能会引起某些功能性异常,但用户可以配置自己的监听器,以便在应用启动、停止的时候执行用户自定义的动作。

    # 配置文件与关键类

    配置文件:handler- startup.xml 关键类:IRuntimeListener、RuntimeEvent、ApplicationContext

    # 配置文件格式说明

    文件路径:eosserver\working\应用名\config\handler- startup.xml handler- startup.xml文件格式如下:

    <handlers>
        <!--启动DAS_ENTITY-->
        <handler handle-class="com.primeton.ext.das.common.
    DASCommonStartupListener"/>
    </handlers>
    

    格式说明:

    • handlers节点: 下面可以配置多个handler节点,多个handler节点之间的执行顺序,按照配置文件的顺序执行各个handler。
    • handler节点: 可以有多个handler节点,不同的handler执行顺序按照配置文件中定义的顺序执行。 handle-class属性: 具体的实现类,必须实现com.eos.runtime.core.IRuntimeListener。

    # 关键类

    • IRuntimeListener类:

      用户实现接口IRuntimeListener,需要分别实现start()和stop()方法,分别在应用启动和应用停止的时候回调用户的操作。

      类定义如下:

    public interface IRuntimeListener {
        /**
         * 启动应用
         * @param envent
         */
        public void start(RuntimeEvent envent);
         
        /**
         * 结束应用
         * @param envent
         */
        public void stop(RuntimeEvent envent);
    }
    

    IRuntimeListener类操作说明:

    方法签名 功能说明
    start(RuntimeEvent envent) 应用启动的时候,会触发该操作
    stop(RuntimeEvent envent) 应用停止的时候,会触发该操作
    • RuntimeEvent类:

      在应用启动、停止的时候,会发出该事件,通过RuntimeEvent可以获取:

      Unknown macro: {span}

      • 系统配置文件对象;
      • 用户配置文件对象;
      • 用户自定义配置文件对象;
      • 应用上下文对象。

      RuntimeEvent类操作说明:

    方法签名 功能说明
    ApplicationContext getApplicationContext() 应用上下文对象ApplicationContext
    Configuration getSystemConfiguration() 系统配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/sys-config.xml)
    Configuration getUserConfiguration() 用户配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/user-config.xml)
    Configuration getUserLocalConfiguration() 用户自定义配置文件对象Configuration(对应配置文件$EOS_HOME/working/$AppName/config/user-local-config.xml)
    • ApplicationContext类:

      应用上下文类,可以获取以下的应用环境信息:

      ApplicationContext类操作说明:

    方法签名 功能说明
    方法签名 功能说明
    String getEOS_HOME() 获取返回EOS_HOME路径
    String getAppName() 获取应用名
    String getApplicationWorkPath() 获取应用的工作路径 eg:eosserver/working/eos-default
    String getApplicationConfigPath() 获取应用配置文件路径 eg:eosserver/working/eos-default/config
    String getApplicationSysConfigurationFile() 取得应用级别系统配置文件(sys-config.xml)的全路径
    String getApplicationUserConfigurationFile() 取得应用级别用户配置文件(user-config.xml)的全路径
    String getApplicationUserLocalConfigurationFile() 取得应用级别本地用户自定义配置文件(user-local-config.xml)的全路径
    String getApplicationSystemWorkingPath() 取得系统构件包的工作路径
    String getApplicationUserWorkingPath() 取得用户构件包的工作路径
    String getEarRealPath() 取得应用EAR的实际路径
    String getWarRealPath() 取得应用WAR的类路径
    String getWebContextPath() 取得应用对应的WEB Context名称

    # 应用示例

    # 场景说明

    用户拿到EOS之后,自行开发了一个平台模块(统计监控)的功能,希望在EOS应用启动的时候将该平台模块(统计监控)启动起来,以方便对外提供服务使用。

    为了实现上述的场景,用户只需要简单的实现IRuntimeListener接口,然后在hanlder-startup.xml配置上述Listener即可。

    # 操作步骤

    1. 实现IRuntimeListener接口,完成StatisticRuntimeListener.java的开发。

      StatisticRuntimeListener中统计监控模块的启动和停止功能。

      实现类的代码如下:

    public class StatisticRuntimeListener implements IRuntimeListener{
    /**
     * 打开统计功能
     */
    public void start(RuntimeEvent envent) {
        //打开统计功能
        Statistic.openStatistic();
    }
    /**
     * 关闭统计功能
     */
    public void stop(RuntimeEvent envent) {
        //关闭统计功能
        Statistic.closeStatistic();
    }
    }
    
    1. 在配置文件handler- startup.xml中配置实体拦截器。

      下面是配置文件的信息:

    <handles>
        <!—统计功能模块-->
        <handler handle-class="com.primeton.ext.runtime.resource.
    startup.StatisticRuntimeListener"/>
    </handles>
    

    这样在应用启动的时候,就可以将统计模块自动的加载起来;可以对外提供统计服务功能。

    # 资源访问检查拦截器(IAccessedResourceCheckedHandler接口)

    与事务同步扩展点相关的接口类: 关键类说明:

    关键类 包名 说明
    IAccessedResourceCheckedHandler com.eos.access.authorization.IAccessedResourceCheckedHandler 资源访问检查接口
    IAccessedResourceFactory com.eos.access.authorization.IAccessedResourceFactory 可访问资源创建工厂
    IAccessedResource com.eos.access.authorization.IAccessedResource 可访问资源对象

    # 功能描述

    资源访问授权检查接口,可以利用该接口完成具体的授权访问策略。用来检查用户是否拥有对某些资源进行访问的权限。这里接口的实现者需要根据自己业务上的规则,确定用户可以访问的资源;如果用户可以访问资源,返回通过;否则返回不通过。

    # 关键类

    关键类:IAccessedResourceCheckedHandler、IAccessedResourceFactory

    • IAccessedResourceCheckedHandler类: 类定义如下:
    public interface IAccessedResourceCheckedHandler extends Serializable {
        /**
         * 检查用户是否可以访问资源.<br>
         * @param accessedResource 被访问的资源.
         * @param userObject 用户对象.
         * @return 检查结果.
         */
        CheckedResult check(IAccessedResource accessedResource,
                IUserObject userObject);
    }
    

    IAccessedResourceCheckedHandler类操作说明:

    方法签名 功能说明
    check(IAccessedResource accessedResource, IUserObject userObject) 校验用户使用可以访问资源
    • IAccessedResource 可访问资源类,类包含一个资源的唯一标示符URI和一个资源类型。类定义如下:
    public interface IAccessedResource extends Serializable {
        /**
         * 获取资源对应的URI.<br>
         * 如: /user/login.jsp;com.eos.userLogin.flow
         * @return 资源对应的URI.
         */
        String getResourceURI();
     
        /**
         * 获取资源类型.<br>
         * 见{@link AccessedResourceType#BIZ_RESOURCE}
         * @return 资源类型.
         */
        int getResourceType();
    }
    
    • IAccessedResourceFactory 资源访问工厂类,用来创建可以访问的资源对象IAccessedResource(包含resourceURI和resourceType两个属性)。EOS系统缺省提供了一个DefaultAccessedResourceFactory工厂类,可以创建jsp页面、页面流、逻辑流、服务等资源信息。用户可以扩展这个接口,提供新的访问资源。资源类定义如下:
    public interface IAccessedResourceFactory {
        /**
         * 创建资源对象.<br>
         * @param context 资源访问的上下文.
         * @return 资源对象.
         */
        IAccessedResource create(IAccessedResourceContext context);
    }
    

    下面是DefaultAccessedResourceFactory类的例子,用户如果想扩展,可以参考这个例子来写。

    public class DefaultAccessedResourceFactory implements
            IAccessedResourceFactory {
        private static IAccessedResourceFactory factory = new DefaultAccessedResourceFactory();
     
        public static IAccessedResourceFactory getInstance() {
            return factory;
        }
     
        public IAccessedResource create(IAccessedResourceContext context) {
            //先做用户定义的
        if (AccessedResourceCustomFactoryProvider.getFactory() != null) {
            IAccessedResource resource = AccessedResourceCustomFactoryProvider
                    .getFactory().create(context);
            if (resource != null)
                return resource;
        }
        String resource = context.getResource();
        switch (context.getResourceType()) {
        case AccessedResourceType.PAGE_RESOURCE:
            AccessedHttpResource pageResource = new AccessedPageResource(resource);
            pageResource.setRequest(context.getRequest());
            pageResource.setResponse(context.getResponse());
            return pageResource;
        case AccessedResourceType.PAGE_FLOW_RESOURCE:
            AccessedPageFlowResource pageFlowResource = new AccessedPageFlowResource(resource);
            pageFlowResource.setRequest(context.getRequest());
            pageFlowResource.setResponse(context.getResponse());
            String eosFlowAction=(String)context.getRequest().getAttribute(AbstractPageFlowProcessor.EOS_PAGEFLOW_ACTION);
            if(eosFlowAction == null){
                eosFlowAction=(String)context.getRequest().getParameter(AbstractPageFlowProcessor.EOS_PAGEFLOW_ACTION);
            }
            pageFlowResource.setActionName(eosFlowAction);
            return pageFlowResource;
        case AccessedResourceType.BIZ_RESOURCE:
            AccessedBizResource bizResource = new AccessedBizResource(resource);
            return bizResource;
        case AccessedResourceType.SERVICE_RESOURCE:
            AccessedServiceResource serviceResource = new AccessedServiceResource(resource);
            return serviceResource;
        default:
            throw new IllegalArgumentException(
                    "the type cannot create IAccessedResource");
            }
        }
    }
    

    # 应用示例

    # 场景说明

    用户希望完成对资源的访问控制,不同的用户对不同的资源有不同的权限。可以实现IAccessedResourceCheckedHandler接口,定义不同用户对资源的访问规则。

    示例中只有用户名为"root"的超级用户有访问逻辑流资源的权限;其它用户都没有访问权限。

    # 示例实现

    1. 实现IAccessedResourceCheckedHandler接口,完成MyAccessedResourceCheckedHandler的开发。 内部的判断逻辑,是只有用户名为"root"的超级用户拥有访问逻辑流的权限; 实现类的代码如下:
    public class MyAccessedResourceCheckedHandler implements
     IAccessedResourceCheckedHandler{
        public CheckedResult check(IAccessedResource accessedResource,
                IUserObject userObject){
    boolean isRoot = "root".equals(userObject.getUserId());
            //是否是逻辑流资源
    boolean isBizResource = (AccessedResourceType.BIZ_RESOURCE ==
     accessedResource.getResourceType());
            if(isBizResource){
                if(isRoot){
                    return CheckedResult.PASS;
                }else{
                    return CheckedResult.REJECT;
                }
            }
            return CheckedResult.PASS;
        }
    }
    
    1. 在EOS管理控制台上配置资源监察拦截器。 登录Governor,选择"配置—资源方法权限"菜单,进入配置页面如下,将用户自定义的资源检查拦截器和资源创建工厂类名写入配置项,按"确定"更新。 img 以上配置对应配置文件user-config.xml下面的配置内容:
    <!-- 资源访问的检查 -->
    <module name="Accessed-Resource-Checked">
        <group name="Provider">
            <!-- 用户自定义资源检查的handler -->
            <configValue key="CheckedHandler">
    com.primeton.sample. MyAccessedResourceCheckedHandler </configValue>
            <!-- 用户自定义资源的创建工厂 -->
            <configValue key="ResourceFactory">
                com.primeton.ext.access.authorization.DefaultAccessedResourceFactory
            </configValue>
        </group>
    </module>
    

    # 系统服务监听(LifecycleSupport接口)

    与系统服务监听相关的接口类: 配置文件、关键类说明:

    关键类 路径/包名 说明
    config.xml 安装目录/eosserver/config/config.xml 配置生命周期接口实现类
    ILifecycle com.eos.system.ILifecycle 生命周期接口类
    ILifecycleListener com.eos.system.ILifecycleListener 生命周期事件监听器,监听生命周期事件
    LifecycleEvent com.eos.system.LifecycleEvent 定义了生命周期的事件
    LifecycleSupport com.eos.system.LifecycleSupport 生命周期接口支持类,实现了部分ILifecycle和ILifecycleListener接口,并可以触发所有监听器处理生命周期事件; 用户可以直接使用该抽象类来完成上面的接口完成的功能,大大简化了用户使用的复杂度。

    # 功能描述

    系统服务是EOS服务器最底层的服务,主要负责整个EOSserver的生命周期管理、EOS域的管理、EOS应用的管理和部署、主管服务器和被管服务之间的相互通讯、应用的同步等管理操作。

    系统服务提供了一个服务的生命周期的管理框架,允许用户在EOS服务器启动过程中,运行用户自定义的服务。也就是说,用户通过扩展开发可以在EOS Server启动的过程中加入自己希望启动的底层服务。

    # 关键类

    关键类:ILifecycle、ILifecycleListener、LifecycleEvent、LifecycleSupport

    • ILifecycle类: 生命周期的接口类,用户需要重点实现其中的start()和 stop()两个方法,分别表示服务的启动、服务的停止操作。 类定义如下:
    public interface ILifecycle {
        public static final  String  START_EVENT="start";
        public static final  String  STOP_EVENT="stop";
     
        public void start() throws LifecycleException;
        public void stop() throws LifecycleException;
        public void addLifecycleListener(ILifecycleListener listener);
        public List<ILifecycleListener> findLifecycleListeners();
        public void removeLifecycleListener(ILifecycleListener listener);
    }
    

    ILifecycle类操作说明:

    方法签名 功能说明
    start() 服务启动入口
    stop() 服务停止入口
    addLifecycleListener(ILifecycleListener listener) 注册生命周期监听器
    List<ILifecycleListener> findLifecycleListeners() 查找所有注册过的生命周期监听器
    removeLifecycleListener(ILifecycleListener listener) 删除生命周期监听器
    • ILifecycleListener类: 生命周期事件监听器类,用于监听生命周期事件。 ILifecycleListener类操作说明:
    方法签名 功能说明
    void handleEvent(LifecycleEvent event) 处理生命周期事件
    • LifecycleEvent类: 生命周期事件类,主要包括事件的类型、事件的发生源、上下文数据等。 LifecycleEvent类操作说明:
    方法签名 功能说明
    Object getData() 上下文数据,一般传入ServerContext
    ILifecycle getLifecycle() 事件的发生源(是触发时间的ILifecycle实例)
    String getType() 获取事件的类型,通常有两种,由ILifecycle的常量来定义。 START_EVENT:启动事件 STOP_EVENT:停止事件
    • LifecycleSupport类: 生命周期接口支持类,实现了部分ILifecycle和ILifecycleListener接口,并可以触发所有监听器处理生命周期事件; 用户可以直接使用该抽象类来完成上面的接口完成的功能,大大简化了用户使用的复杂度(com.eos.system.LifecycleSupport抽象类,这个类实现了ILifecycle接口和ILifecycleListener接口); 用户直接使用这个抽象类的时候,只需要实现start()和stop()两个方法。

    # 应用示例

    # 场景说明

    本例中在EOS系统服务启动的过程中,启动一个时间服务器,当客户端每次访问的时候,可以返回当前的服务器端的时间。

    # 示例实现

    1. 继承LifecycleSupport抽象类,完成TimeService的开发。 TimeServer中,主要实现了start()和stop()方法。提供的时间服务,通过创建一个ServerSocket连接,将当前服务器的时间返回给客户端。 实现类的代码如下:
    public class TimeService extends LifecycleSupport {
        private TimeServiceThread timeService;
     
        static class TimeServiceThread extends Thread {
            private ServerSocket server;
     
            public ServerSocket getServerSocket() {
                return server;
            }
     
            public void run() {
                int port = ServerContext.getInstance().getAdminPort()+1;
                try {
                    server = new ServerSocket(port);
                    System.out.println("Time Service is opened on port " + port);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
                Socket connection = null;
                while (true) {
                    try {
                        if (this.isInterrupted()) { // 中断线程
                            server.close();
                            System.out.println("Time Service is stopped.");
                            break;
                        }
                        connection = server.accept();
                        Writer out = new OutputStreamWriter(
    connection.getOutputStream());
                        Date now = new Date();
                        out.write(now + "\r\n");
                        out.flush();
                        connection.close();
                    } catch (IOException ex) {
                    } finally {
                        try {
                            if (connection != null) connection.close();
                        } catch (IOException ex) {
                        }
                    }
                }
            }
        }
     
        public void start() throws LifecycleException {
            this.timeService = new TimeServiceThread();
            this.timeService.start();
        }
     
        public void stop() throws LifecycleException {
            this.timeService.interrupt();
        }
    }
    
    1. 在安装目录/eosserver/config/config.xml文件中配置时间服务器。 参见下面的代码示例:
    <listeners>
            <listener name="TimeService" className="test.TimeService"/>
    </listeners>
    
    1. 为了完整的演示效果,这里提供一个客户端的代码;通过执行客户端的代码,可以获取服务器端的时间。

      注意

      为了正确执行,需要正确的配置Socket的ip和端口号。

      参见下面的客户端代码示例:

    public static void main(String[] args) {
            try {
                Socket soc = new Socket("localhost", 6287);
                BufferedReader br = null;
                InputStreamReader isr;
                isr = new InputStreamReader(soc.getInputStream ());
                br = new BufferedReader (isr);
                String result = br.readLine();
                System.out.println(result);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
     
        }
    

    执行上面的main函数后,可以从控制台看到服务器端的时间: Thu Sep 17 16:00:33 CST 2009

    上次更新: 2023/7/20下午12:25:28