org.globus.workspace.accounting.impls.dbdefault.DBAccountingAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.globus.workspace.accounting.impls.dbdefault.DBAccountingAdapter.java

Source

/*
 * Copyright 1999-2008 University of Chicago
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

package org.globus.workspace.accounting.impls.dbdefault;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.workspace.Lager;
import org.globus.workspace.WorkspaceException;
import org.globus.workspace.accounting.AccountingEventAdapter;
import org.globus.workspace.accounting.AccountingReaderAdapter;
import org.globus.workspace.accounting.ElapsedAndReservedMinutes;
import org.globus.workspace.accounting.impls.Util;
import org.globus.workspace.persistence.WorkspaceDatabaseException;
import org.globus.workspace.persistence.DBLoader;
import org.safehaus.uuid.UUIDGenerator;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.Calendar;

import commonj.timers.TimerManager;
import org.springframework.core.io.Resource;

public class DBAccountingAdapter implements AccountingEventAdapter, AccountingReaderAdapter {

    // -------------------------------------------------------------------------
    // STATIC VARIABLES
    // -------------------------------------------------------------------------

    private static final Log logger = LogFactory.getLog(DBAccountingAdapter.class.getName());

    public static final int DEFAULT_WRITE_DELAY_MILLISECONDS = 10000;

    // -------------------------------------------------------------------------
    // INSTANCE VARIABLES
    // -------------------------------------------------------------------------

    private final DataSource dataSource;
    private final Lager lager;
    private final TimerManager timerManager;

    private DBAccountingPersistence db;
    private final UUIDGenerator uuidGen = UUIDGenerator.getInstance();

    private String currentReservationsPath;
    private String eventsPath;
    private long writeDelayMilliseconds = -1;
    private int chargeGranularity;

    // see comment in initialize()
    private boolean initialized;

    private DelayedAccountingFileLogger fileLog;

    // -------------------------------------------------------------------------
    // CONSTRUCTOR
    // -------------------------------------------------------------------------

    public DBAccountingAdapter(DataSource dataSource, Lager lager, TimerManager timerManager, DBLoader loader)
            throws Exception {

        if (dataSource == null) {
            throw new IllegalArgumentException("dataSource may not be null");
        }
        this.dataSource = dataSource;

        if (lager == null) {
            throw new IllegalArgumentException("lager may not be null");
        }
        this.lager = lager;

        if (timerManager == null) {
            throw new IllegalArgumentException("timerManager may not be null");
        }
        this.timerManager = timerManager;

        if (loader == null) {
            throw new IllegalArgumentException("loader may not be null");
        }
        if (!loader.isLoaded()) {
            throw new Exception("DBLoader reporting not loaded (?)");
        }
    }

    // -------------------------------------------------------------------------
    // INITIALIZATION
    // -------------------------------------------------------------------------

    public void setCurrentReservationsResource(Resource currentReservationsResource) throws IOException {
        this.currentReservationsPath = currentReservationsResource.getFile().getAbsolutePath();
    }

    public void setEventsResource(Resource eventsResource) throws IOException {
        this.eventsPath = eventsResource.getFile().getAbsolutePath();
    }

    public void setWriteDelayMilliseconds(int writeDelayMilliseconds) {
        final int min = DelayedAccountingFileLogger.MIN_WRITE_DELAY_MILLISECONDS;
        if (writeDelayMilliseconds < min) {
            throw new RuntimeException("write delay can not be less " + "than " + min + " ms");
        }
        this.writeDelayMilliseconds = writeDelayMilliseconds;
    }

    public void setChargeGranularity(int chargeGranularity) {
        if (chargeGranularity < 1) {
            throw new RuntimeException("chargeGranularity must" + " be greater than zero");
        }
        this.chargeGranularity = chargeGranularity;
    }

    // -------------------------------------------------------------------------
    // IoC INIT METHOD
    // -------------------------------------------------------------------------

    public synchronized void initialize() throws Exception {

        logger.debug("validating/initializing");

        if (this.initialized) {
            throw new Exception("already initialized, illegal to initialize " + "more than once");
        }

        if (this.chargeGranularity == 0) {
            throw new Exception("chargeGranularity was not set");
        }

        if (this.db == null) {
            this.db = new DBAccountingPersistence(this.dataSource, this.lager);
            this.db.initialize();
        }

        boolean res = false;
        boolean ev = false;
        if (this.currentReservationsPath != null && this.currentReservationsPath.length() != 0) {
            logger.debug("Configuration found for accounting reservation " + "file-logging");
            res = true;
        } else {
            logger.debug("No configuration found for accounting reservation " + "file-logging");
            this.currentReservationsPath = null;
        }

        if (this.eventsPath != null && this.eventsPath.length() != 0) {
            logger.debug("Configuration found for accounting event " + "file-logging");
            ev = true;
        } else {
            logger.debug("No configuration found for accounting event " + "file-logging");
            this.eventsPath = null;
        }

        if (res || ev) {
            if (this.writeDelayMilliseconds < DelayedAccountingFileLogger.MIN_WRITE_DELAY_MILLISECONDS) {

                // values via jndi below min are rejected: config was left out
                logger.debug("Delay for reservation and event file-logging " + "not set, defaulting to "
                        + DEFAULT_WRITE_DELAY_MILLISECONDS + " ms");
                this.writeDelayMilliseconds = DEFAULT_WRITE_DELAY_MILLISECONDS;
            }

            // TODO: DelayedAccountingFileLogger should be via IoC too

            // exception flies, client did not disable everything and there
            // was a problem initializing
            this.fileLog = DelayedAccountingFileLogger.create(this.currentReservationsPath, this.eventsPath,
                    this.writeDelayMilliseconds, this.db, this.lager, this.timerManager);
        }

        this.initialized = true;
        logger.debug("validated/initialized");
    }

    // -------------------------------------------------------------------------
    // implements AccountingEventAdapter
    // -------------------------------------------------------------------------

    public void create(int id, String ownerDN, long minutesRequested, String network, String resource,
            String clientLaunchName, int CPUCount, int memory, double chargeRatio) {

        String moreToLog = "";

        if (resource != null) {
            moreToLog += ", vmm='" + resource.trim() + '\'';
        }

        if (clientLaunchName != null) {
            moreToLog += ", clientLaunchName='" + clientLaunchName.trim() + '\'';
        }

        if (network != null) {
            moreToLog += ", network='" + network.trim() + '\'';
        }

        if (this.lager.accounting) {
            logger.trace("create(): id = " + id + ", ownerDN = '" + ownerDN + "', minutesRequested = "
                    + minutesRequested + ", CPUCount = " + CPUCount + ", memory = " + memory + moreToLog);
        }

        if (!this.initialized) {
            logger.error("never initialized, can't do anything");
            return;
        }

        if (ownerDN == null) {
            logger.error("ownerDN is null, can't do anything");
            return;
        }

        // account for container recovery after a service state reset
        if (id == 1) {
            try {
                final int updated = this.db.forceAllInactive();

                if (updated < 0) {

                    logger.error("compound, unresolvable DB problem");
                    return;

                } else if (updated > 0) {

                    logger.fatal("Fresh service install or service state "
                            + "was wiped: ALL previous deployments tracked "
                            + "by accounting module were moved to inactive.  "
                            + "Destruction time in this case is undefined and " + "not set!  Set " + updated
                            + " deployments to " + "inactive.");

                } else {

                    logger.debug("fresh service install or service state "
                            + "was wiped, but all previous deployments were " + "already inactive: all is well");
                }

            } catch (WorkspaceDatabaseException e) {
                logger.error(e.getMessage());
                return;
            }
        }

        try {

            long charge = Util.positiveCeiling(minutesRequested, this.chargeGranularity);

            final Double chargeDouble = charge * chargeRatio;
            charge = chargeDouble.longValue();

            final String uuid = uuidGen.generateRandomBasedUUID().toString();

            final Calendar now = Calendar.getInstance();

            this.db.add(uuid, id, ownerDN, charge, now, CPUCount, memory);

            if (this.lager.eventLog) {
                logger.info(Lager.ev(id) + "accounting: ownerDN = '" + ownerDN + "', minutesRequested = "
                        + minutesRequested + ", minutes reserved = " + charge + ", charge ratio = " + chargeRatio
                        + ", CPUCount = " + CPUCount + ", memory = " + memory + ", uuid = '" + uuid + "'"
                        + moreToLog);
            }

            if (this.fileLog != null) {
                try {
                    this.fileLog.logCreate(uuid, id, ownerDN, minutesRequested, charge, chargeRatio, now, CPUCount,
                            memory, moreToLog);
                } catch (WorkspaceException e) {
                    if (logger.isDebugEnabled()) {
                        logger.error(e.getMessage(), e);
                    } else {
                        logger.error(e.getMessage());
                    }
                }
            }

        } catch (WorkspaceDatabaseException e) {
            logger.error(e.getMessage());
        }

    }

    public void destroy(int id, String ownerDN, long minutesElapsed, double chargeRatio) {

        if (this.lager.accounting) {
            logger.trace(
                    "destroy(): id = " + id + ", ownerDN = '" + ownerDN + "', minutesElapsed = " + minutesElapsed);
        }

        if (!this.initialized) {
            logger.error("never initialized, can't do anything");
            return;
        }

        long charge = Util.positiveCeiling(minutesElapsed, this.chargeGranularity);
        final Double chargeDouble = charge * chargeRatio;
        charge = chargeDouble.longValue();

        try {

            final String uuid = this.db.end(id, ownerDN, charge);

            if (this.lager.eventLog) {
                logger.info(Lager.ev(id) + "accounting: ownerDN = '" + ownerDN + "', minutesElapsed = " + charge
                        + ", chargeRatio = " + chargeRatio + ", real usage = " + minutesElapsed + ", uuid = '"
                        + uuid + '\'');
            }

            if (this.fileLog != null) {
                final Calendar now = Calendar.getInstance();
                try {
                    this.fileLog.logRemove(uuid, id, ownerDN, charge, chargeRatio, now);
                } catch (WorkspaceException e) {
                    if (logger.isDebugEnabled()) {
                        logger.error(e.getMessage(), e);
                    } else {
                        logger.error(e.getMessage());
                    }
                }
            }

        } catch (WorkspaceDatabaseException e) {
            logger.error(e.getMessage());
        }
    }

    // getChargeGranularity below is also from AccountingEventAdapter

    // -------------------------------------------------------------------------
    // implements AccountingReaderAdapter
    // -------------------------------------------------------------------------

    public long totalElapsedMinutes(String ownerDN) throws WorkspaceException {

        if (this.lager.accounting) {
            logger.trace("totalElapsedMinutes(): ownerDN = '" + ownerDN + "'");
        }

        if (!this.initialized) {
            throw new WorkspaceException("never initialized, " + "can't do anything");
        }

        return this.db.totalElapsedMinutes(ownerDN);
    }

    public long currentReservedMinutes(String ownerDN) throws WorkspaceException {

        if (lager.accounting) {
            logger.trace("currentReservedMinutes(): ownerDN = '" + ownerDN + "'");
        }

        if (!this.initialized) {
            throw new WorkspaceException("never initialized, " + "can't do anything");
        }

        return this.db.currentReservedMinutes(ownerDN);
    }

    public long totalElapsedAndReservedMinutes(String ownerDN) throws WorkspaceException {

        if (this.lager.accounting) {
            logger.trace("totalElapsedAndReservedMinutes(): ownerDN = '" + ownerDN + "'");
        }

        if (!this.initialized) {
            throw new WorkspaceException("never initialized, " + "can't do anything");
        }

        final ElapsedAndReservedMinutes elapRes = this.db.totalElapsedAndReservedMinutesTuple(ownerDN);

        return elapRes.getElapsed() + elapRes.getReserved();
    }

    public ElapsedAndReservedMinutes totalElapsedAndReservedMinutesTuple(String ownerDN) throws WorkspaceException {

        if (this.lager.accounting) {
            logger.trace("totalElapsedAndReservedMinutesTuple(): ownerDN = '" + ownerDN + "'");
        }

        if (!this.initialized) {
            throw new WorkspaceException("never initialized, " + "can't do anything");
        }

        return this.db.totalElapsedAndReservedMinutesTuple(ownerDN);
    }

    public int getChargeGranularity() {
        return this.chargeGranularity;
    }
}