<commit_before>/*
 * Copyright 2013 by Cloudsoft Corp.
 *
 * 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.network.bind;

import java.io.ByteArrayInputStream;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

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

import brooklyn.entity.Entity;
import brooklyn.entity.basic.DynamicGroup;
import brooklyn.entity.basic.SoftwareProcessImpl;
import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
import brooklyn.entity.proxying.EntitySpecs;
import brooklyn.entity.trait.Startable;
import brooklyn.location.Location;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.ssh.CommonCommands;
import brooklyn.util.text.Strings;

import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

/**
 * This sets up a BIND DNS server.
 */
public class BindDnsServerImpl extends SoftwareProcessImpl implements BindDnsServer {

    protected static final Logger LOG = LoggerFactory.getLogger(BindDnsServerImpl.class);
    protected static final String RESOURCES_CLASSPATH = "classpath://brooklyn/entity/network/bind/";

    private AtomicLong serial = new AtomicLong(System.currentTimeMillis());
    private Object[] mutex = new Object[0];
    private DynamicGroup entities;
    private AbstractMembershipTrackingPolicy policy;
    private Multimap<Location, Entity> entityLocations = HashMultimap.create();
    private ConcurrentMap<String, String> addressMappings = Maps.newConcurrentMap();
    protected List<InetAddress> addresses = Lists.newArrayList();

    public BindDnsServerImpl() {
        super();
    }

    public String getManagementCidr() {
        return getConfig(MANAGEMENT_CIDR);
    }

    public Integer getDnsPort() {
        return getAttribute(DNS_PORT);
    }

    public String getDomainName() {
        return getConfig(DOMAIN_NAME);
    }

    public long getSerial() {
        return serial.incrementAndGet();
    }

    @Override
    public void init() {
        entities = addChild(EntitySpecs.spec(DynamicGroup.class)
                .configure("entityFilter", getConfig(ENTITY_FILTER)));
    }

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

    @Override
    public Map<String, String> getAddressMappings() {
        return addressMappings;
    }

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

    @Override
    public void connectSensors() {
        connectServiceUpIsRunning();
    }

    @Override
    public void disconnectSensors() {
        disconnectServiceUpIsRunning();
    }

    @Override
    protected void preStart() {
        Map<?, ?> flags = MutableMap.builder()
                .put("name", "Address tracker")
                .put("sensorsToTrack", ImmutableSet.of(getConfig(HOSTNAME_SENSOR)))
                .build();
        policy = new AbstractMembershipTrackingPolicy(flags) {
            @Override
            protected void onEntityChange(Entity member) { added(member); }
            @Override
            protected void onEntityAdded(Entity member) {
                if (!Strings.isNonBlank(member.getAttribute(getConfig(HOSTNAME_SENSOR)))) added(member); // Ignore, unless attrib already set
            }
            @Override
            protected void onEntityRemoved(Entity member) { removed(member); }
        };

        addPolicy(policy);
        policy.setGroup(entities);

        // For any entities that have already come up
        for (Entity member : entities.getMembers()) {
            if (!Strings.isNonBlank(member.getAttribute(getConfig(HOSTNAME_SENSOR)))) added(member);
        }
    }

    @Override
    public void postStart() {
        update();
    }

    public void added(Entity member) {
        synchronized (mutex) {
            Optional<Location> location = Iterables.tryFind(member.getLocations(), Predicates.instanceOf(SshMachineLocation.class));
            String hostname = member.getAttribute(getConfig(HOSTNAME_SENSOR));
            if (location.isPresent() && Strings.isNonBlank(hostname)) {
                SshMachineLocation machine = (SshMachineLocation) location.get();
                String address = machine.getAddress().getHostAddress();
                if (!entityLocations.containsKey(machine)) {
                    entityLocations.put(machine, member);
                    addressMappings.putIfAbsent(address, hostname);
                    if (getAttribute(Startable.SERVICE_UP)) {
                        update();
                    }
                    configure(machine);
                    LOG.info("{} added at location {} with name {}", new Object[] { member, machine, hostname });
                }
            } else {
                LOG.warn("added({}) called but entity not ready", member);
            }
        }
    }

    public void removed(Entity member) {
        synchronized (mutex) {
            Optional<Location> location = Iterables.tryFind(member.getLocations(), Predicates.instanceOf(SshMachineLocation.class));
            SshMachineLocation machine = (SshMachineLocation) location.get();
            entityLocations.remove(machine, member);
            if (!entityLocations.containsKey(machine)) {
                addressMappings.remove(machine.getAddress().getHostAddress());
            }
            update();
        }
    }

    public void update() {
        Optional<Location> location = Iterables.tryFind(getLocations(), Predicates.instanceOf(SshMachineLocation.class));<commit_msg>Fix BindDnsServer.removed(Entity) for when loc unknown<commit_after>/*
 * Copyright 2013 by Cloudsoft Corp.
 *
 * 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.network.bind;

import java.io.ByteArrayInputStream;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

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

import brooklyn.entity.Entity;
import brooklyn.entity.basic.DynamicGroup;
import brooklyn.entity.basic.SoftwareProcessImpl;
import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
import brooklyn.entity.proxying.EntitySpecs;
import brooklyn.entity.trait.Startable;
import brooklyn.location.Location;
import brooklyn.location.MachineLocation;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.ssh.CommonCommands;
import brooklyn.util.text.Strings;

import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;

/**
 * This sets up a BIND DNS server.
 */
public class BindDnsServerImpl extends SoftwareProcessImpl implements BindDnsServer {

    protected static final Logger LOG = LoggerFactory.getLogger(BindDnsServerImpl.class);
    protected static final String RESOURCES_CLASSPATH = "classpath://brooklyn/entity/network/bind/";

    private AtomicLong serial = new AtomicLong(System.currentTimeMillis());
    private Object[] mutex = new Object[0];
    private DynamicGroup entities;
    private AbstractMembershipTrackingPolicy policy;
    private Multimap<Location, Entity> entityLocations = HashMultimap.create();
    private ConcurrentMap<String, String> addressMappings = Maps.newConcurrentMap();
    protected List<InetAddress> addresses = Lists.newArrayList();

    public BindDnsServerImpl() {
        super();
    }

    public String getManagementCidr() {
        return getConfig(MANAGEMENT_CIDR);
    }

    public Integer getDnsPort() {
        return getAttribute(DNS_PORT);
    }

    public String getDomainName() {
        return getConfig(DOMAIN_NAME);
    }

    public long getSerial() {
        return serial.incrementAndGet();
    }

    @Override
    public void init() {
        entities = addChild(EntitySpecs.spec(DynamicGroup.class)
                .configure("entityFilter", getConfig(ENTITY_FILTER)));
    }

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

    @Override
    public Map<String, String> getAddressMappings() {
        return addressMappings;
    }

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

    @Override
    public void connectSensors() {
        connectServiceUpIsRunning();
    }

    @Override
    public void disconnectSensors() {
        disconnectServiceUpIsRunning();
    }

    @Override
    protected void preStart() {
        Map<?, ?> flags = MutableMap.builder()
                .put("name", "Address tracker")
                .put("sensorsToTrack", ImmutableSet.of(getConfig(HOSTNAME_SENSOR)))
                .build();
        policy = new AbstractMembershipTrackingPolicy(flags) {
            @Override
            protected void onEntityChange(Entity member) { added(member); }
            @Override
            protected void onEntityAdded(Entity member) {
                if (!Strings.isNonBlank(member.getAttribute(getConfig(HOSTNAME_SENSOR)))) added(member); // Ignore, unless attrib already set
            }
            @Override
            protected void onEntityRemoved(Entity member) { removed(member); }
        };

        addPolicy(policy);
        policy.setGroup(entities);

        // For any entities that have already come up
        for (Entity member : entities.getMembers()) {
            if (!Strings.isNonBlank(member.getAttribute(getConfig(HOSTNAME_SENSOR)))) added(member);
        }
    }

    @Override
    public void postStart() {
        update();
    }

    public void added(Entity member) {
        synchronized (mutex) {
            Optional<Location> location = Iterables.tryFind(member.getLocations(), Predicates.instanceOf(SshMachineLocation.class));
            String hostname = member.getAttribute(getConfig(HOSTNAME_SENSOR));
            if (location.isPresent() && Strings.isNonBlank(hostname)) {
                SshMachineLocation machine = (SshMachineLocation) location.get();
                String address = machine.getAddress().getHostAddress();
                if (!entityLocations.containsKey(machine)) {
                    entityLocations.put(machine, member);
                    addressMappings.putIfAbsent(address, hostname);
                    if (getAttribute(Startable.SERVICE_UP)) {
                        update();
                    }
                    configure(machine);
                    LOG.info("{} added at location {} with name {}", new Object[] { member, machine, hostname });
                }
            } else {
                LOG.warn("added({}) called but entity not ready", member);
            }
        }
    }

    public void removed(Entity member) {
        synchronized (mutex) {
            Location location = reverseLookupLocation(member);
            if (location != null) {
                entityLocations.remove(location, member);
                if (!entityLocations.containsKey(location)) {
                    addressMappings.remove(((MachineLocation)location).getAddress().getHostAddress());
                }
            }
            update();
        }
    }

    private Location reverseLookupLocation(Entity member) {
        // don't use member.getLocations(), because when being stopped the location might not be set
        if (entityLocations.containsValue(member)) {
            for (Map.Entry<Location, Entity> entry : entityLocations.entries()) {
                if (member.equals(entry.getValue())) {
                    return entry.getKey();
                }
            }
            return null;
        } else {
            return null;
        }
    }
    
    public void update() {
        Optional<Location> location = Iterables.tryFind(getLocations(), Predicates.instanceOf(SshMachineLocation.class));
{'fraction_non_alphanumeric': 0.0970263753927084, 'fraction_numerical': 0.0016073646525900489, 'mean_word_length': 2.8765222316624186, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '6275896', 'n_tokens_mistral': 3672, 'n_tokens_neox': 3584, 'n_words': 839}