Storing and retreiving long strings in XPages - xpages

I want to work with long strings (size minimum: 100kb) on Xpages. I assume the best method to store a large string is in a data field of the type "Rich Text".
Right now I am stuck with the data handing of this string. How can I transfer this string between server and client?
So far I tried:
data binding controls: Rich text field (Problem: formats the text, tags), text field (Problem: does not work after a certain size)
implementing a rest service: The response body will be cut off at a certain point
<xe:restService pathInfo="getTestString">
<xe:this.service>
<xe:customRestService>
<xe:this.doGet><![CDATA[#{javascript:var id = context.getUrlParameter("documentId");
session.getCurrentDatabase().getDocumentByID(id).getItemValueString("test");}]]></xe:this.doGet>
</xe:customRestService>
</xe:this.service>
</xe:restService>
var url = new URL(window.location.href);
var documentId = url.searchParams.get("documentId");
xhr.open('GET', './rest.xsp/getTestString?documentId=' + documentId, true);;
xhr.send(null);
xhr.response;
So I was wondering whether I missed out on a configuration of my REST Service. Which other alternatives are available to transfer large data between client and server on Xpages?

I tested your scenario. doc.getItemValueString() only reads 64 KB of data from the rich text field. If you want all data you can use (in SSJS):
var doc = database.getDocumentByUNID(id);
var item:NotesRichTextItem = doc.getFirstItem('test');
return item.getUnformattedText();
Looks like that method return the exact text from the rich text item, no paragraph characters are inserted.

Related

Getting value of key from Web Content Display Portlet

I got a requirement. I have added two text fields Value and Key from structure in Web Content Display portlet.
right now in the portlet i am getting value from hard code like below.
BasicModel model = (BasicModel)requestContext.getFlowScope().get("BasicModel");
if(model == null){
model = new BasicModel();
}
model.setEmployeeId("AB1223344S");
model.setHireDate("01-Jan-2000");
model.setNiNumber("AB123456S");
model.setDateOfBirth("12-Dec-1980");
model.setBasicForm(new BasicDetailsForm());
}
but what i want is to get the value of each attribute from web content. Like, If i have given lfr.intel.empid as key and ABSD1822D as value in the added web content structure field like this.
and we can fetch the value of key like this.
model.setEmployeeId(lfr.intel.empid);
You can write a custom function for this which passes the key to that function, now that function will use the JournalArticleLocalServiceUtil API to get respective value from the DB.
Now you need to find How to fetch values from JournalArticleLocalServiceUtil, which you can google or this link can help you.
Thanks.
Try this, assuming that you could get the JournalArticle object, I've done it using the resourcePrimKey
long resourcePrimKey = 12345; //hard coded the resourcePrimKey
JournalArticle article = JournalArticleLocalServiceUtil.getLatestArticle(resourcePrimKey);
com.liferay.portal.kernel.xml.Document document = SAXReaderUtil.read(article.getContentByLocale("en_US"));
Node keyNode = document.selectSingleNode("/root/dynamic-element[#name='Key']/dynamic-content");
String key = keyNode.getStringValue();
Node valueNode = document.selectSingleNode("/root/dynamic-element[#name='Value']/dynamic-content");
String value = valueNode .getStringValue();

How to store a list of dates in a multi-value field using SSJS?

In the past, I've added multi-value text data to a field putting the values into a simple JavaScript array. For example:
doc.replaceItemValue('AlwaysAccess', ["John Doe","Bob Smith"]);
Any recommendations on how to store a series of DATES in a multi-value, Time/Date field in a Notes document?
TL;DR: The concept should be almost identical to a multi-value Field of Strings, your Date(/Time) values need to be valid NotesDateTime values properly stored.
A Notes field can have multiple Date/Time values; you can see this in the Form, selecting a field of type Date/Time and checking "Allow multiple values".
You can also see that a multi-value of from the replaceItemValue page of the Domino Designer Knowledge Center.
To accomplish the same with the NotesDominoAPI (in SSJS), we'll need to:
get a handle on the NotesItem (the field, which I'll create)
create our values to put in the field (I'll create a couple using session.createDateTime)
add these values to a java.util.Vector, which will be interpreted as multi-value (you should also be able to use the SSJS Array, if you prefer)
set the values to the field
Sample code (I just ran it in the onClick event of an xp:button):
//create a new doc
var tmpDoc:NotesDocument = database.createDocument();
//give it a Form
tmpDoc.replaceItemValue("Form","MultiDateFieldForm");
//create a NotesItem
var itm:NotesItem = tmpDoc.replaceItemValue("DateFieldName",new java.util.Vector());
//create the Vector, our multi-value container
var vec:java.util.Vector = new java.util.Vector();
//create a couple NotesDateTime values to store
var first = session.createDateTime(new Date());
vec.add(first);
var second = session.createDateTime("Tomorrow");
vec.add(second);
//save the values to the item
itm.setValues(vec);
//save
tmpDoc.save();
//recycle!
first.recycle();
second.recylce();
itm.recycle();
tmpDoc.recylce();
[Edit]
As Frantisek Kossuth points out in the comments, be sure to recycle your NotesDomino API objects (especially the Date/Time ones). I've updated the code to reflect this.
[/Edit]
Checking a Form-based View after running, I'm giving this (field properties reflect the multi-value field of Date/Time values; two shots as it ran out of the box).
Essentially, I found that I needed to create a vector to store the list of dates, and populate it with NotesDateTime objects.
var vRepeatDates:java.util.Vector = new java.util.Vector();
In my case, I needed to increment the dates x amount of times. So, I used a for loop to add the NotesDateTime elements to the vector (while using .adjustDay(1) to increment the dates)
And finally store the vector in a field using replaceItemValue()
doc.replaceItemValue("RepeatInstanceDates",vRepeatDates);

getting a list of forms that contain a specified field, is there a better method

The following code is a script object on an XPage in it I loop through an array of all the forms in a database, looking for all the forms that contain the field "ACIncludeForm". My method works but it takes 2 - 3 seconds to compute which really slows the load of the XPage. My question is - is there a better method to accomplish this. I added code to check to see if the sessionScope variable is null and only execute if needed and the second time the page loads it does so in under a second. So my method really consumes a lot of processor time.
var forms:Array = database.getForms();
var rtn = new Array;
for (i=0 ; i<forms.length; ++i){
var thisForm:NotesForm = forms[i];
var a = thisForm.getFields().indexOf("ACIncludeForm");
if (a >= 0){
if (!thisForm.isSubForm()) {
if (thisForm.getAliases()[0] == ""){
rtn.push(thisForm.getName() + "|" + thisForm.getName() );
}else{
rtn.push(thisForm.getName() + "|" + thisForm.getAliases()[0] );
}
}
}
thisForm.recycle()
}
sessionScope.put("ssAllFormNames",rtn)
One approach would be to build an index of forms by yourself. For example, create an agent (LotusScript or Java) that gets all forms and for each form, create a document with for example a field "form" containing the form name and and a field "fields" containing all field names (beware of 32K limit).
Then create a view that displays all these documents and contains the value of the "fields" field in the first column so that each value of this field creates one line in this view.
Having such a view, you can simply make a #DbLookup from your XPage.
If your forms are changed, you only need to re-run the agent to re-build your index. The #DbLookup should be pretty fast.
Place the form list in a static field of a Java class. It will stay there for a long time (maybe until http boot). In my experience applicationScope values dissappear in 15 minutes.

Parse attribute of Media Element

I want to parse url attribute from the XML and show image in image control (the one reffered to by the URL) in listbox from the following feed link: http://feeds.bbci.co.uk/news/rss.xml
My code is:
var ComingNewsFromUri = from rss in XElement.Parse(e.Result).Descendants("item")
select new NewsItems
{
Title = rss.Element("title").Value,
PubDate = rss.Element("pubDate").Value,
Description = rss.Element("description").Value
};
For RSS, I would recommend using SyndicationFeed and SyndicationItem....does all the parsing and converting to objects automatically and brilliantly for you.
http://ryanhayes.net/blog/how-to-build-an-rss-feed-reader-in-windows-phone-7part-i-retrieving-parsing-and-displaying-post-titles/
I have an RSS feed app on the store myself using SyndicationFeed and it is very reliable and convenient.
Here is another sample by Microsoft
http://code.msdn.microsoft.com/wpapps/RSS-Reader-Sample-1702775f

Setting a document field with replaceItemValue from a rich text control?

How do you set a richText value with replaceItemValue from a rich tect control?
I found this bit of code here:
http://www.bleedyellow.com/blogs/martin/entry/save_a_richtext_field_from_a_xpage_to_a_document?lang=en_us
var doc = configuratieformulieren.getDocumentByKey("ConfiguratieIVNL", true);
if(doc == null){
return;
}else{
var titel = getComponent("inputTextIBPTitelIVNL").getValue();
doc.replaceItemValue("IBPTitel",titel);
var inhoud = getComponent("inputRichTextIBPInhoudIVNL").getValue();
if (inhoud != null){
var contentType = doc.getMIMEEntity("IBPInhoud").getContentType();
var encoding = doc.getMIMEEntity("IBPInhoud").getEncoding();
var str = session.createStream();
inhoud.toString();
str.writeText(inhoud.toString());
doc.getMIMEEntity("IBPInhoud").setContentFromText(str, contentType, encoding);
}
doc.save(true, true);
}
sessionScope.put("FormulierIVNLInfoBeschPG","Lezen");
Is it correct? It looks like this code depends on the fact that the field already exists. How id this handled if the field does not exist? Is there and easier way to set a field value to the contents of a rich text control?
Let data sources do the heavy lifting. For a long and boring (but thorough) explanation of why, read this article. But here's the quick version:
Don't use:
getComponent("someID").getValue()
Instead, use:
someDataSource.getValue("someFieldName")
This is always a more efficient way to access data: instead of having to spider through the component tree to locate a match, it goes straight to the data source, which the component would have to ask anyway if you asked it what its value is.
Similarly, don't use:
someDataSource.replaceItemValue("someFieldName", someValue)
Instead, use:
someDataSource.setValue("someFieldName", someValue)
The latter is much more flexible on input type. The data source already contains all the logic for determining what to do based on whether the value is text, date, number, rich text, file upload, etc. No need to duplicate any of that logic in your own code.
So if the goal is to update a separate document based on data in the current document, just define a separate document data source that points to the document you want to update. Then it's literally this simple:
configData.setValue("RichTextData", currentDocument.getValue("RichTextData"));
configData.save();
With the above code, if the field you specify on the current document is rich text, then the item it creates on the other document will be rich text. If it's any other type on the current document, it will be the same type on the other document. With getValue() and setValue(), you don't have to pay attention to the data type... the data source handles all of that for you.
For bonus points, scope configData to applicationScope so that any updates to it are immediately cached for all users... or sessionScope if the document you're updating is user-specific.
I was able to solve my orginal issue. To expand on my issue I was having problems with using a dialog box to create Form / Document B from Form / Document A using a dialog box on Form A. What was happening was any changes to Form B would be saved to Document A's datasource.
I found the ingoreRequestParams on Form B's datasource, set it and that solved my problem with Form B writing to Form A document.

Resources