brooklyn.entity.waratek.cloudvm.JavaVirtualMachineImpl.java Source code

Java tutorial

Introduction

Here is the source code for brooklyn.entity.waratek.cloudvm.JavaVirtualMachineImpl.java

Source

/*
 * Copyright 2014 by Cloudsoft Corporation Limited
 *
 * 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 brooklyn.entity.waratek.cloudvm;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.Nullable;

import org.jclouds.compute.domain.OsFamily;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.enricher.Enrichers;
import brooklyn.entity.Entity;
import brooklyn.entity.basic.Entities;
import brooklyn.entity.basic.SoftwareProcessImpl;
import brooklyn.entity.group.Cluster;
import brooklyn.entity.group.DynamicCluster;
import brooklyn.entity.java.JavaAppUtils;
import brooklyn.entity.java.UsesJavaMXBeans;
import brooklyn.entity.proxying.EntitySpec;
import brooklyn.event.feed.function.FunctionFeed;
import brooklyn.event.feed.function.FunctionPollConfig;
import brooklyn.event.feed.jmx.JmxAttributePollConfig;
import brooklyn.event.feed.jmx.JmxFeed;
import brooklyn.location.Location;
import brooklyn.location.LocationDefinition;
import brooklyn.location.MachineProvisioningLocation;
import brooklyn.location.basic.BasicLocationDefinition;
import brooklyn.location.basic.Machines;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.location.jclouds.templates.PortableTemplateBuilder;
import brooklyn.location.waratek.WaratekLocation;
import brooklyn.location.waratek.WaratekMachineLocation;
import brooklyn.location.waratek.WaratekResolver;
import brooklyn.management.LocationManager;
import brooklyn.policy.PolicySpec;
import brooklyn.policy.ha.ServiceFailureDetector;
import brooklyn.policy.ha.ServiceReplacer;
import brooklyn.policy.ha.ServiceRestarter;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.guava.Maybe;
import brooklyn.util.time.Duration;

import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;

public class JavaVirtualMachineImpl extends SoftwareProcessImpl implements JavaVirtualMachine {

    static {
        JavaAppUtils.init();
        WaratekAttributes.init();
    }

    private static final Logger log = LoggerFactory.getLogger(JavaVirtualMachineImpl.class);
    private static final AtomicInteger counter = new AtomicInteger(0);

    private JmxFeed jmxMxBeanFeed;
    private FunctionFeed jvcFeed;
    private DynamicCluster containers;

    @Override
    public void init() {
        log.info("Starting JVM id {}", getId());

        String jvmName = String.format(getConfig(JavaVirtualMachine.JVM_NAME_FORMAT), getId(),
                counter.incrementAndGet());
        setDisplayName(jvmName);
        setAttribute(JVM_NAME, jvmName);

        EntitySpec<?> jvcSpec = EntitySpec.create(getConfig(JVC_SPEC)).configure(JavaVirtualContainer.JVM, this);
        if (getConfig(HA_POLICY_ENABLE)) {
            jvcSpec.policy(PolicySpec.create(ServiceFailureDetector.class));
            jvcSpec.policy(PolicySpec.create(ServiceRestarter.class)
                    .configure(ServiceRestarter.FAILURE_SENSOR_TO_MONITOR, ServiceFailureDetector.ENTITY_FAILED));
        }

        containers = addChild(EntitySpec.create(DynamicCluster.class).configure(Cluster.INITIAL_SIZE, 0)
                .configure(DynamicCluster.QUARANTINE_FAILED_ENTITIES, false)
                .configure(DynamicCluster.MEMBER_SPEC, jvcSpec).displayName("Guest Java Virtual Machines"));
        if (getConfig(HA_POLICY_ENABLE)) {
            containers.addPolicy(PolicySpec.create(ServiceReplacer.class)
                    .configure(ServiceReplacer.FAILURE_SENSOR_TO_MONITOR, ServiceRestarter.ENTITY_RESTART_FAILED));
        }

        if (Entities.isManaged(this))
            Entities.manage(containers);

        containers.addEnricher(
                Enrichers.builder().aggregating(WaratekAttributes.HEAP_MEMORY_DELTA_PER_SECOND_IN_WINDOW)
                        .publishing(WaratekAttributes.HEAP_MEMORY_DELTA_PER_SECOND_IN_WINDOW).fromMembers()
                        .computingSum().build());
        containers.addEnricher(Enrichers.builder().aggregating(UsesJavaMXBeans.USED_HEAP_MEMORY)
                .publishing(WaratekAttributes.TOTAL_HEAP_MEMORY).fromMembers().computingSum().build());
        containers.addEnricher(Enrichers.builder().aggregating(WaratekAttributes.CPU_USAGE)
                .publishing(WaratekAttributes.AVERAGE_CPU_USAGE).fromMembers().computingAverage().build());

        addEnricher(Enrichers.builder()
                .propagating(ImmutableMap.of(DynamicCluster.GROUP_SIZE, WaratekAttributes.JVC_COUNT))
                .from(containers).build());
        addEnricher(Enrichers.builder().propagating(WaratekAttributes.TOTAL_HEAP_MEMORY,
                WaratekAttributes.AVERAGE_CPU_USAGE, WaratekAttributes.HEAP_MEMORY_DELTA_PER_SECOND_IN_WINDOW)
                .from(containers).build());
    }

    @Override
    public Class<?> getDriverInterface() {
        return JavaVirtualMachineDriver.class;
    }

    @Override
    public JavaVirtualMachineDriver getDriver() {
        return (JavaVirtualMachineDriver) super.getDriver();
    }

    @SuppressWarnings({ "unchecked", "rawtypes" })
    @Override
    protected Map<String, Object> obtainProvisioningFlags(MachineProvisioningLocation location) {
        Map flags = super.obtainProvisioningFlags(location);
        Long heapSize = getConfig(HEAP_SIZE, 512 * (1024L * 1024L));
        int megabytes = (int) (heapSize / (1024L * 1024L));
        flags.put("templateBuilder",
                new PortableTemplateBuilder().os64Bit(true).osFamily(OsFamily.CENTOS).minRam(megabytes));
        String securityGroup = getConfig(WaratekInfrastructure.SECURITY_GROUP);
        if (securityGroup != null) {
            flags.put("securityGroups", securityGroup);
        }
        return flags;
    }

    @Override
    public WaratekInfrastructure getInfrastructure() {
        return getConfig(WARATEK_INFRASTRUCTURE);
    }

    @Override
    public Integer getSshPort() {
        return getConfig(SSH_ADMIN_ENABLE) ? getAttribute(SSH_PORT) : null;
    }

    @Override
    public Integer getHttpPort() {
        return getConfig(HTTP_ADMIN_ENABLE) ? getAttribute(HTTP_PORT) : null;
    }

    @Override
    public String getJvmName() {
        return getAttribute(JVM_NAME);
    }

    @Override
    public List<Entity> getJvcList() {
        return ImmutableList.copyOf(containers.getMembers());
    }

    @Override
    public DynamicCluster getJvcCluster() {
        return containers;
    }

    /** The path to the root directory of the running CloudVM */
    @Override
    public String getRootDirectory() {
        return getAttribute(ROOT_DIRECTORY);
    }

    @Override
    public String getJavaHome() {
        return getAttribute(JAVA_HOME);
    }

    @Override
    protected void connectSensors() {
        super.connectSensors();
        jmxMxBeanFeed = JavaAppUtils.getMxBeanSensorsBuilder(this)
                .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
                        .objectName(WaratekUtils.VIRTUAL_MACHINE_MX_BEAN).attributeName("Vendor")
                        .onException(Functions.constant(Boolean.FALSE)).onSuccess(Functions.constant(Boolean.TRUE)))
                .build();
        jvcFeed = FunctionFeed.builder().entity(this).period(Duration.TEN_SECONDS)
                .poll(new FunctionPollConfig<Integer, Integer>(STOPPED_JVCS).callable(new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        return Iterables.size(getAvailableJvcs());
                    }
                }).onFailureOrException(Functions.constant(0)))
                .poll(new FunctionPollConfig<Integer, Integer>(RUNNING_JVCS).callable(new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        return getRunningJvcs();
                    }
                }).onFailureOrException(Functions.constant(0)))
                .poll(new FunctionPollConfig<Integer, Integer>(PAUSED_JVCS).callable(new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        return getPausedJvcs();
                    }
                }).onFailureOrException(Functions.constant(0))).build();
    }

    @Override
    protected void disconnectSensors() {
        if (jmxMxBeanFeed != null)
            jmxMxBeanFeed.stop();
        if (jvcFeed != null)
            jvcFeed.stop();
        super.disconnectSensors();
    }

    @Override
    public void doStart(Collection<? extends Location> locations) {
        super.doStart(locations);

        Maybe<SshMachineLocation> found = Machines.findUniqueSshMachineLocation(getLocations());
        Map<String, ?> flags = MutableMap.<String, Object>builder().putAll(getConfig(LOCATION_FLAGS))
                .put("machine", found.get()).build();

        createLocation(flags);
    }

    @Override
    public void doStop() {
        deleteLocation();

        super.doStop();
    }

    @Override
    public void deleteLocation() {
        WaratekMachineLocation location = getDynamicLocation();
        log.info("Deleting JVM location {}", location);

        if (location != null) {
            LocationManager mgr = getManagementContext().getLocationManager();
            if (mgr.isManaged(location)) {
                mgr.unmanage(location);
            }
            if (getConfig(WaratekInfrastructure.REGISTER_JVM_LOCATIONS)) {
                getManagementContext().getLocationRegistry().removeDefinedLocation(location.getId());
            }
        }
        setAttribute(DYNAMIC_LOCATION, null);
        setAttribute(LOCATION_NAME, null);
    }

    @Override
    public Integer resize(Integer desiredSize) {
        // Integer maxSize = getDynamicLocation().getConfig(DynamicLocation.MAX_SUB_LOCATIONS);
        Integer maxSize = getConfig(JVC_CLUSTER_MAX_SIZE);
        if (desiredSize > maxSize) {
            return getJvcCluster().resize(maxSize);
        } else {
            return getJvcCluster().resize(desiredSize);
        }
    }

    @Override
    public Integer getCurrentSize() {
        return getJvcCluster().getCurrentSize();
    }

    @Override
    public Iterable<Entity> getAvailableJvcs() {
        return Iterables.filter(getJvcList(), new Predicate<Entity>() {
            @Override
            public boolean apply(@Nullable Entity input) {
                return input.getAttribute(JavaVirtualContainer.ENTITY) == null
                        && JavaVirtualContainer.STATUS_SHUT_OFF
                                .equals(input.getAttribute(WaratekAttributes.STATUS));
            }
        });
    }

    @Override
    public Integer getRunningJvcs() {
        return Iterables.size(Iterables.filter(getJvcList(), new Predicate<Entity>() {
            @Override
            public boolean apply(@Nullable Entity input) {
                return input.getAttribute(JavaVirtualContainer.ENTITY) != null
                        && JavaVirtualContainer.STATUS_RUNNING.equals(input.getAttribute(WaratekAttributes.STATUS));
            }
        }));
    }

    @Override
    public Integer getPausedJvcs() {
        return Iterables.size(Iterables.filter(getJvcList(), new Predicate<Entity>() {
            @Override
            public boolean apply(@Nullable Entity input) {
                return input.getAttribute(JavaVirtualContainer.ENTITY) != null
                        && JavaVirtualContainer.STATUS_PAUSED.equals(input.getAttribute(WaratekAttributes.STATUS));
            }
        }));
    }

    @Override
    public WaratekMachineLocation getDynamicLocation() {
        return (WaratekMachineLocation) getAttribute(DYNAMIC_LOCATION);
    }

    /**
     * Create a new {@link WaratekMachineLocation} wrapping the machine we are starting in.
     */
    @Override
    public WaratekMachineLocation createLocation(Map<String, ?> flags) {
        WaratekInfrastructure infrastructure = getConfig(WARATEK_INFRASTRUCTURE);
        WaratekLocation waratek = infrastructure.getDynamicLocation();
        String locationName = waratek.getId() + "-" + getJvmName();

        String locationSpec = String.format(WaratekResolver.WARATEK_VIRTUAL_MACHINE_SPEC, infrastructure.getId(),
                getId()) + String.format(":(name=\"%s\")", locationName);
        setAttribute(LOCATION_SPEC, locationSpec);
        LocationDefinition definition = new BasicLocationDefinition(locationName, locationSpec, flags);
        Location location = getManagementContext().getLocationRegistry().resolve(definition);
        getManagementContext().getLocationManager().manage(location);

        setAttribute(DYNAMIC_LOCATION, location);
        setAttribute(LOCATION_NAME, location.getId());
        if (getConfig(WaratekInfrastructure.REGISTER_JVM_LOCATIONS)) {
            getManagementContext().getLocationRegistry().updateDefinedLocation(definition);
        }

        log.info("New JVM location {} created", location);
        return (WaratekMachineLocation) location;
    }

    @Override
    public boolean isLocationAvailable() {
        return getDynamicLocation() != null;
    }

    @Override
    public String getShortName() {
        return "JVM";
    }

}