2012-03-06 63 views
6

我們有許多查找數據庫,我們在多個應用程序中使用,我試圖找出通過java函數使這些查找數據庫可用的最佳和最有效的方法,或者bean在OSGi插件庫中。在java中爲xpages構建一個緩存查找系統

我想實現的是創建一個函數,我可以傳遞查找鍵和字段名稱,該函數將返回正確的值和可能的對象類型(處理datatime值)的某種方式。它還需要在應用程序級緩存大約一個小時的值,因爲這些查找文檔根本沒有改變。

通常我會想使用它們用於顯示目的,這樣我只需要密鑰存儲在我的筆記文檔,然後使用類似下面的在屏幕上顯示什麼,我需要

<xp:text escape="true" id="computedField1"> 
    <xp:this.value><![CDATA[#{javascript:com.mycompany.lookup.GetDoc("docID","fieldName")}]]></xp:this.value> 
</xp:text> 
+0

可以肯定的,它需要一個OSGi的插件?或者也可以用數據庫中定義的userbean完成?有關查找數據庫的信息存儲在哪裏? – jjtbsomhorst 2012-03-06 15:28:19

+0

它可能是一個在OSGi插件中定義的bean。我的想法是,讓它在插件中對服務器來說是全局的,所以任何需要查找的應用程序都可以調用函數來返回值。查找數據庫位於服務器上的固定位置。 – 2012-03-06 15:32:23

回答

8

你現在可以很好地使用scoped bean來做到這一點,但有一點需要注意,bean是NSF特定的。雖然我相信XSP入門套件包含了一個如何執行Server scoped bean的例子(這是一個單例,意味着整個JVM只有一個類的實例)。

首先創建一個簡單的可序列化的POJO,它叫做CachedData,它有兩個成員字段,第一個是一個字段,它包含一個日期時間值,指示您最後一次從磁盤讀取數據的時間值,第二個是某種列表對象,就像一個載體一樣,它保存着你的價值觀。

然後創建另一個POJO稱爲ServerMap具有地圖<串,地圖<串,地圖<串,地圖<對象,地圖<對象,CachedData > > > >作爲成員,和一個稱爲doCachedLookup()的函數或類似的東西。該函數的參數可以與@DbLookup,服務器,數據庫,視圖,鍵等幾乎相同。然後在doCachedLookup中,檢查ServerMap是否存在指定的服務器作爲密鑰。如果它不存在,則創建一個新映射並將其插入ServerMap中,其中鍵爲服務器名稱。如果確實存在,則查找該地圖中的數據庫名稱,然後查看下一張地圖中的視圖,最後查看最後一張地圖中的值。一旦你獲得了CachedData對象,你可以檢查日期時間字段,看看它是否過期,如果不是,返回向量,如果是,丟棄它,然後重新進行查找,並重新緩存數據,然後返回矢量。

這裏是代碼示例,我在重載方法中獲取列與獲取字段名稱有點懶,我使用了一些不推薦的java日期方法,但它會爲您提供一個很好的基礎。所有代碼進行測試:

CachedData類別:如何在使用

package com.ZetaOne.example; 

import java.io.Serializable; 
import java.util.Date; 
import java.util.Vector; 
import com.ZetaOne.example.CachedData; 
import java.util.HashMap; 
import java.util.Collections; 
import java.util.Map; 

import lotus.domino.Session; 
import lotus.domino.Database; 
import lotus.domino.View; 
import lotus.domino.NotesException; 
import lotus.domino.ViewEntryCollection; 
import lotus.domino.ViewEntry; 
import lotus.domino.Document; 

import javax.faces.context.FacesContext; 

public class CachedLookup implements Serializable { 

    private static CachedLookup _instance; 

    private static final long serialVersionUID = 1L; 
    private Map<String, HashMap<String, HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>>> cachedLookup; 

    public static CachedLookup getCurrentInstance() { 
     if (_instance == null) { 
      _instance = new CachedLookup(); 
     } 
     return _instance; 
    }  

    private CachedLookup() { 
     HashMap<String, HashMap<String, HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>>> cachedLookupMap = 
      new HashMap<String, HashMap<String, HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>>>(); 
     this.cachedLookup = Collections.synchronizedMap(cachedLookupMap); 
    } 

    @SuppressWarnings("deprecation") 
    public Vector<Object> doCachedLookup(String serverName, String filePath, String viewName, Object keyValues, int columnNumber, boolean exactMatch) { 

     if (cachedLookup.containsKey(serverName)) { 
      if (cachedLookup.get(serverName).containsKey(filePath)) { 
       if (cachedLookup.get(serverName).get(filePath).containsKey(viewName)) { 
        if (cachedLookup.get(serverName).get(filePath).get(viewName).containsKey(keyValues)) { 
         if (cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).containsKey(columnNumber)) { 
          CachedData cache = cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).get(columnNumber); 
          if (cache.getUpdateTime().compareTo(new Date()) > 0) { 
           System.out.println("Cache Hit"); 
           return cache.getValues(); 
          } 
         } 
        } 
       } 
      } 
     } 

     System.out.println("Cache Miss"); 
     // if we drop to here, cache is either expired or not present, do the lookup. 

     try { 
      Session session = (Session)resolveVariable("session"); 
      Database db = session.getDatabase(serverName, filePath); 
      View view = db.getView(viewName); 
      ViewEntryCollection vc = view.getAllEntriesByKey(keyValues, exactMatch); 
      ViewEntry ve, vn; 
      ve = vc.getFirstEntry(); 
      Vector<Object> results = new Vector<Object>(); 
      while (ve != null) { 
       results.add(ve.getColumnValues().elementAt(columnNumber)); 

       vn = vc.getNextEntry(); 
       ve.recycle(); 
       ve = vn; 
      } 

      vc.recycle(); 

      if (!cachedLookup.containsKey(serverName)) { 
       cachedLookup.put(serverName, new HashMap<String, HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>>()); 
      } 

      if (!cachedLookup.get(serverName).containsKey(filePath)) { 
       cachedLookup.get(serverName).put(filePath, new HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>()); 
      } 

      if (!cachedLookup.get(serverName).get(filePath).containsKey(viewName)) { 
       cachedLookup.get(serverName).get(filePath).put(viewName, new HashMap<Object, HashMap<Object, CachedData>>()); 
      } 

      if (!cachedLookup.get(serverName).get(filePath).get(viewName).containsKey(keyValues)) { 
       cachedLookup.get(serverName).get(filePath).get(viewName).put(keyValues, new HashMap<Object, CachedData>()); 
      } 

      CachedData cache; 
      if (cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).containsKey(columnNumber)) { 
       cache = cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).get(columnNumber); 
      } else { 
       cache = new CachedData(); 
      } 

      Date dt = new Date(); 
      dt.setHours(dt.getHours() + 1); 
      cache.setUpdateTime(dt); 
      cache.setValues(results);   

      cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).put(columnNumber, cache); 

      view.recycle(); 
      db.recycle(); 

      return results; 

     } catch (NotesException e) { 
      // debug here, im lazy 
      return null; 
     } 
    } 

    public Vector<Object> doCachedLookup(String serverName, String filePath, String viewName, Object keyValues, String fieldName, boolean exactMatch) { 

     if (cachedLookup.containsKey(serverName)) { 
      if (cachedLookup.get(serverName).containsKey(filePath)) { 
       if (cachedLookup.get(serverName).get(filePath).containsKey(viewName)) { 
        if (cachedLookup.get(serverName).get(filePath).get(viewName).containsKey(keyValues)) { 
         if (cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).containsKey(fieldName)) { 
          CachedData cache = cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).get(fieldName); 
          if (cache.getUpdateTime().compareTo(new Date()) > 0) { 
           System.out.println("Cache Hit");         
           return cache.getValues(); 
          } 
         } 
        } 
       } 
      } 
     } 

     System.out.println("Cache Miss");   
     // if we drop to here, cache is either expired or not present, do the lookup. 

     try { 
      Session session = (Session)resolveVariable("session"); 
      Database db = session.getDatabase(serverName, filePath); 
      View view = db.getView(viewName); 
      ViewEntryCollection vc = view.getAllEntriesByKey(keyValues, exactMatch); 
      ViewEntry ve, vn; 
      ve = vc.getFirstEntry(); 
      Vector<Object> results = new Vector<Object>(); 
      while (ve != null) { 
       Document doc = ve.getDocument(); 
       results.add(doc.getItemValue(fieldName)); 
       doc.recycle(); 

       vn = vc.getNextEntry(); 
       ve.recycle(); 
       ve = vn; 
      } 

      vc.recycle(); 

      if (!cachedLookup.containsKey(serverName)) { 
       cachedLookup.put(serverName, new HashMap<String, HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>>()); 
      } 

      if (!cachedLookup.get(serverName).containsKey(filePath)) { 
       cachedLookup.get(serverName).put(filePath, new HashMap<String, HashMap<Object, HashMap<Object, CachedData>>>()); 
      } 

      if (!cachedLookup.get(serverName).get(filePath).containsKey(viewName)) { 
       cachedLookup.get(serverName).get(filePath).put(viewName, new HashMap<Object, HashMap<Object, CachedData>>()); 
      } 

      if (!cachedLookup.get(serverName).get(filePath).get(viewName).containsKey(keyValues)) { 
       cachedLookup.get(serverName).get(filePath).get(viewName).put(keyValues, new HashMap<Object, CachedData>()); 
      } 

      CachedData cache; 
      if (cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).containsKey(fieldName)) { 
       cache = cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).get(fieldName); 
      } else { 
       cache = new CachedData(); 
      } 

      Date dt = new Date(); 
      dt.setHours(dt.getHours() + 1); 
      cache.setUpdateTime(dt); 
      cache.setValues(results);   

      cachedLookup.get(serverName).get(filePath).get(viewName).get(keyValues).put(fieldName, cache); 

      view.recycle(); 
      db.recycle(); 

      return results; 

     } catch (NotesException e) { 
      // debug here, im lazy 
      return null; 
     } 
    } 

    private static Object resolveVariable(String variable) { 
     return FacesContext.getCurrentInstance().getApplication() 
       .getVariableResolver().resolveVariable(
         FacesContext.getCurrentInstance(), variable); 
    } 

} 

示例:被實現爲一個單,使得它可以用於服務器範圍

package com.ZetaOne.example; 

import java.io.Serializable; 
import java.util.Date; 
import java.util.Vector; 

public class CachedData implements Serializable { 

    private static final long serialVersionUID = 1L; 
    private Date updateTime; 
    private Vector<Object> values; 

    public Date getUpdateTime() { 
     return this.updateTime; 
    } 

    public void setUpdateTime(Date UpdateTime) { 
     updateTime = UpdateTime; 
    } 

    public Vector<Object> getValues() { 
     return this.values; 
    } 

    public void setValues(Vector<Object> values) { 
     this.values = values; 
    } 
} 

CachedLookup類一個XPage:

<xp:text id="text1"> 
    <xp:this.value><![CDATA[#{javascript: 
     com.ZetaOne.example.CachedLookup.getCurrentInstance().doCachedLookup(
      database.getServer(), 
      database.getFilePath(), 
      "lookup", 
      "Test Category", 
      "Value", 
      true 
     ) 
    }]]></xp:this.value> 
</xp:text> 

+1

這真的很有幫助。由於我的查詢數據庫是固定的,如果需要傳遞給函數的變量只是鍵和字段以及查找所需的其餘部分在函數中設置,我會減少數量。謝謝你。 – 2012-03-06 19:28:18

+0

我沒有任何關於服務器範圍bean的經驗,但是這樣一個bean需要多久纔會失效?在nsf級別,您可以指定應用程序從內存中清除之前的超時時間。 – jjtbsomhorst 2012-03-07 05:29:23

+1

這與服務器範圍的bean不同,它與視圖範圍的bean相同。它的whats稱爲單例,意味着只有一個實例被創建並用於整個JVM,並且在JVM重新啓動之前不會死亡。既然如此,那就是爲什麼CachedData具有updateTime成員,它控制着高速緩存數據的有效生存期。此示例不會剔除任何緩存,因此即使緩存不再有效,緩存仍位於內存中,而更強大的實現可能可用於在指定的時間段內剔除緩存記錄。 – 2012-03-07 14:50:01

2

當你做bean時,你可以使用EL來獲取比SSJS更快的內容。並且是 - 使用XSP Starter套件中的服務器範圍。對於緩存:不要重新發明輪子!有各種可用的花式緩存的一個非常完整的實現:http://commons.apache.org/jcs/我用在Tomcat應用之前和它的工作非常可靠。我不明白爲什麼它不適合你的任務。