org.apache.brooklyn.rest.resources.UsageResource.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.brooklyn.rest.resources.UsageResource.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.brooklyn.rest.resources;

import static org.apache.brooklyn.rest.util.WebResourceUtils.notFound;

import java.net.URI;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
import org.apache.brooklyn.core.mgmt.usage.ApplicationUsage;
import org.apache.brooklyn.core.mgmt.usage.LocationUsage;
import org.apache.brooklyn.core.mgmt.usage.ApplicationUsage.ApplicationEvent;
import org.apache.brooklyn.rest.api.UsageApi;
import org.apache.brooklyn.rest.domain.UsageStatistic;
import org.apache.brooklyn.rest.domain.UsageStatistics;
import org.apache.brooklyn.rest.transform.ApplicationTransformer;
import org.apache.brooklyn.util.exceptions.UserFacingException;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Time;

import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;

public class UsageResource extends AbstractBrooklynRestResource implements UsageApi {

    private static final Logger log = LoggerFactory.getLogger(UsageResource.class);

    private static final Set<Lifecycle> WORKING_LIFECYCLES = ImmutableSet.of(Lifecycle.RUNNING, Lifecycle.CREATED,
            Lifecycle.STARTING);

    @Override
    public List<UsageStatistics> listApplicationsUsage(@Nullable String start, @Nullable String end) {
        log.debug("REST call to get application usage for all applications: dates {} -> {}",
                new Object[] { start, end });

        List<UsageStatistics> response = Lists.newArrayList();

        Date startDate = parseDate(start, new Date(0));
        Date endDate = parseDate(end, new Date());

        checkDates(startDate, endDate);

        Set<ApplicationUsage> usages = ((ManagementContextInternal) mgmt()).getUsageManager()
                .getApplicationUsage(Predicates.alwaysTrue());

        for (ApplicationUsage usage : usages) {
            List<UsageStatistic> statistics = retrieveApplicationUsage(usage, startDate, endDate);
            if (statistics.size() > 0) {
                response.add(new UsageStatistics(statistics, ImmutableMap.<String, URI>of()));
            }
        }
        return response;
    }

    @Override
    public UsageStatistics getApplicationUsage(String application, String start, String end) {
        log.debug("REST call to get application usage for application {}: dates {} -> {}",
                new Object[] { application, start, end });

        Date startDate = parseDate(start, new Date(0));
        Date endDate = parseDate(end, new Date());

        checkDates(startDate, endDate);

        ApplicationUsage usage = ((ManagementContextInternal) mgmt()).getUsageManager()
                .getApplicationUsage(application);
        if (usage != null) {
            List<UsageStatistic> statistics = retrieveApplicationUsage(usage, startDate, endDate);
            return new UsageStatistics(statistics, ImmutableMap.<String, URI>of());
        } else {
            throw notFound("Application '%s' not found", application);
        }
    }

    private List<UsageStatistic> retrieveApplicationUsage(ApplicationUsage usage, Date startDate, Date endDate) {
        log.debug("Determining application usage for application {}: dates {} -> {}",
                new Object[] { usage.getApplicationId(), startDate, endDate });
        log.trace("Considering application usage events of {}: {}", usage.getApplicationId(), usage.getEvents());

        List<UsageStatistic> result = Lists.newArrayList();

        // Getting duration of state by comparing with next event (if next event is of same type, we just generate two statistics)...
        for (int i = 0; i < usage.getEvents().size(); i++) {
            ApplicationEvent current = usage.getEvents().get(i);
            Date eventStartDate = current.getDate();
            Date eventEndDate;

            if (i < usage.getEvents().size() - 1) {
                ApplicationEvent next = usage.getEvents().get(i + 1);
                eventEndDate = next.getDate();
            } else if (current.getState() == Lifecycle.DESTROYED) {
                eventEndDate = eventStartDate;
            } else {
                eventEndDate = new Date();
            }

            if (eventStartDate.compareTo(endDate) > 0 || eventEndDate.compareTo(startDate) < 0) {
                continue;
            }

            if (eventStartDate.compareTo(startDate) < 0) {
                eventStartDate = startDate;
            }
            if (eventEndDate.compareTo(endDate) > 0) {
                eventEndDate = endDate;
            }
            long duration = eventEndDate.getTime() - eventStartDate.getTime();
            UsageStatistic statistic = new UsageStatistic(
                    ApplicationTransformer.statusFromLifecycle(current.getState()), usage.getApplicationId(),
                    usage.getApplicationId(), format(eventStartDate), format(eventEndDate), duration,
                    usage.getMetadata());
            log.trace("Adding application usage statistic to response for app {}: {}", usage.getApplicationId(),
                    statistic);
            result.add(statistic);
        }

        return result;
    }

    @Override
    public List<UsageStatistics> listMachinesUsage(final String application, final String start, final String end) {
        log.debug("REST call to get machine usage for application {}: dates {} -> {}",
                new Object[] { application, start, end });

        final Date startDate = parseDate(start, new Date(0));
        final Date endDate = parseDate(end, new Date());

        checkDates(startDate, endDate);

        // Note currently recording ALL metrics for a machine that contains an Event from given Application
        Set<LocationUsage> matches = ((ManagementContextInternal) mgmt()).getUsageManager()
                .getLocationUsage(new Predicate<LocationUsage>() {
                    @Override
                    public boolean apply(LocationUsage input) {
                        LocationUsage.LocationEvent first = input.getEvents().get(0);
                        if (endDate.compareTo(first.getDate()) < 0) {
                            return false;
                        }
                        LocationUsage.LocationEvent last = input.getEvents().get(input.getEvents().size() - 1);
                        if (!WORKING_LIFECYCLES.contains(last.getState())
                                && startDate.compareTo(last.getDate()) > 0) {
                            return false;
                        }
                        if (application != null) {
                            for (LocationUsage.LocationEvent e : input.getEvents()) {
                                if (Objects.equal(application, e.getApplicationId())) {
                                    return true;
                                }
                            }
                            return false;
                        }
                        return true;
                    }
                });

        List<UsageStatistics> response = Lists.newArrayList();
        for (LocationUsage usage : matches) {
            List<UsageStatistic> statistics = retrieveMachineUsage(usage, startDate, endDate);
            if (statistics.size() > 0) {
                response.add(new UsageStatistics(statistics, ImmutableMap.<String, URI>of()));
            }
        }
        return response;
    }

    @Override
    public UsageStatistics getMachineUsage(final String machine, final String start, final String end) {
        log.debug("REST call to get machine usage for machine {}: dates {} -> {}",
                new Object[] { machine, start, end });

        final Date startDate = parseDate(start, new Date(0));
        final Date endDate = parseDate(end, new Date());

        checkDates(startDate, endDate);

        // Note currently recording ALL metrics for a machine that contains an Event from given Application
        LocationUsage usage = ((ManagementContextInternal) mgmt()).getUsageManager().getLocationUsage(machine);

        if (usage == null) {
            throw notFound("Machine '%s' not found", machine);
        }

        List<UsageStatistic> statistics = retrieveMachineUsage(usage, startDate, endDate);
        return new UsageStatistics(statistics, ImmutableMap.<String, URI>of());
    }

    private List<UsageStatistic> retrieveMachineUsage(LocationUsage usage, Date startDate, Date endDate) {
        log.debug("Determining machine usage for location {}", usage.getLocationId());
        log.trace("Considering machine usage events of {}: {}", usage.getLocationId(), usage.getEvents());

        List<UsageStatistic> result = Lists.newArrayList();

        // Getting duration of state by comparing with next event (if next event is of same type, we just generate two statistics)...
        for (int i = 0; i < usage.getEvents().size(); i++) {
            LocationUsage.LocationEvent current = usage.getEvents().get(i);
            Date eventStartDate = current.getDate();
            Date eventEndDate;

            if (i < usage.getEvents().size() - 1) {
                LocationUsage.LocationEvent next = usage.getEvents().get(i + 1);
                eventEndDate = next.getDate();
            } else if (current.getState() == Lifecycle.DESTROYED || current.getState() == Lifecycle.STOPPED) {
                eventEndDate = eventStartDate;
            } else {
                eventEndDate = new Date();
            }

            if (eventStartDate.compareTo(endDate) > 0 || eventEndDate.compareTo(startDate) < 0) {
                continue;
            }

            if (eventStartDate.compareTo(startDate) < 0) {
                eventStartDate = startDate;
            }
            if (eventEndDate.compareTo(endDate) > 0) {
                eventEndDate = endDate;
            }
            long duration = eventEndDate.getTime() - eventStartDate.getTime();
            UsageStatistic statistic = new UsageStatistic(
                    ApplicationTransformer.statusFromLifecycle(current.getState()), usage.getLocationId(),
                    current.getApplicationId(), format(eventStartDate), format(eventEndDate), duration,
                    usage.getMetadata());
            log.trace("Adding machine usage statistic to response for app {}: {}", usage.getLocationId(),
                    statistic);
            result.add(statistic);
        }

        return result;
    }

    private void checkDates(Date startDate, Date endDate) {
        if (startDate.compareTo(endDate) > 0) {
            throw new UserFacingException(new IllegalArgumentException("Start must be less than or equal to end: "
                    + startDate + " > " + endDate + " (" + startDate.getTime() + " > " + endDate.getTime() + ")"));
        }
    }

    private Date parseDate(String toParse, Date def) {
        return Strings.isBlank(toParse) ? def : Time.parseDate(toParse);
    }

    private String format(Date date) {
        return Time.makeDateString(date, Time.DATE_FORMAT_ISO8601_NO_MILLIS, Time.TIME_ZONE_UTC);
    }
}