All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.anrisoftware.sscontrol.dns.service.DnsServiceImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012-2015 Erwin Müller 
 *
 * This file is part of sscontrol-dns.
 *
 * sscontrol-dns is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * sscontrol-dns is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with sscontrol-dns. If not, see .
 */
package com.anrisoftware.sscontrol.dns.service;

import static com.anrisoftware.sscontrol.dns.service.DnsServiceFactory.SERVICE_NAME;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.ACLS_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.ADDRESSES_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.ADDRESS_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.ALIAS_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.DURATION_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.GENERATE_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.NAME_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.ROOT_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.SERIAL_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.SERVERS_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.SERVER_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.TTL_KEY;
import static com.anrisoftware.sscontrol.dns.service.DnsServiceStatement.UPSTREAM_KEY;
import static java.lang.String.format;
import static java.util.Collections.unmodifiableList;
import groovy.lang.Script;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.inject.Inject;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.DateTime;

import com.anrisoftware.sscontrol.core.api.Service;
import com.anrisoftware.sscontrol.core.api.ServiceException;
import com.anrisoftware.sscontrol.core.api.ServiceScriptFactory;
import com.anrisoftware.sscontrol.core.bindings.BindingAddress;
import com.anrisoftware.sscontrol.core.bindings.BindingAddressesStatementsTable;
import com.anrisoftware.sscontrol.core.bindings.BindingAddressesStatementsTableFactory;
import com.anrisoftware.sscontrol.core.groovy.StatementsException;
import com.anrisoftware.sscontrol.core.groovy.StatementsMap;
import com.anrisoftware.sscontrol.core.groovy.StatementsMapFactory;
import com.anrisoftware.sscontrol.core.groovy.StatementsTable;
import com.anrisoftware.sscontrol.core.groovy.StatementsTableFactory;
import com.anrisoftware.sscontrol.core.list.StringToListFactory;
import com.anrisoftware.sscontrol.core.service.AbstractService;
import com.anrisoftware.sscontrol.dns.zone.DnsZone;
import com.anrisoftware.sscontrol.dns.zone.DnsZoneFactory;
import com.anrisoftware.sscontrol.dns.zone.Record;
import com.anrisoftware.sscontrol.dns.zone.ZoneRecord;

/**
 * DNS service.
 *
 * @author Erwin Mueller, [email protected]
 * @since 1.0
 */
@SuppressWarnings("serial")
class DnsServiceImpl extends AbstractService implements DnsService {

    private final List zones;

    @Inject
    private DnsServiceImplLogger log;

    @Inject
    private StringToListFactory toListFactory;

    @Inject
    private DnsZoneFactory zoneFactory;

    private StatementsMap statementsMap;

    private StatementsTable statementsTable;

    private BindingAddressesStatementsTable bindingAddressesStatementsTable;

    DnsServiceImpl() {
        this.zones = new ArrayList();
    }

    @Inject
    public void setStatementsMapFactory(StatementsMapFactory factory) {
        StatementsMap map = factory.create(this, SERVICE_NAME);
        this.statementsMap = map;
        map.addAllowed(SERIAL_KEY, SERVERS_KEY, ACLS_KEY);
        map.setAllowValue(true, SERIAL_KEY);
        map.setAllowMultiValue(true, ACLS_KEY);
        map.addAllowedKeys(SERIAL_KEY, GENERATE_KEY);
        map.addAllowedKeys(SERVERS_KEY, UPSTREAM_KEY, ROOT_KEY);
        map.putValue(SERIAL_KEY.toString(), 0);
        map.putMapValue(SERIAL_KEY.toString(), GENERATE_KEY.toString(), true);
    }

    @Inject
    public void setStatementsTableFactory(StatementsTableFactory factory) {
        StatementsTable table = factory.create(this, SERVICE_NAME);
        this.statementsTable = table;
        table.addAllowed(SERVER_KEY, ALIAS_KEY);
        table.addAllowedKeys(SERVER_KEY, ADDRESS_KEY);
        table.addAllowedKeys(ALIAS_KEY, ADDRESS_KEY, ADDRESSES_KEY);
    }

    @Inject
    public final void setBindingAddressesStatementsTable(
            BindingAddressesStatementsTableFactory factory) {
        BindingAddressesStatementsTable table;
        table = factory.create(this, SERVICE_NAME);
        table.setRequirePort(false);
        this.bindingAddressesStatementsTable = table;
    }

    @Override
    protected Script getScript(String profileName) throws ServiceException {
        ServiceScriptFactory scriptFactory = findScriptFactory(SERVICE_NAME);
        return (Script) scriptFactory.getScript();
    }

    /**
     * Because we load the script from a script service the dependencies are
     * already injected.
     */
    @Override
    protected void injectScript(Script script) {
    }

    /**
     * Returns the DNS service name.
     */
    @Override
    public String getName() {
        return SERVICE_NAME;
    }

    /**
     * Entry point for the DNS service script.
     *
     * @param statements
     *            the DNS service statements.
     *
     * @return this {@link Service}.
     */
    public Service dns(Object statements) {
        return this;
    }

    @Override
    public int getSerialNumber() {
        int serial = statementsMap.value(SERIAL_KEY);
        return isSerialGenerate() ? generateSerial(serial) : serial;
    }

    @Override
    public boolean isSerialGenerate() {
        return statementsMap.mapValue(SERIAL_KEY, GENERATE_KEY);
    }

    @Override
    public Map> getBindingAddresses() {
        return bindingAddressesStatementsTable.getBindingAddresses();
    }

    @Override
    public List getUpstreamServers() {
        return statementsMap.mapValueAsStringList(SERVERS_KEY, UPSTREAM_KEY);
    }

    @Override
    public List getRootServers() {
        return statementsMap.mapValueAsStringList(SERVERS_KEY, ROOT_KEY);
    }

    @Override
    public Map getServers() {
        return statementsTable.tableKeys(SERVER_KEY, ADDRESS_KEY);
    }

    @Override
    public Map> getAliases() {
        Map> amap = new HashMap>();
        List alist;
        Map> address;
        address = statementsTable.tableKeysAsList(ALIAS_KEY, ADDRESS_KEY);
        Map> addresses;
        addresses = statementsTable.tableKeysAsList(ALIAS_KEY, ADDRESSES_KEY);
        if (address != null) {
            for (Entry> entry : address.entrySet()) {
                alist = amap.get(entry.getKey());
                if (alist == null) {
                    alist = new ArrayList();
                    amap.put(entry.getKey(), alist);
                }
                alist.addAll(entry.getValue());
            }
        }
        if (addresses != null) {
            for (Entry> entry : addresses.entrySet()) {
                alist = amap.get(entry.getKey());
                if (alist == null) {
                    alist = new ArrayList();
                    amap.put(entry.getKey(), alist);
                }
                alist.addAll(entry.getValue());
            }
        }
        return amap.size() == 0 ? null : amap;
    }

    @Override
    public List getAcls() {
        List value = statementsMap.value(ACLS_KEY);
        if (value == null) {
            return null;
        }
        List result = new ArrayList();
        for (Object object : value) {
            List list = toListFactory.create(object).getList();
            for (Object o : list) {
                result.add(o.toString());
            }
        }
        return result;
    }

    /**
     * Adds a new DNS zone.
     *
     * @see DnsZoneFactory#create(Map, String)
     *
     * @return the {@link DnsZone}.
     *
     * @throws ParseException
     *             if the TTL duration of the automatic A-record could not be
     *             parsed.
     */
    public void zone(Map args, String name)
            throws ParseException {
        zone(args, name, null);
    }

    /**
     * Adds a new DNS zone.
     *
     * @see DnsZoneFactory#create(Map, String)
     *
     * @return the {@link DnsZone}.
     *
     * @throws ParseException
     *             if the TTL duration of the automatic A-record could not be
     *             parsed.
     */
    public DnsZone zone(Map args, String name, Object statements)
            throws ParseException {
        if (!args.containsKey(SERIAL_KEY.toString())) {
            args.put(SERIAL_KEY.toString(), getSerialNumber());
        }
        DnsZone zone = zoneFactory.create(args, name);
        zones.add(zone);
        if (args.containsKey(ADDRESS_KEY.toString())) {
            automaticARecord(args, name, zone);
        }
        log.zoneAdded(this, zone);
        return zone;
    }

    private void automaticARecord(Map args, String name,
            DnsZone zone) throws ParseException {
        Map aargs = new HashMap();
        aargs.put(NAME_KEY.toString(), name);
        aargs.put(ADDRESS_KEY.toString(), args.get(ADDRESS_KEY.toString()));
        ZoneRecord record = zone.record(aargs, Record.a, (Object) null);
        if (args.containsKey(TTL_KEY.toString())) {
            aargs.put(DURATION_KEY.toString(), args.get(TTL_KEY.toString()));
            record.ttl(aargs);
        }
    }

    private int generateSerial(int serial) {
        DateTime date = new DateTime();
        String string = format("%d%d%d%02d", date.getYear(),
                date.getMonthOfYear(), date.getDayOfMonth(), serial);
        return Integer.parseInt(string);
    }

    @Override
    public List getZones() {
        return unmodifiableList(zones);
    }

    /**
     * @see BindingAddress#local
     */
    public BindingAddress getLocal() {
        return BindingAddress.local;
    }

    /**
     * @see BindingAddress#all
     */
    public BindingAddress getAll() {
        return BindingAddress.all;
    }

    /**
     * @see Record#a
     */
    public Record getA() {
        return Record.a;
    }

    /**
     * @see Record#cname
     */
    public Record getCname() {
        return Record.cname;
    }

    /**
     * @see Record#mx
     */
    public Record getMx() {
        return Record.mx;
    }

    /**
     * @see Record#ns
     */
    public Record getNs() {
        return Record.ns;
    }

    public Object methodMissing(String name, Object args)
            throws ServiceException {
        try {
            return statementsMap.methodMissing(name, args);
        } catch (StatementsException e) {
            try {
                return statementsTable.methodMissing(name, args);
            } catch (StatementsException e1) {
                return bindingAddressesStatementsTable
                        .methodMissing(name, args);
            }
        }
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).appendSuper(super.toString())
                .toString();
    }

}