diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java index aa6c961bda..5b1ef22729 100644 --- a/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java +++ b/logback-classic/src/main/java/ch/qos/logback/classic/tyler/TylerConfiguratorBase.java @@ -17,8 +17,12 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.joran.JoranConfigurator; +import ch.qos.logback.classic.model.ConfigurationModel; import ch.qos.logback.classic.util.LevelUtil; import ch.qos.logback.core.Context; +import ch.qos.logback.core.joran.GenericXMLConfigurator; +import ch.qos.logback.core.model.Model; import ch.qos.logback.core.model.util.PropertyModelHandlerHelper; import ch.qos.logback.core.model.util.VariableSubstitutionsHelper; import ch.qos.logback.core.spi.ContextAwareBase; @@ -29,6 +33,7 @@ import ch.qos.logback.core.util.StringUtil; import java.util.Map; +import java.util.function.Supplier; public class TylerConfiguratorBase extends ContextAwareBase implements ContextAwarePropertyContainer { @@ -64,13 +69,13 @@ public void setContext(Context context) { } protected void setContextName(String name) { - if(StringUtil.isNullOrEmpty(name)) { + if (StringUtil.isNullOrEmpty(name)) { addError("Cannot set context name to null or empty string"); return; } try { String substName = subst(name); - addInfo("Setting context name to ["+substName+"]"); + addInfo("Setting context name to [" + substName + "]"); context.setName(substName); } catch (IllegalStateException e) { addError("Failed to rename context as [" + name + "]"); @@ -153,4 +158,29 @@ public String property(String k) { else return ""; } + + private JoranConfigurator makeAnotherInstance() { + JoranConfigurator jc = new JoranConfigurator(); + jc.setContext(context); + return jc; + } + + /** + * Return a supplier which supplies an instance of {@link JoranConfigurator} set to + * the same context the context of 'this'. + * @since 1.5.11 + */ + @Override + public Supplier getConfiguratorSupplier() { + Supplier supplier = () -> this.makeAnotherInstance(); + return supplier; + } + + protected void processModelFromIncludedFile(Model modelFromIncludedFile) { + Supplier configuratorSupplier = this.getConfiguratorSupplier(); + GenericXMLConfigurator genericXMLConfigurator = configuratorSupplier.get(); + ConfigurationModel configururationModel = new ConfigurationModel(); + configururationModel.addSubModel(modelFromIncludedFile); + genericXMLConfigurator.processModel(configururationModel); + } } diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/processor/IncludeModelHandler.java b/logback-core/src/main/java/ch/qos/logback/core/model/processor/IncludeModelHandler.java index 97a0d30150..db5891b5dd 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/model/processor/IncludeModelHandler.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/processor/IncludeModelHandler.java @@ -22,6 +22,7 @@ import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil; import ch.qos.logback.core.model.IncludeModel; import ch.qos.logback.core.model.Model; +import ch.qos.logback.core.spi.ContextAwarePropertyContainer; import ch.qos.logback.core.spi.ErrorCodes; import ch.qos.logback.core.util.Loader; import ch.qos.logback.core.util.OptionHelper; @@ -60,18 +61,35 @@ protected Class getSupportedModelClass() { @Override public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException { IncludeModel includeModel = (IncludeModel) model; + Model modelFromIncludedFile = buildModelFromIncludedFile(mic, includeModel); + if (modelFromIncludedFile == null) { + warnIfRequired("Failed to build include model from included file"); + return; + } + processModelFromIncludedFile(includeModel, modelFromIncludedFile); + } + + /** + * This method is called by logback-tyler at TylerConfigurator run-time. + * + * @param capc + * @param includeModel + * @throws ModelHandlerException + * @since 1.5.11 + */ + public Model buildModelFromIncludedFile(ContextAwarePropertyContainer capc, IncludeModel includeModel) throws ModelHandlerException { this.optional = OptionHelper.toBoolean(includeModel.getOptional(), false); if (!checkAttributes(includeModel)) { inError = true; - return; + return null; } - InputStream in = getInputStream(mic, includeModel); - if(in == null) { + InputStream in = getInputStream(capc, includeModel); + if (in == null) { inError = true; - return; + return null; } SaxEventRecorder recorder = null; @@ -82,41 +100,40 @@ public void handle(ModelInterpretationContext mic, Model model) throws ModelHand List saxEvents = recorder.getSaxEventList(); if (saxEvents.isEmpty()) { addWarn("Empty sax event list"); - return; + return null; } - Supplier jcSupplier = mic.getConfiguratorSupplier(); + Supplier jcSupplier = capc.getConfiguratorSupplier(); if (jcSupplier == null) { addError("null configurator supplier. Abandoning inclusion of [" + attributeInUse + "]"); inError = true; - return; + return null; } GenericXMLConfigurator genericXMLConfigurator = jcSupplier.get(); genericXMLConfigurator.getRuleStore().addPathPathMapping(INCLUDED_TAG, CONFIGURATION_TAG); Model modelFromIncludedFile = genericXMLConfigurator.buildModelFromSaxEventList(recorder.getSaxEventList()); - if (modelFromIncludedFile == null) { - addError(ErrorCodes.EMPTY_MODEL_STACK); - return; - } - - includeModel.getSubModels().addAll(modelFromIncludedFile.getSubModels()); - + return modelFromIncludedFile; } catch (JoranException e) { inError = true; addError("Error processing XML data in [" + attributeInUse + "]", e); + return null; } } + private void processModelFromIncludedFile(IncludeModel includeModel, Model modelFromIncludedFile) { + includeModel.getSubModels().addAll(modelFromIncludedFile.getSubModels()); + } + public SaxEventRecorder populateSaxEventRecorder(final InputStream inputStream) throws JoranException { SaxEventRecorder recorder = new SaxEventRecorder(context); recorder.recordEvents(inputStream); return recorder; } - private InputStream getInputStream(ModelInterpretationContext mic, IncludeModel includeModel) { - URL inputURL = getInputURL(mic, includeModel); + private InputStream getInputStream(ContextAwarePropertyContainer capc, IncludeModel includeModel) { + URL inputURL = getInputURL(capc, includeModel); if (inputURL == null) return null; ConfigurationWatchListUtil.addToWatchList(context, inputURL); diff --git a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java index a0e899ad76..4ddb6abeee 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java +++ b/logback-core/src/main/java/ch/qos/logback/core/model/processor/ModelInterpretationContext.java @@ -289,6 +289,7 @@ public String getImport(String stem) { * * @return a supplier of {@link GenericXMLConfigurator} instance, may be null */ + @Override public Supplier getConfiguratorSupplier() { return this.configuratorSupplier; } diff --git a/logback-core/src/main/java/ch/qos/logback/core/spi/ContextAwarePropertyContainer.java b/logback-core/src/main/java/ch/qos/logback/core/spi/ContextAwarePropertyContainer.java index 1763d64ef7..efce2a4ffb 100644 --- a/logback-core/src/main/java/ch/qos/logback/core/spi/ContextAwarePropertyContainer.java +++ b/logback-core/src/main/java/ch/qos/logback/core/spi/ContextAwarePropertyContainer.java @@ -14,6 +14,10 @@ package ch.qos.logback.core.spi; +import ch.qos.logback.core.joran.GenericXMLConfigurator; + +import java.util.function.Supplier; + /** * An interface extending both {@link PropertyContainer} and {@link ContextAware} * @@ -30,4 +34,17 @@ public interface ContextAwarePropertyContainer extends PropertyContainer, Contex */ String subst(String input); + + /** + * Returns a supplier of {@link GenericXMLConfigurator} instance. The returned value may be null. + * + *

This method could/should have been part of a new interface. It is added here for reasons + * of commodity and not coherence.

+ * + * @return a supplier of {@link GenericXMLConfigurator} instance, may be null + * @since 1.5.11 + */ + default public Supplier getConfiguratorSupplier() { + return null; + } }