package org.orienteer.core.widget; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.apache.wicket.WicketRuntimeException; import org.apache.wicket.model.IModel; import org.apache.wicket.util.string.Strings; import org.orienteer.core.OrienteerWebApplication; import ru.ydn.wicket.wicketorientdb.model.ODocumentModel; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Sets; import com.google.common.reflect.ClassPath; import com.google.common.reflect.ClassPath.ClassInfo; import com.google.inject.Singleton; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.record.impl.ODocument; /** * Default implementation of {@link IWidgetTypesRegistry} */ @Singleton public class DefaultWidgetTypesRegistry implements IWidgetTypesRegistry { private static class AnnotatedWidgetType<T> implements IWidgetType<T> { private Class<? extends AbstractWidget<T>> widgetClass; private Widget widget; private AnnotatedWidgetType(Class<? extends AbstractWidget<T>> widgetClass, Widget widget) { this.widgetClass = widgetClass; this.widget = widget; } public static <T> IWidgetType<T> create(Class<? extends AbstractWidget<T>> widgetClass) { Widget ann = widgetClass.getAnnotation(Widget.class); return ann!=null?new AnnotatedWidgetType<T>(widgetClass, ann):null; } @Override public String getId() { return widget.id(); } @Override public String getOClassName() { return widget.oClass(); } @Override public String getDomain() { return widget.domain(); } @Override public String getTab() { return widget.tab(); } @Override public int getOrder() { return widget.order(); } @Override public boolean isAutoEnable() { return widget.autoEnable(); } @Override public String getSelector() { return widget.selector(); } @Override public Class<? extends AbstractWidget<T>> getWidgetClass() { return widgetClass; } @Override public AbstractWidget<T> instanciate(String componentId, IModel<T> model, ODocument widgetDoc) { try { return getWidgetClass() .getConstructor(String.class, IModel.class, IModel.class) .newInstance(componentId, model, new ODocumentModel(widgetDoc)); } catch (Exception e) { throw new WicketRuntimeException("Can't instanciate widget for descriptor: "+this , e); } } @Override public String toString() { return widget.toString(); } } private SortedSet<IWidgetType<?>> widgetDescriptions = Collections.synchronizedSortedSet(new TreeSet<IWidgetType<?>>(new Comparator<IWidgetType<?>>() { @Override public int compare(IWidgetType<?> o1, IWidgetType<?> o2) { int ret = Integer.compare(o1.getOrder(), o2.getOrder()); if(ret==0) ret=o1.getId().compareTo(o2.getId()); return ret; } })); @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public <T> List<IWidgetType<?>> listWidgetTypes(Predicate<IWidgetType<T>> filter) { Collection<IWidgetType<?>> ret = widgetDescriptions; if(filter!=null) ret = Collections2.filter(ret, (Predicate)filter); return Collections.unmodifiableList(new ArrayList<IWidgetType<?>>(ret)); } @Override public IWidgetType<?> lookupByTypeId(String id) { if(id==null) return null; for(IWidgetType<?> description : widgetDescriptions) { if(id.equals(description.getId())) return description; } return null; } @SuppressWarnings("unchecked") @Override public <T> List<IWidgetType<T>> lookupByDomain(String domain, Predicate<IWidgetType<T>> filter) { List<IWidgetType<T>> ret = new ArrayList<IWidgetType<T>>(); for(IWidgetType<?> description : widgetDescriptions) { if(domain.equals(description.getDomain()) && (filter==null || filter.apply((IWidgetType<T>)description))) ret.add((IWidgetType<T>)description); } return Collections.unmodifiableList(ret); } @SuppressWarnings("unchecked") @Override public <T> List<IWidgetType<T>> lookupByDomainAndTab( String domain, String tab, Predicate<IWidgetType<T>> filter) { List<IWidgetType<T>> ret = new ArrayList<IWidgetType<T>>(); for(IWidgetType<?> description : widgetDescriptions) { String defaultDomain = description.getDomain(); String defaultTab = description.getTab(); if(domain.equals(defaultDomain) && (Strings.isEmpty(defaultTab) || tab.equals(defaultTab)) && (filter==null || filter.apply((IWidgetType<T>)description))) ret.add((IWidgetType<T>)description); } return Collections.unmodifiableList(ret); } @SuppressWarnings("unchecked") @Override public IWidgetType<?> lookupByWidgetClass( Class<? extends AbstractWidget<?>> widgetClass) { if(widgetClass==null) return null; for(IWidgetType<?> description : widgetDescriptions) { if(widgetClass.equals(description.getWidgetClass())) return description; } return null; } @Override public IWidgetTypesRegistry register(IWidgetType<?> description) { widgetDescriptions.add(description); return this; } @Override public <T> IWidgetTypesRegistry register(final Class<? extends AbstractWidget<T>> widgetClass) { IWidgetType<T> widgetType = AnnotatedWidgetType.create(widgetClass); if(widgetType==null) throw new WicketRuntimeException("There is no a @Widget annotation on "+widgetClass.getName()); return register(widgetType); } @Override public IWidgetTypesRegistry register(String packageName) { ClassPath classPath; try { classPath = ClassPath.from(DefaultWidgetTypesRegistry.class.getClassLoader()); } catch (IOException e) { throw new WicketRuntimeException("Can't scan classpath", e); } for(ClassInfo classInfo : classPath.getTopLevelClassesRecursive(packageName)) { Class<?> clazz = classInfo.load(); Widget widgetDescription = clazz.getAnnotation(Widget.class); if(widgetDescription!=null) { if(!AbstractWidget.class.isAssignableFrom(clazz)) throw new WicketRuntimeException("@"+Widget.class.getSimpleName()+" should be only on widgets"); Class<? extends AbstractWidget<Object>> widgetClass = (Class<? extends AbstractWidget<Object>>) clazz; register(widgetClass); } } return this; } @Override public IWidgetTypesRegistry unregister(IWidgetType<?> description) { widgetDescriptions.remove(description); return this; } @Override public <T> IWidgetTypesRegistry unregister(Class<? extends AbstractWidget<T>> widgetClass) { unregister(lookupByWidgetClass(widgetClass)); return this; } @Override public IWidgetTypesRegistry unregister(String packageName) { Iterator<IWidgetType<?>> it = widgetDescriptions.iterator(); while(it.hasNext()) { if(it.next().getWidgetClass().getName().startsWith(packageName)) it.remove(); } return this; } }