/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.datatables.tags;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.HtmlUtils;
import com.github.dandelion.datatables.core.configuration.Configuration;
import com.github.dandelion.datatables.jsp.tag.AbstractTableTag;
import com.github.dandelion.datatables.jsp.tag.TableTag;
/**
* Extends the {@link TableTag} to make it compatible with the usual roo tag
* attributes. This way it may replace the roo table tag just by changing the
* xmlns:table reference in the jspx header to the URL of this tag library.
*
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
*/
public class RooTableTag extends TableTag {
// Logger
private static final Logger LOGGER = LoggerFactory
.getLogger(RooTableTag.class);
private static final long serialVersionUID = 8646911296425084063L;
public static final String TABLE_TAG_VARIABLE = "__datatables_table_tag_instance__";
private final SpringContextHelper helper = new SpringContextHelper();
/** The identifier field name for the type (defaults to 'id'). */
private String typeIdFieldName = "id";
/** Include 'create' link into table (default true). */
private Boolean create = Boolean.TRUE;
/** Include 'update' link into table (default true). */
private Boolean update = Boolean.TRUE;
/** Include 'delete' link into table (default true). */
private Boolean delete = Boolean.TRUE;
/**
* Indicate if the contents of this tag and all enclosed tags should be
* rendered (default 'true')
*/
private Boolean render = Boolean.TRUE;
/**
* Used for checking if element has been modified (to recalculate simply
* provide empty string value)
*/
private String z;
/**
* View path. Used for compute default AJAX request url
*/
private String path;
/**
* ConversionService bean name in the Spring application context. It is used
* to convert the property value to String. (default
* 'applicationConversionService').
*/
private String conversionServiceId = "applicationConversionService";
private boolean doRender() {
return Boolean.TRUE.equals(render) || render == null;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public int doStartTag() throws JspException {
if (!doRender()) {
return SKIP_BODY;
}
// Add reference to this tag as request attributes
// to assure it's available for columns tags
pageContext.setAttribute(TABLE_TAG_VARIABLE, this,
PageContext.REQUEST_SCOPE);
Boolean serverSide = (Boolean) stagingConf
.get(Configuration.AJAX_SERVERSIDE);
// Check url value
if (serverSide != null && serverSide) {
if (StringUtils.isBlank(url) && StringUtils.isNotBlank(path)) {
// generate url based on path
setUrl(path.concat("/datatables/ajax"));
}
else {
setUrl(url);
}
}
else {
// Check dom data
if (data != null) {
setData((Collection) data);
}
}
int value = super.doStartTag();
return value;
}
@Override
public int doEndTag() throws JspException {
if (!doRender()) {
return SKIP_PAGE;
}
int result = super.doEndTag();
// Remove this tag reference as tag is finished
pageContext.removeAttribute(TABLE_TAG_VARIABLE);
return result;
}
@Override
public int doAfterBody() throws JspException {
if (!doRender()) {
return SKIP_BODY;
}
return super.doAfterBody();
}
/**
* Return the row id using prefix, base and suffix. Prefix and sufix are
* just prepended and appended strings. Base is extracted from the current
* iterated object. <br>
* Override {@link AbstractTableTag#getRowId()} to allow evaluate baseRowId
* using spring evaluator (as do {@link RooColumnTag#getColumnContent()}
*
* @return return the row id using prefix, base and suffix.
* @throws JspException is the rowIdBase doesn't have a corresponding
* property accessor method.
*/
protected String getRowId() throws JspException {
StringBuilder rowId = new StringBuilder();
if (StringUtils.isNotBlank(this.rowIdPrefix)) {
rowId.append(this.rowIdPrefix);
}
if (StringUtils.isNotBlank(this.rowIdBase)) {
Object propertyValue = getIdContent();
rowId.append(propertyValue != null ? propertyValue : "");
}
if (StringUtils.isNotBlank(this.rowIdSufix)) {
rowId.append(this.rowIdSufix);
}
return rowId.toString();
}
/**
* Gets Id content
*
* @return
* @throws JspException
*/
protected String getIdContent() throws JspException {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(this.rowIdBase);
EvaluationContext context = new StandardEvaluationContext(currentObject);
Object value = exp.getValue(context);
String result = "";
if (value == null) {
// Use AbstractTablaTag standard behavior
try {
value = PropertyUtils.getNestedProperty(this.currentObject,
this.rowIdBase);
}
catch (IllegalAccessException e) {
LOGGER.error(
"Unable to get the value for the given rowIdBase {}",
this.rowIdBase);
throw new JspException(e);
}
catch (InvocationTargetException e) {
LOGGER.error(
"Unable to get the value for the given rowIdBase {}",
this.rowIdBase);
throw new JspException(e);
}
catch (NoSuchMethodException e) {
LOGGER.error(
"Unable to get the value for the given rowIdBase {}",
this.rowIdBase);
throw new JspException(e);
}
}
if (value != null) {
// TODO manage exceptions to log it
ConversionService conversionService = (ConversionService) helper
.getBean(this.pageContext, getConversionServiceId());
if (conversionService != null
&& conversionService.canConvert(value.getClass(),
String.class)) {
result = conversionService.convert(value, String.class);
}
else {
result = ObjectUtils.getDisplayString(value);
}
result = HtmlUtils.htmlEscape(result);
}
return result;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getTypeIdFieldName() {
return typeIdFieldName;
}
public void setTypeIdFieldName(String typeIdFieldName) {
this.typeIdFieldName = typeIdFieldName;
}
public Boolean getCreate() {
return create;
}
public void setCreate(Boolean create) {
this.create = create;
}
public Boolean getUpdate() {
return update;
}
public void setUpdate(Boolean update) {
this.update = update;
}
public Boolean getDelete() {
return delete;
}
public void setDelete(Boolean delete) {
this.delete = delete;
}
public Boolean getRender() {
return render;
}
public void setRender(Boolean render) {
this.render = render;
}
public String getZ() {
return z;
}
public void setZ(String z) {
this.z = z;
}
public String getConversionServiceId() {
return conversionServiceId;
}
public void setConversionServiceId(String conversionServiceId) {
this.conversionServiceId = conversionServiceId;
}
}