com.hcl.domino.jna.internal.richtext.JNARichtextNavigator 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.richtext;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.LinkedList;
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.richtext.RichTextUtil;
import com.hcl.domino.commons.richtext.RichtextNavigator;
import com.hcl.domino.data.Database.Action;
import com.hcl.domino.data.Document;
import com.hcl.domino.exception.ObjectDisposedException;
import com.hcl.domino.jna.BaseJNAAPIObject;
import com.hcl.domino.jna.data.JNADocument;
import com.hcl.domino.jna.data.JNAItem;
import com.hcl.domino.jna.internal.DisposableMemory;
import com.hcl.domino.jna.internal.gc.allocations.JNARichtextNavigatorAllocations;
import com.hcl.domino.richtext.RichTextWriter;
import com.hcl.domino.richtext.records.RichTextRecord;
public class JNARichtextNavigator extends BaseJNAAPIObject implements RichtextNavigator {
private String m_richTextItemName;
private LinkedList m_items;
private int m_currentItemIndex = -1;
private LinkedList> m_currentItemRecords;
private int m_currentItemRecordsIndex = -1;
public JNARichtextNavigator(JNADocument doc, String richTextItemName) {
super(doc);
m_richTextItemName = richTextItemName;
//read items
m_items = new LinkedList<>();
doc.forEachItem(richTextItemName, (item, loop) -> {
if (JNAItem.CD_TYPES.contains(item.getType()) && item instanceof JNAItem) {
m_items.add((JNAItem) item);
}
});
setInitialized();
}
/**
* Constructs a new rich-text navigator for the specific item within a document.
*
* @param doc the parent document
* @param item the item containing composite data
* @since 1.0.43
*/
public JNARichtextNavigator(JNADocument doc, JNAItem item) {
super(doc);
m_richTextItemName = item.getName();
//read items
m_items = new LinkedList<>();
m_items.add(item);
setInitialized();
}
@Override
public Document getParentDocument() {
return (Document) getParent();
}
@Override
public String getItemName() {
return m_richTextItemName;
}
@Override
protected void checkDisposedLocal() {
Document doc = getParentDocument();
if (doc instanceof JNADocument && ((JNADocument)doc).isDisposed()) {
throw new ObjectDisposedException(doc);
}
}
@SuppressWarnings("rawtypes")
@Override
protected JNARichtextNavigatorAllocations createAllocations(IGCDominoClient> parentDominoClient,
APIObjectAllocations parentAllocations, ReferenceQueue super IAPIObject> queue) {
return new JNARichtextNavigatorAllocations(parentDominoClient, parentAllocations, this, queue);
}
@Override
public RichtextPosition getCurrentPosition() {
JNARichTextPosition posImpl = new JNARichTextPosition(this, m_currentItemIndex, m_currentItemRecordsIndex);
return posImpl;
}
@Override
public void restorePosition(RichtextPosition pos) {
checkDisposed();
if (!(pos instanceof JNARichTextPosition)) {
throw new IllegalArgumentException("Invalid position, not generated by this navigator");
}
JNARichTextPosition posImpl = (JNARichTextPosition) pos;
if (posImpl.m_parentNav!=this) {
throw new IllegalArgumentException("Invalid position, not generated by this navigator");
}
int oldItemIndex = m_currentItemIndex;
m_currentItemIndex = posImpl.m_itemIndex;
m_currentItemRecordsIndex = posImpl.m_recordIndex;
if (posImpl.m_itemIndex==-1) {
m_currentItemRecords = null;
}
else if (oldItemIndex!=posImpl.m_itemIndex) {
//current item changed, so we need to reload the records
JNAItem currItem = m_items.get(m_currentItemIndex);
m_currentItemRecords = readCDRecords(currItem);
}
}
@Override
public boolean isEmpty() {
checkDisposed();
if (m_items.isEmpty()) {
return true;
}
else {
boolean hasRecords = hasCDRecords(m_items.getFirst());
return !hasRecords;
}
}
@Override
public boolean gotoFirst() {
checkDisposed();
if (isEmpty()) {
m_currentItemIndex = -1;
m_currentItemRecords = null;
m_currentItemRecordsIndex = -1;
return false;
}
else if (m_currentItemRecords==null || m_currentItemIndex!=0) {
//move to first item
JNAItem firstItem = m_items.getFirst();
m_currentItemRecords = readCDRecords(firstItem);
m_currentItemIndex = 0;
}
//move to first record
if (m_currentItemRecords.isEmpty()) {
m_currentItemRecordsIndex = -1;
return false;
}
else {
m_currentItemRecordsIndex = 0;
return true;
}
}
private boolean hasCDRecords(JNAItem item) {
final boolean[] hasRecords = new boolean[1];
item.enumerateCDRecords((signature, cdRecordPtr, cdRecordLength) -> {
hasRecords[0] = true;
return Action.Stop;
});
return hasRecords[0];
}
/**
* Copies all CD records from the specified item
*
* @param item item
* @return list with CD record data
*/
private LinkedList> readCDRecords(JNAItem item) {
final LinkedList> itemRecords = new LinkedList<>();
item.enumerateCDRecords((signature, cdRecordPtr, cdRecordLength) -> {
byte[] cdRecordDataArr = cdRecordPtr.getByteArray(0, cdRecordLength);
@SuppressWarnings("resource")
DisposableMemory cdRecordDataMem = new DisposableMemory(cdRecordLength);
cdRecordDataMem.write(0, cdRecordDataArr, 0, cdRecordLength);
ByteBuffer data = cdRecordDataMem.getByteBuffer(0, cdRecordLength).order(ByteOrder.nativeOrder());
RichTextRecord> record = RichTextUtil.encapsulateRecord(signature, data);
itemRecords.add(record);
return Action.Continue;
});
return itemRecords;
}
@Override
public boolean gotoLast() {
checkDisposed();
if (isEmpty()) {
m_currentItemIndex = -1;
m_currentItemRecords = null;
m_currentItemRecordsIndex = -1;
return false;
}
else if (m_currentItemIndex!=(m_items.size()-1)) {
//move to last item
JNAItem lastItem = m_items.getLast();
m_currentItemRecords = readCDRecords(lastItem);
m_currentItemIndex = m_items.size()-1;
}
//move to last record
if (m_currentItemRecords.isEmpty()) {
m_currentItemRecordsIndex = -1;
return false;
}
else {
m_currentItemRecordsIndex = m_currentItemRecords.size()-1;
return true;
}
}
@Override
public boolean gotoNext() {
checkDisposed();
if (isEmpty()) {
m_currentItemIndex = -1;
m_currentItemRecords = null;
m_currentItemRecordsIndex = -1;
return false;
}
else {
if (m_currentItemRecordsIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemRecordsIndex<(m_currentItemRecords.size()-1)) {
//more records available for current item
m_currentItemRecordsIndex++;
return true;
}
else {
//move to next item
if (m_currentItemIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemIndex<(m_items.size()-1)) {
//move items available
m_currentItemIndex++;
JNAItem currItem = m_items.get(m_currentItemIndex);
m_currentItemRecords = readCDRecords(currItem);
if (m_currentItemRecords.isEmpty()) {
m_currentItemRecordsIndex = -1;
return false;
}
else {
//more to first record of that item
m_currentItemRecordsIndex = 0;
return true;
}
}
else {
//no more items available
return false;
}
}
}
}
@Override
public boolean gotoPrev() {
checkDisposed();
if (isEmpty()) {
m_currentItemIndex = -1;
m_currentItemRecords = null;
m_currentItemRecordsIndex = -1;
return false;
}
else {
if (m_currentItemRecordsIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemRecordsIndex>0) {
//more records available for current item
m_currentItemRecordsIndex--;
return true;
}
else {
//move to prev item
if (m_currentItemIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemIndex>0) {
//move items available
m_currentItemIndex--;
JNAItem currItem = m_items.get(m_currentItemIndex);
m_currentItemRecords = readCDRecords(currItem);
if (m_currentItemRecords.isEmpty()) {
m_currentItemRecordsIndex = -1;
return false;
}
else {
//more to last record of that item
m_currentItemRecordsIndex = m_currentItemRecords.size()-1;
return true;
}
}
else {
//no more items available
return false;
}
}
}
}
@Override
public boolean hasNext() {
checkDisposed();
if (m_items.isEmpty()) {
return false;
}
else {
if (m_currentItemRecordsIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemRecordsIndex<(m_currentItemRecords.size()-1)) {
//more records available for current item
return true;
}
else {
if (m_currentItemIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemIndex<(m_items.size()-1)) {
//more items available
JNAItem currItem = m_items.get(m_currentItemIndex+1);
boolean hasRecords = hasCDRecords(currItem);
return hasRecords;
}
else {
//no more items available
return false;
}
}
}
}
@Override
public boolean hasPrev() {
checkDisposed();
if (m_items.isEmpty()) {
return false;
}
else {
if (m_currentItemRecordsIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemRecordsIndex>0) {
//more records available for current item
return true;
}
else {
//move to prev item
if (m_currentItemIndex==-1) {
//offroad?
return false;
}
else if (m_currentItemIndex>0) {
//move items available
JNAItem currItem = m_items.get(m_currentItemIndex-1);
boolean hasRecords = hasCDRecords(currItem);
return hasRecords;
}
else {
//no more items available
return false;
}
}
}
}
@Override
public RichTextRecord> getCurrentRecord() {
if (m_currentItemRecordsIndex==-1) {
return null;
}
else {
RichTextRecord> record = m_currentItemRecords.get(m_currentItemRecordsIndex);
return record;
}
}
@Override
public ByteBuffer getCurrentRecordData() {
RichTextRecord> record = getCurrentRecord();
if (record==null) {
return null;
}
else {
return record.getDataWithoutHeader();
}
}
@Override
public ByteBuffer getCurrentRecordDataWithHeader() {
RichTextRecord> record = getCurrentRecord();
if (record==null) {
return null;
}
else {
return record.getData();
}
}
@Override
public int getCurrentRecordHeaderLength() {
RichTextRecord> record = getCurrentRecord();
if (record==null) {
return 0;
}
else {
return record.getRecordHeaderLength();
}
}
@Override
public short getCurrentRecordTypeConstant() {
RichTextRecord> record = getCurrentRecord();
return record==null ? 0 : record.getTypeValue();
}
@Override
public int getCurrentRecordDataLength() {
RichTextRecord> record = getCurrentRecord();
return record==null ? 0 : record.getPayloadLength();
}
@Override
public int getCurrentRecordTotalLength() {
RichTextRecord> record = getCurrentRecord();
return record==null ? 0 : record.getCDRecordLength();
}
@Override
public void copyCurrentRecordTo(RichTextWriter ct) {
RichTextRecord> record = getCurrentRecord();
if (record==null) {
throw new IllegalStateException("Current record is null");
}
ct.addRichTextRecord(record);
}
public static class JNARichTextPosition implements RichtextPosition {
private RichtextNavigator m_parentNav;
private int m_itemIndex;
private int m_recordIndex;
public JNARichTextPosition(RichtextNavigator parentNav, int itemIndex, int recordIndex) {
m_parentNav = parentNav;
m_itemIndex = itemIndex;
m_recordIndex = recordIndex;
}
@Override
public int hashCode() {
RichtextNavigator nav = m_parentNav;
final int prime = 31;
int result = 1;
result = prime * result + (nav == null ? 0 : nav.hashCode());
result = prime * result + m_itemIndex;
result = prime * result + (nav == null ? 0 : nav.hashCode());
result = prime * result + m_recordIndex;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
JNARichTextPosition other = (JNARichTextPosition) obj;
RichtextNavigator nav = m_parentNav;
if(nav == null && other.m_parentNav != null) {
return false;
}
if (nav != null && !nav.equals(other.m_parentNav)) {
return false;
}
if (m_itemIndex != other.m_itemIndex) {
return false;
}
if (m_recordIndex != other.m_recordIndex) {
return false;
}
return true;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy