/** * 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 wicket.contrib.groovy.builder; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import wicket.MarkupContainer; import wicket.contrib.groovy.builder.impl.wicket.DefaultComponentBuilderFactoryConfigurationProvider; /** * Factory of factories. Finds the proper implementation of WicketComponentBuilder for the given * 'name'. * * To find builders, it first looks at the local package. If there's a match, it uses that. Otherwise, it'll * recurse through the packages provided. It'll then attempt to match the found class type with a builder * and return it. * * To customize the implementation, call addConfiguration(WicketGroovyConfigurationProvider provider). * * TODO: We need some caching for the found builders. The code is there, but there was some other trouble, * so for now I've disabled it. * * @author Kevin Galligan * */ public class WicketComponentBuilderFactory { static Map nameHelperMapping = new HashMap(); static List searchPackageList = new ArrayList(); static Map localPackageNameHelperMappingMap = new HashMap(); protected static WicketComponentBuilder checkLocalPackage(String name, MarkupContainer context) { Map localPackageNameHelperMapping = (Map) localPackageNameHelperMappingMap.get(context.getClass().getPackage().getName()); if(localPackageNameHelperMapping != null && localPackageNameHelperMapping.get(name)!= null) return (WicketComponentBuilder) localPackageNameHelperMapping.get(name); return null; } protected static void putLocalPackage(String name, MarkupContainer context, WicketComponentBuilder builder) { String packageName = context.getClass().getPackage().getName(); Map localPackageNameHelperMapping = (Map) localPackageNameHelperMappingMap.get(packageName); if(localPackageNameHelperMapping == null) { localPackageNameHelperMapping = new HashMap(); localPackageNameHelperMappingMap.put(packageName, localPackageNameHelperMapping); } localPackageNameHelperMapping.put(name, builder); } protected static Class checkPackageForComponent(String packageName, String name) throws ClassNotFoundException { String className = packageName + "." + StringUtils.capitalize(name); return Class.forName(className); } public static WicketComponentBuilder generateComponentBuilder(String name, MarkupContainer context)throws Exception { WicketComponentBuilder localBuilderClass = checkLocalPackage(name, context); if(localBuilderClass != null) return localBuilderClass; if(nameHelperMapping.get(name)!= null) return (WicketComponentBuilder) nameHelperMapping.get(name); Class componentClass = null; boolean localPackage = false; try{ componentClass = checkPackageForComponent(context.getClass().getPackage().getName(), name); } catch (ClassNotFoundException e) {} if(componentClass != null) localPackage = true; else { //TODO: Also need a more robust configuration tree. Based on different levels: //Global > Applicaiton > package > Page //Right now, a local class in the page would override a global on if it were found //first. Again, this was mostly written in a day, so you get what you pay for for(int i=0; i<searchPackageList.size(); i++) { try { componentClass = checkPackageForComponent((String)searchPackageList.get(i), name); if(componentClass != null) break; } catch (ClassNotFoundException e) {} } if(componentClass == null) return null; // throw new UnsupportedOperationException("Can't find type '"+ name +"'"); } Method localBuilder = null; try { localBuilder = componentClass.getMethod("localBuilder", new Class[0]); } catch(Exception e) {} if(localBuilder != null) { return (WicketComponentBuilder) localBuilder.invoke(null, new Object[0]); } Class wicketNodeHelperClass = (Class)helperTree.getBest(componentClass); WicketComponentBuilder helper = (WicketComponentBuilder) wicketNodeHelperClass.getConstructors()[0].newInstance(new Object[]{componentClass}); // if(localPackage) // { // putLocalPackage(name, context, helper); // } // else // { // nameHelperMapping.put(name, helper); // } return helper; } static ClassHierarchyTree helperTree = new ClassHierarchyTree(); static List configurationProviders = new ArrayList(); static Map componentAccentMap = new HashMap(); public static Object getComponentAccentForName(String name) { return componentAccentMap.get(name); } static { addConfiguration(new DefaultComponentBuilderFactoryConfigurationProvider()); } public static void addConfiguration(WicketGroovyConfigurationProvider provider) { configurationProviders.add(provider); provider.getConfiguration().augmentHelperClassHierarchy(helperTree); provider.getConfiguration().addComponentAccentDefinitions(componentAccentMap); String[] packageList = provider.getConfiguration().componentPackageSearchList(); if(packageList != null) Collections.addAll(searchPackageList, packageList); } }