/**
* 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);
}
}