/* * Copyright (C) 2008 Universidade Federal de Campina Grande * * This file is part of OurGrid. * * OurGrid is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.ourgrid.peer.business.controller.accounting; import java.util.List; import org.ourgrid.common.interfaces.to.Accounting; import org.ourgrid.common.interfaces.to.GridProcessAccounting; import org.ourgrid.common.interfaces.to.RequestSpecification; import org.ourgrid.common.interfaces.to.WorkAccounting; import org.ourgrid.common.internal.IResponseTO; import org.ourgrid.common.internal.response.LoggerResponseTO; import org.ourgrid.common.statistics.beans.peer.Job; import org.ourgrid.common.statistics.beans.status.ExecutionStatus; import org.ourgrid.common.statistics.control.AccountingControl; import org.ourgrid.common.statistics.control.JobControl; import org.ourgrid.common.statistics.control.UserControl; import org.ourgrid.common.statistics.control.WorkerControl; import org.ourgrid.peer.business.controller.messages.AccountingMessages; import org.ourgrid.peer.business.dao.AccountingDAO; import org.ourgrid.peer.business.dao.LocalWorkersDAO; import org.ourgrid.peer.business.dao.PeerDAOFactory; import org.ourgrid.peer.business.dao.UsersDAO; import org.ourgrid.peer.communication.dao.ScheduledRequestDAO; import org.ourgrid.peer.to.AllocableWorker; import org.ourgrid.peer.to.LocalWorker; import org.ourgrid.peer.to.PeerBalance; import org.ourgrid.reqtrace.Req; /** * Performs accounting actions */ @Req("REQ027") public class AccountingController { private static final long serialVersionUID = 1L; private static AccountingController instance = null; public static AccountingController getInstance() { if (instance == null) { instance = new AccountingController(); } return instance; } private AccountingController() {} /** * Validates if the sender can report the replica accounting and if the * accounting data is valid. Call the DAO to store the replica accounting * data. * * The sender must have its public key already saved in the local users * set. * * The replica accounting must contain the request specification and a * valid allocable worker. * * The request must be running in this peer. * * @param userPublicKey The sender public key * @param replicaAccounting The replica accounting data * * @see UsersDAO#getUserByPublicKey(String) * @see ScheduledRequestDAO#isRunning(RequestSpecification) * @see AccountingDAO#addReplicaAccounting(Accounting) */ public void reportReplicaAccounting(List<IResponseTO> responses, GridProcessAccounting replicaAccounting, String userPublicKey) { UsersDAO usersDAO = PeerDAOFactory.getInstance().getUsersDAO(); if (! UserControl.getInstance().userExists(responses, userPublicKey)) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getUnknownUserReplicaAccountingMessage(userPublicKey), LoggerResponseTO.WARN); responses.add(loggerResponse); return; } if (!usersDAO.isLoggedUser(userPublicKey)) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNotLoggerUserMessage(userPublicKey), LoggerResponseTO.WARN); responses.add(loggerResponse); return; } String userAddress = usersDAO.getLoggedUser(userPublicKey).getWorkerProviderClientAddress(); if (replicaAccounting == null) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNullReplicaAccountingMessage(userAddress), LoggerResponseTO.WARN); responses.add(loggerResponse); return; } long requestId = replicaAccounting.getRequestId(); if (!validateRequestSpecification(responses, userPublicKey, userAddress, requestId)) { return; } if (replicaAccounting.getWorkerID() == null) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getUserWithoutWorkerMessage(userAddress), LoggerResponseTO.WARN); responses.add(loggerResponse); return; } String workerAddress = replicaAccounting.getWorkerID(); String workerPublicKey = replicaAccounting.getWorkerPublicKey(); AllocableWorker allocableWorker = validateWorker(responses, userPublicKey, userAddress, workerAddress, workerPublicKey); if (allocableWorker == null) { return; } PeerBalance accountings = replicaAccounting.getAccountings(); if (!validateAccountings(responses, userAddress, workerAddress, accountings)) { return; } LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getReceivedReplicaAccountingMessage( userAddress, requestId, workerAddress, accountings, replicaAccounting.getState(), allocableWorker.isWorkerLocal()), LoggerResponseTO.DEBUG); responses.add(loggerResponse); // DeploymentID wpID = null; // Object workerProvider = allocableWorker.getWorkerProvider(); // if (allocableWorker.isWorkerLocal()) { // wpID = serviceManager.getLocalDeploymentID(workerProvider); // } else { // wpID = serviceManager.getStubDeploymentID(workerProvider); // } JobControl.getInstance().addProcessAccounting(responses, replicaAccounting); AccountingControl.getInstance().addReplicaAccounting(responses, replicaAccounting, allocableWorker.getProviderCertificateDN()); } private boolean validateRequestSpecification(List<IResponseTO> responses, String userPublicKey, String userDeploymentID, long requestId) { // if (requestSpec == null) { // LoggerResponseTO loggerResponse = new LoggerResponseTO( // AccountingMessages.getNullRequestMessage(userDeploymentID), // LoggerResponseTO.WARN); // responses.add(loggerResponse); // // return false; // } Job job = JobControl.getInstance().findByRequestId(responses, requestId); if (job == null || (job.getStatus() != null && job.getStatus().equals(ExecutionStatus.FINISHED))) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getInexistentRequestMessage(userDeploymentID, requestId), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } if (!job.getLogin().getUser().getPublicKey().equals(userPublicKey)) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getWrongRequestConsumerMessage(userDeploymentID, requestId), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } return true; } private AllocableWorker validateWorker(List<IResponseTO> responses, String userPublicKey, String userAddress, String workerAddress, String workerPublicKey) { if (workerAddress == null) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getUserWithoutWorkerMessage(userAddress), LoggerResponseTO.WARN); responses.add(loggerResponse); return null; } AllocableWorker allocableWorker = PeerDAOFactory.getInstance().getAllocationDAO().getAllocableWorker(workerPublicKey); String publicKey = ""; if (allocableWorker != null) { publicKey = allocableWorker.getConsumerPublicKey(); } if (allocableWorker == null || !userPublicKey.equals(publicKey) || !allocableWorker.isDelivered()) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getWorkerNotAllocatedForUserMessage(userAddress, workerAddress, allocableWorker), LoggerResponseTO.WARN); responses.add(loggerResponse); return null; } return allocableWorker; } private boolean validateAccountings(List<IResponseTO> responses, String userAddress, String workerAddress, PeerBalance accountings) { if (accountings.getAttribute(PeerBalance.CPU_TIME) < 0) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNegativeCPUReplicaAccountingMessage(userAddress, workerAddress), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } if (accountings.getAttribute(PeerBalance.DATA) < 0) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNonPositiveDataReplicaAccountingMessage(userAddress, workerAddress), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } return true; } /** * Validate if the sender can report the work accountings, calculate the * new balances for the remote peers that consumed the worker, and call the * DAO to update the remote peers balance. * * The sender must have its public key already saved in the local workers * set. * * The AccountingEvaluator is responsible for calculating the balance from * the accounting data. * * @param workerPublicKey The sender public key * @param consumersAccountings A list of accountings for the remote peers * that consumed the worker * * @see LocalWorkersDAO#getRecoveredWorker(String) * @see AccountingDAO#getRemotePeerBalance(String) * @see AccountingDAO#setRemotePeerBalance(String, Double) */ public void reportWorkAccounting(List<IResponseTO> responses, List<WorkAccounting> consumersAccountings, String workerPublicKey, String workerAddress, String workerUserAtServer, String myPublicKey, String myCertSubjectDN) { LocalWorker localWorker = WorkerControl.getInstance().getLocalWorker( responses, workerUserAtServer); if (!validateWorker(responses, workerPublicKey, localWorker)) { return; } double accumCpuTime = 0; double accumDataStored = 0; for (WorkAccounting accounting : consumersAccountings) { String wmAddress = localWorker.getWorkerManagementAddress(); if (!validateAccounting(responses, accounting, wmAddress, myCertSubjectDN)) { continue; } LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getReceivedWorkAccountingMessage(accounting, wmAddress), LoggerResponseTO.DEBUG); responses.add(loggerResponse); commitReceivedFavour(responses, accounting, myCertSubjectDN); accumCpuTime += accounting.getAccountings().getCPUTime(); accumDataStored += accounting.getAccountings().getData(); } WorkerControl.getInstance().updateWorkAccounting(responses, localWorker.getWorkerUserAtServer(), accumCpuTime, accumDataStored); } private boolean validateAccounting(List<IResponseTO> responses, WorkAccounting accounting, String workerManagAdress, String myCertSubjectDN) { String consumerPeerDN = accounting.getConsumerPeerDN(); if (consumerPeerDN == null) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNoConsumerWorkAccountingMessage(workerManagAdress), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } if (accounting.getAccountings().getAttribute(PeerBalance.CPU_TIME) <= 0) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNegativeCPUWorkAccountingMessage(workerManagAdress, consumerPeerDN), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } if (accounting.getAccountings().getAttribute(PeerBalance.DATA) < 0) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getNonPositiveDataWorkAccountingMessage(workerManagAdress, consumerPeerDN), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } if (myCertSubjectDN.equals(consumerPeerDN)) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getLocalPeerWorkAccountingMessage(workerManagAdress), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } return true; } private boolean validateWorker(List<IResponseTO> responses, String workerPublicKey, LocalWorker localWorker) { if (localWorker == null) { LoggerResponseTO loggerResponse = new LoggerResponseTO( AccountingMessages.getUnknownWorkerMessage(workerPublicKey), LoggerResponseTO.WARN); responses.add(loggerResponse); return false; } return true; } private void commitReceivedFavour(List<IResponseTO> responses, WorkAccounting accounting, String myCertSubjectDN) { String remoteDNData = accounting.getConsumerPeerDN(); PeerBalance oldBalance = null; if (remoteDNData != null) { oldBalance = AccountingControl.getInstance().getRemotePeerBalance( responses, myCertSubjectDN, remoteDNData); } if (oldBalance == null) { oldBalance = new PeerBalance(0., 0.); } double cpu = Math.max(oldBalance.getCPUTime() - accounting.getAccountings().getCPUTime(), 0); double data = Math.max(oldBalance.getData() - accounting.getAccountings().getData(), 0); AccountingControl.getInstance().setRemotePeerBalance( responses, myCertSubjectDN, remoteDNData, new PeerBalance(cpu, data)); } /** * Validates if the sender can save the balance and call the DAO to save it. * * The sender (timer or component) must have the save key pair of the * current module. * * @param senderPublicKey The sender public key */ public void saveRanking(List<IResponseTO> responses, boolean isThisMyPublicKey, String senderPublicKey, String rankingFilePath) { if (!isThisMyPublicKey) { responses.add(new LoggerResponseTO(AccountingMessages.getUnknownSenderSaveRankingMessage( senderPublicKey), LoggerResponseTO.WARN)); return; } responses.add(new LoggerResponseTO(AccountingMessages.getSaveRankingMessage(), LoggerResponseTO.DEBUG)); PeerDAOFactory.getInstance().getAccountingDAO().saveBalancesRanking(rankingFilePath); } }