/*
* � Copyright IBM Corp. 2010, 2013
*
* 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 com.ibm.xsp.extlib.component.picker;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.ValueBinding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.commons.util.TextUtil;
import com.ibm.domino.services.rest.RestServiceEngine;
import com.ibm.xsp.component.UITypeAhead;
import com.ibm.xsp.dojo.DojoAttribute;
import com.ibm.xsp.dojo.FacesDojoComponent;
import com.ibm.xsp.extlib.component.picker.data.INamePickerData;
import com.ibm.xsp.extlib.component.picker.data.IPickerData;
import com.ibm.xsp.extlib.component.picker.data.IPickerEntry;
import com.ibm.xsp.extlib.component.picker.data.IPickerOptions;
import com.ibm.xsp.extlib.component.picker.data.IPickerResult;
import com.ibm.xsp.extlib.component.picker.data.NamePickerAggregatorData;
import com.ibm.xsp.extlib.component.picker.data.NamePickerAggregatorData.AggregatedPickerOptions;
import com.ibm.xsp.extlib.component.picker.data.SimplePickerOptions;
import com.ibm.xsp.extlib.component.rest.IRestService;
import com.ibm.xsp.extlib.component.rest.UIBaseRestService;
import com.ibm.xsp.extlib.services.rest.picker.RestValuePickerService;
import com.ibm.xsp.extlib.services.rest.picker.ValuePickerParameters;
import com.ibm.xsp.extlib.util.ExtLibUtil;
import com.ibm.xsp.util.StateHolderUtil;
import com.ibm.xsp.util.TypedUtil;
/**
* Base class for the pickers associated to an input text.
*/
public abstract class AbstractPicker extends UIBaseRestService implements FacesDojoComponent {
public static final String COMPONENT_TYPE = "com.ibm.xsp.extlib.picker.AbstractPicker"; //$NON-NLS-1$
public static final String COMPONENT_FAMILY = "com.ibm.xsp.extlib.picker.Picker"; //$NON-NLS-1$
private String _for;
private String pickerIcon;
private String pickerText;
private String dialogTitle;
private String listWidth;
private String listHeight;
// Dynamic Dojo attributes
private String dojoType;
private List<DojoAttribute> dojoAttributes;
public AbstractPicker() {
}
@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
public abstract IPickerData getDataProvider();
public String getFor() {
if (null != this._for) {
return this._for;
}
ValueBinding _vb = getValueBinding("for"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(FacesContext.getCurrentInstance());
} else {
return null;
}
}
public void setFor(String _for) {
this._for = _for;
}
public String getDialogTitle() {
if (null != this.dialogTitle) {
return this.dialogTitle;
}
ValueBinding _vb = getValueBinding("dialogTitle"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(FacesContext.getCurrentInstance());
} else {
return null;
}
}
public void setDialogTitle(String dialogTitle) {
this.dialogTitle = dialogTitle;
}
public String getPickerIcon() {
if (null != this.pickerIcon) {
return this.pickerIcon;
}
ValueBinding _vb = getValueBinding("pickerIcon"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(FacesContext.getCurrentInstance());
} else {
return null;
}
}
public void setPickerIcon(String pickerIcon) {
this.pickerIcon = pickerIcon;
}
public String getPickerText() {
if (null != this.pickerText) {
return this.pickerText;
}
ValueBinding _vb = getValueBinding("pickerText"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(FacesContext.getCurrentInstance());
} else {
return null;
}
}
public void setPickerText(String pickerText) {
this.pickerText = pickerText;
}
public String getListWidth() {
if (null != this.listWidth) {
return this.listWidth;
}
ValueBinding _vb = getValueBinding("listWidth"); //$NON-NLS-1$
if (_vb != null) {
return (String) _vb.getValue(FacesContext.getCurrentInstance());
}
return null;
}
public void setListWidth(String listWidth) {
this.listWidth = listWidth;
}
public String getListHeight() {
if (null != this.listHeight) {
return this.listHeight;
}
ValueBinding _vb = getValueBinding("listHeight"); //$NON-NLS-1$
if (_vb != null) {
return (String) _vb.getValue(FacesContext.getCurrentInstance());
}
return null;
}
public void setListHeight(String listHeight) {
this.listHeight = listHeight;
}
public java.lang.String getDojoType() {
if (null != this.dojoType) {
return this.dojoType;
}
ValueBinding _vb = getValueBinding("dojoType"); //$NON-NLS-1$
if (_vb != null) {
return (java.lang.String) _vb.getValue(getFacesContext());
} else {
return null;
}
}
public void setDojoType(java.lang.String dojoType) {
this.dojoType = dojoType;
}
public List<DojoAttribute> getDojoAttributes() {
return this.dojoAttributes;
}
public void addDojoAttribute(DojoAttribute attribute) {
if(dojoAttributes==null) {
dojoAttributes = new ArrayList<DojoAttribute>();
}
dojoAttributes.add(attribute);
}
public void setDojoAttributes(List<DojoAttribute> dojoAttributes) {
this.dojoAttributes = dojoAttributes;
}
@Override
public void restoreState(FacesContext _context, Object _state) {
Object _values[] = (Object[]) _state;
super.restoreState(_context, _values[0]);
this.dojoType = (java.lang.String) _values[1];
this.dojoAttributes = StateHolderUtil.restoreList(_context, this, _values[2]);
this._for = (String)_values[3];
this.dialogTitle = (String)_values[4];
this.pickerIcon = (String)_values[5];
this.pickerText = (String)_values[6];
this.listWidth = (String)_values[7];
this.listHeight = (String)_values[8];
}
@Override
public Object saveState(FacesContext _context) {
Object _values[] = new Object[9];
_values[0] = super.saveState(_context);
_values[1] = dojoType;
_values[2] = StateHolderUtil.saveList(_context, dojoAttributes);
_values[3] = _for;
_values[4] = dialogTitle;
_values[5] = pickerIcon;
_values[6] = pickerText;
_values[7] = listWidth;
_values[8] = listHeight;
return _values;
}
@Override
public IRestService getService() {
return new Service();
}
protected static class Service implements IRestService {
public RestServiceEngine createEngine(FacesContext context, final UIBaseRestService parent, HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
ValuePickerParameters p = new ValuePickerParameters() {
public String[] getAttributeNames() {
return null;
}
public IPickerData getDataProvider() {
AbstractPicker picker = (AbstractPicker)parent;
return picker.getDataProvider();
}
public int getSource() {
return 0;
}
public int getStart() {
return 0;
}
public int getCount() {
return 1000; // Maximum allowed by default?
}
public String getKey() {
return null;
}
public String getStartKey() {
return null;
}
public String getContentType() {
return "application/json"; // $NON-NLS-1$
}
public boolean isCompact() {
return !ExtLibUtil.isDevelopmentMode(); // false for debug
}
};
return new RestValuePickerService(httpRequest,httpResponse,p);
}
public boolean writePageMarkup(FacesContext context, UIBaseRestService parent, ResponseWriter writer) throws IOException {
return false;
}
}
// =====================================================================
// Validation interface
// =====================================================================
public boolean isValidValue(Object value) {
IPickerData dp = getDataProvider();
if(dp!=null) {
List<IPickerEntry> val = dp.loadEntries(new Object[]{value}, null);
if(val!=null && val.get(0)!=null) {
return true;
}
}
return false;
}
// =====================================================================
// Interface with typeahead
// =====================================================================
public Object getTypeAheadValue(UITypeAhead typeAhead) {
boolean mk = typeAhead.isValueMarkup();
return mk ? getTypeAheadMarkupValue(typeAhead) : getTypeAheadSimpleValue(typeAhead);
}
/**
* @deprecated Use {@link #getTypeAheadSimpleValue(UITypeAhead)} instead
*/
public Object getTypeAheadSampleValue(UITypeAhead typeAhead) {
throw new UnsupportedOperationException("Method renamed from getTypeAheadSampleValue to getTypeAheadSimpleValue"); // $NLX-AbstractPicker.MethodrenamedfromgetTypeAheadSamp-1$
}
public Object getTypeAheadSimpleValue(UITypeAhead typeAhead) {
IPickerData dp = getDataProvider();
if(dp!=null) {
int max = typeAhead.getMaxValues();
if(max<=0) {
max = Integer.MAX_VALUE;
}
max = Math.min(max,50); // Put a limit for now...
// How to get isMultipleTrim here?
String value = getStartsValue(FacesContext.getCurrentInstance(), typeAhead, true);
// Use the Key and not the startKey to filter the right set of values
int source = 0; // Always the first source?
SimplePickerOptions options = new SimplePickerOptions(source, 0, max, value, null, null);
List<IPickerEntry> entries;
if(dp instanceof NamePickerAggregatorData ){
List<INamePickerData> sources=((NamePickerAggregatorData) dp).getDataProviders();
entries=readMultipleEntries(sources,options);
}
else{
IPickerResult r= dp.readEntries(options);
entries = r.getEntries();
}
Object[] res = new Object[entries.size()];
for(int i=0; i<res.length; i++) {
res[i] = entries.get(i).getValue();
}
return res;
}
return null;
}
public Object getTypeAheadMarkupValue(UITypeAhead typeAhead) {
IPickerData dp = getDataProvider();
if(dp!=null) {
int max = typeAhead.getMaxValues();
if(max<=0) {
max = Integer.MAX_VALUE;
}
max = Math.min(max,50); // Put a limit for now...
// Read the entry
String value = getStartsValue(FacesContext.getCurrentInstance(), typeAhead, true);
// Use the Key and not the startKey to filter the right set of values
int source = 0; // Always the first source?
SimplePickerOptions options = new SimplePickerOptions(source,0, max, value, null, null);
List<IPickerEntry> entries;
if(dp instanceof NamePickerAggregatorData ){
List<INamePickerData> sources=((NamePickerAggregatorData) dp).getDataProviders();
entries=readMultipleEntries(sources,options);
}
else{
IPickerResult r= dp.readEntries(options);
entries = r.getEntries();
}
StringBuilder b = new StringBuilder();
b.append("<ul>"); // $NON-NLS-1$
int sz = entries.size();
for(int i=0; i<sz; i++) {
IPickerEntry e = entries.get(i);
Object val = e.getValue();
if(value!=null) {
b.append("<li>"); // $NON-NLS-1$
Object label = e.getLabel();
if(label!=null) {
// Note, use double-quotes instead of single-quotes for
// attributes, so as to be XHTML-compliant.
b.append("<span class=\"informal\">"); // $NON-NLS-1$
b.append(TextUtil.toXMLString(label.toString()));
b.append("</span>"); // $NON-NLS-1$
}
b.append(TextUtil.toXMLString(val.toString()));
b.append("</li>"); // $NON-NLS-1$
}
}
b.append("</ul>"); // $NON-NLS-1$
return b.toString();
}
return null;
}
// The typeahead control should expose some features here...
private String getStartsValue(FacesContext context, UITypeAhead typeAhead, boolean isMultipleTrim) {
Map<String, String> requestMap = TypedUtil.getRequestParameterMap(context.getExternalContext());
String startsValue = requestMap.get(UITypeAhead.VALUE_NAME);
if( isMultipleTrim && null != startsValue){
startsValue = startsValue.trim();
}
return startsValue;
}
public List<IPickerEntry> readMultipleEntries(List<INamePickerData> sources,SimplePickerOptions options){
if(sources!=null && !sources.isEmpty()) {
List<IPickerEntry> results = new ArrayList<IPickerEntry>();
int source = options.getSource();
int off = 0;
for( int i=0; i<sources.size(); i++) {
INamePickerData pd = sources.get(i);
int srcCount = pd.getSourceLabels().length;
int relIdx = source-off;
if(relIdx<srcCount) {
IPickerOptions newOptions = new AggregatedPickerOptions(options,relIdx);
IPickerResult result=pd.readEntries(newOptions);
if(result!=null)
results.addAll(result.getEntries());
}
off += srcCount;
}
return results;
}
return null;
}
}