/*
* © Copyright FOCONIS AG, 2014
*
* 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 org.openntf.domino.xsp.formula;
import java.util.HashMap;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import org.openntf.domino.Document;
import org.openntf.domino.formula.FormulaContextNotes;
import org.openntf.domino.utils.Factory;
import org.openntf.domino.xsp.model.DominoDocumentMapAdapter;
import org.openntf.formula.EvaluateException;
import org.openntf.formula.ValueHolder;
import com.ibm.xsp.application.ApplicationEx;
import com.ibm.xsp.binding.ComponentBindingObject;
import com.ibm.xsp.binding.ValueBindingEx;
import com.ibm.xsp.model.domino.wrapped.DominoDocument;
/**
* This is the formula context in Xsp-environment. It adds additional features to the {@link FormulaContextNotes} like accessing the current
* component or FacesContext in the {@literal @}Formulas.
*
* DataMap may be a {@link org.openntf.domino.Document} or a {@link DominoDocument} so that you can directly interact on the
* "currentDocument"
*
* @author Roland Praml, FOCONIS AG
*
*/
public class FormulaContextXsp extends FormulaContextNotes {
private UIComponent component;
private FacesContext context;
private Map<String, ValueBinding> valueBindings = new HashMap<String, ValueBinding>();
/**
* Initialize the context with xpage parameters
*
* @param component
* the current component
* @param ctx
* the current FacesContext
*/
public void init(final UIComponent component, final FacesContext ctx) {
this.component = component;
this.context = ctx;
}
/**
* returns the current document. If dataMap is a {@link DominoDocument}, the containing document is returned. Otherwise
* {@link FormulaContextNotes#getDocument()} is returned.
*
* @return the current {@link Document}
*/
@SuppressWarnings("deprecation")
@Override
public Document getDocument() {
DominoDocument dominoDoc = getXspDocument();
if (dominoDoc != null) {
return Factory.fromLotus(dominoDoc.getDocument(), Document.SCHEMA, null);
} else {
return super.getDocument();
}
}
/**
* returns the current Xpage-Document or null if we don't have one
*
* @return the current {@link DominoDocument}
*/
public DominoDocument getXspDocument() {
if (dataMap instanceof DominoDocument) {
return (DominoDocument) dataMap;
} else if (dataMap instanceof DominoDocumentMapAdapter) {
return ((DominoDocumentMapAdapter) dataMap).getDelegate();
}
return null;
}
/**
* Returns the UI-Component or null if we don't have one
*
* @return a {@link UIComponent}
*/
public UIComponent getComponent() {
return component;
}
/**
* Returns a field
*
* @param key
* if it is a field identifier (like <code>Subject</code>) then dataMap.get(key) is returned.<br/>
* if it contains a "." and we have a valid FacesContext then it is treated as XPage-value. So you can access XPage-Values
* inside formula language. e.g. {@literal @}text(myBean.myValue)
* @return the value wrapped in a {@link ValueHolder}
*/
@Override
public ValueHolder getField(final String key) {
if (key.indexOf('.') < 0 || context == null) {
return super.getField(key);
} else {
Object var = getValueBinding(key).getValue(context);
return ValueHolder.valueOf(var);
}
}
/**
* Sets a field
*
* @param key
* You can read/write dataMap and/or XPage-values. See {@link #getField(String)}
*/
@Override
public void setField(final String key, final ValueHolder elem) {
if (key.indexOf('.') < 0) {
super.setField(key, elem);
} else {
try {
Object var = elem.toList();
getValueBinding(key).setValue(context, var);
} catch (EvaluateException e) {
e.printStackTrace();
}
}
}
/**
* Create a value binding for {@link #getField(String)} and {@link #setField(String, ValueHolder)}
*
* @param variable
* the variableName, like <code>"document2.Form"</code>
* @return a {@link ValueBinding}
*/
protected ValueBinding getValueBinding(final String variable) {
ValueBinding ret = valueBindings.get(variable);
if (ret == null) {
ApplicationEx app = (ApplicationEx) context.getApplication();
ret = app.createValueBinding("#{" + variable + "}");
if ((ret instanceof ValueBindingEx)) {
ValueBindingEx valueEx = (ValueBindingEx) ret;
valueEx.setComponent(component);
valueEx.setSourceReferenceId(null); // TODO RPr: What to set here
valueEx.setExpectedType(Object.class);
} else if ((ret instanceof ComponentBindingObject)) {
((ComponentBindingObject) ret).setComponent(component);
}
valueBindings.put(variable, ret);
}
return ret;
}
}