001/*
002 * (C) Copyright 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 *     Kevin Leturc <kleturc@nuxeo.com>
018 *     Anahide Tchertchian
019 */
020package org.nuxeo.runtime;
021
022import java.util.ArrayList;
023import java.util.List;
024import java.util.Set;
025import java.util.function.Predicate;
026import java.util.stream.Collectors;
027
028import org.nuxeo.runtime.RuntimeMessage.Level;
029import org.nuxeo.runtime.RuntimeMessage.Source;
030import org.nuxeo.runtime.model.ComponentManager;
031
032/**
033 * Handles runtime messages by taking care of component manager lifecycle in order to work correctly with hot reload.
034 * This is interesting to not store several time the same message in case of hot reload.
035 *
036 * @since 9.10
037 */
038public class RuntimeMessageHandlerImpl implements RuntimeMessageHandler, ComponentManager.Listener {
039
040    protected ComponentManagerStep step;
041
042    protected final List<RuntimeMessage> messages = new ArrayList<>();
043
044    @Override
045    @Deprecated
046    public void addWarning(String message) {
047        addMessage(new RuntimeMessage(Level.WARNING, message, Source.UNKNOWN, null));
048    }
049
050    @Override
051    @Deprecated
052    public List<String> getWarnings() {
053        return getMessages(Level.WARNING);
054    }
055
056    @Override
057    @Deprecated
058    public void addError(String message) {
059        addMessage(new RuntimeMessage(Level.ERROR, message, Source.UNKNOWN, null));
060    }
061
062    @Override
063    @Deprecated
064    public List<String> getErrors() {
065        return getMessages(Level.ERROR);
066    }
067
068    @Override
069    public void beforeActivation(ComponentManager mgr) {
070        changeStep(ComponentManagerStep.ACTIVATING);
071    }
072
073    @Override
074    public void beforeStart(ComponentManager mgr, boolean isResume) {
075        changeStep(ComponentManagerStep.STARTING);
076    }
077
078    @Override
079    public void afterStart(ComponentManager mgr, boolean isResume) {
080        changeStep(ComponentManagerStep.RUNNING);
081    }
082
083    @Override
084    public void beforeStop(ComponentManager mgr, boolean isStandby) {
085        changeStep(ComponentManagerStep.STOPPING);
086    }
087
088    @Override
089    public void beforeDeactivation(ComponentManager mgr) {
090        changeStep(ComponentManagerStep.DEACTIVATING);
091    }
092
093    protected void changeStep(ComponentManagerStep step) {
094        if (this.step == ComponentManagerStep.RUNNING) {
095            // reset bundle/component/extension messages when previous step was "running"
096            messages.removeIf(m -> Set.of(Source.BUNDLE, Source.COMPONENT, Source.EXTENSION).contains(m.getSource()));
097        }
098        this.step = step;
099    }
100
101    @Override
102    public void addMessage(RuntimeMessage message) {
103        messages.add(message);
104    }
105
106    @Override
107    public List<String> getMessages(Level level) {
108        return getMessages(msg -> level.equals(msg.getLevel()));
109    }
110
111    @Override
112    public List<String> getMessages(Predicate<RuntimeMessage> predicate) {
113        return messages.stream()
114                       .filter(predicate)
115                       .map(RuntimeMessage::getMessage)
116                       .collect(Collectors.toUnmodifiableList());
117    }
118
119    @Override
120    public List<RuntimeMessage> getRuntimeMessages(Level level) {
121        return getRuntimeMessages(msg -> level.equals(msg.getLevel()));
122    }
123
124    @Override
125    public List<RuntimeMessage> getRuntimeMessages(Predicate<RuntimeMessage> predicate) {
126        return messages.stream().filter(predicate).collect(Collectors.toUnmodifiableList());
127    }
128
129    protected enum ComponentManagerStep {
130
131        ACTIVATING,
132
133        STARTING,
134
135        RUNNING,
136
137        STOPPING,
138
139        DEACTIVATING
140
141    }
142
143}