Package fiftyone.mobile.detection

Source Code of fiftyone.mobile.detection.Dataset

package fiftyone.mobile.detection;

import java.io.IOException;
import java.util.Calendar;
import java.util.Date;

import fiftyone.mobile.detection.entities.AsciiString;
import fiftyone.mobile.detection.entities.Component;
import fiftyone.mobile.detection.entities.Guid;
import fiftyone.mobile.detection.entities.Map;
import fiftyone.mobile.detection.entities.Node;
import fiftyone.mobile.detection.entities.Profile;
import fiftyone.mobile.detection.entities.ProfileOffset;
import fiftyone.mobile.detection.entities.RankedSignatureIndex;
import fiftyone.mobile.detection.entities.Property;
import fiftyone.mobile.detection.entities.Signature;
import fiftyone.mobile.detection.entities.Value;
import fiftyone.mobile.detection.entities.Version;
import fiftyone.mobile.detection.entities.stream.ICacheList;
import fiftyone.mobile.detection.readers.BinaryReader;
import fiftyone.properties.DetectionConstants;

/* *********************************************************************
* This Source Code Form is copyright of 51Degrees Mobile Experts Limited.
* Copyright 2014 51Degrees Mobile Experts Limited, 5 Charlotte Close,
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY
*
* This Source Code Form is the subject of the following patent
* applications, owned by 51Degrees Mobile Experts Limited of 5 Charlotte
* Close, Caversham, Reading, Berkshire, United Kingdom RG4 7BY:
* European Patent Application No. 13192291.6; and
* United States Patent Application Nos. 14/085,223 and 14/085,301.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0.
*
* If a copy of the MPL was not distributed with this file, You can obtain
* one at http://mozilla.org/MPL/2.0/.
*
* This Source Code Form is "Incompatible With Secondary Licenses", as
* defined by the Mozilla Public License, v. 2.0.
* ********************************************************************* */
/**
* Data set used for device detection created by the reader classes. <p> The
* Memory.Reader and Stream.Reader factories should be used to create detector
* data sets. They can not be constructed directly from external code. <p> All
* information about the detector data set is exposed in this class including
* meta data and data used for device detection in the form of lists. <p>
* Detector data sets created using the <see cref="Stream.Reader"/> factory
* using a file must be disposed of to ensure any readers associated with the
* file are closed elegantly. <p> For more information see
* http://51degrees.mobi/Support/Documentation/Java
*/
public class Dataset implements Disposable {

    /**
     * The percentage of requests for signatures which were not already
     * contained in the cache. <p> A value is only returned when operating in
     * Stream mode.
     */
    public double getPercentageSignatureCacheMisses() {
        if (signatures instanceof ICacheList) {
            return ((ICacheList) signatures).getPercentageMisses();
        }
        return 0;
    }

    /**
     * The percentage of requests for nodes which were not already contained in
     * the cache. <p> A value is only returned when operating in Stream mode.
     */
    public double getPercentageNodeCacheMisses() {
        if (nodes instanceof ICacheList) {
            return ((ICacheList) nodes).getPercentageMisses();
        }
        return 0;
    }

    /**
     * The percentage of requests for strings which were not already contained
     * in the cache. <p> A value is only returned when operating in Stream mode.
     */
    public double getPercentageStringsCacheMisses() {
        if (strings instanceof ICacheList) {
            return ((ICacheList) strings).getPercentageMisses();
        }
        return 0;
    }

    /**
     * The percentage of requests for profiles which were not already contained
     * in the cache. <p> A value is only returned when operating in Stream mode.
     */
    public double getPercentageProfilesCacheMisses() {
        if (profiles instanceof ICacheList) {
            return ((ICacheList) profiles).getPercentageMisses();
        }
        return 0;
    }

    /**
     * The percentage of requests for values which were not already contained in
     * the cache. <p> A value is only returned when operating in Stream mode.
     */
    public double getPercentageValuesCacheMisses() {
        if (values instanceof ICacheList) {
            return ((ICacheList) values).getPercentageMisses();
        }
        return 0;
    }

    /**
     * Indicates if the data set has been disposed.
     */
    public boolean getDisposed() {
        return disposed;
    }
    private boolean disposed = false;
    /**
     * The date the data set was published.
     */
    public final Date published;
    /**
     * The date the data set is next expected to be updated by 51Degrees.
     */
    public final Date nextUpdate;
    /**
     * The minimum number of times a user agent should have been seen before it
     * was included in the dataset.
     */
    public final int minUserAgentCount;
    /**
     * The version of the data set.
     */
    public final Version version;
    /**
     * The maximum length of a user agent string.
     */
    public final short maxUserAgentLength;
    /**
     * The minimum length of a user agent string.
     */
    private final short minUserAgentLength;
    /**
     * The lowest character the character trees can contain.
     */
    public final byte lowestCharacter;
    /**
     * The highest character the character trees can contain.
     */
    public final byte highestCharacter;
    /**
     * The number of unique device combinations available in the data set.
     */
    public final int deviceCombinations;
    /**
     * The maximum number of signatures that can be checked. Needed to avoid
     * bogus user agents which deliberately require so many signatures to be
     * checked that performance is degraded.
     */
    public final int maxSignatures;
    /**
     * The maximum number of values that can be returned by a profile and a
     * property supporting a list of values.
     */
    public final short maxValues;
    /**
     * The number of bytes to allocate to a buffer returning CSV format data for
     * a match.
     */
    public final int csvBufferLength;
    /**
     * The number of bytes to allocate to a buffer returning JSON format data
     * for a match.
     */
    public final int jsonBufferLength;
    /**
     * The number of bytes to allocate to a buffer returning XML format data for
     * a match.
     */
    public final int xmlBufferLength;
    /**
     * The maximum number of signatures that could possibly be returned during a
     * closest match.
     */
    public final int maxSignaturesClosest;
    public final Guid guid;
    /**
     * Age of the data in months when exported.
     */
    public final int age;

    /**
     * The hardware component.
     *
     * @throws IOException
     */
    public Component getHardware() throws IOException {
        if (hardware == null) {
            synchronized (this) {
                if (hardware == null) {
                    hardware = getComponent("HardwarePlatform");
                }
            }
        }
        return hardware;
    }
    private Component hardware;

    /**
     * The software component.
     *
     * @throws IOException
     */
    public Component getSoftware() throws IOException {
        if (software == null) {
            synchronized (this) {
                if (software == null) {
                    software = getComponent("SoftwarePlatform");
                }
            }
        }
        return software;
    }
    private Component software;

    /**
     * The browser component.
     *
     * @throws IOException
     */
    public Component getBrowsers() throws IOException {
        if (browsers == null) {
            synchronized (this) {
                if (browsers == null) {
                    browsers = getComponent("BrowserUA");
                }
            }
        }
        return browsers;
    }
    private Component browsers;

    /**
     * The crawler component.
     *
     * @throws IOException
     */
    public Component getCrawlers() throws IOException {
        if (crawlers == null) {
            synchronized (this) {
                if (crawlers == null) {
                    crawlers = getComponent("Crawler");
                }
            }
        }
        return crawlers;
    }
    private Component crawlers;

    /**
     * The copyright notice associated with the data set.
     *
     * @throws IOException
     */
    public String getCopyright() throws IOException {
        if (copyright == null) {
            synchronized (this) {
                if (copyright == null) {
                    copyright = strings.get(copyrightOffset).toString();
                }
            }
        }
        return copyright;
    }
    protected String copyright;
    protected final int copyrightOffset;

    /**
     * The common name of the data set.
     *
     * @throws IOException
     */
    public String getName() throws IOException {
        if (name == null) {
            synchronized (this) {
                if (name == null) {
                    name = strings.get(nameOffset).toString();
                }
            }
        }
        return name;
    }
    protected final int nameOffset;
    private String name;

    /**
     * The name of the property map used to create the dataset.
     *
     * @throws IOException
     */
    public String getFormat() throws IOException {
        if (format == null) {
            synchronized (this) {
                if (format == null) {
                    format = strings.get(formatOffset).toString();
                }
            }
        }
        return format;
    }
    protected final int formatOffset;
    protected String format;

    /**
     * A list of all the components the data set contains.
     */
    public ReadonlyList<Component> getComponents() {
        return components;
    }
    public ReadonlyList<Component> components;

    /**
     * A list of all property maps the data set contains.
     */
    public ReadonlyList<Map> getMaps() {
        return maps;
    }
    public ReadonlyList<Map> maps;

    /**
     * A list of all properties the data set contains.
     */
    public ReadonlyList<Property> getProperties() {
        return properties;
    }
    public ReadonlyList<Property> properties;

    /**
     * A list of all property values the data set contains.
     */
    public ReadonlyList<Value> getValues() {
        return values;
    }
    public ReadonlyList<Value> values;

    /**
     * List of signatures the data set contains.
     */
    public ReadonlyList<Signature> getSignatures() {
        return signatures;
    }
    /**
     * A list of all the signatures the data set contains.
     */
    public ReadonlyList<Signature> signatures;
    /**
     * A list of signature indexes ordered in ascending order of rank. Used by
     * the node ranked signature indexes lists to identify the corresponding
     * signature.
     */
    public ReadonlyList<RankedSignatureIndex> rankedSignatureIndexes;
    /**
     * A list of all the possible profiles the data set contains.
     */
    public ReadonlyList<Profile> profiles;
    /**
     * List of nodes the data set contains.
     */
    public ReadonlyList<Node> nodes;
    /**
     * Nodes for each of the possible character positions in the user agent.
     */
    public ReadonlyList<Node> rootNodes;
    /**
     * List of profile offsets the data set contains.
     */
    public ReadonlyList<ProfileOffset> profileOffsets;
    /**
     * A list of ASCII byte arrays for strings used by the dataset.
     */
    public ReadonlyList<AsciiString> strings;
    private int signatureProfilesCount;
    private int signatureNodesCount;

    /**
     * Constructs a new data set ready to have lists of data assigned to it.
     *
     * @param reader Reader connected to the source data structure and
     * positioned to start reading
     */
    public Dataset(BinaryReader reader) throws IOException {
        // Read the detection data set headers.
        version = new Version(reader.readInt32(), reader.readInt32(),
                reader.readInt32(), reader.readInt32());

        // Throw exception if the data file does not have the correct
        // version in formation.
        if (version.major != DetectionConstants.FormatVersion.major
                || version.minor != DetectionConstants.FormatVersion.minor) {
            throw new IOException(String.format(
                    "Version mismatch. Data is version '%s' for '%s' reader",
                    version,
                    DetectionConstants.FormatVersion));
        }

        guid = new Guid(reader.readBytes(16));
        copyrightOffset = reader.readInt32();
        age = reader.readInt16();
        minUserAgentCount = reader.readInt32();
        nameOffset = reader.readInt32();
        formatOffset = reader.readInt32();
        published = readDate(reader);
        nextUpdate = readDate(reader);
        deviceCombinations = reader.readInt32();
        maxUserAgentLength = reader.readInt16();
        minUserAgentLength = reader.readInt16();
        lowestCharacter = reader.readByte();
        highestCharacter = reader.readByte();
        maxSignatures = reader.readInt32();
        signatureProfilesCount = reader.readInt32();
        signatureNodesCount = reader.readInt32();
        maxValues = reader.readInt16();
        csvBufferLength = reader.readInt32();
        jsonBufferLength = reader.readInt32();
        xmlBufferLength = reader.readInt32();
        maxSignaturesClosest = reader.readInt32();

        nodes = null;
    }

    /**
     * Reads a date in year, month and day order from the reader.
     *
     * @param reader Reader positioned at the start of the date
     * @return A date time with the year, month and day set from the reader
     */
    private static Date readDate(BinaryReader reader) {
        int year = reader.readInt16();
        int month = reader.readByte() - 1;
        int day = reader.readByte();
        Calendar cal = Calendar.getInstance();
        cal.clear();
        cal.set(year, month, day);
        return cal.getTime();
    }

    /**
     * List of nodes the data set contains.
     */
    public ReadonlyList<Node> getNodes() {
        return nodes;
    }

    /**
     * A list of all the possible profiles the data set contains.
     */
    public ReadonlyList<Profile> getProfiles() {
        return profiles;
    }

    public short getMinUserAgentLength() {
        return minUserAgentLength;
    }

    /**
     * Called after the entire data set has been loaded to ensure any further
     * initialisation steps that require other items in the data set can be
     * completed.
     *
     * @throws IOException
     */
    public void init() throws IOException {

        // Set the string values of the data set.
        name = strings.get(nameOffset).toString();
        format = strings.get(formatOffset).toString();
        copyright = strings.get(copyrightOffset).toString();

        // Initialise any objects that can be pre referenced to speed up
        // initial matching.
        for (Signature signature : signatures) {
            signature.init();
        }
        for (Node node : nodes) {
            node.init();
        }
        for (Profile profile : profiles) {
            profile.init();
        }
        for (Component component : getComponents()) {
            component.init();
        }
        for (Property property : getProperties()) {
            property.init();
        }
        for (Value value : values) {
            value.init();
        }

        // We no longer need the strings data structure as all dependent
        // data has been taken from it.
        strings.dispose();
        strings = null;

        // The list of profiles is no longer needed as they've been assigned
        // components and signatures.
        profiles.dispose();
        profiles = null;
    }

    /**
     * Returns the Component associated with the name provided.
     *
     * @param componentName
     * @return The component matching the name, or null if no component is found
     * @throws IOException
     *
     */
    public Component getComponent(String componentName) throws IOException {
        for (Component component : components) {
            if (componentName.equals(component.getName())) {
                return component;
            }
        }
        return null;
    }

    public Property get(String propertyName) throws IOException {
        for (Property property : properties) {
            if (propertyName.equals(property.getName())) {
                return property;
            }
        }
        return null;
    }

    public int getProfilesCount() {
        return signatureProfilesCount;
    }

    public int getNodesCount() {
        return signatureNodesCount;
    }

    /**
     * Searches the list of profile Ids and returns the profile if the profile
     * id is valid.
     *
     * @param profileId Id of the profile to be found
     * @return Profile related to the id, or null if none found
     * @throws IOException
     */
    public Profile findProfile(int profileId) throws IOException {
        int lower = 0;
        int upper = profileOffsets.size() - 1;

        while (lower <= upper) {
            int middle = lower + (upper - lower) / 2;
            int comparisonResult = profileOffsets.get(middle).getProfileId() - profileId;
            if (comparisonResult == 0) {
                return profiles.get(profileOffsets.get(middle).getOffset());
            } else if (comparisonResult > 0) {
                upper = middle - 1;
            } else {
                lower = middle + 1;
            }
        }

        return null;
    }

    @Override
    public void dispose() {
        disposed = true;
        if (strings != null) {
            strings.dispose();
        }
        if (components != null) {
            components.dispose();
        }
        if (properties != null) {
            properties.dispose();
        }
        if (values != null) {
            values.dispose();
        }
        if (signatures != null) {
            signatures.dispose();
        }
        if (profiles != null) {
            profiles.dispose();
        }
        if (nodes != null) {
            nodes.dispose();
        }
        if (rootNodes != null) {
            rootNodes.dispose();
        }
    }
}
TOP

Related Classes of fiftyone.mobile.detection.Dataset

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.