Merge "Fix sonars in policy models"
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / main / java / org / onap / policy / controlloop / actorserviceprovider / ActorService.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ActorService
4  * ================================================================================
5  * Copyright (C) 2017-2018, 2020-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.controlloop.actorserviceprovider;
23
24 import com.google.common.collect.ImmutableMap;
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.LinkedList;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.ServiceConfigurationError;
32 import java.util.ServiceLoader;
33 import java.util.Set;
34 import org.onap.policy.controlloop.actorserviceprovider.impl.StartConfigPartial;
35 import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
36 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 /**
41  * Service that manages a set of actors. To use the service, first invoke
42  * {@link #configure(Map)} to configure all of the actors, and then invoke
43  * {@link #start()} to start all of the actors. When finished using the actor service,
44  * invoke {@link #stop()} or {@link #shutdown()}.
45  */
46 public class ActorService extends StartConfigPartial<Map<String, Object>> {
47     private static final Logger logger = LoggerFactory.getLogger(ActorService.class);
48
49     private final Map<String, Actor> name2actor;
50
51     /**
52      * Constructs the object and loads the list of actors.
53      */
54     public ActorService() {
55         super("actors");
56
57         Map<String, Actor> map = new HashMap<>();
58
59         for (Actor newActor : buildList()) {
60             map.compute(newActor.getName(), (name, existingActor) -> {
61                 if (existingActor == null) {
62                     return newActor;
63                 }
64
65                 logger.warn("duplicate actor names for {}: {}, ignoring {}", name,
66                                 existingActor.getClass().getSimpleName(), newActor.getClass().getSimpleName());
67                 return existingActor;
68             });
69         }
70
71         name2actor = ImmutableMap.copyOf(map);
72     }
73
74     /**
75      * Builds the list of actors, discarding those that cannot be constructed.
76      *
77      * @return the list of actors, sorted by ascending sequence number
78      */
79     private List<Actor> buildList() {
80         List<Actor> actors = new LinkedList<>();
81
82         Iterator<Actor> iter = loadActors().iterator();
83         while (iter.hasNext()) {
84             try {
85                 actors.add(iter.next());
86             } catch (ServiceConfigurationError e) {
87                 logger.warn("unable to load actor", e);
88             }
89         }
90
91         actors.sort((actor1, actor2) -> {
92             var cmp = Integer.compare(actor1.getSequenceNumber(), actor2.getSequenceNumber());
93             if (cmp != 0) {
94                 return cmp;
95             }
96
97             return actor1.getClass().getName().compareTo(actor2.getClass().getName());
98         });
99
100         return actors;
101     }
102
103     /**
104      * Gets a particular actor.
105      *
106      * @param name name of the actor of interest
107      * @return the desired actor
108      * @throws IllegalArgumentException if no actor by the given name exists
109      */
110     public Actor getActor(String name) {
111         var actor = name2actor.get(name);
112         if (actor == null) {
113             throw new IllegalArgumentException("unknown actor " + name);
114         }
115
116         return actor;
117     }
118
119     /**
120      * Gets the actors.
121      *
122      * @return the actors
123      */
124     public Collection<Actor> getActors() {
125         return name2actor.values();
126     }
127
128     /**
129      * Gets the names of the actors.
130      *
131      * @return the actor names
132      */
133     public Set<String> getActorNames() {
134         return name2actor.keySet();
135     }
136
137     @Override
138     protected void doConfigure(Map<String, Object> parameters) {
139         logger.info("configuring actors");
140
141         for (Actor actor : name2actor.values()) {
142             String actorName = actor.getName();
143             Object paramValue = parameters.get(actorName);
144
145             if (paramValue instanceof Map) {
146                 @SuppressWarnings("unchecked")
147                 Map<String, Object> subparams = (Map<String, Object>) paramValue;
148
149                 try {
150                     actor.configure(subparams);
151
152                 } catch (ParameterValidationRuntimeException e) {
153                     logger.warn("failed to configure actor {} because:\n{}", actorName, e.getResult().getResult(), e);
154
155                 } catch (RuntimeException e) {
156                     logger.warn("failed to configure actor {}", actorName, e);
157                 }
158
159             } else if (actor.isConfigured()) {
160                 logger.warn("missing configuration parameters for actor {}; using previous parameters", actorName);
161
162             } else {
163                 logger.warn("missing configuration parameters for actor {}; actor cannot be started", actorName);
164             }
165         }
166     }
167
168     @Override
169     protected void doStart() {
170         logger.info("starting actors");
171
172         for (Actor actor : name2actor.values()) {
173             if (actor.isConfigured()) {
174                 Util.runFunction(actor::start, "failed to start actor {}", actor.getName());
175
176             } else {
177                 logger.warn("not starting unconfigured actor {}", actor.getName());
178             }
179         }
180     }
181
182     @Override
183     protected void doStop() {
184         logger.info("stopping actors");
185         name2actor.values().forEach(actor -> Util.runFunction(actor::stop, "failed to stop actor {}", actor.getName()));
186     }
187
188     @Override
189     protected void doShutdown() {
190         logger.info("shutting down actors");
191
192         // @formatter:off
193         name2actor.values().forEach(
194             actor -> Util.runFunction(actor::shutdown, "failed to shutdown actor {}", actor.getName()));
195
196         // @formatter:on
197     }
198
199     // the following methods may be overridden by junit tests
200
201     protected Iterable<Actor> loadActors() {
202         return ServiceLoader.load(Actor.class);
203     }
204 }