2012-03-06 3 views
6

Abbiamo un numero di database di ricerca che utilizziamo in più applicazioni e sto cercando di capire il modo migliore e più efficiente per rendere questi database di ricerca disponibili tramite una funzione java o bean in una libreria di plugin OSGi.Creazione di un sistema di ricerca nella cache in java per xpages

Quello che mi piacerebbe ottenere è un modo di creare una funzione che posso passare in una chiave di ricerca e un nome di campo e la funzione restituirà il valore corretto e possibilmente il tipo di oggetto (per gestire i valori datatime). Dovrebbe inoltre memorizzare il valore nel cache per circa un'ora a livello di applicazione poiché questi documenti di ricerca non cambiano affatto.

genere che vorrei usarli per scopi di visualizzazione in modo che ho solo bisogno di memorizzare la chiave nel mio documento note e quindi usare qualcosa come il seguente per visualizzare sullo schermo quello che mi serve

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

Per essere sicuro, deve essere un plug-in osgi? O potrebbe anche essere fatto con un bean utente definito nel database? Dove sono archiviate le informazioni sui database di ricerca? – jjtbsomhorst

+0

Potrebbe essere un bean definito in un plug-in OSGi. Il mio pensiero è che averlo nel plugin lo renderà globale per il server, quindi qualsiasi app che deve effettuare una ricerca può semplicemente chiamare la funzione per restituire un valore. I database di ricerca si trovano in una posizione fissa sul server. –

risposta

8

È può benissimo farlo ora con scope scope, con l'avvertenza che un bean è specifico NSF. Anche se il kit Starter XSP credo includa un esempio di come fare un bean con scope Server (che è in realtà un singleton, il che significa che esiste solo un'istanza della classe per l'intera JVM).

Per prima cosa creare un POJO serializzabile semplice chiamato CachedData con due campi membro, il primo è un campo che contiene un valore di data e ora che indica l'ultima volta in cui i dati sono stati letti dal disco e il secondo è una sorta di oggetto elenco , come un vettore, che contiene i tuoi valori.

Quindi creare un altro POJO chiamato ServerMap che ha una stringa cartina <, carta < stringa, carta < stringa, carta < oggetto, carta < oggetto, CachedData > > > > come membro, e una funzione chiamata doCachedLookup() o qualcosa del genere. I parametri di tale funzione possono essere quasi gli stessi di @DbLookup, server, database, vista, chiave, ecc. Quindi, in doCachedLookup, controlla la tua ServerMap per l'esistenza del server specificato come chiave. Se non esiste, quindi creare una nuova mappa e inserirla in ServerMap con la chiave come nome del server. Se esiste, cerca il nome del database in quella mappa, quindi la vista nella mappa successiva e infine il valore nell'ultima mappa. Una volta ottenuto l'oggetto CachedData, è possibile controllare il campo relativo alla data e vedere se è scaduto, se non lo è, restituire il vettore, e se lo è, scartarlo, quindi eseguire una nuova ricerca e ricollegare la cache i dati e quindi restituire il vettore.

Ecco gli esempi di codice, ero un po 'pigro nei miei metodi di overload per ottenere una colonna rispetto a ottenere un nome di campo, e io uso di alcuni metodi di data java deprecati, ma vi darà una buona base da cui partire. Tutto il codice è testato:

CachedData Classe: Classe

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 che viene implementato come un Singleton in modo che possa essere utilizzato in tutto il server:

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); 
    } 

} 

esempio su come utilizzare in una 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

Questo è stato davvero utile. Poiché i miei database di ricerca sono corretti, ho ridotto il numero se le variabili necessarie per passare alla funzione solo la chiave e il campo e il resto necessario per la ricerca sono impostati all'interno della funzione. Grazie per questo. –

+0

Non ho alcuna esperienza con i bean con scope del server, ma quanto tempo impiegherebbe un tale bean per invalidare? A livello NSF è possibile specificare il timeout prima che l'applicazione venga pulita dalla memoria. – jjtbsomhorst

+1

Questo non è realmente un bean con scope server nello stesso senso di un bean con scope vista. Ciò che è chiamato singleton, significa che solo un'istanza viene creata e utilizzata per l'intera JVM e non muore finché non viene riavviata la JVM. Poiché questo è il caso, ecco perché CachedData ha il membro updateTime, che controlla la durata valida dei dati memorizzati nella cache. Questo esempio non elimina la cache in modo che resti ancora in memoria anche se non è più valida e un'implementazione più solida potrebbe funzionare per eliminare i record di cache obsoleti in periodi specifici. –

2

Quando si utilizzano i bean, è possibile utilizzare EL per ottenere il contenuto più veloce di SSJS. E SÌ: utilizzare l'ambito server dal kit Starter XSP. Per il caching: non reinventare la ruota!Esiste un'implementazione MOLTO completa di tutti i tipi di caching di fantasia disponibili: http://commons.apache.org/jcs/ L'ho usato in un'app Tomcat prima e ha funzionato in modo molto affidabile. Non vedo perché non sarebbe una buona scelta per il tuo compito.