Removing Drools-pdp swagger annotations
[policy/drools-pdp.git] / policy-management / src / main / java / org / onap / policy / drools / server / restful / RestManager.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2021,2023 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.drools.server.restful;
23
24 import ch.qos.logback.classic.LoggerContext;
25 import com.google.re2j.Pattern;
26 import java.io.BufferedReader;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37 import java.util.UUID;
38 import java.util.function.Function;
39 import java.util.function.Supplier;
40 import java.util.stream.Collectors;
41 import javax.ws.rs.Consumes;
42 import javax.ws.rs.DELETE;
43 import javax.ws.rs.DefaultValue;
44 import javax.ws.rs.GET;
45 import javax.ws.rs.POST;
46 import javax.ws.rs.PUT;
47 import javax.ws.rs.Path;
48 import javax.ws.rs.PathParam;
49 import javax.ws.rs.Produces;
50 import javax.ws.rs.QueryParam;
51 import javax.ws.rs.core.MediaType;
52 import javax.ws.rs.core.Response;
53 import javax.ws.rs.core.Response.Status;
54 import lombok.AllArgsConstructor;
55 import lombok.Getter;
56 import lombok.Setter;
57 import lombok.ToString;
58 import org.onap.policy.common.endpoints.event.comm.Topic;
59 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
60 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
61 import org.onap.policy.common.endpoints.event.comm.TopicSink;
62 import org.onap.policy.common.endpoints.event.comm.TopicSource;
63 import org.onap.policy.common.endpoints.http.server.YamlMessageBodyHandler;
64 import org.onap.policy.common.utils.logging.LoggerUtils;
65 import org.onap.policy.drools.controller.DroolsController;
66 import org.onap.policy.drools.properties.DroolsPropertyConstants;
67 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
68 import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants;
69 import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
70 import org.onap.policy.drools.protocol.coders.ProtocolCoderToolset;
71 import org.onap.policy.drools.protocol.configuration.ControllerConfiguration;
72 import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
73 import org.onap.policy.drools.system.PolicyController;
74 import org.onap.policy.drools.system.PolicyControllerConstants;
75 import org.onap.policy.drools.system.PolicyEngineConstants;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 /**
80  * Telemetry JAX-RS Interface to the PDP-D.
81  */
82
83 @Path("/policy/pdp")
84 @Produces({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML})
85 @Consumes({MediaType.APPLICATION_JSON, YamlMessageBodyHandler.APPLICATION_YAML})
86 @ToString
87 public class RestManager implements SwaggerApi, DefaultApi, FeaturesApi, InputsApi,
88         PropertiesApi, EnvironmentApi, SwitchesApi, ControllersApi,
89         TopicsApi, ToolsApi {
90
91     private static final String OFFER_FAILED = "{}: cannot offer to topic {} because of {}";
92     private static final String CANNOT_PERFORM_OPERATION = "cannot perform operation";
93     private static final String NO_FILTERS = " no filters";
94     private static final String NOT_FOUND = " not found: ";
95     private static final String NOT_FOUND_MSG = " not found";
96     private static final String DOES_NOT_EXIST_MSG = " does not exist";
97     private static final String NOT_ACCEPTABLE_MSG = " not acceptable";
98     private static final String FETCH_POLICY_FAILED = "{}: cannot get policy-controller because of {}";
99     private static final String FETCH_POLICY_BY_NAME_FAILED = "{}: cannot get policy-controller {} because of {}";
100     private static final String FETCH_POLICY_BY_TOPIC_FAILED =
101         "{}: cannot get policy-controller {} topic {} because of {}";
102     private static final String FETCH_DROOLS_FAILED = "{}: cannot get drools-controller {} because of {}";
103     private static final String FETCH_DROOLS_BY_ENTITY_FAILED =
104         "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}";
105     private static final String FETCH_DROOLS_BY_PARAMS_FAILED =
106         "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}";
107     private static final String FETCH_DROOLS_BY_FACTTYPE_FAILED =
108         "{}: cannot get: drools-controller {}, session {}, factType {}, because of {}";
109     private static final String FETCH_DECODERS_BY_POLICY_FAILED =
110         "{}: cannot get decoders for policy-controller {} because of {}";
111     private static final String FETCH_DECODERS_BY_TOPIC_FAILED =
112         "{}: cannot get decoders for policy-controller {} topic {} because of {}";
113     private static final String FETCH_DECODER_BY_TYPE_FAILED =
114         "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}";
115     private static final String FETCH_DECODER_BY_FILTER_FAILED =
116         "{}: cannot get decoder filters for policy-controller {} topic {} type {} filters {} because of {}";
117     private static final String FETCH_ENCODER_BY_FILTER_FAILED =
118         "{}: cannot get encoder filters for policy-controller {} because of {}";
119
120     private static final String SWAGGER = "/swagger/swagger.json";
121
122     /**
123      * Logger.
124      */
125     private static final Logger logger = LoggerFactory.getLogger(RestManager.class);
126
127     /**
128      * Feed Ports into Resources.
129      */
130     private static final List<String> INPUTS = Collections.singletonList("configuration");
131
132     /**
133      * Resource Toggles.
134      */
135     private static final List<String> SWITCHES = Arrays.asList("activation", "lock");
136
137     /**
138      * GET.
139      *
140      * @return response object
141      */
142     @Override
143     @GET
144     @Path("engine/swagger")
145     public Response swagger() {
146
147         try (InputStream inputStream = getClass().getResourceAsStream(SWAGGER);
148             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
149             String contents = reader.lines()
150                     .collect(Collectors.joining(System.lineSeparator()));
151             return Response.status(Response.Status.OK)
152                         .entity(contents)
153                         .build();
154         } catch (IOException e) {
155             logger.error("Cannot read swagger.json {} because of {}", e.getMessage(), e);
156             return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
157                     .build();
158         }
159
160     }
161
162     /**
163      * GET.
164      *
165      * @return response object
166      */
167     @Override
168     @GET
169     @Path("engine")
170     public Response engine() {
171         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build();
172     }
173
174     /**
175      * DELETE.
176      *
177      * @return response object
178      */
179     @Override
180     @DELETE
181     @Path("engine")
182     public Response engineShutdown() {
183         try {
184             PolicyEngineConstants.getManager().shutdown();
185         } catch (final IllegalStateException e) {
186             logger.error("{}: cannot shutdown {} because of {}", this, PolicyEngineConstants.getManager(),
187                 e.getMessage(), e);
188             return Response.status(Response.Status.BAD_REQUEST).entity(PolicyEngineConstants.getManager()).build();
189         }
190
191         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build();
192     }
193
194     /**
195      * GET.
196      *
197      * @return response object
198      */
199     @Override
200     @GET
201     @Path("engine/features")
202     public Response engineFeatures() {
203         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatures()).build();
204     }
205
206     @Override
207     @GET
208     @Path("engine/features/inventory")
209     public Response engineFeaturesInventory() {
210         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatureProviders())
211             .build();
212     }
213
214     /**
215      * GET.
216      *
217      * @return response object
218      */
219     @Override
220     @GET
221     @Path("engine/features/{featureName}")
222     public Response engineFeature(@PathParam("featureName") String featureName) {
223         try {
224             return Response.status(Response.Status.OK)
225                 .entity(PolicyEngineConstants.getManager().getFeatureProvider(featureName)).build();
226         } catch (final IllegalArgumentException iae) {
227             logger.debug("feature unavailable: {}", featureName, iae);
228             return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build();
229         }
230     }
231
232     /**
233      * GET.
234      *
235      * @return response object
236      */
237     @Override
238     @GET
239     @Path("engine/inputs")
240     public Response engineInputs() {
241         return Response.status(Response.Status.OK).entity(INPUTS).build();
242     }
243
244     /**
245      * POST.
246      *
247      * @return response object
248      */
249     @Override
250     @POST
251     @Path("engine/inputs/configuration")
252     public Response engineUpdate(PdpdConfiguration configuration) {
253         final PolicyController controller = null;
254         boolean success;
255         try {
256             success = PolicyEngineConstants.getManager().configure(configuration);
257         } catch (final Exception e) {
258             success = false;
259             logger.info("{}: cannot configure {} because of {}", this, PolicyEngineConstants.getManager(),
260                 e.getMessage(), e);
261         }
262
263         if (!success) {
264             return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION))
265                 .build();
266         } else {
267             return Response.status(Response.Status.OK).entity(controller).build();
268         }
269     }
270
271     /**
272      * GET.
273      *
274      * @return response object
275      */
276     @Override
277     @GET
278     @Path("engine/properties")
279     public Response engineProperties() {
280         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getProperties()).build();
281     }
282
283     /**
284      * GET.
285      *
286      * @return response object
287      */
288     @Override
289     @GET
290     @Path("engine/environment")
291     public Response engineEnvironment() {
292         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getEnvironment()).build();
293     }
294
295     /**
296      * GET.
297      *
298      * @return response object
299      */
300     @Override
301     @GET
302     @Path("engine/environment/{envProperty}")
303     @Consumes(MediaType.TEXT_PLAIN)
304     public Response engineEnvironmentProperty(@PathParam("envProperty") String envProperty) {
305         return Response.status(Response.Status.OK)
306             .entity(PolicyEngineConstants.getManager().getEnvironmentProperty(envProperty)).build();
307     }
308
309     /**
310      * PUT.
311      *
312      * @return response object
313      */
314     @Override
315     @PUT
316     @Path("engine/environment/{envProperty}")
317     @Consumes(MediaType.TEXT_PLAIN)
318     @Produces(MediaType.TEXT_PLAIN)
319     public Response engineEnvironmentAdd(@PathParam("envProperty") String envProperty, String envValue) {
320         final String previousValue = PolicyEngineConstants.getManager().setEnvironmentProperty(envProperty, envValue);
321         return Response.status(Response.Status.OK).entity(previousValue).build();
322     }
323
324     /**
325      * GET.
326      *
327      * @return response object
328      */
329     @Override
330     @GET
331     @Path("engine/switches")
332     public Response engineSwitches() {
333         return Response.status(Response.Status.OK).entity(SWITCHES).build();
334     }
335
336     /**
337      * PUT.
338      *
339      * @return response object
340      */
341     @Override
342     @PUT
343     @Path("engine/switches/activation")
344     public Response engineActivation() {
345         var success = true;
346         try {
347             PolicyEngineConstants.getManager().activate();
348         } catch (final Exception e) {
349             success = false;
350             logger.info("{}: cannot activate {} because of {}", this, PolicyEngineConstants.getManager(),
351                 e.getMessage(), e);
352         }
353
354         if (!success) {
355             return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION))
356                 .build();
357         } else {
358             return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build();
359         }
360     }
361
362     /**
363      * DELETE.
364      *
365      * @return response object
366      */
367     @Override
368     @DELETE
369     @Path("engine/switches/activation")
370     public Response engineDeactivation() {
371         var success = true;
372         try {
373             PolicyEngineConstants.getManager().deactivate();
374         } catch (final Exception e) {
375             success = false;
376             logger.info("{}: cannot deactivate {} because of {}", this, PolicyEngineConstants.getManager(),
377                 e.getMessage(), e);
378         }
379
380         if (!success) {
381             return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION))
382                 .build();
383         } else {
384             return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager()).build();
385         }
386     }
387
388     /**
389      * PUT.
390      *
391      * @return response object
392      */
393     @Override
394     @PUT
395     @Path("engine/switches/lock")
396     public Response engineLock() {
397         final boolean success = PolicyEngineConstants.getManager().lock();
398         if (success) {
399             return Response.status(Status.OK).entity(PolicyEngineConstants.getManager()).build();
400         } else {
401             return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build();
402         }
403     }
404
405     /**
406      * DELETE.
407      *
408      * @return response object
409      */
410     @Override
411     @DELETE
412     @Path("engine/switches/lock")
413     public Response engineUnlock() {
414         final boolean success = PolicyEngineConstants.getManager().unlock();
415         if (success) {
416             return Response.status(Status.OK).entity(PolicyEngineConstants.getManager()).build();
417         } else {
418             return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build();
419         }
420     }
421
422     /**
423      * GET.
424      *
425      * @return response object
426      */
427     @Override
428     @GET
429     @Path("engine/controllers")
430     public Response controllers() {
431         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getPolicyControllerIds())
432             .build();
433     }
434
435     /**
436      * GET.
437      *
438      * @return response object
439      */
440     @Override
441     @GET
442     @Path("engine/controllers/inventory")
443     public Response controllerInventory() {
444         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getPolicyControllers())
445             .build();
446     }
447
448     /**
449      * POST.
450      *
451      * @return response object
452      */
453     @Override
454     @POST
455     @Path("engine/controllers")
456     public Response controllerAdd(Properties config) {
457         if (config == null) {
458             return Response.status(Response.Status.BAD_REQUEST).entity(new Error("A configuration must be provided"))
459                 .build();
460         }
461
462         final String controllerName = config.getProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME);
463         if (controllerName == null || controllerName.isEmpty()) {
464             return Response.status(Response.Status.BAD_REQUEST)
465                 .entity(new Error(
466                     "Configuration must have an entry for " + DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME))
467                 .build();
468         }
469
470         PolicyController controller;
471         try {
472             controller = PolicyControllerConstants.getFactory().get(controllerName);
473             if (controller != null) {
474                 return Response.status(Response.Status.NOT_MODIFIED).entity(controller).build();
475             }
476         } catch (final IllegalArgumentException e) {
477             logger.trace("OK ", e);
478             // This is OK
479         } catch (final IllegalStateException e) {
480             logger.info(FETCH_POLICY_FAILED, this, e.getMessage(), e);
481             return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + NOT_FOUND_MSG))
482                 .build();
483         }
484
485         try {
486             controller = PolicyEngineConstants.getManager().createPolicyController(
487                 config.getProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME), config);
488         } catch (IllegalArgumentException | IllegalStateException e) {
489             logger.warn("{}: cannot create policy-controller because of {}", this, e.getMessage(), e);
490             return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build();
491         }
492
493         try {
494             final boolean success = controller.start();
495             if (!success) {
496                 logger.info("{}: cannot start {}", this, controller);
497                 return Response.status(Response.Status.PARTIAL_CONTENT)
498                     .entity(new Error(controllerName + " can't be started")).build();
499             }
500         } catch (final IllegalStateException e) {
501             logger.info("{}: cannot start {} because of {}", this, controller, e.getMessage(), e);
502             return Response.status(Response.Status.PARTIAL_CONTENT).entity(controller).build();
503         }
504
505         return Response.status(Response.Status.CREATED).entity(controller).build();
506     }
507
508     /**
509      * GET.
510      *
511      * @return response object
512      */
513     @Override
514     @GET
515     @Path("engine/controllers/features")
516     public Response controllerFeatures() {
517         return Response.status(Response.Status.OK).entity(PolicyEngineConstants.getManager().getFeatures()).build();
518     }
519
520     /**
521      * GET.
522      *
523      * @return response object
524      */
525     @Override
526     @GET
527     @Path("engine/controllers/features/inventory")
528     public Response controllerFeaturesInventory() {
529         return Response.status(Response.Status.OK)
530             .entity(PolicyControllerConstants.getFactory().getFeatureProviders()).build();
531     }
532
533     /**
534      * GET.
535      *
536      * @return response object
537      */
538     @Override
539     @GET
540     @Path("engine/controllers/features/{featureName}")
541     public Response controllerFeature(@PathParam("featureName") String featureName) {
542         try {
543             return Response.status(Response.Status.OK)
544                 .entity(PolicyControllerConstants.getFactory().getFeatureProvider(featureName))
545                 .build();
546         } catch (final IllegalArgumentException iae) {
547             logger.debug("{}: cannot feature {} because of {}", this, featureName, iae.getMessage(), iae);
548             return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build();
549         }
550     }
551
552     /**
553      * GET.
554      *
555      * @return response object
556      */
557     @Override
558     @GET
559     @Path("engine/controllers/{controller}")
560     public Response controller(@PathParam("controller") String controllerName) {
561
562         return catchArgStateGenericEx(
563             () -> Response.status(Response.Status.OK)
564                 .entity(PolicyControllerConstants.getFactory().get(controllerName)).build(),
565             e -> {
566                 logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
567                 return (controllerName);
568             });
569     }
570
571     /**
572      * DELETE.
573      *
574      * @return response object
575      */
576     @Override
577     @DELETE
578     @Path("engine/controllers/{controller}")
579     public Response controllerDelete(@PathParam("controller") String controllerName) {
580
581         PolicyController controller;
582         try {
583             controller = PolicyControllerConstants.getFactory().get(controllerName);
584             if (controller == null) {
585                 return Response.status(Response.Status.BAD_REQUEST)
586                     .entity(new Error(controllerName + DOES_NOT_EXIST_MSG)).build();
587             }
588         } catch (final IllegalArgumentException e) {
589             logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
590             return Response.status(Response.Status.BAD_REQUEST)
591                 .entity(new Error(controllerName + NOT_FOUND + e.getMessage())).build();
592         } catch (final IllegalStateException e) {
593             logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
594             return Response.status(Response.Status.NOT_ACCEPTABLE)
595                 .entity(new Error(controllerName + NOT_ACCEPTABLE_MSG)).build();
596         }
597
598         try {
599             PolicyEngineConstants.getManager().removePolicyController(controllerName);
600         } catch (IllegalArgumentException | IllegalStateException e) {
601             logger.debug("{}: cannot remove policy-controller {} because of {}", this, controllerName, e.getMessage(),
602                 e);
603             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build();
604         }
605
606         return Response.status(Response.Status.OK).entity(controller).build();
607     }
608
609     /**
610      * GET.
611      *
612      * @return response object
613      */
614     @Override
615     @GET
616     @Path("engine/controllers/{controller}/properties")
617
618     public Response controllerProperties(@PathParam("controller") String controllerName) {
619
620         return catchArgStateGenericEx(() -> {
621             final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName);
622             return Response.status(Response.Status.OK).entity(controller.getProperties()).build();
623
624         }, e -> {
625             logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
626             return (controllerName);
627         });
628     }
629
630     /**
631      * GET.
632      *
633      * @return response object
634      */
635     @Override
636     @GET
637     @Path("engine/controllers/{controller}/inputs")
638     public Response controllerInputs(@PathParam("controller") String controllerName) {
639         return Response.status(Response.Status.OK).entity(INPUTS).build();
640     }
641
642     /**
643      * POST.
644      *
645      * @return response object
646      */
647     @Override
648     @POST
649     @Path("engine/controllers/{controller}/inputs/configuration")
650     public Response controllerUpdate(ControllerConfiguration controllerConfiguration,
651             @PathParam("controller") String controllerName) {
652
653         if (controllerName == null || controllerName.isEmpty() || controllerConfiguration == null
654             || !controllerName.equals(controllerConfiguration.getName())) {
655             return Response.status(Response.Status.BAD_REQUEST)
656                 .entity("A valid or matching controller names must be provided").build();
657         }
658
659         return catchArgStateGenericEx(() -> {
660             var controller =
661                 PolicyEngineConstants.getManager().updatePolicyController(controllerConfiguration);
662             if (controller == null) {
663                 return Response.status(Response.Status.BAD_REQUEST)
664                     .entity(new Error(controllerName + DOES_NOT_EXIST_MSG)).build();
665             }
666
667             return Response.status(Response.Status.OK).entity(controller).build();
668
669         }, e -> {
670             logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName,
671                 e.getMessage(), e);
672             return (controllerName);
673         });
674     }
675
676     /**
677      * GET.
678      *
679      * @return response object
680      */
681     @Override
682     @GET
683     @Path("engine/controllers/{controller}/switches")
684     public Response controllerSwitches(@PathParam("controller") String controllerName) {
685         return Response.status(Response.Status.OK).entity(SWITCHES).build();
686     }
687
688     /**
689      * PUT.
690      *
691      * @return response object
692      */
693     @Override
694     @PUT
695     @Path("engine/controllers/{controller}/switches/lock")
696     public Response controllerLock(@PathParam("controller") String controllerName) {
697         var policyController = PolicyControllerConstants.getFactory().get(controllerName);
698         final boolean success = policyController.lock();
699         if (success) {
700             return Response.status(Status.OK).entity(policyController).build();
701         } else {
702             return Response.status(Status.NOT_ACCEPTABLE)
703                 .entity(new Error("Controller " + controllerName + " cannot be locked")).build();
704         }
705     }
706
707     /**
708      * DELETE.
709      *
710      * @return response object
711      */
712     @Override
713     @DELETE
714     @Path("engine/controllers/{controller}/switches/lock")
715     public Response controllerUnlock(@PathParam("controller") String controllerName) {
716         var policyController = PolicyControllerConstants.getFactory().get(controllerName);
717         final boolean success = policyController.unlock();
718         if (success) {
719             return Response.status(Status.OK).entity(policyController).build();
720         } else {
721             return Response.status(Status.NOT_ACCEPTABLE)
722                 .entity(new Error("Controller " + controllerName + " cannot be unlocked")).build();
723         }
724     }
725
726     /**
727      * GET.
728      *
729      * @return response object
730      */
731     @Override
732     @GET
733     @Path("engine/controllers/{controller}/drools")
734     public Response drools(@PathParam("controller") String controllerName) {
735
736         return catchArgStateGenericEx(() -> {
737             var drools = this.getDroolsController(controllerName);
738             return Response.status(Response.Status.OK).entity(drools).build();
739
740         }, e -> {
741             logger.debug(FETCH_DROOLS_FAILED, this, controllerName, e.getMessage(), e);
742             return (controllerName);
743         });
744     }
745
746     /**
747      * GET.
748      *
749      * @return response object
750      */
751     @Override
752     @GET
753     @Path("engine/controllers/{controller}/drools/facts")
754     public Response droolsFacts2(@PathParam("controller") String controllerName) {
755
756         return catchArgStateGenericEx(() -> {
757             final Map<String, Long> sessionCounts = new HashMap<>();
758             var drools = this.getDroolsController(controllerName);
759             for (final String session : drools.getSessionNames()) {
760                 sessionCounts.put(session, drools.factCount(session));
761             }
762             return sessionCounts;
763
764         }, e -> {
765             logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
766             return controllerName;
767         });
768     }
769
770     /**
771      * GET.
772      *
773      * @return response object
774      */
775     @Override
776     @GET
777     @Path("engine/controllers/{controller}/drools/facts/{session}")
778     public Response droolsFacts1(@PathParam("controller") String controllerName,
779         @PathParam("session") String sessionName) {
780
781         return catchArgStateGenericEx(() -> {
782             var drools = this.getDroolsController(controllerName);
783             return drools.factClassNames(sessionName);
784
785         }, e -> {
786             logger.debug(FETCH_DROOLS_FAILED, this, controllerName, e.getMessage(), e);
787             return (controllerName + ":" + sessionName);
788         });
789     }
790
791     /**
792      * GET.
793      *
794      * @return response object
795      */
796     @Override
797     @GET
798     @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}")
799     public Response droolsFacts(
800         @PathParam("controller") String controllerName,
801         @PathParam("session") String sessionName,
802         @PathParam("factType") String factType,
803         @DefaultValue("false") @QueryParam("count") boolean count) {
804
805         return catchArgStateGenericEx(() -> {
806             var drools = this.getDroolsController(controllerName);
807             final List<Object> facts = drools.facts(sessionName, factType, false);
808             return (count ? facts.size() : facts);
809
810         }, e -> {
811             logger.debug(FETCH_POLICY_BY_NAME_FAILED, this, controllerName, e.getMessage(), e);
812             return (controllerName + ":" + sessionName + ":" + factType);
813         });
814     }
815
816     /**
817      * GET.
818      *
819      * @return response object
820      */
821     @Override
822     @GET
823     @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}")
824     public Response droolsFacts3(
825         @PathParam("controller") String controllerName,
826         @PathParam("session") String sessionName,
827         @PathParam("query") String queryName,
828         @PathParam("queriedEntity") String queriedEntity,
829         @DefaultValue("false") @QueryParam("count") boolean count) {
830
831         return catchArgStateGenericEx(() -> {
832             var drools = this.getDroolsController(controllerName);
833             final List<Object> facts = drools.factQuery(sessionName, queryName, queriedEntity, false);
834             return (count ? facts.size() : facts);
835
836         }, e -> {
837             logger.debug(FETCH_DROOLS_BY_ENTITY_FAILED, this,
838                 controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e);
839             return (controllerName + ":" + sessionName + ":" + queryName + queriedEntity);
840         });
841     }
842
843     /**
844      * POST.
845      *
846      * @return response object
847      */
848     @Override
849     @POST
850     @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}")
851     public Response droolsFacts4(
852         @PathParam("controller") String controllerName,
853         @PathParam("session") String sessionName,
854         @PathParam("query") String queryName,
855         @PathParam("queriedEntity") String queriedEntity,
856         List<Object> queryParameters) {
857
858         return catchArgStateGenericEx(() -> {
859             var drools = this.getDroolsController(controllerName);
860             if (queryParameters == null || queryParameters.isEmpty()) {
861                 return drools.factQuery(sessionName, queryName, queriedEntity, false);
862             } else {
863                 return drools.factQuery(sessionName, queryName, queriedEntity, false, queryParameters.toArray());
864             }
865
866         }, e -> {
867             logger.debug(FETCH_DROOLS_BY_PARAMS_FAILED,
868                 this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e);
869             return (controllerName + ":" + sessionName + ":" + queryName + queriedEntity);
870         });
871     }
872
873     /**
874      * DELETE.
875      *
876      * @return response object
877      */
878     @Override
879     @DELETE
880     @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}")
881     public Response droolsFactsDelete1(
882         @PathParam("controller") String controllerName,
883         @PathParam("session") String sessionName,
884         @PathParam("factType") String factType) {
885
886         return catchArgStateGenericEx(() -> {
887             var drools = this.getDroolsController(controllerName);
888             return drools.facts(sessionName, factType, true);
889
890         }, e -> {
891             logger.debug(FETCH_DROOLS_BY_FACTTYPE_FAILED, this,
892                 controllerName, sessionName, factType, e.getMessage(), e);
893             return (controllerName + ":" + sessionName + ":" + factType);
894         });
895     }
896
897     /**
898      * DELETE.
899      *
900      * @return response object
901      */
902     @Override
903     @DELETE
904     @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}")
905     public Response droolsFactsDelete(
906         @PathParam("controller") String controllerName,
907         @PathParam("session") String sessionName,
908         @PathParam("query") String queryName,
909         @PathParam("queriedEntity") String queriedEntity) {
910
911         return catchArgStateGenericEx(() -> {
912             var drools = this.getDroolsController(controllerName);
913             return drools.factQuery(sessionName, queryName, queriedEntity, true);
914
915
916         }, e -> {
917             logger.debug(FETCH_DROOLS_BY_PARAMS_FAILED,
918                 this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e);
919             return (controllerName + ":" + sessionName + ":" + queryName + queriedEntity);
920         });
921     }
922
923     /**
924      * POST.
925      *
926      * @return response object
927      */
928     @Override
929     @POST
930     @Path("engine/controllers/tools/coders/decoders/filters/rule")
931     public Response rules(String expression) {
932         return Response.status(Status.OK).entity(new JsonProtocolFilter(expression)).build();
933     }
934
935     /**
936      * GET.
937      *
938      * @return response object
939      */
940     @Override
941     @GET
942     @Path("engine/controllers/{controller}/decoders")
943     public Response decoders(@PathParam("controller") String controllerName) {
944
945         return catchArgStateGenericEx(() -> {
946             var drools = this.getDroolsController(controllerName);
947             return EventProtocolCoderConstants.getManager().getDecoders(drools.getGroupId(), drools.getArtifactId());
948
949         }, e -> {
950             logger.debug(FETCH_DECODERS_BY_POLICY_FAILED, this, controllerName,
951                 e.getMessage(), e);
952             return (controllerName);
953         });
954     }
955
956     /**
957      * GET.
958      *
959      * @return response object
960      */
961     @Override
962     @GET
963     @Path("engine/controllers/{controller}/decoders/filters")
964     public Response decoderFilters(@PathParam("controller") String controllerName) {
965
966         return catchArgStateGenericEx(() -> {
967             var drools = this.getDroolsController(controllerName);
968             return EventProtocolCoderConstants.getManager()
969                 .getDecoderFilters(drools.getGroupId(), drools.getArtifactId());
970
971         }, e -> {
972             logger.debug(FETCH_DECODERS_BY_POLICY_FAILED, this, controllerName, e.getMessage(), e);
973             return (controllerName);
974         });
975     }
976
977     /**
978      * GET.
979      *
980      * @return response object
981      */
982     @Override
983     @GET
984     @Path("engine/controllers/{controller}/decoders/{topic}")
985     public Response decoder(
986         @PathParam("controller") String controllerName,
987         @PathParam("topic") String topic) {
988
989         return catchArgStateGenericEx(() -> {
990             var drools = this.getDroolsController(controllerName);
991             return EventProtocolCoderConstants.getManager()
992                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
993
994         }, e -> {
995             logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this, controllerName, topic, e.getMessage(), e);
996             return (controllerName + ":" + topic);
997         });
998     }
999
1000     /**
1001      * GET.
1002      *
1003      * @return response object
1004      */
1005     @Override
1006     @GET
1007     @Path("engine/controllers/{controller}/decoders/{topic}/filters")
1008     public Response decoderFilter2(
1009         @PathParam("controller") String controllerName,
1010         @PathParam("topic") String topic) {
1011
1012         return catchArgStateGenericEx(() -> {
1013             var drools = this.getDroolsController(controllerName);
1014             final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1015                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1016             if (decoder == null) {
1017                 return Response.status(Response.Status.BAD_REQUEST).entity(new Error(topic + DOES_NOT_EXIST_MSG))
1018                     .build();
1019             } else {
1020                 return decoder.getCoders();
1021             }
1022
1023         }, e -> {
1024             logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this, controllerName, topic, e.getMessage(), e);
1025             return (controllerName + ":" + topic);
1026         });
1027     }
1028
1029     /**
1030      * GET.
1031      *
1032      * @return response object
1033      */
1034     @Override
1035     @GET
1036     @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}")
1037     public Response decoderFilter1(
1038         @PathParam("controller") String controllerName,
1039         @PathParam("topic") String topic,
1040         @PathParam("factType") String factClass) {
1041
1042         return catchArgStateGenericEx(() -> {
1043             var drools = this.getDroolsController(controllerName);
1044             final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1045                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1046             final CoderFilters filters = decoder.getCoder(factClass);
1047             if (filters == null) {
1048                 return Response.status(Response.Status.BAD_REQUEST)
1049                     .entity(new Error(topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build();
1050             } else {
1051                 return filters;
1052             }
1053
1054         }, e -> {
1055             logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this,
1056                 controllerName, topic, factClass, e.getMessage(), e);
1057             return (controllerName + ":" + topic + ":" + factClass);
1058         });
1059     }
1060
1061     /**
1062      * PUT.
1063      *
1064      * @return response object
1065      */
1066     @Override
1067     @PUT
1068     @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}")
1069     public Response decoderFilter(
1070             JsonProtocolFilter configFilters,
1071             @PathParam("controller") String controllerName,
1072             @PathParam("topic") String topic,
1073             @PathParam("factType") String factClass) {
1074
1075         if (configFilters == null) {
1076             return Response.status(Response.Status.BAD_REQUEST).entity(new Error("Configuration Filters not provided"))
1077                 .build();
1078         }
1079
1080         return catchArgStateGenericEx(() -> {
1081             var drools = this.getDroolsController(controllerName);
1082             final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1083                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1084             final CoderFilters filters = decoder.getCoder(factClass);
1085             if (filters == null) {
1086                 return Response.status(Response.Status.BAD_REQUEST)
1087                     .entity(new Error(topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build();
1088             }
1089             filters.setFilter(configFilters);
1090             return filters;
1091
1092         }, e -> {
1093             logger.debug(FETCH_DECODER_BY_FILTER_FAILED,
1094                 this, controllerName, topic, factClass, configFilters, e.getMessage(), e);
1095             return (controllerName + ":" + topic + ":" + factClass);
1096         });
1097     }
1098
1099     /**
1100      * GET.
1101      *
1102      * @return response object
1103      */
1104     @Override
1105     @GET
1106     @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
1107     public Response decoderFilterRules(
1108         @PathParam("controller") String controllerName,
1109         @PathParam("topic") String topic,
1110         @PathParam("factType") String factClass) {
1111
1112         return catchArgStateGenericEx(() -> {
1113             var drools = this.getDroolsController(controllerName);
1114             final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1115                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1116
1117             final CoderFilters filters = decoder.getCoder(factClass);
1118             if (filters == null) {
1119                 return Response.status(Response.Status.BAD_REQUEST)
1120                     .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build();
1121             }
1122
1123             final JsonProtocolFilter filter = filters.getFilter();
1124             if (filter == null) {
1125                 return Response.status(Response.Status.BAD_REQUEST)
1126                     .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build();
1127             }
1128
1129             return filter.getRule();
1130
1131         }, e -> {
1132             logger.debug(FETCH_DECODER_BY_TYPE_FAILED, this,
1133                 controllerName, topic, factClass, e.getMessage(), e);
1134             return (controllerName + ":" + topic + ":" + factClass);
1135         });
1136     }
1137
1138     /**
1139      * DELETE.
1140      *
1141      * @return response object
1142      */
1143     @Override
1144     @DELETE
1145     @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
1146     public Response decoderFilterRuleDelete(
1147         @PathParam("controller") String controllerName,
1148         @PathParam("topic") String topic,
1149         @PathParam("factType") String factClass) {
1150
1151         return catchArgStateGenericEx(() -> {
1152             var drools = this.getDroolsController(controllerName);
1153             final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1154                 .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1155
1156             final CoderFilters filters = decoder.getCoder(factClass);
1157             if (filters == null) {
1158                 return Response.status(Response.Status.BAD_REQUEST)
1159                     .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build();
1160             }
1161
1162             final JsonProtocolFilter filter = filters.getFilter();
1163             if (filter == null) {
1164                 return Response.status(Response.Status.BAD_REQUEST)
1165                     .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build();
1166             }
1167
1168             filter.setRule(null);
1169             return filter.getRule();
1170
1171         }, e -> {
1172             logger.debug(FETCH_DECODER_BY_TYPE_FAILED,
1173                 this, controllerName, topic, factClass, e.getMessage(), e);
1174             return (controllerName + ":" + topic + ":" + factClass);
1175         });
1176     }
1177
1178     /**
1179      * PUT.
1180      *
1181      * @return response object
1182      */
1183     @Override
1184     @PUT
1185     @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
1186     public Response decoderFilterRule(
1187         @PathParam("controller") String controllerName,
1188         @PathParam("topic") String topic,
1189         @PathParam("factType") String factClass,
1190         String rule) {
1191
1192         return catchArgStateGenericEx(() -> decoderFilterRule2(controllerName, topic, factClass, rule), e -> {
1193             logger.debug("{}: cannot access decoder filter rules for policy-controller {} "
1194                 + "topic {} type {} because of {}",
1195                 this, controllerName, topic, factClass, e.getMessage(), e);
1196             return (controllerName + ":" + topic + ":" + factClass);
1197         });
1198     }
1199
1200     private Object decoderFilterRule2(String controllerName, String topic, String factClass, String rule) {
1201         var drools = this.getDroolsController(controllerName);
1202         final ProtocolCoderToolset decoder = EventProtocolCoderConstants.getManager()
1203             .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
1204
1205         final CoderFilters filters = decoder.getCoder(factClass);
1206         if (filters == null) {
1207             return Response.status(Response.Status.BAD_REQUEST)
1208                 .entity(new Error(controllerName + ":" + topic + ":" + factClass + DOES_NOT_EXIST_MSG)).build();
1209         }
1210
1211         final JsonProtocolFilter filter = filters.getFilter();
1212         if (filter == null) {
1213             return Response.status(Response.Status.BAD_REQUEST)
1214                 .entity(new Error(controllerName + ":" + topic + ":" + factClass + NO_FILTERS)).build();
1215         }
1216
1217         if (rule == null || rule.isEmpty()) {
1218             return Response.status(Response.Status.BAD_REQUEST).entity(new Error(controllerName + ":" + topic + ":"
1219                 + factClass + " no filter rule provided")).build();
1220         }
1221
1222         filter.setRule(rule);
1223         return filter.getRule();
1224     }
1225
1226     /**
1227      * POST.
1228      *
1229      * @return response object
1230      */
1231     @Override
1232     @POST
1233     @Path("engine/controllers/{controller}/decoders/{topic}")
1234     @Consumes(MediaType.TEXT_PLAIN)
1235     public Response decode(
1236         @PathParam("controller") String controllerName,
1237         @PathParam("topic") String topic,
1238         String json) {
1239
1240         if (!checkValidNameInput(controllerName)) {
1241             return Response.status(Response.Status.NOT_ACCEPTABLE)
1242                 .entity(new Error("controllerName contains whitespaces " + NOT_ACCEPTABLE_MSG)).build();
1243         }
1244
1245         if (!checkValidNameInput(topic)) {
1246             return Response.status(Response.Status.NOT_ACCEPTABLE)
1247                 .entity(new Error("topic contains whitespaces " + NOT_ACCEPTABLE_MSG)).build();
1248         }
1249
1250         PolicyController policyController;
1251         try {
1252             policyController = PolicyControllerConstants.getFactory().get(controllerName);
1253         } catch (final IllegalArgumentException e) {
1254             logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this,
1255                 controllerName, topic, e.getMessage(), e);
1256             return Response.status(Response.Status.NOT_FOUND)
1257                 .entity(new Error(controllerName + ":" + topic + ":" + NOT_FOUND_MSG)).build();
1258         } catch (final IllegalStateException e) {
1259             logger.debug(FETCH_DECODERS_BY_TOPIC_FAILED, this,
1260                 controllerName, topic, e.getMessage(), e);
1261             return Response.status(Response.Status.NOT_ACCEPTABLE)
1262                 .entity(new Error(controllerName + ":" + topic + ":" + NOT_ACCEPTABLE_MSG)).build();
1263         }
1264
1265         var result = new CodingResult();
1266         result.setDecoding(false);
1267         result.setEncoding(false);
1268         result.setJsonEncoding(null);
1269
1270         Object event;
1271         try {
1272             event = EventProtocolCoderConstants.getManager().decode(policyController.getDrools().getGroupId(),
1273                 policyController.getDrools().getArtifactId(), topic, json);
1274             result.setDecoding(true);
1275         } catch (final Exception e) {
1276             logger.debug(FETCH_POLICY_BY_TOPIC_FAILED, this, controllerName, topic,
1277                 e.getMessage(), e);
1278             return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build();
1279         }
1280
1281         try {
1282             result.setJsonEncoding(EventProtocolCoderConstants.getManager().encode(topic, event));
1283             result.setEncoding(true);
1284         } catch (final Exception e) {
1285             // continue so to propagate decoding results ..
1286             logger.debug("{}: cannot encode for policy-controller {} topic {} because of {}", this, controllerName,
1287                 topic, e.getMessage(), e);
1288         }
1289
1290         return Response.status(Response.Status.OK).entity(result).build();
1291     }
1292
1293     /**
1294      * GET.
1295      *
1296      * @return response object
1297      */
1298     @Override
1299     @GET
1300     @Path("engine/controllers/{controller}/encoders")
1301     public Response encoderFilters(@PathParam("controller") String controllerName) {
1302
1303         return catchArgStateGenericEx(() -> {
1304             final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName);
1305             var drools = controller.getDrools();
1306             return EventProtocolCoderConstants.getManager()
1307                 .getEncoderFilters(drools.getGroupId(), drools.getArtifactId());
1308
1309         }, e -> {
1310             logger.debug(FETCH_ENCODER_BY_FILTER_FAILED, this, controllerName,
1311                 e.getMessage(), e);
1312             return (controllerName);
1313         });
1314     }
1315
1316     @Override
1317     @GET
1318     @Path("engine/topics")
1319     public Response topics() {
1320         return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager()).build();
1321     }
1322
1323     @Override
1324     @GET
1325     @Path("engine/topics/switches")
1326     public Response topicSwitches() {
1327         return Response.status(Response.Status.OK).entity(SWITCHES).build();
1328     }
1329
1330     /**
1331      * PUT.
1332      *
1333      * @return response object
1334      */
1335     @Override
1336     @PUT
1337     @Path("engine/topics/switches/lock")
1338     public Response topicsLock() {
1339         final boolean success = TopicEndpointManager.getManager().lock();
1340         if (success) {
1341             return Response.status(Status.OK).entity(TopicEndpointManager.getManager()).build();
1342         } else {
1343             return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build();
1344         }
1345     }
1346
1347     /**
1348      * DELETE.
1349      *
1350      * @return response object
1351      */
1352     @Override
1353     @DELETE
1354     @Path("engine/topics/switches/lock")
1355     public Response topicsUnlock() {
1356         final boolean success = TopicEndpointManager.getManager().unlock();
1357         if (success) {
1358             return Response.status(Status.OK).entity(TopicEndpointManager.getManager()).build();
1359         } else {
1360             return Response.status(Status.NOT_ACCEPTABLE).entity(new Error(CANNOT_PERFORM_OPERATION)).build();
1361         }
1362     }
1363
1364     /**
1365      * GET.
1366      *
1367      * @return response object
1368      */
1369     @Override
1370     @GET
1371     @Path("engine/topics/sources")
1372     public Response sources() {
1373         return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager().getTopicSources()).build();
1374     }
1375
1376     /**
1377      * GET.
1378      *
1379      * @return response object
1380      */
1381     @Override
1382     @GET
1383     @Path("engine/topics/sinks")
1384     public Response sinks() {
1385         return Response.status(Response.Status.OK).entity(TopicEndpointManager.getManager().getTopicSinks()).build();
1386     }
1387
1388     /**
1389      * GET sources of a communication type.
1390      */
1391     @Override
1392     @GET
1393     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}")
1394     public Response commSources(
1395         @PathParam("comm") String comm) {
1396         if (!checkValidNameInput(comm)) {
1397             return Response
1398                 .status(Response.Status.NOT_ACCEPTABLE)
1399                 .entity(new Error("source communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG))
1400                 .build();
1401         }
1402
1403         List<TopicSource> sources = new ArrayList<>();
1404         var status = Status.OK;
1405         switch (CommInfrastructure.valueOf(comm.toUpperCase())) {
1406             case UEB:
1407                 sources.addAll(TopicEndpointManager.getManager().getUebTopicSources());
1408                 break;
1409             case DMAAP:
1410                 sources.addAll(TopicEndpointManager.getManager().getDmaapTopicSources());
1411                 break;
1412             case NOOP:
1413                 sources.addAll(TopicEndpointManager.getManager().getNoopTopicSources());
1414                 break;
1415             default:
1416                 status = Status.BAD_REQUEST;
1417                 logger.debug("Invalid communication mechanism");
1418                 break;
1419         }
1420         return Response.status(status).entity(sources).build();
1421     }
1422
1423     /**
1424      * GET sinks of a communication type.
1425      */
1426     @Override
1427     @GET
1428     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}")
1429     public Response commSinks(
1430         @PathParam("comm") String comm) {
1431         if (!checkValidNameInput(comm)) {
1432             return Response
1433                 .status(Response.Status.NOT_ACCEPTABLE)
1434                 .entity(new Error("sink communication mechanism contains whitespaces " + NOT_ACCEPTABLE_MSG))
1435                 .build();
1436         }
1437
1438         List<TopicSink> sinks = new ArrayList<>();
1439         var status = Status.OK;
1440         switch (CommInfrastructure.valueOf(comm.toUpperCase())) {
1441             case UEB:
1442                 sinks.addAll(TopicEndpointManager.getManager().getUebTopicSinks());
1443                 break;
1444             case DMAAP:
1445                 sinks.addAll(TopicEndpointManager.getManager().getDmaapTopicSinks());
1446                 break;
1447             case NOOP:
1448                 sinks.addAll(TopicEndpointManager.getManager().getNoopTopicSinks());
1449                 break;
1450             default:
1451                 status = Status.BAD_REQUEST;
1452                 logger.debug("Invalid communication mechanism");
1453                 break;
1454         }
1455         return Response.status(status).entity(sinks).build();
1456     }
1457
1458     /**
1459      * GET a source.
1460      */
1461     @Override
1462     @GET
1463     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}")
1464     public Response sourceTopic(
1465         @PathParam("comm") String comm,
1466         @PathParam("topic") String topic) {
1467         return Response
1468             .status(Response.Status.OK)
1469             .entity(TopicEndpointManager.getManager()
1470                 .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic))
1471             .build();
1472     }
1473
1474     /**
1475      * GET a sink.
1476      */
1477     @Override
1478     @GET
1479     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}")
1480     public Response sinkTopic(
1481         @PathParam("comm") String comm,
1482         @PathParam("topic") String topic) {
1483         return Response
1484             .status(Response.Status.OK)
1485             .entity(TopicEndpointManager.getManager()
1486                 .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic))
1487             .build();
1488     }
1489
1490     /**
1491      * GET a source events.
1492      */
1493     @Override
1494     @GET
1495     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/events")
1496     public Response sourceEvents(
1497         @PathParam("comm") String comm,
1498         @PathParam("topic") String topic) {
1499         return Response.status(Status.OK)
1500             .entity(Arrays.asList(TopicEndpointManager.getManager()
1501                 .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic)
1502                 .getRecentEvents()))
1503             .build();
1504     }
1505
1506     /**
1507      * GET a sink events.
1508      */
1509     @Override
1510     @GET
1511     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/events")
1512     public Response sinkEvents(
1513         @PathParam("comm") String comm,
1514         @PathParam("topic") String topic) {
1515         return Response.status(Status.OK)
1516             .entity(Arrays.asList(TopicEndpointManager.getManager()
1517                 .getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic)
1518                 .getRecentEvents()))
1519             .build();
1520     }
1521
1522     /**
1523      * GET source topic switches.
1524      */
1525     @Override
1526     @GET
1527     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/switches")
1528     public Response commSourceTopicSwitches(
1529         @PathParam("comm") String comm,
1530         @PathParam("topic") String topic) {
1531         return Response.status(Response.Status.OK).entity(SWITCHES).build();
1532     }
1533
1534     /**
1535      * GET sink topic switches.
1536      */
1537     @Override
1538     @GET
1539     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/switches")
1540     public Response commSinkTopicSwitches(
1541         @PathParam("comm") String comm,
1542         @PathParam("topic") String topic) {
1543         return Response.status(Response.Status.OK).entity(SWITCHES).build();
1544     }
1545
1546     /**
1547      * PUTs a lock on a topic.
1548      */
1549     @Override
1550     @PUT
1551     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/switches/lock")
1552     public Response commSourceTopicLock(
1553         @PathParam("comm") String comm,
1554         @PathParam("topic") String topic) {
1555         var source =
1556             TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1557         return getResponse(topic, source.lock(), source);
1558     }
1559
1560     /**
1561      * DELETEs the lock on a topic.
1562      */
1563     @Override
1564     @DELETE
1565     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/switches/lock")
1566     public Response commSourceTopicUnlock(
1567         @PathParam("comm") String comm,
1568         @PathParam("topic") String topic) {
1569         var source =
1570             TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1571         return getResponse(topic, source.unlock(), source);
1572     }
1573
1574     /**
1575      * Starts a topic source.
1576      */
1577     @Override
1578     @PUT
1579     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/switches/activation")
1580     public Response commSourceTopicActivation(
1581         @PathParam("comm") String comm,
1582         @PathParam("topic") String topic) {
1583         var source =
1584             TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1585         return getResponse(topic, source.start(), source);
1586     }
1587
1588     /**
1589      * Stops a topic source.
1590      */
1591     @Override
1592     @DELETE
1593     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/switches/activation")
1594     public Response commSourceTopicDeactivation(
1595         @PathParam("comm") String comm,
1596         @PathParam("topic") String topic) {
1597         var source =
1598             TopicEndpointManager.getManager().getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1599         return getResponse(topic, source.stop(), source);
1600     }
1601
1602     /**
1603      * PUTs a lock on a topic.
1604      */
1605     @Override
1606     @PUT
1607     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/switches/lock")
1608     public Response commSinkTopicLock(
1609         @PathParam("comm") String comm,
1610         @PathParam("topic") String topic) {
1611         var sink =
1612             TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1613         return getResponse(topic, sink.lock(), sink);
1614     }
1615
1616     /**
1617      * DELETEs the lock on a topic.
1618      */
1619     @Override
1620     @DELETE
1621     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/switches/lock")
1622     public Response commSinkTopicUnlock(
1623         @PathParam("comm") String comm,
1624         @PathParam("topic") String topic) {
1625         var sink =
1626             TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1627         return getResponse(topic, sink.unlock(), sink);
1628     }
1629
1630     /**
1631      * Starts a topic sink.
1632      */
1633     @Override
1634     @PUT
1635     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/switches/activation")
1636     public Response commSinkTopicActivation(
1637         @PathParam("comm") String comm,
1638         @PathParam("topic") String topic) {
1639         var sink =
1640             TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1641         return getResponse(topic, sink.start(), sink);
1642     }
1643
1644     /**
1645      * Stops a topic sink.
1646      */
1647     @Override
1648     @DELETE
1649     @Path("engine/topics/sinks/{comm: ueb|dmaap|noop}/{topic}/switches/activation")
1650     public Response commSinkTopicDeactivation(
1651         @PathParam("comm") String comm,
1652         @PathParam("topic") String topic) {
1653         var sink =
1654             TopicEndpointManager.getManager().getTopicSink(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1655         return getResponse(topic, sink.stop(), sink);
1656     }
1657
1658     private Response getResponse(String topicName, boolean success, Topic topic) {
1659         if (success) {
1660             return Response.status(Status.OK).entity(topic).build();
1661         } else {
1662             return Response.status(Status.NOT_ACCEPTABLE).entity(makeTopicOperError(topicName)).build();
1663         }
1664     }
1665
1666     private Error makeTopicOperError(String topic) {
1667         return new Error("cannot perform operation on " + topic);
1668     }
1669
1670     /**
1671      * Offers an event to a topic in a communication infrastructure.
1672      *
1673      * @return response object
1674      */
1675     @Override
1676     @PUT
1677     @Path("engine/topics/sources/{comm: ueb|dmaap|noop}/{topic}/events")
1678     @Consumes(MediaType.TEXT_PLAIN)
1679     public Response commEventOffer(
1680         @PathParam("comm") String comm,
1681         @PathParam("topic") String topic,
1682         String json) {
1683
1684         return catchArgStateGenericEx(() -> {
1685             var source = TopicEndpointManager.getManager()
1686                 .getTopicSource(CommInfrastructure.valueOf(comm.toUpperCase()), topic);
1687             if (source.offer(json)) {
1688                 return Arrays.asList(source.getRecentEvents());
1689             } else {
1690                 return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("Failure to inject event over " + topic))
1691                     .build();
1692             }
1693
1694         }, e -> {
1695             logger.debug(OFFER_FAILED, this, topic, e.getMessage(), e);
1696             return (topic);
1697         });
1698     }
1699
1700     /**
1701      * GET.
1702      *
1703      * @return response object
1704      */
1705     @Override
1706     @GET
1707     @Path("engine/tools/uuid")
1708     @Produces(MediaType.TEXT_PLAIN)
1709     public Response uuid() {
1710         return Response.status(Status.OK).entity(UUID.randomUUID().toString()).build();
1711     }
1712
1713     /**
1714      * GET.
1715      *
1716      * @return response object
1717      */
1718     @Override
1719     @GET
1720     @Path("engine/tools/loggers")
1721     public Response loggers() {
1722         final List<String> names = new ArrayList<>();
1723         if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) {
1724             logger.warn("The SLF4J logger factory is not configured for logback");
1725             return Response.status(Status.INTERNAL_SERVER_ERROR).entity(names).build();
1726         }
1727
1728         final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
1729         for (final Logger lgr : context.getLoggerList()) {
1730             names.add(lgr.getName());
1731         }
1732
1733         return Response.status(Status.OK).entity(names).build();
1734     }
1735
1736     /**
1737      * GET.
1738      *
1739      * @return response object
1740      */
1741     @Override
1742     @GET
1743     @Path("engine/tools/loggers/{logger}")
1744     @Produces(MediaType.TEXT_PLAIN)
1745     public Response loggerName1(@PathParam("logger") String loggerName) {
1746         if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) {
1747             logger.warn("The SLF4J logger factory is not configured for logback");
1748             return Response.status(Status.INTERNAL_SERVER_ERROR).build();
1749         }
1750
1751         final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
1752         var lgr = context.getLogger(loggerName);
1753         if (lgr == null) {
1754             return Response.status(Status.NOT_FOUND).build();
1755         }
1756
1757         final String loggerLevel = (lgr.getLevel() != null) ? lgr.getLevel().toString() : "";
1758         return Response.status(Status.OK).entity(loggerLevel).build();
1759     }
1760
1761     /**
1762      * PUT.
1763      *
1764      * @return response object
1765      */
1766     @Override
1767     @PUT
1768     @Path("engine/tools/loggers/{logger}/{level}")
1769     @Produces(MediaType.TEXT_PLAIN)
1770     @Consumes(MediaType.TEXT_PLAIN)
1771     public Response loggerName(@PathParam("logger") String loggerName, @PathParam("level") String loggerLevel) {
1772
1773         String newLevel;
1774         try {
1775             if (!checkValidNameInput(loggerName)) {
1776                 return Response.status(Response.Status.NOT_ACCEPTABLE)
1777                     .entity(new Error("logger name: " + NOT_ACCEPTABLE_MSG))
1778                     .build();
1779             }
1780             if (!Pattern.matches("^[a-zA-Z]{3,5}$", loggerLevel)) {
1781                 return Response.status(Response.Status.NOT_ACCEPTABLE)
1782                     .entity(new Error("logger level: " + NOT_ACCEPTABLE_MSG))
1783                     .build();
1784             }
1785             newLevel = LoggerUtils.setLevel(loggerName, loggerLevel);
1786         } catch (final IllegalArgumentException e) {
1787             logger.warn("{}: invalid operation for logger {} and level {}", this, loggerName, loggerLevel, e);
1788             return Response.status(Status.NOT_FOUND).build();
1789         } catch (final IllegalStateException e) {
1790             logger.warn("{}: logging framework unavailable for {} / {}", this, loggerName, loggerLevel, e);
1791             return Response.status(Status.INTERNAL_SERVER_ERROR).build();
1792         }
1793
1794         return Response.status(Status.OK).entity(newLevel
1795
1796         ).build();
1797     }
1798
1799     /**
1800      * gets the underlying drools controller from the named policy controller.
1801      *
1802      * @param controllerName the policy controller name
1803      * @return the underlying drools controller
1804      * @throws IllegalArgumentException if an invalid controller name has been passed in
1805      */
1806     protected DroolsController getDroolsController(String controllerName) {
1807         final PolicyController controller = PolicyControllerConstants.getFactory().get(controllerName);
1808         if (controller == null) {
1809             throw new IllegalArgumentException(controllerName + DOES_NOT_EXIST_MSG);
1810         }
1811
1812         var drools = controller.getDrools();
1813         if (drools == null) {
1814             throw new IllegalArgumentException(controllerName + " has no drools configuration");
1815         }
1816
1817         return drools;
1818     }
1819
1820     /**
1821      * Invokes a function and returns the generated response, catching illegal argument,
1822      * illegal state, and generic runtime exceptions.
1823      *
1824      * @param responder function that will generate a response. If it returns a "Response"
1825      *        object, then that object is returned as-is. Otherwise, this method will
1826      *        return an "OK" Response, using the function's return value as the "entity"
1827      * @param errorMsg function that will generate an error message prefix to be included
1828      *        in responses generated as a result of catching an exception
1829      * @return a response
1830      */
1831     private Response catchArgStateGenericEx(Supplier<Object> responder, Function<Exception, String> errorMsg) {
1832         try {
1833             Object result = responder.get();
1834             if (result instanceof Response) {
1835                 return (Response) result;
1836             }
1837
1838             return Response.status(Response.Status.OK).entity(result).build();
1839
1840         } catch (final IllegalArgumentException e) {
1841             return Response.status(Response.Status.NOT_FOUND).entity(new Error(errorMsg.apply(e) + NOT_FOUND_MSG))
1842                 .build();
1843
1844         } catch (final IllegalStateException e) {
1845             return Response.status(Response.Status.NOT_ACCEPTABLE)
1846                 .entity(new Error(errorMsg.apply(e) + NOT_ACCEPTABLE_MSG)).build();
1847
1848         } catch (final RuntimeException e) {
1849             errorMsg.apply(e);
1850             return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build();
1851         }
1852     }
1853
1854     public static boolean checkValidNameInput(String test) {
1855         return Pattern.matches("\\S+", test);
1856     }
1857
1858     /*
1859      * Helper classes for aggregation of results
1860      */
1861
1862     /**
1863      * Coding/Encoding Results Aggregation Helper class.
1864      */
1865     @Getter
1866     @Setter
1867     public static class CodingResult {
1868         /**
1869          * serialized output.
1870          */
1871
1872         private String jsonEncoding;
1873         /**
1874          * encoding result.
1875          */
1876
1877         private Boolean encoding;
1878
1879         /**
1880          * decoding result.
1881          */
1882         private Boolean decoding;
1883     }
1884
1885     /**
1886      * Generic Error Reporting class.
1887      */
1888     @AllArgsConstructor
1889     public static class Error {
1890         private String msg;
1891
1892         public String getError() {
1893             return msg;
1894         }
1895
1896         public void setError(String msg) {
1897             this.msg = msg;
1898         }
1899     }
1900 }