规则引擎编辑中的最重要的两个部分就是:模型model和商务规则business rule。比如说你的业务系统现在要增加一个字段fieldA,就会引起model的变化,新的规则就需要能够动态发现fieldA,并且能够支持fieldA的数据录入和校验,这样才算是动态的系统。
model的动态原理上很简单,就是动态生成Java类,drools中通过declare model来实现。原始的模型比较简单,效果如下:
我希望达到的效果是这样:
支持从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; } }
这样,后台和数据层的交道就差不多了,下一篇我们介绍如何在前端实现增强的效果。