Тогда и я навалю кода по поводу:
По моему, универсально - написать классы-итераторы для каждого варианта (NotesDocumentCollection, NotesViewEntryCollection, NotesViewNavigator), а внутрь их вбрасывать объекты классов, в которых реализованы определённые алгоритмы обработки.
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">PDocumentBase.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Document;
/**
* Базовый класс для всех классов обработки документов;
* предназначен для вбрасывания в классы-итераторы,
*/
public abstract class PDocumentBase {
/**
* Прототип метода, содержащий основной алгоритм работы с документом
* @param oParameter - любой объект для передачи параметром
* @return
*/
protected boolean processDocument(Object oParameter) {
return false;
}
protected boolean processDocument(Document nd) {
return false;
}
}[/CODE]
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorBase.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Document;
/**
* Базовый класс-итератор;
* предназначен для организации перебора документов,
* вне зависимости от контейнеров их содержащих
* Некоторые свойства и метода остались от LS, возможно н.б. выпилить
*/
abstract class IteratorBase extends PDocumentBase {
private String sActionText = "обработано документов"; //по умолчанию
//выводить ли в статусбар процент выполнения
protected boolean bOutputProgress;
//выводить ли в статусбар общую инфу по завершению процесса
protected boolean bOutputResult = true;
//общее количество элементов
protected long Count = -1; // по умолчанию "не инициализировано"
//текущее значение счётчика (всего)
protected long lCounter;
//текущее значение счётчика (выполнено с положительным результатом)
protected long lProcessed;
/**
* Конструктор
* Для случаев, когда объект-итератор не известен вначале,
* а определяется в ходе выполнения (поиск по базе и т.п.)
*/
public IteratorBase() {
}
/**
* @param sActionText the sActionText to set
*/
public void setActionText(String sActionText) {
this.sActionText = sActionText;
}
/**
* @return the sActionText
*/
public String getActionText() {
return sActionText;
}
/**
* Задание "выводить или нет" процент выполнения по ходу работы
*/
public void outputProgress(boolean bOutputProgress) {
this.bOutputProgress = bOutputProgress;
}
/**
* Задание "выводить или нет" результат выполнения
*/
public void outputResult(boolean bOutputResult) {
this.bOutputResult = bOutputResult;
}
/**
* Возвращает количество обработанных документов;
* по данному значению можно косвенно судить о выполнении задания, возложенного на класс
*/
public long isProcessed() {
return this.lProcessed;
}
/**
* Метод содержит основную логику - перебор документов в цикле;
* @param oPDocument - вбрасываемый объект,
* метод processDocument() которго будет вызываться в цикле
* @return Результат как boolean
*/
public boolean run(PDocumentBase oPDocument) {
return false;
}
/**
* Метод без параметра будет вызывать собственный processDocument(),
* т.е. реализованый внутри себя
* @return Результат как boolean
*/
public boolean run() {
return run(this);
}
/**
* Метод обработки конкретного документа; переопределяется в классах-наследниках
* При необходимости расширить логику внутри цикла также переопределяем этот метод
*/
protected boolean processDocument(Document nd) {
return false;
}
/**
* Вывод (на печать) информации о текущей позиции (возможно %) обработки
*/
protected void outputProgressInfo() {
this.lProcessed += 1;
if (this.bOutputProgress) {
//Print StrConv(this.sActionText, 3) + ": " & Fix(this.lCounter * 100 / this.Count) & "%";
}
}
/**
* Вывод (на печать) информации об окончании обработки
* Отдельной функцией, по причинам:
* - метод run м.б. переопределён и сообщение выдано позже;
* - сама процедура вывода результата м.б. переопределена
*/
protected void outputResultInfo() {
//Print "Процесс завершён. Всего " + this.sActionText + ": " & this.lCounter & ".";
}
protected void finalize() {
try {
super.finalize();
}
catch (Throwable e) {}
}
}[/CODE]<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorDocumentCollection.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Document;
import lotus.domino.DocumentCollection;
import lotus.domino.NotesException;
/**
* Базовый класс-итератор для перебора коллекции документов
* раньше назывался PDocumentCollection
*/
public class IteratorDocumentCollection extends IteratorBase {
protected DocumentCollection ndc;
/**
* Конструктор
* Для случаев, когда коллекция известна с самого начала
* @param collection
*/
public IteratorDocumentCollection(DocumentCollection collection) {
initialize(collection);
}
/**
* Задание извне коллекции для обработки
* @param collection
*/
public void initialize(DocumentCollection collection) {
this.ndc = collection;
}
/**
* Метод содержит основную логику - перебор документов в цикле
* подробности см. в классе-родителе
*/
public boolean run(PDocumentBase oPDocument) {
try {
if (this.ndc == null)
return false;
if (this.ndc.getCount() == 0) return false;
this.Count = this.ndc.getCount();
Document ndTmp;
Document nd = this.ndc.getFirstDocument();
while (nd != null) {
if (oPDocument.processDocument(nd)) {
this.outputProgressInfo();
}
ndTmp = this.ndc.getNextDocument();
nd.recycle();
nd = ndTmp;
}
if (this.bOutputResult) {
this.outputResultInfo();
}
return true;
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
}
protected void finalize() {
recycle();
super.finalize();
}
public void recycle() {
try {
if (ndc != null)
ndc.recycle();
}
catch (NotesException e) {}
}
}[/CODE]<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorViewEntryCollection.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Document;
import lotus.domino.ViewEntry;
import lotus.domino.ViewEntryCollection;
import lotus.domino.NotesException;
/**
* Базовый класс-итератор для перебора коллекции элементов вида
*/
public class IteratorViewEntryCollection extends IteratorBase {
protected ViewEntryCollection nvec;
/**
* Конструктор
* Для случаев, когда коллекция известна с самого начала
* @param collection
*/
public IteratorViewEntryCollection(ViewEntryCollection collection) {
initialize(collection);
}
/**
* Задание извне коллекции для обработки
* @param collection
*/
public void initialize(ViewEntryCollection collection) {
this.nvec = collection;
}
/**
* Метод содержит основную логику - перебор документов в цикле
* подробности см. в классе-родителе
*/
public boolean run(PDocumentBase oPDocument) {
try {
if (this.nvec == null)
return false;
if (this.nvec.getCount() == 0) return false;
this.Count = this.nvec.getCount();
Document nd;
ViewEntry nveTmp;
ViewEntry nve = this.nvec.getFirstEntry();
while (nve != null) {
lCounter++;
if (nve.isDocument()) {
nd = nve.getDocument();
if (oPDocument.processDocument(nd)) {
this.outputProgressInfo();
}
}
nveTmp = this.nvec.getNextEntry();
nve.recycle();
nve = nveTmp;
}
if (this.bOutputResult) {
this.outputResultInfo();
}
return true;
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
}
protected void finalize() {
recycle();
super.finalize();
}
public void recycle() {
try {
nvec.recycle();
}
catch (NotesException e) {}
}
}[/CODE]<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorViewNavigator.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Document;
import lotus.domino.ViewEntry;
import lotus.domino.ViewNavigator;
import lotus.domino.NotesException;
/**
* Базовый класс-итератор для перебора документов навигатора
*/
public class IteratorViewNavigator extends IteratorBase {
protected ViewNavigator navigator;
/**
* Конструктор
* Для случаев, когда навигатор известен с самого начала
* @param navigator
*/
public IteratorViewNavigator(ViewNavigator navigator) {
initialize(navigator);
}
/**
* Задание извне навигатора для обработки
* @param navigator
*/
public void initialize(ViewNavigator navigator) {
this.navigator = navigator;
}
/**
* Метод содержит основную логику - перебор документов в цикле;
* подробности см. в классе-родителе
*/
public boolean run(PDocumentBase oPDocument) {
try {
if (this.navigator == null)
return false;
if (this.navigator.getCount() == 0) return false;
this.Count = navigator.getCount();
Document nd;
ViewEntry nveTmp;
ViewEntry nve = this.navigator.getFirstDocument();
while (nve != null) {
lCounter++;
if (nve.isDocument()) {
nd = nve.getDocument();
if (oPDocument.processDocument(nd)) {
this.outputProgressInfo();
}
}
nveTmp = this.navigator.getNextDocument();
nve.recycle();
nve = nveTmp;
}
if (this.bOutputResult) {
this.outputResultInfo();
}
return true;
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
}
protected void finalize() {
recycle();
super.finalize();
}
public void recycle() {
try {
navigator.recycle();
}
catch (NotesException e) {}
}
}[/CODE]<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorVectorUNID.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import java.util.Vector;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
/**
* Базовый класс-итератор для перебора документов с взятием их по UNID.
* Будет почти всегда использоваться при работе в web.
*/
public class IteratorVectorUNID extends IteratorBase {
/**
* item, в котором содержатся UNID'ы обрабатываемых документов;
* часто используется при передаче из UI
*/
public static final String ITEM_UNID = "DocumentsUNID";
private Database ndbParent;
protected Vector<String> vctUNID;
/**
* Конструктор
* Для случаев, когда UNID'ы известны с самого начала
* @param vct - объект Vector с UNID'ами обрабатываемых документов
*/
public IteratorVectorUNID(Database ndb, Vector<String> vct) {
initialize(ndb, vct);
}
/**
* Задание извне UNID'ов документов для обработки
* @param collection
*/
public void initialize(Database ndb, Vector<String> vct) {
this.ndbParent = ndb;
this.vctUNID = vct;
}
/**
* Метод содержит основную логику - перебор документов в цикле
* подробности см. в классе-родителе
*/
public boolean run(PDocumentBase oPDocument) {
try {
if (this.vctUNID.size() == 0) return false;
this.Count = this.vctUNID.size();
Document nd = null;
for (lCounter = 0; lCounter < this.Count; lCounter++) {
try {
nd = ndbParent.getDocumentByUNID((String) this.vctUNID.get((int) lCounter));
} catch (NotesException en) {/* игнорим Err=4091 */}
if (nd != null) {
if (oPDocument.processDocument(nd)) {
this.outputProgressInfo();
}
nd.recycle();
nd = null;
}
}
if (this.bOutputResult) {
this.outputResultInfo();
}
return true;
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
}
protected void finalize() {
recycle();
super.finalize();
}
public void recycle() {
try {
if (ndbParent != null)
ndbParent.recycle();
}
catch (NotesException e) {}
vctUNID = null;
}
}[/CODE]
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">IteratorDocumentsBridge.java</div></div><div class="sp-body"><div class="sp-content"><!--shcode--><pre><code class='java'>import lotus.domino.Database;
import lotus.domino.DocumentCollection;
import lotus.domino.NotesException;
import lotus.domino.ViewEntryCollection;
import lotus.domino.ViewNavigator;
/**
* Базовый класс для реализации собственного функционала,
* где необходим перебор документов, находящихся в Lotus-контейнерах
*/
public abstract class IteratorDocumentsBridge extends PDocumentBase {
protected int count;
private Database parentDatabase;
/**
* @return объект БД, в которой был сформирован контейнер документов,
* переданный в run
*/
public void setParentDatabase(Database ndb) {
parentDatabase = ndb;
}
/**
* @return объект БД, в которой был сформирован контейнер документов,
* переданный в run
*/
public Database getParentDatabase() {
return parentDatabase;
}
/**
* Запуск на выполнение;
* передаём свою логику в класс-итератор для Vector
* @param collection - коллекция документов
* @return Результат в виде boolean
*/
public boolean run(java.util.Vector<String> vct) {
count = vct.size();
if (runPrepare()) {
IteratorVectorUNID iterator = new IteratorVectorUNID(parentDatabase, vct);
return iterator.run(this);
}
else return false;
}
/**
* Запуск на выполнение;
* передаём свою логику в класс-итератор для DocumentCollection
* @param collection - коллекция документов
* @return Результат в виде boolean
*/
public boolean run(DocumentCollection collection) {
try {
parentDatabase = collection.getParent();
count = collection.getCount();
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
if (runPrepare()) {
IteratorDocumentCollection iterator = new IteratorDocumentCollection(collection);
return iterator.run(this);
}
else return false;
}
/**
* Запуск на выполнение;
* передаём свою логику в класс-итератор для ViewEntryCollection
* @param collection - коллекция элементов вида/папки
* @return Результат в виде boolean
*/
public boolean run(ViewEntryCollection collection) {
try {
parentDatabase = collection.getParent().getParent();
count = collection.getCount();
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
if (runPrepare()) {
IteratorViewEntryCollection iterator = new IteratorViewEntryCollection(collection);
return iterator.run(this);
}
else return false;
}
/**
* Запуск на выполнение;
* передаём свою логику в класс-итератор для ViewNavigator
* @param navigator - заранее подготовленный навигатор, содержащий элементы вида
* @return Результат в виде boolean
*/
public boolean run(ViewNavigator navigator) {
try {
parentDatabase = navigator.getParentView().getParent();
count = navigator.getCount();
}
catch (NotesException en) {
System.out.println(en.getStackTrace());
return false;
}
if (runPrepare()) {
IteratorViewNavigator iterator = new IteratorViewNavigator(navigator);
return iterator.run(this);
}
else return false;
}
/**
* Расширяем метод run;
* для ситуаций, когда необходимо переопределить метод run,
* добавив код перед основным вызовом.
* @return Результат в виде boolean;
* [true] для классов не переопределяющих данный метод.
*/
public boolean runPrepare() {
return true;
}
protected void finalize() {
recycle();
}
public void recycle() {
if (parentDatabase != null) {
try {
parentDatabase.recycle();
}
catch (NotesException en) {}
}
}
}[/CODE]
С Reflection и generics не заморачивался, всё по простому.