multiple source calculation

This commit is contained in:
Ali Sadeghi
2025-08-04 18:26:36 +03:30
parent 09933c8bbf
commit 831eab906b
7 changed files with 812 additions and 496 deletions

View File

@@ -2,8 +2,13 @@ package com.sgs.graphql.dataCenter.domain;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sgs.lib.dao.domain.BaseDomain;
import java.util.Map;
import java.util.HashMap;
import javax.persistence.*;
@Entity
@@ -18,9 +23,11 @@ public class VM extends BaseDomain {
private String host;
private String flavorName;
private String tag;
private String emissionSourceData; // JSON string to store emission source map
private Config config;
private PhysicalMachine physicalMachine;
@Column(name = "state")
public String getState() {
return state;
@@ -102,6 +109,15 @@ public class VM extends BaseDomain {
this.ip = ip;
}
@Column(name = "emission_source_data", columnDefinition = "text")
public String getEmissionSourceData() {
return emissionSourceData;
}
public void setEmissionSourceData(String emissionSourceData) {
this.emissionSourceData = emissionSourceData;
}
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "vm")
@JsonManagedReference
public Config getConfig() {
@@ -123,4 +139,33 @@ public class VM extends BaseDomain {
this.physicalMachine = physicalMachine;
}
// Helper methods for emission source map
@Transient
public Map<String, Integer> getEmissionSource() {
if (emissionSourceData == null || emissionSourceData.trim().isEmpty()) {
return new HashMap<>();
}
try {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(emissionSourceData, new TypeReference<Map<String, Integer>>() {});
} catch (Exception e) {
System.err.println("Error parsing emission source data: " + e.getMessage());
return new HashMap<>();
}
}
public void setEmissionSource(Map<String, Integer> emissionSource) {
if (emissionSource == null) {
this.emissionSourceData = null;
return;
}
try {
ObjectMapper mapper = new ObjectMapper();
this.emissionSourceData = mapper.writeValueAsString(emissionSource);
} catch (Exception e) {
System.err.println("Error serializing emission source data: " + e.getMessage());
this.emissionSourceData = null;
}
}
}

View File

@@ -2,6 +2,7 @@ package com.sgs.graphql.dataCenter.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
public class VMDto {
@JsonProperty("vm_name")
@@ -28,6 +29,9 @@ public class VMDto {
@JsonProperty("confg") // Note: keeping the typo from JSON
private List<Object> confg;
@JsonProperty("emissionsource")
private Map<String, Integer> emissionSource;
private String ip; // IP address from the message key
private boolean calcOn = false; // Derived from state: active = true, inactive = false
@@ -113,6 +117,14 @@ public class VMDto {
this.calcOn = calcOn;
}
public Map<String, Integer> getEmissionSource() {
return emissionSource;
}
public void setEmissionSource(Map<String, Integer> emissionSource) {
this.emissionSource = emissionSource;
}
// Helper method to get config as ConfigDto
public ConfigDto getConfig() {
if (confg != null && confg.size() >= 5) {

View File

@@ -92,7 +92,14 @@ public class MessageListener {
DataCenter entity = toDataCenterEntity(dto);
DataCenter dataCenter = createDataCenter(entity);
processEmissionCalculations(dataCenter);
// Save message processing success log
systemLogger.createSystemLog(LogType.INFO,
"VM data processed successfully for DataCenter ID: " + dataCenter.getExternalId());
// Process emission calculations in a separate transaction to avoid rollback issues
// This will be done asynchronously after the VM data is committed
processEmissionCalculationsAsync(dataCenter);
// System.out.println(entity.toString());
System.out.println("✅ Raw JSON message:\n" + message);
@@ -117,7 +124,11 @@ public class MessageListener {
//System.out.println("✅ Saved DataCenter:\n" + objectMapper.writeValueAsString(dataCenter));
} catch (Exception e) {
System.err.println("Mesaj işlenirken hata oluştu: " + e.getMessage());
System.err.println("Mesaj işlenirken hata oluştu: " + e.getMessage());
e.printStackTrace();
systemLogger.createSystemLog(LogType.ERROR,
"Error processing VM message: " + e.getMessage());
// Don't rethrow the exception to prevent transaction rollback
}
}
@@ -153,8 +164,14 @@ public class MessageListener {
// Handle config from confg array
entity.setConfig(toConfigEntity(dto.getConfig()));
// Handle emission source map
entity.setEmissionSource(dto.getEmissionSource());
// Debug logging
System.out.println("🔍 VM Entity Created: " + dto.getVmName() + " - state = " + dto.getState() + " - calcOn = " + dto.isCalcOn());
if (dto.getEmissionSource() != null && !dto.getEmissionSource().isEmpty()) {
System.out.println(" Emission Sources: " + dto.getEmissionSource());
}
return entity;
}
@@ -401,6 +418,7 @@ public class MessageListener {
vm.setHost(newVm.getHost());
vm.setFlavorName(newVm.getFlavorName());
vm.setTag(newVm.getTag());
vm.setEmissionSource(newVm.getEmissionSource());
System.out.println("✅ Updated existing VM: " + vm.getVmName() + " (IP: " + vm.getIp() + ") - calcOn = " + vm.getCalcOn());
} else {
@@ -450,6 +468,32 @@ public class MessageListener {
}
/**
* Process emission calculations asynchronously to avoid transaction conflicts
*/
public void processEmissionCalculationsAsync(DataCenter dataCenter) {
// Run emission calculations in a separate thread to avoid transaction issues
new Thread(() -> {
try {
// Wait a bit to ensure the transaction is committed and VMs have IDs
Thread.sleep(2000);
// Refresh the DataCenter to get the latest state with VM IDs
Optional<DataCenter> refreshedDcOpt = dataCenterRepo.findByExternalId(dataCenter.getExternalId());
if (refreshedDcOpt.isPresent()) {
DataCenter refreshedDc = refreshedDcOpt.get();
System.out.println("🔄 Processing emission calculations asynchronously for DataCenter: " + refreshedDc.getDataCenter());
processEmissionCalculations(refreshedDc);
} else {
System.err.println("❌ Could not find DataCenter for emission calculations: " + dataCenter.getExternalId());
}
} catch (Exception e) {
System.err.println("❌ Error in async emission calculations: " + e.getMessage());
e.printStackTrace();
}
}).start();
}
public void processEmissionCalculations(DataCenter dataCenter) {
System.out.println("🔍 Starting VM-level emission calculations for DataCenter ID: " + dataCenter.getId() +
" (Name: " + dataCenter.getDataCenter() + ")");
@@ -476,7 +520,10 @@ public class MessageListener {
" (Name: " + dataCenter.getDataCenter() + ")");
int totalVMs = 0;
int eligibleVMs = 0;
int processedVMs = 0;
int successfulCalculations = 0;
int failedCalculations = 0;
int totalEmissionSources = 0;
for (Project project : dataCenter.getProjects()) {
for (PhysicalMachine pm : project.getPhysicalMachines()) {
@@ -488,8 +535,37 @@ public class MessageListener {
eligibleVMs++;
if (vm.getPower() != null && vm.getPower() > 0) {
System.out.println("✅ Processing VM " + vm.getVmName() + " (calcOn = true)");
boolean success = createVMEmissionRecord(dataCenter, vm, project, pm);
if (success) successfulCalculations++;
processedVMs++;
// Check if VM has emission sources
Map<String, Integer> emissionSources = vm.getEmissionSource();
if (emissionSources != null && !emissionSources.isEmpty()) {
// Create separate emission record for each emission source
System.out.println("🔍 VM has " + emissionSources.size() + " emission sources");
totalEmissionSources += emissionSources.size();
for (Map.Entry<String, Integer> sourceEntry : emissionSources.entrySet()) {
String sourceName = sourceEntry.getKey();
Integer percentage = sourceEntry.getValue();
System.out.println(" - " + sourceName + ": " + percentage + "%");
boolean success = createVMEmissionRecordForSource(dataCenter, vm, project, pm, sourceName, percentage);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
}
} else {
// Fallback to default emission source if VM has no emission sources
System.out.println("⚠️ VM has no emission sources, using default");
totalEmissionSources++;
boolean success = createVMEmissionRecord(dataCenter, vm, project, pm);
if (success) {
successfulCalculations++;
} else {
failedCalculations++;
}
}
} else {
System.out.println("⚠️ Skipping VM " + vm.getVmName() + " (calcOn = true) - no power consumption data");
}
@@ -504,13 +580,21 @@ public class MessageListener {
System.out.println("🎯 VM Emission Calculation Summary:");
System.out.println(" Total VMs found: " + totalVMs);
System.out.println(" VMs with calcOn = true: " + eligibleVMs);
System.out.println(" VMs processed for emissions: " + processedVMs);
System.out.println(" VMs skipped (calcOn = false or null): " + (totalVMs - eligibleVMs));
System.out.println(" Total emission source calculations: " + totalEmissionSources);
System.out.println(" Successful emission calculations: " + successfulCalculations);
System.out.println(" Failed calculations: " + (eligibleVMs - successfulCalculations));
System.out.println(" Failed emission calculations: " + failedCalculations);
}
private boolean createVMEmissionRecord(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) {
try {
// Check if VM has an ID (is persisted)
if (vm.getId() == null) {
System.err.println("❌ VM " + vm.getVmName() + " has no ID - cannot create emission record");
return false;
}
MainDataTableCreateInput input = createVMMainDataTableInput(dataCenter, vm, project, pm);
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() + " (Power: " + vm.getPower() + "W)");
@@ -535,6 +619,52 @@ public class MessageListener {
}
}
private boolean createVMEmissionRecordForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, String emissionSourceName, Integer percentage) {
try {
// Check if VM has an ID (is persisted)
if (vm.getId() == null) {
System.err.println("❌ VM " + vm.getVmName() + " has no ID - cannot create emission record for source " + emissionSourceName);
return false;
}
// Find the emission source by name/tag
List<EmissionSource> emissionSources = emissionSourceRepo.findByTag(emissionSourceName);
if (emissionSources.isEmpty()) {
System.err.println("❌ Could not find emission source: " + emissionSourceName);
return false;
}
EmissionSource emissionSource = emissionSources.get(0);
// Calculate power consumption for this emission source (percentage of total VM power)
double sourceSpecificPower = vm.getPower() * (percentage / 100.0);
MainDataTableCreateInput input = createVMMainDataTableInputForSource(dataCenter, vm, project, pm, emissionSource, sourceSpecificPower, percentage);
System.out.println("🔍 Creating emission record for VM: " + vm.getVmName() +
" - Source: " + emissionSourceName + " (" + percentage + "%) - Power: " + sourceSpecificPower + "W");
MainDataTable result = callMainDataTableMutation(input);
if (result != null) {
System.out.println("✅ VM Emission calculation completed for source " + emissionSourceName + ":");
System.out.println(" - VM: " + vm.getVmName());
System.out.println(" - Emission Source: " + emissionSourceName + " (" + percentage + "%)");
System.out.println(" - Power: " + sourceSpecificPower + "W");
System.out.println(" - CO2: " + result.getCo2());
System.out.println(" - Total Emission: " + result.getTotalEmission());
System.out.println(" - Record ID: " + result.getId());
return true;
} else {
System.err.println("❌ Failed to create emission record for VM: " + vm.getVmName() + " - Source: " + emissionSourceName);
return false;
}
} catch (Exception e) {
System.err.println("❌ Error calculating emissions for VM " + vm.getVmName() + " - Source: " + emissionSourceName + ": " + e.getMessage());
return false;
}
}
private MainDataTableCreateInput createVMMainDataTableInput(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm) {
MainDataTableCreateInput input = new MainDataTableCreateInput();
@@ -615,6 +745,76 @@ public class MessageListener {
return input;
}
private MainDataTableCreateInput createVMMainDataTableInputForSource(DataCenter dataCenter, VM vm, Project project, PhysicalMachine pm, EmissionSource emissionSource, double sourceSpecificPower, Integer percentage) {
MainDataTableCreateInput input = new MainDataTableCreateInput();
// Copy datacenter-level information (if available)
input.setYear("2025");
input.setMonth("07");
// Note: These fields are no longer received in the message
// They need to be set via DataCenter CRUD operations first
if (dataCenter.getArea() != null && !dataCenter.getArea().getCities().isEmpty()) {
input.setCity(dataCenter.getArea().getCities().get(0).getId());
}
if (dataCenter.getArea() != null && !dataCenter.getArea().getDistricts().isEmpty()) {
input.setDistrict(dataCenter.getArea().getDistricts().get(0).getId());
}
if (dataCenter.getSector() != null) {
input.setSector(dataCenter.getSector().getId());
} else {
System.out.println("⚠️ Warning: DataCenter has no sector set - emission calculation may fail");
}
if (dataCenter.getSubSector() != null) {
input.setSubSector(dataCenter.getSubSector().getId());
}
// Use the specific emission source for this calculation
input.setEmissionSource(emissionSource.getId());
if (dataCenter.getActivitySubUnit() != null) {
input.setActivitySubUnit(dataCenter.getActivitySubUnit().getId());
}
if (dataCenter.getConsuptionUnit() != null) {
input.setConsuptionUnit(dataCenter.getConsuptionUnit().getId());
}
// Default to Kapsam-3 if no emission scope is set
input.setScope(dataCenter.getEmissionScope() != null ?
dataCenter.getEmissionScope().getTag().equals("Kapsam-3") : true);
try {
List<Organization> organizations = organizationRepo.findAll();
if (!organizations.isEmpty()) {
input.setOrganization(organizations.get(0).getId());
}
} catch (Exception e) {
System.err.println("❌ Error finding organization: " + e.getMessage());
}
// Set VM-specific fields
input.setVmId(vm.getId());
// Use the source-specific power consumption (percentage of total VM power)
input.setConsuptionAmount(String.valueOf(sourceSpecificPower));
System.out.println("🔍 VM Emission Input for Source:");
System.out.println(" VM ID: " + vm.getId());
System.out.println(" VM Name: " + vm.getVmName());
System.out.println(" Emission Source: " + emissionSource.getTag());
System.out.println(" Percentage: " + percentage + "%");
System.out.println(" Source Power: " + sourceSpecificPower + "W");
System.out.println(" Physical Machine: " + pm.getName());
System.out.println(" Project: " + project.getName());
System.out.println(" DataCenter Sector: " + (dataCenter.getSector() != null ? dataCenter.getSector().getTag() : "NOT SET"));
return input;
}
private void setupSecurityContext() {
User systemUser = new User("system", "", Collections.singletonList(new SimpleGrantedAuthority("dataset_create")));
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(systemUser, null, systemUser.getAuthorities());