/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Neil C Smith. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 3 for more details. * * You should have received a copy of the GNU General Public License version 3 * along with this work; if not, see http://www.gnu.org/licenses/ * * * Please visit http://neilcsmith.net if you need additional information or * have any questions. */ package net.neilcsmith.praxis.live.components; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import net.neilcsmith.praxis.core.Component; import net.neilcsmith.praxis.core.ComponentFactory; import net.neilcsmith.praxis.core.ComponentFactoryProvider; import net.neilcsmith.praxis.core.ComponentInstantiationException; import net.neilcsmith.praxis.core.ComponentType; import net.neilcsmith.praxis.core.Root; import net.neilcsmith.praxis.live.components.api.MetaDataRewriter; import net.neilcsmith.praxis.live.core.CoreFactoryProvider; import org.openide.util.Lookup; import org.openide.util.lookup.ServiceProvider; /** * * @author Neil C Smith (http://neilcsmith.net) */ public class ComponentRegistry implements ComponentFactory { private final static Logger LOG = Logger.getLogger(ComponentRegistry.class.getName()); private final static ComponentRegistry INSTANCE = new ComponentRegistry(); private Map<ComponentType, ExtMetaData<? extends Component>> componentCache; private Map<ComponentType, ExtMetaData<? extends Root>> rootCache; private ComponentRegistry() { initData(); } private void initData() { componentCache = new LinkedHashMap<ComponentType, ExtMetaData<? extends Component>>(); rootCache = new LinkedHashMap<ComponentType, ExtMetaData<? extends Root>>(); Collection<? extends MetaDataRewriter> rewriters = Lookup.getDefault().lookupAll(MetaDataRewriter.class); for (ComponentFactoryProvider provider : findFactoryProviders()) { ComponentFactory factory = provider.getFactory(); LOG.log(Level.INFO, "Adding components from : {0}", factory.getClass()); for (ComponentType type : factory.getComponentTypes()) { MetaData<? extends Component> data = factory.getMetaData(type); if (data == null) { LOG.log(Level.WARNING, "MetaData null for {0}", type); continue; } for (MetaDataRewriter rewriter : rewriters) { MetaData<? extends Component> d = rewriter.rewrite(type, data); data = d == null ? data : d; } componentCache.put(type, getExtMetaData(data, factory)); } for (ComponentType type : factory.getRootComponentTypes()) { MetaData<? extends Root> data = factory.getRootMetaData(type); if (data == null) { LOG.log(Level.WARNING, "MetaData null for {0}", type); continue; } for (MetaDataRewriter rewriter : rewriters) { MetaData<? extends Root> d = rewriter.rewrite(type, data); data = d == null ? data : d; } rootCache.put(type, getExtMetaData(data, factory)); } } } private <T> ExtMetaData<T> getExtMetaData(MetaData<T> data, ComponentFactory factory) { return new ExtMetaData<T>(data, factory); } private List<? extends ComponentFactoryProvider> findFactoryProviders() { Collection<? extends ComponentFactoryProvider> lkp = Lookup.getDefault().lookupAll(ComponentFactoryProvider.class); List<ComponentFactoryProvider> providers = new ArrayList<ComponentFactoryProvider>(lkp); Collections.reverse(providers); return providers; } @Override public ComponentType[] getComponentTypes() { Set<ComponentType> keys = componentCache.keySet(); return keys.toArray(new ComponentType[keys.size()]); } @Override public ComponentType[] getRootComponentTypes() { Set<ComponentType> keys = rootCache.keySet(); return keys.toArray(new ComponentType[keys.size()]); } @Override public MetaData<? extends Component> getMetaData(ComponentType type) { return componentCache.get(type); // if (factory != null) { // return factory.getMetaData(type); // } else { // throw new IllegalArgumentException(); // } } @Override public MetaData<? extends Root> getRootMetaData(ComponentType type) { return rootCache.get(type); } @Override public Component createComponent(ComponentType type) throws ComponentInstantiationException { ExtMetaData<? extends Component> data = componentCache.get(type); if (data != null) { return data.getFactory().createComponent(type); } else { throw new IllegalArgumentException(); } } @Override public Root createRootComponent(ComponentType type) throws ComponentInstantiationException { ExtMetaData<? extends Root> data = rootCache.get(type); if (data != null) { return data.getFactory().createRootComponent(type); } else { throw new IllegalArgumentException(); } } public static ComponentRegistry getDefault() { return INSTANCE; } private static class ExtMetaData<T> extends MetaData<T> { private final MetaData<T> delegate; private final ComponentFactory factory; private ExtMetaData(MetaData<T> delegate, ComponentFactory factory) { this.delegate = delegate; this.factory = factory; } @Override public boolean isTest() { return delegate.isTest(); } @Override public boolean isDeprecated() { return delegate.isDeprecated(); } @Override public ComponentType getReplacement() { return delegate.getReplacement(); } @Override public net.neilcsmith.praxis.core.Lookup getLookup() { return delegate.getLookup(); } @Override public Class<T> getComponentClass() { return delegate.getComponentClass(); } private ComponentFactory getFactory() { return factory; } } @ServiceProvider(service = CoreFactoryProvider.class) public static class Provider implements CoreFactoryProvider { @Override public ComponentFactory getFactory() { return getDefault(); } } }