package com.google.sitebricks.rendering.control; import com.google.common.collect.MapMaker; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Singleton; import com.google.sitebricks.Evaluator; import com.google.sitebricks.Renderable; import com.google.sitebricks.compiler.EvaluatorCompiler; import com.google.sitebricks.compiler.ExpressionCompileException; import com.google.sitebricks.compiler.Parsing; import com.google.sitebricks.compiler.RepeatToken; import com.google.sitebricks.routing.PageBook; import net.jcip.annotations.ThreadSafe; import java.util.Map; import java.util.concurrent.ConcurrentMap; /** * @author Dhanji R. Prasanna (dhanji@gmail.com) */ @ThreadSafe @Singleton class DefaultWidgetRegistry implements WidgetRegistry { public static final String TEXT_WIDGET = "__w:wRawText_Widget"; private final Injector injector; private final Evaluator evaluator; private final PageBook pageBook; private final ConcurrentMap<String, WidgetWrapper> widgets = new MapMaker().makeMap(); @Inject public DefaultWidgetRegistry(Evaluator evaluator, PageBook pageBook, Injector injector) { this.evaluator = evaluator; this.pageBook = pageBook; this.injector = injector; //register core sitebricks controllers. addCoreControllers(); } private void addCoreControllers() { //TODO make these case sensitive add("textfield", TextFieldWidget.class); add("repeat", RepeatWidget.class); add("showif", ShowIfWidget.class); add("choose", ChooseWidget.class); add("include", IncludeWidget.class); add("decorated", DecorateWidget.class); add("errors", ErrorsWidget.class); } public void add(String key, Class<? extends Renderable> widget) { widgets.put(key.toLowerCase().trim(), WidgetWrapper.forWidget(key, widget)); } public boolean isSelfRendering(String widget) { WidgetWrapper wrapper = widgets.get(widget); if (null == wrapper) { throw new NoSuchWidgetException( "No widget found matching the name: @" + widget + " ; Did you forget to bind your" + " widget class using the embed().as() rule?"); } return wrapper.isSelfRendering(); } public RepeatToken parseRepeat(String expression) { //parse and convert widget into metadata annotation final Map<String, String> bindMap = Parsing.toBindMap(expression); //noinspection OverlyComplexAnonymousInnerClass return new RepeatToken() { public String items() { return bindMap.get(RepeatToken.ITEMS); } public String var() { final String var = bindMap.get(RepeatToken.VAR); return null != var ? Parsing.stripQuotes(var) : null; } public String pageVar() { final String pageVar = bindMap.get(RepeatToken.PAGE_VAR); return null == pageVar ? RepeatToken.DEFAULT_PAGEVAR : pageVar; } }; } public Renderable headWidget(WidgetChain childsChildren, Map<String, String> attribs, EvaluatorCompiler compiler) throws ExpressionCompileException { return new HeaderWidget(childsChildren, attribs, compiler); } public XmlWidget xmlWidget(WidgetChain childsChildren, String elementName, Map<String, String> attribs, EvaluatorCompiler compiler) throws ExpressionCompileException { final XmlWidget widget = new XmlWidget(childsChildren, elementName, compiler, attribs); injector.injectMembers(widget); return widget; } public Renderable newWidget(String key, String expression, WidgetChain widgetChain, EvaluatorCompiler compiler) throws ExpressionCompileException { if (!widgets.containsKey(key)) { throw new NoSuchWidgetException("No such widget registered (did you add" + " it correctly in module setup?): " + key); } if (TEXT_WIDGET.equals(key)) return new TextWidget(null, compiler); //otherwise construct via reflection (all sitebricks MUST have // a constructor with: widgetchain, expression, evaluator; in that order) final Renderable widget = widgets .get(key) .newWidget(widgetChain, expression, evaluator, pageBook); //add some injection (some sitebricks require it). It's a bit hacky, maybe we can reimplement some stuff later with @AssistedInject injector.injectMembers(widget); return widget; } public Renderable requireWidget(XmlWidget xmlWidget) throws ExpressionCompileException { return new RequireWidget(xmlWidget); } public Renderable textWidget(String template, EvaluatorCompiler compiler) throws ExpressionCompileException { return new TextWidget(template, compiler); } public Renderable rawTextWidget(String template, EvaluatorCompiler compiler) throws ExpressionCompileException { return new RawTextWidget(template, compiler); } @Override public Renderable xmlDirectiveWidget(String wholeDeclaration, EvaluatorCompiler evaluatorCompiler) throws ExpressionCompileException { return new XmlDirectiveWidget(wholeDeclaration, evaluatorCompiler); } public void addEmbed(String embedAs) { add(embedAs, EmbedWidget.class); } public void addArgument(String callWith) { add(callWith, ArgumentWidget.class); } }