I will start by saying that:
- I'm using ODA (godmode,khan,marcel).
- I'm the only code signer.
- sessionAsSigner is working the first time I load an XPage that calls it.
- sessionAsSigner becomes null after I reload a page (cmd + R) but not when I'm subsequently referencing it in any action during in the context of the viewScope lifetime.
- I'm implementing @Gidgerby 's concept of controller classes
I would also add that sessionAsSigner works consistently if I just prepare a simple XPage that does the following:
<p>
<xp:text value="session: #{session.effectiveUserName}" />
</p>
<p>
<xp:text value="sessionAsSigner: #{sessionAsSigner.effectiveUserName}" />
</p>
Now, I am not using SSJS. I'm JSF/EL oriented as much as I can, according to my current knowledge. So, the way I access Domino back-end is unconventional for a Domino XPages programmer.
Where I can't get getSessionAsSigner to work consistently is when I try to do the above mentioned thing...
Here is my XPage controller (backing bean):
public class TestPageController extends StandardXPageController {
private static final long serialVersionUID = 1L;
private AnswerDTO answer;
public TestPageController() {
loadQuotation();
}
private void loadQuotation() {
AnswerDAO answerDAO = Factory.createAnswerDAO();
try {
answer = answerDAO.read("doc_id");
} catch (Exception e) {
e.printStackTrace();
}
}
public AnswerDTO getAnswer() {
return answer;
}
}
AnswerDTO is a POJO. I'm using the DAO/DTO design pattern. The AnswerDAO implementation - with simplified code (wrap method is just a mere mapping of fields) - as following:
public class AnswerDAODominoImpl implements AnswerDAO {
private transient Session s;
private transient Database db;
private Session getSession() {
if (s == null) {
s = XSPUtil.getCurrentSessionAsSigner();
}
return s;
}
private Database getDatabase() throws NotesException {
if (db == null) {
db = getSession().getDatabase("server_name", "server_path");
}
return db;
}
public AnswerDTO read(String id) throws Exception {
Database db = getDatabase();
return wrap(db.getDocumentByID(id));
}
}
This is the ViewHandler class:
public class ViewHandler extends ViewHandlerExImpl {
public ViewHandler(final javax.faces.application.ViewHandler delegate) {
super(delegate);
}
@SuppressWarnings("unchecked")
public UIViewRoot createView(final FacesContext context, final String pageName) {
try {
// pageName is the XPage name prefixing the slash (e.g. "/home")
String pageClassName = pageName.substring(1);
Class<? extends XPageController> controllerClass = null;
try {
controllerClass = (Class<? extends XPageController>) context.getContextClassLoader().loadClass(
"com.sea.xsp.controller." + StringUtil.getProperCaseString(pageClassName) + "PageController");
} catch (ClassNotFoundException cnfe) {
controllerClass = StandardXPageController.class;
}
XPageController controller = controllerClass.newInstance();
Map<String, Object> requestScope = (Map<String, Object>) context.getApplication().getVariableResolver().resolveVariable(context, "requestScope");
requestScope.put("controller", controller);
UIViewRootEx root = (UIViewRootEx) super.createView(context, pageName);
root.getViewMap().put("controller", controller);
requestScope.remove("controller");
// MethodBinding beforePageLoad = context.getApplication().createMethodBinding("#{controller.beforePageLoad}", new Class[] { PhaseEvent.class });
// root.setBeforePageLoad(beforePageLoad);
return root;
} catch (Exception e) {
e.printStackTrace();
}
return super.createView(context, pageName);
}
}
Basically, what the viewhandler does is to check the existence of a java class which prefix is the XPage name itself.
eg. test.xsp = something.something.package.TestPageController
This approach allows me to forget about declaring specific XPage related classes as generic managed beans in the faces-config.xml All the XPages will get an easy handle to their corresponding backing bean that will always be named #{controller}
Now, having that being said if I simply write the following in an XPage, everything will work the first time, but not a second time (getSession() is OK, getSessionAsSigner is null), never ever again. I need to push a new change to the database (design update after any change to the java code and xsp.application.forcefullrefresh=true) and it will work again, but, again, just the first time the page is loaded.
<p>
<xp:text value="answer doc id: #{controller.answer.id}" />
</p>
Ideas?