com.hcl.domino.jna.data.JNAQueryResultsProcessor Maven / Gradle / Ivy
The newest version!
/*
* ==========================================================================
* Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
* All rights reserved.
* ==========================================================================
* Licensed under the Apache License, Version 2.0 (the "License"). You may
* not use this file except in compliance with the License. You may obtain a
* copy of the License at .
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* ==========================================================================
*/
package com.hcl.domino.jna.data;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.lang.ref.ReferenceQueue;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import com.hcl.domino.BuildVersionInfo;
import com.hcl.domino.DominoException;
import com.hcl.domino.commons.errors.INotesErrorConstants;
import com.hcl.domino.commons.gc.APIObjectAllocations;
import com.hcl.domino.commons.gc.IAPIObject;
import com.hcl.domino.commons.gc.IGCDominoClient;
import com.hcl.domino.commons.util.NotesErrorUtils;
import com.hcl.domino.commons.util.StringUtil;
import com.hcl.domino.data.Database;
import com.hcl.domino.data.NativeItemCoder;
import com.hcl.domino.data.NativeItemCoder.LmbcsVariant;
import com.hcl.domino.dql.QueryResultsProcessor;
import com.hcl.domino.jna.BaseJNAAPIObject;
import com.hcl.domino.jna.internal.LMBCSStringList;
import com.hcl.domino.jna.internal.Mem;
import com.hcl.domino.jna.internal.Mem.LockedMemory;
import com.hcl.domino.jna.internal.NotesNamingUtils;
import com.hcl.domino.jna.internal.NotesStringUtils;
import com.hcl.domino.jna.internal.capi.NotesCAPI;
import com.hcl.domino.jna.internal.capi.NotesCAPI12;
import com.hcl.domino.jna.internal.capi.NotesCAPI1201;
import com.hcl.domino.jna.internal.gc.allocations.JNADatabaseAllocations;
import com.hcl.domino.jna.internal.gc.allocations.JNAIDTableAllocations;
import com.hcl.domino.jna.internal.gc.allocations.JNANotesQueryResultsProcessorAllocations;
import com.hcl.domino.jna.internal.gc.allocations.LMBCSStringListAllocations;
import com.hcl.domino.jna.internal.gc.handles.DHANDLE;
import com.hcl.domino.jna.internal.gc.handles.DHANDLE32;
import com.hcl.domino.jna.internal.gc.handles.DHANDLE64;
import com.hcl.domino.jna.internal.gc.handles.LockUtil;
import com.hcl.domino.jna.internal.structs.NotesFieldFormulaStruct;
import com.hcl.domino.jna.internal.structs.NotesQueryResultsHandles;
import com.hcl.domino.jna.internal.structs.NotesResultsInfoStruct;
import com.hcl.domino.jna.internal.structs.NotesResultsSortColumnStruct;
import com.hcl.domino.misc.NotesConstants;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.ShortByReference;
/**
* JNA implementation of {@link QueryResultsProcessor} to run multi-database read operations.
*
* @author Karsten Lehmann
*/
public class JNAQueryResultsProcessor extends BaseJNAAPIObject implements QueryResultsProcessor {
private JNADatabase m_db;
private int m_totalNotesAdded;
public JNAQueryResultsProcessor(IGCDominoClient> dominoClient, JNADatabase db) {
super(dominoClient);
m_db = db;
//the data structures we use were changed between 12.0.0 beta 2 and beta 3,
//so let's check the build number
BuildVersionInfo buildVersionInfo = dominoClient.getBuildVersion(""); //$NON-NLS-1$
if (buildVersionInfo.getBuildNumber() <= 461) {
throw new UnsupportedOperationException("The QueryResultsProcessor requires a R12.0.0 environment or later");
}
}
@SuppressWarnings("rawtypes")
@Override
protected JNANotesQueryResultsProcessorAllocations createAllocations(IGCDominoClient> parentDominoClient,
APIObjectAllocations parentAllocations, ReferenceQueue super IAPIObject> queue) {
return new JNANotesQueryResultsProcessorAllocations(parentDominoClient, parentAllocations, this, queue);
}
@Override
public QueryResultsProcessor addNoteIds(Database parentDb, Collection idTable, String resultsname) {
checkDisposed();
NotesResultsInfoStruct ri = NotesResultsInfoStruct.newInstance();
String dbServer = NotesNamingUtils.toCommonName(parentDb.getServer());
String dbPath = StringUtil.isEmpty(dbServer) ? parentDb.getRelativeFilePath() : (dbServer + "!!" + parentDb.getRelativeFilePath()); //$NON-NLS-1$
Memory dbPathMem = NotesStringUtils.toLMBCS(dbPath, true);
byte[] dbPathArr = dbPathMem.getByteArray(0, (int) dbPathMem.size());
if (dbPathArr.length > ri.dbPath.length) {
throw new IllegalArgumentException("Database path length exceeds max size in bytes");
}
System.arraycopy(dbPathArr, 0, ri.dbPath, 0, dbPathArr.length);
if (resultsname!=null && resultsname.length()>0) {
Memory resultsnameMem = NotesStringUtils.toLMBCS(resultsname, true);
byte[] resultsnameArr = resultsnameMem.getByteArray(0, (int) resultsnameMem.size());
if (resultsnameArr.length > ri.name.length) {
throw new IllegalArgumentException("Result name exceeds max size in bytes");
}
System.arraycopy(resultsnameArr, 0, ri.name, 0, resultsnameArr.length);
}
JNAIDTable idTableCopy = idTable==null ? new JNAIDTable(getParentDominoClient()) : new JNAIDTable(getParentDominoClient(), idTable);
JNAIDTableAllocations idTableCopyAllocations = (JNAIDTableAllocations) idTableCopy.getAdapter(APIObjectAllocations.class);
DHANDLE idTableCopyHandle = idTableCopyAllocations.getIdTableHandle();
if (idTableCopyHandle instanceof DHANDLE64) {
ri.hResults = (int) (((DHANDLE64)idTableCopyHandle).hdl & 0xffffffff);
}
else if (idTableCopyHandle instanceof DHANDLE32) {
ri.hResults = ((DHANDLE32)idTableCopyHandle).hdl;
}
ri.write();
JNANotesQueryResultsProcessorAllocations queryResultsProcessorAllocations = getAllocations();
Pointer queryResultsHandlesPtr = queryResultsProcessorAllocations.getNotesQueryResultsHandles().getPointer();
IntByReference hretError = new IntByReference();
short result = NotesCAPI12.get().NSFQueryAddToResultsList(NotesConstants.QUEP_LISTTYPE.INPUT_RESULTS_LST.getValue(),
ri.getPointer(), queryResultsHandlesPtr /* &hInResults */, hretError);
if (result!=0 && hretError.getValue()!=0) {
if (hretError.getValue()!=0) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails;
try (LockedMemory memErr = Mem.OSMemoryLock(hretError.getValue(), true)) {
errorDetails = NotesStringUtils.fromLMBCS(memErr.getPointer(), -1);
}
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
else {
NotesErrorUtils.checkResult(result);
}
}
queryResultsProcessorAllocations.getNotesQueryResultsHandles().read();
m_totalNotesAdded += idTable.size();
return this;
}
@Override
public QueryResultsProcessor addColumn(String colname, String title, String formula, SortOrder sortorder, Hidden ishidden, Categorized iscategorized) {
NotesResultsSortColumnStruct rsc = NotesResultsSortColumnStruct.newInstance();
rsc.write();
if (StringUtil.isEmpty(colname)) {
throw new IllegalArgumentException("Column name cannot be empty");
}
if (title!=null && title.length()==0) {
//title is optional
title = null;
}
Memory colnameMem = NotesStringUtils.toLMBCS(colname, true);
byte[] colnameArr = colnameMem.getByteArray(0, (int) colnameMem.size());
if (colnameArr.length > NotesConstants.MAX_CMD_VALLEN) {
throw new IllegalArgumentException("Column name exceeds max text length in bytes");
}
System.arraycopy(colnameArr, 0, rsc.name, 0, colnameArr.length);
if (!StringUtil.isEmpty(title)) {
Memory titleMem = NotesStringUtils.toLMBCS(title, true);
byte[] titleArr = titleMem.getByteArray(0, (int) titleMem.size());
if (titleArr.length > NotesConstants.MAX_CMD_VALLEN) {
throw new IllegalArgumentException("Title exceeds max text length in bytes");
}
System.arraycopy(titleArr, 0, rsc.title, 0, titleArr.length);
}
IntByReference rethFormulaStr = new IntByReference();
JNANotesQueryResultsProcessorAllocations allocations = getAllocations();
if (!StringUtil.isEmpty(formula)) {
Charset charset = NativeItemCoder.get().getLmbcsCharset(LmbcsVariant.NULLTERM_KEEPNEWLINES);
byte[] formulaStringArr = formula.getBytes(charset);
short result = Mem.OSMemoryAllocate(NotesConstants.BLK_MEM_ALLOC, formulaStringArr.length, rethFormulaStr);
NotesErrorUtils.checkResult(result);
if (rethFormulaStr.getValue()==0) {
throw new DominoException("Memory allocation for formula failed");
}
allocations.addFormulaHandleForDispose(rethFormulaStr.getValue());
try (LockedMemory mem = Mem.OSMemoryLock(rethFormulaStr.getValue(), false)) {
mem.getPointer().write(0, formulaStringArr, 0, formulaStringArr.length);
}
rsc.hColFormula = rethFormulaStr.getValue();
}
rsc.sortorder = sortorder.getValue();
rsc.bHidden = ishidden == Hidden.TRUE;
rsc.bCategorized = iscategorized == Categorized.TRUE;
rsc.write();
JNANotesQueryResultsProcessorAllocations queryResultsProcessorAllocations = getAllocations();
Pointer queryResultsHandlesPtr = queryResultsProcessorAllocations.getNotesQueryResultsHandles().getPointer();
Pointer hOutFieldsPtr = queryResultsHandlesPtr.share(4);
IntByReference hretError = new IntByReference();
short result = NotesCAPI12.get().NSFQueryAddToResultsList(NotesConstants.QUEP_LISTTYPE.SORT_COL_LST.getValue(),
rsc.getPointer(), hOutFieldsPtr, hretError);
if (result!=0 && hretError.getValue()!=0) {
if (hretError.getValue()!=0) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails;
try (LockedMemory memErr = Mem.OSMemoryLock(hretError.getValue(), true)) {
errorDetails = NotesStringUtils.fromLMBCS(memErr.getPointer(), -1);
}
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
else {
NotesErrorUtils.checkResult(result);
}
}
return this;
}
@Override
public QueryResultsProcessor addFormula(String formula, String columnname, String resultsname) {
checkDisposed();
if (StringUtil.isEmpty(formula)) {
throw new IllegalArgumentException("Formula cannot be empty");
}
if (StringUtil.isEmpty(columnname)) {
throw new IllegalArgumentException("Column name cannot be empty");
}
if (StringUtil.isEmpty(resultsname)) {
throw new IllegalArgumentException("Results name cannot be empty");
}
Memory resultsnameMem = NotesStringUtils.toLMBCS(resultsname, true);
byte[] resultsnameArr = resultsnameMem.getByteArray(0, (int) resultsnameMem.size());
if (resultsnameArr.length > NotesConstants.MAX_CMD_VALLEN) {
throw new IllegalArgumentException("Results name exceeds max size in bytes");
}
Memory columnnameMem = NotesStringUtils.toLMBCS(columnname, true);
byte[] columnnameArr = columnnameMem.getByteArray(0, (int) columnnameMem.size());
if (columnnameArr.length > NotesConstants.MAX_CMD_VALLEN) {
throw new IllegalArgumentException("Column name exceeds max size in bytes");
}
Charset charset = NativeItemCoder.get().getLmbcsCharset(LmbcsVariant.NULLTERM_KEEPNEWLINES);
byte[] formulaStringArr = formula.getBytes(charset);
NotesFieldFormulaStruct ffStruct = NotesFieldFormulaStruct.newInstance();
ffStruct.write();
//write result set name
System.arraycopy(resultsnameArr, 0, ffStruct.resultsname, 0, resultsnameArr.length);
//write column name
System.arraycopy(columnnameArr, 0, ffStruct.columnname, 0, columnnameArr.length);
//write formula string
{
IntByReference rethFormula = new IntByReference();
short result = Mem.OSMemoryAllocate(NotesConstants.BLK_MEM_ALLOC, formulaStringArr.length, rethFormula);
NotesErrorUtils.checkResult(result);
if (rethFormula.getValue()==0) {
throw new DominoException("Memory allocation for formula failed");
}
try (LockedMemory mem = Mem.OSMemoryLock(rethFormula.getValue());) {
mem.getPointer().write(0, formulaStringArr, 0, formulaStringArr.length);
}
ffStruct.hFormula = rethFormula.getValue();
//dispose this later
JNANotesQueryResultsProcessorAllocations allocations = getAllocations();
allocations.addFormulaHandleForDispose(ffStruct.hFormula);
}
ffStruct.write();
Pointer ptrFF = ffStruct.getPointer();
JNANotesQueryResultsProcessorAllocations queryResultsProcessorAllocations = getAllocations();
Pointer queryResultsHandlesPtr = queryResultsProcessorAllocations.getNotesQueryResultsHandles().getPointer();
Pointer hFieldRulesPtr = queryResultsHandlesPtr.share(4 + 4);
IntByReference hretError = new IntByReference();
short result = NotesCAPI12.get().NSFQueryAddToResultsList(NotesConstants.QUEP_LISTTYPE.FIELD_FORMULA_LST.getValue(),
ptrFF, hFieldRulesPtr, hretError);
if (result!=0 && hretError.getValue()!=0) {
if (hretError.getValue()!=0) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails;
try (LockedMemory memErr = Mem.OSMemoryLock(hretError.getValue(), true)) {
errorDetails = NotesStringUtils.fromLMBCS(memErr.getPointer(), -1);
}
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
else {
NotesErrorUtils.checkResult(result);
}
}
return this;
}
@Override
public void executeToJSON(Appendable appendable, Set options) {
if (appendable==null) {
throw new IllegalArgumentException("Appendable is null");
}
JNANotesQueryResultsProcessorAllocations allocations = getAllocations();
allocations.checkDisposed();
if (m_totalNotesAdded==0) {
//workaround for 12.0.0 / 12.0.1 issue where the produced json string is invalid
try {
appendable.append(" {\"StreamResults\" :[]} "); //$NON-NLS-1$
} catch (IOException e) {
throw new DominoException(0, "Error writing data to Appendable", e);
}
}
NotesQueryResultsHandles handles = allocations.getNotesQueryResultsHandles();
handles.read();
if (handles.hOutFields == 0) {
throw new DominoException("No column has been defined");
}
JNADatabaseAllocations dbAllocations = (JNADatabaseAllocations) m_db.getAdapter(APIObjectAllocations.class);
dbAllocations.checkDisposed();
Memory viewNameMem = null;
IntByReference hErrorText = new IntByReference();
hErrorText.setValue(0);
DHANDLE.ByReference hqueue = DHANDLE.newInstanceByReference();
int dwFlags = NotesConstants.PROCRES_JSON_OUTPUT;
if (options!=null) {
if (options.contains(QRPOptions.RETURN_UNID)) {
dwFlags |= NotesConstants.PROCRES_RETURN_UNID;
}
if (options.contains(QRPOptions.RETURN_REPLICAID)) {
dwFlags |= NotesConstants.PROCRES_RETURN_REPLICAID;
}
}
final int fDwFlags = dwFlags;
short result = LockUtil.lockHandle(dbAllocations.getDBHandle(), (dbHandleByVal) -> {
return NotesCAPI12.get().NSFProcessResults(dbHandleByVal, viewNameMem,
fDwFlags, handles.hInResults, handles.hOutFields,
handles.hFieldRules, handles.hCombineRules, hErrorText, hqueue);
});
if (result == 0) {
AtomicReference hHoldQueueEntry = new AtomicReference<>();
DHANDLE.ByReference hQueueEntry = DHANDLE.newInstanceByReference();
try {
result = LockUtil.lockHandle(hqueue, (hqueueByVal) -> {
short loopError = 0;
while (loopError == 0) {
loopError = NotesCAPI.get().QueueGet(hqueueByVal, hQueueEntry);
/* hqueueentry is reused for each segment. last time it is NULLHANDLE,
so remember the handle for release */
if (hHoldQueueEntry.get() == null) {
hHoldQueueEntry.set(hQueueEntry);
}
if (loopError == 0 & !hQueueEntry.isNull()) {
LockUtil.lockHandle(hQueueEntry, (hqueueentryByVal) -> {
Pointer pinbuf = Mem.OSLockObject(hqueueentryByVal);
try {
//skip header
pinbuf = pinbuf.share(NotesConstants.queueEntryHeaderSize);
pinbuf = pinbuf.share(NotesConstants.resultsStreamBufferHeaderSize);
String dataStr = NotesStringUtils.fromLMBCS(pinbuf, -1);
appendable.append(dataStr);
} catch (IOException e) {
throw new DominoException("Error writing data to Appendable", e);
}
finally {
Mem.OSUnlockObject(hqueueentryByVal); /* note: do not free until done with queue */
}
return null;
});
}
/* not an error condition */
if (loopError == INotesErrorConstants.ERR_QUEUE_EMPTY) {
loopError = 0;
break;
}
}
return loopError;
});
}
finally {
if (hqueue!=null && !hqueue.isNull()) {
short resultQueueDelete = LockUtil.lockHandle(hqueue, (hqueueByVal)-> {
return NotesCAPI.get().QueueDelete(hqueueByVal);
});
NotesErrorUtils.checkResult(resultQueueDelete);
}
if (hHoldQueueEntry.get()!=null && !hHoldQueueEntry.get().isNull()) {
short resultMemFree = LockUtil.lockHandle(hHoldQueueEntry.get(), (hholdqueueentryByVal) -> {
return Mem.OSMemFree(hholdqueueentryByVal);
});
NotesErrorUtils.checkResult(resultMemFree);
}
}
}
if (result!=0) {
if (hErrorText.getValue()!=0) {
try (LockedMemory errMsgMem = Mem.OSMemoryLock(hErrorText.getValue(), true);) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails = NotesStringUtils.fromLMBCS(errMsgMem.getPointer(), -1);
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
}
else {
NotesErrorUtils.checkResult(result);
}
}
}
@Override
public Reader executeToJSON(Set options) {
JNANotesQueryResultsProcessorAllocations allocations = getAllocations();
allocations.checkDisposed();
if (m_totalNotesAdded==0) {
//workaround for 12.0.0 / 12.0.1 issue where the produced json string is invalid
return new StringReader(" {\"StreamResults\" :[]} "); //$NON-NLS-1$
}
NotesQueryResultsHandles handles = allocations.getNotesQueryResultsHandles();
handles.read();
if (handles.hOutFields == 0) {
throw new DominoException("No column has been defined");
}
JNADatabaseAllocations dbAllocations = (JNADatabaseAllocations) m_db.getAdapter(APIObjectAllocations.class);
dbAllocations.checkDisposed();
Memory viewNameMem = null;
IntByReference hErrorText = new IntByReference();
hErrorText.setValue(0);
DHANDLE.ByReference hqueue = DHANDLE.newInstanceByReference();
int dwFlags = NotesConstants.PROCRES_JSON_OUTPUT;
if (options!=null) {
if (options.contains(QRPOptions.RETURN_UNID)) {
dwFlags |= NotesConstants.PROCRES_RETURN_UNID;
}
if (options.contains(QRPOptions.RETURN_REPLICAID)) {
dwFlags |= NotesConstants.PROCRES_RETURN_REPLICAID;
}
}
final int fDwFlags = dwFlags;
short result = LockUtil.lockHandle(dbAllocations.getDBHandle(), (dbHandleByVal) -> {
//NSFProcessResults exists in the 12.0.0 C API:
return NotesCAPI12.get().NSFProcessResults(dbHandleByVal, viewNameMem,
fDwFlags, handles.hInResults, handles.hOutFields,
handles.hFieldRules, handles.hCombineRules, hErrorText, hqueue);
});
if (result!=0) {
if (hErrorText.getValue()!=0) {
try (LockedMemory errMsgMem = Mem.OSMemoryLock(hErrorText.getValue(), true);) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails = NotesStringUtils.fromLMBCS(errMsgMem.getPointer(), -1);
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
}
else {
NotesErrorUtils.checkResult(result);
}
}
if (hqueue.isNull()) {
return new StringReader(""); //$NON-NLS-1$
}
QueryResultsJSONReader reader = new QueryResultsJSONReader(this, hqueue, hErrorText);
//register this reader to ensure it is closed on GC
allocations.registerReaderForClose(reader);
return reader;
}
/**
* Reader implementation to receive the JSON data from the queue
*/
private static class QueryResultsJSONReader extends Reader {
private JNAQueryResultsProcessor m_processor;
private DHANDLE.ByReference m_hqueue;
private DHANDLE.ByReference m_hHoldQueueEntry;
//the last read chunk of JSON data
private String m_jsonChunk;
//position of character to return next
private int m_jsonChunkPos;
private boolean m_eof;
private boolean m_isClosed;
private IntByReference m_hErrorText;
public QueryResultsJSONReader(JNAQueryResultsProcessor processor, DHANDLE.ByReference hqueue,
IntByReference hErrorText) {
super();
m_processor = processor;
m_hqueue = hqueue;
m_hErrorText = hErrorText;
}
@Override
public void close() throws IOException {
if (m_isClosed) {
return;
}
if (m_hqueue!=null && !m_hqueue.isNull()) {
short resultQueueDelete = LockUtil.lockHandle(m_hqueue, (hqueueByVal)-> {
return NotesCAPI.get().QueueDelete(hqueueByVal);
});
NotesErrorUtils.checkResult(resultQueueDelete);
m_hqueue.clear();
}
if (m_hHoldQueueEntry!=null && !m_hHoldQueueEntry.isNull()) {
short resultMemFree = LockUtil.lockHandle(m_hHoldQueueEntry, (hholdqueueentryByVal) -> {
return Mem.OSMemFree(hholdqueueentryByVal);
});
NotesErrorUtils.checkResult(resultMemFree);
m_hHoldQueueEntry.clear();
}
JNANotesQueryResultsProcessorAllocations allocations = m_processor.getAllocations();
allocations.unregisterReaderForClose(this);
m_isClosed = true;
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
if (cbuf.length==0) {
return 0;
}
int numCharsCopied = 0;
boolean isEOF = false;
for (int i=off; i<(off+len); i++) {
//read next character
int currChar = read();
if (currChar==-1) {
//no more data
isEOF = true;
break;
}
cbuf[i] = (char) currChar;
numCharsCopied++;
}
if (numCharsCopied==0 && isEOF) {
return -1;
}
return numCharsCopied;
}
@Override
public int read(char[] cbuf) throws IOException {
return read(cbuf, 0, cbuf.length);
}
@Override
public int read() throws IOException {
if (m_jsonChunk==null || m_jsonChunkPos>=m_jsonChunk.length()) {
m_jsonChunk = readNextChunk();
m_jsonChunkPos = 0;
}
if (m_jsonChunkPos>=m_jsonChunk.length()) {
return -1;
}
return m_jsonChunk.charAt(m_jsonChunkPos++);
}
private String readNextChunk() {
if (m_eof) {
return ""; //$NON-NLS-1$
}
//make sure we have not been disposed
JNANotesQueryResultsProcessorAllocations allocations = m_processor.getAllocations();
allocations.checkDisposed();
return LockUtil.lockHandle(m_hqueue, (m_hqueueByVal) -> {
DHANDLE.ByReference hQueueEntry = DHANDLE.newInstanceByReference();
short readQueueError = NotesCAPI.get().QueueGet(m_hqueueByVal, hQueueEntry);
/* hqueueentry is reused for each segment. last time it is NULLHANDLE,
so remember the handle for release */
if (m_hHoldQueueEntry == null) {
m_hHoldQueueEntry = hQueueEntry;
}
String dataStr = "";
if (readQueueError == 0 & !hQueueEntry.isNull()) {
dataStr = LockUtil.lockHandle(hQueueEntry, (hqueueentryByVal) -> {
Pointer pinbuf = Mem.OSLockObject(hqueueentryByVal);
try {
//skip header
pinbuf = pinbuf.share(NotesConstants.queueEntryHeaderSize);
pinbuf = pinbuf.share(NotesConstants.resultsStreamBufferHeaderSize);
return NotesStringUtils.fromLMBCS(pinbuf, -1);
}
finally {
Mem.OSUnlockObject(hqueueentryByVal); /* note: do not free until done with queue */
}
});
}
/* not an error condition */
if (readQueueError == INotesErrorConstants.ERR_QUEUE_EMPTY) {
readQueueError = 0;
}
if (readQueueError!=0) {
if (m_hErrorText.getValue()!=0) {
try (LockedMemory errMsgMem = Mem.OSMemoryLock(m_hErrorText.getValue(), true);) {
Pointer errMsgPtr = errMsgMem.getPointer();
String errMsg = NotesStringUtils.fromLMBCS(errMsgPtr, -1);
throw new DominoException(readQueueError, errMsg);
}
}
else {
NotesErrorUtils.checkResult(readQueueError);
}
}
if (dataStr.length()==0) {
m_eof = true;
}
return dataStr;
});
}
}
@Override
public int executeToView(String viewName, int hoursUntilExpire, Collection readers) {
JNANotesQueryResultsProcessorAllocations allocations = getAllocations();
allocations.checkDisposed();
NotesQueryResultsHandles handles = allocations.getNotesQueryResultsHandles();
handles.read();
if (handles.hOutFields == 0) {
throw new DominoException("No column has been defined");
}
JNADatabaseAllocations dbAllocations = (JNADatabaseAllocations) m_db.getAdapter(APIObjectAllocations.class);
dbAllocations.checkDisposed();
Memory viewNameMem = NotesStringUtils.toLMBCS(viewName, true);
List readersCanonical = NotesNamingUtils.toCanonicalNames(readers);
LMBCSStringList readersList = new LMBCSStringList(this, readersCanonical, false);
LMBCSStringListAllocations readersListAllocations = (LMBCSStringListAllocations) readersList.getAdapter(APIObjectAllocations.class);
IntByReference hErrorText = new IntByReference();
hErrorText.setValue(0);
DHANDLE.ByReference hqueue = DHANDLE.newInstanceByReference();
final int timeoutsec = 0;
final int maxEntries = 0;
ShortByReference hviewcoll = new ShortByReference();
IntByReference viewnid = new IntByReference();
short result = LockUtil.lockHandles(dbAllocations.getDBHandle(), readersListAllocations.getListHandle() , (dbHandleByVal, hListByVal) -> {
//NSFProcessResultsExt got introduced in the 12.0.1 C API:
return NotesCAPI1201.get().NSFProcessResultsExt(
dbHandleByVal,
viewNameMem,
NotesConstants.PROCRES_CREATE_VIEW,
handles.hInResults,
handles.hOutFields,
handles.hFieldRules,
handles.hCombineRules,
hListByVal,
hoursUntilExpire,
hErrorText,
hqueue,
hviewcoll,
viewnid,
timeoutsec*1000,
maxEntries,
0
);
});
if (result==0) {
return viewnid.getValue();
}
else {
if (hErrorText.getValue()!=0) {
try (LockedMemory errMsgMem = Mem.OSMemoryLock(hErrorText.getValue(), true);) {
String errorMessage = NotesErrorUtils.errToString(result);
String errorDetails = NotesStringUtils.fromLMBCS(errMsgMem.getPointer(), -1);
throw new DominoException(result, errorMessage + " - " + errorDetails); //$NON-NLS-1$
}
}
else {
NotesErrorUtils.checkResult(result);
//unreachable
return 0;
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy