Создание системы поиска кэширования в java для xpages

У нас есть несколько баз данных поиска, которые мы используем в нескольких приложениях, и я пытаюсь выяснить лучший и наиболее эффективный способ сделать эти базы данных поиска доступными через функцию java или bean в библиотеке плагинов OSGi.

то, что я хотел бы достичь, - это способ создания функции, которую я могу передать в ключе поиска и имени Поля, и функция вернет правильное значение и, возможно, тип объекта ( для работы со значениями datatime ). Ему также потребуется кэшируйте значение в течение примерно часа на уровне приложения, так как эти документы поиска не изменяются вообще.

обычно я хотел бы использовать их для отображения, так что мне нужно только сохранить ключ в моем документе notes, а затем использовать что-то вроде следующего, чтобы отобразить на экране то, что мне нужно

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

2 ответов


вы можете довольно хорошо сделать это сейчас с фасолью, с одной оговоркой, что фасоль специфична для NSF. Хотя стартовый комплект XSP, я считаю, включает пример того, как сделать серверный компонент (который действительно является одноэлементным, что означает, что есть только один экземпляр класса для всего JVM).

сначала создайте простой сериализуемый POJO, называемый CachedData, который имеет два поля-члена, первое поле, которое содержит значение даты, которое указывает, когда вы в последний раз читали данные с диска, а второй-какой-то объект списка, например вектор, который содержит ваши значения.

затем создайте другой POJO под названием ServerMap, который имеет map>>> в качестве члена и функцию doCachedLookup() или что-то в этом роде. Параметры этой функции могут быть почти такими же, как @DbLookup, сервер, база данных, представление, ключ и т. д. Затем в doCachedLookup проверьте ServerMap на наличие в качестве ключа указан сервер. Если он не существует, создайте новую карту и вставьте ее в ServerMap с ключом, являющимся именем сервера. Если он существует, найдите имя базы данных на этой карте, затем представление на следующей карте, затем, наконец, значение на последней карте. Как только вы получите объект CachedData, вы можете проверить поле даты и времени и посмотреть, истек ли он, если это не так, верните вектор, и если это так, отбросьте его, а затем выполните новый поиск и повторно кэшируйте данные, а затем верните вектор.

вот примеры кода, я был немного ленив в моих перегруженных методах получения столбца против получения имени Поля, и я использую некоторые устаревшие методы даты java, но это даст вам хорошую базу для начала. Весь код тестируется:

Класс CachedData:

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, который реализован как одноэлементный, чтобы его можно было использовать на уровне сервера:

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

}

пример использования в Элемент 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>


когда вы делаете бобы, вы можете использовать EL для получения контента, который быстрее, чем SSJS. И да-используйте область сервера из стартового набора XSP. Для кэширования: не изобретайте колесо! Существует очень полная реализация всех видов фантазии кэширования доступны:http://commons.apache.org/jcs/ я использовал это в приложении Tomcat раньше, и он работал очень надежно. Я не вижу, почему это не было бы хорошим выбором для вашей задачи.