org.apache.juli.logging.ch.qos.logback.core.joran.action.IncludeAction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tomcat10-slf4j-logback Show documentation
Show all versions of tomcat10-slf4j-logback Show documentation
Tomcat10 Slf4j Logback Integration
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package org.apache.juli.logging.ch.qos.logback.core.joran.action;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.List;
import org.xml.sax.Attributes;
import org.apache.juli.logging.ch.qos.logback.core.joran.event.SaxEvent;
import org.apache.juli.logging.ch.qos.logback.core.joran.event.SaxEventRecorder;
import org.apache.juli.logging.ch.qos.logback.core.joran.spi.ActionException;
import org.apache.juli.logging.ch.qos.logback.core.joran.spi.JoranException;
import org.apache.juli.logging.ch.qos.logback.core.joran.spi.SaxEventInterpretationContext;
import org.apache.juli.logging.ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
import org.apache.juli.logging.ch.qos.logback.core.model.IncludeModel;
import org.apache.juli.logging.ch.qos.logback.core.model.Model;
import org.apache.juli.logging.ch.qos.logback.core.util.Loader;
import org.apache.juli.logging.ch.qos.logback.core.util.OptionHelper;
import static org.apache.juli.logging.ch.qos.logback.core.joran.JoranConstants.INCLUDED_TAG;
/**
*
* @author ceki
*
*/
public class IncludeAction extends Action {
private static final String FILE_ATTR = "file";
private static final String URL_ATTR = "url";
private static final String RESOURCE_ATTR = "resource";
private static final String OPTIONAL_ATTR = "optional";
private String attributeInUse;
private boolean optional;
Model parentModel;
IncludeModel includeModel;
boolean inError = false;
@Override
public void begin(SaxEventInterpretationContext ec, String name, Attributes attributes) throws ActionException {
parentModel = null;
includeModel = null;
SaxEventRecorder recorder = new SaxEventRecorder(context);
String optionalStr = attributes.getValue(OPTIONAL_ATTR);
createModelForAlternateUse(ec, name, attributes, optionalStr);
this.attributeInUse = null;
this.optional = OptionHelper.toBoolean(optionalStr, false);
if (!checkAttributes(attributes)) {
inError = true;
return;
}
InputStream in = getInputStream(ec, attributes);
try {
if (in != null) {
parseAndRecord(in, recorder);
// remove the tag from the beginning and from the end
trimHeadAndTail(recorder);
// offset = 2, because we need to get past this element as well as the end
// element
ec.getSaxEventInterpreter().getEventPlayer().addEventsDynamically(recorder.getSaxEventList(), 2);
}
} catch (JoranException je) {
addError("Error while parsing " + attributeInUse, je);
} finally {
close(in);
}
}
// model created for later use, not necessarily for configuration purposes.
private void createModelForAlternateUse(SaxEventInterpretationContext seic, String name, Attributes attributes,
String optionalStr) {
this.includeModel = new IncludeModel();
this.includeModel.setOptional(optionalStr);
fillInIncludeModelAttributes(includeModel, name, attributes);
if (!seic.isModelStackEmpty()) {
parentModel = seic.peekModel();
}
final int lineNumber = getLineNumber(seic);
this.includeModel.setLineNumber(lineNumber);
seic.pushModel(includeModel);
}
private void fillInIncludeModelAttributes(IncludeModel includeModel, String name, Attributes attributes) {
this.includeModel.setTag(name);
String fileAttribute = attributes.getValue(FILE_ATTR);
String urlAttribute = attributes.getValue(URL_ATTR);
String resourceAttribute = attributes.getValue(RESOURCE_ATTR);
this.includeModel.setFile(fileAttribute);
this.includeModel.setUrl(urlAttribute);
this.includeModel.setResource(resourceAttribute);
}
void close(InputStream in) {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
private boolean checkAttributes(Attributes attributes) {
String fileAttribute = attributes.getValue(FILE_ATTR);
String urlAttribute = attributes.getValue(URL_ATTR);
String resourceAttribute = attributes.getValue(RESOURCE_ATTR);
int count = 0;
if (!OptionHelper.isNullOrEmpty(fileAttribute)) {
count++;
}
if (!OptionHelper.isNullOrEmpty(urlAttribute)) {
count++;
}
if (!OptionHelper.isNullOrEmpty(resourceAttribute)) {
count++;
}
if (count == 0) {
addError("One of \"path\", \"resource\" or \"url\" attributes must be set.");
return false;
} else if (count > 1) {
addError("Only one of \"file\", \"url\" or \"resource\" attributes should be set.");
return false;
} else if (count == 1) {
return true;
}
throw new IllegalStateException("Count value [" + count + "] is not expected");
}
URL attributeToURL(String urlAttribute) {
try {
return new URL(urlAttribute);
} catch (MalformedURLException mue) {
String errMsg = "URL [" + urlAttribute + "] is not well formed.";
addError(errMsg, mue);
return null;
}
}
InputStream openURL(URL url) {
try {
return url.openStream();
} catch (IOException e) {
optionalWarning("Failed to open [" + url.toString() + "]");
return null;
}
}
URL resourceAsURL(String resourceAttribute) {
URL url = Loader.getResourceBySelfClassLoader(resourceAttribute);
if (url == null) {
optionalWarning("Could not find resource corresponding to [" + resourceAttribute + "]");
return null;
} else
return url;
}
private void optionalWarning(String msg) {
if (!optional) {
addWarn(msg);
}
}
URL filePathAsURL(String path) {
URI uri = new File(path).toURI();
try {
return uri.toURL();
} catch (MalformedURLException e) {
// impossible to get here
e.printStackTrace();
return null;
}
}
URL getInputURL(SaxEventInterpretationContext ec, Attributes attributes) {
String fileAttribute = attributes.getValue(FILE_ATTR);
String urlAttribute = attributes.getValue(URL_ATTR);
String resourceAttribute = attributes.getValue(RESOURCE_ATTR);
if (!OptionHelper.isNullOrEmpty(fileAttribute)) {
this.attributeInUse = ec.subst(fileAttribute);
return filePathAsURL(attributeInUse);
}
if (!OptionHelper.isNullOrEmpty(urlAttribute)) {
this.attributeInUse = ec.subst(urlAttribute);
return attributeToURL(attributeInUse);
}
if (!OptionHelper.isNullOrEmpty(resourceAttribute)) {
this.attributeInUse = ec.subst(resourceAttribute);
return resourceAsURL(attributeInUse);
}
// given previous checkAttributes() check we cannot reach this line
throw new IllegalStateException("A URL stream should have been returned");
}
InputStream getInputStream(SaxEventInterpretationContext ec, Attributes attributes) {
URL inputURL = getInputURL(ec, attributes);
if (inputURL == null)
return null;
ConfigurationWatchListUtil.addToWatchList(context, inputURL);
return openURL(inputURL);
}
private void trimHeadAndTail(SaxEventRecorder recorder) {
// Let's remove the two events before
// adding the events to the player.
// note saxEventList.size() changes over time as events are removed
List saxEventList = recorder.getSaxEventList();
if (saxEventList.size() == 0) {
return;
}
SaxEvent first = saxEventList.get(0);
if (first != null && first.qName.equalsIgnoreCase(INCLUDED_TAG)) {
saxEventList.remove(0);
}
SaxEvent last = saxEventList.get(saxEventList.size() - 1);
if (last != null && last.qName.equalsIgnoreCase(INCLUDED_TAG)) {
saxEventList.remove(saxEventList.size() - 1);
}
}
private void parseAndRecord(InputStream inputSource, SaxEventRecorder recorder) throws JoranException {
recorder.setContext(context);
recorder.recordEvents(inputSource);
}
@Override
public void end(SaxEventInterpretationContext seic, String name) throws ActionException {
if(inError)
return;
Model m = seic.peekModel();
if (m != includeModel) {
addWarn("The object at the of the stack is not the model [" + includeModel.idString()
+ "] pushed earlier.");
addWarn("This is wholly unexpected.");
}
// do not pop nor add to parent if there is no parent
if (parentModel != null) {
parentModel.addSubModel(includeModel);
seic.popModel();
}
}
}