/** * Copyright 2010 Marko Lavikainen * * 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 net.contextfw.web.application.internal.component; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import net.contextfw.web.application.WebApplicationException; import net.contextfw.web.application.component.Component; import net.contextfw.web.application.component.DOMBuilder; import net.contextfw.web.application.component.ScriptContext; import net.contextfw.web.application.internal.util.AttributeHandler; import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class ComponentBuilderImpl implements ComponentBuilder, ScriptContext { private static final Map<Class<?>, MetaComponent> metaModels = new HashMap<Class<?>, MetaComponent>(); private static final Map<Class<?>, Class<?>> actualClasses = new WeakHashMap<Class<?>, Class<?>>(); private final AttributeHandler attributeHandler; private final Gson gson; @Inject public ComponentBuilderImpl(AttributeHandler attributeHandler, Gson gson) { this.attributeHandler = attributeHandler; this.gson = gson; } @Override public MetaComponent getMetaComponent(final Class<?> cl) { Class<?> actual = actualClasses.get(cl); if (actual == null) { actual = getActualClass(cl); actualClasses.put(cl, actual); } MetaComponent model = metaModels.get(actual); if (model == null) { model = new MetaComponent(actual, this, gson, this); metaModels.put(actual, model); } return model; } public void clean() { metaModels.clear(); actualClasses.clear(); } public static Class<?> getActualClass(Object element) { return getActualClass(element.getClass()); } public static Class<?> getActualClass(Class<?> cl) { Class<?> actual = actualClasses.get(cl); if (actual != null) { return actual; } else { actual = cl; while (actual.getSimpleName().contains("EnhancerByGuice")) { actual = actual.getSuperclass(); } actualClasses.put(cl, actual); return actual; } } @Override public String getBuildName(Class<?> cl) { MetaComponent model = getMetaComponent(cl); if (model.annotation != null) { return model.buildName; } else { throw new WebApplicationException(cl, "Class is not buildable", null); } } @Override public void build(DOMBuilder sb, Object component, Object... buildins) { MetaComponent model = getMetaComponent(component.getClass()); if (model.annotation != null) { if (component instanceof Component && !((Component) component).isEnabled()) { return; } DOMBuilder b = model.buildName == null ? sb : sb .descend(model.buildName); build(model, b, component, model.builders, false, null, buildins); } else { sb.text(attributeHandler.serialize(component)); } } private void build(MetaComponent model, DOMBuilder b, Object component, List<Builder> builders, boolean partial, Set<String> updates, Object... buildins) { model.applyBeforeBuilds(component); if (partial) { for (Builder builder : builders) { if (builder.isUpdateBuildable(updates)) { builder.build(b, component); } } } else { for (Builder builder : builders) { builder.build(b, component); } } // Handling buildins if (buildins != null) { for (Object buildIn : buildins) { if (buildIn != null) { MetaComponent bmodel = getMetaComponent(buildIn.getClass()); if (bmodel.annotation != null) { for (Builder builder : bmodel.builders) { builder.build(b, buildIn); } } } } } model.applyAfterBuilds(component); } @Override public void buildUpdate(DOMBuilder sb, Component component, String updateName) { MetaComponent model = getMetaComponent(component.getClass()); if (model.annotation != null) { DOMBuilder b = sb.descend(model.buildName + "." + updateName); build(model, b, component, model.updateBuilders, false, null, (Object[]) null); } } @Override public void buildPartialUpdate(DOMBuilder sb, Component component, String updateName, Set<String> updates) { MetaComponent model = getMetaComponent(component.getClass()); if (model.annotation != null) { DOMBuilder b = sb.descend(model.buildName + "." + updateName); build(model, b, component, model.partialBuilders, true, updates, (Object[]) null); } } @Override public boolean isBuildable(Class<?> cl) { return getMetaComponent(cl).annotation != null; } }