基于Drools规则引擎的企业级应用系列(五)

     规则引擎编辑中的最重要的两个部分就是:模型model和商务规则business rule。比如说你的业务系统现在要增加一个字段fieldA,就会引起model的变化,新的规则就需要能够动态发现fieldA,并且能够支持fieldA的数据录入和校验,这样才算是动态的系统。

     model的动态原理上很简单,就是动态生成Java类,drools中通过declare model来实现。原始的模型比较简单,效果如下:基于Drools规则引擎的企业级应用系列(五)_第1张图片

我希望达到的效果是这样:

基于Drools规则引擎的企业级应用系列(五)_第2张图片
 支持从XML Schema中选择对应的节点,同时在属性上能够更加丰富,支持正则表达式。为了达到这个效果,同时保持对原有的兼容,就需要创建一个新的资产(Asset)类型。

    新增资产类型首先在contenthandler.properties文件中定义

# for models
model.drl=org.drools.guvnor.server.contenthandler.drools.FactModelContentHandler

# for new models
mymodel.drl=org.drools.guvnor.server.contenthandler.drools.MyModelContentHandler

 新定义的MyModelContentHandler是用来控制model和持久数据之间的访问的,参考FactModelContentHandler的写法,编写自己的实现。

public class MyModelContentHandler extends ContentHandler
    implements
    ICanRenderSource {

    private static final LoggingHelper log = LoggingHelper.getLogger( FactModelContentHandler.class );

    @Override
    public void retrieveAssetContent(Asset asset,
                                     AssetItem item) throws SerializationException {
        try {
            List<FactMetaModel> models = unmarshall( item.getContent() );
            FactModels ms = new FactModels();
            ms.models = models;
            asset.setContent( ms );
        } catch ( Exception e ) {
            log.error( "Unable to parse the MyModel for the model - falling back to text (" + e.getMessage() + ")" );
            RuleContentText text = new RuleContentText();
            text.content = item.getContent();
            asset.setContent( text );
        }

    }

    @Override
    public void storeAssetContent(Asset asset,
                                  AssetItem repoAsset)
                                                      throws SerializationException {
        if ( asset.getContent() instanceof FactModels ) {
            FactModels fm = (FactModels) asset.getContent();
            repoAsset.updateContent( marshall( fm.models ) );
        } else {
            RuleContentText text = (RuleContentText) asset.getContent();
            repoAsset.updateContent( text.content );
        }

    }

    public void assembleSource(PortableObject assetContent,
                               StringBuilder stringBuilder) {
    	FactModels fms = (FactModels) assetContent;
        for ( FactMetaModel fm : fms.models ) {
            stringBuilder.append( toDRL( fm ) );
            stringBuilder.append( "\n\n" );
        }
    }


    List<FactMetaModel> toModel(String drl) throws DroolsParserException {
        if ( drl != null && (drl.startsWith( "#advanced" ) || drl.startsWith( "//advanced" )) ) {
            throw new DroolsParserException( "Using advanced editor" );
        }
        DrlParser parser = new DrlParser();
        PackageDescr pkg = parser.parse( drl );
        if ( parser.hasErrors() ) {
            throw new DroolsParserException( "The model drl " + drl + " is not valid" );
        }

        if ( pkg == null ) return new ArrayList<FactMetaModel>();
        List<TypeDeclarationDescr> types = pkg.getTypeDeclarations();
        List<FactMetaModel> list = new ArrayList<FactMetaModel>( types.size() );
        for ( TypeDeclarationDescr td : types ) {
            FactMetaModel mm = new FactMetaModel();
            mm.setName( td.getTypeName() );
            mm.setSuperType( td.getSuperTypeName() );

            Map<String, TypeFieldDescr> fields = td.getFields();
            for ( Map.Entry<String, TypeFieldDescr> en : fields.entrySet() ) {
                String fieldName = en.getKey();
                TypeFieldDescr descr = en.getValue();
                FieldMetaModel fm = new FieldMetaModel( fieldName,
                                                        descr.getPattern().getObjectType(), 
                                                        null,
                                                        null,
                                                        null,
                                                        null);

                mm.getFields().add( fm );
            }

            list.add( mm );
        }
        return list;
    }
    
    public String marshall(List<FactMetaModel> models){
    	MyModelPersistence persistence = MyModelPersistence.getInstance();
    	StringBuilder sb = new StringBuilder();
    	sb.append("<Model>");
        for ( FactMetaModel factMetaModel : models ) {
            String str = persistence.marshal( factMetaModel );
            sb.append( str ).append( "\n\n" );
        }
        sb.append("</Model>");
        return sb.toString().trim();
    }
    
    public static List<FactMetaModel> unmarshall(String content){
    	
    	String xml = content.replaceAll("<Model>", "").replace("</Model>", "");
    	
    	MyModelPersistence persistence = MyModelPersistence.getInstance();
    	if(content == null || content.trim().length() == 0){
    		return new ArrayList<FactMetaModel>();
    	}
    	String[] strs = xml.split("\n\n");
    	List<FactMetaModel> list = new ArrayList<FactMetaModel>( strs.length );
        for ( String str : strs ) {
            FactMetaModel mm = persistence.unmarshal(str);
            list.add( mm );
        }
        return list;
    }
    
    public static String toDRL(String content) {
    	List<FactMetaModel> models = unmarshall( content );
        StringBuilder sb = new StringBuilder();
        for ( FactMetaModel factMetaModel : models ) {
            String drl = toDRL( factMetaModel );
            sb.append( drl ).append( "\n\n" );
        }
        return sb.toString().trim();
    }
    /*
    * 获得模型中的字段对应的中文显示名称
    */    
    public static Map<String, String> getDisplayNames(AssetItem item){
    	Map<String, String> displayNames = new HashMap<String, String>();
    	List<FactMetaModel> models = unmarshall( item.getContent() );
        for ( FactMetaModel factMetaModel : models ) {
        	displayNames.put(factMetaModel.getName(), factMetaModel.getDisplayName());
        	for ( int i = 0; i < factMetaModel.getFields().size(); i++ ) {
                FieldMetaModel f = factMetaModel.getFields().get( i );
                displayNames.put(factMetaModel.getName() + "." + f.name, f.displayName);
            }
        }
    	return displayNames;
    }
    /*
     * 获得模型中每个字段的限制正则表达式
     */    
    public static Map<String, String> getRestrictions(AssetItem item){
    	Map<String, String> regexs = new HashMap<String, String>();
    	List<FactMetaModel> models = unmarshall( item.getContent() );
        for ( FactMetaModel factMetaModel : models ) {
        	for ( int i = 0; i < factMetaModel.getFields().size(); i++ ) {
                FieldMetaModel f = factMetaModel.getFields().get( i );
                regexs.put(factMetaModel.getName() + "." + f.name, f.regex);
            }
        }
    	return regexs;
    }
    /*
    * 将FactMetaModel翻译成DRL文件
    */
    static String toDRL(FactMetaModel mm) {
        StringBuilder sb = new StringBuilder();
        sb.append( "declare " ).append( mm.getName() );
        if ( mm.hasSuperType() ) {
            sb.append( " extends " );
            sb.append( mm.getSuperType() );
        }
        for ( int i = 0; i < mm.getFields().size(); i++ ) {
            FieldMetaModel f = mm.getFields().get( i );
            sb.append( "\n\t" );
            sb.append( f.name ).append( ": " ).append( f.type );
        }
        sb.append( "\nend" );
        return sb.toString();
    }
    /*
    * 获得模型中每个字段的修饰操作标记,可以是可读写的、只读、只写状态
    */
    public static Map<String, FieldAccessorsAndMutators> getAccessorsAndMutators(
			AssetItem as) {
    	Map<String, FieldAccessorsAndMutators> fieldAccessors = new HashMap<String, FieldAccessorsAndMutators>();
    	List<FactMetaModel> models = unmarshall( as.getContent() );
        for ( FactMetaModel factMetaModel : models ) {
        	for ( int i = 0; i < factMetaModel.getFields().size(); i++ ) {
                FieldMetaModel f = factMetaModel.getFields().get( i );
                FieldAccessorsAndMutators accessor;
                if(f.scope.equals("when")){
                	accessor = FieldAccessorsAndMutators.ACCESSOR;
                }else if(f.scope.equals("then")){
                	accessor = FieldAccessorsAndMutators.MUTATOR;
                }else{
                	accessor = FieldAccessorsAndMutators.BOTH;
                }
                fieldAccessors.put(factMetaModel.getName() + "." + f.name, accessor);
            }
        }
    	return fieldAccessors;
	}
    
}

 相应的模型定义为

/**
 * Represents the GUI data for a fact model definition.
 */
public class FactMetaModel
    implements
        PortableObject {

    private static final long         serialVersionUID = 510L;

    private String                    name;
    private String	          displayName;
    private String                    superType;
    private List<FieldMetaModel> fields = new ArrayList<FieldMetaModel>();
    //List reference schema by this fact
    private List<String[]>      schemas  = new ArrayList<String[]>();
    
    public List<String[]> getSchemas() {
        return schemas;
    }

    public void setSchemas(List<String[]> schemas) {
         this.schemas = schemas;
    }

    public FactMetaModel() {
    }

    public FactMetaModel(String name, String displayName) {
        this.name = name;
        this.displayName = displayName;
    }

    public FactMetaModel(String name,
                         String displayName,
                         List<FieldMetaModel> fields) {
        this.name = name;
        this.displayName = displayName;
        this.fields = fields;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDisplayName() {
        return displayName;
    }

    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }
 
    public List<FieldMetaModel> getFields() {
        return fields;
    }

    public void setFields(List<FieldMetaModel> fields) {
        this.fields = fields;
    }

    public void setSuperType(String superType) {
        this.superType = superType;
    }

    public String getSuperType() {
        return this.superType;
    }

    public boolean hasSuperType() {
        return this.superType != null;
    }
}

 

这样,后台和数据层的交道就差不多了,下一篇我们介绍如何在前端实现增强的效果。

 

你可能感兴趣的:(drools)