com.edmunds.etm.runtime.impl.ApplicationRepository.java Source code

Java tutorial

Introduction

Here is the source code for com.edmunds.etm.runtime.impl.ApplicationRepository.java

Source

/*
 * Copyright 2011 Edmunds.com, Inc.
 *
 * 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 com.edmunds.etm.runtime.impl;

import com.edmunds.common.configuration.api.EnvironmentConfiguration;
import com.edmunds.etm.loadbalancer.api.PoolMember;
import com.edmunds.etm.loadbalancer.api.VirtualServer;
import com.edmunds.etm.loadbalancer.impl.LoadBalancerController;
import com.edmunds.etm.management.api.ManagementPoolMember;
import com.edmunds.etm.management.api.ManagementVip;
import com.edmunds.etm.management.api.ManagementVips;
import com.edmunds.etm.management.api.MavenModule;
import com.edmunds.etm.runtime.api.Application;
import com.edmunds.etm.runtime.api.ApplicationSeries;
import com.edmunds.etm.runtime.api.ApplicationVersion;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;

/**
 * Repository for ETM-managed applications.
 * <p/>
 * TODO: Add persistence to accomodate failover and restart
 *
 * @author Ryan Holmes
 */
@Component
public class ApplicationRepository {

    private static final Logger logger = LoggerFactory.getLogger(ApplicationRepository.class);

    private EnvironmentConfiguration environment;

    private ImmutableMap<String, ApplicationSeries> seriesByName;

    @Autowired
    public ApplicationRepository(EnvironmentConfiguration environment) {
        this.environment = environment;
        this.seriesByName = ImmutableMap.of();
    }

    public synchronized Set<Application> getAllApplications() {

        Set<Application> applications = Sets.newHashSet();

        for (ApplicationSeries series : seriesByName.values()) {
            applications.addAll(series.getAllVersions());
        }
        return applications;
    }

    public synchronized Set<Application> getActiveApplications() {

        Set<Application> applications = Sets.newHashSetWithExpectedSize(seriesByName.size());

        for (ApplicationSeries series : seriesByName.values()) {
            final Application activeVersion = series.getActiveVersion();
            if (activeVersion != null) {
                applications.add(activeVersion);
            }
        }
        return applications;
    }

    public synchronized Set<Application> getInactiveApplications() {
        Set<Application> applications = Sets.newHashSet();
        for (ApplicationSeries series : seriesByName.values()) {
            applications.addAll(series.getInactiveVersions());
        }
        return applications;
    }

    public synchronized Application getApplicationById(String id) {
        Application match = null;
        for (Application app : getAllApplications()) {
            if (app.getId().equals(id)) {
                match = app;
                break;
            }
        }
        return match;
    }

    public synchronized ApplicationSeries getSeriesByName(String name) {
        return seriesByName.get(name);
    }

    public synchronized void addOrReplaceApplication(Application app) {
        Validate.notNull(app, "Application is null");

        ApplicationSeries series = getSeriesByName(app.getName());

        if (series == null) {
            // Create singleton series.
            series = new ApplicationSeries(app);
        } else {
            // Create new series adding in the app.
            series = series.addOrReplace(app);
        }

        // Add (or replace) the series in the map.
        Map<String, ApplicationSeries> temp = Maps.newHashMap(seriesByName);
        temp.put(series.getName(), series);

        setSeriesByName(temp);
    }

    public synchronized void removeApplication(Application app) {
        if (app == null) {
            return;
        }

        final String applicationName = app.getName();

        ApplicationSeries previousSeries = seriesByName.get(applicationName);

        if (previousSeries == null) {
            return;
        }

        ApplicationSeries series = previousSeries.remove(app);

        // if no change was made to the series return
        if (previousSeries == series) {
            return;
        }

        final HashMap<String, ApplicationSeries> temp = Maps.newHashMap(seriesByName);

        // series will be null if we just removed the last version from the series.
        if (series == null) {
            temp.remove(applicationName);
        } else {
            // The series has more than one entry in it and we need to add the replacement (smaller) series.
            temp.put(applicationName, series);
        }
        setSeriesByName(temp);
    }

    private void setSeriesByName(final Map<String, ApplicationSeries> seriesByName) {
        this.seriesByName = ImmutableMap.copyOf(seriesByName);
    }

    public synchronized void updateFromDeltaVips(ManagementVips vips) {
        Application app;
        for (ManagementVip vip : vips.getVips()) {

            switch (vip.getLoadBalancerState()) {
            case CREATE_REQUEST:
            case ACTIVE:
                // Do not activate applications with no rules
                // Check for vip with null rules
                if (vip.getRules() == null) {
                    String message = String.format("Vip with null rules detected: %s", vip.getHostAddress());
                    logger.error(message);
                    continue;
                }
                app = createApplicationFromVip(vip);
                addOrReplaceApplication(app);
                break;
            case DELETE_REQUEST:
                app = getApplicationByMavenModule(vip.getMavenModule());
                removeApplication(app);
                break;
            case UNKNOWN:
                logger.warn(String.format("Unexpected LoadBalancerState: %s", vip.getLoadBalancerState()));
                break;
            default:
                String message = String.format("Unknown LoadBalancerState: %s", vip.getLoadBalancerState());
                logger.error(message);
                throw new RuntimeException(message);
            }
        }
    }

    private Application getApplicationByMavenModule(MavenModule mavenModule) {

        String name = Application.applicationName(mavenModule);
        ApplicationSeries series = seriesByName.get(name);

        if (series == null) {
            return null;
        }

        ApplicationVersion version = Application.applicationVersion(mavenModule);
        return series.getVersion(version);
    }

    private Application createApplicationFromVip(ManagementVip vip) {
        VirtualServer vs = null;
        if (vip.getHostAddress() != null) {
            Collection<ManagementPoolMember> vipMembers = vip.getPoolMembers().values();
            SortedSet<PoolMember> members = Sets.newTreeSet();
            for (ManagementPoolMember mpm : vipMembers) {
                members.add(new PoolMember(mpm.getHostAddress()));
            }
            String prefix = LoadBalancerController.VIRTUAL_SERVER_NAME_PREFIX;
            String serverName = VirtualServer.createServerName(prefix, vip.getMavenModule(), environment);
            vs = new VirtualServer(serverName, vip.getHostAddress(), members);
        }

        return new Application(vip.getMavenModule(), vip.getRules(), vip.getHttpMonitor(), vs);
    }
}