2013-04-05 57 views
0

我有從進一步擴展庫中的對話框控件的一個問題:XPAGE EXTLIB對話框keepComponents真實和JSF組件

我創建了一個Java自定義控制至極搜索的一些看法,收集一些數據,並顯示出來。這很好,如果我把它放在XPage上。

但我想在對話框中顯示的數據,所以我使用從進一步擴展庫對話控制。使用對話框控件無需任何配置也能正常工作,但它需要一些時間對我的控制搜索的意見和每次我打開dialog.So,以減少用戶的等待時間時,我想利用選項"keepComponents="true"從顯示數據對話框控件。

現在,如果我第一次打開對話框一切都是完美的,但如果我打開它secound時間,它顯示的內容從第一次打開除了從我的controlRenderer錯誤,告訴我它不能得到來自控件的viewName。每當我打開和關閉對話框時,此錯誤都會疊加起來。

我在OpenNtf上發現了一篇文章,內容是有人在使用此選項時在對話框中出現了多個內容的問題,但他沒有得到任何答案。 這是組件的錯誤嗎?我應該忘記這個選項並將數據緩存在一個bean中嗎?爲什麼渲染器不能從組件獲取視圖名?

+1

代碼示例請 – stwissel 2013-04-05 10:05:24

回答

0

下面的回答假設你的問題短語「Java自定義控制」是指你開發的JSF組件;在XPages中,術語「自定義控件」通常指自定義控件設計元素的一個實例,這是IBM對「複合組件」的JSF概念的實現。

你說,最初成分表現如預期,但未能在後續的請求。這通常表示該組件的restoreStatesaveState方法並沒有得到很好的貫徹。

當爲應用程序啓用默認序列化選項時,所有組件狀態在每個請求結束時寫入磁盤,並在下一個開始時讀回到內存中。這兩個操作的處理,分別由每種組分的saveStaterestoreState方法。

例如,假設您定義了一個用於將HTML canvas標籤添加到XPage的組件,並決定支持與該元素關聯的手勢和觸摸事件。所以,你的組件類會包含字段存儲綁定到這些事件的任何代碼:

private String ongesturechange; 
private String ongestureend; 
private String ongesturestart; 
private String ontouchcancel; 
private String ontouchend; 
private String ontouchmove; 
private String ontouchstart; 

每個這些字段通常會再有一個相關的「吸氣」和「二傳手」的方法:

public String getOngesturechange() { 
    return getStringProperty("ongesturechange", this.ongesturechange); 
} 

public void setOngesturechange(String ongesturechange) { 
    this.ongesturechange = ongesturechange; 
} 

當該組件的一個實例被初始化,與爲該組件實例定義的每個屬性關聯的「setter」方法將被傳遞爲該屬性定義的值。然後,對於初始頁面請求的其餘部分,每個已定義屬性的專用字段將存儲已設置的值。在請求結束時,saveState方法將這些字段的值寫入磁盤。一個典型的saveState方法看起來類似如下:

@Override 
public Object saveState(FacesContext context) { 
    Object[] properties = new Object[8]; 
    int idx = 0; 
    properties[idx++] = super.saveState(context); 
    properties[idx++] = this.ongesturechange; 
    properties[idx++] = this.ongestureend; 
    properties[idx++] = this.ongesturestart; 
    properties[idx++] = this.ontouchcancel; 
    properties[idx++] = this.ontouchend; 
    properties[idx++] = this.ontouchmove; 
    properties[idx++] = this.ontouchstart; 
    return properties; 
} 

super.saveState()調用執行相同的方法,但是使用在父類中定義的方法的版本。因此,每個組件的磁盤表示本質上是一個嵌套數組:層次結構中的每個層都存儲它從其父類繼承的所有屬性到數組的第一個元素中,然後將其定義的所有屬性存儲在其他數組元素中。

當組分樹在後續請求恢復,各組件使用其restoreState方法來重構其所有字段的值。一個典型的restoreState方法類似於以下內容:

@Override 
public void restoreState(FacesContext context, Object state) { 
    Object[] properties = (Object[]) state; 
    int idx = 0; 
    super.restoreState(context, properties[idx++]); 
    this.ongesturechange = ((String) properties[idx++]); 
    this.ongestureend = ((String) properties[idx++]); 
    this.ongesturestart = ((String) properties[idx++]); 
    this.ontouchcancel = ((String) properties[idx++]); 
    this.ontouchend = ((String) properties[idx++]); 
    this.ontouchmove = ((String) properties[idx++]); 
    this.ontouchstart = ((String) properties[idx++]); 
} 

此分層讀取在磁盤上的數據回覆於:每個類將一組屬性的父類的,然後分配剩餘的數組元素中的字段他們與保存組件狀態的時間有關。

這一過程提供了一種簡單的方式來維護跨請求組件狀態 - 繼承的每一層只需要與該層定義了新的屬性本身的關注 - 但這些國家的保養方法很容易忘記實現。如果組件實現中省略了任何一種方法,那麼頁面會在後續請求中「忘記」屬性值,因爲它們從未寫入磁盤,或者未被加載回內存中,或者兩者都未加載。

假設這是問題的根本原因,當組件位於默認值爲(false)值爲keepComponents的對話框中時,問題不會發生的原因是默認的對話行爲是將其子項從組件樹完全在對話框關閉時。這種行爲是出於性能方面的原因:理論上存儲服務器端組件的表示只存在於用戶當前沒有與之進行交互的對話框中沒有任何好處。當對話框再次打開時,使用原始屬性值創建每個子組件的新的實例。在這種情況下,組件不會保存其狀態,因爲每次使用它時都會創建一個新實例。但是,如果通知對話將子對象保留在組件樹中,那麼現在組件必須正確維護其自己的狀態......否則其屬性值將在每個請求結束時丟棄,並且後續請求不知道以前的值。

總之,是的,你顯示的數據應該在一個bean(或數據源)高速緩存,如果數據是不可能足夠的請求之間的每一個事件再次變更證明獲得的數據。但是你描述的特定行爲的原因很可能是因爲你的組件實現不能正確維護自己的狀態。

+0

您好蒂姆,thx您的建議,但我已經使用'saveState'和'restoreState'方法,但我認爲問題是我的組件每次恢復時都會嘗試自我渲染。 – 2013-04-08 07:03:14

+0

我不確定您的意思是「嘗試呈現它自己」......如果您可以發佈組件的源代碼(當然,不包括任何機密的業務邏輯),那麼可以更輕鬆地排查此問題。否則,我們只是猜測。 :) – 2013-04-08 09:18:05

+0

Jep,我將添加一些代碼 - 需要首先從業務邏輯中清除它 - 但我必須先考慮具有更高優先級的另一個問題。 – 2013-04-08 09:39:25