2
votes

Can anyone provide an example of how to carry out basic CRUD operations using a managed bean, with a back end RichText field, so the end result is the same as using a Document Data Source in standard XPage development.

The following code is clearly wrong or incomplete, but I can't find any documentation to take it further.

I know I haven't recycled anything yet.

Many thanks.

public class RichTextTest implements Serializable {
private static final long serialVersionUID = 1L;
private String plainItem;
private RichTextItem richItem;
private String unid;


public RichTextTest ()throws NotesException {

String docID = ExtLibUtil.readParameter(FacesContext.getCurrentInstance(),"key");
if (StringUtil.isNotEmpty(docID)){load(docID);}}

public void load(String ID) throws NotesException{
Document doc = null;
setUnid(ID);

doc = ExtLibUtil.getCurrentDatabase().getDocumentByUNID(ID);
setPlainItem(doc.getItemValueString("PlainTextField"));
setRichItem ((RichTextItem) doc.getFirstItem("RichTextField"));

}

public void save() throws NotesException{

    Database database = ExtLibUtil.getCurrentDatabase();
    Document doc = database.getDocumentByUNID(getUnid());
    doc.replaceItemValue("PlainTextField", getPlainItem());
    doc.replaceItemValue("RichTextField",getRichItem());
    doc.save();


}



public String getPlainItem() {
    return plainItem;
}
public void setPlainItem(String plainItem) {
    this.plainItem = plainItem;
}
public RichTextItem getRichItem() {
    return richItem;
}
public void setRichItem(RichTextItem richItem) {
    this.richItem = richItem;
}
public void setUnid(String unid) {
    this.unid = unid;
}
public String getUnid() {
    return unid;
}

And on the XPage

    <xp:inputText value="#{richTextTest.plainItem}" id="plainTextField1">     </xp:inputText>
<xp:br></xp:br>
<xp:inputRichText value="#{richTextTest.richItem}" id="richTextField1"></xp:inputRichText>
<xp:br></xp:br>
<xp:button value="Save" id="button1"><xp:eventHandler event="onclick" submit="true" refreshMode="complete">
<xp:this.action>
    <xp:executeScript script="#{richTextTest.save}"></xp:executeScript>
</xp:this.action></xp:eventHandler></xp:button>
1
A managed bean can't hold a Notes object during serialization, so the private variable won't work. You can store the RichText as plain String. In your SAVE event, there's a bit more work. The easiest/savest way is to treat the RichText (which isn't Richtext, but HTML - there is no RichText on the web) as Mime and use the Mime classes for savingstwissel
@stwissel Many thanks for your help. A very torturous path getting ones head around the Java/Managed Beans in XPages, without any detailed documentation on the do's and don'ts. Yep, I thought there was some issue on serialization and Notes objects, I have run in to serveral problems in my efforts. I have not experience using Mime, so I guess that is my next step.Mark Maden

1 Answers

5
votes

Firstly as Stephan said in his comments, RichTextItem's are nowhere to be found in XPages. Domino can store 'Rich Text' fields in 2 ways:

  • As the classic 'RichTextItem' which the Notes Client would usually use
  • As Mime/Html which is another format entirely, made up of lotus.domino.MimeEntity's

Any "RichTextItem" field that you access/modify through XPages and save will be converted to Mime. If you are going to do anything with sending/processing emails, it is well worth learning about Mime and understanding how it all works.

If you are looking to use the inputRichText with embedded images then I don't think anyone will be able to provide you with an example. The inputRichText control is very tightly bound to the Domino Document data source. It may be possible to come up with a solution, but it would involve creating your own type of DataSource, creating a DocumentAdapter, creating a DocumentAdapterFactory, supplying it through an XspContributor and re-implementing a lot of the functionality that is within the DominoDocument, which itself wasn't trivial.

If you are only looking to allow HTML content (no embedded images or files) then you may be able to use the following solution in a previously answered stack overflow question. Bind an inputRichText to a Bean This answer describes how you can bind a bean to a inputRichText control using the MimeMultipart class. I have never used this solution so I can't comment on it's effectiveness however it has 7 upvotes so it looks good. You would want to disable the editor's toolbar icon for uploading images so that the user does not think they can upload (because they won't be able to)

At a guess, when you go to save the MimeMultipart to the Document, you would have 2 options.

  • Save it as a String
    • To save I think you would use the MimeMultipart's getHTML() function to get the HTML as string
    • To load you could create the MimeMultipart using it's static method MimeMultipart.fromHTML(yourhtml)
  • Save it as a MimeEntity
    • To save create a MimeEntity (doc.createMimeEntity()) and on that use setContentFromText(), passing in the getHTML() using a NotesStream see examples in help
    • To load, using getContentAsText() in combination with the static MimeMultipart.fromHTML(mimeEntity.getContentAsText())

Sorry none of the above is comprehensive but at least you have some avenues to explore. Note you also should look into the session.convertMime setting and how it works - learning Mime is fun, no? :)

Alternative An alternative to all this is to go with a hybrid approach of Document DataSource + bean. Binding the document Data Source to the inputRichText control, and then binding your bean to the other controls. To load your bean's data you would get access to the DominoDocument using the variable resolver. The DominoDocument is a java class that wraps the 'backend' lotus.domino.Document class. It does a bunch of stuff like keeping track of what fields have changed and whether or not someone else has modified the document since you loaded it. You can access the backend class using the DominoDocument's getDocument() function, but if you are using this hybrid approach, do not save the backend document directly, always save through the DominoDocument's save() method.

e.g. if your document data source was 'document1', make yourself a private function

private DominoDocument getDominoDocument() {
    Object o = ExtLibUtil.resolveVariable(FacesContext.getCurrentInstance(), "document1");

    if (o == null) return null;

    if (o instanceof DominoDocument) {
        return (DominoDocument)o;
    } else if (o instanceof DominoDocumentData) {
        return ((DominoDocumentData)o).getDocument();
    }
}

Then in some other function in your bean you can use to load, note the timing of when this is called is probably important (maybe postOpenDocument?)

public void loadFromDominoDocument() {
    DominoDocument ddoc = getDominoDocument();

    this.someBeanVar = ddoc.getItemValueString("someBeanVar");
    this.anotherBeanVar = ddoc.getItemValueString("anotherBeanVar");

}

conversely you will have some other function to update to the domino document with the bean values.

public void updateDominoDocument() {

    DominoDocument ddoc = getDominoDocument();

    ddoc.replaceItemValue("someBeanVar",this.someBeanVar);
    ddoc.replaceItemValue("anotherBeanVar", this.anotherBeanVar);

}

Note: I haven't done any saving yet, if you use this hybrid model then note that you must do all saving using the 'DominoDocument' class (either the save() method in your bean or the standard document save action - which calls the save() method). This is because the save method keeps track of the 'last modified date' and if you save using the backend document, it will save fine one time and then if you try to save using the DominoDocument, it will fail as it will think that the Document has been modified by someone else (as the last modified date does not match it's previously known value). Unfortunately none of the 'concurrency' settings change this behaviour.

The above code is a guide, I have only written from the top of my head so let me know if any problem with it I will have a deeper look. I'm sure you will have some questions! :)