org.globus.workspace.network.defaults.DefaultAssociationAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.globus.workspace.network.defaults.DefaultAssociationAdapter.java

Source

/*
 * Copyright 1999-2008 University of Chicago
 *
 * 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 org.globus.workspace.network.defaults;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.workspace.network.Association;
import org.globus.workspace.network.AssociationAdapter;
import org.globus.workspace.network.AssociationEntry;
import org.globus.workspace.persistence.PersistenceAdapter;
import org.globus.workspace.Lager;
import org.nimbustools.api.services.rm.ResourceRequestDeniedException;
import org.nimbustools.api.services.rm.ManageException;
import org.springframework.core.io.Resource;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class DefaultAssociationAdapter implements AssociationAdapter {

    private static final Log logger = LogFactory.getLog(DefaultAssociationAdapter.class.getName());

    private static final String MAC_MESSAGE = "When choosing MAC addresses to use, ensure you choose a unicast address.\n"
            + "That is, one with the low bit of the first octet set to zero. For example, an\n"
            + "address starting aa: is OK but ab: is not. It is best to keep to the range of\n"
            + "addresses declared to be \"locally assigned\" (rather than allocated globally to\n"
            + "hardware vendors). These have the second lowest bit set to one in the first\n"
            + "octet. For example, aa: is OK, a8: isn't.\n" + "\n"
            + "In summary, an address of the following form should be OK:\n" + "\n" + "XY:XX:XX:XX:XX:XX\n" + "\n"
            + "where X is any hexadecimal digit, and Y is one of 2, 6, A or E";

    private final Object lock = new Object();

    private List allMacs;

    private static final String[] zeroLen = new String[0];

    private final PersistenceAdapter persistence;
    private final Lager lager;

    private Resource networksDir;

    private String macPrefix;
    private String netSampleNetwork;
    private Resource netSampleResource;
    private Resource dhcpdEntriesResource;
    private Resource ipMacResource;

    public DefaultAssociationAdapter(PersistenceAdapter db, Lager lagerImpl) {
        if (db == null) {
            throw new IllegalArgumentException("db may not be null");
        }
        this.persistence = db;

        if (lagerImpl == null) {
            throw new IllegalArgumentException("lagerImpl may not be null");
        }
        this.lager = lagerImpl;
    }

    // -------------------------------------------------------------------------
    // implements AssociationAdapter
    // -------------------------------------------------------------------------

    public String[] getAssociationNames() throws ManageException {

        final Hashtable associations = this.persistence.currentAssociations(false);
        if (associations == null || associations.isEmpty()) {
            return zeroLen;
        } else {
            final Set keys = associations.keySet();
            return (String[]) keys.toArray(new String[keys.size()]);
        }
    }

    public Object[] getNextEntry(String name, int vmid)

            throws ResourceRequestDeniedException {

        if (this.persistence == null) {
            throw new ResourceRequestDeniedException("networking initialization problem");
        }

        synchronized (this.lock) {
            return Util.getNextEntry(name, this.persistence, vmid, this.lager.eventLog);
        }
    }

    public void retireEntry(String name, String ipAddress, int trackingID)

            throws ManageException {

        if (this.persistence == null) {
            throw new ManageException("networking initialization problem");
        }

        synchronized (this.lock) {
            Util.retireEntry(name, ipAddress, this.persistence, trackingID);
        }

    }

    // -------------------------------------------------------------------------
    // IoC INIT METHOD
    // -------------------------------------------------------------------------

    public void validate() throws Exception {

        if (this.macPrefix != null) {
            this.validateMacPrefix();
            logger.info("MAC prefix: \"" + this.macPrefix + "\"");
        }

        if (this.networksDir != null) {

            final File associationDir = this.networksDir.getFile();

            Hashtable previous_associations;
            try {
                previous_associations = this.persistence.currentAssociations(false);
            } catch (ManageException e) {
                logger.error("", e);
                previous_associations = null;
            }

            final Hashtable new_associations = Util.loadDirectory(associationDir, previous_associations);

            if (this.macPrefix != null) {
                long mstart = 0;
                if (logger.isDebugEnabled()) {
                    mstart = System.currentTimeMillis();
                }
                this.allMacs = MacUtil.handleMacs(previous_associations, new_associations, this.macPrefix);
                if (logger.isDebugEnabled()) {
                    final long mstop = System.currentTimeMillis();
                    logger.debug("MAC handling took " + Long.toString(mstop - mstart) + "ms.");
                }
            }

            this.persistence.replaceAssocations(new_associations);

            final Enumeration en = new_associations.keys();
            while (en.hasMoreElements()) {
                final String assocName = (String) en.nextElement();
                final Association assoc = (Association) new_associations.get(assocName);
                int numEntries = 0;
                if (assoc.getEntries() != null) {
                    numEntries = assoc.getEntries().size();
                }

                if (numEntries == 1) {
                    logger.info("Network '" + assocName + "' loaded with one address.");
                } else {
                    logger.info("Network '" + assocName + "' loaded with " + numEntries + " addresses.");
                }
            }

            // we write network info to various files (dhcpd entries, etc)
            this.writeNetworkFiles(new_associations);
        }
    }

    private void writeNetworkFiles(Map<String, Association> associations) {
        if (this.netSampleResource != null) {
            if (this.netSampleNetwork != null && this.netSampleNetwork.length() != 0) {
                final Association assoc = associations.get(this.netSampleNetwork);

                if (assoc == null || assoc.getEntries() == null || assoc.getEntries().isEmpty()) {
                    logger.warn("Not writing netsample file because network '" + this.netSampleNetwork
                            + "' does not exist or has no entries");
                } else {
                    final List entries = assoc.getEntries();
                    final File netsampleFile;
                    try {

                        netsampleFile = this.netSampleResource.getFile();

                        FileUtil.writeNetSample(netsampleFile, (AssociationEntry) entries.get(0),
                                this.netSampleNetwork, assoc.getDns());

                    } catch (IOException e) {
                        logger.warn("Failed to write netsample file to " + this.netSampleResource.getFilename(), e);
                    }
                }
            }
        }

        if (this.dhcpdEntriesResource != null) {
            try {
                final File dhcpdEntriesFile = this.dhcpdEntriesResource.getFile();
                FileUtil.writeDhcpdEntries(dhcpdEntriesFile, associations);
            } catch (IOException e) {
                logger.warn("Failed to write dhcpd entries file to: " + this.dhcpdEntriesResource.getFilename(), e);
            }
        }

        if (this.ipMacResource != null) {
            try {
                final File ipMacFile = this.ipMacResource.getFile();
                FileUtil.writeIpMacPairs(ipMacFile, associations);
            } catch (IOException e) {
                logger.warn("Failed to write IP -> MAC pairs to file: " + this.ipMacResource.getFilename(), e);
            }
        }
    }

    private void validateMacPrefix() {
        if (this.macPrefix.length() > 17) {
            throw new IllegalArgumentException(
                    "MAC prefix is too long, " + " it is " + this.macPrefix.length() + " characters, max is 17");
        }

        if (!MacUtil.isValidMac(this.macPrefix, true)) {
            throw new IllegalArgumentException("MAC prefix has invalid characters or format: " + this.macPrefix);
        }

        final char[] macChars = this.macPrefix.toCharArray();

        if (macChars.length > 1) {
            boolean ok = false;
            switch (macChars[1]) {
            case '2':
                ok = true;
                break;
            case '6':
                ok = true;
                break;
            case 'A':
                ok = true;
                break;
            case 'E':
                ok = true;
                break;
            }

            if (!ok) {
                final String choice = "\n\nYou're seeing this message" + " because you chose '" + macChars[1]
                        + "' as the second character in MAC prefix \"" + this.macPrefix + "\"\n";
                throw new IllegalArgumentException(MAC_MESSAGE + choice);
            }
        }
    }

    public String newMAC() throws ResourceRequestDeniedException {
        if (this.macPrefix == null || this.allMacs == null) {
            return null;
        } else {
            return MacUtil.pickNew(this.allMacs, this.macPrefix);
        }
    }

    public void setNetworksDir(Resource dir) {
        this.networksDir = dir;
    }

    public void setMacPrefix(String prefix) {
        if (prefix == null || prefix.trim().length() == 0) {
            this.macPrefix = null;
        } else {
            this.macPrefix = prefix.toUpperCase();
        }
    }

    public void setNetSampleResource(Resource netSampleResource) {
        this.netSampleResource = netSampleResource;
    }

    public Resource getNetSampleResource() {
        return netSampleResource;
    }

    public void setDhcpdEntriesResource(Resource dhcpdEntriesResource) {
        this.dhcpdEntriesResource = dhcpdEntriesResource;
    }

    public Resource getDhcpdEntriesResource() {
        return dhcpdEntriesResource;
    }

    public void setIpMacResource(Resource ipMacResource) {
        this.ipMacResource = ipMacResource;
    }

    public Resource getIpMacResource() {
        return ipMacResource;
    }

    public String getNetSampleNetwork() {
        return netSampleNetwork;
    }

    public void setNetSampleNetwork(String netSampleNetwork) {
        this.netSampleNetwork = netSampleNetwork;
    }
}