001package org.intellimate.izou.sdk;
002
003import org.apache.logging.log4j.spi.ExtendedLogger;
004import org.intellimate.izou.addon.AddOnModel;
005import org.intellimate.izou.identification.Identifiable;
006import org.intellimate.izou.identification.Identification;
007import org.intellimate.izou.identification.IllegalIDException;
008import org.intellimate.izou.sdk.contentgenerator.EventListener;
009import org.intellimate.izou.sdk.properties.PropertiesAssistant;
010import org.intellimate.izou.sdk.specification.ContentGeneratorModel;
011import org.intellimate.izou.sdk.specification.context.ContentGenerators;
012import org.intellimate.izou.system.context.*;
013import org.intellimate.izou.system.context.System;
014
015import java.util.List;
016import java.util.Objects;
017import java.util.concurrent.ExecutorService;
018
019/**
020 * The Izou context is a means for all addOns to get general information they might need. Every addOn its own context
021 * and can use it to reach certain Izou components. It controls what an addOn has access to and what it does not have
022 * access to.
023 * <br>
024 * For instance, the addOn should have access to a logger (created in Izou for the addOn), but it should not have
025 * access to classes like the AddOnManager, which loads all addOns at the start. Hence the logger is included in the
026 * context, but the addOn manager is not. Anything that is not included in the context, and addOn does not have access to.
027 * So in short, the context exists to give addOns access to higher Izou components while still denying access to other
028 * components.
029 */
030public class Context implements org.intellimate.izou.system.Context {
031    private final PropertiesAssistant propertiesAssistant;
032    private final org.intellimate.izou.system.Context context;
033    private final org.intellimate.izou.sdk.specification.context.ThreadPool threadPool;
034    private final ContentGenerators contentGenerators;
035
036    /**
037     * Creates a context for the addOn.
038     * @param context the context to use
039     */
040    public Context(org.intellimate.izou.system.Context context) {
041        this.context = context;
042        threadPool = new ThreadPoolImpl();
043        contentGenerators = new ContentGeneratorsImpl();
044        propertiesAssistant = new PropertiesAssistant(this, getAddOn().getID());
045    }
046
047    /**
048     * Gets the API used for the Properties
049     *
050     * @return Properties
051     */
052    public PropertiesAssistant getPropertiesAssistant() {
053        return propertiesAssistant;
054    }
055
056    /**
057     * returns the API used for interaction with Events
058     *
059     * @return Events
060     */
061    @Override
062    public Events getEvents() {
063        return context.getEvents();
064    }
065
066    /**
067     * returns the API used for interaction with Resource
068     *
069     * @return Resource
070     */
071    @Override
072    public Resources getResources() {
073        return context.getResources();
074    }
075
076    /**
077     * returns the API used for interaction with Files
078     *
079     * @return Files
080     */
081    @Override
082    public Files getFiles() {
083        return context.getFiles();
084    }
085
086    /**
087     * returns the API used to log
088     * @return Logger
089     */
090    @Override
091    public ExtendedLogger getLogger() {
092        return context.getLogger();
093    }
094
095    /**
096     * returns the API used to manage the ThreadPool
097     *
098     * @return ThreadPool
099     */
100    @Override
101    public org.intellimate.izou.sdk.specification.context.ThreadPool getThreadPool() {
102        return threadPool;
103    }
104
105    /**
106     * returns the API to manage the Activators
107     *
108     * @return Activator
109     */
110    @Override
111    public Activators getActivators() {
112        return context.getActivators();
113    }
114
115    /**
116     * returns the API used to manage the OutputPlugins and OutputExtensions
117     *
118     * @return Output
119     */
120    @Override
121    public Output getOutput() {
122        return context.getOutput();
123    }
124
125    @Override
126    public System getSystem() {
127        return context.getSystem();
128    }
129
130    /**
131     * returns the API used to manage the ContentGenerators
132     * @return ContentGenerator
133     */
134    public ContentGenerators getContentGenerators() {
135        return contentGenerators;
136    }
137
138    /**
139     * gets addOn
140     *
141     * @return the addOn
142     */
143    @Override
144    public AddOnModel getAddOn() {
145        return context.getAddOn();
146    }
147
148    private class ContentGeneratorsImpl implements ContentGenerators {
149
150        /**
151         * Register an ContentGenerator
152         *
153         * @param contentGenerator the contentGenerator to register
154         * @throws IllegalIDException not implemented yet
155         */
156        @Override
157        public void registerContentGenerator(ContentGeneratorModel contentGenerator) throws IllegalIDException {
158            List<? extends EventListener> triggeredEvents = contentGenerator.getTriggeredEvents();
159            if (triggeredEvents != null) {
160                triggeredEvents.stream()
161                        .filter(Objects::nonNull)
162                        .forEach(propertiesAssistant.getEventPropertiesAssistant()::registerEventListener);
163            }
164            getResources().registerResourceBuilder(contentGenerator);
165        }
166
167        /**
168         * Unregisters an ContentGenerator
169         *
170         * @param contentGenerator the ContentGenerator to unregister
171         */
172        @Override
173        public void unregisterContentGenerator(ContentGeneratorModel contentGenerator) {
174            List<? extends EventListener> triggeredEvents = contentGenerator.getTriggeredEvents();
175            for (EventListener eventListener : triggeredEvents) {
176                propertiesAssistant.getEventPropertiesAssistant().unregisterEventID(eventListener.getDescriptorID());
177            }
178            getResources().unregisterResourceBuilder(contentGenerator);
179        }
180    }
181
182    private class ThreadPoolImpl implements org.intellimate.izou.sdk.specification.context.ThreadPool {
183        private ExecutorService executorService = null;
184
185        /**
186         * returns a ThreadPool associated with the AddOn
187         *
188         * @return an instance of ExecutorService or Null if there is a problem with the Identifier
189         */
190        @Override
191        public ExecutorService getThreadPool() {
192            if (executorService != null) {
193                return executorService;
194            } else {
195                try {
196                    executorService = getThreadPool(getAddOn());
197                } catch (IllegalIDException e) {
198                    getLogger().error("Unable to obtain ExecutorService", e);
199                    return null;
200                }
201                return executorService;
202            }
203        }
204
205        /**
206         * returns a NEW ThreadPool where all the IzouPlugins are running
207         *
208         * @param identifiable the Identifiable to set each created Task as the Source
209         * @return an instance of ExecutorService
210         * @throws org.intellimate.izou.identification.IllegalIDException not implemented yet
211         */
212        @Override
213        public ExecutorService getThreadPool(Identifiable identifiable) throws IllegalIDException {
214            return context.getThreadPool().getThreadPool(identifiable);
215        }
216
217        /**
218         * tries everything to log the exception
219         *
220         * @param throwable the Throwable
221         * @param target    an instance of the thing which has thrown the Exception
222         */
223        @Override
224        public void handleThrowable(Throwable throwable, Object target) {
225            context.getThreadPool().handleThrowable(throwable, target);
226        }
227
228        /**
229         * returns the ID of the Manager
230         */
231        @Override
232        public Identification getManagerIdentification() {
233            return context.getThreadPool().getManagerIdentification();
234        }
235    }
236}