001/* 002 * Copyright 2025 devteam@scivics-lab.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, 011 * software distributed under the License is distributed on an 012 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the 014 * specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package com.scivicslab.actoriac; 019 020import java.util.concurrent.ExecutionException; 021import java.util.logging.Level; 022import java.util.logging.Logger; 023 024import org.json.JSONObject; 025 026import com.scivicslab.actoriac.log.DistributedLogStore; 027import com.scivicslab.actoriac.log.LogLevel; 028import com.scivicslab.pojoactor.core.ActionResult; 029import com.scivicslab.pojoactor.core.accumulator.Accumulator; 030import com.scivicslab.pojoactor.workflow.IIActorRef; 031import com.scivicslab.pojoactor.workflow.IIActorSystem; 032 033/** 034 * Accumulator actor reference that also logs to H2 database. 035 * 036 * <p>This class extends the standard accumulator functionality to also write 037 * logs to the H2LogStore for persistent storage. Each node's output is stored 038 * with the node ID for later querying.</p> 039 * 040 * <h2>Supported Actions</h2> 041 * <ul> 042 * <li>{@code add} - Adds a result and logs to database</li> 043 * <li>{@code getSummary} - Returns formatted summary of all results</li> 044 * <li>{@code getCount} - Returns the number of added results</li> 045 * <li>{@code clear} - Clears all accumulated results</li> 046 * </ul> 047 * 048 * @author devteam@scivics-lab.com 049 * @since 2.9.0 050 */ 051public class LoggingAccumulatorIIAR extends IIActorRef<Accumulator> { 052 053 private final Logger logger; 054 private final DistributedLogStore logStore; 055 private final long sessionId; 056 057 /** 058 * Constructs a new LoggingAccumulatorIIAR. 059 * 060 * @param actorName the name of this actor 061 * @param object the Accumulator implementation 062 * @param system the actor system 063 * @param logStore the distributed log store for database logging 064 * @param sessionId the session ID for this workflow execution 065 */ 066 public LoggingAccumulatorIIAR(String actorName, Accumulator object, IIActorSystem system, 067 DistributedLogStore logStore, long sessionId) { 068 super(actorName, object, system); 069 this.logger = Logger.getLogger(actorName); 070 this.logStore = logStore; 071 this.sessionId = sessionId; 072 } 073 074 @Override 075 public ActionResult callByActionName(String actionName, String arg) { 076 logger.fine(String.format("actionName = %s, arg = %s", actionName, arg)); 077 078 try { 079 switch (actionName) { 080 case "add": 081 return handleAdd(arg); 082 083 case "getSummary": 084 return handleGetSummary(); 085 086 case "getCount": 087 return handleGetCount(); 088 089 case "clear": 090 return handleClear(); 091 092 default: 093 logger.warning("Unknown action: " + actionName); 094 return new ActionResult(false, "Unknown action: " + actionName); 095 } 096 } catch (Exception e) { 097 logger.log(Level.SEVERE, "Error in " + actionName, e); 098 return new ActionResult(false, "Error: " + e.getMessage()); 099 } 100 } 101 102 /** 103 * Handles the add action. 104 * 105 * <p>Adds the result to the accumulator (for console output) and also 106 * logs to the H2 database for persistent storage.</p> 107 * 108 * @param arg JSON object with source, type, and data fields 109 * @return ActionResult indicating success or failure 110 */ 111 private ActionResult handleAdd(String arg) throws ExecutionException, InterruptedException { 112 JSONObject json = new JSONObject(arg); 113 String source = json.getString("source"); 114 String type = json.getString("type"); 115 String data = json.getString("data"); 116 117 // Add to accumulator (console output) 118 this.tell(acc -> acc.add(source, type, data)).get(); 119 120 // Log to H2 database 121 if (logStore != null && sessionId >= 0) { 122 // source = node ID (e.g., "node-192.168.1.1") 123 // type = vertex YAML snippet (what step is being executed) 124 // data = command output 125 logStore.logAction(sessionId, source, type, "executeCommand", 0, 0L, data); 126 } 127 128 return new ActionResult(true, "Added"); 129 } 130 131 /** 132 * Handles the getSummary action. 133 * 134 * @return ActionResult with the formatted summary 135 */ 136 private ActionResult handleGetSummary() throws ExecutionException, InterruptedException { 137 String summary = this.ask(Accumulator::getSummary).get(); 138 return new ActionResult(true, summary); 139 } 140 141 /** 142 * Handles the getCount action. 143 * 144 * @return ActionResult with the count 145 */ 146 private ActionResult handleGetCount() throws ExecutionException, InterruptedException { 147 int count = this.ask(Accumulator::getCount).get(); 148 return new ActionResult(true, String.valueOf(count)); 149 } 150 151 /** 152 * Handles the clear action. 153 * 154 * @return ActionResult indicating success 155 */ 156 private ActionResult handleClear() throws ExecutionException, InterruptedException { 157 this.tell(Accumulator::clear).get(); 158 return new ActionResult(true, "Cleared"); 159 } 160}