com.hcl.domino.jna.internal.views.NotesLookupResultBufferDecoder Maven / Gradle / Ivy
/*
* ==========================================================================
* 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.internal.views;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import com.hcl.domino.DominoException;
import com.hcl.domino.commons.data.AbstractTypedAccess;
import com.hcl.domino.commons.data.DefaultDominoDateRange;
import com.hcl.domino.commons.util.NotesDateTimeUtils;
import com.hcl.domino.commons.util.NotesErrorUtils;
import com.hcl.domino.commons.views.IItemTableData;
import com.hcl.domino.commons.views.IItemValueTableData;
import com.hcl.domino.commons.views.NotesCollectionStats;
import com.hcl.domino.commons.views.ReadMask;
import com.hcl.domino.data.Database;
import com.hcl.domino.data.Database.OpenDocumentMode;
import com.hcl.domino.data.Document;
import com.hcl.domino.data.DominoCollection;
import com.hcl.domino.data.DominoDateTime;
import com.hcl.domino.data.ItemDataType;
import com.hcl.domino.data.TypedAccess;
import com.hcl.domino.jna.data.JNACollectionEntry;
import com.hcl.domino.jna.data.JNADocument;
import com.hcl.domino.jna.data.JNADominoCollection;
import com.hcl.domino.jna.data.JNADominoDateTime;
import com.hcl.domino.jna.internal.ItemDecoder;
import com.hcl.domino.jna.internal.JNANotesConstants;
import com.hcl.domino.jna.internal.LMBCSString;
import com.hcl.domino.jna.internal.Mem;
import com.hcl.domino.jna.internal.NotesStringUtils;
import com.hcl.domino.jna.internal.gc.handles.DHANDLE;
import com.hcl.domino.jna.internal.gc.handles.LockUtil;
import com.hcl.domino.jna.internal.search.ItemTableDataDocAdapter;
import com.hcl.domino.jna.internal.structs.NotesCollectionStatsStruct;
import com.hcl.domino.jna.internal.structs.NotesItemTableLargeStruct;
import com.hcl.domino.jna.internal.structs.NotesItemTableStruct;
import com.sun.jna.Pointer;
/**
* Utility class to decode the buffer returned by data lookups, e.g. in {@link DominoCollection}s
* and for database searches.
*
* @author Karsten Lehmann
*/
public class NotesLookupResultBufferDecoder {
/**
* Decodes the buffer
*
* @param parentCollection parent collection
* @param bufferHandle buffer handle
* @param numEntriesSkipped entries skipped during collection scan
* @param numEntriesReturned entries read during collection scan
* @param returnMask bitmask used to fill the buffer with data
* @param signalFlags signal flags returned by NIFReadEntries, e.g. whether we have more data to read
* @param pos position to add to NotesViewLookupResultData object in case view data is read via {@link JNADominoCollection#findByKeyExtended2(Set, Set, Object...)}
* @param indexModifiedSequenceNo index modified sequence no
* @param retDiffTime only set in {@link JNADominoCollection#readEntriesExt(com.hcl.domino.jna.data.JNADominoCollectionPosition, com.hcl.domino.data.Navigate, boolean, int, com.hcl.domino.data.Navigate, int, Set, DominoDateTime, com.hcl.domino.jna.data.JNAIDTable, Integer)}
* @param convertStringsLazily true to delay string conversion until the first use
* @param convertDominoDateTimeToCalendar true to convert {@link JNADominoDateTime} values to {@link Calendar}
* @param singleColumnLookupName for single column lookups, programmatic name of lookup column
* @return collection data
*/
public static NotesViewLookupResultData decodeCollectionLookupResultBuffer(JNADominoCollection parentCollection,
DHANDLE bufferHandle, int numEntriesSkipped, int numEntriesReturned,
Set returnMask, short signalFlags, String pos, int indexModifiedSequenceNo, DominoDateTime retDiffTime,
boolean convertStringsLazily, boolean convertDominoDateTimeToCalendar, String singleColumnLookupName) {
return LockUtil.lockHandle(bufferHandle, (handleByVal) -> {
Pointer bufferPtr = Mem.OSLockObject(handleByVal);
try {
return decodeCollectionLookupResultBuffer(parentCollection, bufferPtr, numEntriesSkipped,
numEntriesReturned, returnMask, signalFlags, pos, indexModifiedSequenceNo, retDiffTime,
convertStringsLazily, convertDominoDateTimeToCalendar, singleColumnLookupName);
}
finally {
Mem.OSUnlockObject(handleByVal);
short result = Mem.OSMemFree(handleByVal);
NotesErrorUtils.checkResult(result);
}
});
}
/**
* Decodes the buffer
*
* @param parentCollection parent collection
* @param bufferPtr buffer pointer
* @param numEntriesSkipped entries skipped during collection scan
* @param numEntriesReturned entries read during collection scan
* @param returnMask bitmask used to fill the buffer with data
* @param signalFlags signal flags returned by NIFReadEntries, e.g. whether we have more data to read
* @param pos position to add to NotesViewLookupResultData object in case view data is read via {@link JNADominoCollection#findByKeyExtended2(Set, Set, Object...)}
* @param indexModifiedSequenceNo index modified sequence no
* @param retDiffTime only set in {@link JNADominoCollection#readEntriesExt(com.hcl.domino.jna.data.JNADominoCollectionPosition, com.hcl.domino.data.Navigate, boolean, int, com.hcl.domino.data.Navigate, int, Set, DominoDateTime, com.hcl.domino.jna.data.JNAIDTable, Integer)}
* @param convertStringsLazily true to delay string conversion until the first use
* @param convertDominoDateTimeToCalendar true to convert {@link JNADominoDateTime} values to {@link Calendar}
* @param singleColumnLookupName for single column lookups, programmatic name of lookup column
* @return collection data
*/
public static NotesViewLookupResultData decodeCollectionLookupResultBuffer(JNADominoCollection parentCollection,
Pointer bufferPtr, int numEntriesSkipped, int numEntriesReturned,
Set returnMask, short signalFlags, String pos, int indexModifiedSequenceNo, DominoDateTime retDiffTime,
boolean convertStringsLazily, boolean convertDominoDateTimeToCalendar, String singleColumnLookupName) {
int bufferPos = 0;
NotesCollectionStats collectionStats = null;
if (returnMask.contains(ReadMask.COLLECTIONSTATS)) {
NotesCollectionStatsStruct tmpStats = NotesCollectionStatsStruct.newInstance(bufferPtr);
tmpStats.read();
collectionStats = new NotesCollectionStats(tmpStats.TopLevelEntries, tmpStats.LastModifiedTime);
bufferPos += tmpStats.size();
}
List viewEntries = new ArrayList<>();
final boolean decodeAllValues = true;
if (returnMask.size()==1 && returnMask.contains(ReadMask.NOTEID)) {
//special optimized case for reading only note ids
int[] noteIds = new int[numEntriesReturned];
bufferPtr.read(0, noteIds, 0, numEntriesReturned);
for (int i=0; i itemValues = itemTableData.asMap(false);
newData.setSummaryData(itemValues);
}
if (singleColumnLookupName!=null) {
newData.setSingleColumnLookupName(singleColumnLookupName);
}
}
}
return new NotesViewLookupResultData(collectionStats, viewEntries, numEntriesSkipped, numEntriesReturned, signalFlags, pos, indexModifiedSequenceNo, retDiffTime);
}
/**
* Produces an item table by decoding an ITEM_VALUE_TABLE structure, which contains an ordered list of item values,
* and adding an array of column names
*
* @param db parent database
* @param noteId note ID of document
* @param columnFormulasFixedOrder column item names/formulas in a fixed order (matching the summary buffer content)
* @param bufferPtr pointer to a buffer
* @param convertStringsLazily true to delay string conversion until the first use
* @param convertJNADominoDateTimeToCalendar true to convert {@link JNADominoDateTime} values to {@link Calendar}
* @param decodeAllValues true to decode all values in the buffer
* @return item value table data
*/
public static IItemTableData decodeItemValueTableWithColumnNames(
Database db,
int noteId,
LinkedHashMap columnFormulasFixedOrder,
Pointer bufferPtr, boolean convertStringsLazily, boolean convertJNADominoDateTimeToCalendar, boolean decodeAllValues) {
ItemValueTableDataImpl valueTable = (ItemValueTableDataImpl) decodeItemValueTable(bufferPtr, convertStringsLazily, convertJNADominoDateTimeToCalendar, decodeAllValues);
IItemTableData itemTableData = new ItemTableDataImpl(db, noteId, columnFormulasFixedOrder, valueTable);
return itemTableData;
}
/**
* Produces an item table by decoding an ITEM_VALUE_TABLE structure, which contains an ordered list of item values,
* and adding an array of column names
*
* @param db parent database
* @param noteId note ID of document
* @param columnFormulasFixedOrder column item names/formulas in a fixed order (matching the summary buffer content)
* @param bufferPtr pointer to a buffer
* @param convertStringsLazily true to delay string conversion until the first use
* @param convertJNADominoDateTimeToCalendar true to convert {@link JNADominoDateTime} values to {@link Calendar}
* @param decodeAllValues true to decode all values in the buffer
* @return item value table data
*/
public static IItemTableData decodeItemValueTableLargeWithColumnNames(
Database db,
int noteId,
LinkedHashMap columnFormulasFixedOrder,
Pointer bufferPtr, boolean convertStringsLazily, boolean convertJNADominoDateTimeToCalendar, boolean decodeAllValues) {
ItemValueTableDataImpl valueTable = (ItemValueTableDataImpl) decodeItemValueTableLarge(bufferPtr, convertStringsLazily, convertJNADominoDateTimeToCalendar, decodeAllValues);
IItemTableData itemTableData = new ItemTableDataImpl(db, noteId, columnFormulasFixedOrder, valueTable);
return itemTableData;
}
/**
* Decodes a large item value table structure, which contains an ordered list of item values
*
* @param bufferPtr pointer to a buffer
* @param convertStringsLazily true to delay string conversion until the first use
* @param convertJNADominoDateTimeToCalendar true to convert {@link JNADominoDateTime} values to {@link Calendar}
* @param decodeAllValues true to decode all values in the buffer
* @return item value table data
*/
public static IItemValueTableData decodeItemValueTableLarge(Pointer bufferPtr,
boolean convertStringsLazily, boolean convertJNADominoDateTimeToCalendar, boolean decodeAllValues) {
int bufferPos = 0;
//skip item value table header
bufferPos += JNANotesConstants.itemValueTableLargeSize;
// The information in a view summary of values is as follows:
//
// ITEM_VALUE_TABLE containing header information (total length of summary, number of items in summary)
// WORD containing the length of item #1 (including data type)
// WORD containing the length of item #2 (including data type)
// WORD containing the length of item #3 (including data type)
// ...
// USHORT containing the data type of item #1
// value of item #1
// USHORT containing the data type of item #2
// value of item #2
// USHORT containing the data type of item #3
// value of item #3
// ....
int totalBufferLength = bufferPtr.getInt(0);// & 0xffff;
int itemsCount = bufferPtr.getShort(4) & 0xffff;
int[] itemValueLengths = new int[itemsCount];
//we don't have any item names:
int[] itemNameLengths = null;
bufferPos+=2;
//read all item lengths
for (int j=0; j0) {
itemNames[j] = NotesStringUtils.fromLMBCS(bufferPtr.share(bufferPos), itemNameLengths[j]);
bufferPos += itemNameLengths[j];
}
//read data type
if (itemValueLengths[j] == 0) {
/* If an item has zero length it indicates an "empty" item in the
summary. This might occur in a lower-level category and stand for a
higher-level category that has already appeared. Or an empty item might
be a field that is missing in a response doc. Just print * as a place
holder and go on to the next item in the pSummary. */
continue;
}
else {
itemDataTypes[j] = bufferPtr.getShort(bufferPos) & 0xffff;
//add data type size to position
bufferPos += 2;
//read item values
itemValueBufferPointers[j] = bufferPtr.share(bufferPos);
itemValueBufferSizes[j] = itemValueLengths[j] - 2;
//skip item value
bufferPos += (itemValueLengths[j] - 2);
if (decodeAllValues) {
int itemValueBufferSizeAsInt = (int) (itemValueBufferSizes[j] & 0xffffffff);
if (itemDataTypes[j] == ItemDataType.TYPE_TEXT.getValue()) {
Object strVal = ItemDecoder.decodeTextValue(itemValueBufferPointers[j], itemValueBufferSizeAsInt, convertStringsLazily);
decodedItemValues[j] = strVal;
}
else if (itemDataTypes[j] == ItemDataType.TYPE_TEXT_LIST.getValue()) {
//read a text list item value
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy