Package org.jscsi.target

Source Code of org.jscsi.target.Configuration

package org.jscsi.target;


import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.jscsi.target.scsi.lun.LogicalUnitNumber;
import org.jscsi.target.settings.TextKeyword;
import org.jscsi.target.storage.IStorageModule;
import org.jscsi.target.storage.JCloudsStorageModule;
import org.jscsi.target.storage.RandomAccessStorageModule;
import org.jscsi.target.storage.SynchronizedRandomAccessStorageModule;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;


/**
* Instances of {@link Configuration} provides access target-wide parameters, variables that are the same across all
* sessions and connections that do not change after initialization and which play a role during text parameter
* negotiation. Some of these parameters are provided or can be overridden by the content of an XML file -
* <code>jscsi-target.xml</code>.
*
* @author Andreas Ergenzinger, University of Konstanz
*/
public class Configuration {

    public static final String ELEMENT_TARGET_LIST = "TargetList"; // Name of
                                                                   // node that
                                                                   // contains
                                                                   // list of
    // targets

    public static final String ELEMENT_TARGET = "Target"; // Name for nodes
                                                          // that contain a
                                                          // target
    // Target configuration elements
    public static final String ELEMENT_SYNCFILESTORAGE = "SyncFileStorage";
    public static final String ELEMENT_ASYNCFILESTORAGE = "AsyncFileStorage";
    public static final String ELEMENT_JCLOUDSSTORAGE = "JCloudsStorage";
    public static final String ELEMENT_FILESTORAGE = "FileStorage";
    public static final String ELEMENT_CREATE = "Create";
    public static final String ATTRIBUTE_SIZE = "size";

    // Global configuration elements
    public static final String ELEMENT_ALLOWSLOPPYNEGOTIATION = "AllowSloppyNegotiation";
    public static final String ELEMENT_PORT = "Port";

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    /**
     * The relative path (to the project) of the main directory of all configuration files.
     */
    private static final File CONFIG_DIR = new File(new StringBuilder("src").append(File.separator).append("main").append(File.separator).append("resources").append(File.separator).toString());

    /**
     * The file name of the XML Schema configuration file for the global settings.
     */
    public static final File CONFIGURATION_SCHEMA_FILE = new File(CONFIG_DIR, "jscsi-target.xsd");

    /** The file name, which contains all global settings. */
    public static final File CONFIGURATION_CONFIG_FILE = new File(CONFIG_DIR, "jscsi-target.xml");

    // --------------------------------------------------------------------------
    // --------------------------------------------------------------------------

    protected final List<Target> targets;

    /**
     * The <code>TargetAddress</code> parameter (the jSCSI Target's IP address).
     * <p>
     * This parameter is initialized automatically.
     */
    protected String targetAddress;

    /**
     * The port used by the jSCSI Target for listening for new connections.
     * <p>
     * The default port number is 3260. This value may be overridden by specifying a different value in the
     * configuration file.
     */
    protected int port;

    /**
     * This variable toggles the strictness with which the parameters <code>IFMarkInt</code> and <code>OFMarkInt</code>
     * are processed, when provided by the initiator. Usually the offered values must have to following format:
     * <code>smallInteger~largeInteger</code>, however the jSCSI Initiator sends only single integers as <i>value</i>
     * part of the <i>key-value</i> pairs. Since the value of these two parameters always are <code>Irrelevant</code>,
     * this bug can be ignored without any negative consequences by setting {@link #allowSloppyNegotiation} to
     * <code>true</code> in the configuration file. The default is <code>false</code>.
     */
    protected boolean allowSloppyNegotiation;// TODO fix in jSCSI Initiator and
                                             // remove

    /**
     * The <code>TargetPortalGroupTag</code> parameter.
     */
    protected final int targetPortalGroupTag = 1;

    /**
     * The Logical Unit Number of the virtual Logical Unit.
     */
    protected final LogicalUnitNumber logicalUnitNumber = new LogicalUnitNumber(0L);

    /**
     * The <code>MaxRecvDataSegmentLength</code> parameter for PDUs sent in the out direction (i.e. initiator to
     * target).
     * <p>
     * Since the value of this variable is equal to the specified default value, it does not have to be declared during
     * login.
     */
    protected final int outMaxRecvDataSegmentLength = 8192;

    /**
     * The maximum number of consecutive Login PDUs or Text Negotiation PDUs the target will accept in a single
     * sequence.
     * <p>
     * The iSCSI standard does not dictate a minimum or maximum text PDU sequence length, but only suggests to select a
     * value large enough for all expected key-value pairs that might be sent in a single sequence. A limit should be
     * imposed, however, to prevent {@link OutOfMemoryError}s resulting from malicious or accidental text PDU sequences
     * of extreme lengths.
     * <p>
     * Since all common text parameters (plus values) easily fit into a single text PDU with the default data segment
     * size, this value could be set to <code>1</code> without negatively affecting compatibility with most initiators.
     */
    private final int maxRecvTextPduSequenceLength = 4;

    public Configuration (final String pTargetAddress) throws IOException {
        port = 3260;

        if (pTargetAddress.equals("")) {
            targetAddress = InetAddress.getLocalHost().getHostAddress();

        } else {
            targetAddress = pTargetAddress;
        }

        targets = new ArrayList<Target>();
    }

    public int getInMaxRecvTextPduSequenceLength () {
        return maxRecvTextPduSequenceLength;
    }

    public int getOutMaxRecvDataSegmentLength () {
        return outMaxRecvDataSegmentLength;
    }

    public String getTargetAddress () {
        return targetAddress;
    }

    public int getPort () {
        return port;
    }

    public boolean getAllowSloppyNegotiation () {
        return allowSloppyNegotiation;
    }

    public int getTargetPortalGroupTag () {
        return targetPortalGroupTag;
    }

    public LogicalUnitNumber getLogicalUnitNumber () {
        return logicalUnitNumber;
    }

    public List<Target> getTargets () {
        return targets;
    }

    public static Configuration create (final String pTargetAddress) throws SAXException , ParserConfigurationException , IOException {
        return create(CONFIGURATION_SCHEMA_FILE, CONFIGURATION_CONFIG_FILE, pTargetAddress);
    }

    /**
     * Reads the given configuration file in memory and creates a DOM representation.
     *
     * @throws SAXException If this operation is supported but failed for some reason.
     * @throws ParserConfigurationException If a {@link DocumentBuilder} cannot be created which satisfies the
     *             configuration requested.
     * @throws IOException If any IO errors occur.
     */
    public static Configuration create (final File schemaLocation, final File configFile, final String pTargetAddress) throws SAXException , ParserConfigurationException , IOException {
        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Schema schema = schemaFactory.newSchema(schemaLocation);

        // create a validator for the document
        final Validator validator = schema.newValidator();

        final DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true); // never forget this
        final DocumentBuilder builder = domFactory.newDocumentBuilder();
        final Document doc = builder.parse(configFile);

        final DOMSource source = new DOMSource(doc);
        final DOMResult result = new DOMResult();

        validator.validate(source, result);
        Document root = (Document) result.getNode();

        // TargetName
        Configuration returnConfiguration = new Configuration(pTargetAddress);
        Element targetListNode = (Element) root.getElementsByTagName(ELEMENT_TARGET_LIST).item(0);
        NodeList targetList = targetListNode.getElementsByTagName(ELEMENT_TARGET);
        for (int curTargetNum = 0; curTargetNum < targetList.getLength(); curTargetNum++) {
            Target curTargetInfo = parseTargetElement((Element) targetList.item(curTargetNum));
            synchronized (returnConfiguration.targets) {
                returnConfiguration.targets.add(curTargetInfo);
            }

        }

        // else it is null

        // port
        if (root.getElementsByTagName(ELEMENT_PORT).getLength() > 0)
            returnConfiguration.port = Integer.parseInt(root.getElementsByTagName(ELEMENT_PORT).item(0).getTextContent());
        else
            returnConfiguration.port = 3260;

        // support sloppy text parameter negotiation (i.e. the jSCSI Initiator)?
        final Node allowSloppyNegotiationNode = root.getElementsByTagName(ELEMENT_ALLOWSLOPPYNEGOTIATION).item(0);
        if (allowSloppyNegotiationNode == null)
            returnConfiguration.allowSloppyNegotiation = false;
        else
            returnConfiguration.allowSloppyNegotiation = Boolean.parseBoolean(allowSloppyNegotiationNode.getTextContent());

        return returnConfiguration;

    }

    protected static Target parseTargetElement (Element targetElement) throws IOException {
        // TargetName
        // TargetName
        Node nextNode = chopWhiteSpaces(targetElement.getFirstChild());
        // assert
        // nextNode.getLocalName().equals(OperationalTextKey.TARGET_NAME);
        String targetName = nextNode.getTextContent();

        // TargetAlias (optional)
        nextNode = chopWhiteSpaces(nextNode.getNextSibling());
        String targetAlias = "";
        if (nextNode.getLocalName().equals(TextKeyword.TARGET_ALIAS)) {
            targetAlias = nextNode.getTextContent();
            nextNode = chopWhiteSpaces(nextNode.getNextSibling());
        }

        // Finding out the concrete storage
        Class<? extends IStorageModule> kind = null;
        switch (nextNode.getLocalName()) {
            case ELEMENT_SYNCFILESTORAGE :
                kind = SynchronizedRandomAccessStorageModule.class;
                break;
            case ELEMENT_ASYNCFILESTORAGE :
                kind = RandomAccessStorageModule.class;
                break;
            case ELEMENT_JCLOUDSSTORAGE :
                kind = JCloudsStorageModule.class;
                break;
        }

        // Getting storagepath
        nextNode = nextNode.getFirstChild();
        nextNode = chopWhiteSpaces(nextNode);
        // assert nextNode.getLocalName().equals(ELEMENT_PATH);
        String storageFilePath = nextNode.getTextContent();

        // CreateNode with size
        nextNode = chopWhiteSpaces(nextNode.getNextSibling());
        long storageLength = -1;
        boolean create = true;
        if (nextNode.getLocalName().equals(ELEMENT_CREATE)) {
            Node sizeAttribute = nextNode.getAttributes().getNamedItem(ATTRIBUTE_SIZE);
            storageLength = Math.round(((Double.valueOf(sizeAttribute.getTextContent())) * Math.pow(1024, 3)));
        } else {
            storageLength = new File(storageFilePath).length();
            create = false;
            // assert nextNode.getLocalName().equals(ELEMENT_DONTCREATE);
        }
        final IStorageModule module = RandomAccessStorageModule.open(new File(storageFilePath), storageLength, create, kind);

        return new Target(targetName, targetAlias, module);

    }

    protected static Node chopWhiteSpaces (final Node node) {
        Node toIterate = node;
        while (toIterate instanceof Text && toIterate.getTextContent().trim().length() == 0) {
            toIterate = toIterate.getNextSibling();
        }
        return toIterate;
    }

}
TOP

Related Classes of org.jscsi.target.Configuration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.