001/*
002 * (C) Copyright 2006-2017 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Bogdan Stefanescu
018 *     Florent Guillaume
019 */
020package org.nuxeo.runtime.model;
021
022import java.util.Collection;
023import java.util.Map;
024import java.util.Set;
025
026import org.nuxeo.runtime.ComponentListener;
027import org.nuxeo.runtime.api.Framework;
028import org.nuxeo.runtime.model.impl.DefaultRuntimeContext;
029
030/**
031 * @author Bogdan Stefanescu
032 * @author Florent Guillaume
033 */
034public interface ComponentManager {
035
036    /**
037     * Adds a component listener.
038     * <p>
039     * Does nothing if the given listener is already registered.
040     *
041     * @param listener the component listener to add
042     */
043    void addComponentListener(ComponentListener listener);
044
045    /**
046     * Removes a component listener.
047     * <p>
048     * Does nothing if the given listener is not registered.
049     *
050     * @param listener the component listener to remove
051     */
052    void removeComponentListener(ComponentListener listener);
053
054    /**
055     * Handles the registration of the given registration info.
056     * <p>
057     * This is called by the main registry when all dependencies of this registration info were solved and the object
058     * can be registered.
059     * <p>
060     * If true is returned, the object will be added to the main registry under the name given in RegistrationInfo.
061     *
062     * @param ri the registration info
063     */
064    void register(RegistrationInfo ri);
065
066    /**
067     * Handles the unregistration of the given registration info.
068     * <p>
069     * This is called by the main registry when the object is unregistered.
070     * <p>
071     * If true is returned, the object will be removed from the main registry.
072     *
073     * @param ri the registration info
074     */
075    void unregister(RegistrationInfo ri);
076
077    /**
078     * Unregisters a component given its name.
079     *
080     * @param name the component name
081     */
082    void unregister(ComponentName name);
083
084    /**
085     * This method was added only to support unregistering by location which is used by some tests. Removing by location
086     * should be managed at a higher level (it is useful only for tests) and this method should be removed
087     *
088     * @param sourceId the location from where the component was deployed
089     * @return false if no component was registered from that location, true otherwise
090     * @see DefaultRuntimeContext for more on this
091     * @since 9.2
092     * @deprecated since 9.2
093     */
094    @Deprecated
095    boolean unregisterByLocation(String sourceId);
096
097    /**
098     * Given a source location tests if a component was deployed from that location <br>
099     * This method was added to support undeploying by location needed by tests. Should be removed and a test specific
100     * helper implemented to support locations
101     *
102     * @deprecated since 9.2
103     */
104    @Deprecated
105    boolean hasComponentFromLocation(String sourceId);
106
107    /**
108     * Gets the component if there is one having the given name.
109     *
110     * @param name the component name
111     * @return the component if any was registered with that name, null otherwise
112     */
113    RegistrationInfo getRegistrationInfo(ComponentName name);
114
115    /**
116     * Gets object instance managed by the named component.
117     *
118     * @param name the object name
119     * @return the object instance if any. may be null
120     */
121    ComponentInstance getComponent(ComponentName name);
122
123    /**
124     * Checks whether or not a component with the given name was registered.
125     *
126     * @param name the object name
127     * @return true if an object with the given name was registered, false otherwise
128     */
129    boolean isRegistered(ComponentName name);
130
131    /**
132     * Gets the registered components.
133     *
134     * @return a read-only collection of components
135     */
136    Collection<RegistrationInfo> getRegistrations();
137
138    /**
139     * Gets the pending registrations and their dependencies.
140     *
141     * @return the pending registrations
142     */
143    Map<ComponentName, Set<ComponentName>> getPendingRegistrations();
144
145    /**
146     * Returns the missing registrations, linked to missing target extension points.
147     *
148     * @since 8.10
149     */
150    Map<ComponentName, Set<Extension>> getMissingRegistrations();
151
152    /**
153     * Gets the pending extensions by component.
154     *
155     * @return the pending extensions
156     */
157    Collection<ComponentName> getActivatingRegistrations();
158
159    /**
160     * Gets the resolved component names in the order they were resolved
161     *
162     * @since 9.2
163     */
164    Collection<ComponentName> getResolvedRegistrations();
165
166    /**
167     * Gets the components that fail on applicationStarted notification
168     *
169     * @since 7.4
170     */
171    Collection<ComponentName> getStartFailureRegistrations();
172
173    /**
174     * Gets the number of registered objects in this registry.
175     *
176     * @return the number of registered objects
177     */
178    int size();
179
180    /**
181     * Shuts down the component registry.
182     * <p>
183     * This unregisters all objects registered in this registry.
184     */
185    void shutdown();
186
187    /**
188     * Gets the service of type serviceClass if such a service was declared by a resolved runtime component.
189     * <p>
190     * If the component is not yet activated it will be prior to return the service.
191     *
192     * @param <T> the service type
193     * @param serviceClass the service class
194     * @return the service object
195     */
196    <T> T getService(Class<T> serviceClass);
197
198    /**
199     * Get the list of all registered service names An empty array is returned if no registered services are found.
200     *
201     * @return an array of registered service.
202     */
203    String[] getServices();
204
205    /**
206     * Gets the component that provides the given service.
207     *
208     * @param serviceClass the service class
209     * @return the component or null if none
210     */
211    ComponentInstance getComponentProvidingService(Class<?> serviceClass);
212
213    Set<String> getBlacklist();
214
215    void setBlacklist(Set<String> blacklist);
216
217    /**
218     * Activate and start all resolved components. If components were already started do nothing.
219     *
220     * @return false if components were already started, true otherwise
221     * @since 9.2
222     */
223    boolean start();
224
225    /**
226     * Stop and deactivate all resolved components. If components were not yet started do nothing
227     *
228     * @return false if components were not yet started, true otherwise
229     * @since 9.2
230     */
231    boolean stop();
232
233    /**
234     * Same as {@link #stop()} but log a warning if the timeout is reached while stopping components
235     *
236     * @since 9.2
237     */
238    void stop(int timeout);
239
240    /**
241     * Stop all started components but don't deactivate them. After calling this method you can safely contribute new
242     * extensions (i.e. modify extension registries).
243     * <p>
244     * If any components were previously started do nothing
245     *
246     * @since 9.2
247     */
248    void standby();
249
250    /**
251     * Same as {@link #standby()} but log a warning if the timeout is reached while stopping components
252     *
253     * @since 9.2
254     */
255    void standby(int timeout);
256
257    /**
258     * Start standby components. If components are not in standby mode the it does nothing.
259     *
260     * @since 9.2
261     */
262    void resume();
263
264    /**
265     * Make a snapshot of the component registry. When calling restart
266     *
267     * @since 9.2
268     */
269    void snapshot();
270
271    /**
272     * Optionally reset the registry to the last snapshot and restart the components.
273     * <p>
274     * When restarting components all components will be stopped, deactivated and re-instantiated. It means that all
275     * references to components before a restart will become invalid after the restart.
276     * <p>
277     * If no snapshot was created then the components will be restarted without changing the registry.
278     * <p>
279     * If the <code>reset</code> argument is true then the registry will be reverted to the last snapshot before
280     * starting the components.
281     *
282     * @param reset whether or not to revert to the last snapshot
283     * @since 9.2
284     */
285    void restart(boolean reset);
286
287    /**
288     * Reset the registry to the last snapshot if any and stop the components (if they are currently started). After a
289     * reset all the components are stopped so we can contribute new components if needed. You must call
290     * {@link #start()} to start again the components
291     *
292     * @return true if the components were stopped, false otherwise
293     * @since 9.2
294     */
295    boolean reset();
296
297    /**
298     * Refresh the registry using stashed registrations if any. If the <code>reset</code> argument is true then the
299     * registry will be reverted to the last snapshot before applying the stash.
300     * <p>
301     * If the stash is empty it does nothing and return true, otherwise it will:
302     * <ol>
303     * <li>stop the components (if they are started)
304     * <li>revert to the last snapshot (if reset flag is true)
305     * <li>apply the stash (the stash will remain empty after this operation)
306     * <li>start the components (if they was started)
307     * </ol>
308     *
309     * @param reset whether or not to revert to the last snapshot
310     * @return false if stash is empty and nothing was done, true otherwise
311     * @since 9.2
312     */
313    boolean refresh(boolean reset);
314
315    /**
316     * Shortcut for refresh(false).
317     *
318     * @see #refresh(boolean)
319     * @since 9.2
320     */
321    default boolean refresh() {
322        return refresh(false);
323    }
324
325    /**
326     * Tests whether the components were already started.
327     *
328     * @return true if components are started, false
329     * @since 9.2
330     */
331    boolean isStarted();
332
333    /**
334     * Tests whether the components are in standby mode. That means they were started and then stopped - waiting to be
335     * started again.
336     * <p>
337     * When putting components in standby they are stopped but not deactivated. You start back the standby components by
338     * calling #resume
339     * <p>
340     * While in standby mode the component manager remains in running state.
341     *
342     * @since 9.2
343     */
344    boolean isStandby();
345
346    /**
347     * Tests whether the components are running. That means they are either started either in standby mode.
348     *
349     * @since 9.2
350     */
351    boolean isRunning();
352
353    /**
354     * Tests whether components were deployed over the initial snapshot (i.e. the actual registry differs from the
355     * snapshot) If no snapshot was done returns false.
356     *
357     * @since 9.2
358     */
359    boolean hasChanged();
360
361    /**
362     * Check if a snapshot was done
363     *
364     * @return true if a snapshot already exists, false otherwise
365     * @since 9.2
366     */
367    boolean hasSnapshot();
368
369    /**
370     * Tests if the stash is empty
371     *
372     * @since 9.2
373     */
374    boolean isStashEmpty();
375
376    /**
377     * Apply the stash if not empty. This is a low level operation and may not be safe to call when the component
378     * manager is running {@link #isRunning()}.
379     * <p>
380     * For compatibility reasons (to be able to emulate the old hot deploy mechanism or to speed up tests) this method
381     * will force a registry refresh in all 3 component manager states: stopped, standby, started.
382     * <p>
383     * Usually you should apply the stash by calling {@link #refresh()} which is similar to
384     * <code>stop(); [restoreSnapshot();] unstash(); start();</code>
385     *
386     * @since 9.2
387     */
388    void unstash();
389
390    /**
391     * Add a listener to be notified on manager actions like start / stop components.
392     *
393     * @since 9.2
394     */
395    void addListener(ComponentManager.Listener listener);
396
397    /**
398     * Remove the component manager listener previously added by {@link #addListener(Listener)}. If the listener were
399     * not added then nothing is done.
400     *
401     * @since 9.2
402     */
403    void removeListener(ComponentManager.Listener listener);
404
405    /**
406     * Listener interface for component manager events
407     *
408     * @author bogdan
409     * @since 9.2
410     */
411    interface Listener {
412
413        /**
414         * Called just before activating components. This is fired when entering {@link ComponentManager#start()}
415         */
416        default void beforeActivation(ComponentManager mgr) {
417        }
418
419        /**
420         * Called just after all the components were activated.
421         */
422        default void afterActivation(ComponentManager mgr) {
423        }
424
425        /**
426         * Called just before activating components.
427         */
428        default void beforeDeactivation(ComponentManager mgr) {
429        }
430
431        /**
432         * Called just after all the components were deactivated. This is fired just before exiting from
433         * {@link ComponentManager#stop()}.
434         */
435        default void afterDeactivation(ComponentManager mgr) {
436        }
437
438        /**
439         * Called just before starting components.
440         *
441         * @param isResume true if the event was initiated by a {@link ComponentManager#resume()} call, false otherwise.
442         */
443        default void beforeStart(ComponentManager mgr, boolean isResume) {
444        }
445
446        /**
447         * Called just after all components were started
448         *
449         * @param isResume true if the event was initiated by a {@link ComponentManager#resume()} call, false otherwise.
450         */
451        default void afterStart(ComponentManager mgr, boolean isResume) {
452        }
453
454        /**
455         * Called just before stopping components.
456         *
457         * @param isStandby true if the event was initiated by a {@link ComponentManager#standby()} call, false
458         *            otherwise
459         */
460        default void beforeStop(ComponentManager mgr, boolean isStandby) {
461        }
462
463        /**
464         * Called just after the components were stopped.
465         *
466         * @param isStandby true if the event was initiated by a {@link ComponentManager#standby()} call, false
467         *            otherwise
468         */
469        default void afterStop(ComponentManager mgr, boolean isStandby) {
470        }
471
472        default Listener install() {
473            Framework.getRuntime().getComponentManager().addListener(this);
474            return this;
475        }
476
477        default Listener uninstall() {
478            Framework.getRuntime().getComponentManager().removeListener(this);
479            return this;
480        }
481
482    }
483
484}