de.dal33t.powerfolder.net.DynDnsManager.java Source code

Java tutorial

Introduction

Here is the source code for de.dal33t.powerfolder.net.DynDnsManager.java

Source

/*
 * Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
 *
 * This file is part of PowerFolder.
 *
 * PowerFolder is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * PowerFolder 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PowerFolder. If not, see <http://www.gnu.org/licenses/>.
 *
 * $Id$
 */
package de.dal33t.powerfolder.net;

import java.awt.Component;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Hashtable;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JDialog;
import javax.swing.JLabel;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import de.dal33t.powerfolder.ConfigurationEntry;
import de.dal33t.powerfolder.Controller;
import de.dal33t.powerfolder.PFComponent;
import de.dal33t.powerfolder.ui.dialog.ErrorDialog;
import de.dal33t.powerfolder.ui.dialog.DialogFactory;
import de.dal33t.powerfolder.ui.dialog.GenericDialogType;
import de.dal33t.powerfolder.ui.preferences.DynDnsSettingsTab;
import de.dal33t.powerfolder.util.StringUtils;
import de.dal33t.powerfolder.util.Translation;

/**
 * The DynDnsManager class is responsible for: - to provide services to the
 * DynDns updates and, - DynDns validation as well as some UI utility methods.
 *
 * @author Albena Roshelova
 */

public class DynDnsManager extends PFComponent {

    private static final long DYNDNS_TIMER_INTERVAL = 1000 * 60 * 5;
    private TimerTask updateTask;
    private Thread updateThread;

    private Hashtable<String, DynDns> dynDnsTable;
    public DynDns activeDynDns;
    public String externalIP;
    private ErrorDialog errorDialog;

    private JDialog uiComponent;

    public DynDnsManager(Controller controller) {
        super(controller);

        registerDynDns("DynDnsOrg", new DynDnsOrg(controller));
        errorDialog = new ErrorDialog(controller, true);
    }

    /*
     * RegisterDynDns methods register the dyndns source
     */
    public void registerDynDns(String dynDnsId, DynDns dynDns) {
        dynDnsTable = new Hashtable<String, DynDns>();
        dynDns.setDynDnsManager(this);
        dynDnsTable.put(dynDnsId, dynDns);
    }

    public String getUsername() {
        if (DynDnsSettingsTab.getUsername() == null) {
            return ConfigurationEntry.DYNDNS_USERNAME.getValue(getController());
        }
        return DynDnsSettingsTab.getUsername();
    }

    public String getUserPassword() {
        if (DynDnsSettingsTab.getPassword() == null) {
            return ConfigurationEntry.DYNDNS_PASSWORD.getValue(getController());
        }
        return DynDnsSettingsTab.getPassword();
    }

    public String getHost2Update() {
        if (DynDnsSettingsTab.getNewDyndns() == null) {
            return ConfigurationEntry.HOSTNAME.getValue(getController());
        }
        return DynDnsSettingsTab.getNewDyndns();
    }

    public boolean isDynDnsSet() {
        return !StringUtils.isBlank(getHost2Update());
    }

    public void fillDefaultUpdateData(DynDnsUpdateData updateData) {
        updateData.username = getUsername();
        updateData.pass = getUserPassword();
        updateData.host = getHost2Update();
        updateData.ipAddress = getIPviaHTTPCheckIP();
    }

    /**
     * Validates given dynDns for compatibility with the current host
     *
     * @param dynDns
     *            to validate
     * @return true if validation succeeded, false otherwise
     */
    public boolean validateDynDns(String dynDns) {

        // validates the dynamic dns entry if there is one entered
        if (StringUtils.isBlank(dynDns)) {
            // just resets the dyndns entry
            if (getController().getConnectionListener() != null) {
                getController().getConnectionListener().setMyDynDns(null, false);
            }
        } else {
            if (getController().hasConnectionListener()) {

                // sets the new dyndns with validation enabled
                int res = getController().getConnectionListener().setMyDynDns(dynDns, true);

                // check the result from validation
                switch (res) {
                case ConnectionListener.VALIDATION_FAILED:

                    // validation failed ask the user if he/she
                    // wants to continue with these settings
                    String message = Translation.getTranslation("exp.preferences.dyn_dns.manager_no_match_text");
                    String title = Translation.getTranslation("exp.preferences.dyn_dns.manager_no_match_title");

                    int result = DialogFactory
                            .genericDialog(getController(), title, message,
                                    new String[] { Translation.getTranslation("general.continue"),
                                            Translation.getTranslation("general.cancel") },
                                    0, GenericDialogType.WARN); // Default is
                    // continue

                    if (result == 0) { // Continue
                        // the user is happy with his/her settings, then
                        // set the new dyndns without further validation
                        getController().getConnectionListener().setMyDynDns(dynDns, false);
                    } else {
                        // the user wants to change the dyndns settings
                        getController().getConnectionListener().setMyDynDns(null, false);
                        return false;
                    }
                    break;
                case ConnectionListener.CANNOT_RESOLVE:
                    // the new dyndns could not be resolved
                    // force the user to enter a new one
                    getController().getConnectionListener().setMyDynDns(null, false);
                    return false;

                case ConnectionListener.OK:
                    logInfo("Successfully validated dyndns '" + dynDns + '\'');
                    // getController().getUIController()
                    // .showMessage(null,
                    // "Success",
                    // Translation.getTranslation("preferences.dialog.statusDynDnsSuccess",
                    // dynDns));
                }
            }

        }
        // all validations have passed
        return true;
    }

    /**
     * Shows warning message to the user in case the validation goes wrong
     *
     * @param type
     *            of validation failure
     * @param arg
     *            additional argument (dyndns)
     */
    public void showWarningMsg(int type, String arg) {
        switch (type) {
        case ConnectionListener.VALIDATION_FAILED:

            DialogFactory.genericDialog(getController(),
                    Translation.getTranslation("exp.preferences.dyn_dns.warning_message"),
                    Translation.getTranslation("exp.preferences.dyn_dns.status_valid_failed", arg),
                    GenericDialogType.WARN);

            break;

        case ConnectionListener.CANNOT_RESOLVE:
            DialogFactory.genericDialog(getController(),
                    Translation.getTranslation("exp.preferences.dyn_dns.warning_message"),
                    Translation.getTranslation("exp.preferences.dyn_dns.status_valid_failed", arg),
                    GenericDialogType.WARN);

        }
    }

    public void showPanelErrorMessage() {
        String err = "";
        if (getHost2Update().length() == 0) {
            err = "hostname";
        } else if (getUsername().length() == 0) {
            err = "username";
        } else if (getUserPassword().length() == 0) {
            err = "password";
        }

        DialogFactory.genericDialog(getController(),
                Translation.getTranslation("exp.preferences.dyn_dns.update_title"),
                Translation.getTranslation("exp.preferences.dyn_dns.update_text", err), GenericDialogType.ERROR);
    }

    /**
     *
     */
    public void showDynDnsUpdaterMsg(int type) {

        switch (type) {
        case ErrorManager.NO_ERROR:

            DialogFactory.genericDialog(getController(),
                    Translation.getTranslation("exp.preferences.dyn_dns.update_title"),

                    activeDynDns.getErrorText(), GenericDialogType.INFO);
            break;

        case ErrorManager.WARN:
        case ErrorManager.ERROR:
            errorDialog.open(activeDynDns.getErrorText(), type);
            break;

        case ErrorManager.UNKNOWN:
            DialogFactory.genericDialog(getController(),
                    Translation.getTranslation("exp.preferences.dyn_dns.update_title"),
                    Translation.getTranslation("exp.preferences.dyn_dns.update_unknown_error"),
                    GenericDialogType.ERROR);
            break;

        }
    }

    /**
     * close the wait message box
     */
    public final void close() {
        logFiner("Close called: " + this);
        if (uiComponent != null) {
            uiComponent.dispose();
            uiComponent = null;
        }
    }

    /**
     * Shows (and builds) the wait message box
     */
    public final void show(String dyndns) {
        logFiner("Open called: " + this);
        getUIComponent(dyndns).setVisible(true);
    }

    /**
     * retrieves the title of the message box
     *
     * @return
     */
    private String getTitle() {
        return Translation.getTranslation("preferences.dialog.title_processing");
    }

    /**
     * saves updated ip to the config file
     *
     * @param updateData
     */
    private void saveUpdatedIP(DynDnsUpdateData updateData) {
        ConfigurationEntry.DYNDNS_LAST_UPDATED_IP.setValue(getController(), updateData.ipAddress);
        // save
        getController().saveConfig();
    }

    /**
     * Setups the UI for the wait message box
     *
     * @param dyndns
     * @return
     */
    protected final JDialog getUIComponent(String dyndns) {
        if (uiComponent == null) {
            logFiner("Building ui component for " + this);
            uiComponent = new JDialog(getController().getUIController().getMainFrame().getUIComponent(),
                    getTitle());
            uiComponent.setResizable(false);

            uiComponent.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

            FormLayout layout = new FormLayout("pref, 14dlu, pref:grow", "pref, pref:grow, 6dlu, pref");
            PanelBuilder builder = new PanelBuilder(layout);
            builder.setBorder(Borders.DLU14_BORDER);

            CellConstraints cc = new CellConstraints();

            // Build
            int xpos = 1;
            int ypos = 1;
            int wpos = 1;
            int hpos = 1;
            builder.add(new JLabel(Translation.getTranslation("exp.preferences.dyn_dns.status_wait", dyndns)),
                    cc.xywh(xpos, ypos, wpos, hpos));

            // Add panel to component
            uiComponent.getContentPane().add(builder.getPanel());

            uiComponent.pack();
            Component parent = uiComponent.getOwner();
            int x = parent.getX() + (parent.getWidth() - uiComponent.getWidth()) / 2;
            int y = parent.getY() + (parent.getHeight() - uiComponent.getHeight()) / 2;
            uiComponent.setLocation(x, y);
        }
        return uiComponent;
    }

    /**
     * Checks if the current dyndns host is still valid (=matches the real ip).
     *
     * @return false, if the dyndns service should be updated.
     */
    private boolean dyndnsValid() {
        String dyndnsIP = getHostIP(ConfigurationEntry.HOSTNAME.getValue(getController()));
        if (StringUtils.isEmpty(dyndnsIP)) {
            return true;
        }

        String myHostIP = getIPviaHTTPCheckIP();
        String lastUpdatedIP = ConfigurationEntry.DYNDNS_LAST_UPDATED_IP.getValue(getController());
        logFine("Dyndns hostname IP: " + dyndnsIP + ". Real IP: " + myHostIP + ". Last update IP: "
                + lastUpdatedIP);
        if (dyndnsIP.equals(myHostIP)) {
            return true;
        }
        // If host did non change...
        return myHostIP.equals(lastUpdatedIP);

    }

    /**
     * Forces an update of the DynDNS service.
     *
     * @return The update result
     */
    private int updateDynDNS() {
        activeDynDns = dynDnsTable.get("DynDnsOrg");
        DynDnsUpdateData updateData = activeDynDns.getDynDnsUpdateData();
        int res = activeDynDns.update(updateData);

        logInfo("Updated dyndns. Result: " + res);
        if (res == ErrorManager.NO_ERROR) {
            saveUpdatedIP(updateData);
        }

        logFiner("the updated dyndns > " + externalIP);
        return res;
    }

    public void forceUpdate() {
        showDynDnsUpdaterMsg(updateDynDNS());
    }

    /**
     * Updates DYNDNS if necessary.
     */
    public synchronized void updateIfNessesary() {
        if (!ConfigurationEntry.DYNDNS_AUTO_UPDATE.getValueBoolean(getController())) {
            return;
        }
        if (updateTask == null) {
            setupUpdateTask();
            logFiner("DNS Autoupdate requested. Starting updater.");
        }

        if (updateThread != null) {
            logFine("No dyndns update performed. Already running");
            return;
        }

        // Perform this by a seperate Thread
        updateThread = new Thread("DynDns Updater") {
            @Override
            public void run() {
                boolean dyndnsIsValid = dyndnsValid();
                logFine("Dyndns updater start. Update required? " + !dyndnsIsValid);
                if (dyndnsIsValid) {
                    logFiner("No dyndns update performed: IP still valid");
                } else {
                    updateDynDNS();
                }
                logFiner("Dyndns updater finished");
                updateThread = null;
            }
        };
        updateThread.start();
    }

    /**
     * Start updating Timer.
     */
    private void setupUpdateTask() {
        if (updateTask != null) {
            updateTask.cancel();
        }
        updateTask = new TimerTask() {
            @Override
            public void run() {
                updateIfNessesary();
            }
        };
        getController().scheduleAndRepeat(updateTask, 0, DYNDNS_TIMER_INTERVAL);
    }

    /**
     * Returns dyndns IP address
     *
     * @param newDns
     */

    public String getHostIP(String host) {

        if (host == null) {
            return "";
        }

        String strDyndnsIP = "";
        try {
            InetAddress myDyndnsIP = InetAddress.getByName(host);
            if (myDyndnsIP != null) {
                strDyndnsIP = myDyndnsIP.getHostAddress();
            }
        } catch (IllegalArgumentException ex) {
            logSevere("Can't get the host ip address" + ex.toString());
        } catch (UnknownHostException ex) {
            logSevere("Can't get the host ip address" + ex.toString());
        }
        return strDyndnsIP;
    }

    /**
     * Returns the internet address of this machine.
     *
     * @return the ip address or empty string if none is found
     */

    public String getIPviaHTTPCheckIP() {

        String ipAddr = "";

        try {
            URL dyndns = new URL("http://checkip.dyndns.org/");
            URLConnection urlConn = dyndns.openConnection();
            int length = urlConn.getContentLength();
            ByteArrayOutputStream tempBuffer;

            if (length < 0) {
                tempBuffer = new ByteArrayOutputStream();
            } else {
                tempBuffer = new ByteArrayOutputStream(length);
            }

            InputStream inStream = urlConn.getInputStream();

            int ch;
            while ((ch = inStream.read()) >= 0) {
                tempBuffer.write(ch);
            }

            String ipText = tempBuffer.toString();
            logFiner("Received '" + ipText + "' from " + dyndns);
            ipAddr = filterIPs(ipText);

        } catch (IOException e) {
        }

        // return the ip address or empty string if none is found
        return ipAddr;
    }

    /**
     * Parse the HTML string and filter everything out but the ip address
     *
     * @param str
     * @return
     */
    private static String filterIPs(String txt) {
        String ip = null;
        Pattern p = Pattern.compile("[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}");
        Matcher m = p.matcher(txt);

        if (m.find()) {
            // ip match is found
            ip = txt.substring(m.start(), m.end());
        }
        return ip;
    }

}