查詢Auditing history及應用說明

        在《FileNet Auditing簡單配置及說明》中已經介紹了Auditing的作用及其能夠統計的相關內容。可以說其對評估一個文檔類產品的利用情況很有價值,對此早些購買FileNet產品的公司(如zhy)會直接在XT上進行定製開發,使其具備文檔報表統計功能。

         整個報表統計過程,其實就是對auditing history的查詢過程,其映射的是對event log的查詢。就像我們查詢Document類型(或自定義Document類型)一樣,我們使用的方式是相同的。在理解好Query語法的基礎上,便能容易的進行相關操作了。代碼示例如下所示。

public long getAuditingInfos(ObjectStore os,
												Date startDate,
												Date endDate,
												Id auditingType,
												Boolean 				needParentClassType,
												String topParentClass,
												
) throws Exception{
		
		
		long total = 0;
		
		AuditingInfoBean bean = null;
		RepositoryRowSet rrs = null;
		RepositoryRow rr = null;
		
		if(startDate != null && endDate != null && 
				(rrs = buildData(os,startDate,endDate,auditingType)) != null){
			
			PageIterator iter = rrs.pageIterator();
			while (iter.nextPage())
			{
			    Object[] currentPage = iter.getCurrentPage();
			    if(currentPage != null){
			    	for(int i=0;i<currentPage.length;i++){
			    		rr = (RepositoryRow)currentPage[i];
			    		
			    		if(null != rr && rr.getProperties().getInteger32Value(PropertyNames.EVENT_STATUS) == 0){
			    			
					    	try{
					    		rr.getProperties().getIdValue(PropertyNames.ID).toString();
					    		rr.getProperties().getObjectValue(PropertyNames.CREATOR);
					    		rr.getProperties().getIdValue(PropertyNames.SOURCE_OBJECT_ID);
					    		Id classId = rr.getProperties().getIdValue(PropertyNames.SOURCE_CLASS_ID);
					    		PropertyFilter filter = new PropertyFilter();
								FilterElement ele0 = new FilterElement(null, null, null, PropertyNames.SYMBOLIC_NAME, null);
								FilterElement ele1 = new FilterElement(null, null, null, PropertyNames.SUPERCLASS_DESCRIPTION, null);
								filter.addIncludeProperty(ele0);
								filter.addIncludeProperty(ele1);
								ClassDescription classDescription = Factory.ClassDescription.fetchInstance(os, classId, filter);
								String selfSymbolicName = classDescription.get_SymbolicName();
					    		
					    	}catch(Exception e){
					    		logger.error(e.toString());
					    		continue;
					    	}
			    		}
			    	}
			    }
			}
		}
		
		return total;
	}
	
	private RepositoryRowSet buildData(ObjectStore os,Date startDate,Date endDate,Id auditingType){

		RepositoryRowSet rrs  = null;
		
		if(AuditingUtil.CREATIONEVENT == auditingType 
				|| AuditingUtil.GETCONTENTEVENT == auditingType){
			
			String sqlString = "SELECT "  + PropertyNames.CREATOR + "," + 
											PropertyNames.ID + "," + 
											PropertyNames.DATE_CREATED + "," + 
											PropertyNames.EVENT_STATUS + "," + 
											PropertyNames.SOURCE_CLASS_ID + "," + 
											PropertyNames.SOURCE_OBJECT_ID;

			SearchSQL searchSql = new SearchSQL(sqlString + 
									" FROM " + auditingType + 
							        " WHERE " + 
							        	PropertyNames.DATE_CREATED + " >= " + dateFormat(startDate) + 
							        	" AND " + 
							        	PropertyNames.DATE_CREATED  + " < " + dateFormat(endDate) +
							        " ORDER BY " + PropertyNames.DATE_CREATED);
			
			SearchScope ss = new SearchScope(os);
			
			PropertyFilter filter = new PropertyFilter();
			FilterElement ele1 = new FilterElement(null, null, null, PropertyNames.EVENT_STATUS, null);
			FilterElement ele2 = new FilterElement(null, null, null, PropertyNames.CREATOR, null);
			FilterElement ele3 = new FilterElement(null, null, null, PropertyNames.DATE_CREATED, null);
			FilterElement ele4 = new FilterElement(null, null, null, PropertyNames.SOURCE_CLASS_ID, null);
			FilterElement ele5 = new FilterElement(null, null, null, PropertyNames.SOURCE_OBJECT_ID, null);
			filter.addIncludeProperty(ele1);
			filter.addIncludeProperty(ele2);
			filter.addIncludeProperty(ele3);
			filter.addIncludeProperty(ele4);
			filter.addIncludeProperty(ele5);
			
			rrs = ss.fetchRows(searchSql, 1000, filter, true);
		}

		return rrs;
	}
	
	private String dateFormat(Date date){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String dateStr = sdf.format(date);
		sdf = new SimpleDateFormat("HHmmss");
		dateStr = dateStr + "T" + sdf.format(date) + "Z";
		return dateStr;
	}

         FileNet提供了對流程的報表分析工具(process Analyzer),卻沒有提供與Auditing相互配合的產品。這種直接定製性開發的工作雖然功能上可以實現,但效率問題是已經在XT上定製出來的功能隨着zhy某分公司幾十萬附件的量也使得這個功能形同虛設。究其原因不是FileNet存儲不夠優化,而是auditing存儲的是相應操作事件相關的內容,雖然也已存儲着操作的文檔實例,但要藉此獲取到文檔相關信息(如名稱、甚至是操作者所在部門)則會非常耗時。

         針對此類問題可以考慮去直接理清FileNet數據庫繼而直接操作數據庫,但這種風險較高,而且產品升級也可能有所不便;另外可以考慮將業務相關數據在定時任務中轉移到應用的業務庫中,這種短時間的auditing查詢,且是在應用空閒時間進行的,會較易接受,雖然這種方式會有一定延遲,但統計本身的時間量很大,這種一天甚至更短時間的延遲是可以接受的;當然,我們還可以完全不使用auditing,直接在業務中記錄相關要統計的數據,但這樣做除了要做更多的開發工作,更要緊的是對已經成型的產品(或應用)的改動會很大,可能會帶來比這種開發更大的工作量(如測試)。所以,可以根據是項目階段在後兩種中選擇,如果是FileNet內部人員可能會更喜歡第一種,但要考慮升級風險。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章