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

Darkhan

Green Team
14.12.2012
99
2
BIT
0
Доброе время суток, уважаемые "кодебчане")!
Наверняка многие из вас сталкивались с необходимостью безопасного итерирования по коллекции на 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">
Код:
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">
Код:
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">
Код:
%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">
Код:
%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
 

garrick

Lotus Team
26.10.2009
1 367
152
BIT
340
Положил в копилочку, на досуге посмотрю повнимательнее.
А LotusScript зачем? Там вроде с GC проблем нету.
 
T

turumbay

Симпатично. Правда есть небольшой косяк: не вызовется 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]
 

oshmianski

Достойный программист
Lotus Team
25.04.2012
711
59
BIT
8
я бы добавил для LS:
1) обработку не только NotesDocumentCollection, но и NotesViewNavigator, NotesViewEntryCollection + Самопальный итератор
2) прогресс бар
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!