Actor redesign.
[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 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.Map;
28 import java.util.ServiceLoader;
29 import java.util.Set;
30 import org.onap.policy.common.parameters.BeanValidationResult;
31 import org.onap.policy.controlloop.actorserviceprovider.impl.StartConfigPartial;
32 import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
33 import org.onap.policy.controlloop.actorserviceprovider.spi.Actor;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Service that manages a set of actors. To use the service, first invoke
39  * {@link #configure(Map)} to configure all of the actors, and then invoke
40  * {@link #start()} to start all of the actors. When finished using the actor service,
41  * invoke {@link #stop()} or {@link #shutdown()}.
42  */
43 public class ActorService extends StartConfigPartial<Map<String, Object>> {
44     private static final Logger logger = LoggerFactory.getLogger(ActorService.class);
45
46     private final Map<String, Actor> name2actor;
47
48     private static class LazyHolder {
49         static final ActorService INSTANCE = new ActorService();
50     }
51
52     /**
53      * Constructs the object and loads the list of actors.
54      */
55     protected ActorService() {
56         super("actors");
57
58         Map<String, Actor> map = new HashMap<>();
59
60         for (Actor newActor : loadActors()) {
61             map.compute(newActor.getName(), (name, existingActor) -> {
62                 if (existingActor == null) {
63                     return newActor;
64                 }
65
66                 // TODO: should this throw an exception?
67                 logger.warn("duplicate actor names for {}: {}, ignoring {}", name,
68                                 existingActor.getClass().getSimpleName(), newActor.getClass().getSimpleName());
69                 return existingActor;
70             });
71         }
72
73         name2actor = ImmutableMap.copyOf(map);
74     }
75
76     /**
77      * Get the single instance.
78      *
79      * @return the instance
80      */
81     public static ActorService getInstance() {
82         return LazyHolder.INSTANCE;
83     }
84
85     /**
86      * Gets a particular actor.
87      *
88      * @param name name of the actor of interest
89      * @return the desired actor
90      * @throws IllegalArgumentException if no actor by the given name exists
91      */
92     public Actor getActor(String name) {
93         Actor actor = name2actor.get(name);
94         if (actor == null) {
95             throw new IllegalArgumentException("unknown actor " + name);
96         }
97
98         return actor;
99     }
100
101     /**
102      * Gets the actors.
103      *
104      * @return the actors
105      */
106     public Collection<Actor> getActors() {
107         return name2actor.values();
108     }
109
110     /**
111      * Gets the names of the actors.
112      *
113      * @return the actor names
114      */
115     public Set<String> getActorNames() {
116         return name2actor.keySet();
117     }
118
119     @Override
120     protected void doConfigure(Map<String, Object> parameters) {
121         logger.info("configuring actors");
122
123         BeanValidationResult valres = new BeanValidationResult("ActorService", parameters);
124
125         for (Actor actor : name2actor.values()) {
126             String actorName = actor.getName();
127             Map<String, Object> subparams = Util.translateToMap(actorName, parameters.get(actorName));
128
129             if (subparams != null) {
130
131                 try {
132                     actor.configure(subparams);
133
134                 } catch (ParameterValidationRuntimeException e) {
135                     logger.warn("failed to configure actor {}", actorName, e);
136                     valres.addResult(e.getResult());
137
138                 } catch (RuntimeException e) {
139                     logger.warn("failed to configure actor {}", actorName, e);
140                 }
141
142             } else if (actor.isConfigured()) {
143                 logger.warn("missing configuration parameters for actor {}; using previous parameters", actorName);
144
145             } else {
146                 logger.warn("missing configuration parameters for actor {}; actor cannot be started", actorName);
147             }
148         }
149
150         if (!valres.isValid() && logger.isWarnEnabled()) {
151             logger.warn("actor services validation errors:\n{}", valres.getResult());
152         }
153     }
154
155     @Override
156     protected void doStart() {
157         logger.info("starting actors");
158
159         for (Actor actor : name2actor.values()) {
160             if (actor.isConfigured()) {
161                 Util.logException(actor::start, "failed to start actor {}", actor.getName());
162
163             } else {
164                 logger.warn("not starting unconfigured actor {}", actor.getName());
165             }
166         }
167     }
168
169     @Override
170     protected void doStop() {
171         logger.info("stopping actors");
172         name2actor.values()
173                         .forEach(actor -> Util.logException(actor::stop, "failed to stop actor {}", actor.getName()));
174     }
175
176     @Override
177     protected void doShutdown() {
178         logger.info("shutting down actors");
179
180         // @formatter:off
181         name2actor.values().forEach(
182             actor -> Util.logException(actor::shutdown, "failed to shutdown actor {}", actor.getName()));
183
184         // @formatter:on
185     }
186
187     // the following methods may be overridden by junit tests
188
189     protected Iterable<Actor> loadActors() {
190         return ServiceLoader.load(Actor.class);
191     }
192 }