Как стать автором
Обновить

Java DNS API, Wikipedia и twitter-марафон в одном флаконе

Время на прочтение5 мин
Количество просмотров2.1K
Некоторое время назад я решал задачу автоматической покупки домена. Нужно было оформить в виде библиотеки (jar и файл настроек), которая использовалась бы в корпоративном приложении на Java. Я начал поиски DNS провайдеров с public API. Желательно, чтобы API были попроще, и домены подешевле — такой баланс оказалось не просто найти.
Было рассмотрено много вариантов, некоторые из которых можно найти тут: stackoverflow. В последствии, я сузил круг до следующих претендентов:

Последний многие советовали, но это хостинг провайдер, а мне нужен был только ДНС – возможности не покупать сервер я там не нашел.

Первый имеет, на мой взгляд, очень удобный API – аутентификация может проходить вообще через HTTP Header X-DNSimple-Token, но есть и традиционный подход с http basic authorization. Формат запроса очень прост – короткие урлы. Ответы можно получать в JSON (XML тоже доступен) – вобщем все радует глаз, кроме цены — .com домен там стоит $14/y. Знающие люди поймут, что это неприемлимо.

Когда начал разбираться с http://www.namecheap.com/ — все оказалось довольно не плохо. И со стороны покупателя — цены в норме, на рынке он больше 10 лет (dnsimple.com через who is дал Creation date: 07 Apr 2010 17:32:00 – мелковат еще, плюс ID доменов, когда я создавал их через API был в районе 3000). И со стороны программиста: запросы в XML, но структура не сильно запутанная. Аутентификация через параметры в самом урле – ничего сложного.

Что мне больше всего понравилось – у них единственных из всех кандидатов оказался правильный sandbox. При регистрации в тестовом окружении у тебя на счету $9000 и ты можешь реально потестировать функции покупки, renew, reactivate и т.д. для домена. В DNsimple, к примеру, я не нашел возможности пользоваться тестовым окружением без того, чтоб вводить номер кредитки – а что это за sandbox, который не может работать без реальных данных?

Кроме того у них при редактировании host records домена есть возможность задать нестандартные значения (не только A, CNAME, AAAA, etc.) – есть еще “URL” – это позволяет делать редирект с вашего домена на некий урл (произвольный), а это как раз требовалось для задачи, и в случае отсутствия такой опции было бы необходимо что-то придумывать со стороны сервера заказчика. Такая фича есть далеко не у всех DNS провайдеров.

И еще этот провайдер довольно часто раздает купоны со скидкой (в API есть возможность использовать эти купоны) и организовывает акции (об одной из них – в конце статьи). Например недавно там были скидки для всех кто переводит свои домены от GoDaddy, в связи с SOPA-позициями последнего.

Перейдем к коду

Полностью он выложен в свободном доступе: github.com кому надо пользуйтесь (заказчику по барабану).

Интерфейс DNSProvider имеет конкретную реализацию: NamecheapProvider, где присутствуют основные функции для работы с доменами – покупка, обновление записей, реактивация. Есть пакет моделей, где находятся объекты основных сущностей: Domain, DomainRecord, RecordType. Все остальное это классы запросов, и xml парсеры ответов.

Базовый класс запроса:
public abstract class DNSBaseRequest {

    private List<NameValuePair> params = new ArrayList<NameValuePair>();

    protected DNSBaseRequest(Properties properties) {

        params.add(new BasicNameValuePair("ApiUser", properties.getProperty("api.login")));
        params.add(new BasicNameValuePair("ApiKey", properties.getProperty("api.key")));
        params.add(new BasicNameValuePair("UserName", properties.getProperty("api.login")));
        params.add(new BasicNameValuePair("ClientIp", properties.getProperty("client.ip")));
        //each class has its own command - his purpose
        params.add(new BasicNameValuePair("Command", getCommand()));
    }

    protected abstract String getCommand();
....
}



Каждый класс запроса реализует свою getCommand, которая соответствует его назначению:

public class DomainReactivateRequest extends DNSBaseRequest{

    public DomainReactivateRequest(String domainName, Properties properties) {
        super(properties);
        addParam(new BasicNameValuePair("DomainName", domainName));
    }

    @Override
    protected String getCommand() {
        return "namecheap.domains.reactivate";
    }
}



Интерфейс парсера:
public interface XmlResponseParser<T> {

    T parse(String xml);
}


И пример реализации для получения списка доменов из вашего аккаунта:
public class DomainsListParser extends DefaultHandler implements XmlResponseParser<ArrayList<Domain>> {

    private static final Logger log = LoggerFactory.getLogger(DomainsListParser.class);

    private SAXParser parser;
    private ArrayList<Domain> result;

    public DomainsListParser() throws Exception{
        SAXParserFactory factory = SAXParserFactory.newInstance();
        parser = factory.newSAXParser();
        result = new ArrayList<Domain>();
    }

    public ArrayList<Domain> parse(String xml) {

        try {
            parser.parse(new InputSource(new StringReader(xml)), this);
        } catch(Exception e){
            log.error("Error in parsing string.", e);
        }

        return result;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

        if ("Domain".equalsIgnoreCase(qName)){
            Domain domain = new Domain(Long.parseLong(attributes.getValue("ID")), attributes.getValue("Name"));
            domain.setCreateDate(attributes.getValue("Created"));
            domain.setExpireDate(attributes.getValue("Expires"));

            result.add(domain);
        }
    }
}



Друг с другом запрос и разбор ответа сводит класс на дженериках:
public class ProviderOperator {

    private static final Logger log = LoggerFactory.getLogger(ProviderOperator.class);

    private DNSRequestProcessor dnsRequestProcessor;

    public ProviderOperator(DNSRequestProcessor dnsRequestProcessor) {
        this.dnsRequestProcessor = dnsRequestProcessor;
    }

    public <T, S extends T> T process(DNSBaseRequest dnsRequest, XmlResponseParser<T> parser, S defaultResult) {

        T result = defaultResult;
        try {
            String xml = dnsRequestProcessor.get(dnsRequest);
            log.debug("Response: {}", xml);
            result = parser.parse(xml);
        } catch (Exception e) {
            log.error("Error in parse", e);
        }
        return result;
    }
}



Который принимает их через параметры и возвращает результат разбора xml ответа.

Для расширения функциональности нужно добавить функцию в интерфейс, создать класс запроса, класс парсера ответа, и объединить их через вызов ProviderOperator в соотв. функции NamecheapProvider.

Напоследок интересная история

www.namecheap.com имеет традицию – каждый год они организовывают твиттер-марафон на определенную тему. В течение 48 часов задаются 48 вопросов. Каждый час дается правильный ответ на предыдущий вопрос и задается следующий. Победителям деньги на счет (для покупки доменов) и пара iPad2 – самый ходовой приз большинства викторин. В этом году марафон решили приурочить к суперкубку. Я в американских видах спорта не силен, но решил для интереса ответить на какой-нибудь вопрос. Номер третий звучал примерно так:

«In what year was Bart Starr elected to the Wisconsin Athletic Hall of Fame»

— не долго думая, пошел в википедию смотреть его биографию. Отдельным обзацом было написано, что это произошло в 1980. Я твитнул это число в ответ. Через час твит с правильным ответом меня немного расстроил – 1981. Ну кто бы сомневался, подумал я, что в википедии даты не точные. Но все-таки решил зайти туда снова и посмотреть – расстроился еще больше. Там было действительно написано 1981. Я подумал, что пора затариваться таблетками для улучшения зрения, повышения внимания и ускорения работы мозга – вобщем все что прописывают старикам, и занялся другими делами.

Однако через пару часов от организатора марафона поступил интересный твит, приблизительно такого содержания:

«Уважаемые участники, мы считаем НЕДОПУСТИМЫМ редактировать википедию, чтобы дезинформировать соперников – это противоречит духу fair play. Уличенный в мошенничестве будет дисквалифицирован»

Я обрадовался — значит рано покупать лекарства.

UPD Всем спасибо за сообщение о поломанной подсветке.
Теги:
Хабы:
Всего голосов 14: ↑14 и ↓0+14
Комментарии0

Публикации

Истории

Работа

Java разработчик
355 вакансий

Ближайшие события