Actor redesign.
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / main / java / org / onap / policy / controlloop / actorserviceprovider / impl / ActorImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.controlloop.actorserviceprovider.impl;
22
23 import com.google.common.collect.ImmutableMap;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.function.Function;
32 import org.onap.policy.common.parameters.BeanValidationResult;
33 import org.onap.policy.controlloop.actorserviceprovider.Operator;
34 import org.onap.policy.controlloop.actorserviceprovider.Util;
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  * Implementation of an actor.
42  */
43 public class ActorImpl extends StartConfigPartial<Map<String, Object>> implements Actor {
44     private static final Logger logger = LoggerFactory.getLogger(ActorImpl.class);
45
46     /**
47      * Maps a name to an operator.
48      */
49     private Map<String, Operator> name2operator;
50
51     /**
52      * Constructs the object.
53      *
54      * @param name actor name
55      * @param operators the operations supported by this actor
56      */
57     public ActorImpl(String name, Operator... operators) {
58         super(name);
59         setOperators(Arrays.asList(operators));
60     }
61
62     /**
63      * Sets the operators supported by this actor, overriding any previous list.
64      *
65      * @param operators the operations supported by this actor
66      */
67     protected void setOperators(List<Operator> operators) {
68         if (isConfigured()) {
69             throw new IllegalStateException("attempt to set operators on a configured actor: " + getName());
70         }
71
72         Map<String, Operator> map = new HashMap<>();
73         for (Operator newOp : operators) {
74             map.compute(newOp.getName(), (opName, existingOp) -> {
75                 if (existingOp == null) {
76                     return newOp;
77                 }
78
79                 // TODO: should this throw an exception?
80                 logger.warn("duplicate names for actor operation {}.{}: {}, ignoring {}", getName(), opName,
81                                 existingOp.getClass().getSimpleName(), newOp.getClass().getSimpleName());
82                 return existingOp;
83             });
84         }
85
86         this.name2operator = ImmutableMap.copyOf(map);
87     }
88
89     @Override
90     public String getName() {
91         return getFullName();
92     }
93
94     @Override
95     public Operator getOperator(String name) {
96         Operator operator = name2operator.get(name);
97         if (operator == null) {
98             throw new IllegalArgumentException("unknown operation " + getName() + "." + name);
99         }
100
101         return operator;
102     }
103
104     @Override
105     public Collection<Operator> getOperators() {
106         return name2operator.values();
107     }
108
109     @Override
110     public Set<String> getOperationNames() {
111         return name2operator.keySet();
112     }
113
114     /**
115      * For each operation, it looks for a set of parameters by the same name and, if
116      * found, configures the operation with the parameters.
117      */
118     @Override
119     protected void doConfigure(Map<String, Object> parameters) {
120         final String actorName = getName();
121         logger.info("configuring operations for actor {}", actorName);
122
123         BeanValidationResult valres = new BeanValidationResult(actorName, parameters);
124
125         // function that creates operator-specific parameters, given the operation name
126         Function<String, Map<String, Object>> opParamsMaker = makeOperatorParameters(parameters);
127
128         for (Operator operator : name2operator.values()) {
129             String operName = operator.getName();
130             Map<String, Object> subparams = opParamsMaker.apply(operName);
131
132             if (subparams != null) {
133
134                 try {
135                     operator.configure(subparams);
136
137                 } catch (ParameterValidationRuntimeException e) {
138                     logger.warn("failed to configure operation {}.{}", actorName, operName, e);
139                     valres.addResult(e.getResult());
140
141                 } catch (RuntimeException e) {
142                     logger.warn("failed to configure operation {}.{}", actorName, operName, e);
143                 }
144
145             } else if (operator.isConfigured()) {
146                 logger.warn("missing configuration parameters for operation {}.{}; using previous parameters",
147                                 actorName, operName);
148
149             } else {
150                 logger.warn("missing configuration parameters for operation {}.{}; operation cannot be started",
151                                 actorName, operName);
152             }
153         }
154     }
155
156     /**
157      * Extracts the operator parameters from the actor parameters, for a given operator.
158      * This method assumes each operation has its own set of parameters.
159      *
160      * @param actorParameters actor parameters
161      * @return a function to extract the operator parameters from the actor parameters.
162      *         Note: this function may return {@code null} if there are no parameters for
163      *         the given operation name
164      */
165     protected Function<String, Map<String, Object>> makeOperatorParameters(Map<String, Object> actorParameters) {
166
167         return operName -> Util.translateToMap(getName() + "." + operName, actorParameters.get(operName));
168     }
169
170     /**
171      * Starts each operation.
172      */
173     @Override
174     protected void doStart() {
175         final String actorName = getName();
176         logger.info("starting operations for actor {}", actorName);
177
178         for (Operator oper : name2operator.values()) {
179             if (oper.isConfigured()) {
180                 Util.logException(oper::start, "failed to start operation {}.{}", actorName, oper.getName());
181
182             } else {
183                 logger.warn("not starting unconfigured operation {}.{}", actorName, oper.getName());
184             }
185         }
186     }
187
188     /**
189      * Stops each operation.
190      */
191     @Override
192     protected void doStop() {
193         final String actorName = getName();
194         logger.info("stopping operations for actor {}", actorName);
195
196         // @formatter:off
197         name2operator.values().forEach(
198             oper -> Util.logException(oper::stop, "failed to stop operation {}.{}", actorName, oper.getName()));
199         // @formatter:on
200     }
201
202     /**
203      * Shuts down each operation.
204      */
205     @Override
206     protected void doShutdown() {
207         final String actorName = getName();
208         logger.info("shutting down operations for actor {}", actorName);
209
210         // @formatter:off
211         name2operator.values().forEach(oper -> Util.logException(oper::shutdown,
212                         "failed to shutdown operation {}.{}", actorName, oper.getName()));
213         // @formatter:on
214     }
215
216     // TODO old code: remove lines down to **HERE**
217
218     @Override
219     public String actor() {
220         return null;
221     }
222
223     @Override
224     public List<String> recipes() {
225         return Collections.emptyList();
226     }
227
228     @Override
229     public List<String> recipeTargets(String recipe) {
230         return Collections.emptyList();
231     }
232
233     @Override
234     public List<String> recipePayloads(String recipe) {
235         return Collections.emptyList();
236     }
237
238     // **HERE**
239 }