Помощник Для Итерации По Коллекции

Тема в разделе "Lotus - Программирование", создана пользователем Darkhan, 25 авг 2014.

  1. Darkhan

    Darkhan Lotus team
    Lotus team

    Регистрация:
    14 дек 2012
    Сообщения:
    97
    Симпатии:
    4
    Доброе время суток, уважаемые "кодебчане")!
    Наверняка многие из вас сталкивались с необходимостью безопасного итерирования по коллекции на Java (в силу "особенного" отношения GC к нотусевым объектам). В интернете много примеров кусков кода для таких задач. Однако иногда надоедает постоянно плодить в коде такие вот выкрутасы. Именно для этого был написан помощник.
    Для его использования достаточно вызвать один его статисечкий метод, передав коллекцию и имплементацию обработчика документов.
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">DocumentCollectionIterator</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    import lotus.domino.Document;
    import lotus.domino.DocumentCollection;
    import lotus.domino.NotesException;

    /**
    * Class-helper for memory safety DocumentCollection iteration
    */
    public class DocumentCollectionIterator {

    public static interface ICollectionDocumentProcessor{
    public abstract void processDocument(Document document) throws CollectionDocumentProcessorException;
    }

    public static class DocumentCollectionIteratorException extends Exception{

    public DocumentCollectionIteratorException() {
    super();
    // TODO Auto-generated constructor stub
    }

    public DocumentCollectionIteratorException(String arg0) {
    super(arg0);
    // TODO Auto-generated constructor stub
    }

    public DocumentCollectionIteratorException(String arg0, Throwable arg1) {
    super(arg0, arg1);
    // TODO Auto-generated constructor stub
    }

    public DocumentCollectionIteratorException(Throwable arg0) {
    super(arg0);
    // TODO Auto-generated constructor stub
    }

    }

    public static class CollectionDocumentProcessorException extends Exception{

    public CollectionDocumentProcessorException() {
    super();
    // TODO Auto-generated constructor stub
    }

    public CollectionDocumentProcessorException(String arg0) {
    super(arg0);
    // TODO Auto-generated constructor stub
    }

    public CollectionDocumentProcessorException(String arg0, Throwable arg1) {
    super(arg0, arg1);
    // TODO Auto-generated constructor stub
    }

    public CollectionDocumentProcessorException(Throwable arg0) {
    super(arg0);
    // TODO Auto-generated constructor stub
    }

    }

    /**
    * New object creation restriction
    */
    private DocumentCollectionIterator(){
    }

    /**
    * DocumentCollection memory safety iteration
    * @param documentCollection
    * @param processor
    * @throws DocumentCollectionIteratorException
    * @throws CollectionDocumentProcessorException
    */
    public static void iterate(DocumentCollection documentCollection, ICollectionDocumentProcessor processor)
    throws DocumentCollectionIteratorException, CollectionDocumentProcessorException{
    try {
    if (documentCollection==null){
    throw new DocumentCollectionIteratorException("Argument documentCollection is null!");
    }
    Document tempDocument = null;
    Document document = documentCollection.getFirstDocument();
    while(document!=null){
    try {
    processor.processDocument(document);
    } catch (CollectionDocumentProcessorException e) {
    document.recycle();
    throw e;
    }
    tempDocument = documentCollection.getNextDocument(document);
    document.recycle();
    document = tempDocument;
    }

    } catch (NotesException e) {
    throw new DocumentCollectionIteratorException("DocumentCollection iteration exception", e);
    }
    }
    }
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">пример использования</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    import lotus.domino.*;

    public class JavaAgent extends AgentBase {

    public void NotesMain() {

    try {
    Session session = getSession();
    AgentContext agentContext = session.getAgentContext();

    DocumentCollection someCollection = null;
    DocumentCollectionIterator.iterate(someCollection, new DocumentCollectionIterator.ICollectionDocumentProcessor(){
    public void processDocument(Document document) throws DocumentCollectionIterator.CollectionDocumentProcessorException {
    //Do something with document
    }
    });

    } catch(Exception e) {
    e.printStackTrace();
    }
    }
    }
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Реализация на LotusScript</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Library LSCollectionIterator
    Created Aug 25, 2014 by Administrator
    Description: Comments for Library
    %END REM
    Option Public
    Option Declare

    %REM
    Class BaseClass
    Description: Базовый класс
    %END REM
    Public Class BaseClass

    %REM
    Function getClassName
    Description: Comments for Function
    %END REM
    Public Function getClassName() As String
    getClassName = TypeName(Me)
    End Function

    %REM
    Sub destroyObject
    Description: Уничтожает объект
    %END REM
    Public Sub destroyObject(object As Variant)
    On Error GoTo eh

    If IsObject(object) Then
    If Not object Is Nothing Then Delete object
    ElseIf IsList(object) Then
    Erase object
    ElseIf IsArray(object) Then
    Erase object
    End If

    GoTo ex
    eh:    
    Call throwError()
    ex:
    End Sub

    %REM
    Function getErrorText
    Description: Получение текста ошибки

    On Error GoTo eh

    GoTo ex
    eh:    
    Call getErrorText(LSI_Info(12))
    ex:
    %END REM
    Public Function getErrorText(callerMethodName As String) As String
    getErrorText = getErrorDescription(LSI_Info(12), callerMethodName, "")
    End Function

    %REM
    Function getErrorTextExt
    Description: Получение расширенного текста ошибки
    %END REM
    Public Function getErrorTextExt(callerMethodName As String, additionalText As String) As String
    getErrorTextExt = getErrorDescription(LSI_Info(12), callerMethodName, additionalText)
    End Function

    %REM
    Sub throwError
    Description: Передача ошибки вверх

    On Error GoTo eh

    GoTo ex
    eh:    
    Call throwError(LSI_Info(12))
    ex:
    %END REM
    Public Sub throwError()
    Error Err, getErrorDescription(LSI_Info(12), "", "")
    End Sub

    %REM
    Sub throwErrorExt
    Description: Comments for Sub
    %END REM
    Public Sub throwErrorExt(additionalText As String)
    Error Err, getErrorDescription(LSI_Info(12), "", additionalText)
    End Sub

    %REM
    Function getErrorDescription
    Description: Comments for Function
    %END REM
    Private Function getErrorDescription(methodName As String,_
    callerMethodName As String, additionalText As String) As String
    getErrorDescription = Error & Chr(10) &_
    "Method: " & getClassName() & "." & methodName & ": " & Erl & Chr(10) &_
    "Called by: " & callerMethodName & Chr(10) & additionalText & Chr(10) & _
    "--------------------------------------------------"
    End Function

    End Class
    %REM
    Class NotesDocumentCollectionIterator
    Description: Comments for Class
    %END REM
    Public Class DocumentCollectionIterator As BaseClass

    %REM
    Sub iterate
    Description: Comments for Sub
    %END REM
    Public Sub iterate(collection As NotesDocumentCollection, processor As ICollectionDocumentProcessor)
    On Error GoTo eh
    Dim document As NotesDocument

    If collection Is Nothing Then
    Error 1, "Argument documentCollection is nothing!"
    End If

    Set document = collection.Getfirstdocument()
    While(Not document Is Nothing)
    Call processor.processDocument(document)
    Set document = collection.Getnextdocument(document)
    Wend

    GoTo ex
    eh:
    Call throwError()
    ex:
    End Sub

    End Class
    %REM
    Class ICollectionDocumentProcessor
    Description: Comments for Class
    %END REM
    Public Class ICollectionDocumentProcessor As BaseClass

    %REM
    Sub process
    Description: Comments for Sub
    %END REM
    Public Sub processDocument(document As NotesDocument)
    On Error GoTo eh

    Error 1, "Error calling abstract method!"

    GoTo ex
    eh:
    Call throwError()
    ex:
    End Sub

    End Class
    Public Function DocumentCollectionIterator As DocumentCollectionIterator
    Static iterator As DocumentCollectionIterator
    If iterator Is Nothing Then
    Set iterator = New DocumentCollectionIterator
    End If
    Set DocumentCollectionIterator = iterator
    End Function
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">пример использования LS</div></div><div class="sp-body"><div class="sp-content">
    Код (Text):
    %REM
    Agent Test
    Created Aug 25, 2014 by Administrator
    Description: Comments for Agent
    %END REM
    Option Public
    Option Declare
    Use "LSCollectionIterator"
    %REM
    Class DocumentProcessor
    Description: Comments for Class
    %END REM
    Private Class DocumentProcessor As ICollectionDocumentProcessor

    %REM
    Sub process
    Description: Comments for Sub
    %END REM
    Public Sub processDocument(document As NotesDocument)
    On Error GoTo eh

    'Do something with document

    GoTo ex
    eh:
    Call throwError()
    ex:
    End Sub
    End Class
    Sub Initialize
    Dim collection As NotesDocumentCollection
    Dim processor As New DocumentProcessor

    Call DocumentCollectionIterator().iterate(collection, processor)
    End Sub
     
  2. garrick

    garrick Lotus team
    Lotus team

    Регистрация:
    26 окт 2009
    Сообщения:
    773
    Симпатии:
    52
    Положил в копилочку, на досуге посмотрю повнимательнее.
    А LotusScript зачем? Там вроде с GC проблем нету.
     
  3. Darkhan

    Darkhan Lotus team
    Lotus team

    Регистрация:
    14 дек 2012
    Сообщения:
    97
    Симпатии:
    4
    не безопасности ради, просто для удобства и сокращения повторяемости кода
     
  4. turumbay

    Регистрация:
    13 мар 2009
    Сообщения:
    625
    Симпатии:
    2
    Симпатично. Правда есть небольшой косяк: не вызовется recycle для документа, если processDocument кинет исключение.

    И таки хочется немного попиарить альтернативный язык программирования. То же самое, но на scala:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">functional way, 20 строк кода</div></div><div class="sp-body"><div class="sp-content">
    <!--shcode--><pre><code class='scala'>import lotus.domino.{Document, DocumentCollection}
    import scala.annotation.tailrec

    class RichCollection(collection:DocumentCollection){
    def map[T](f: Document => T): List[T] = {

    @tailrec
    def iteration(doc: Option[Document], acc: List[T]): List[T] = doc match {
    case None => acc
    case Some(nd) =>
    val (next: Option[Document], result: T) = Domino.using(nd) {
    doc => (f(doc), Option(collection.getNextDocument(doc))).swap
    }
    iteration(next, result :: acc)
    }

    iteration(Option(collection.getFirstDocument), Nil)
    }
    }[/CODE]Использование:
    <!--shcode--><pre><code class='scala'>def readProductFromDocument(doc:Document):product = ???
    val collection:DocumentCollection = ???
    val products:List[Product] = collection.map(readProductFromDocument)[/CODE]

    В паблике есть OSGI модуль для домино со следующими плюшками:
    - автоматический recycle всех доминошных объектов
    - функции map, flatMap, filter, withFilter для доминошных коллекций и им подобных ( DocumentCollection, View, ViewNavigator )
    - type safe аналог для getItemValue
    - ну и по мелочи: нормальный логгер, поддержка REST сервисов и web-статики, шедулер, декларативные сервисы, автоматическая сборка Domino Update Site.


    Еще примеры:
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">запись-чтение объекта в поле(multivalue) </div></div><div class="sp-body"><div class="sp-content">
    <!--shcode--><pre><code class='scala'> case class Product(id:Int, name:String, brand:String)
    val doc:Document = ???

    // write values to document
    val products = List( Product(1, "iPhone 5S", "Apple") , Product(2, "Galaxy Note", "Samsung") )
    doc.fieled("product") = products

    // read values from document
    val apples:List[Product] = doc.field[Product]("product").filter(_.brand == "Apple")[/CODE]
    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">объявление мэппера</div></div><div class="sp-body"><div class="sp-content">
    <!--shcode--><pre><code class='scala'> implicit val mapper = new FieldValueMapper[Product] {
    override def read(doc: Document, field: String): List[Product] = {
    val id = doc.field[Int](field + ".id")
    val name = doc.field[String](field + ".name")
    val brand = doc.field[String](field + ".brand")
    (id zip (name zip brand)).map{
    case (id, (name, brand)) => Product(id,name,brand)
    }
    }

    override def write(doc: Document, field: String, value: List[Product]): Unit = {
    doc.field(field + ".id") = value.map(_.id)
    doc.field(field + ".name") = value.map(_.name)
    doc.field(field + ".brand") = value.map(_.brand)
    }
    }[/CODE]

    <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">for-comprehension with lazy filter</div></div><div class="sp-body"><div class="sp-content">
    <!--shcode--><pre><code class='scala'> // все доминошные объекты(session, db, collection, doc) автоматически ресайкляца
    val groups = for{
    session <- Domino.Session
    db <- session.getDatabase("","names.nsf")
    doc <- db.getAllDocuments
    if doc.field[String]("Form") == List("Group")
    } yield doc.getItemValueString("ListName")
    groups should contain ("LocalDomainServers")[/CODE]
     
  5. Darkhan

    Darkhan Lotus team
    Lotus team

    Регистрация:
    14 дек 2012
    Сообщения:
    97
    Симпатии:
    4
    turumbay, благодарю за замечания, подправил
     
  6. oshmianski

    oshmianski Достойный программист
    Lotus team

    Регистрация:
    25 апр 2012
    Сообщения:
    521
    Симпатии:
    13
    я бы добавил для LS:
    1) обработку не только NotesDocumentCollection, но и NotesViewNavigator, NotesViewEntryCollection + Самопальный итератор
    2) прогресс бар
     
Загрузка...

Поделиться этой страницей