001/*
002 * *********************************************************************** *
003 * project: org.matsim.*
004 * *********************************************************************** *
005 *                                                                         *
006 * copyright       : (C) 2019 by the members listed in the COPYING,        *
007 *                   LICENSE and WARRANTY file.                            *
008 * email           : info at matsim dot org                                *
009 *                                                                         *
010 * *********************************************************************** *
011 *                                                                         *
012 *   This program is free software; you can redistribute it and/or modify  *
013 *   it under the terms of the GNU General Public License as published by  *
014 *   the Free Software Foundation; either version 2 of the License, or     *
015 *   (at your option) any later version.                                   *
016 *   See also COPYING, LICENSE and WARRANTY file                           *
017 *                                                                         *
018 * *********************************************************************** *
019 */
020
021package org.matsim.contrib.dvrp.run;
022
023import java.util.function.Function;
024
025import org.matsim.core.controler.listener.ControlerListener;
026import org.matsim.core.mobsim.framework.listeners.MobsimInitializedListener;
027import org.matsim.core.mobsim.framework.listeners.MobsimListener;
028
029import com.google.inject.Provider;
030
031/**
032 * Typical usecase: binding multi-iteration object stats calculators to overcome the limitation of the QSim scope of Fleet.
033 * Notifies objectListener to that the object has been created.
034 * <p>
035 * If objectListener is also ControllerListener and/or MobsimListener, which is quite typical,
036 * addControlerListenerBinding() and/or addModalComponent() will be called, respectively.
037 *
038 * @author Michal Maciejewski (michalm)
039 */
040public final class QSimScopeObjectListenerModule<T, L extends QSimScopeObjectListener<T> & ControlerListener & MobsimListener>
041                extends AbstractDvrpModeModule {
042        //without requiring listenerClass to implement ControlerListener & MobsimListener
043        public static <T> AbstractDvrpModeQSimModule createSimplifiedModule(String mode, Class<T> objectClass,
044                        Class<? extends QSimScopeObjectListener<T>> listenerClass) {
045                return new AbstractDvrpModeQSimModule(mode) {
046                        @Override
047                        protected void configureQSim() {
048                                addModalQSimComponentBinding().toProvider(modalProvider(
049                                                getter -> mobsimInitializedListener(getter.getModal(listenerClass),
050                                                                getter.getModal(objectClass))));
051                        }
052                };
053        }
054
055        private final Class<T> objectClass;
056        private final Class<L> listenerClass;
057        private final Provider<L> listenerProvider;
058
059        private QSimScopeObjectListenerModule(Builder<T, L> builder) {
060                super(builder.mode);
061                objectClass = builder.objectClass;
062                listenerClass = builder.listenerClass;
063                listenerProvider = builder.listenerProvider;
064        }
065
066        @Override
067        public void install() {
068                bindModal(listenerClass).toProvider(listenerProvider).asEagerSingleton();
069                addControlerListenerBinding().to(modalKey(listenerClass));
070
071                installQSimModule(new AbstractDvrpModeQSimModule(getMode()) {
072                        @Override
073                        protected void configureQSim() {
074                                addModalQSimComponentBinding().to(modalKey(listenerClass));
075                                addModalQSimComponentBinding().toProvider(modalProvider(
076                                                getter -> mobsimInitializedListener(getter.getModal(listenerClass),
077                                                                getter.getModal(objectClass))));
078                        }
079                });
080        }
081
082        private static <T> MobsimInitializedListener mobsimInitializedListener(QSimScopeObjectListener<T> objectListener,
083                        T object) {
084                return e -> objectListener.objectCreated(object);
085        }
086
087        public static <T, L extends QSimScopeObjectListener<T> & ControlerListener & MobsimListener> Builder<T, L> builder(
088                        Class<L> listenerClass) {
089                return new Builder<>(listenerClass);
090        }
091
092        public static final class Builder<T, L extends QSimScopeObjectListener<T> & ControlerListener & MobsimListener> {
093                private final Class<L> listenerClass;
094                private String mode;
095                private Class<T> objectClass;
096                private Provider<L> listenerProvider;
097
098                private Builder(Class<L> listenerClass) {
099                        this.listenerClass = listenerClass;
100                }
101
102                public Builder<T, L> mode(String val) {
103                        mode = val;
104                        return this;
105                }
106
107                public Builder<T, L> objectClass(Class<T> val) {
108                        objectClass = val;
109                        return this;
110                }
111
112                public Builder<T, L> listenerCreator(Function<ModalProviders.InstanceGetter, L> val) {
113                        listenerProvider = ModalProviders.createProvider(mode, val);
114                        return this;
115                }
116
117                public Builder<T, L> listenerProvider(Provider<L> val) {
118                        listenerProvider = val;
119                        return this;
120                }
121
122                public QSimScopeObjectListenerModule<T, L> build() {
123                        return new QSimScopeObjectListenerModule<>(this);
124                }
125        }
126}