de.tsl2.nano.h5.configuration.BeanConfigurator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tsl2.nano.h5 Show documentation
Show all versions of tsl2.nano.h5 Show documentation
TSL2 Framework Html5 Extensions (WebServer, Html5Presentation, RuleCover, BeanConfigurator, LogicTable-Sheet, Expression-Descriptors for Actions, Rules, URLs, Queries)
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Tom, Thomas Schneider
* created on: 07.01.2014
*
* Copyright: (c) Thomas Schneider 2014, all rights reserved
*/
package de.tsl2.nano.h5.configuration;
import static de.tsl2.nano.h5.HtmlUtil.ATTR_BGCOLOR;
import static de.tsl2.nano.h5.HtmlUtil.COLOR_LIGHT_GRAY;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import de.tsl2.nano.action.CommonAction;
import de.tsl2.nano.action.IConstraint;
import de.tsl2.nano.bean.annotation.ConstraintValueSet;
import de.tsl2.nano.bean.def.AttributeDefinition;
import de.tsl2.nano.bean.def.Bean;
import de.tsl2.nano.bean.def.BeanDefinition;
import de.tsl2.nano.bean.def.Constraint;
import de.tsl2.nano.bean.def.IAttributeDefinition;
import de.tsl2.nano.bean.def.IPresentable;
import de.tsl2.nano.bean.def.IPresentableColumn;
import de.tsl2.nano.bean.def.Presentable;
import de.tsl2.nano.bean.def.ValueColumn;
import de.tsl2.nano.bean.def.ValueExpression;
import de.tsl2.nano.bean.def.ValueExpressionFormat;
import de.tsl2.nano.bean.def.ValueGroup;
import de.tsl2.nano.collection.Entry;
import de.tsl2.nano.core.ENV;
import de.tsl2.nano.core.ManagedException;
import de.tsl2.nano.core.cls.BeanClass;
import de.tsl2.nano.core.cls.IAttribute;
import de.tsl2.nano.core.cls.PrivateAccessor;
import de.tsl2.nano.core.util.ConcurrentUtil;
import de.tsl2.nano.core.util.FileUtil;
import de.tsl2.nano.core.util.MapUtil;
import de.tsl2.nano.core.util.StringUtil;
import de.tsl2.nano.core.util.Util;
import de.tsl2.nano.h5.Html5Presentable;
import de.tsl2.nano.h5.SpecifiedAction;
import de.tsl2.nano.h5.collector.CSheet;
import de.tsl2.nano.h5.collector.Compositor;
import de.tsl2.nano.h5.collector.Controller;
import de.tsl2.nano.h5.collector.Increaser;
import de.tsl2.nano.h5.expression.Query;
import de.tsl2.nano.h5.expression.WebClient;
import de.tsl2.nano.specification.Pool;
import de.tsl2.nano.specification.actions.Action;
import de.tsl2.nano.specification.rules.Rule;
import de.tsl2.nano.specification.rules.RuleScript;
/**
* wrapper class to handle presentation of a bean-definition. at a time, only one BeanConfigurator is active. this
* instance will be registered to the environment to be usable as something like a singleton from outside.
*
* @author Tom, Thomas Schneider
* @version $Revision$
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class BeanConfigurator implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
BeanDefinition def;
private PrivateAccessor> defAccessor;
private transient List attrConfigurators;
/**
* factory method to create a bean configurator for the given instance type.
*
* @param instance to evaluate the type and {@link BeanDefinition} for.
* @return new bean configurator instance
*/
public static Bean> create(Class type) {
boolean autopersistEnv = ENV.isAutopersist();
BeanConfigurator> configurer = ConcurrentUtil.getCurrent(BeanConfigurator.class);
if (configurer == null || !configurer.def.getDeclaringClass().equals(type)) {
try {
ENV.setAutopersist(false);
Serializable layout = (Serializable) MapUtil.asMap(ATTR_BGCOLOR, COLOR_LIGHT_GRAY);
if (configurer == null)
prepareBeanDefinitionProperties(layout);
//wrap the bean-def into a bean-configurator and pack it into an own bean
configurer = new BeanConfigurator(BeanDefinition.getBeanDefinition(type));
//register it to be used by creating new AttributeConfigurators
ConcurrentUtil.setCurrent(configurer); //avoid stackoverflow
//define the presentation
Bean> configBean = Bean.getBean(configurer);
if (configBean.isDefault()) {
configBean.setAttributeFilter("name", "valueExpression", "presentable", "valueGroups", "attributes");
configBean.getPresentable().setLayout(layout);
((ValueExpressionFormat) configBean.getAttribute("attributes").getFormat())
.getValueExpression()
.setExpression("{name}");
// configBean.saveDefinition();
}
return (Bean>) configBean;
} finally {
ENV.setAutopersist(autopersistEnv);
}
}
return (Bean>) (Object)Bean.getBean(configurer);
}
private static void prepareBeanDefinitionProperties(Serializable layout) {
BeanDefinition configPres = BeanDefinition.getBeanDefinition(Html5Presentable.class, false);
configPres.setAttributeFilter("label", "description", "icon", "type", "style", "visible", "searchable",
"nesting", "width",
"height", "layout",
"layoutConstraints", "groups");
configPres.getPresentable().setLayout(layout);
configPres.getValueExpression();
// configPres.saveDefinition();
BeanDefinition configValueGroup = BeanDefinition.getBeanDefinition(ValueGroup.class, false);
configValueGroup.setAttributeFilter("label", "description", "icon", "type", "style", "width", "height",
"layout",
"layoutConstraints", "attributes");
configValueGroup.getPresentable().setLayout(layout);
configValueGroup.getValueExpression();
// configValueGroup.saveDefinition();
BeanDefinition configColDef = BeanDefinition.getBeanDefinition(ValueColumn.class, false);
configColDef.setAttributeFilter("name", "description", "index", "sortIndex", "sortUpDirection",
"format",
"width"
/* "standardSummary",
"presentable",
"minSearchValue",
"maxSearchValue"*/
);
configColDef.getPresentable().setLayout(layout);
BeanDefinition.getBeanDefinition(IPresentableColumn.class, false).setAttributeFilter(configColDef.getAttributeNames());
// configColDef.saveDefinition();
BeanDefinition configConstraint = BeanDefinition.getBeanDefinition(Constraint.class, false);
configConstraint.setAttributeFilter("type", "minimum", "maximum", "format", "length", "scale",
"precision",
"nullable");
configConstraint.getPresentable().setLayout(layout);
BeanDefinition.getBeanDefinition(IConstraint.class, false).setAttributeFilter(configConstraint.getAttributeNames());
// configConstraint.saveDefinition();
defineAction(layout);
BeanDefinition configEntry = BeanDefinition.getBeanDefinition(Entry.class, false);
configEntry.setAttributeFilter("key", "value");
configEntry.getPresentable().setLayout(layout);
configEntry.getValueExpression();
// configEntry.saveDefinition();
BeanDefinition configAttr =
BeanDefinition.getBeanDefinition(AttributeConfigurator.class, false);
configAttr.setAttributeFilter("name", "description", "type", "format",
"constraint"/*, "length", "min", "max"*/,
"presentable", "columnDefinition", "declaration", "valueExpression", "default", "listener");
configAttr.getPresentable().setLayout(layout);
configAttr.setValueExpression(new ValueExpression("{name}", AttributeConfigurator.class));
// configAttr.saveDefinition();
}
/**
* defineAction
*
* @param layout
*/
public static void defineAction(Serializable layout) {
BeanDefinition configAction = BeanDefinition.getBeanDefinition(CommonAction.class);
configAction.setAttributeFilter("id", "shortDescription", "longDescription", "keyStroke", "enabled", "default",
"imagePath");
configAction.setIdAttribute("id");
configAction.setValueExpression(new ValueExpression("{shortDescription}", CommonAction.class));
if (layout != null) {
configAction.getPresentable().setLayout(layout);
}
}
/**
* constructor
*
* @param def bean-def
*/
protected BeanConfigurator(BeanDefinition def) {
super();
this.def = def;
defAccessor = new PrivateAccessor>(def);
}
/**
* @return Returns the attributeDefinitions.
*/
public List getAttributes() {
if (attrConfigurators == null) {
//we know that there are attribute-defs inside!
List attributes = def.getAttributes();
attrConfigurators = new ArrayList(attributes.size());
for (IAttribute> a : attributes) {
attrConfigurators.add(new AttributeConfigurator((AttributeDefinition>) a));
}
}
return attrConfigurators;
}
/**
* @param attributes The attributeDefinitions to set.
*/
public void setAttributes(List attributes) {
Map definitions = defAccessor.call("getAttributeDefinitions", Map.class);
Map invisibles = new LinkedHashMap<>(definitions);
definitions.clear();
int i = 0;
for (AttributeConfigurator cattr : attributes) {
IAttributeDefinition a = cattr.unwrap();
if (a.getColumnDefinition() == null)
a.setColumnDefinition(++i, IPresentable.UNDEFINED, true, IPresentable.UNDEFINED);
else //IMPROVE: enhance interfaces to set index without reflection
new PrivateAccessor(a.getColumnDefinition()).set("columnIndex", ++i);
def.addAttribute(a);
invisibles.remove(a.getName());
}
//add not-selected attributes as invisibles at the end
for (IAttributeDefinition> a : invisibles.values()) {
//IMPROVE: enhance interfaces to set index without reflection
a.getPresentation().setVisible(false);
if (a.getColumnDefinition() != null) {
new PrivateAccessor(a.getColumnDefinition()).set("columnIndex", ++i);
a.getColumnDefinition().getPresentable().setVisible(false);
}
def.addAttribute(a);
}
attrConfigurators = null;
}
/**
* @return Returns the presentable.
*/
public Presentable getPresentable() {
return (Presentable) def.getPresentable();
}
/**
* @param presentable The presentable to set.
*/
public void setPresentable(Presentable presentable) {
def.setPresentable(presentable);
}
/**
* @return Returns the presentable.
*/
public Collection getValueGroups() {
return defAccessor.member("valueGroups", Collection.class);
}
/**
* @param valueGroups The presentable to set.
*/
public void setValueGroups(Collection valueGroups) {
defAccessor.set("valueGroups", valueGroups);
}
/**
* @return Returns the name.
*/
public String getName() {
return def.getName();
}
/**
* @return Returns the valueExpression.
*/
public String getValueExpression() {
return def.getValueExpression().getExpression();
}
/**
* @param valueExpression The valueExpression to set.
*/
public void setValueExpression(String valueExpression) {
def.setValueExpression(new ValueExpression(valueExpression, def.getClazz()));
}
/**
* saves the current bean configuration.
* this method will trigger the bean-framework to provide an action to be presented as button in a gui.
*
* @return null
*/
public Object actionSave() {
defAccessor.set("isdefault", false);
//WORKAROUND: doesn't call setAttributes(), so we do it here
if (attrConfigurators != null)
setAttributes(attrConfigurators);
def.saveDefinition();
ConcurrentUtil.removeCurrent(BeanConfigurator.class);
/*
* refresh all beans
*/
Bean.clearCache();
//return null to let the session-navigation return to the last element.
return null;
}
public Object actionReset() {
defAccessor.set("isdefault", true);
def.deleteDefinition();
ConcurrentUtil.removeCurrent(BeanConfigurator.class);
/*
* refresh all beans
*/
Bean.clearCache();
return null;
}
@Override
public int hashCode() {
return def.hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof BeanConfigurator ? def.equals(((BeanConfigurator) obj).def) : false;
}
@Override
public String toString() {
return Util.toString(getClass(), def);
}
@de.tsl2.nano.bean.annotation.Action(name = "createRuleOrAction", argNames = { "newActionName", "actionType",
"actionExpression" })
public void actionCreateRuleOrAction(String newActionName,
@de.tsl2.nano.bean.annotation.Constraint(defaultValue = "%: RuleScript (--> JavaScript)", allowed = {
"§: Rule (--> Operation)", "%: RuleScript (--> JavaScript)", "!: Action (--> Java)"
, "?: Query (--> SQL statement)", "@: Web (--> URL/REST)" }) String actionType,
/*@de.tsl2.nano.bean.annotation.Constraint(pattern = ".*") */String actionExpression) {
if (actionType.startsWith("%"))
ENV.get(Pool.class).add(new RuleScript<>(newActionName, actionExpression, null));
else if (actionType.startsWith("§"))
ENV.get(Pool.class).add(new Rule(newActionName, actionExpression, null));
else if (actionType.startsWith("!"))
ENV.get(Pool.class).add(new Action(newActionName, actionExpression));
else if (actionType.startsWith("@"))
ENV.get(Pool.class).add(WebClient.create(actionExpression, def.getDeclaringClass()));
else if (actionType.startsWith("?"))
ENV.get(Pool.class).add(new Query(newActionName, actionExpression, true, null));
}
@de.tsl2.nano.bean.annotation.Action(name = "addAction", argNames = { "specifiedAction" })
public void actionAddAction(
@de.tsl2.nano.bean.annotation.Constraint(allowed=ConstraintValueSet.ALLOWED_ENVFILES + ".*specification/action.*") String specifiedAction) {
//check, if action available
specifiedAction = StringUtil.substring(FileUtil.replaceToJavaSeparator(specifiedAction), "/", ".", true);
ENV.get(Pool.class).get(specifiedAction, Action.class);
SpecifiedAction