2012-03-06 10 views
6

Mamy wiele odnośników do baz danych, których używamy w wielu aplikacjach i próbuję znaleźć najlepszy i najbardziej efektywny sposób udostępnienia tych baz danych za pomocą funkcji java lub bean w bibliotece Plugin OSGi.Budowanie systemu wyszukiwania pamięci podręcznej w języku Java dla stron xpages

Co chciałbym osiągnąć to jakiś sposób na stworzenie funkcji, którą mogę przekazać w kluczu wyszukiwania i nazwie pola, a funkcja zwróci poprawną wartość i ewentualnie typ obiektu (aby poradzić sobie z wartościami datatime). Musiałby również buforować wartość przez około godzinę na poziomie aplikacji, ponieważ te dokumenty nie zmieniają się wcale.

Zazwyczaj chciałbym wykorzystać je do celów wyświetlania tak, że tylko trzeba przechowywać klucz w moim dokumencie notatki, a następnie użyć coś jak poniżej w celu wyświetlenia na ekranie, co muszę

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

Czy to musi być wtyczka osgi? Czy może to być również wykonane przy użyciu userbean zdefiniowanej w bazie danych? Gdzie są przechowywane informacje o przechowywanych bazach danych? – jjtbsomhorst

+0

Może to być komponent bean zdefiniowany w wtyczce OSGi. Moim zdaniem, posiadanie go w wtyczce spowoduje, że będzie on globalny na serwerze, więc każda aplikacja, która musi wykonać odnośnik, może po prostu wywołać funkcję zwracającą wartość. Bazy wyszukiwania znajdują się w ustalonej lokalizacji na serwerze. –

Odpowiedz

8

Ty może całkiem dobrze zrobić to teraz z ziarnami o określonym zasięgu, z jednym zastrzeżeniem, że fasola jest specyficzna dla NSF. Chociaż wydaje mi się, że zestaw startowy XSP zawiera przykład, jak wykonać komponent bean z obsługą serwera (który jest tak naprawdę singletonem, co oznacza, że ​​istnieje tylko jedno wystąpienie tej klasy dla całej maszyny JVM).

Najpierw utwórz proste POJO z serializacją o nazwie CachedData, które ma dwa pola składowe, pierwszym jest pole zawierające wartość daty, która wskazuje, kiedy ostatnio odczytałeś dane z dysku, a drugie jest jakimś obiektem listy , podobnie jak wektor, który trzyma twoje wartości.

Następnie utworzyć kolejną POJO nazwie ServerMap że ma map < ciąg, mapa < ciąg, mapa < ciąg, mapa < Object, mapa < obiekt, CachedData > > > > jako członek, a funkcja nazywa doCachedLookup() lub coś w tym stylu. Parametry tej funkcji mogą być prawie takie same jak @DbLookup, serwer, baza danych, widok, klucz itp. Następnie w instrukcji doCachedLookup sprawdź swoją Mapę serwerów pod kątem istnienia określonego serwera jako klucza. Jeśli nie istnieje, utwórz nową mapę i wstaw ją do mapy serwerów z kluczem będącym nazwą serwera. Jeśli istnieje, wyszukaj nazwę bazy danych na tej mapie, następnie widok na następnej mapie, a na końcu wartość na ostatniej mapie. Po pobraniu obiektu CachedData można sprawdzić pole daty i sprawdzić, czy wygasło, a jeśli nie, zwrócić wektor, a jeśli tak, odrzucić go, a następnie wykonać nowe wyszukiwanie i ponownie zapisać w pamięci podręcznej. dane, a następnie zwróć wektor.

Oto przykłady kodu, byłem trochę leniwy w swoich przeciążonych metodach uzyskiwania kolumny w porównaniu z uzyskiwaniem nazwy pola i używam pewnych wycofanych metod datowania java, ale to da ci dobrą podstawę do rozpoczęcia. Cały kod jest testowany:

CachedData Klasa: klasa

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 który jest zaimplementowany jako pojedyncza tak, że może on być stosowany całego serwera:

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

} 

przykład jak używać w 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

To było naprawdę pomocne. Ponieważ moje bazy danych wyszukiwania są poprawione, zmniejszyłem liczbę, jeśli zmienne potrzebne do przejścia do funkcji tylko do klucza i pola, a reszta potrzebna do wyszukiwania jest ustawiona w funkcji. Dzięki za to. –

+0

Nie mam żadnego doświadczenia z ziarnami na serwerze z serwerem, ale jak długo taki komponent będzie wymagał unieważnienia? Na poziomie nsf można określić limit czasu, zanim aplikacja zostanie wyczyszczona z pamięci. – jjtbsomhorst

+1

To nie jest tak naprawdę komponent o zakreślonym serwerze w tym samym znaczeniu, co komponent bean o widoku. Jest to tzw. Singleton, co oznacza, że ​​tylko jedna instancja jest tworzona i używana dla całej maszyny JVM i nie umiera, dopóki JVM nie zostanie zrestartowana. Ponieważ tak jest, dlatego składnik CachedData ma element updateTime, który kontroluje poprawny okres ważności buforowanych danych. Ten przykład nie usuwa żadnej pamięci podręcznej, więc nadal znajduje się w pamięci, nawet jeśli nie jest już poprawny, a bardziej niezawodna implementacja może działać w celu usunięcia nieaktualnych rekordów pamięci podręcznej w określonych okresach. –

2

Po wykonaniu fasoli można użyć EL, aby uzyskać zawartość szybszą niż SSJS. I TAK - użyj zakresu serwera z zestawu startowego XSP. Pamięć podręczna: nie wymyślaj ponownie koła!Istnieje BARDZO kompletna implementacja wszelkiego rodzaju wymyślnego buforowania: http://commons.apache.org/jcs/ Użyłem tego wcześniej w aplikacji Tomcat i działało bardzo wiarygodnie. Nie rozumiem, dlaczego nie byłby to dobry wybór dla twojego zadania.