Mercurial Hosting > nabble
view src/nabble/modules/ModuleManager.java @ 62:4674ed7d56df default tip
remove n2
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sat, 30 Sep 2023 20:25:29 -0600 |
parents | e0c501fb5229 |
children |
line wrap: on
line source
package nabble.modules; import fschmidt.util.java.CollectionUtils; import fschmidt.util.java.IoUtils; import nabble.model.Site; import nabble.modules.hacks.HacksModule; import nabble.modules.poll.PollModule; import nabble.modules.workgroup.WorkgroupModule; import nabble.naml.compiler.CompileException; import nabble.naml.compiler.Macro; import nabble.naml.compiler.Module; import nabble.naml.compiler.Program; import nabble.naml.compiler.Source; import nabble.naml.compiler.StackTrace; import nabble.naml.compiler.StackTraceElement; import nabble.naml.compiler.Template; import nabble.naml.compiler.TemplatePrintWriter; import nabble.naml.compiler.TemplateRuntimeException; import nabble.naml.dom.Attribute; import nabble.naml.dom.Element; import nabble.naml.dom.ElementName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletException; import java.io.IOException; import java.io.Writer; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; public final class ModuleManager { private static final Logger logger = LoggerFactory.getLogger(ModuleManager.class); private static final Map<String,ModuleInfo> MODULES = new LinkedHashMap<String,ModuleInfo>(); private static class ModuleInfo { final Module module; final boolean isEnabledByDefault; ModuleInfo(Module module,boolean isEnabledByDefault) { this.module = module; this.isEnabledByDefault = isEnabledByDefault; MODULES.put( module.getName(), this ); } } static { new ModuleInfo(WorkgroupModule.INSTANCE,false); new ModuleInfo(PollModule.INSTANCE,true); new ModuleInfo(HacksModule.INSTANCE,false); } private static final String CUSTOM_TWEAK_PREFIX = "custom_tweak:"; public static final String CONFIGURATION_TWEAK = "configuration"; private static List<Module> getBaseModules() { List<Module> modules = new ArrayList<Module>(); modules.add(SOURCE_MODULE); return modules; } public static List<Module> getGenericModules() { List<Module> modules = getBaseModules(); for( ModuleInfo mi : MODULES.values() ) { if( mi.isEnabledByDefault ) modules.add( mi.module ); } modules = sort(modules); return modules; } public static List<Module> getModules(Site site) { List<Module> modules = getBaseModules(); for( ModuleInfo mi : MODULES.values() ) { if( site.isModuleEnabled(mi.module.getName()) ) { modules.add( mi.module ); } } modules = sort(modules); if( site.getTweakException() == null ) { String config = site.getConfigurationTweak(); if( config.length() > 0 ) { Source source = Source.getInstance(CONFIGURATION_TWEAK,config); Module module = new NamlModule( "config", Collections.singleton(source), Collections.<String>emptySet() ); modules.add(module); } Map<String,String> tweaks = site.getCustomTweaks(); if( !tweaks.isEmpty() ) { List<Source> sources = new ArrayList<Source>(); for( Map.Entry<String,String> entry : tweaks.entrySet() ) { String name = entry.getKey(); String content = entry.getValue(); Source source = Source.getInstance(CUSTOM_TWEAK_PREFIX+name,content); sources.add(source); } Module module = new NamlModule( "tweak", sources, Collections.<String>emptySet() ); modules.add(module); } } return modules; } private static List<Module> sort(List<Module> modules) { List<Module> rtn = new ArrayList<Module>(); Set<String> names = new HashSet<String>(); while( !modules.isEmpty() ) { boolean changed = false; for( Iterator<Module> iter = modules.iterator(); iter.hasNext(); ) { Module m = iter.next(); if( names.containsAll(m.getDependencies()) ) { rtn.add(m); names.add(m.getName()); iter.remove(); changed = true; } } if( !changed ) throw new RuntimeException("circular dependencies: "+modules); } return rtn; } public static Collection<Source> loadSource(Module module) { String moduleName = module.getName(); try { return Collections.singleton( Source.getInstance( moduleName + ":" + moduleName + ".naml", IoUtils.read( ClassLoader.getSystemResource( module.getClass().getPackage().getName().replace('.','/') + '/' + moduleName+".naml" ) ) ) ); } catch(IOException e) { throw new RuntimeException(e); } } private static List<URL> listNamlFiles(String path) { List<URL> list = new ArrayList<URL>(); for( URL url : IoUtils.getResources(ModuleManager.class) ) { String s = url.toString(); if( s.endsWith(".naml") && s.indexOf(path) != -1 ) list.add(url); } return list; } private static final ElementName DEPENDENCY = new ElementName("dependency"); private static final Set<ElementName> IGNORE_TAGS = Collections.singleton(DEPENDENCY); private static final Set<String> DEFAULT_ON = new HashSet<String>(); static { DEFAULT_ON.add("responsive"); } static { try { for( URL url : listNamlFiles("/nabble/modules/naml/") ) { String s = url.toString(); String name = s.substring(s.lastIndexOf('/')+1); name = name.substring(0,name.length()-5); Source source = Source.getInstance( name + ":" + name + ".naml", IoUtils.read(url), IGNORE_TAGS ); Set<String> dependencies = new HashSet<String>(); StackTrace stackTrace = new StackTrace(); for( Object obj : source.parse() ) { if( obj instanceof Element ) { Element element = (Element)obj; if( element.name().equals(DEPENDENCY) ) { stackTrace.push( new StackTraceElement(source,element) ); try { Attribute attr = element.getAttribute("module"); if( attr == null ) throw new CompileException(stackTrace,"module attribute required"); String dependency = attr.value().toString(); dependencies.add(dependency); } finally { stackTrace.pop(); } } } } Module module = new NamlModule( name, Collections.singleton(source), CollectionUtils.optimizeSet(dependencies) ); new ModuleInfo(module,DEFAULT_ON.contains(name)); } } catch(IOException e) { throw new RuntimeException(e); } catch(CompileException e) { throw new RuntimeException(e); } } public static Module getModule(String moduleName) { return MODULES.get(moduleName).module; } public static boolean isEnabledByDefault(String moduleName) { ModuleInfo info = MODULES.get(moduleName); return info != null && info.isEnabledByDefault; } // from TemplateManager private static final Module SOURCE_MODULE; static { List<Source> sources = new ArrayList<Source>(); try { for( URL url : listNamlFiles("/nabble/view/naml/") ) { String s = url.toString(); String name = s.substring(s.lastIndexOf('/')+1); String content = IoUtils.read(url); sources.add( Source.getInstance("nabble:"+name,content) ); } } catch(IOException e) { throw new RuntimeException(e); } SOURCE_MODULE = new NamlModule( "nabble", sources, Collections.<String>emptySet() ); logger.info("SOURCES has " + sources.size() + " macros"); } public static boolean isConfigurationTweak(Source source) { return source.id.equals(CONFIGURATION_TWEAK); } public static boolean isCustomTweak(Source source) { return source.id.startsWith(CUSTOM_TWEAK_PREFIX); } public static List<Macro> getConfigurationMacros(Program program) throws CompileException { List<Macro> macros = new ArrayList<Macro>(); for( Source source : program.getSources() ) { if( isConfigurationTweak(source) ) { macros.addAll(source.getMacros()); } } return macros; } public static List<Macro> getCustomMacros(Program program) throws CompileException { List<Macro> macros = new ArrayList<Macro>(); for( Source source : program.getSources() ) { if( isCustomTweak(source) ) { macros.addAll(source.getMacros()); } } return macros; } public static void run(Template template,Writer out,Map<String,Object> args,Object... base) throws IOException, ServletException { try { template.run( new TemplatePrintWriter(out), args, base ); } catch(TemplateRuntimeException e) { Throwable cause = e.getCause(); if( cause instanceof IOException ) throw (IOException)cause; if( cause instanceof ServletException ) throw new ServletException(cause.getMessage(),e); throw e; } } public static void nop() {} private ModuleManager() {} // never }