001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, 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 */
014package ch.qos.logback.core.sift;
015
016import java.util.Collection;
017import java.util.Map;
018
019import ch.qos.logback.core.Appender;
020import ch.qos.logback.core.Context;
021import ch.qos.logback.core.joran.JoranConstants;
022import ch.qos.logback.core.joran.ParamModelHandler;
023import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
024import ch.qos.logback.core.joran.spi.JoranException;
025import ch.qos.logback.core.model.AppenderModel;
026import ch.qos.logback.core.model.ImplicitModel;
027import ch.qos.logback.core.model.Model;
028import ch.qos.logback.core.model.ParamModel;
029import ch.qos.logback.core.model.PropertyModel;
030import ch.qos.logback.core.model.SiftModel;
031import ch.qos.logback.core.model.processor.AppenderModelHandler;
032import ch.qos.logback.core.model.processor.ImplicitModelHandler;
033import ch.qos.logback.core.model.processor.ModelInterpretationContext;
034import ch.qos.logback.core.model.processor.PropertyModelHandler;
035
036/**
037 * Builds new appenders dynamically by running SiftingJoranConfigurator instance,
038 * a custom configurator tailored for the contents of the sift element.
039 * @param <E>
040 */
041public class AppenderFactoryUsingSiftModel<E> implements AppenderFactory<E> {
042    
043    Context context;
044    final Model siftModel;
045    protected String discriminatingKey;
046    protected ModelInterpretationContext parentMic;
047    protected DefaultNestedComponentRegistry registry;
048    
049    public AppenderFactoryUsingSiftModel(ModelInterpretationContext parentMic, Model aSiftModel, String discriminatingKey)  {
050        this.siftModel = Model.duplicate(aSiftModel);
051        this.discriminatingKey = discriminatingKey;
052        this.parentMic = parentMic;
053        this.context = parentMic.getContext();
054      
055    }
056
057
058    public SiftProcessor<E> getSiftingModelProcessor(String value) {
059        ModelInterpretationContext smic = new ModelInterpretationContext(parentMic) {
060            @Override
061            public boolean hasDependers(String dependeeName) {
062                return true;
063            } 
064        };
065        SiftProcessor<E> siftProcessor = new SiftProcessor<>(context, smic); 
066        siftProcessor.addHandler(ParamModel.class, ParamModelHandler::makeInstance);
067        siftProcessor.addHandler(PropertyModel.class, PropertyModelHandler::makeInstance);
068        siftProcessor.addHandler(ImplicitModel.class, ImplicitModelHandler::makeInstance);
069        siftProcessor.addHandler(AppenderModel.class, AppenderModelHandler::makeInstance);
070        siftProcessor.addHandler(SiftModel.class, NOPSiftModelHandler::makeInstance);
071        
072        return siftProcessor;
073
074    }
075
076    public Appender<E> buildAppender(Context context, String discriminatingValue) throws JoranException {
077        
078        SiftProcessor<E> sp = getSiftingModelProcessor(discriminatingValue);
079        ModelInterpretationContext mic = sp.getModelInterpretationContext();
080        sp.setContext(context);
081        Model duplicate = Model.duplicate(siftModel);
082        mic.addSubstitutionProperty(discriminatingKey, discriminatingValue);
083        sp.process(duplicate);
084        @SuppressWarnings("unchecked")
085        Map<String, Appender<E>> appenderBag = (Map<String, Appender<E>>) mic.getObjectMap()
086                .get(JoranConstants.APPENDER_BAG);
087        Collection<Appender<E>> values = appenderBag.values();
088        if (values.size() == 0) {
089            return null;
090        }
091        return values.iterator().next();
092    }
093
094    public Model getSiftModel() {
095        return siftModel;
096    }
097
098}