From 4933290f594fe8ecdbec348865668c0dc32810eb Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Mon, 16 Dec 2024 10:48:16 +0100 Subject: [PATCH 01/17] #342 remove deprecations #352 use newly extracted module-framework --- cms-api/pom.xml | 2 +- .../HookSystemRegisterExtentionPoint.java | 40 -- .../TemplateEngineProviderExtentionPoint.java | 40 -- .../TemplateModelExtendingExtentionPoint.java | 51 --- .../features/ServerPropertiesFeature.java | 1 - .../features/SitePropertiesFeature.java | 1 - cms-auth/pom.xml | 2 +- .../cms/content/DefaultContentRenderer.java | 11 - cms-server/pom.xml | 2 +- .../cms/request/RequestContextFactory.java | 34 +- .../cms/server/configs/ModulesModule.java | 8 - modules-framework/api/pom.xml | 18 - .../condation/modules/api/BaseExtension.java | 64 --- .../com/condation/modules/api/Context.java | 33 -- .../condation/modules/api/ExtensionPoint.java | 42 -- .../modules/api/ManagerConfiguration.java | 142 ------ .../com/condation/modules/api/Module.java | 58 --- .../modules/api/ModuleConfiguration.java | 125 ------ .../modules/api/ModuleDescription.java | 65 --- .../modules/api/ModuleLifeCycleExtension.java | 42 -- .../condation/modules/api/ModuleManager.java | 87 ---- .../modules/api/ModuleRequestContext.java | 33 -- .../api/ModuleRequestContextFactory.java | 33 -- .../modules/api/annotation/Extension.java | 39 -- .../ExtensionAnnotationProcessor.java | 153 ------- .../javax.annotation.processing.Processor | 1 - modules-framework/manager/pom.xml | 28 -- .../modules/manager/Configuration.java | 146 ------- .../modules/manager/ModuleAPIClassLoader.java | 171 -------- .../modules/manager/ModuleComparator.java | 40 -- .../condation/modules/manager/ModuleImpl.java | 284 ------------ .../modules/manager/ModuleInjector.java | 37 -- .../modules/manager/ModuleLoader.java | 148 ------- .../modules/manager/ModuleManagerImpl.java | 411 ------------------ .../modules/manager/ModuleServiceLoader.java | 112 ----- .../manager/ModuledFirstURLClassLoader.java | 130 ------ modules-framework/pom.xml | 17 - modules/example-module/pom.xml | 2 +- modules/pom.xml | 2 +- pom.xml | 14 +- 40 files changed, 27 insertions(+), 2642 deletions(-) delete mode 100644 cms-api/src/main/java/com/condation/cms/api/extensions/HookSystemRegisterExtentionPoint.java delete mode 100644 cms-api/src/main/java/com/condation/cms/api/extensions/TemplateEngineProviderExtentionPoint.java delete mode 100644 cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtentionPoint.java delete mode 100644 modules-framework/api/pom.xml delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/BaseExtension.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/Context.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ExtensionPoint.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ManagerConfiguration.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/Module.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleConfiguration.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleDescription.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleLifeCycleExtension.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleManager.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContext.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContextFactory.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/annotation/Extension.java delete mode 100644 modules-framework/api/src/main/java/com/condation/modules/api/annotation/ExtensionAnnotationProcessor.java delete mode 100644 modules-framework/api/src/main/resources/META-INF/services/javax.annotation.processing.Processor delete mode 100644 modules-framework/manager/pom.xml delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/Configuration.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleAPIClassLoader.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleComparator.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleImpl.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleInjector.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleLoader.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleManagerImpl.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleServiceLoader.java delete mode 100644 modules-framework/manager/src/main/java/com/condation/modules/manager/ModuledFirstURLClassLoader.java delete mode 100644 modules-framework/pom.xml diff --git a/cms-api/pom.xml b/cms-api/pom.xml index 296fd3a7f..8f4e00591 100644 --- a/cms-api/pom.xml +++ b/cms-api/pom.xml @@ -16,7 +16,7 @@ provided - com.condation.cms.module.framework + com.condation.modules.framework modules-api diff --git a/cms-api/src/main/java/com/condation/cms/api/extensions/HookSystemRegisterExtentionPoint.java b/cms-api/src/main/java/com/condation/cms/api/extensions/HookSystemRegisterExtentionPoint.java deleted file mode 100644 index 540fbbd7f..000000000 --- a/cms-api/src/main/java/com/condation/cms/api/extensions/HookSystemRegisterExtentionPoint.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.condation.cms.api.extensions; - -/*- - * #%L - * cms-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import com.condation.cms.api.hooks.HookSystem; - -/** - * ExtensionPoint for modules to register hooks. - * - * @deprecated As of release 7.2.0, replaced by {@link HookSystemRegisterExtensionPoint} - * - * @author thmar - */ -@Deprecated(since = "7.2.0", forRemoval = true) -public abstract class HookSystemRegisterExtentionPoint extends AbstractExtensionPoint{ - - public abstract void register (final HookSystem hookSystem); - -} diff --git a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateEngineProviderExtentionPoint.java b/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateEngineProviderExtentionPoint.java deleted file mode 100644 index f3c1b1fe6..000000000 --- a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateEngineProviderExtentionPoint.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.condation.cms.api.extensions; - -/*- - * #%L - * cms-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import com.condation.cms.api.template.TemplateEngine; - -/** - * - * @deprecated As of release 7.2.0, replaced by {@link TemplateEngineProviderExtensionPoint} - * - * @author t.marx - */ -@Deprecated(since = "7.2.0", forRemoval = true) -public abstract class TemplateEngineProviderExtentionPoint extends AbstractExtensionPoint { - - public abstract String getName (); - public abstract TemplateEngine getTemplateEngine (); - -} diff --git a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtentionPoint.java b/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtentionPoint.java deleted file mode 100644 index 499e458a7..000000000 --- a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtentionPoint.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.condation.cms.api.extensions; - -import java.util.Map; - -import com.condation.cms.api.Constants; - -/*- - * #%L - * cms-api - * %% - * Copyright (C) 2023 Marx-Software - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.condation.cms.api.template.TemplateEngine; - -/** - * - * @deprecated As of release 7.2.0, replaced by {@link TemplateModelExtendingExtensionPoint} - * - * @author thmar - */ -@Deprecated(since = "7.2.0", forRemoval = true) -public abstract class TemplateModelExtendingExtentionPoint extends AbstractExtensionPoint{ - - public abstract void extendModel (TemplateEngine.Model model); - - public Map getModel () { - TemplateEngine.Model model = new TemplateEngine.Model(null, null); - extendModel(model); - return model.values; - } - - public String getNamespace () { - return Constants.DEFAULT_MODULE_NAMESPACE; - } -} diff --git a/cms-api/src/main/java/com/condation/cms/api/feature/features/ServerPropertiesFeature.java b/cms-api/src/main/java/com/condation/cms/api/feature/features/ServerPropertiesFeature.java index d69b18c96..04884ad3d 100644 --- a/cms-api/src/main/java/com/condation/cms/api/feature/features/ServerPropertiesFeature.java +++ b/cms-api/src/main/java/com/condation/cms/api/feature/features/ServerPropertiesFeature.java @@ -33,7 +33,6 @@ * * @author t.marx */ -@Deprecated(since = "6.5.0") @FeatureScope({FeatureScope.Scope.GLOBAL, FeatureScope.Scope.MODULE, FeatureScope.Scope.REQUEST}) public record ServerPropertiesFeature(ServerProperties serverProperties) implements Feature { diff --git a/cms-api/src/main/java/com/condation/cms/api/feature/features/SitePropertiesFeature.java b/cms-api/src/main/java/com/condation/cms/api/feature/features/SitePropertiesFeature.java index c1a6f94d4..f6ad14aa0 100644 --- a/cms-api/src/main/java/com/condation/cms/api/feature/features/SitePropertiesFeature.java +++ b/cms-api/src/main/java/com/condation/cms/api/feature/features/SitePropertiesFeature.java @@ -33,7 +33,6 @@ * * @author t.marx */ -@Deprecated(since = "6.5.0") @FeatureScope({FeatureScope.Scope.GLOBAL, FeatureScope.Scope.MODULE, FeatureScope.Scope.REQUEST}) public record SitePropertiesFeature(SiteProperties siteProperties) implements Feature { diff --git a/cms-auth/pom.xml b/cms-auth/pom.xml index ab64b75b4..d269335d9 100644 --- a/cms-auth/pom.xml +++ b/cms-auth/pom.xml @@ -19,7 +19,7 @@ cms-filesystem - com.condation.cms.module.framework + com.condation.modules.framework modules-api provided diff --git a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java index 2f83379d5..8312d0eb2 100644 --- a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java +++ b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java @@ -31,7 +31,6 @@ import com.condation.cms.api.db.taxonomy.Taxonomy; import com.condation.cms.api.extensions.ContentQueryOperatorExtensionPoint; import com.condation.cms.api.extensions.TemplateModelExtendingExtensionPoint; -import com.condation.cms.api.extensions.TemplateModelExtendingExtentionPoint; import com.condation.cms.api.feature.features.AuthFeature; import com.condation.cms.api.feature.features.HookSystemFeature; import com.condation.cms.api.feature.features.InjectorFeature; @@ -252,16 +251,6 @@ private boolean isDevMode(final RequestContext context) { } private void extendModel(final TemplateEngine.Model model, Namespace namespace) { - moduleManager.extensions(TemplateModelExtendingExtentionPoint.class).forEach(extensionPoint -> { - var modModel = extensionPoint.getModel(); - // deprecated: module extensions on root will be remove in 8.0.0 - model.values.putAll(modModel); - modModel.entrySet().forEach(entry -> namespace.add( - extensionPoint.getNamespace(), - entry.getKey(), - entry.getValue() - )); - }); moduleManager.extensions(TemplateModelExtendingExtensionPoint.class).forEach(extensionPoint -> { var modModel = extensionPoint.getModel(); // deprecated: module extensions on root will be remove in 8.0.0 diff --git a/cms-server/pom.xml b/cms-server/pom.xml index 917a5f998..0c4608397 100644 --- a/cms-server/pom.xml +++ b/cms-server/pom.xml @@ -108,7 +108,7 @@ - com.condation.cms.module.framework + com.condation.modules.framework modules-manager diff --git a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java index 473283ad9..c8fdc93f4 100644 --- a/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java +++ b/cms-server/src/main/java/com/condation/cms/request/RequestContextFactory.java @@ -28,7 +28,6 @@ import com.condation.cms.api.configuration.configs.SiteConfiguration; import com.condation.cms.api.content.ContentParser; import com.condation.cms.api.extensions.HookSystemRegisterExtensionPoint; -import com.condation.cms.api.extensions.HookSystemRegisterExtentionPoint; import com.condation.cms.api.extensions.RegisterShortCodesExtensionPoint; import com.condation.cms.api.feature.features.ConfigurationFeature; import com.condation.cms.api.feature.features.ContentNodeMapperFeature; @@ -150,10 +149,22 @@ public void initContext (RequestContext requestContext, Request request) throws requestContext.add(RequestExtensions.class, requestExtensions); } - private HookSystem initHookSystem(RequestContext requestContext) { + private void initHookSystem(RequestContext requestContext) { var hookSystem = requestContext.get(HookSystemFeature.class).hookSystem(); var moduleManager = injector.getInstance(ModuleManager.class); - moduleManager.extensions(HookSystemRegisterExtentionPoint.class).forEach(extensionPoint -> extensionPoint.register(hookSystem)); + moduleManager.extensions(HookSystemRegisterExtensionPoint.class).forEach(extensionPoint -> extensionPoint.register(hookSystem)); + } + + /** + * Has to run as one of the last steps, because we need the requestContext + * to be filled + * + * @param requestContext + * @return + */ + private HookSystem setupAndGetHookSystem() { + var hookSystem = injector.getInstance(HookSystem.class); + var moduleManager = injector.getInstance(ModuleManager.class); moduleManager.extensions(HookSystemRegisterExtensionPoint.class).forEach(extensionPoint -> extensionPoint.register(hookSystem)); return hookSystem; @@ -202,7 +213,7 @@ public RequestContext create() throws IOException { requestContext.add(DBHooks.class, new DBHooks(requestContext)); requestContext.add(ContentHooks.class, new ContentHooks(requestContext)); - requestContext.add(HookSystemFeature.class, new HookSystemFeature(setupHookSystem())); + requestContext.add(HookSystemFeature.class, new HookSystemFeature(setupAndGetHookSystem())); RequestExtensions requestExtensions = extensionManager.newContext(theme, requestContext); @@ -243,21 +254,6 @@ public RequestContext create( return requestContext; } - /** - * Has to run as one of the last steps, because we need the requestContext - * to be filled - * - * @param requestContext - * @return - */ - private HookSystem setupHookSystem() { - var hookSystem = injector.getInstance(HookSystem.class); - var moduleManager = injector.getInstance(ModuleManager.class); - moduleManager.extensions(HookSystemRegisterExtentionPoint.class).forEach(extensionPoint -> extensionPoint.register(hookSystem)); - - return hookSystem; - } - private ShortCodes createShortCodes(RequestContext requestContext) { Map> codes = new HashMap<>(); diff --git a/cms-server/src/main/java/com/condation/cms/server/configs/ModulesModule.java b/cms-server/src/main/java/com/condation/cms/server/configs/ModulesModule.java index 5e2cf1110..4b0a4d776 100644 --- a/cms-server/src/main/java/com/condation/cms/server/configs/ModulesModule.java +++ b/cms-server/src/main/java/com/condation/cms/server/configs/ModulesModule.java @@ -24,7 +24,6 @@ import com.condation.cms.api.SiteProperties; import com.condation.cms.api.extensions.MarkdownRendererProviderExtensionPoint; import com.condation.cms.api.extensions.TemplateEngineProviderExtensionPoint; -import com.condation.cms.api.extensions.TemplateEngineProviderExtentionPoint; import com.condation.cms.api.feature.features.ModuleManagerFeature; import com.condation.cms.api.hooks.HookSystem; import com.condation.cms.api.markdown.MarkdownRenderer; @@ -170,13 +169,6 @@ public TemplateEngine resolveTemplateEngine(SiteProperties siteProperties, Theme if (extOpt.isPresent()) { return extOpt.get().getTemplateEngine(); } - - List extensionsLegacy = moduleManager.extensions(TemplateEngineProviderExtentionPoint.class); - Optional extLegacyOpt = extensionsLegacy.stream().filter((ext) -> ext.getName().equals(engine)).findFirst(); - - if (extLegacyOpt.isPresent()) { - return extLegacyOpt.get().getTemplateEngine(); - } throw new RuntimeException("no template engine found"); } diff --git a/modules-framework/api/pom.xml b/modules-framework/api/pom.xml deleted file mode 100644 index 4f8446453..000000000 --- a/modules-framework/api/pom.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - 4.0.0 - - com.condation.cms.module.framework - module-framework - 7.4.2 - - modules-api - jar - - - - com.google.code.gson - gson - - - \ No newline at end of file diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/BaseExtension.java b/modules-framework/api/src/main/java/com/condation/modules/api/BaseExtension.java deleted file mode 100644 index 1ae856b6c..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/BaseExtension.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -/** - * - * @author marx - * @param - */ -public abstract class BaseExtension implements ExtensionPoint { - - protected ModuleConfiguration configuration; - - private C context; - - private R requestContext; - - @Override - public void setContext(C context) { - this.context = context; - } - - public C getContext () { - return this.context; - } - - @Override - public void setRequestContext(R context) { - this.requestContext = requestContext; - } - - public R getRequestContext () { - return this.requestContext; - } - - @Override - public void setConfiguration(ModuleConfiguration configuration) { - this.configuration = configuration; - } - - -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/Context.java b/modules-framework/api/src/main/java/com/condation/modules/api/Context.java deleted file mode 100644 index e1e323792..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/Context.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -/** - * The Context is passed to the module. It can be used to inject implementation dependend objects or functionality - * - * @author marx - */ -public interface Context { -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ExtensionPoint.java b/modules-framework/api/src/main/java/com/condation/modules/api/ExtensionPoint.java deleted file mode 100644 index 92a7eee1f..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ExtensionPoint.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - - - -/** - * - * @author marx - * @param - */ -public interface ExtensionPoint { - void setConfiguration (ModuleConfiguration configuration); - - void setContext (C context); - - void setRequestContext (R context); - - void init (); -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ManagerConfiguration.java b/modules-framework/api/src/main/java/com/condation/modules/api/ManagerConfiguration.java deleted file mode 100644 index 9b0748d3b..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ManagerConfiguration.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * - * @author thmarx - */ -public class ManagerConfiguration { - - private ConcurrentMap modules = new ConcurrentHashMap<>(); - - public ManagerConfiguration () { - - } - - public ConcurrentMap getModules() { - return modules; - } - - public void setModules(ConcurrentMap modules) { - this.modules = modules; - } - - public ModuleConfig get (final String moduleId) { - return modules.get(moduleId); - } - public void add (final ModuleConfig config) { - modules.put(config.getId(), config); - } - public void remove (final String moduleId) { - modules.remove(moduleId); - } - - public static class ModuleConfig { - - private boolean active = false; - - private String id; - - private String moduleDir; - - private String moduleDataDir; - - public ModuleConfig () { - - } - public ModuleConfig (final String id) { - this.id = id; - } - - public void setId (final String id) { - this.id = id; - } - - public String getId () { - return id; - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } - - public String getModuleDir() { - return moduleDir; - } - - public ModuleConfig setModuleDir(String moduleDir) { - this.moduleDir = moduleDir; - return this; - } - - public String getModuleDataDir() { - return moduleDataDir; - } - - public ModuleConfig setModuleDataDir(String moduleDataDir) { - this.moduleDataDir = moduleDataDir; - - return this; - } - - - - @Override - public int hashCode() { - int hash = 3; - hash = 37 * hash + Objects.hashCode(this.id); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ModuleConfig other = (ModuleConfig) obj; - if (!Objects.equals(this.id, other.id)) { - return false; - } - return true; - } - - - } -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/Module.java b/modules-framework/api/src/main/java/com/condation/modules/api/Module.java deleted file mode 100644 index b26ce43e2..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/Module.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import java.util.List; - -/** - * - * @author marx - */ -public interface Module { - - public enum Priority { - NORMAL, - // System modules must be loaded before default modules - HIGH, - HIGHER, - HIGHEST; - } - - Priority getPriority (); - - List extensions(Class extensionClass); - - String getAuthor(); - - String getDescription(); - - String getId(); - - String getName(); - - String getVersion(); - - boolean provides(Class extensionClass); - -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleConfiguration.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleConfiguration.java deleted file mode 100644 index 9bede7137..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleConfiguration.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Properties; - -/** - * - * @author thmarx - */ -public class ModuleConfiguration { - - private final Properties properties = new Properties(); - - final File configFile; - - final File dataDirectory; - - public ModuleConfiguration (final File path) throws IOException{ - configFile = new File(path, "configuration.properties"); - if (!configFile.exists()) { - configFile.createNewFile(); - } - properties.load(new FileReader(configFile)); - - this.dataDirectory = new File(path.toURI()); - } - - public File getDataDir () { - return dataDirectory; - } - - - /** - * Stores the module configuration in the data directory for this module. - * - * @throws IOException - */ - public void store () throws IOException { - properties.store(new FileWriter(configFile), "module configuraion saved"); - } - /** - * Returns a configuration property value. - * - * @param key The key of the property. - * @param defaultValue The default value to return. - * @return The value for the key or the default value. - */ - public Object get (final String key, final Object defaultValue) { - return properties.getOrDefault(key, defaultValue); - } - /** - * Returns a configuration property value as int. - * - * @param key The key of the property. - * @param defaultValue The default value to return. - * @return The value for the key or the default value. - */ - public int getInt (final String key, final int defaultValue) { - Object value = properties.get(key); - if (value != null) { - if (value instanceof Integer) { - return (int) value; - } else { - return Integer.parseInt(((String)value).trim()); - } - } - return defaultValue; - } - /** - * Returns a configuration property value as String. - * - * @param key The key of the property. - * @param defaultValue The default value to return. - * @return The value for the key or the default value. - */ - public String getString (final String key, final String defaultValue) { - Object value = properties.get(key); - if (value != null) { - if (value instanceof String) { - return (String) value; - } else { - return String.valueOf(value); - } - } - return defaultValue; - } - - /** - * Sets a configuration property. - * - * @param key The property key. - * @param value The property value. - */ - public void set (final String key, final Object value) { - properties.put(key, value); - } -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleDescription.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleDescription.java deleted file mode 100644 index 603076674..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleDescription.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -/** - * - * @author marx - */ -public class ModuleDescription { - private String name; - private String description; - private String version; - - public ModuleDescription () { - - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleLifeCycleExtension.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleLifeCycleExtension.java deleted file mode 100644 index 86be03b42..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleLifeCycleExtension.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - - - -/** - * - * @author marx - */ -public abstract class ModuleLifeCycleExtension extends BaseExtension { - /** - * Called when the module is activated. - */ - public void activate () {}; - /** - * called when the module is deactivated. - */ - public void deactivate () {}; -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleManager.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleManager.java deleted file mode 100644 index e559536c9..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleManager.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - - -import java.io.IOException; -import java.util.List; - -/** - * - * @author marx - */ -public interface ModuleManager extends AutoCloseable { - - /** - * activates a module. - * - * @param moduleId - * @return returns true if the module is correctly or allready installed, otherwise false - * @throws java.io.IOException - */ - boolean activateModule(final String moduleId) throws IOException; - - /** - * - * @param moduleId - * @return - */ - boolean deactivateModule(final String moduleId) throws IOException; - - void initModules(); - - /** - * Returns the module description. - * @param id - * @return - * @throws IOException - */ - ModuleDescription description(final String id) throws IOException; - - /** - * Returns all Extensions of the given type. - * - * @param - * @param extensionClass - * @return - */ - List extensions(Class extensionClass); - - public Module module(final String id); - - /** - * Returns the configuration of the module manager. - * - * @return - */ - public ManagerConfiguration configuration(); - - /** - * Returns a list of all available module ids. - * - * @return - */ - public List getModuleIds (); -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContext.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContext.java deleted file mode 100644 index 35db574a9..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContext.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -/** - * The Context is passed to the module. It can be used to inject implementation dependend objects or functionality - * - * @author marx - */ -public interface ModuleRequestContext { -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContextFactory.java b/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContextFactory.java deleted file mode 100644 index 0323f9b0e..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/ModuleRequestContextFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.condation.modules.api; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -/** - * - * @author t.marx - */ -public interface ModuleRequestContextFactory { - - ModuleRequestContext createContext (); -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/annotation/Extension.java b/modules-framework/api/src/main/java/com/condation/modules/api/annotation/Extension.java deleted file mode 100644 index 62bab21b4..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/annotation/Extension.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.condation.modules.api.annotation; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -import com.condation.modules.api.ExtensionPoint; -import java.lang.annotation.Documented; -import static java.lang.annotation.ElementType.TYPE; -import java.lang.annotation.Retention; -import static java.lang.annotation.RetentionPolicy.SOURCE; -import java.lang.annotation.Target; - -@Documented -@Retention(SOURCE) -@Target(TYPE) -public @interface Extension { - Class value(); -} diff --git a/modules-framework/api/src/main/java/com/condation/modules/api/annotation/ExtensionAnnotationProcessor.java b/modules-framework/api/src/main/java/com/condation/modules/api/annotation/ExtensionAnnotationProcessor.java deleted file mode 100644 index 3f0ae2a41..000000000 --- a/modules-framework/api/src/main/java/com/condation/modules/api/annotation/ExtensionAnnotationProcessor.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.condation.modules.api.annotation; - -/*- - * #%L - * modules-api - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.nio.file.NoSuchFileException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Filer; -import javax.annotation.processing.Processor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.MirroredTypesException; -import javax.lang.model.util.Elements; -import javax.tools.Diagnostic.Kind; -import javax.tools.FileObject; -import javax.tools.StandardLocation; - -@SupportedAnnotationTypes("com.condation.modules.api.annotation.Extension") -public class ExtensionAnnotationProcessor extends AbstractProcessor implements Processor { - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latest(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (roundEnv.processingOver()) { - return false; - } - Map> extensions = new HashMap<>(); - - Elements elements = processingEnv.getElementUtils(); - - roundEnv.getElementsAnnotatedWith(Extension.class).stream().forEach((e) -> { - Extension a = e.getAnnotation(Extension.class); - if (!(a == null)) { - if (!(!e.getKind().isClass() && !e.getKind().isInterface())) { - TypeElement typedElement = (TypeElement) e; - Collection teCollection = getTypeElements(typedElement, a); - teCollection.forEach((te) -> { - String extensionName = elements.getBinaryName(te).toString(); - String extensionImplName = elements.getBinaryName(typedElement).toString(); - if (!extensions.containsKey(extensionName)) { - extensions.put(extensionName, new TreeSet<>()); - } - extensions.get(extensionName).add(extensionImplName); - }); - } - } - }); - - // load existing extensions - final Filer filer = processingEnv.getFiler(); - extensions.entrySet().stream().forEach((e) -> { - try { - String contract = e.getKey(); - FileObject extensionFileObject = filer.getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" + contract); - BufferedReader r = new BufferedReader(new InputStreamReader(extensionFileObject.openInputStream(), "UTF-8")); - String line; - while ((line = r.readLine()) != null) { - e.getValue().add(line); - } - r.close(); - } catch (FileNotFoundException fnfe) { - // file not found - } catch (IOException x) { - //x.printStackTrace(); - if (NoSuchFileException.class.isInstance(x)) { - // file not found - } else { - //processingEnv.getMessager().printMessage(Kind.ERROR, "Error loading existing extension files: " + x); - } - } - }); - - // now write them back out - extensions.entrySet().stream().forEach((e) -> { - try { - String extension = e.getKey(); - processingEnv.getMessager().printMessage(Kind.NOTE, "Creating META-INF/services/" + extension); - FileObject f = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/services/" + extension); - PrintWriter pw = new PrintWriter(new OutputStreamWriter(f.openOutputStream(), "UTF-8")); - for (String value : e.getValue()) { - pw.println(value); - } - pw.close(); - } catch (IOException x) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Error creating extension file: " + x); - } - }); - - return false; - } - - private Collection getTypeElements(TypeElement type, Extension a) { - List typeElements = new ArrayList<>(); - - try { - a.value(); - } catch (MirroredTypesException e) { - - e.getTypeMirrors().stream().forEach((m) -> { - if (m instanceof DeclaredType) { - DeclaredType dt = (DeclaredType) m; - typeElements.add((TypeElement) dt.asElement()); - } else { - processingEnv.getMessager().printMessage(Kind.ERROR, "Invalid type specified", type); - } - }); - } - return typeElements; - } - -} diff --git a/modules-framework/api/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/modules-framework/api/src/main/resources/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index 8be52f338..000000000 --- a/modules-framework/api/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1 +0,0 @@ -com.condation.modules.api.annotation.ExtensionAnnotationProcessor diff --git a/modules-framework/manager/pom.xml b/modules-framework/manager/pom.xml deleted file mode 100644 index 04be151e2..000000000 --- a/modules-framework/manager/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - 4.0.0 - - com.condation.cms.module.framework - module-framework - 7.4.2 - - modules-manager - jar - - - - com.condation.cms.module.framework - modules-api - - - org.slf4j - slf4j-api - - - org.projectlombok - lombok - provided - - - - \ No newline at end of file diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/Configuration.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/Configuration.java deleted file mode 100644 index 5e0baecd4..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/Configuration.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.util.EnumMap; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author thmarx - */ -public class Configuration { - - public enum Field { - DB_DIR ("db.dir"); - - private final String value; - - Field (final String value) { - this.value = value; - } - - public String value () { - return value; - } - } - - public enum Stage { - - Production("production"), - Development("development"), - Test("test"); - - private final String value; - private Stage (final String value) { - this.value = value; - } - - public static Stage forStage (final String stage) { - for (final Stage s : values()) { - if (s.value.equals(stage)) { - return s; - } - } - throw new IllegalArgumentException("unknown stage: " + stage); - } - } - - private static final EnumMap configurations = new EnumMap<>(Stage.class); - - private final Properties properties = new Properties(); - - private Configuration (){} - - public synchronized static Configuration empty () { - return new Configuration(); - } - - public synchronized static Configuration getInstance(final File baseDir) { - Configuration instance = new Configuration(); - - try { - instance.properties.load(new FileReader(new File(baseDir, "conf/configuration.properties"))); - } catch (FileNotFoundException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - - return instance; - } - - public synchronized static Configuration getInstance(final Stage stage) { - if (!configurations.containsKey(stage)) { - Configuration INSTANCE = new Configuration(); - // loading resource using getResourceAsStream() method - InputStream in = Configuration.class.getResourceAsStream("/configuration_" + stage.value + ".properties"); - try { - INSTANCE.properties.load(in); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); - } - configurations.put(stage, INSTANCE); - } - return configurations.get(stage); - } - - public Object get (final String key, final Object defaultValue) { - return properties.getOrDefault(key, defaultValue); - } - public int getInt (final String key, final int defaultValue) { - Object value = properties.get(key); - if (value != null) { - if (value instanceof Integer) { - return (int) value; - } else { - return Integer.parseInt(((String)value).trim()); - } - } - return defaultValue; - } - - public String getString (final String key, final String defaultValue) { - Object value = properties.get(key); - if (value != null) { - if (value instanceof String) { - return (String) value; - } else { - return String.valueOf(value); - } - } - return defaultValue; - } - - public void set (final String key, final Object value) { - properties.put(key, value); - } -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleAPIClassLoader.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleAPIClassLoader.java deleted file mode 100644 index 1fe454acd..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleAPIClassLoader.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; - -/** - * - * @author marx - */ -public class ModuleAPIClassLoader extends ClassLoader { - - private final List apiPackages; - - private final ClassLoader parent; - - public ModuleAPIClassLoader(ClassLoader classLoader, List apiPackages) { - super(classLoader); - - this.parent = classLoader; - List temp = apiPackages != null ? apiPackages : new ArrayList<>(); - this.apiPackages = temp.stream().map(c -> !c.endsWith(".") ? c + "." : c).collect(Collectors.toList()); - - this.apiPackages.add("com.condation.modules.api."); - this.apiPackages.add("java."); - this.apiPackages.add("javax."); - this.apiPackages.add("com.sun."); - this.apiPackages.add("sun."); - } - - private boolean isAllowed(final String name) { - for (String packageName : apiPackages) { - if (name.startsWith(packageName)) { - return true; - } - - String tempname = packageName.replaceAll("\\.", "/"); - if (name.startsWith("/")) { - tempname = "/" + tempname; - } - if (name.startsWith(tempname)) { - return true; - } - } - return false; - } - - @Override - protected Class loadClass(String className, boolean resolve) throws ClassNotFoundException { - if (isAllowed(className)) { - return getParent().loadClass(className); - } - - throw new ClassNotFoundException(className + "not visible"); - } - - @Override - public Class loadClass(String className) throws ClassNotFoundException { - if (isAllowed(className)) { - return getParent().loadClass(className); - } - - throw new ClassNotFoundException(className + "not visible"); - } - - @Override - protected Class findClass(String className) throws ClassNotFoundException { - if (isAllowed(className)) { - return getParent().loadClass(className); - } - - throw new ClassNotFoundException(className + "not visible"); - } - - @Override - public InputStream getResourceAsStream(String name) { - if (isAllowed(name)) { - return getParent().getResourceAsStream(name); - } - - return null; - } - - @Override - public Enumeration getResources(String name) throws IOException { - if (isAllowed(name)) { - return getParent().getResources(name); - } - - return new Enumeration() { - Iterator iter = Collections.EMPTY_LIST.iterator(); - - @Override - public boolean hasMoreElements() { - return iter.hasNext(); - } - - @Override - public URL nextElement() { - return iter.next(); - } - }; - } - - @Override - public URL getResource(String name) { - if (isAllowed(name)) { - return getParent().getResource(name); - } - return null; - } - - @Override - protected Enumeration findResources(String name) throws IOException { - if (isAllowed(name)) { - return parent.getResources(name); - } - - return new Enumeration() { - Iterator iter = Collections.EMPTY_LIST.iterator(); - - @Override - public boolean hasMoreElements() { - return iter.hasNext(); - } - - @Override - public URL nextElement() { - return iter.next(); - } - }; - } - - @Override - protected URL findResource(String name) { - if (isAllowed(name)) { - return parent.getResource(name); - } - return null; - } - -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleComparator.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleComparator.java deleted file mode 100644 index 56becb909..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleComparator.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -import java.util.Comparator; - -/** - * - * @author marx - */ -public class ModuleComparator implements Comparator { - - @Override - public int compare(ModuleImpl o1, ModuleImpl o2) { - return ((Integer) o1.getDependencies().size()).compareTo(o2.getDependencies().size()); - } - -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleImpl.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleImpl.java deleted file mode 100644 index 2674ca0bc..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleImpl.java +++ /dev/null @@ -1,284 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.condation.modules.api.Context; -import com.condation.modules.api.ExtensionPoint; -import com.condation.modules.api.Module; -import com.condation.modules.api.Module.Priority; -import com.condation.modules.api.ModuleConfiguration; -import com.condation.modules.api.ModuleRequestContextFactory; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * - * @author thmarx - */ -public class ModuleImpl implements Module { - - private String id; - private String version; - private String name; - private String description; - private String author; - private Priority priority = Priority.NORMAL; - private final List dependencyList = new ArrayList<>(); - private final ModuleRequestContextFactory requestContextFactory; - - File moduleDir; - - File modulesDataDir; - - URLClassLoader classloader; - - ModuleConfiguration configuration; - - private final Context context; - private final ModuleInjector injector; - - Map extensions = new HashMap<>(); - - private ModuleServiceLoader moduleServiceLoader; - - protected ModuleImpl(final File moduleDir, final File modulesDataDir, final Context context, - final ModuleInjector injector, final ModuleRequestContextFactory requestContextFactory) throws MalformedURLException, IOException { - this.moduleDir = moduleDir; - this.modulesDataDir = modulesDataDir; - this.context = context; - this.injector = injector; - this.requestContextFactory = requestContextFactory; - - Properties properties = new Properties(); - try (FileReader reader = new FileReader(new File(moduleDir, "module.properties"))) { - properties.load(reader); - this.id = properties.getProperty("id"); - this.name = properties.getProperty("name"); - this.version = properties.getProperty("version"); - this.description = properties.getProperty("description"); - this.author = properties.getProperty("author"); - String dependencies = properties.getProperty("dependencies"); - if (dependencies != null && !dependencies.equals("")) { - for (String dep : dependencies.split(";")) { - String[] dependency = dep.split("#"); - if (dependency != null && dependency.length == 2) { - dependencyList.add(new Dependency(dependency[0], dependency[1])); - } - } - } - String config_prio = properties.getProperty("priority", "NORMAL"); - this.priority = Priority.valueOf(config_prio); - } - } - - public void init(final ClassLoader parentClassLoader) throws MalformedURLException, IOException { - List urls = new ArrayList<>(); - - File[] libs = new File(moduleDir, "libs").listFiles((File dir, String name1) -> name1.endsWith(".jar")); - for (File lib : libs) { - urls.add(new URL("jar:" + lib.toURI().toURL() + "!/")); - lib = null; - } - - classloader = new ModuledFirstURLClassLoader(urls.toArray(new URL[libs.length]), parentClassLoader); - urls.clear(); - urls = null; - libs = null; - - File dataDir = new File(modulesDataDir, id); - if (!dataDir.exists()) { - dataDir.mkdirs(); - } - this.configuration = new ModuleConfiguration(dataDir); - - this.moduleServiceLoader = ModuleServiceLoader.create(classloader); - } - - @Override - public boolean provides(Class extensionClass) { - ServiceLoader serviceLoader = ServiceLoader.load(extensionClass, classloader); - return serviceLoader.iterator().hasNext(); - } - - @Override - public List extensions(Class extensionClass) { - - return moduleServiceLoader.get(extensionClass).stream() - .map(ext -> { - ext.setContext(context); - ext.setConfiguration(configuration); - - if (requestContextFactory != null) { - ext.setRequestContext(requestContextFactory.createContext()); - } - - if (injector != null) { - injector.inject(ext); - } - - ext.init(); - - return ext; - }).toList(); - } - - @Override - public Priority getPriority() { - return priority; - } - - @Override - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - - @Override - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - @Override - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - @Override - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public List getDependencies() { - return this.dependencyList; - } - - public File getModuleDir() { - return moduleDir; - } - - public File getModulesDataDir() { - return modulesDataDir; - } - - @Override - public int hashCode() { - int hash = 7; - hash = 61 * hash + Objects.hashCode(this.id); - return hash; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final ModuleImpl other = (ModuleImpl) obj; - if (!Objects.equals(this.id, other.id)) { - return false; - } - return true; - } - - public void close() throws IOException { - this.classloader.close(); - - // workaround: close all libs manually: see https://bugs.openjdk.java.net/browse/JDK-7183373 - for (URL u : this.classloader.getURLs()) { - if (u.getProtocol().equals("jar")) { - ((JarURLConnection) u.openConnection()).getJarFile().close(); - } - } - - this.classloader = null; - this.configuration = null; - this.dependencyList.clear(); - this.extensions.clear(); - this.extensions = null; - this.modulesDataDir = null; - this.moduleDir = null; - } - - public static class Dependency { - - private final String id; - private final String version; - - public Dependency(String id, String version) { - this.id = id; - this.version = version; - } - - public String id() { - return id; - } - - public String version() { - return version; - } - - } -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleInjector.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleInjector.java deleted file mode 100644 index 2689642d2..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleInjector.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import com.condation.modules.api.ExtensionPoint; - - - -/** - * - * @author marx - */ -public interface ModuleInjector { - - public void inject (final ExtensionPoint extension); -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleLoader.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleLoader.java deleted file mode 100644 index 76b87ce9a..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleLoader.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -import com.condation.modules.api.Context; -import com.condation.modules.api.ManagerConfiguration; -import com.condation.modules.api.ModuleLifeCycleExtension; -import com.condation.modules.api.ModuleRequestContextFactory; -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * - * @author marx - */ -public class ModuleLoader { - - private final ManagerConfiguration configuration; - - final Map activeModules = new ConcurrentHashMap<>(); - - final File modulesPath; - final File modulesDataPath; - - final ClassLoader globalClassLoader; - - final Context context; - final ModuleInjector injector; - - final ModuleRequestContextFactory requestContextFactory; - - protected ModuleLoader(final ManagerConfiguration configuration, final File modulesPath, final File modulesDataPath, - final ClassLoader globalClassLoader, final Context context, final ModuleInjector injector, - final ModuleRequestContextFactory requestContextFactory) { - this.configuration = configuration; - this.modulesPath = modulesPath; - this.modulesDataPath = modulesDataPath; - this.globalClassLoader = globalClassLoader; - this.context = context; - this.injector = injector; - this.requestContextFactory = requestContextFactory; - } - - protected Map activeModules() { - return activeModules; - } - - protected boolean deactivateModule(final String moduleId) throws IOException { - - ModuleImpl module = activeModules().get(moduleId); - module.extensions(ModuleLifeCycleExtension.class).stream().forEach((ModuleLifeCycleExtension mle) -> { - mle.setContext(context); - mle.deactivate(); - }); - - activeModules().get(moduleId).close(); - activeModules().remove(moduleId); - - return true; - } - - protected boolean activateModule(final String moduleId) throws IOException { - - File moduleDir = new File(modulesPath, configuration.get(moduleId).getModuleDir()); - File moduleData = modulesDataPath; -// File moduleData = activeModules().get(moduleId).getModulesDataDir(); - - ModuleImpl module = new ModuleImpl(moduleDir, moduleData, this.context, this.injector, this.requestContextFactory); - - if (areDependencyFulfilled(module)) { - ManagerConfiguration.ModuleConfig config = configuration.get(moduleId); - if (config == null) { - config = new ManagerConfiguration.ModuleConfig(moduleId); - } - - module.init(this.globalClassLoader); - - config.setActive(true); - module.extensions(ModuleLifeCycleExtension.class).stream().forEach((ModuleLifeCycleExtension mle) -> { - mle.setContext(context); - mle.activate(); - }); - configuration.add(config); - - activeModules().put(module.getId(), module); - return true; - } - return false; - } - - protected void tryToLoadModules(final List modules) { - // sort modules by dependency count low to max - Collections.sort(modules, new ModuleComparator()); - - int tryCount = 0; - int oldSize = modules.size(); - while (!modules.isEmpty()) { - if (tryCount > 2) { - break; - } - loadFulfilledModules(modules); - if (modules.size() == oldSize) { - tryCount++; - } else { - oldSize = modules.size(); - } - } - } - - private void loadFulfilledModules(final List modules) { - for (final ModuleImpl module : modules) { - if (areDependencyFulfilled(module) && configuration.get(module.getId()).isActive()) { - activeModules.put(module.getId(), module); - } - } - modules.removeAll(activeModules.values()); - } - - private boolean areDependencyFulfilled(final ModuleImpl module) { - return module.getDependencies().stream().noneMatch((dependency) -> (!activeModules.containsKey(dependency.id()))); - } -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleManagerImpl.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleManagerImpl.java deleted file mode 100644 index 968965764..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleManagerImpl.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ -import com.condation.modules.api.Context; -import com.condation.modules.api.ExtensionPoint; -import com.condation.modules.api.ManagerConfiguration; -import com.condation.modules.api.Module; -import com.condation.modules.api.ModuleDescription; -import com.condation.modules.api.ModuleLifeCycleExtension; -import com.condation.modules.api.ModuleManager; -import com.condation.modules.api.ModuleRequestContextFactory; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The ModuleManager loads all modules from a given directoy. - * - * @author thmarx - */ -public class ModuleManagerImpl implements ModuleManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(ModuleManagerImpl.class); - - public static class Builder { - - private File modulesPath = null; - private File modulesDataPath = null; - private Context context = null; - private ModuleAPIClassLoader classLoader = null; - private ModuleInjector injector = null; - private ModuleRequestContextFactory requestContextFactory = null; - - public Builder requestContextFactory(ModuleRequestContextFactory requestContextFactory) { - this.requestContextFactory = requestContextFactory; - return this; - } - - public ModuleManager build() { - return new ModuleManagerImpl(this); - } - - public Builder setModulesPath(File path) { - this.modulesPath = path; - return this; - } - - public Builder setModulesDataPath(File path) { - this.modulesDataPath = path; - return this; - } - - public Builder setContext(Context context) { - this.context = context; - return this; - } - - public Builder setClassLoader(ModuleAPIClassLoader classLoader) { - this.classLoader = classLoader; - return this; - } - - public Builder setInjector(ModuleInjector injector) { - this.injector = injector; - return this; - } - } - - public static Builder builder() { - return new Builder(); - } - - /** - * Creates a new ModuleManager instance. - * - * @param modulesPath Path where the modules are stored - * @param modulesDataPath Path, where the modules data is stored - * @param context the context - * @return A new ModuleManager. - */ - public static ModuleManager create(final File modulesPath, final File modulesDataPath, final Context context) { - return create(modulesPath, modulesDataPath, context, new ModuleAPIClassLoader(ModuleManagerImpl.class.getClassLoader(), Collections.EMPTY_LIST)); - } - - /** - * Creates a new ModuleManager instance. - * - * @param modulesPath the path where the installed modules are located. - * @param modulesDataPath the path where the modules data directory is - * located. - * @param context the context - * @param classLoader the classloader - * @return - */ - public static ModuleManager create(final File modulesPath, final File modulesDataPath, final Context context, final ModuleAPIClassLoader classLoader) { - return create(modulesPath, modulesDataPath, context, classLoader, null); - } - - /** - * Creates a new ModuleManager instance. - * - * @param modulesPath the path where the installed modules are located. - * @param modulesDataPath the path where the modules data directory is - * located. - * @param context the context - * @param injector Injector for dependency injection - * @return A new ModuleManager. - */ - public static ModuleManager create(final File modulesPath, final File modulesDataPath, final Context context, final ModuleInjector injector) { - return create(modulesPath, modulesDataPath, context, new ModuleAPIClassLoader(ModuleManagerImpl.class.getClassLoader(), Collections.EMPTY_LIST), injector); - } - - /** - * Creates a ne ModuleManager instance. - * - * @param modulesPath the path where the installed modules are located. - * @param modulesDataPath the path where the modules data directory is - * located. - * @param context the context - * @param classLoader the classloader - * @param injector Injector for dependency injection - * @return - */ - public static ModuleManager create(final File modulesPath, final File modulesDataPath, final Context context, final ModuleAPIClassLoader classLoader, final ModuleInjector injector) { - return builder().setClassLoader(classLoader) - .setModulesPath(modulesPath) - .setModulesDataPath(modulesDataPath) - .setContext(context).setInjector(injector).build(); - } - - final File modulesPath; - final File modulesDataPath; - - final ModuleLoader moduleLoader; - - final ModuleAPIClassLoader globalClassLoader; - - private ManagerConfiguration configuration; - - private final Context context; - - final ModuleInjector injector; - - final ModuleRequestContextFactory requestContextFactory; - - final ModuleServiceLoader systemExtensionLoader; - - public ModuleManagerImpl() { - this.modulesDataPath = null; - this.modulesPath = null; - this.globalClassLoader = null; - this.moduleLoader = null; - this.context = null; - this.injector = null; - this.requestContextFactory = null; - this.systemExtensionLoader = null; - } - - private ModuleManagerImpl(final Builder builder) { - this.modulesPath = builder.modulesPath; - this.modulesDataPath = builder.modulesDataPath; - this.context = builder.context; - this.injector = builder.injector; - this.requestContextFactory = builder.requestContextFactory; - - this.configuration = new ManagerConfiguration(); - this.globalClassLoader = builder.classLoader; - this.moduleLoader = new ModuleLoader(configuration, modulesPath, modulesDataPath, this.globalClassLoader, - this.context, this.injector, this.requestContextFactory); - - File[] moduleFiles = modulesPath.listFiles((File file) -> file.isDirectory()); - File moduleData = modulesDataPath; - - Set allUsedModuleIDs = new HashSet<>(); - - Map modules = new HashMap<>(); - if (moduleFiles != null) { - loadModules(moduleFiles, moduleData, allUsedModuleIDs, modules); - } - configuration.getModules().values().stream().filter((mc) -> (!allUsedModuleIDs.contains(mc.getId()))).forEach((mc) -> { - configuration.remove(mc.getId()); - }); - - systemExtensionLoader = ModuleServiceLoader.create(globalClassLoader.getParent()); - - } - - @Override - public void initModules() { - - File[] moduleFiles = modulesPath.listFiles((File file) -> file.isDirectory()); - File moduleData = modulesDataPath; - - Set allUsedModuleIDs = new HashSet<>(); - - Map modules = new HashMap<>(); - if (moduleFiles != null) { - loadModules(moduleFiles, moduleData, allUsedModuleIDs, modules); - } - - List moduleList = new ArrayList<>(modules.values()); - moduleLoader.tryToLoadModules(moduleList); - - configuration.getModules().values().forEach((mc) -> { - if (!moduleLoader.activeModules().containsKey(mc.getId())) { - configuration.get(mc.getId()).setActive(false); - } - }); - } - - private void loadModules(File[] moduleFiles, File moduleData, Set allUsedModuleIDs, Map modules) { - for (File module : moduleFiles) { - try { - ModuleImpl mod = new ModuleImpl(module, moduleData, this.context, this.injector, this.requestContextFactory - ); - allUsedModuleIDs.add(mod.getId()); - modules.put(mod.getId(), mod); - if (configuration.get(mod.getId()) == null) { - configuration.add(new ManagerConfiguration.ModuleConfig(mod.getId()).setModuleDir(module.getName())); - } - } catch (IOException ex) { - LOGGER.error("", ex); - // deactivate module - String modid = module.getName(); - allUsedModuleIDs.add(modid); - if (configuration.get(modid) != null) { - LOGGER.warn("deactivate module caused by an error"); - configuration.get(modid).setActive(false); - } - } - } - } - - @Override - public void close() { - extensions(ModuleLifeCycleExtension.class).stream().forEach((ModuleLifeCycleExtension mle) -> { - mle.setContext(context); - mle.deactivate(); - }); - } - - /** - * Returns a module by id. All the modules are loaded correctly so you can - * get extensions. - * - * @param id The id of the module. - * @return The module for the given id or null. - */ - @Override - public Module module(final String id) { - return moduleLoader.activeModules.get(id); - } - - @Override - public List getModuleIds() { - List modules = new ArrayList<>(configuration.getModules().values()); - - return modules.stream().map((mc) -> { - try { - File moduleDir = new File(modulesPath, configuration.get(mc.getId()).getModuleDir()); - File moduleData = modulesDataPath; - ModuleImpl module = new ModuleImpl(moduleDir, moduleData, this.context, this.injector, this.requestContextFactory); - return module; - } catch (IOException ex) { - throw new RuntimeException(ex); - } - }).sorted(new ModuleComparator()).map(Module::getId).collect(Collectors.toList()); - } - - /** - * Returns the module description. - * - * @param id - * @return - * @throws IOException - */ - @Override - public ModuleDescription description(final String id) throws IOException { - ModuleImpl module; - if (moduleLoader.activeModules.containsKey(id)) { - module = moduleLoader.activeModules.get(id); - } else { - ManagerConfiguration.ModuleConfig mc = configuration.get(id); - File moduleDir = new File(modulesPath, configuration.get(mc.getId()).getModuleDir()); - module = new ModuleImpl(moduleDir, null, this.context, this.injector, this.requestContextFactory); - } - - ModuleDescription description = new ModuleDescription(); - description.setVersion(module.getVersion()); - description.setName(module.getName()); - description.setDescription(module.getDescription()); - return description; - } - - /** - * activates a module. - * - * @param moduleId - * @return returns true if the module is correctly or allready installed, - * otherwise false - * @throws java.io.IOException - */ - @Override - public boolean activateModule(final String moduleId) throws IOException { - if (configuration.get(moduleId) == null || !configuration.get(moduleId).isActive()) { - return moduleLoader.activateModule(moduleId); - } else if (configuration.get(moduleId) != null && configuration.get(moduleId).isActive()) { - return true; - } - return false; - - } - - /** - * - * @param moduleId - * @return - */ - @Override - public boolean deactivateModule(final String moduleId) throws IOException { - if (configuration.get(moduleId) == null) { - return true; - } else if (configuration.get(moduleId) != null && !configuration.get(moduleId).isActive()) { - return true; - } - - moduleLoader.deactivateModule(moduleId); - - configuration.get(moduleId).setActive(false); - return true; - - } - - /** - * Returns all Extensions of the given type. - * - * @param - * @param extensionClass - * @return - */ - @Override - public List extensions(Class extensionClass) { - List extensions = new ArrayList<>(); - moduleLoader.activeModules().values().forEach((ModuleImpl m) -> { - var moduleExt = m.extensions(extensionClass); - if (!moduleExt.isEmpty()) { - extensions.addAll(moduleExt); - } - }); - // system modules - systemExtensionLoader.get(extensionClass) - .stream() - .map(ext -> { - ext.setContext(context); - - if (requestContextFactory != null) { - ext.setRequestContext(requestContextFactory.createContext()); - } - - if (injector != null) { - injector.inject(ext); - } - - ext.init(); - - return ext; - }) - .forEach(extensions::add); - - return extensions; - } - - /** - * Returns the configuration of the module manager. - * - * @return - */ - @Override - public ManagerConfiguration configuration() { - return configuration; - } -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleServiceLoader.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleServiceLoader.java deleted file mode 100644 index 49f9e3d93..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuleServiceLoader.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import lombok.extern.slf4j.Slf4j; - -/** - * - * @author t.marx - */ -@Slf4j -public final class ModuleServiceLoader { - - static final String PREFIX = "META-INF/services/"; - - private final ClassLoader loader; - - private final ConcurrentMap, List>> providers = new ConcurrentHashMap<>(); - - private ModuleServiceLoader(ClassLoader loader) { - this.loader = loader; - } - - public static ModuleServiceLoader create(ClassLoader loader) { - return new ModuleServiceLoader(loader); - } - - public List get(Class service) { - try { - return providers.computeIfAbsent(service, clazz -> { - return initService(clazz); - }).stream() - .map(this::newInstance) - .filter(Objects::nonNull) - .map(service::cast) - .toList(); - } catch (Exception ex) { - log.error("", ex); - } - return Collections.emptyList(); - } - - private S newInstance(Provider provider) { - try { - return provider.get(); - } catch (Exception ex) { - log.error("error createing instance", ex); - } - return null; - } - - private List> initService(Class service) { - - List> providerImpls = new ArrayList<>(); - try { - String fullName = PREFIX + service.getName(); - Enumeration resources = loader.getResources(fullName); - while (resources.hasMoreElements()) { - var url = resources.nextElement(); - try (var ins = url.openStream(); var reader = new BufferedReader(new InputStreamReader(ins))) { - - String line; - while ((line = reader.readLine()) != null) { - var serviceImplClass = (Class) Class.forName(line, false, loader); - providerImpls.add(new Provider<>(serviceImplClass)); - } - } - } - } catch (Exception e) { - log.error("", e); - } - - return providerImpls; - } - - private record Provider(Class type) { - - public S get() throws Exception { - return (S) type.getConstructors()[0].newInstance(); - } - } -} diff --git a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuledFirstURLClassLoader.java b/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuledFirstURLClassLoader.java deleted file mode 100644 index 402958488..000000000 --- a/modules-framework/manager/src/main/java/com/condation/modules/manager/ModuledFirstURLClassLoader.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.condation.modules.manager; - -/*- - * #%L - * modules-manager - * %% - * Copyright (C) 2023 - 2024 CondationCMS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; - -/** - * - * @author marx - */ -public class ModuledFirstURLClassLoader extends URLClassLoader { - - public ModuledFirstURLClassLoader(URL[] classpath, ClassLoader parent) { - super(classpath, parent); - } - - @Override - protected synchronized Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - // First, check if the class has already been loaded - Class c = findLoadedClass(name); - if (c == null) { - - if (c == null) { - try { - // checking local - c = findClass(name); - } catch (ClassNotFoundException e) { - // checking parent - // This call to loadClass may eventually call findClass again, in case the parent doesn't find anything. - c = super.loadClass(name, resolve); - } - } - } - if (resolve) { - resolveClass(c); - } - return c; - } - - @Override - public URL getResource(String name) { - URL url = null; - if (url == null) { - url = findResource(name); - if (url == null) { - // This call to getResource may eventually call findResource again, in case the parent doesn't find anything. - url = super.getResource(name); - } - } - return url; - } - - @Override - public Enumeration getResources(String name) throws IOException { - /** - * Similar to super, but local resources are enumerated before parent - * resources - */ - Enumeration localUrls = findResources(name); - Enumeration parentUrls = null; - if (getParent() != null) { - parentUrls = getParent().getResources(name); - } - final List urls = new ArrayList<>(); - if (localUrls != null) { - while (localUrls.hasMoreElements()) { - urls.add(localUrls.nextElement()); - } - } - if (parentUrls != null) { - while (parentUrls.hasMoreElements()) { - urls.add(parentUrls.nextElement()); - } - } - return new Enumeration() { - Iterator iter = urls.iterator(); - - @Override - public boolean hasMoreElements() { - return iter.hasNext(); - } - - @Override - public URL nextElement() { - return iter.next(); - } - }; - } - - @Override - public InputStream getResourceAsStream(String name) { - URL url = getResource(name); - try { - return url != null ? url.openStream() : null; - } catch (IOException e) { - } - return null; - } - -} diff --git a/modules-framework/pom.xml b/modules-framework/pom.xml deleted file mode 100644 index 87b294b4b..000000000 --- a/modules-framework/pom.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - - com.condation.cms - cms-parent - 7.4.2 - - com.condation.cms.module.framework - module-framework - pom - - - api - manager - - diff --git a/modules/example-module/pom.xml b/modules/example-module/pom.xml index 99133c151..ed2ef96eb 100644 --- a/modules/example-module/pom.xml +++ b/modules/example-module/pom.xml @@ -21,7 +21,7 @@ provided - com.condation.cms.module.framework + com.condation.modules.framework modules-api provided diff --git a/modules/pom.xml b/modules/pom.xml index 4ae1a2766..df0a38010 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -12,6 +12,6 @@ example-module - system-modules + system-modules diff --git a/pom.xml b/pom.xml index a3cdb152f..de0c71816 100644 --- a/pom.xml +++ b/pom.xml @@ -13,11 +13,11 @@ yyyy-MM-dd HH:mm 12.0.16 10.0.0 + 1.0.0 cms-api cms-server - modules-framework modules cms-filesystem cms-media @@ -113,14 +113,14 @@ ${project.version} - com.condation.cms.module.framework + com.condation.modules.framework modules-manager - ${project.version} + ${modules-framework.version} - com.condation.cms.module.framework + com.condation.modules.framework modules-api - ${project.version} + ${modules-framework.version} com.condation.cms.modules @@ -374,9 +374,9 @@ 1.1.1 - com.condation.cms.module.framework + com.condation.modules.framework modules-api - 6.4.0 + ${modules-framework.version} From 4e4e91aef1f766b4529dac660d1634517c95d3cc Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Tue, 17 Dec 2024 11:01:07 +0100 Subject: [PATCH 02/17] fix wrong check for filters --- .../com/condation/cms/templates/TemplateConfiguration.java | 2 +- .../com/condation/cms/templates/filter/FilterRegistry.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cms-templates/src/main/java/com/condation/cms/templates/TemplateConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/TemplateConfiguration.java index ea95edffc..4cfc08c21 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/TemplateConfiguration.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/TemplateConfiguration.java @@ -58,7 +58,7 @@ public boolean hasTags () { } public boolean hasFilters () { - return !registeredTags.isEmpty(); + return !filterRegistry.empty(); } public TemplateConfiguration setCache (ICache cache) { diff --git a/cms-templates/src/main/java/com/condation/cms/templates/filter/FilterRegistry.java b/cms-templates/src/main/java/com/condation/cms/templates/filter/FilterRegistry.java index 3e1392a46..3a415a33f 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/filter/FilterRegistry.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/filter/FilterRegistry.java @@ -28,6 +28,10 @@ public class FilterRegistry { private final Map filters = new HashMap<>(); + public boolean empty () { + return filters.isEmpty(); + } + public void register(String name, Filter filter) { filters.put(name, filter); } From c1055bb4f076f43f7755d5583eed9efb2fb9849a Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Tue, 17 Dec 2024 14:50:54 +0100 Subject: [PATCH 03/17] allow dynamicly adding of shortcodes as tags --- .../cms/content/shortcodes/ShortCodes.java | 5 + .../cms/content/shortcodes/TagMap.java | 6 + cms-templates/pom.xml | 4 + .../cms/templates/CMSTemplateEngine.java | 6 +- .../cms/templates/DefaultTemplate.java | 14 +- .../cms/templates/DynamicConfiguration.java | 59 +++++++ .../com/condation/cms/templates/Template.java | 2 + .../condation/cms/templates/lexer/Lexer.java | 2 +- .../cms/templates/parser/Parser.java | 23 ++- .../templates/parser/ParserConfiguration.java | 56 +++++++ .../renderer/RenderConfiguration.java | 56 +++++++ .../cms/templates/renderer/Renderer.java | 21 ++- .../condation/cms/templates/tags/ForTag.java | 1 - .../tags/shortcode/EndShortCodeTag.java | 49 ++++++ .../tags/shortcode/ShortCodeTag.java | 157 ++++++++++++++++++ .../TemplateEngineShortCodeTest.java | 91 ++++++++++ 16 files changed, 533 insertions(+), 19 deletions(-) create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java create mode 100644 cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java index 33470aed2..87469d342 100644 --- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java +++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/ShortCodes.java @@ -26,6 +26,7 @@ import com.condation.cms.api.model.Parameter; import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.function.Function; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -47,6 +48,10 @@ public ShortCodes (Map> codes, TagParser tag this.tagMap.putAll(codes); } + public Set getShortCodeNames () { + return tagMap.names(); + } + public String replace (final String content) { return replace(content, Collections.emptyMap()); } diff --git a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java index e503f067a..b8daff203 100644 --- a/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java +++ b/cms-content/src/main/java/com/condation/cms/content/shortcodes/TagMap.java @@ -23,8 +23,10 @@ */ import com.condation.cms.api.model.Parameter; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.function.Function; /** @@ -35,6 +37,10 @@ public class TagMap { private final Map> tags = new HashMap<>(); + public Set names () { + return Collections.unmodifiableSet(tags.keySet()); + } + public void put(String codeName, Function function) { tags.put(codeName, function); } diff --git a/cms-templates/pom.xml b/cms-templates/pom.xml index 1f1d34ebf..89d7be727 100644 --- a/cms-templates/pom.xml +++ b/cms-templates/pom.xml @@ -25,6 +25,10 @@ com.condation.cms cms-api + + com.condation.cms + cms-content + com.condation.cms cms-core diff --git a/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java b/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java index 67a074837..26317f272 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java @@ -88,6 +88,10 @@ public Template getTemplateFromString (String templateContent) { } public Template getTemplate (String template) { + return getTemplate(template, null); + } + + public Template getTemplate (String template, DynamicConfiguration dynamicConfiguration) { if (templateCache != null && templateCache.contains(template)) { return templateCache.get(template).get(); @@ -98,7 +102,7 @@ public Template getTemplate (String template) { throw new TemplateNotFoundException("template % not found".formatted(template)); } var tokenStream = lexer.tokenize(templateString); - var rootNode = parser.parse(tokenStream); + var rootNode = parser.parse(tokenStream, dynamicConfiguration); var temp = new DefaultTemplate(rootNode, renderer); if (templateCache != null) { diff --git a/cms-templates/src/main/java/com/condation/cms/templates/DefaultTemplate.java b/cms-templates/src/main/java/com/condation/cms/templates/DefaultTemplate.java index 60e6382b9..073399dfd 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/DefaultTemplate.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/DefaultTemplate.java @@ -26,6 +26,7 @@ import com.condation.cms.templates.renderer.Renderer; import com.condation.cms.templates.renderer.ScopeStack; import java.io.IOException; +import java.io.StringWriter; import java.io.Writer; import java.util.Map; import lombok.Getter; @@ -52,9 +53,20 @@ public void evaluate(Map context, Writer writer) throws IOExcept writer.flush(); } + + @Override + public String evaluate(Map context, DynamicConfiguration dynamicConfiguration) throws IOException { + ScopeStack scopes = new ScopeStack(context); + + try (var writer = new StringWriter()) { + renderer.render(rootNode, scopes, writer, dynamicConfiguration); + writer.flush(); + return writer.toString(); + } + } public void evaluate (ScopeStack scopes, Writer writer) throws IOException { - renderer.render(rootNode, scopes, writer); + renderer.render(rootNode, scopes, writer, null); } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java new file mode 100644 index 000000000..0071707dc --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java @@ -0,0 +1,59 @@ +package com.condation.cms.templates; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.content.shortcodes.ShortCodes; +import com.condation.cms.templates.tags.shortcode.EndShortCodeTag; +import com.condation.cms.templates.tags.shortcode.ShortCodeTag; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * + * @author t.marx + */ +public record DynamicConfiguration(ShortCodes shortCodes, Map dynamicTags) { + + public DynamicConfiguration { + for (var tag : shortCodes.getShortCodeNames()) { + var openTag = new ShortCodeTag(tag, shortCodes); + var closeTag = new EndShortCodeTag(tag); + + dynamicTags.put(openTag.getTagName(), openTag); + dynamicTags.put(closeTag.getTagName(), closeTag); + } + } + + public DynamicConfiguration(ShortCodes shortcodes) { + this(shortcodes, new HashMap<>()); + } + + public boolean hasTag (String tagName) { + return dynamicTags.containsKey(tagName); + } + + public Optional getTag (String tagName) { + return Optional.ofNullable(dynamicTags.get(tagName)); + } +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/Template.java b/cms-templates/src/main/java/com/condation/cms/templates/Template.java index 071a35f38..ff0fa229c 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/Template.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/Template.java @@ -43,5 +43,7 @@ default String evaluate(Map context) throws IOException { return writer.toString(); } + String evaluate(Map context, DynamicConfiguration dynamicConfiguration) throws IOException; + void evaluate (Map context, Writer writer) throws IOException; } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java index 934d668da..f31faabc1 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java @@ -138,7 +138,7 @@ public static String readVariableContent(CharacterStream stream) { private void readTagContent(List tokens, CharacterStream charStream) { charStream.skipWhitespace(); - String keyword = charStream.readWhile(Character::isLetter); + String keyword = charStream.readWhile(Character::isLetterOrDigit); tokens.add(new Token(Token.Type.IDENTIFIER, keyword, charStream.getLine(), charStream.getColumn())); String condition = charStream.readUntil("%}"); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java index d659599d2..a964b8fbf 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java @@ -22,6 +22,7 @@ * #L% */ +import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.lexer.TokenStream; import com.condation.cms.templates.Tag; import com.condation.cms.templates.TemplateConfiguration; @@ -41,7 +42,15 @@ public class Parser { private final JexlEngine engine; - public ASTNode parse(final TokenStream tokenStream) { + public ASTNode parse (final TokenStream tokenStream, final DynamicConfiguration dynamicConfiguration) { + return _parse(tokenStream, new ParserConfiguration(configuration, dynamicConfiguration)); + } + + public ASTNode parse (final TokenStream tokenStream) { + return _parse(tokenStream, new ParserConfiguration(configuration)); + } + + private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration parserConfiguration) { ASTNode root = new ASTNode(0, 0); Stack nodeStack = new Stack<>(); nodeStack.push(root); @@ -81,15 +90,15 @@ public ASTNode parse(final TokenStream tokenStream) { } case TAG_END: { if (!nodeStack.isEmpty() && nodeStack.peek() instanceof TagNode tempNode) { - if (configuration.hasTag(tempNode.getName())) { - Tag tag = configuration.getTag(tempNode.getName()).get(); + if (parserConfiguration.hasTag(tempNode.getName())) { + Tag tag = parserConfiguration.getTag(tempNode.getName()).get(); if (tag.isClosingTag()) { nodeStack.pop(); var temp = (TagNode) nodeStack.peek(); - var ptag = configuration.getTag(temp.getName()).get(); + var ptag = parserConfiguration.getTag(temp.getName()).get(); if (ptag.getCloseTagName().isPresent() && ptag.getCloseTagName().get().equals(tag.getTagName())) { @@ -154,16 +163,14 @@ public ASTNode parse(final TokenStream tokenStream) { if (currentNode instanceof TagNode tagNode) { tagNode.setCondition(token.value); - if (configuration.getTag(tagNode.getName()).isEmpty()) { + if (parserConfiguration.getTag(tagNode.getName()).isEmpty()) { throw new UnknownTagException("unkown tag (%s)".formatted(tagNode.getName()), currentNode.getLine(), currentNode.getColumn()); } - Tag tag = configuration.getTag(tagNode.getName()).get(); + Tag tag = parserConfiguration.getTag(tagNode.getName()).get(); if (tag.parseExpressions()) { tagNode.setExpression(engine.createExpression(token.value)); } - } else if (currentNode instanceof TagNode vNode) { - } break; diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java new file mode 100644 index 000000000..f33fe45f4 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java @@ -0,0 +1,56 @@ +package com.condation.cms.templates.parser; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.templates.DynamicConfiguration; +import com.condation.cms.templates.Tag; +import com.condation.cms.templates.TemplateConfiguration; +import java.util.Optional; + +/** + * + * @author t.marx + */ +public record ParserConfiguration(TemplateConfiguration templateEngineConfiguration, DynamicConfiguration dynamicConfiguration) { + + public ParserConfiguration (TemplateConfiguration templateConfiguration) { + this(templateConfiguration, null); + } + + public boolean hasTag (String tagName) { + return templateEngineConfiguration.hasTag(tagName) + || (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)); + } + + public Optional getTag (String tagName) { + if (templateEngineConfiguration.hasTag(tagName)) { + return templateEngineConfiguration.getTag(tagName); + } + + if (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)) { + return dynamicConfiguration.getTag(tagName); + } + + return Optional.empty(); + } +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java new file mode 100644 index 000000000..7e97ca489 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java @@ -0,0 +1,56 @@ +package com.condation.cms.templates.renderer; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.templates.DynamicConfiguration; +import com.condation.cms.templates.Tag; +import com.condation.cms.templates.TemplateConfiguration; +import java.util.Optional; + +/** + * + * @author t.marx + */ +public record RenderConfiguration(TemplateConfiguration templateEngineConfiguration, DynamicConfiguration dynamicConfiguration) { + + public RenderConfiguration (TemplateConfiguration templateConfiguration) { + this(templateConfiguration, null); + } + + public boolean hasTag (String tagName) { + return templateEngineConfiguration.hasTag(tagName) + || (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)); + } + + public Optional getTag (String tagName) { + if (templateEngineConfiguration.hasTag(tagName)) { + return templateEngineConfiguration.getTag(tagName); + } + + if (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)) { + return dynamicConfiguration.getTag(tagName); + } + + return Optional.empty(); + } +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java index 19b37cd2d..ab3f69a52 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java @@ -25,6 +25,7 @@ import com.condation.cms.templates.RenderFunction; import com.condation.cms.templates.TemplateConfiguration; import com.condation.cms.templates.CMSTemplateEngine; +import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.parser.ASTNode; import com.condation.cms.templates.parser.TagNode; import com.condation.cms.templates.parser.TextNode; @@ -70,11 +71,17 @@ public ScopeContext createEngineContext() { } } - public void render(ASTNode node, final ScopeStack scopes, final Writer writer) throws IOException { + public void render(ASTNode node, final ScopeStack scopes, final Writer writer, final DynamicConfiguration dynamicConfiguration) throws IOException { + + var renderConfig = new RenderConfiguration(configuration, dynamicConfiguration); + + var renderFunction = (RenderFunction) (ASTNode node1, Context context, Writer writer1) -> { + renderNode(node1, context, writer1, renderConfig); + }; var contentWriter = new StringWriter(); - final Context renderContext = new Context(engine, scopes, this::renderNode, templateEngine); - renderNode(node, renderContext, contentWriter); + final Context renderContext = new Context(engine, scopes, renderFunction, templateEngine); + renderFunction.render(node, renderContext, contentWriter); if (renderContext.context().containsKey("_extends")) { ExtendsTag.Extends ext = (ExtendsTag.Extends) renderContext.context().get("_extends"); @@ -83,7 +90,7 @@ public void render(ASTNode node, final ScopeStack scopes, final Writer writer) t StringWriter parentWriter = new StringWriter(); renderContext.context().put("_parent", Boolean.TRUE); - renderNode(parentTemplate.getRootNode(), renderContext, parentWriter); + renderFunction.render(parentTemplate.getRootNode(), renderContext, parentWriter); writer.write(parentWriter.toString()); } else { @@ -91,20 +98,20 @@ public void render(ASTNode node, final ScopeStack scopes, final Writer writer) t } } - private void renderNode(ASTNode node, Context context, Writer writer) throws IOException { + private void renderNode(ASTNode node, Context context, Writer writer, RenderConfiguration renderConfiguration) throws IOException { if (node instanceof TextNode textNode) { writer.write(textNode.text); } else if (node instanceof VariableNode vnode) { renderVariable(vnode, context, writer); } else if (node instanceof TagNode tagNode) { - var tag = configuration.getTag(tagNode.getName()); + var tag = renderConfiguration.getTag(tagNode.getName()); if (tag.isPresent()) { tag.get().render(tagNode, context, writer); } } else { for (ASTNode child : node.getChildren()) { - renderNode(child, context, writer); + renderNode(child, context, writer, renderConfiguration); } } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/ForTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/ForTag.java index 790f8375c..e3f9b9ea1 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/ForTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/ForTag.java @@ -54,7 +54,6 @@ public Optional getCloseTagName() { public void render(TagNode node, Renderer.Context context, Writer writer) { var forCondition = parseForLoop(node); - var collectionVariable = context.scopes().getVariable(forCondition.collection); var colExp = context.engine().createExpression(forCondition.collection); var collection = colExp.evaluate(context.createEngineContext()); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java new file mode 100644 index 000000000..c1be46a79 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java @@ -0,0 +1,49 @@ +package com.condation.cms.templates.tags.shortcode; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.templates.Tag; +import lombok.RequiredArgsConstructor; + +/** + * + * @author t.marx + */ +@RequiredArgsConstructor +public class EndShortCodeTag implements Tag { + + private final String shortCodeName; + + @Override + public String getTagName() { + return "end%s".formatted(shortCodeName); + } + + @Override + public boolean isClosingTag() { + return true; + } + + + +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java new file mode 100644 index 000000000..664414197 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java @@ -0,0 +1,157 @@ +package com.condation.cms.templates.tags.shortcode; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.content.shortcodes.ShortCodes; +import com.condation.cms.templates.Tag; +import com.condation.cms.templates.exceptions.RenderException; +import com.condation.cms.templates.parser.TagNode; +import com.condation.cms.templates.renderer.Renderer; +import com.google.common.base.Strings; +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.apache.commons.jexl3.JexlExpression; + +/** + * + * @author t.marx + */ +@RequiredArgsConstructor +public class ShortCodeTag implements Tag { + + private final String shortCodeName; + + private final ShortCodes shortCodes; + + @Override + public String getTagName() { + return shortCodeName; + } + + @Override + public Optional getCloseTagName() { + return Optional.of("end%s".formatted(shortCodeName)); + } + + @Override + public void render(TagNode node, Renderer.Context context, Writer writer) { + try { + var params = parseAndEvaluate(node.getCondition(), context); + var content = renderChildren(node, context); + + params.put("_content", content); + + var shortCodeResult = shortCodes.execute(shortCodeName, params); + if (!Strings.isNullOrEmpty(shortCodeResult)) { + writer.write(shortCodeResult); + } + } catch (Exception e) { + throw new RenderException(e.getMessage(), node.getLine(), node.getColumn()); + } + } + + private String renderChildren(TagNode node, Renderer.Context context) { + try { + StringWriter writer = new StringWriter(); + for (var child : node.getChildren()) { + context.renderer().render(child, context, writer); + } + return writer.toString(); + } catch (IOException ioe) { + throw new RenderException(ioe.getMessage(), node.getLine(), node.getColumn()); + } + } + + public Map parseAndEvaluate(String input, Renderer.Context context) { + Map resultMap = new HashMap<>(); + + // Tokenize den Eingabestring (Leerzeichen als Trennung der Parameter) + List tokens = tokenize(input); + + var jexlContext = context.createEngineContext(); + + for (String token : tokens) { + int equalsIndex = token.indexOf('='); + if (equalsIndex > 0) { + String key = token.substring(0, equalsIndex).trim(); // Schlüssel extrahieren + String value = token.substring(equalsIndex + 1).trim(); // Wert extrahieren + + // Anführungszeichen entfernen, falls vorhanden + if (value.startsWith("\"") && value.endsWith("\"")) { + value = value.substring(1, value.length() - 1); + } + + // Wert mit JEXL evaluieren + Object evaluatedValue; + try { + JexlExpression expression = context.engine().createExpression(value); + evaluatedValue = expression.evaluate(jexlContext); + } catch (Exception e) { + // Falls der Wert keine JEXL-Expression ist, einfach als String speichern + evaluatedValue = value; + } + + resultMap.put(key, evaluatedValue); + } + } + + return resultMap; + } + + private List tokenize(String input) { + List tokens = new ArrayList<>(); + StringBuilder currentToken = new StringBuilder(); + boolean inQuotes = false; + + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + + if (c == '"') { + inQuotes = !inQuotes; // Zustand der Anführungszeichen umkehren + currentToken.append(c); + } else if (c == ' ' && !inQuotes) { + // Bei Leerzeichen trennen, sofern nicht in Anführungszeichen + if (currentToken.length() > 0) { + tokens.add(currentToken.toString()); + currentToken.setLength(0); + } + } else { + currentToken.append(c); + } + } + + if (currentToken.length() > 0) { + tokens.add(currentToken.toString()); + } + + return tokens; + } + +} diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java new file mode 100644 index 000000000..521fe1090 --- /dev/null +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java @@ -0,0 +1,91 @@ +package com.condation.cms.templates; + +/*- + * #%L + * templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ +import com.condation.cms.content.shortcodes.ShortCodes; +import com.condation.cms.content.shortcodes.TagParser; +import com.condation.cms.templates.loaders.StringTemplateLoader; +import java.io.IOException; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * + * @author thmar + */ +public class TemplateEngineShortCodeTest extends AbstractTemplateEngineTest { + + static ShortCodes shortCodes; + static DynamicConfiguration dynamicConfiguration; + + @BeforeAll + public void setupShortCodes() { + shortCodes = new ShortCodes( + Map.of( + "tag1", (params) -> { + return "Hello"; + }, + "tag2", (param) -> { + return "Hello " + param.get("name") + "!"; + }), + new TagParser(null) + ); + dynamicConfiguration = new DynamicConfiguration(shortCodes); + } + + @Override + public TemplateLoader getLoader() { + return new StringTemplateLoader() + .add("tag1", """ + {% tag1 %} + + {% endtag1 %} + """) + .add("tag2", """ + {% tag2 name="CondationCMS" %} + {% endtag2 %} + """); + } + + @Test + public void test_tag1() throws IOException { + Template simpleTemplate = SUT.getTemplate("tag1", dynamicConfiguration); + Assertions.assertThat(simpleTemplate).isNotNull(); + + Assertions + .assertThat(simpleTemplate.evaluate(Map.of(), dynamicConfiguration)) + .isEqualToIgnoringWhitespace("Hello"); + } + + @Test + public void test_tag2() throws IOException { + Template simpleTemplate = SUT.getTemplate("tag2", dynamicConfiguration); + Assertions.assertThat(simpleTemplate).isNotNull(); + + Assertions + .assertThat(simpleTemplate.evaluate(Map.of(), dynamicConfiguration)) + .isEqualToIgnoringWhitespace("Hello CondationCMS!"); + } + +} From aef37b23d93d635b679abb1c3f00deb0261f1dbd Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Tue, 17 Dec 2024 14:58:36 +0100 Subject: [PATCH 04/17] allow dynamicly adding of shortcodes as tags --- cms-api/pom.xml | 2 +- cms-auth/pom.xml | 2 +- cms-content/pom.xml | 2 +- .../cms/content/DefaultContentRenderer.java | 2 +- .../shortcode/ShortCodeTemplateFunction.java | 5 +++++ cms-core/pom.xml | 2 +- cms-extensions/pom.xml | 2 +- cms-filesystem/pom.xml | 2 +- cms-git/pom.xml | 2 +- cms-media/pom.xml | 2 +- cms-server/pom.xml | 2 +- cms-templates/pom.xml | 2 +- .../templates/module/CMSModuleTemplateEngine.java | 12 ++++++++++-- cms-test/pom.xml | 2 +- integration-tests/pom.xml | 2 +- modules/example-module/pom.xml | 2 +- modules/pom.xml | 2 +- modules/system-modules/pom.xml | 2 +- pom.xml | 2 +- 19 files changed, 32 insertions(+), 19 deletions(-) diff --git a/cms-api/pom.xml b/cms-api/pom.xml index 8f4e00591..f336ec9c7 100644 --- a/cms-api/pom.xml +++ b/cms-api/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-api jar diff --git a/cms-auth/pom.xml b/cms-auth/pom.xml index d269335d9..9931f6184 100644 --- a/cms-auth/pom.xml +++ b/cms-auth/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-auth jar diff --git a/cms-content/pom.xml b/cms-content/pom.xml index 3eb46135d..815b01b3a 100644 --- a/cms-content/pom.xml +++ b/cms-content/pom.xml @@ -6,7 +6,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-content jar diff --git a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java index 8312d0eb2..0bd66358a 100644 --- a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java +++ b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java @@ -150,7 +150,7 @@ public String render(final ReadOnlyFile contentFile, final RequestContext contex namespace.add("node", "sections", sections); ShortCodeTemplateFunction shortCodeFunction = createShortCodeFunction(context); - model.values.put("shortCodes", shortCodeFunction); + model.values.put(ShortCodeTemplateFunction.KEY, shortCodeFunction); namespace.add("cms", "shortCodes", shortCodeFunction); NavigationFunction navigationFunction = createNavigationFunction(contentFile, context); diff --git a/cms-content/src/main/java/com/condation/cms/content/template/functions/shortcode/ShortCodeTemplateFunction.java b/cms-content/src/main/java/com/condation/cms/content/template/functions/shortcode/ShortCodeTemplateFunction.java index 353091f52..961b0f58c 100644 --- a/cms-content/src/main/java/com/condation/cms/content/template/functions/shortcode/ShortCodeTemplateFunction.java +++ b/cms-content/src/main/java/com/condation/cms/content/template/functions/shortcode/ShortCodeTemplateFunction.java @@ -25,6 +25,7 @@ import com.condation.cms.content.shortcodes.ShortCodes; import java.util.Map; +import lombok.Getter; import lombok.RequiredArgsConstructor; /** @@ -33,6 +34,10 @@ */ @RequiredArgsConstructor public class ShortCodeTemplateFunction { + + public static final String KEY = "shortCodes"; + + @Getter private final ShortCodes shortCodes; public String call (String name, Map parameters) { diff --git a/cms-core/pom.xml b/cms-core/pom.xml index 340f1cfd2..902ee4f77 100644 --- a/cms-core/pom.xml +++ b/cms-core/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-core jar diff --git a/cms-extensions/pom.xml b/cms-extensions/pom.xml index 5f8d74f11..d7f3a59a6 100644 --- a/cms-extensions/pom.xml +++ b/cms-extensions/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-extensions jar diff --git a/cms-filesystem/pom.xml b/cms-filesystem/pom.xml index 3a9ecc1b2..72372143b 100644 --- a/cms-filesystem/pom.xml +++ b/cms-filesystem/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-filesystem jar diff --git a/cms-git/pom.xml b/cms-git/pom.xml index 3542a9b77..74aeec147 100644 --- a/cms-git/pom.xml +++ b/cms-git/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-git jar diff --git a/cms-media/pom.xml b/cms-media/pom.xml index 8f599280b..ba41dc15a 100644 --- a/cms-media/pom.xml +++ b/cms-media/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-media jar diff --git a/cms-server/pom.xml b/cms-server/pom.xml index 0c4608397..db23703e8 100644 --- a/cms-server/pom.xml +++ b/cms-server/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-server jar diff --git a/cms-templates/pom.xml b/cms-templates/pom.xml index 89d7be727..b038adda4 100644 --- a/cms-templates/pom.xml +++ b/cms-templates/pom.xml @@ -7,7 +7,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-templates diff --git a/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java b/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java index d43be166d..5a28fd1e0 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java @@ -25,7 +25,9 @@ import com.condation.cms.api.db.DB; import com.condation.cms.api.template.TemplateEngine; import com.condation.cms.api.theme.Theme; +import com.condation.cms.content.template.functions.shortcode.ShortCodeTemplateFunction; import com.condation.cms.templates.CMSTemplateEngine; +import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.TemplateEngineFactory; import com.condation.cms.templates.TemplateLoader; import com.condation.cms.templates.loaders.CompositeTemplateLoader; @@ -108,13 +110,19 @@ public void updateTheme(Theme theme) { public String render(String template, Model model) throws IOException { var cmsTemplate = templateEngine.getTemplate(template); - return cmsTemplate.evaluate(model.values); + return cmsTemplate.evaluate(model.values, createDynamicConfiguration(model)); + } + + private DynamicConfiguration createDynamicConfiguration(Model model) { + ShortCodeTemplateFunction shortCodeFunction = (ShortCodeTemplateFunction) model.values.get(ShortCodeTemplateFunction.KEY); + DynamicConfiguration dynamicConfig = new DynamicConfiguration(shortCodeFunction.getShortCodes()); + return dynamicConfig; } @Override public String renderFromString(String templateString, Model model) throws IOException { var template = templateEngine.getTemplateFromString(templateString); - return template.evaluate(model.values); + return template.evaluate(model.values, createDynamicConfiguration(model)); } diff --git a/cms-test/pom.xml b/cms-test/pom.xml index f59fd391d..a2a37478d 100644 --- a/cms-test/pom.xml +++ b/cms-test/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 cms-test jar diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index bd1ebf479..ae6d5fcd8 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 integration-tests jar diff --git a/modules/example-module/pom.xml b/modules/example-module/pom.xml index ed2ef96eb..d9a68f7c0 100644 --- a/modules/example-module/pom.xml +++ b/modules/example-module/pom.xml @@ -4,7 +4,7 @@ com.condation.cms.modules cms-modules - 7.4.2 + 7.5.0 example-module jar diff --git a/modules/pom.xml b/modules/pom.xml index df0a38010..68caa3783 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -4,7 +4,7 @@ com.condation.cms cms-parent - 7.4.2 + 7.5.0 com.condation.cms.modules cms-modules diff --git a/modules/system-modules/pom.xml b/modules/system-modules/pom.xml index 1c3176bab..83de8a4c1 100644 --- a/modules/system-modules/pom.xml +++ b/modules/system-modules/pom.xml @@ -4,7 +4,7 @@ com.condation.cms.modules cms-modules - 7.4.2 + 7.5.0 cms-system-modules jar diff --git a/pom.xml b/pom.xml index f26e81964..453e778a9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.condation.cms cms-parent - 7.4.2 + 7.5.0 pom UTF-8 From c17391b7940391c95c5916c9f6e74fe56343bdba Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Tue, 17 Dec 2024 15:15:45 +0100 Subject: [PATCH 05/17] use shortcodes to add tags dynamicly --- .../extensions/TemplateModelExtendingExtensionPoint.java | 2 +- .../com/condation/cms/api/template/TemplateEngine.java | 2 ++ .../condation/cms/content/DefaultContentRenderer.java | 9 +++++---- .../cms/templates/module/CMSModuleTemplateEngine.java | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtensionPoint.java b/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtensionPoint.java index 6afd7438e..8ea1dd4fe 100644 --- a/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtensionPoint.java +++ b/cms-api/src/main/java/com/condation/cms/api/extensions/TemplateModelExtendingExtensionPoint.java @@ -38,7 +38,7 @@ public abstract class TemplateModelExtendingExtensionPoint extends AbstractExten public abstract void extendModel (TemplateEngine.Model model); public Map getModel () { - TemplateEngine.Model model = new TemplateEngine.Model(null, null); + TemplateEngine.Model model = new TemplateEngine.Model(null, null, null); extendModel(model); return model.values; } diff --git a/cms-api/src/main/java/com/condation/cms/api/template/TemplateEngine.java b/cms-api/src/main/java/com/condation/cms/api/template/TemplateEngine.java index 877fb50ee..8181325d4 100644 --- a/cms-api/src/main/java/com/condation/cms/api/template/TemplateEngine.java +++ b/cms-api/src/main/java/com/condation/cms/api/template/TemplateEngine.java @@ -24,6 +24,7 @@ import com.condation.cms.api.db.ContentNode; import com.condation.cms.api.db.cms.ReadOnlyFile; +import com.condation.cms.api.request.RequestContext; import com.condation.cms.api.theme.Theme; import java.io.IOException; import java.util.HashMap; @@ -51,5 +52,6 @@ public static class Model { public final Map values = new HashMap<>(); public final ReadOnlyFile contentFile; public final ContentNode contentNode; + public final RequestContext requestContext; } } diff --git a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java index 0bd66358a..b1223fef0 100644 --- a/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java +++ b/cms-content/src/main/java/com/condation/cms/content/DefaultContentRenderer.java @@ -135,12 +135,13 @@ public String render(final ReadOnlyFile contentFile, final RequestContext contex Optional contentNode = db.getContent().byUri(uri); - TemplateEngine.Model model = new TemplateEngine.Model(contentFile, contentNode.isPresent() ? contentNode.get() : null); + TemplateEngine.Model model = new TemplateEngine.Model( + contentFile, + contentNode.isPresent() ? contentNode.get() : null, + context); modelExtending.accept(model); - //model.values.put("cms", Namespace.create("cms", meta)); - Namespace namespace = new Namespace(); model.values.put("meta", new MapAccess(meta)); @@ -151,7 +152,7 @@ public String render(final ReadOnlyFile contentFile, final RequestContext contex ShortCodeTemplateFunction shortCodeFunction = createShortCodeFunction(context); model.values.put(ShortCodeTemplateFunction.KEY, shortCodeFunction); - namespace.add("cms", "shortCodes", shortCodeFunction); + namespace.add("cms", ShortCodeTemplateFunction.KEY, shortCodeFunction); NavigationFunction navigationFunction = createNavigationFunction(contentFile, context); model.values.put("navigation", navigationFunction); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java b/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java index 5a28fd1e0..4573fd2d0 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/module/CMSModuleTemplateEngine.java @@ -25,6 +25,7 @@ import com.condation.cms.api.db.DB; import com.condation.cms.api.template.TemplateEngine; import com.condation.cms.api.theme.Theme; +import com.condation.cms.content.RenderContext; import com.condation.cms.content.template.functions.shortcode.ShortCodeTemplateFunction; import com.condation.cms.templates.CMSTemplateEngine; import com.condation.cms.templates.DynamicConfiguration; @@ -114,8 +115,8 @@ public String render(String template, Model model) throws IOException { } private DynamicConfiguration createDynamicConfiguration(Model model) { - ShortCodeTemplateFunction shortCodeFunction = (ShortCodeTemplateFunction) model.values.get(ShortCodeTemplateFunction.KEY); - DynamicConfiguration dynamicConfig = new DynamicConfiguration(shortCodeFunction.getShortCodes()); + var shortCodes = model.requestContext.get(RenderContext.class).shortCodes(); + DynamicConfiguration dynamicConfig = new DynamicConfiguration(shortCodes); return dynamicConfig; } From c39fc875099e88006172cd73dcf24538431975ca Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Wed, 18 Dec 2024 11:47:10 +0100 Subject: [PATCH 06/17] add some tests for parsing end evaluating of parameters --- .../cms/templates/tags/macro/ImportTag.java | 2 +- .../tags/shortcode/ShortCodeTag.java | 69 +----------- .../cms/templates/utils/ParameterUtil.java | 101 ++++++++++++++++++ .../TemplateEngineShortCodeTest.java | 17 +++ .../templates/utils/ParameterUtilTest.java | 54 ++++++++++ 5 files changed, 176 insertions(+), 67 deletions(-) create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/utils/ParameterUtil.java create mode 100644 cms-templates/src/test/java/com/condation/cms/templates/utils/ParameterUtilTest.java diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/macro/ImportTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/macro/ImportTag.java index d1395762d..944d0f5bb 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/macro/ImportTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/macro/ImportTag.java @@ -112,7 +112,7 @@ public void setVariable(String name, Object value) { } // Method to parse the import statement - public static ImportDefinition parseImport(String importStatement, TagNode node) { + private ImportDefinition parseImport(String importStatement, TagNode node) { Matcher matcher = PATTERN.matcher(importStatement.trim()); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java index 664414197..dba61b3d1 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java @@ -27,6 +27,7 @@ import com.condation.cms.templates.exceptions.RenderException; import com.condation.cms.templates.parser.TagNode; import com.condation.cms.templates.renderer.Renderer; +import com.condation.cms.templates.utils.ParameterUtil; import com.google.common.base.Strings; import java.io.IOException; import java.io.StringWriter; @@ -63,7 +64,8 @@ public Optional getCloseTagName() { @Override public void render(TagNode node, Renderer.Context context, Writer writer) { try { - var params = parseAndEvaluate(node.getCondition(), context); + + var params = ParameterUtil.parseAndEvaluate(node.getCondition(), context.createEngineContext(), context.engine()); var content = renderChildren(node, context); params.put("_content", content); @@ -89,69 +91,4 @@ private String renderChildren(TagNode node, Renderer.Context context) { } } - public Map parseAndEvaluate(String input, Renderer.Context context) { - Map resultMap = new HashMap<>(); - - // Tokenize den Eingabestring (Leerzeichen als Trennung der Parameter) - List tokens = tokenize(input); - - var jexlContext = context.createEngineContext(); - - for (String token : tokens) { - int equalsIndex = token.indexOf('='); - if (equalsIndex > 0) { - String key = token.substring(0, equalsIndex).trim(); // Schlüssel extrahieren - String value = token.substring(equalsIndex + 1).trim(); // Wert extrahieren - - // Anführungszeichen entfernen, falls vorhanden - if (value.startsWith("\"") && value.endsWith("\"")) { - value = value.substring(1, value.length() - 1); - } - - // Wert mit JEXL evaluieren - Object evaluatedValue; - try { - JexlExpression expression = context.engine().createExpression(value); - evaluatedValue = expression.evaluate(jexlContext); - } catch (Exception e) { - // Falls der Wert keine JEXL-Expression ist, einfach als String speichern - evaluatedValue = value; - } - - resultMap.put(key, evaluatedValue); - } - } - - return resultMap; - } - - private List tokenize(String input) { - List tokens = new ArrayList<>(); - StringBuilder currentToken = new StringBuilder(); - boolean inQuotes = false; - - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - - if (c == '"') { - inQuotes = !inQuotes; // Zustand der Anführungszeichen umkehren - currentToken.append(c); - } else if (c == ' ' && !inQuotes) { - // Bei Leerzeichen trennen, sofern nicht in Anführungszeichen - if (currentToken.length() > 0) { - tokens.add(currentToken.toString()); - currentToken.setLength(0); - } - } else { - currentToken.append(c); - } - } - - if (currentToken.length() > 0) { - tokens.add(currentToken.toString()); - } - - return tokens; - } - } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/utils/ParameterUtil.java b/cms-templates/src/main/java/com/condation/cms/templates/utils/ParameterUtil.java new file mode 100644 index 000000000..3ee45fa4a --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/utils/ParameterUtil.java @@ -0,0 +1,101 @@ +package com.condation.cms.templates.utils; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.templates.renderer.Renderer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.jexl3.JexlContext; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.JexlExpression; + +/** + * + * @author t.marx + */ +public class ParameterUtil { + public static Map parseAndEvaluate(String input, JexlContext jexlContext, JexlEngine engine) { + Map resultMap = new HashMap<>(); + + // Tokenize den Eingabestring (Leerzeichen als Trennung der Parameter) + List tokens = tokenize(input); + + for (String token : tokens) { + int equalsIndex = token.indexOf('='); + if (equalsIndex > 0) { + String key = token.substring(0, equalsIndex).trim(); // Schlüssel extrahieren + String value = token.substring(equalsIndex + 1).trim(); // Wert extrahieren + + // Anführungszeichen entfernen, falls vorhanden + if (value.startsWith("\"") && value.endsWith("\"")) { + value = value.substring(1, value.length() - 1); + } + + // Wert mit JEXL evaluieren + Object evaluatedValue; + try { + JexlExpression expression = engine.createExpression(value); + evaluatedValue = expression.evaluate(jexlContext); + } catch (Exception e) { + // Falls der Wert keine JEXL-Expression ist, einfach als String speichern + evaluatedValue = value; + } + + resultMap.put(key, evaluatedValue); + } + } + + return resultMap; + } + + private static List tokenize(String input) { + List tokens = new ArrayList<>(); + StringBuilder currentToken = new StringBuilder(); + boolean inQuotes = false; + + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + + if (c == '"') { + inQuotes = !inQuotes; // Zustand der Anführungszeichen umkehren + currentToken.append(c); + } else if (c == ' ' && !inQuotes) { + // Bei Leerzeichen trennen, sofern nicht in Anführungszeichen + if (currentToken.length() > 0) { + tokens.add(currentToken.toString()); + currentToken.setLength(0); + } + } else { + currentToken.append(c); + } + } + + if (currentToken.length() > 0) { + tokens.add(currentToken.toString()); + } + + return tokens; + } +} diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java index 521fe1090..dd557d5c4 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java @@ -48,6 +48,9 @@ public void setupShortCodes() { }, "tag2", (param) -> { return "Hello " + param.get("name") + "!"; + }, + "tag3", (param) -> { + return "
%s
".formatted(param.get("_content")); }), new TagParser(null) ); @@ -65,6 +68,11 @@ public TemplateLoader getLoader() { .add("tag2", """ {% tag2 name="CondationCMS" %} {% endtag2 %} + """) + .add("tag3", """ + {% tag3 %} + This is the content! + {% endtag2 %} """); } @@ -88,4 +96,13 @@ public void test_tag2() throws IOException { .isEqualToIgnoringWhitespace("Hello CondationCMS!"); } + @Test + public void test_tag3() throws IOException { + Template simpleTemplate = SUT.getTemplate("tag3", dynamicConfiguration); + Assertions.assertThat(simpleTemplate).isNotNull(); + + Assertions + .assertThat(simpleTemplate.evaluate(Map.of(), dynamicConfiguration)) + .isEqualToIgnoringWhitespace("
This is the content!
"); + } } diff --git a/cms-templates/src/test/java/com/condation/cms/templates/utils/ParameterUtilTest.java b/cms-templates/src/test/java/com/condation/cms/templates/utils/ParameterUtilTest.java new file mode 100644 index 000000000..297ddda53 --- /dev/null +++ b/cms-templates/src/test/java/com/condation/cms/templates/utils/ParameterUtilTest.java @@ -0,0 +1,54 @@ +package com.condation.cms.templates.utils; + +/*- + * #%L + * cms-templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import org.apache.commons.jexl3.JexlBuilder; +import org.apache.commons.jexl3.JexlEngine; +import org.apache.commons.jexl3.MapContext; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * + * @author t.marx + */ +public class ParameterUtilTest { + + JexlEngine engine = new JexlBuilder().create(); + + @Test + public void testSomeMethod() { + + var context = new MapContext(); + context.set("variable", "CMS"); + + var parameters = ParameterUtil.parseAndEvaluate("param1=\"CondationCMS\" param2=30 param3=variable", context, engine); + + Assertions.assertThat(parameters) + .hasSize(3) + .containsEntry("param1", "CondationCMS") + .containsEntry("param2", 30) + .containsEntry("param3", "CMS"); + } + +} From 48207905dd738e5d85669f4df070fdf4b875e093 Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Wed, 18 Dec 2024 12:09:15 +0100 Subject: [PATCH 07/17] fix test --- .../condation/cms/templates/TemplateEngineShortCodeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java index dd557d5c4..288d6faba 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java @@ -72,7 +72,7 @@ public TemplateLoader getLoader() { .add("tag3", """ {% tag3 %} This is the content! - {% endtag2 %} + {% endtag3 %} """); } From b29904b5fe404b85f2c54ba39706f260ed6e547f Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Fri, 20 Dec 2024 12:26:06 +0100 Subject: [PATCH 08/17] introduce new template syntax for components --- .../condation/cms/templates/Component.java | 49 ++++++++++++++ .../cms/templates/DynamicConfiguration.java | 22 +++---- .../condation/cms/templates/lexer/Lexer.java | 66 +++++++++---------- .../condation/cms/templates/lexer/State.java | 1 + .../condation/cms/templates/lexer/Token.java | 2 + .../cms/templates/parser/ComponentNode.java | 44 +++++++++++++ .../cms/templates/parser/Parser.java | 46 ++++++++++++- .../templates/parser/ParserConfiguration.java | 24 ++++--- .../renderer/RenderConfiguration.java | 35 +++++----- .../cms/templates/renderer/Renderer.java | 31 +++++---- .../ComponentTag.java} | 22 +++---- .../EndComponentTag.java} | 13 ++-- ....java => TemplateEngineComponentTest.java} | 14 ++-- .../cms/templates/lexer/LexerTest.java | 18 +++++ 14 files changed, 275 insertions(+), 112 deletions(-) create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/Component.java create mode 100644 cms-templates/src/main/java/com/condation/cms/templates/parser/ComponentNode.java rename cms-templates/src/main/java/com/condation/cms/templates/tags/{shortcode/ShortCodeTag.java => component/ComponentTag.java} (78%) rename cms-templates/src/main/java/com/condation/cms/templates/tags/{shortcode/EndShortCodeTag.java => component/EndComponentTag.java} (82%) rename cms-templates/src/test/java/com/condation/cms/templates/{TemplateEngineShortCodeTest.java => TemplateEngineComponentTest.java} (91%) diff --git a/cms-templates/src/main/java/com/condation/cms/templates/Component.java b/cms-templates/src/main/java/com/condation/cms/templates/Component.java new file mode 100644 index 000000000..3894c03c6 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/Component.java @@ -0,0 +1,49 @@ +package com.condation.cms.templates; + +/*- + * #%L + * templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import com.condation.cms.templates.parser.ComponentNode; +import com.condation.cms.templates.renderer.Renderer; +import java.io.Writer; +import java.util.Optional; + +/** + * + * @author t.marx + */ +public interface Component { + + String getName(); + + default Optional getCloseingName () { + return Optional.empty(); + } + + default boolean isClosing () { + return false; + } + + default void render (ComponentNode node, Renderer.Context context, Writer writer) { + // default render does nothing + }; +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java index 0071707dc..65977de85 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/DynamicConfiguration.java @@ -23,8 +23,8 @@ */ import com.condation.cms.content.shortcodes.ShortCodes; -import com.condation.cms.templates.tags.shortcode.EndShortCodeTag; -import com.condation.cms.templates.tags.shortcode.ShortCodeTag; +import com.condation.cms.templates.tags.component.EndComponentTag; +import com.condation.cms.templates.tags.component.ComponentTag; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -33,15 +33,15 @@ * * @author t.marx */ -public record DynamicConfiguration(ShortCodes shortCodes, Map dynamicTags) { +public record DynamicConfiguration(ShortCodes shortCodes, Map components) { public DynamicConfiguration { for (var tag : shortCodes.getShortCodeNames()) { - var openTag = new ShortCodeTag(tag, shortCodes); - var closeTag = new EndShortCodeTag(tag); + var openTag = new ComponentTag(tag, shortCodes); + var closeTag = new EndComponentTag(tag); - dynamicTags.put(openTag.getTagName(), openTag); - dynamicTags.put(closeTag.getTagName(), closeTag); + components.put(openTag.getName(), openTag); + components.put(closeTag.getName(), closeTag); } } @@ -49,11 +49,11 @@ public DynamicConfiguration(ShortCodes shortcodes) { this(shortcodes, new HashMap<>()); } - public boolean hasTag (String tagName) { - return dynamicTags.containsKey(tagName); + public boolean hasComponent (String name) { + return components.containsKey(name); } - public Optional getTag (String tagName) { - return Optional.ofNullable(dynamicTags.get(tagName)); + public Optional getComponent (String name) { + return Optional.ofNullable(components.get(name)); } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java index f31faabc1..4e28f0311 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Lexer.java @@ -36,11 +36,14 @@ public class Syntax { public static final String VARIABLE_OPEN = "{{"; public static final String VARIABLE_CLOSE = "}}"; + public static final String COMPONENT_OPEN = "{["; + public static final String COMPONENT_CLOSE = "]}"; + public static final String[] OPENING = new String[] { - TAG_OPEN, COMMENT_OPEN, VARIABLE_OPEN}; + TAG_OPEN, COMMENT_OPEN, VARIABLE_OPEN, COMPONENT_OPEN}; public static final String[] CLOSING = new String[] { - TAG_CLOSE, COMMENT_CLOSE, VARIABLE_CLOSE}; + TAG_CLOSE, COMMENT_CLOSE, VARIABLE_CLOSE, COMPONENT_CLOSE}; } public Lexer() { @@ -61,34 +64,43 @@ public TokenStream tokenize(String input) { int column = charStream.getColumn(); if (c == '{' && charStream.peek(1) == '{') { - tokens.add(new Token(Token.Type.VARIABLE_START, "{{", line, column)); + tokens.add(new Token(Token.Type.VARIABLE_START, Syntax.VARIABLE_OPEN, line, column)); charStream.skip(2); state.set(State.Type.VARIABLE); } else if (c == '{' && charStream.peek(1) == '%') { - tokens.add(new Token(Token.Type.TAG_START, "{%", line, column)); + tokens.add(new Token(Token.Type.TAG_START, Syntax.TAG_OPEN, line, column)); charStream.skip(2); state.set(State.Type.TAG); readTagContent(tokens, charStream); // Inhalte des Tags lesen + } else if (c == '{' && charStream.peek(1) == '[') { + tokens.add(new Token(Token.Type.COMPONENT_START, Syntax.COMPONENT_OPEN, line, column)); + charStream.skip(2); + state.set(State.Type.COMPONENT); + readComponentContent(tokens, charStream); } else if (c == '{' && charStream.peek(1) == '#') { - tokens.add(new Token(Token.Type.COMMENT_START, "{*", line, column)); + tokens.add(new Token(Token.Type.COMMENT_START, Syntax.COMMENT_OPEN, line, column)); charStream.skip(2); state.set(State.Type.COMMENT); } else if (state.is(State.Type.TAG) && c == '%' && charStream.peek(1) == '}') { - tokens.add(new Token(Token.Type.TAG_END, "%}", line, column)); + tokens.add(new Token(Token.Type.TAG_END, Syntax.TAG_CLOSE, line, column)); + charStream.skip(2); + state.set(State.Type.NONE); + } else if (state.is(State.Type.COMPONENT) && c == ']' && charStream.peek(1) == '}') { + tokens.add(new Token(Token.Type.COMPONENT_END, Syntax.COMPONENT_CLOSE, line, column)); charStream.skip(2); state.set(State.Type.NONE); } else if (state.is(State.Type.VARIABLE) && c == '}' && charStream.peek(1) == '}') { - tokens.add(new Token(Token.Type.VARIABLE_END, "}}", line, column)); + tokens.add(new Token(Token.Type.VARIABLE_END, Syntax.VARIABLE_CLOSE, line, column)); charStream.skip(2); state.set(State.Type.NONE); } else if (state.is(State.Type.COMMENT) && c == '#' && charStream.peek(1) == '}') { - tokens.add(new Token(Token.Type.COMMENT_END, "#}", line, column)); + tokens.add(new Token(Token.Type.COMMENT_END, Syntax.COMMENT_CLOSE, line, column)); charStream.skip(2); state.set(State.Type.NONE); } else if (state.is(State.Type.VARIABLE)) { tokens.add(new Token(Token.Type.IDENTIFIER, readVariableContent(charStream), line, column)); } else if (state.is(State.Type.COMMENT)) { - tokens.add(new Token(Token.Type.COMMENT_VALUE, charStream.readUntil("#}"), line, column)); // Alles bis zum nächsten '{' als Text speichern + tokens.add(new Token(Token.Type.COMMENT_VALUE, charStream.readUntil(Syntax.COMMENT_CLOSE), line, column)); // Alles bis zum nächsten '{' als Text speichern } else if (!state.is(State.Type.VARIABLE, State.Type.TAG)) { tokens.add(new Token(Token.Type.TEXT, charStream.readUntil(Syntax.OPENING), line, column)); // Alles bis zum nächsten '{' als Text speichern } else { @@ -134,39 +146,21 @@ public static String readVariableContent(CharacterStream stream) { return content.toString().trim(); } - - private void readTagContent(List tokens, CharacterStream charStream) { + private void readContent(List tokens, CharacterStream charStream, final String END) { charStream.skipWhitespace(); String keyword = charStream.readWhile(Character::isLetterOrDigit); tokens.add(new Token(Token.Type.IDENTIFIER, keyword, charStream.getLine(), charStream.getColumn())); - String condition = charStream.readUntil("%}"); + String condition = charStream.readUntil(END); tokens.add(new Token(Token.Type.EXPRESSION, condition, charStream.getLine(), charStream.getColumn())); } - - private String readString(CharacterStream charStream, char delimiter) { - StringBuilder result = new StringBuilder(); - result.append(delimiter); // Anfangs-Anführungszeichen hinzufügen - charStream.advance(); // Das anfängliche Anführungszeichen überspringen - while (charStream.hasMore()) { - char c = charStream.charAtCurrentPosition(); - if (c == delimiter) { - result.append(c); // Abschließendes Anführungszeichen hinzufügen - charStream.advance(); // Das abschließende Anführungszeichen überspringen - break; - } - if (c == '\\') { - // Escape-Sequenzen verarbeiten - result.append(c); // Backslash hinzufügen - charStream.advance(); - if (charStream.hasMore()) { - c = charStream.charAtCurrentPosition(); - } - } - result.append(c); - charStream.advance(); - } - return result.toString(); + + private void readTagContent(List tokens, CharacterStream charStream) { + readContent(tokens, charStream, Syntax.TAG_CLOSE); + } + + private void readComponentContent(List tokens, CharacterStream charStream) { + readContent(tokens, charStream, Syntax.COMPONENT_CLOSE); } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/lexer/State.java b/cms-templates/src/main/java/com/condation/cms/templates/lexer/State.java index 3f91c018d..b960c7772 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/lexer/State.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/lexer/State.java @@ -34,6 +34,7 @@ public class State { public enum Type { NONE, TAG, + COMPONENT, VARIABLE, COMMENT } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Token.java b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Token.java index 63fd6706a..256e15f0e 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/lexer/Token.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/lexer/Token.java @@ -27,6 +27,8 @@ public static enum Type { TEXT, VARIABLE_START, VARIABLE_END, + COMPONENT_START, + COMPONENT_END, TAG_START, TAG_END, COMMENT_START, diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/ComponentNode.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/ComponentNode.java new file mode 100644 index 000000000..547f51541 --- /dev/null +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/ComponentNode.java @@ -0,0 +1,44 @@ +package com.condation.cms.templates.parser; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.jexl3.JexlExpression; + +/*- + * #%L + * templates + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +public class ComponentNode extends ASTNode { + @Getter + @Setter + private String name; + @Getter + @Setter + private String parameters; + public ComponentNode(int line, int column) { + super(line, column); + } + + @Override + public String toString() { + return "ComponentNode('" + name + ", " + parameters + "')"; + } +} diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java index a964b8fbf..700efc97e 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java @@ -22,6 +22,7 @@ * #L% */ +import com.condation.cms.templates.Component; import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.lexer.TokenStream; import com.condation.cms.templates.Tag; @@ -32,6 +33,8 @@ import java.util.Stack; import com.condation.cms.templates.lexer.Token; +import static com.condation.cms.templates.lexer.Token.Type.TAG_END; +import static com.condation.cms.templates.lexer.Token.Type.TAG_START; import lombok.RequiredArgsConstructor; import org.apache.commons.jexl3.JexlEngine; @@ -118,6 +121,43 @@ private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration } break; } + case COMPONENT_START: { + ComponentNode tagNode = new ComponentNode(token.line, token.column); + + nodeStack.peek().addChild(tagNode); + nodeStack.push(tagNode); // In den neuen Kontext für Tags wechseln + break; + } + case COMPONENT_END: { + if (!nodeStack.isEmpty() && nodeStack.peek() instanceof ComponentNode tempNode) { + if (parserConfiguration.hasComponent(tempNode.getName())) { + Component component = parserConfiguration.getComponent(tempNode.getName()).get(); + + if (component.isClosing()) { + nodeStack.pop(); + + var temp = (ComponentNode) nodeStack.peek(); + + var ptag = parserConfiguration.getComponent(temp.getName()).get(); + + if (ptag.getCloseingName().isPresent() + && ptag.getCloseingName().get().equals(component.getName())) { + nodeStack.pop(); + } else { + throw new ParserException("invalid closing component", token.line, token.column); + } + } else if (component.getCloseingName().isEmpty()) { + nodeStack.pop(); + } + + } else { + throw new ParserException("Undefined component: " + tempNode.getName(), token.line, token.column); + } + } else { + throw new ParserException("Unexpected token: COMPONENT_END", token.line, token.column); + } + break; + } case VARIABLE_END: { if (!nodeStack.isEmpty()) { nodeStack.pop(); // Aus dem aktuellen Tag-/Variable-Block heraustreten @@ -137,7 +177,7 @@ private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration case IDENTIFIER: { ASTNode currentNode = nodeStack.peek(); if (currentNode instanceof TagNode tagNode1) { - tagNode1.setName(token.value); // Tag-Name setzen + tagNode1.setName(token.value); } else if (currentNode instanceof VariableNode variableNode1) { var identifier = token.value; if (TemplateUtils.hasFilters(identifier)) { @@ -155,6 +195,8 @@ private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration variableNode1.setVariable(token.value); // Variable setzen variableNode1.setExpression(engine.createExpression(token.value)); } + } else if (currentNode instanceof ComponentNode compNode) { + compNode.setName(token.value); } break; } @@ -171,6 +213,8 @@ private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration if (tag.parseExpressions()) { tagNode.setExpression(engine.createExpression(token.value)); } + } else if (currentNode instanceof ComponentNode compNode) { + compNode.setParameters(token.value); } break; diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java index f33fe45f4..00ebc5d8f 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java @@ -22,6 +22,7 @@ * #L% */ +import com.condation.cms.templates.Component; import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.Tag; import com.condation.cms.templates.TemplateConfiguration; @@ -37,18 +38,21 @@ public ParserConfiguration (TemplateConfiguration templateConfiguration) { this(templateConfiguration, null); } - public boolean hasTag (String tagName) { - return templateEngineConfiguration.hasTag(tagName) - || (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)); + public boolean hasTag (String name) { + return templateEngineConfiguration.hasTag(name); } - public Optional getTag (String tagName) { - if (templateEngineConfiguration.hasTag(tagName)) { - return templateEngineConfiguration.getTag(tagName); - } - - if (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)) { - return dynamicConfiguration.getTag(tagName); + public Optional getTag (String name) { + return templateEngineConfiguration.getTag(name); + } + + public boolean hasComponent (String name) { + return (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)); + } + + public Optional getComponent (String name) { + if (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)) { + return dynamicConfiguration.getComponent(name); } return Optional.empty(); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java index 7e97ca489..f5b2558ab 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/renderer/RenderConfiguration.java @@ -21,7 +21,7 @@ * . * #L% */ - +import com.condation.cms.templates.Component; import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.Tag; import com.condation.cms.templates.TemplateConfiguration; @@ -32,25 +32,28 @@ * @author t.marx */ public record RenderConfiguration(TemplateConfiguration templateEngineConfiguration, DynamicConfiguration dynamicConfiguration) { - - public RenderConfiguration (TemplateConfiguration templateConfiguration) { + + public RenderConfiguration(TemplateConfiguration templateConfiguration) { this(templateConfiguration, null); } - - public boolean hasTag (String tagName) { - return templateEngineConfiguration.hasTag(tagName) - || (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)); + + public boolean hasTag(String tagName) { + return templateEngineConfiguration.hasTag(tagName); } - - public Optional getTag (String tagName) { - if (templateEngineConfiguration.hasTag(tagName)) { - return templateEngineConfiguration.getTag(tagName); - } - - if (dynamicConfiguration != null && dynamicConfiguration.hasTag(tagName)) { - return dynamicConfiguration.getTag(tagName); + + public Optional getTag(String tagName) { + return templateEngineConfiguration.getTag(tagName); + } + + public boolean hasComponent(String name) { + return (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)); + } + + public Optional getComponent(String name) { + if (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)) { + return dynamicConfiguration.getComponent(name); } - + return Optional.empty(); } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java index ab3f69a52..af38098ab 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java @@ -27,6 +27,7 @@ import com.condation.cms.templates.CMSTemplateEngine; import com.condation.cms.templates.DynamicConfiguration; import com.condation.cms.templates.parser.ASTNode; +import com.condation.cms.templates.parser.ComponentNode; import com.condation.cms.templates.parser.TagNode; import com.condation.cms.templates.parser.TextNode; import com.condation.cms.templates.parser.VariableNode; @@ -100,18 +101,26 @@ public void render(ASTNode node, final ScopeStack scopes, final Writer writer, f private void renderNode(ASTNode node, Context context, Writer writer, RenderConfiguration renderConfiguration) throws IOException { - if (node instanceof TextNode textNode) { - writer.write(textNode.text); - } else if (node instanceof VariableNode vnode) { - renderVariable(vnode, context, writer); - } else if (node instanceof TagNode tagNode) { - var tag = renderConfiguration.getTag(tagNode.getName()); - if (tag.isPresent()) { - tag.get().render(tagNode, context, writer); + switch (node) { + case TextNode textNode -> writer.write(textNode.text); + case VariableNode vnode -> renderVariable(vnode, context, writer); + case TagNode tagNode -> { + var tag = renderConfiguration.getTag(tagNode.getName()); + if (tag.isPresent()) { + tag.get().render(tagNode, context, writer); + } } - } else { - for (ASTNode child : node.getChildren()) { - renderNode(child, context, writer, renderConfiguration); + case ComponentNode componentNode -> { + var component = renderConfiguration.getComponent(componentNode.getName()); + if (component.isPresent()) { + component.get().render(componentNode, context, writer); + } + + } + default -> { + for (ASTNode child : node.getChildren()) { + renderNode(child, context, writer, renderConfiguration); + } } } } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java similarity index 78% rename from cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java rename to cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java index dba61b3d1..df28b5769 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/ShortCodeTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java @@ -1,4 +1,4 @@ -package com.condation.cms.templates.tags.shortcode; +package com.condation.cms.templates.tags.component; /*- * #%L @@ -23,8 +23,10 @@ */ import com.condation.cms.content.shortcodes.ShortCodes; +import com.condation.cms.templates.Component; import com.condation.cms.templates.Tag; import com.condation.cms.templates.exceptions.RenderException; +import com.condation.cms.templates.parser.ComponentNode; import com.condation.cms.templates.parser.TagNode; import com.condation.cms.templates.renderer.Renderer; import com.condation.cms.templates.utils.ParameterUtil; @@ -32,40 +34,36 @@ import java.io.IOException; import java.io.StringWriter; import java.io.Writer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Optional; import lombok.RequiredArgsConstructor; -import org.apache.commons.jexl3.JexlExpression; /** * * @author t.marx */ @RequiredArgsConstructor -public class ShortCodeTag implements Tag { +public class ComponentTag implements Component { private final String shortCodeName; private final ShortCodes shortCodes; @Override - public String getTagName() { + public String getName() { return shortCodeName; } + @Override - public Optional getCloseTagName() { + public Optional getCloseingName() { return Optional.of("end%s".formatted(shortCodeName)); } @Override - public void render(TagNode node, Renderer.Context context, Writer writer) { + public void render(ComponentNode node, Renderer.Context context, Writer writer) { try { - var params = ParameterUtil.parseAndEvaluate(node.getCondition(), context.createEngineContext(), context.engine()); + var params = ParameterUtil.parseAndEvaluate(node.getParameters(), context.createEngineContext(), context.engine()); var content = renderChildren(node, context); params.put("_content", content); @@ -79,7 +77,7 @@ public void render(TagNode node, Renderer.Context context, Writer writer) { } } - private String renderChildren(TagNode node, Renderer.Context context) { + private String renderChildren(ComponentNode node, Renderer.Context context) { try { StringWriter writer = new StringWriter(); for (var child : node.getChildren()) { diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/EndComponentTag.java similarity index 82% rename from cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java rename to cms-templates/src/main/java/com/condation/cms/templates/tags/component/EndComponentTag.java index c1be46a79..5b4377d86 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/shortcode/EndShortCodeTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/EndComponentTag.java @@ -1,4 +1,4 @@ -package com.condation.cms.templates.tags.shortcode; +package com.condation.cms.templates.tags.component; /*- * #%L @@ -22,7 +22,7 @@ * #L% */ -import com.condation.cms.templates.Tag; +import com.condation.cms.templates.Component; import lombok.RequiredArgsConstructor; /** @@ -30,20 +30,17 @@ * @author t.marx */ @RequiredArgsConstructor -public class EndShortCodeTag implements Tag { +public class EndComponentTag implements Component { private final String shortCodeName; @Override - public String getTagName() { + public String getName() { return "end%s".formatted(shortCodeName); } @Override - public boolean isClosingTag() { + public boolean isClosing() { return true; } - - - } diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java similarity index 91% rename from cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java rename to cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java index 288d6faba..230fee658 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineShortCodeTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java @@ -34,7 +34,7 @@ * * @author thmar */ -public class TemplateEngineShortCodeTest extends AbstractTemplateEngineTest { +public class TemplateEngineComponentTest extends AbstractTemplateEngineTest { static ShortCodes shortCodes; static DynamicConfiguration dynamicConfiguration; @@ -61,18 +61,18 @@ public void setupShortCodes() { public TemplateLoader getLoader() { return new StringTemplateLoader() .add("tag1", """ - {% tag1 %} + {[ tag1 ]} - {% endtag1 %} + {[ endtag1 ]} """) .add("tag2", """ - {% tag2 name="CondationCMS" %} - {% endtag2 %} + {[ tag2 name="CondationCMS" ]} + {[ endtag2 ]} """) .add("tag3", """ - {% tag3 %} + {[ tag3 ]} This is the content! - {% endtag3 %} + {[ endtag3 ]} """); } diff --git a/cms-templates/src/test/java/com/condation/cms/templates/lexer/LexerTest.java b/cms-templates/src/test/java/com/condation/cms/templates/lexer/LexerTest.java index 9daa26d5b..f6a52f8a9 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/lexer/LexerTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/lexer/LexerTest.java @@ -98,6 +98,24 @@ public void test_tag() throws IOException { token = tokens.next(); Assertions.assertThat(token.type).isEqualTo(Token.Type.TAG_END); } + + @Test + public void test_component() throws IOException { + + var lexer = new Lexer(); + + var tokens = lexer.tokenize("{[ comp1 param1=\"value1\" param2=55 ]}"); + + Token token = tokens.next(); + Assertions.assertThat(token.type).isEqualTo(Token.Type.COMPONENT_START); + token = tokens.next(); + Assertions.assertThat(token.type).isEqualTo(Token.Type.IDENTIFIER); + Assertions.assertThat(token.value.trim()).isEqualTo("comp1"); + token = tokens.next(); + Assertions.assertThat(token.type).isEqualTo(Token.Type.EXPRESSION); + token = tokens.next(); + Assertions.assertThat(token.type).isEqualTo(Token.Type.COMPONENT_END); + } @Test public void test_tag_with_condition_quoted() throws IOException { From cc6e15c6527203f9a597b1a1e2885c9d5c9052e2 Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Fri, 20 Dec 2024 15:07:00 +0100 Subject: [PATCH 09/17] add simple framework for feature flags --- .../cms/api/featureflags/FeatureFlags.java | 69 ++++++++++++++ .../api/featureflags/FeatureFlagsTest.java | 91 +++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java create mode 100644 cms-api/src/test/java/com/condation/cms/api/featureflags/FeatureFlagsTest.java diff --git a/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java b/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java new file mode 100644 index 000000000..b121e406e --- /dev/null +++ b/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java @@ -0,0 +1,69 @@ +package com.condation.cms.api.featureflags; + +/*- + * #%L + * cms-api + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class FeatureFlags { + private static final Map flags = new ConcurrentHashMap<>(); + + private FeatureFlags() {} + + /** + * Initialize Feature-Flags. + * @param initialFlags Map of features + */ + public static void initialize(Map initialFlags) { + flags.clear(); + flags.putAll(initialFlags); + } + + /** + * Checks if a feature is activated + * @param featureName Der Name des Features. + * @return true, wenn das Feature aktiviert ist; andernfalls false. + */ + public static boolean isEnabled(String featureName) { + return flags.getOrDefault(featureName, false); + } + + /** + * Setzt oder aktualisiert ein einzelnes Feature-Flag. + * @param featureName Der Name des Features. + * @param enabled true für aktivieren, false für deaktivieren. + */ + public static void setFlag(String featureName, boolean enabled) { + flags.put(featureName, enabled); + } + + /** + * Gibt eine unveränderliche Sicht auf die Flags zurück. + * @return Map der aktuellen Feature-Flags. + */ + public static Map getFlags() { + return Collections.unmodifiableMap(flags); + } +} diff --git a/cms-api/src/test/java/com/condation/cms/api/featureflags/FeatureFlagsTest.java b/cms-api/src/test/java/com/condation/cms/api/featureflags/FeatureFlagsTest.java new file mode 100644 index 000000000..1c9565bb1 --- /dev/null +++ b/cms-api/src/test/java/com/condation/cms/api/featureflags/FeatureFlagsTest.java @@ -0,0 +1,91 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/UnitTests/JUnit5TestClass.java to edit this template + */ +package com.condation.cms.api.featureflags; + +/*- + * #%L + * cms-api + * %% + * Copyright (C) 2023 - 2024 CondationCMS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * . + * #L% + */ + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class FeatureFlagsTest { + + @BeforeEach + void setup() { + // Initialisiere die FeatureFlags vor jedem Test + FeatureFlags.initialize(Map.of( + "featureX", true, + "newDashboard", false + )); + } + + @Test + void testFeatureIsEnabled() { + // Prüfe, dass ein aktives Feature korrekt erkannt wird + assertThat(FeatureFlags.isEnabled("featureX")).isTrue(); + } + + @Test + void testFeatureIsDisabled() { + // Prüfe, dass ein inaktives Feature korrekt erkannt wird + assertThat(FeatureFlags.isEnabled("newDashboard")).isFalse(); + } + + @Test + void testDefaultFlagIsDisabled() { + // Prüfe, dass ein nicht initialisiertes Feature false zurückgibt + assertThat(FeatureFlags.isEnabled("nonExistentFeature")).isFalse(); + } + + @Test + void testSetFlag() { + // Aktiviere ein neues Feature und prüfe den Status + FeatureFlags.setFlag("betaFeature", true); + assertThat(FeatureFlags.isEnabled("betaFeature")).isTrue(); + + // Deaktiviere es wieder und prüfe den Status + FeatureFlags.setFlag("betaFeature", false); + assertThat(FeatureFlags.isEnabled("betaFeature")).isFalse(); + } + + @Test + void testGetFlags() { + // Prüfe, dass die initialisierten Flags korrekt zurückgegeben werden + Map flags = FeatureFlags.getFlags(); + + assertThat(flags).containsEntry("featureX", true) + .containsEntry("newDashboard", false) + .doesNotContainKey("nonExistentFeature"); + + // Prüfe, dass die Map unveränderlich ist + assertThatThrownBy(() -> flags.put("shouldFail", true)) + .isInstanceOf(UnsupportedOperationException.class); + } +} + From 41d8285de596ac5baf4508811eeb5ccb3e8c2eb3 Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Fri, 20 Dec 2024 15:12:25 +0100 Subject: [PATCH 10/17] add simple framework for feature flags --- .../cms/api/featureflags/FeatureFlags.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java b/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java index b121e406e..a60e1e0f7 100644 --- a/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java +++ b/cms-api/src/main/java/com/condation/cms/api/featureflags/FeatureFlags.java @@ -43,25 +43,25 @@ public static void initialize(Map initialFlags) { /** * Checks if a feature is activated - * @param featureName Der Name des Features. - * @return true, wenn das Feature aktiviert ist; andernfalls false. + * @param featureName Name of the feature. + * @return true, if the feature is activated; otherwise false. */ public static boolean isEnabled(String featureName) { return flags.getOrDefault(featureName, false); } /** - * Setzt oder aktualisiert ein einzelnes Feature-Flag. - * @param featureName Der Name des Features. - * @param enabled true für aktivieren, false für deaktivieren. + * sets or updates a feature + * @param featureName Name of the feature. + * @param enabled true if activated, false if deactivated. */ public static void setFlag(String featureName, boolean enabled) { flags.put(featureName, enabled); } /** - * Gibt eine unveränderliche Sicht auf die Flags zurück. - * @return Map der aktuellen Feature-Flags. + * returns an unmodifiable view of the feature flags + * @return Map of the current feature flags. */ public static Map getFlags() { return Collections.unmodifiableMap(flags); From f25cfca5ea7e0fd8947930e512ae7cafb463516e Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Thu, 26 Dec 2024 14:36:28 +0100 Subject: [PATCH 11/17] fix dynamic components --- .../cms/templates/parser/Parser.java | 33 ++++++++----------- .../tags/component/ComponentTag.java | 2 -- .../TemplateEngineComponentTest.java | 22 ++++++++++--- .../cms/templates/TemplateFeatureTest.java | 16 +++++++-- .../cms/templates/testdata/component_1.html | 23 +++++++++++++ .../templates/testdata/component_1_data.json | 2 ++ .../testdata/component_1_expected.html | 22 +++++++++++++ 7 files changed, 91 insertions(+), 29 deletions(-) create mode 100644 cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1.html create mode 100644 cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_data.json create mode 100644 cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_expected.html diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java index 700efc97e..45900f18b 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java @@ -130,28 +130,21 @@ private ASTNode _parse(final TokenStream tokenStream, final ParserConfiguration } case COMPONENT_END: { if (!nodeStack.isEmpty() && nodeStack.peek() instanceof ComponentNode tempNode) { - if (parserConfiguration.hasComponent(tempNode.getName())) { - Component component = parserConfiguration.getComponent(tempNode.getName()).get(); - - if (component.isClosing()) { - nodeStack.pop(); - - var temp = (ComponentNode) nodeStack.peek(); - - var ptag = parserConfiguration.getComponent(temp.getName()).get(); - - if (ptag.getCloseingName().isPresent() - && ptag.getCloseingName().get().equals(component.getName())) { - nodeStack.pop(); - } else { - throw new ParserException("invalid closing component", token.line, token.column); - } - } else if (component.getCloseingName().isEmpty()) { + + var compName = tempNode.getName(); + var isClosing = compName.startsWith("end"); + var startName = compName.replaceFirst("end", ""); + + if (isClosing) { + nodeStack.pop(); + + var temp = (ComponentNode) nodeStack.peek(); + + if (temp.getName().equals(startName)) { nodeStack.pop(); + } else { + throw new ParserException("invalid closing component", token.line, token.column); } - - } else { - throw new ParserException("Undefined component: " + tempNode.getName(), token.line, token.column); } } else { throw new ParserException("Unexpected token: COMPONENT_END", token.line, token.column); diff --git a/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java index df28b5769..96cf57512 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/tags/component/ComponentTag.java @@ -24,10 +24,8 @@ import com.condation.cms.content.shortcodes.ShortCodes; import com.condation.cms.templates.Component; -import com.condation.cms.templates.Tag; import com.condation.cms.templates.exceptions.RenderException; import com.condation.cms.templates.parser.ComponentNode; -import com.condation.cms.templates.parser.TagNode; import com.condation.cms.templates.renderer.Renderer; import com.condation.cms.templates.utils.ParameterUtil; import com.google.common.base.Strings; diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java index 230fee658..ef9c217e8 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java @@ -23,6 +23,7 @@ */ import com.condation.cms.content.shortcodes.ShortCodes; import com.condation.cms.content.shortcodes.TagParser; +import com.condation.cms.templates.exceptions.ParserException; import com.condation.cms.templates.loaders.StringTemplateLoader; import java.io.IOException; import java.util.Map; @@ -73,22 +74,27 @@ public TemplateLoader getLoader() { {[ tag3 ]} This is the content! {[ endtag3 ]} - """); + """) + .add("tag_exception", """ + {[ tag3 ]} + This is the content! + {[ endtag4 ]} + """); } @Test public void test_tag1() throws IOException { - Template simpleTemplate = SUT.getTemplate("tag1", dynamicConfiguration); + Template simpleTemplate = SUT.getTemplate("tag1"); Assertions.assertThat(simpleTemplate).isNotNull(); Assertions .assertThat(simpleTemplate.evaluate(Map.of(), dynamicConfiguration)) .isEqualToIgnoringWhitespace("Hello"); } - + @Test public void test_tag2() throws IOException { - Template simpleTemplate = SUT.getTemplate("tag2", dynamicConfiguration); + Template simpleTemplate = SUT.getTemplate("tag2"); Assertions.assertThat(simpleTemplate).isNotNull(); Assertions @@ -98,11 +104,17 @@ public void test_tag2() throws IOException { @Test public void test_tag3() throws IOException { - Template simpleTemplate = SUT.getTemplate("tag3", dynamicConfiguration); + Template simpleTemplate = SUT.getTemplate("tag3"); Assertions.assertThat(simpleTemplate).isNotNull(); Assertions .assertThat(simpleTemplate.evaluate(Map.of(), dynamicConfiguration)) .isEqualToIgnoringWhitespace("
This is the content!
"); } + + @Test + public void test_parser_exception() throws IOException { + Assertions.assertThatThrownBy(() -> SUT.getTemplate("tag_exception")) + .isInstanceOf(ParserException.class); + } } diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateFeatureTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateFeatureTest.java index 83d2e0fa3..513da71bd 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateFeatureTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateFeatureTest.java @@ -21,6 +21,8 @@ * . * #L% */ +import com.condation.cms.content.shortcodes.ShortCodes; +import com.condation.cms.content.shortcodes.TagParser; import com.condation.cms.templates.loaders.StringTemplateLoader; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -56,7 +58,8 @@ public TemplateLoader getLoader() { "variable_raw_filter", "variable_1", "for_1", - "if_1" + "if_1", + "component_1" }) void test_features(String templateFile) throws Exception { var templateContent = readContent(templateFile + ".html"); @@ -68,11 +71,20 @@ void test_features(String templateFile) throws Exception { var template = SUT.getTemplate(templateFile); - var rendered = template.evaluate(data); + var rendered = template.evaluate(data, createDynamicConfig()); Assertions.assertThat(rendered).isEqualToIgnoringWhitespace(expectedContent); } + private DynamicConfiguration createDynamicConfig () { + ShortCodes shortCodes = new ShortCodes( + Map.of( + "hello", (params) -> "hello " + params.get("name") + ), + new TagParser(null)); + return new DynamicConfiguration(shortCodes); + } + private Map getData (String filename) throws IOException { String dataFile = filename + "_data.json"; if (!exists(dataFile)) { diff --git a/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1.html b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1.html new file mode 100644 index 000000000..18c3ec03c --- /dev/null +++ b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1.html @@ -0,0 +1,23 @@ + +{[ hello name="CondationCMS" ]} +{[ endhello ]} diff --git a/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_data.json b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_data.json new file mode 100644 index 000000000..2c63c0851 --- /dev/null +++ b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_data.json @@ -0,0 +1,2 @@ +{ +} diff --git a/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_expected.html b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_expected.html new file mode 100644 index 000000000..bcfab4e95 --- /dev/null +++ b/cms-templates/src/test/resources/com/condation/cms/templates/testdata/component_1_expected.html @@ -0,0 +1,22 @@ + +hello CondationCMS From bfbc83d3c502d9cbdda4c3a4917c6c1b9c7dc76e Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Thu, 26 Dec 2024 14:44:37 +0100 Subject: [PATCH 12/17] remove legacy impl --- .../cms/templates/CMSTemplateEngine.java | 6 +----- .../condation/cms/templates/parser/Parser.java | 4 ---- .../templates/parser/ParserConfiguration.java | 18 +----------------- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java b/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java index 26317f272..67a074837 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/CMSTemplateEngine.java @@ -88,10 +88,6 @@ public Template getTemplateFromString (String templateContent) { } public Template getTemplate (String template) { - return getTemplate(template, null); - } - - public Template getTemplate (String template, DynamicConfiguration dynamicConfiguration) { if (templateCache != null && templateCache.contains(template)) { return templateCache.get(template).get(); @@ -102,7 +98,7 @@ public Template getTemplate (String template, DynamicConfiguration dynamicConfig throw new TemplateNotFoundException("template % not found".formatted(template)); } var tokenStream = lexer.tokenize(templateString); - var rootNode = parser.parse(tokenStream, dynamicConfiguration); + var rootNode = parser.parse(tokenStream); var temp = new DefaultTemplate(rootNode, renderer); if (templateCache != null) { diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java index 45900f18b..2e71250aa 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/Parser.java @@ -45,10 +45,6 @@ public class Parser { private final JexlEngine engine; - public ASTNode parse (final TokenStream tokenStream, final DynamicConfiguration dynamicConfiguration) { - return _parse(tokenStream, new ParserConfiguration(configuration, dynamicConfiguration)); - } - public ASTNode parse (final TokenStream tokenStream) { return _parse(tokenStream, new ParserConfiguration(configuration)); } diff --git a/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java index 00ebc5d8f..facc9d2fd 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/parser/ParserConfiguration.java @@ -32,11 +32,7 @@ * * @author t.marx */ -public record ParserConfiguration(TemplateConfiguration templateEngineConfiguration, DynamicConfiguration dynamicConfiguration) { - - public ParserConfiguration (TemplateConfiguration templateConfiguration) { - this(templateConfiguration, null); - } +public record ParserConfiguration(TemplateConfiguration templateEngineConfiguration) { public boolean hasTag (String name) { return templateEngineConfiguration.hasTag(name); @@ -45,16 +41,4 @@ public boolean hasTag (String name) { public Optional getTag (String name) { return templateEngineConfiguration.getTag(name); } - - public boolean hasComponent (String name) { - return (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)); - } - - public Optional getComponent (String name) { - if (dynamicConfiguration != null && dynamicConfiguration.hasComponent(name)) { - return dynamicConfiguration.getComponent(name); - } - - return Optional.empty(); - } } From d676a32f00228cbaea4f42206dfd695f6965cc19 Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Fri, 27 Dec 2024 15:42:54 +0100 Subject: [PATCH 13/17] remove deprecations --- .../template/functions/hooks/HooksTemlateFunction.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cms-content/src/main/java/com/condation/cms/content/template/functions/hooks/HooksTemlateFunction.java b/cms-content/src/main/java/com/condation/cms/content/template/functions/hooks/HooksTemlateFunction.java index 824133cdc..41f47b5da 100644 --- a/cms-content/src/main/java/com/condation/cms/content/template/functions/hooks/HooksTemlateFunction.java +++ b/cms-content/src/main/java/com/condation/cms/content/template/functions/hooks/HooksTemlateFunction.java @@ -39,15 +39,6 @@ public class HooksTemlateFunction { private final HookSystem hookSystem; - @Deprecated(since = "4.18.0", forRemoval = true) - public ActionContext call (String name) { - return execute(name, Map.of()); - } - @Deprecated(since = "4.18.0", forRemoval = true) - public ActionContext call (String name, Map arguments) { - return execute(name, arguments); - } - public ActionContext execute (String name) { return execute(name, Map.of()); } From 9af928625994979821ab4f1cfd1b96653f639a6b Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Fri, 27 Dec 2024 16:07:00 +0100 Subject: [PATCH 14/17] add exception handling for dev mode --- .../cms/templates/renderer/Renderer.java | 5 +++++ .../templates/TemplateEngineComponentTest.java | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java index af38098ab..0c25c91e8 100644 --- a/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java +++ b/cms-templates/src/main/java/com/condation/cms/templates/renderer/Renderer.java @@ -26,6 +26,7 @@ import com.condation.cms.templates.TemplateConfiguration; import com.condation.cms.templates.CMSTemplateEngine; import com.condation.cms.templates.DynamicConfiguration; +import com.condation.cms.templates.exceptions.RenderException; import com.condation.cms.templates.parser.ASTNode; import com.condation.cms.templates.parser.ComponentNode; import com.condation.cms.templates.parser.TagNode; @@ -108,12 +109,16 @@ private void renderNode(ASTNode node, Context context, Writer writer, RenderConf var tag = renderConfiguration.getTag(tagNode.getName()); if (tag.isPresent()) { tag.get().render(tagNode, context, writer); + } else if (this.configuration.isDevMode()) { + throw new RenderException("unknown tag", node.getLine(), node.getColumn()); } } case ComponentNode componentNode -> { var component = renderConfiguration.getComponent(componentNode.getName()); if (component.isPresent()) { component.get().render(componentNode, context, writer); + } else if (this.configuration.isDevMode()) { + throw new RenderException("unknown component", node.getLine(), node.getColumn()); } } diff --git a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java index ef9c217e8..6c49c3109 100644 --- a/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java +++ b/cms-templates/src/test/java/com/condation/cms/templates/TemplateEngineComponentTest.java @@ -24,6 +24,7 @@ import com.condation.cms.content.shortcodes.ShortCodes; import com.condation.cms.content.shortcodes.TagParser; import com.condation.cms.templates.exceptions.ParserException; +import com.condation.cms.templates.exceptions.RenderException; import com.condation.cms.templates.loaders.StringTemplateLoader; import java.io.IOException; import java.util.Map; @@ -75,10 +76,15 @@ public TemplateLoader getLoader() { This is the content! {[ endtag3 ]} """) - .add("tag_exception", """ + .add("parser_exception", """ {[ tag3 ]} This is the content! {[ endtag4 ]} + """) + .add("render_exception", """ + {[ tag4 ]} + This is the content! + {[ endtag4 ]} """); } @@ -114,7 +120,14 @@ public void test_tag3() throws IOException { @Test public void test_parser_exception() throws IOException { - Assertions.assertThatThrownBy(() -> SUT.getTemplate("tag_exception")) + Assertions.assertThatThrownBy(() -> SUT.getTemplate("parser_exception")) .isInstanceOf(ParserException.class); } + + @Test + public void test_render_exception() throws IOException { + var template = SUT.getTemplate("render_exception"); + Assertions.assertThatThrownBy(() -> template.evaluate(Map.of(), dynamicConfiguration)) + .isInstanceOf(RenderException.class); + } } From b9ff1a8611f9dcfe8c715b4573f66d3e9ed31582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Marx=20=E3=8B=A1?= Date: Fri, 3 Jan 2025 08:37:16 +0100 Subject: [PATCH 15/17] Merge main (#363) * Bump the prod-deps group with 2 updates (#360) Bumps the prod-deps group with 2 updates: [com.github.chrisvest:stormpot](https://github.com/chrisvest/stormpot) and [org.semver4j:semver4j](https://github.com/semver4j/semver4j). Updates `com.github.chrisvest:stormpot` from 4.0 to 4.1 - [Release notes](https://github.com/chrisvest/stormpot/releases) - [Changelog](https://github.com/chrisvest/stormpot/blob/main/api-changes.json) - [Commits](https://github.com/chrisvest/stormpot/compare/stormpot-4.0...stormpot-4.1) Updates `org.semver4j:semver4j` from 5.4.1 to 5.5.0 - [Release notes](https://github.com/semver4j/semver4j/releases) - [Commits](https://github.com/semver4j/semver4j/compare/v5.4.1...v5.5.0) --- updated-dependencies: - dependency-name: com.github.chrisvest:stormpot dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps - dependency-name: org.semver4j:semver4j dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump org.assertj:assertj-core in the prod-deps group (#362) Bumps the prod-deps group with 1 update: [org.assertj:assertj-core](https://github.com/assertj/assertj). Updates `org.assertj:assertj-core` from 3.27.0 to 3.27.1 - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.0...assertj-build-3.27.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 29deeade0..b619ef841 100644 --- a/pom.xml +++ b/pom.xml @@ -271,7 +271,7 @@ com.github.chrisvest stormpot - 4.0 + 4.1 @@ -279,7 +279,7 @@ org.assertj assertj-core - 3.27.0 + 3.27.1 test @@ -314,7 +314,7 @@ org.semver4j semver4j - 5.4.1 + 5.5.0 com.google.code.gson From 9cb3f4f5dbda33f4bcd18038e67a95a76795782e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Marx=20=E3=8B=A1?= Date: Sat, 4 Jan 2025 07:26:19 +0100 Subject: [PATCH 16/17] Merge main (#366) * Bump the prod-deps group with 2 updates (#360) Bumps the prod-deps group with 2 updates: [com.github.chrisvest:stormpot](https://github.com/chrisvest/stormpot) and [org.semver4j:semver4j](https://github.com/semver4j/semver4j). Updates `com.github.chrisvest:stormpot` from 4.0 to 4.1 - [Release notes](https://github.com/chrisvest/stormpot/releases) - [Changelog](https://github.com/chrisvest/stormpot/blob/main/api-changes.json) - [Commits](https://github.com/chrisvest/stormpot/compare/stormpot-4.0...stormpot-4.1) Updates `org.semver4j:semver4j` from 5.4.1 to 5.5.0 - [Release notes](https://github.com/semver4j/semver4j/releases) - [Commits](https://github.com/semver4j/semver4j/compare/v5.4.1...v5.5.0) --- updated-dependencies: - dependency-name: com.github.chrisvest:stormpot dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps - dependency-name: org.semver4j:semver4j dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump org.assertj:assertj-core in the prod-deps group (#362) Bumps the prod-deps group with 1 update: [org.assertj:assertj-core](https://github.com/assertj/assertj). Updates `org.assertj:assertj-core` from 3.27.0 to 3.27.1 - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.0...assertj-build-3.27.1) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump the prod-deps group with 2 updates (#365) Bumps the prod-deps group with 2 updates: [org.mockito:mockito-core](https://github.com/mockito/mockito) and [org.mockito:mockito-junit-jupiter](https://github.com/mockito/mockito). Updates `org.mockito:mockito-core` from 5.14.2 to 5.15.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2) Updates `org.mockito:mockito-junit-jupiter` from 5.14.2 to 5.15.2 - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps - dependency-name: org.mockito:mockito-junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-deps ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b619ef841..7c3c9b75c 100644 --- a/pom.xml +++ b/pom.xml @@ -285,13 +285,13 @@ org.mockito mockito-core - 5.14.2 + 5.15.2 test org.mockito mockito-junit-jupiter - 5.14.2 + 5.15.2 test From 1393f5d1f507b2b528d73b6f67119722a4947294 Mon Sep 17 00:00:00 2001 From: Thorsten Marx Date: Mon, 6 Jan 2025 14:45:05 +0100 Subject: [PATCH 17/17] update build version --- distribution/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribution/build.xml b/distribution/build.xml index f2f16f646..ab1ebee05 100644 --- a/distribution/build.xml +++ b/distribution/build.xml @@ -1,6 +1,6 @@ - 7.4.2 + 7.5.0