2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.policy.controlloop;
23 import org.onap.policy.controlloop.params.ControlLoopParams;
24 import org.onap.policy.controlloop.VirtualControlLoopEvent;
25 import org.onap.policy.controlloop.VirtualControlLoopNotification;
26 import org.onap.policy.controlloop.ControlLoopEventStatus;
27 import org.onap.policy.controlloop.ControlLoopNotificationType;
28 import org.onap.policy.controlloop.ControlLoopLogger;
29 import org.onap.policy.controlloop.policy.PolicyResult;
30 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
31 import org.onap.policy.controlloop.policy.Policy;
32 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager;
33 import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager.NEW_EVENT_STATUS;
34 import org.onap.policy.controlloop.eventmanager.ControlLoopOperationManager;
35 import org.onap.policy.controlloop.actor.so.SOActorServiceProvider;
36 import org.onap.policy.aai.AaiNqResponseWrapper;
37 import org.onap.policy.appc.Request;
38 import org.onap.policy.appc.Response;
39 import org.onap.policy.appc.CommonHeader;
40 import org.onap.policy.appclcm.LcmRequestWrapper;
41 import org.onap.policy.appclcm.LcmResponseWrapper;
42 import org.onap.policy.appclcm.LcmRequest;
43 import org.onap.policy.appclcm.LcmResponse;
44 import org.onap.policy.appclcm.LcmCommonHeader;
45 import org.onap.policy.sdnr.PciRequestWrapper;
46 import org.onap.policy.sdnr.PciResponseWrapper;
47 import org.onap.policy.sdnr.PciRequest;
48 import org.onap.policy.sdnr.PciResponse;
49 import org.onap.policy.vfc.VFCRequest;
50 import org.onap.policy.vfc.VFCResponse;
51 import org.onap.policy.vfc.VFCManager;
52 import org.onap.policy.so.SOManager;
53 import org.onap.policy.so.SORequest;
54 import org.onap.policy.so.SORequestStatus;
55 import org.onap.policy.so.SORequestDetails;
56 import org.onap.policy.so.SOModelInfo;
57 import org.onap.policy.so.SOCloudConfiguration;
58 import org.onap.policy.so.SORequestInfo;
59 import org.onap.policy.so.SORequestParameters;
60 import org.onap.policy.so.SORelatedInstanceListElement;
61 import org.onap.policy.so.SORelatedInstance;
62 import org.onap.policy.so.SOResponse;
63 import org.onap.policy.so.SOResponseWrapper;
64 import org.onap.policy.guard.PolicyGuard;
65 import org.onap.policy.guard.PolicyGuard.LockResult;
66 import org.onap.policy.guard.TargetLock;
67 import org.onap.policy.guard.GuardResult;
68 import org.onap.policy.guard.PolicyGuardRequest;
69 import org.onap.policy.guard.PolicyGuardResponse;
70 import org.onap.policy.guard.PolicyGuardXacmlRequestAttributes;
71 import org.onap.policy.guard.PolicyGuardXacmlHelper;
73 import org.yaml.snakeyaml.Yaml;
74 import org.yaml.snakeyaml.constructor.Constructor;
76 import org.slf4j.LoggerFactory;
77 import org.slf4j.Logger;
79 import java.time.Instant;
80 import java.util.LinkedList;
81 import java.util.Iterator;
83 import org.onap.policy.drools.system.PolicyEngine;
86 * This object is to provide support for timeouts
87 * due to a bug in drools' built-in timers
89 declare ControlLoopTimer
90 closedLoopControlName : String
94 //timerType is the type of timer: either "ClosedLoop" or "Operation"
100 * Called when the ControlLoopParams object has been inserted into working memory from the BRMSGW.
105 $params : ControlLoopParams()
108 // Note: globals have bad behavior when persistence is used,
109 // hence explicitly getting the logger vs using a global
111 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
112 logger.info("{}: {} : YAML=[{}]", $params.getClosedLoopControlName(), $params.getPolicyName() + "." + drools.getRule().getName(), $params.getControlLoopYaml());
117 * This rule responds to DCAE Events where there is no manager yet. Either it is
118 * the first ONSET, or a subsequent badly formed Event (i.e. Syntax error, or is-closed-loop-disabled)
123 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
124 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
125 not ( ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() ) )
128 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
129 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
134 // Check the event, because we need it to not be null when
135 // we create the ControlLoopEventManager. The ControlLoopEventManager
136 // will do extra syntax checking as well check if the closed loop is disabled.
138 if ($event.getRequestId() == null) {
139 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
140 notification.setNotification(ControlLoopNotificationType.REJECTED);
141 notification.setFrom("policy");
142 notification.setMessage("Missing requestID");
143 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
144 notification.setPolicyScope($params.getPolicyScope());
145 notification.setPolicyVersion($params.getPolicyVersion());
148 // Let interested parties know
150 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
153 // Retract it from memory
156 } else if ($event.getClosedLoopEventStatus() != ControlLoopEventStatus.ONSET) {
157 throw new ControlLoopException($event.getClosedLoopEventStatus() + " received with no prior onset");
160 // Create an EventManager
162 ControlLoopEventManager manager = new ControlLoopEventManager($clName, $event.getRequestId());
164 // Determine if EventManager can actively process the event (i.e. syntax, is_closed_loop_disabled checks etc.)
166 VirtualControlLoopNotification notification = manager.activate($params.getControlLoopYaml(), $event);
167 notification.setFrom("pdp-0001-controller=controlloop"); // Engine.getInstanceName()
168 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
169 notification.setPolicyScope($params.getPolicyScope());
170 notification.setPolicyVersion($params.getPolicyVersion());
172 // Are we actively pursuing this event?
174 if (notification.getNotification() == ControlLoopNotificationType.ACTIVE) {
176 // Insert Event Manager into memory, this will now kick off processing.
180 // Let interested parties know
182 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
184 // Setup the Overall Control Loop timer
186 ControlLoopTimer clTimer = new ControlLoopTimer();
187 clTimer.setTimerType("ClosedLoop");
188 clTimer.setClosedLoopControlName($event.getClosedLoopControlName());
189 clTimer.setRequestID($event.getRequestId().toString());
190 clTimer.setDelay(manager.getControlLoopTimeout(1500) + "s");
197 // Let interested parties know
199 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
201 // Retract it from memory
207 // Now that the manager is inserted into Drools working memory, we'll wait for
208 // another rule to fire in order to continue processing. This way we can also
209 // then screen for additional ONSET and ABATED events for this RequestID.
212 } catch (Exception e) {
213 logger.warn("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName(), e);
215 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
216 notification.setNotification(ControlLoopNotificationType.REJECTED);
217 notification.setMessage("Exception occurred: " + e.getMessage());
218 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
219 notification.setPolicyScope($params.getPolicyScope());
220 notification.setPolicyVersion($params.getPolicyVersion());
224 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
234 * This rule happens when we got a valid ONSET, closed loop is enabled and an Event Manager
235 * is now created. We can start processing the yaml specification via the Event Manager.
240 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
241 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
242 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
243 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", !expired )
246 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
247 logger.info("{}: {}: event={} manager={} clTimer={}",
248 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
249 $event, $manager, $clTimer);
253 // Check which event this is.
255 ControlLoopEventManager.NEW_EVENT_STATUS eventStatus = $manager.onNewEvent($event);
257 // Check what kind of event this is
259 if (eventStatus == NEW_EVENT_STATUS.SUBSEQUENT_ONSET) {
261 // We don't care about subsequent onsets
263 logger.info("{}: {}: subsequent onset",
264 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
268 if (eventStatus == NEW_EVENT_STATUS.SYNTAX_ERROR) {
270 // Ignore any bad syntax events
272 logger.warn("{}: {}: syntax error",
273 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
278 // We only want the initial ONSET event in memory,
279 // all the other events need to be retracted to support
280 // cleanup and avoid the other rules being fired for this event.
282 if (eventStatus != NEW_EVENT_STATUS.FIRST_ONSET) {
283 logger.warn("{}: {}: no first onset",
284 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
288 logger.debug("{}: {}: target={}", $clName,
289 $params.getPolicyName() + "." + drools.getRule().getName(), $event.getTarget());
291 // Now start seeing if we need to process this event
295 // Check if this is a Final Event
297 VirtualControlLoopNotification notification = $manager.isControlLoopFinal();
300 if (notification != null) {
302 // Its final, but are we waiting for abatement?
304 if ($manager.getNumAbatements() > 0) {
305 logger.info("{}: {}: abatement received for {}. Closing the control loop",
306 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
307 $event.getRequestId());
308 notification.setFrom("policy");
309 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
310 notification.setPolicyScope($params.getPolicyScope());
311 notification.setPolicyVersion($params.getPolicyVersion());
313 // In this case, we are done
315 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
319 TargetLock lock = $manager.unlockCurrentOperation();
321 logger.debug("{}: {}: retracting lock=", $clName,
322 $params.getPolicyName() + "." + drools.getRule().getName(), lock);
326 // Retract everything from memory
328 logger.info("{}: {}: retracting onset, manager, and timer",
329 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
331 retract($manager.getOnsetEvent());
335 // TODO - what if we get subsequent Events for this RequestID?
336 // By default, it will all start over again. May be confusing for Ruby.
337 // Or, we could track this and then subsequently ignore the events
341 // Check whether we need to wait for abatement
343 if ($manager.getProcessor().getControlLoop().getAbatement() == true && notification.getNotification() == ControlLoopNotificationType.FINAL_SUCCESS) {
344 logger.info("{}: {}: waiting for abatement ..",
345 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
347 logger.info("{}: {}: no abatement expect for {}. Closing the control loop",
348 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
349 $event.getRequestId());
351 notification.setFrom("policy");
352 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
353 notification.setPolicyScope($params.getPolicyScope());
354 notification.setPolicyVersion($params.getPolicyVersion());
357 // In this case, we are done
359 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
363 TargetLock lock = $manager.unlockCurrentOperation();
365 logger.debug("{}: {}: retracting lock=", $clName,
366 $params.getPolicyName() + "." + drools.getRule().getName(), lock);
370 // Retract everything from memory
372 logger.info("{}: {}: retracting onset, manager, and timer",
373 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
375 retract($manager.getOnsetEvent());
382 // NOT final, so let's ask for the next operation
384 ControlLoopOperationManager operation = $manager.processControlLoop();
385 if (operation != null) {
387 // Let's ask for a lock right away
389 LockResult<GuardResult, TargetLock> result = $manager.lockCurrentOperation();
390 logger.info("{}: {}: guard lock acquired={}",
391 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
393 if (result.getA().equals(GuardResult.LOCK_ACQUIRED)) {
395 // insert the operation into memory
400 // insert operation timeout object
402 ControlLoopTimer opTimer = new ControlLoopTimer();
403 opTimer.setTimerType("Operation");
404 opTimer.setClosedLoopControlName($event.getClosedLoopControlName());
405 opTimer.setRequestID($event.getRequestId().toString());
406 opTimer.setDelay(operation.getOperationTimeout().toString() + "s");
410 // Insert lock into memory
412 insert(result.getB());
415 logger.debug("The target resource {} is already processing",
416 $event.getAai().get($event.getTarget()));
417 notification = new VirtualControlLoopNotification($event);
418 notification.setNotification(ControlLoopNotificationType.REJECTED);
419 notification.setMessage("The target " + $event.getAai().get($event.getTarget()) + " is already locked");
420 notification.setFrom("policy");
421 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
422 notification.setPolicyScope($params.getPolicyScope());
423 notification.setPolicyVersion($params.getPolicyVersion());
425 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
431 if(result.getB() != null) {
432 retract(result.getB());
435 logger.info("{}: {}: starting operation={}",
436 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
440 // Probably waiting for abatement
442 logger.info("{}: {}: no operation, probably waiting for abatement",
443 $clName, $params.getPolicyName() + "." + drools.getRule().getName());
446 } catch (Exception e) {
447 logger.warn("{}: {}: unexpected",
449 $params.getPolicyName() + "." + drools.getRule().getName(), e);
451 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
452 notification.setNotification(ControlLoopNotificationType.FINAL_FAILURE);
453 notification.setMessage(e.getMessage());
454 notification.setFrom("policy");
455 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
456 notification.setPolicyScope($params.getPolicyScope());
457 notification.setPolicyVersion($params.getPolicyVersion());
459 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
470 * Guard Permitted, let's send request to the actor.
473 rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_PERMITTED"
475 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
476 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
477 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
478 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), "Permit".equalsIgnoreCase(getGuardApprovalStatus()) )
479 $lock : TargetLock (requestID == $event.getRequestId())
480 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
483 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
484 logger.info("{}: {}: event={} manager={} operation={} lock={}",
485 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
486 $event, $manager, $operation, $lock);
488 Object request = null;
489 boolean caughtException = false;
492 request = $operation.startOperation($event);
494 if (request != null) {
495 logger.debug("{}: {}: starting operation ..",
497 $params.getPolicyName() + "." + drools.getRule().getName());
499 // Tell interested parties we are performing this Operation
501 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
502 notification.setNotification(ControlLoopNotificationType.OPERATION);
503 notification.setMessage($operation.getOperationMessage());
504 notification.setHistory($operation.getHistory());
505 notification.setFrom("policy");
506 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
507 notification.setPolicyScope($params.getPolicyScope());
508 notification.setPolicyVersion($params.getPolicyVersion());
510 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
512 switch ($operation.policy.getActor()){
516 if (request instanceof Request) {
517 PolicyEngine.manager.deliver("APPC-CL", request);
519 else if (request instanceof LcmRequestWrapper) {
520 PolicyEngine.manager.deliver("APPC-LCM-READ", request);
524 // at this point the AAI named query request should have already been made, the response recieved and used
525 // in the construction of the SO Request which is stored in operationRequest
527 if(request instanceof SORequest) {
528 // Call SO. The response will be inserted into memory once it's received
529 SOActorServiceProvider.sendRequest($event.getRequestId().toString(), drools.getWorkingMemory(), request);
533 if (request instanceof VFCRequest) {
535 Thread t = new Thread(new VFCManager(drools.getWorkingMemory(), (VFCRequest)request));
540 if (request instanceof PciRequestWrapper) {
541 PolicyEngine.manager.deliver("SDNR-CL", request);
547 // What happens if its null?
549 logger.warn("{}: {}: unexpected null operation request",
551 $params.getPolicyName() + "." + drools.getRule().getName());
552 if ("SO".equals($operation.policy.getActor())) {
555 modify($manager) {finishOperation($operation)};
557 else if ("vfc".equalsIgnoreCase($operation.policy.getActor())) {
560 modify($manager) {finishOperation($operation)};
564 } catch (Exception e) {
565 String msg = e.getMessage();
566 logger.warn("{}: {}: operation={}: AAI failure: {}",
568 $params.getPolicyName() + "." + drools.getRule().getName(),
570 $operation.setOperationHasException(msg);
572 if(request != null) {
574 // Create a notification for it ("DB Write - end operation")
576 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
577 notification.setFrom("policy");
578 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
579 notification.setPolicyScope($params.getPolicyScope());
580 notification.setPolicyVersion($params.getPolicyVersion());
581 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
582 notification.setMessage($operation.getOperationHistory());
583 notification.setHistory($operation.getHistory());
585 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
590 caughtException = true;
593 // Having the modify statement in the catch clause doesn't work for whatever reason
594 if (caughtException) {
595 modify($manager) {finishOperation($operation)};
602 * We were able to acquire a lock so now let's ask Xacml Guard whether
603 * we are allowed to proceed with the request to the actor.
606 rule "EVENT.MANAGER.OPERATION.LOCKED.GUARD_NOT_YET_QUERIED"
608 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
609 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
610 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
611 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId(), getGuardApprovalStatus() == "NONE" )
612 $lock : TargetLock (requestID == $event.getRequestId())
615 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
616 logger.info("{}: {}: event={} manager={} operation={} lock={}",
617 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
618 $event, $manager, $operation, $lock);
621 // Sending notification that we are about to query Guard ("DB write - start operation")
623 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
624 notification.setNotification(ControlLoopNotificationType.OPERATION);
625 notification.setMessage("Sending guard query for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe());
626 notification.setHistory($operation.getHistory());
627 notification.setFrom("policy");
628 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
629 notification.setPolicyScope($params.getPolicyScope());
630 notification.setPolicyVersion($params.getPolicyVersion());
632 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
635 // Now send Guard Request to XACML Guard. In order to bypass the call to Guard,
636 // just change guardEnabled to false.
638 // In order to use REST XACML, provide a URL instead of "" as a second argument
639 // to the CallGuardTask() and set the first argument to null
640 // (instead of XacmlPdpEngine).
643 // NOTE: The environment properties uses "guard.disabled" but the boolean is guardEnabled
644 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
648 Thread t = new Thread(new org.onap.policy.guard.CallGuardTask(
649 drools.getWorkingMemory(),
650 $event.getClosedLoopControlName(),
651 $operation.policy.getActor().toString(),
652 $operation.policy.getRecipe(),
653 $operation.getTargetEntity(),
654 $event.getRequestId().toString(),
656 AaiNqResponseWrapper resp = $manager.getNqVserverFromAai();
657 return(resp == null ? null : resp.countVfModules());
662 insert(new PolicyGuardResponse("Permit", $event.getRequestId(), $operation.policy.getRecipe()));
668 // This rule will be triggered when a thread talking to the XACML Guard inserts a
669 // guardResponse object into the working memory
671 rule "GUARD.RESPONSE"
673 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
674 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
675 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
676 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
677 $lock : TargetLock (requestID == $event.getRequestId())
678 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
679 $guardResponse : PolicyGuardResponse(requestID == $event.getRequestId(), $operation.policy.recipe == operation)
682 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
683 logger.info("{}: {}: event={} manager={} operation={} lock={} opTimer={} guardResponse={}",
684 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
685 $event, $manager, $operation, $lock, $opTimer, $guardResponse);
688 //we will permit the operation if there was no Guard for it
689 if("Indeterminate".equalsIgnoreCase($guardResponse.getResult())){
690 $guardResponse.setResult("Permit");
694 // This notification has Guard result in "message". ("DB write - end operation in case of Guard Deny")
696 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
697 notification.setNotification(ControlLoopNotificationType.OPERATION);
698 notification.setMessage("Guard result for " + $operation.policy.getActor() + " " + $operation.policy.getRecipe() + " is " + $guardResponse.getResult());
699 notification.setHistory($operation.getHistory());
700 notification.setFrom("policy");
701 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
702 notification.setPolicyScope($params.getPolicyScope());
703 notification.setPolicyVersion($params.getPolicyVersion());
705 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
707 if("Permit".equalsIgnoreCase($guardResponse.getResult())){
709 modify($operation){setGuardApprovalStatus($guardResponse.getResult())};
712 //This is the Deny case
713 $operation.startOperation($event);
714 $operation.setOperationHasGuardDeny();
717 modify($manager) {finishOperation($operation)};
720 retract($guardResponse);
726 * This rule responds to APPC Response Events
728 * I would have like to be consistent and write the Response like this:
729 * $response : Response( CommonHeader.RequestId == $onset.getRequestId() )
731 * However, no compile error was given. But a runtime error was given. I think
732 * because drools is confused between the classname CommonHeader vs the property CommonHeader.
737 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
738 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
739 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
740 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
741 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
742 $lock : TargetLock (requestID == $event.getRequestId())
743 $response : Response( getCommonHeader().RequestId == $event.getRequestId() )
746 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
747 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
748 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
749 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
750 $event, $manager, $operation, $lock, $opTimer, $response);
752 // Get the result of the operation
754 PolicyResult policyResult = $operation.onResponse($response);
755 if (policyResult != null) {
756 logger.debug("{}: {}: operation finished - result={}",
757 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
760 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
762 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
763 notification.setFrom("policy");
764 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
765 notification.setPolicyScope($params.getPolicyScope());
766 notification.setPolicyVersion($params.getPolicyVersion());
767 notification.setMessage($operation.getOperationHistory());
768 notification.setHistory($operation.getHistory());
769 if (policyResult.equals(PolicyResult.SUCCESS)) {
770 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
772 // Let interested parties know
774 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
776 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
778 // Let interested parties know
780 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
783 // Ensure the operation is complete
785 if ($operation.isOperationComplete() == true) {
787 // It is complete, remove it from memory
791 // We must also retract the timer object
792 // NOTE: We could write a Rule to do this
796 // Complete the operation
798 modify($manager) {finishOperation($operation)};
801 // Just doing this will kick off the LOCKED rule again
803 modify($operation) {};
807 // Its not finished yet (i.e. expecting more Response objects)
809 // Or possibly it is a leftover response that we timed the request out previously
813 // We are going to retract these objects from memory
820 * The problem with Responses is that they don't have a controlLoopControlName
821 * field in them, so the only way to attach them is via RequestID. If we have multiple
822 * control loop .drl's loaded in the same container, we need to be sure the cleanup
823 * rules don't remove Responses for other control loops.
826 rule "APPC.RESPONSE.CLEANUP"
828 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
829 $response : Response($id : getCommonHeader().RequestId )
830 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
833 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
834 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
835 logger.debug("{}: {}: orphan appc response={}",
836 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
846 * This rule responds to APPC Response Events using the new LCM interface provided by appc
849 rule "APPC.LCM.RESPONSE"
851 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
852 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
853 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
854 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
855 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
856 $lock : TargetLock (requestID == $event.getRequestId())
857 $response : LcmResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
860 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
861 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
862 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
863 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
864 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
867 // Get the result of the operation
869 PolicyResult policyResult = $operation.onResponse($response);
870 if (policyResult != null) {
871 logger.debug("{}: {}: operation finished - result={}",
872 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
876 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
878 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
879 notification.setFrom("policy");
880 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
881 notification.setPolicyScope($params.getPolicyScope());
882 notification.setPolicyVersion($params.getPolicyVersion());
883 notification.setMessage($operation.getOperationHistory());
884 notification.setHistory($operation.getHistory());
885 if (policyResult.equals(PolicyResult.SUCCESS)) {
886 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
888 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
890 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
892 // Ensure the operation is complete
894 if ($operation.isOperationComplete() == true) {
896 // It is complete, remove it from memory
900 // We must also retract the timer object
901 // NOTE: We could write a Rule to do this
905 // Complete the operation
907 modify($manager) {finishOperation($operation)};
910 // Just doing this will kick off the LOCKED rule again
912 modify($operation) {};
916 // Its not finished yet (i.e. expecting more Response objects)
918 // Or possibly it is a leftover response that we timed the request out previously
922 // We are going to retract these objects from memory
929 * Clean Up any lingering LCM reponses
932 rule "APPC.LCM.RESPONSE.CLEANUP"
934 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
935 $response : LcmResponseWrapper($id : getBody().getCommonHeader().getRequestId )
936 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
939 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
940 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
941 logger.debug("{}: {}: orphan appc response={}",
942 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);
951 * This rule responds to SO Response Events
956 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
957 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
958 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
959 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
960 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
961 $lock : TargetLock (requestID == $event.getRequestId())
962 $response : SOResponseWrapper(requestID.toString() == $event.getRequestId().toString() )
965 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
966 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
967 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
968 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
969 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
971 // Get the result of the operation
973 PolicyResult policyResult = $operation.onResponse($response);
974 if (policyResult != null) {
975 logger.debug("{}: {}: operation finished - result={}",
976 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
980 // This Operation has completed, construct a notification showing our results
982 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
983 notification.setFrom("policy");
984 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
985 notification.setPolicyScope($params.getPolicyScope());
986 notification.setPolicyVersion($params.getPolicyVersion());
987 notification.setMessage($operation.getOperationHistory());
988 notification.setHistory($operation.getHistory());
989 if (policyResult.equals(PolicyResult.SUCCESS)) {
990 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
992 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
995 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
997 // Ensure the operation is complete
999 if ($operation.isOperationComplete() == true) {
1001 // It is complete, remove it from memory
1003 retract($operation);
1005 // We must also retract the timer object
1006 // NOTE: We could write a Rule to do this
1010 // Complete the operation
1012 modify($manager) {finishOperation($operation)};
1015 // Just doing this will kick off the LOCKED rule again
1017 modify($operation) {};
1021 // Its not finished yet (i.e. expecting more Response objects)
1023 // Or possibly it is a leftover response that we timed the request out previously
1027 // We are going to retract these objects from memory
1035 * This rule responds to VFC Response Events
1040 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1041 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1042 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1043 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1044 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1045 $lock : TargetLock (requestID == $event.getRequestId())
1046 $response : VFCResponse( requestId.toString() == $event.getRequestId().toString() )
1048 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1049 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1050 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1051 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1052 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1054 // Get the result of the operation
1056 PolicyResult policyResult = $operation.onResponse($response);
1057 if (policyResult != null) {
1059 // This Operation has completed, construct a notification showing our results
1061 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1062 notification.setFrom("policy");
1063 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1064 notification.setPolicyScope($params.getPolicyScope());
1065 notification.setPolicyVersion($params.getPolicyVersion());
1066 notification.setMessage($operation.getOperationHistory());
1067 notification.setHistory($operation.getHistory());
1069 // Ensure the operation is complete
1071 if ($operation.isOperationComplete() == true) {
1073 // It is complete, remove it from memory
1075 retract($operation);
1077 // We must also retract the timer object
1078 // NOTE: We could write a Rule to do this
1082 // Complete the operation
1084 modify($manager) {finishOperation($operation)};
1087 // Just doing this will kick off the LOCKED rule again
1089 modify($operation) {};
1093 // Its not finished yet (i.e. expecting more Response objects)
1095 // Or possibly it is a leftover response that we timed the request out previously
1099 // We are going to retract these objects from memory
1107 * This manages a single timer.
1108 * Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause
1112 timer (expr: $timeout)
1114 $timer : ControlLoopTimer($timeout : delay, !expired)
1116 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1117 logger.info("This is TIMER.FIRED");
1118 modify($timer){setExpired(true)};
1123 * This is the timer that manages the timeout for an individual operation.
1126 rule "EVENT.MANAGER.OPERATION.TIMEOUT"
1128 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1129 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1130 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1131 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1132 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", expired )
1133 $lock : TargetLock (requestID == $event.getRequestId())
1136 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1137 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1138 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={}",
1139 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1140 $event, $manager, $operation, $lock, $operation, $opTimer);
1143 // Tell it its timed out
1145 $operation.setOperationHasTimedOut();
1147 // Create a notification for it ("DB Write - end operation")
1149 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1150 notification.setFrom("policy");
1151 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1152 notification.setPolicyScope($params.getPolicyScope());
1153 notification.setPolicyVersion($params.getPolicyVersion());
1154 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1155 notification.setMessage($operation.getOperationHistory());
1156 notification.setHistory($operation.getHistory());
1158 // Let interested parties know
1160 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1162 // Get rid of the timer
1166 // Ensure the operation is complete
1168 if ($operation.isOperationComplete() == true) {
1170 // It is complete, remove it from memory
1172 retract($operation);
1174 // Complete the operation
1176 modify($manager) {finishOperation($operation)};
1179 // Just doing this will kick off the LOCKED rule again
1181 modify($operation) {};
1187 * This is the timer that manages the overall control loop timeout.
1190 rule "EVENT.MANAGER.TIMEOUT"
1192 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1193 $event : VirtualControlLoopEvent( closedLoopControlName == $clName )
1194 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1195 $clTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "ClosedLoop", expired )
1198 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1199 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1201 logger.debug("{}: {}: event={}",
1202 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1205 // Tell the Event Manager it has timed out
1207 VirtualControlLoopNotification notification = $manager.setControlLoopTimedOut();
1208 if (notification != null) {
1209 notification.setFrom("policy");
1210 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1211 notification.setPolicyScope($params.getPolicyScope());
1212 notification.setPolicyVersion($params.getPolicyVersion());
1214 // Let interested parties know
1216 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1219 // Retract the event
1226 * This rule cleans up the manager and other objects after an event has
1230 rule "EVENT.MANAGER.CLEANUP"
1232 $manager : ControlLoopEventManager( $clName : getClosedLoopControlName(), $requestId : getRequestID() )
1233 $operations : LinkedList()
1234 from collect( ControlLoopOperationManager( onset.closedLoopControlName == $clName, onset.getRequestId() == $requestId ) )
1235 $timers : LinkedList()
1236 from collect( ControlLoopTimer( closedLoopControlName == $clName, requestID == $requestId.toString() ) )
1237 $locks : LinkedList()
1238 from collect( TargetLock (requestID == $requestId) )
1239 not( VirtualControlLoopEvent( closedLoopControlName == $clName, requestId == $requestId ) )
1242 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1243 logger.info("{}: {}", $clName, drools.getRule().getName());
1245 logger.debug("{}: {}: manager={} timers={} operations={}",
1246 $clName, drools.getRule().getName(),
1247 $manager, $timers.size(), $operations.size());
1250 // Retract EVERYTHING
1254 for(Object manager: $operations) {
1255 retract((ControlLoopOperationManager) manager);
1257 for(Object timer: $timers) {
1258 retract((ControlLoopTimer) timer);
1260 for(Object lock: $locks) {
1261 TargetLock tgt = (TargetLock) lock;
1263 // Ensure we release the lock
1265 PolicyGuard.unlockTarget(tgt);
1272 * This rule will clean up any rogue onsets where there is no
1273 * ControlLoopParams object corresponding to the onset event.
1276 rule "EVENT.CLEANUP"
1278 $event : VirtualControlLoopEvent( $clName: closedLoopControlName )
1279 not ( ControlLoopParams( getClosedLoopControlName() == $clName) )
1282 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1283 logger.info("{}: {}", $clName, drools.getRule().getName());
1284 logger.debug("{}: {}: orphan onset event={}",
1285 $clName, drools.getRule().getName(), $event);
1292 * This rule responds to SDNR Response Events.
1295 rule "SDNR.RESPONSE"
1297 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1298 $event : VirtualControlLoopEvent( closedLoopControlName == $clName, closedLoopEventStatus == ControlLoopEventStatus.ONSET )
1299 $manager : ControlLoopEventManager( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId() )
1300 $operation : ControlLoopOperationManager( onset.closedLoopControlName == $event.getClosedLoopControlName(), onset.getRequestId() == $event.getRequestId() )
1301 $opTimer : ControlLoopTimer( closedLoopControlName == $event.getClosedLoopControlName(), requestID == $event.getRequestId().toString(), timerType == "Operation", !expired )
1302 $lock : TargetLock (requestID == $event.getRequestId())
1303 $response : PciResponseWrapper( getBody().getCommonHeader().getRequestId() == $event.getRequestId() )
1306 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1307 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1308 logger.debug("{}: {}: event={} manager={} operation={} lock={} opTimer={} response={}",
1309 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1310 $event, $manager, $operation, $lock, $operation, $opTimer, $response);
1313 // Get the result of the operation
1315 PolicyResult policyResult = $operation.onResponse($response);
1316 if (policyResult != null) {
1317 logger.debug("{}: {}: operation finished - result={}",
1318 $clName, $params.getPolicyName() + "." + drools.getRule().getName(),
1322 // This Operation has completed, construct a notification showing our results. (DB write - end operation)
1324 VirtualControlLoopNotification notification = new VirtualControlLoopNotification($event);
1325 notification.setFrom("policy");
1326 notification.setPolicyName($params.getPolicyName() + "." + drools.getRule().getName());
1327 notification.setPolicyScope($params.getPolicyScope());
1328 notification.setPolicyVersion($params.getPolicyVersion());
1329 notification.setMessage($operation.getOperationHistory());
1330 notification.setHistory($operation.getHistory());
1331 if (policyResult.equals(PolicyResult.SUCCESS)) {
1332 notification.setNotification(ControlLoopNotificationType.OPERATION_SUCCESS);
1334 notification.setNotification(ControlLoopNotificationType.OPERATION_FAILURE);
1336 PolicyEngine.manager.deliver("POLICY-CL-MGT", notification);
1338 // Ensure the operation is complete
1340 if ($operation.isOperationComplete() == true) {
1342 // It is complete, remove it from memory
1344 retract($operation);
1346 // We must also retract the timer object
1347 // NOTE: We could write a Rule to do this
1351 // Complete the operation
1353 modify($manager) {finishOperation($operation)};
1356 // Just doing this will kick off the LOCKED rule again
1358 modify($operation) {};
1362 // Its not finished yet (i.e. expecting more Response objects)
1364 // Or possibly it is a leftover response that we timed the request out previously
1368 // We are going to retract these objects from memory
1375 * Clean Up any lingering SDNR reponses.
1378 rule "SDNR.RESPONSE.CLEANUP"
1380 $params : ControlLoopParams( $clName : getClosedLoopControlName() )
1381 $response : PciResponseWrapper($id : getBody().getCommonHeader().getRequestId )
1382 not ( VirtualControlLoopEvent( requestId == $id, closedLoopEventStatus == ControlLoopEventStatus.ONSET ) )
1385 Logger logger = LoggerFactory.getLogger(drools.getRule().getPackage());
1386 logger.info("{}: {}", $clName, $params.getPolicyName() + "." + drools.getRule().getName());
1387 logger.debug("{}: {}: orphan sdnr response={}",
1388 $clName, $params.getPolicyName() + "." + drools.getRule().getName(), $id);