<commit_before>package brooklyn.entity.webapp

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import brooklyn.enricher.basic.SensorPropagatingEnricher
import brooklyn.entity.Entity
import brooklyn.entity.basic.AbstractEntity
import brooklyn.entity.basic.Attributes
import brooklyn.entity.basic.ConfigurableEntityFactory
import brooklyn.entity.basic.Entities
import brooklyn.entity.group.Cluster
import brooklyn.entity.proxy.AbstractController
import brooklyn.entity.proxy.nginx.NginxController
import brooklyn.entity.trait.Resizable
import brooklyn.entity.trait.Startable
import brooklyn.entity.webapp.jboss.JBoss7ServerFactory
import brooklyn.event.Sensor
import brooklyn.event.SensorEventListener
import brooklyn.event.basic.BasicConfigKey
import brooklyn.location.Location
import brooklyn.util.flags.SetFromFlag

import com.google.common.collect.Iterables

/**
 * This entity contains the sub-groups and entities that go in to a single location (e.g. datacenter)
 * to provide web-app cluster functionality, viz load-balancer (controller) and webapp software processes.
 * <p>
 * You can customise the web server by customising
 * the factory (by reference in calling code)
 * or supplying your own factory (as a config flag).
 * <p>
 * The contents of this group entity are:
 * <ul>
 * <li>a {@link brooklyn.entity.group.DynamicCluster} of {@link JavaWebAppService}s (defaults to JBoss7Server)
 * <li>a cluster controller (defaulting to Nginx if none supplied)
 * <li>a {@link brooklyn.policy.Policy} to resize the DynamicCluster
 * </ul>
 */
public class ControlledDynamicWebAppCluster extends AbstractEntity implements Startable, Resizable, ElasticJavaWebAppService {

    public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppCluster.class);
            
    @SetFromFlag('initialSize')
    public static BasicConfigKey<Integer> INITIAL_SIZE = [ Cluster.INITIAL_SIZE, 1 ]

    @SetFromFlag("controller")
    AbstractController _controller;

    /** factory (or closure) to create the web server, given flags */
    @SetFromFlag("factory")
    ConfigurableEntityFactory<WebAppService> _webServerFactory;

    public static final Sensor HOSTNAME = Attributes.HOSTNAME;
    
    public ControlledDynamicWebAppCluster(Entity owner) { this([:], owner) }
    public ControlledDynamicWebAppCluster(Map flags = [:], Entity owner = null) {
        super(flags, owner)
        setAttribute(SERVICE_UP, false)
    }

    // TODO convert to an entity reference which is serializable
    transient private AbstractController cachedController;
    public synchronized AbstractController getController() {
        if (cachedController!=null) return cachedController;
        cachedController = _controller;
        if (cachedController!=null) return cachedController;
        cachedController = getOwnedChildren().find { it in AbstractController }
        if (cachedController!=null) return cachedController;
        log.debug("creating default controller for {}", this);
        cachedController = new NginxController(this);
    }
    
    private ConfigurableEntityFactory<WebAppService> cachedWebServerFactory;
    public synchronized ConfigurableEntityFactory<WebAppService> getFactory() {
        if (cachedWebServerFactory!=null) return cachedWebServerFactory;
        cachedWebServerFactory = _webServerFactory;
        if (cachedWebServerFactory!=null) return cachedWebServerFactory;
        log.debug("creating default web server factory for {}", this);
        cachedWebServerFactory = new JBoss7ServerFactory();
    }
    
    // TODO convert to an entity reference which is serializable
    transient private DynamicWebAppCluster cachedCluster;
    public synchronized DynamicWebAppCluster getCluster() {
        if (cachedCluster!=null) return cachedCluster;
        cachedCluster = getOwnedChildren().find { it in DynamicWebAppCluster }
        if (cachedCluster!=null) return cachedCluster;
        log.debug("creating cluster child for {}", this);
        cachedCluster = new DynamicWebAppCluster(this,
            factory: factory,
            initialSize: { getConfig(INITIAL_SIZE) });
    }
    
    public void start(Collection<? extends Location> locations) {
        Iterables.getOnlyElement(locations); //assert just one
        
        addOwnedChild(controller);
        this.locations.addAll(locations);
        controller.bind(serverPool:cluster);
        Entities.invokeEffectorList(this, [cluster, controller], Startable.START, [locations:locations]).get();
        
        connectSensors();
        setAttribute(SERVICE_UP, true);
    }
    
    public void stop() {
        controller.stop()
        cluster.stop()

        locations.clear();
        setAttribute(SERVICE_UP, false)
    }

    public void restart() {
        // TODO prod the entities themselves to restart, instead?
        def locations = []
        locations.addAll(this.locations)

        stop();
        start(locations);
    }

    void updateHostnameFromController() {
        String url = controller.getAttribute(NginxController.ROOT_URL);
        if (url==null) url = controller.getAttribute(AbstractController.ROOT_URL);
        if (url==null || url.contains("://"+AbstractController.ANONYMOUS+":") || url.contains("://"+AbstractController.ANONYMOUS+"/")) {
            //probably isn't necessary, as is done in Nginx?
            String hostname = controller.getAttribute(HOSTNAME);
            Object port = controller.getAttribute(AbstractController.PROXY_HTTP_PORT);
            if (hostname==null || port==null) return;
            url = "http://"+hostname+":"+port+"/";
            LOG.warn("Building URL for $this from $controller: $url");
        }
        setAttribute(ROOT_URL, url);
    }
    
    void connectSensors() {
        SensorPropagatingEnricher.newInstanceListeningToAllSensorsBut(cluster, SERVICE_UP, ROOT_URL).
            addToEntityAndEmitAll(this);
        
        //following 3 lines (and updateHostname method) unnecessary if above is working, I think
        controller.subscribe(controller, NginxController.ROOT_URL, { updateHostnameFromController() } as SensorEventListener);
        controller.subscribe(controller, NginxController.ROOT_URL, { updateHostnameFromController() } as SensorEventListener);
        controller.subscribe(controller, AbstractController.HOSTNAME, { updateHostnameFromController() } as SensorEventListener);
        updateHostnameFromController();
        
        SensorPropagatingEnricher.newInstanceListeningTo(controller, AbstractController.HOSTNAME, SERVICE_UP).
        addToEntityAndEmitAll(this);
    }

    public Integer resize(Integer desiredSize) {
        cluster.resize(desiredSize);
    }

    /**
     * @return the current size of the group.
     */
    public Integer getCurrentSize() {
        cluster.getCurrentSize();
    }

}<commit_msg>remove sensor no longer used<commit_after>package brooklyn.entity.webapp

import org.slf4j.Logger
import org.slf4j.LoggerFactory

import brooklyn.enricher.basic.SensorPropagatingEnricher
import brooklyn.entity.Entity
import brooklyn.entity.basic.AbstractEntity
import brooklyn.entity.basic.Attributes
import brooklyn.entity.basic.ConfigurableEntityFactory
import brooklyn.entity.basic.Entities
import brooklyn.entity.group.Cluster
import brooklyn.entity.proxy.AbstractController
import brooklyn.entity.proxy.nginx.NginxController
import brooklyn.entity.trait.Resizable
import brooklyn.entity.trait.Startable
import brooklyn.entity.webapp.jboss.JBoss7ServerFactory
import brooklyn.event.Sensor
import brooklyn.event.SensorEventListener
import brooklyn.event.basic.BasicConfigKey
import brooklyn.location.Location
import brooklyn.util.flags.SetFromFlag

import com.google.common.collect.Iterables

/**
 * This entity contains the sub-groups and entities that go in to a single location (e.g. datacenter)
 * to provide web-app cluster functionality, viz load-balancer (controller) and webapp software processes.
 * <p>
 * You can customise the web server by customising
 * the factory (by reference in calling code)
 * or supplying your own factory (as a config flag).
 * <p>
 * The contents of this group entity are:
 * <ul>
 * <li>a {@link brooklyn.entity.group.DynamicCluster} of {@link JavaWebAppService}s (defaults to JBoss7Server)
 * <li>a cluster controller (defaulting to Nginx if none supplied)
 * <li>a {@link brooklyn.policy.Policy} to resize the DynamicCluster
 * </ul>
 */
public class ControlledDynamicWebAppCluster extends AbstractEntity implements Startable, Resizable, ElasticJavaWebAppService {

    public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppCluster.class);
            
    @SetFromFlag('initialSize')
    public static BasicConfigKey<Integer> INITIAL_SIZE = [ Cluster.INITIAL_SIZE, 1 ]

    @SetFromFlag("controller")
    AbstractController _controller;

    /** factory (or closure) to create the web server, given flags */
    @SetFromFlag("factory")
    ConfigurableEntityFactory<WebAppService> _webServerFactory;

    public static final Sensor HOSTNAME = Attributes.HOSTNAME;
    
    public ControlledDynamicWebAppCluster(Entity owner) { this([:], owner) }
    public ControlledDynamicWebAppCluster(Map flags = [:], Entity owner = null) {
        super(flags, owner)
        setAttribute(SERVICE_UP, false)
    }

    // TODO convert to an entity reference which is serializable
    transient private AbstractController cachedController;
    public synchronized AbstractController getController() {
        if (cachedController!=null) return cachedController;
        cachedController = _controller;
        if (cachedController!=null) return cachedController;
        cachedController = getOwnedChildren().find { it in AbstractController }
        if (cachedController!=null) return cachedController;
        log.debug("creating default controller for {}", this);
        cachedController = new NginxController(this);
    }
    
    private ConfigurableEntityFactory<WebAppService> cachedWebServerFactory;
    public synchronized ConfigurableEntityFactory<WebAppService> getFactory() {
        if (cachedWebServerFactory!=null) return cachedWebServerFactory;
        cachedWebServerFactory = _webServerFactory;
        if (cachedWebServerFactory!=null) return cachedWebServerFactory;
        log.debug("creating default web server factory for {}", this);
        cachedWebServerFactory = new JBoss7ServerFactory();
    }
    
    // TODO convert to an entity reference which is serializable
    transient private DynamicWebAppCluster cachedCluster;
    public synchronized DynamicWebAppCluster getCluster() {
        if (cachedCluster!=null) return cachedCluster;
        cachedCluster = getOwnedChildren().find { it in DynamicWebAppCluster }
        if (cachedCluster!=null) return cachedCluster;
        log.debug("creating cluster child for {}", this);
        cachedCluster = new DynamicWebAppCluster(this,
            factory: factory,
            initialSize: { getConfig(INITIAL_SIZE) });
    }
    
    public void start(Collection<? extends Location> locations) {
        Iterables.getOnlyElement(locations); //assert just one
        
        addOwnedChild(controller);
        this.locations.addAll(locations);
        controller.bind(serverPool:cluster);
        Entities.invokeEffectorList(this, [cluster, controller], Startable.START, [locations:locations]).get();
        
        connectSensors();
    }
    
    public void stop() {
        controller.stop()
        cluster.stop()

        locations.clear();
        setAttribute(SERVICE_UP, false)
    }

    public void restart() {
        // TODO prod the entities themselves to restart, instead?
        def locations = []
        locations.addAll(this.locations)

        stop();
        start(locations);
    }
    
    void connectSensors() {
        SensorPropagatingEnricher.newInstanceListeningToAllSensorsBut(cluster, SERVICE_UP, ROOT_URL).
            addToEntityAndEmitAll(this);
        SensorPropagatingEnricher.newInstanceListeningTo(controller, AbstractController.HOSTNAME, SERVICE_UP, ROOT_URL).
            addToEntityAndEmitAll(this);
    }

    public Integer resize(Integer desiredSize) {
        cluster.resize(desiredSize);
    }

    /**
     * @return the current size of the group.
     */
    public Integer getCurrentSize() {
        cluster.getCurrentSize();
    }

}
{'fraction_non_alphanumeric': 0.08642274452790566, 'fraction_numerical': 0.001049995961553994, 'mean_word_length': 3.7295645530939647, 'pattern_counts': {'":': 4, '<': 27, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5048361', 'n_tokens_mistral': 3273, 'n_tokens_neox': 3227, 'n_words': 820}