001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2024, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.core.model.processor; 016 017import ch.qos.logback.core.Context; 018import ch.qos.logback.core.joran.GenericXMLConfigurator; 019import ch.qos.logback.core.joran.event.SaxEvent; 020import ch.qos.logback.core.joran.event.SaxEventRecorder; 021import ch.qos.logback.core.joran.spi.JoranException; 022import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil; 023import ch.qos.logback.core.model.IncludeModel; 024import ch.qos.logback.core.model.Model; 025import ch.qos.logback.core.spi.ErrorCodes; 026import ch.qos.logback.core.util.Loader; 027import ch.qos.logback.core.util.OptionHelper; 028 029import java.io.File; 030import java.io.IOException; 031import java.io.InputStream; 032import java.net.MalformedURLException; 033import java.net.URI; 034import java.net.URL; 035import java.util.List; 036import java.util.function.Supplier; 037 038import static ch.qos.logback.core.joran.JoranConstants.CONFIGURATION_TAG; 039import static ch.qos.logback.core.joran.JoranConstants.INCLUDED_TAG; 040 041/** 042 * @since 1.5.5 043 */ 044public class IncludeModelHandler extends ResourceHandlerBase { 045 boolean inError = false; 046 047 public IncludeModelHandler(Context context) { 048 super(context); 049 } 050 051 static public IncludeModelHandler makeInstance(Context context, ModelInterpretationContext mic) { 052 return new IncludeModelHandler(context); 053 } 054 055 @Override 056 protected Class<IncludeModel> getSupportedModelClass() { 057 return IncludeModel.class; 058 } 059 060 @Override 061 public void handle(ModelInterpretationContext mic, Model model) throws ModelHandlerException { 062 IncludeModel includeModel = (IncludeModel) model; 063 064 this.optional = OptionHelper.toBoolean(includeModel.getOptional(), false); 065 066 if (!checkAttributes(includeModel)) { 067 inError = true; 068 return; 069 } 070 071 InputStream in = getInputStream(mic, includeModel); 072 if(in == null) { 073 inError = true; 074 return; 075 } 076 077 SaxEventRecorder recorder = null; 078 079 try { 080 recorder = populateSaxEventRecorder(in); 081 082 List<SaxEvent> saxEvents = recorder.getSaxEventList(); 083 if (saxEvents.isEmpty()) { 084 addWarn("Empty sax event list"); 085 return; 086 } 087 088 Supplier<? extends GenericXMLConfigurator> jcSupplier = mic.getConfiguratorSupplier(); 089 if (jcSupplier == null) { 090 addError("null configurator supplier. Abandoning inclusion of [" + attributeInUse + "]"); 091 inError = true; 092 return; 093 } 094 095 GenericXMLConfigurator genericXMLConfigurator = jcSupplier.get(); 096 genericXMLConfigurator.getRuleStore().addPathPathMapping(INCLUDED_TAG, CONFIGURATION_TAG); 097 098 Model modelFromIncludedFile = genericXMLConfigurator.buildModelFromSaxEventList(recorder.getSaxEventList()); 099 if (modelFromIncludedFile == null) { 100 addError(ErrorCodes.EMPTY_MODEL_STACK); 101 return; 102 } 103 104 includeModel.getSubModels().addAll(modelFromIncludedFile.getSubModels()); 105 106 } catch (JoranException e) { 107 inError = true; 108 addError("Error processing XML data in [" + attributeInUse + "]", e); 109 } 110 } 111 112 public SaxEventRecorder populateSaxEventRecorder(final InputStream inputStream) throws JoranException { 113 SaxEventRecorder recorder = new SaxEventRecorder(context); 114 recorder.recordEvents(inputStream); 115 return recorder; 116 } 117 118 private InputStream getInputStream(ModelInterpretationContext mic, IncludeModel includeModel) { 119 URL inputURL = getInputURL(mic, includeModel); 120 if (inputURL == null) 121 return null; 122 ConfigurationWatchListUtil.addToWatchList(context, inputURL); 123 return openURL(inputURL); 124 } 125 126}