Package net.sf.uadetector.parser

Source Code of net.sf.uadetector.parser.AbstractUserAgentStringParser

/*******************************************************************************
* Copyright 2012 André Rouél
*
* 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 net.sf.uadetector.parser;

import java.util.Map.Entry;
import java.util.regex.Matcher;

import javax.annotation.Nonnull;

import net.sf.uadetector.DeviceCategory;
import net.sf.uadetector.ReadableDeviceCategory.Category;
import net.sf.uadetector.UserAgent;
import net.sf.uadetector.UserAgentStringParser;
import net.sf.uadetector.UserAgentType;
import net.sf.uadetector.VersionNumber;
import net.sf.uadetector.datastore.DataStore;
import net.sf.uadetector.internal.data.Data;
import net.sf.uadetector.internal.data.domain.Browser;
import net.sf.uadetector.internal.data.domain.BrowserPattern;
import net.sf.uadetector.internal.data.domain.Device;
import net.sf.uadetector.internal.data.domain.DevicePattern;
import net.sf.uadetector.internal.data.domain.OperatingSystem;
import net.sf.uadetector.internal.data.domain.OperatingSystemPattern;
import net.sf.uadetector.internal.data.domain.Robot;

public abstract class AbstractUserAgentStringParser implements UserAgentStringParser {

  /**
   * The number of capturing groups if nothing matches
   */
  private static final int ZERO_MATCHING_GROUPS = 0;

  /**
   * Examines the user agent string whether it is a browser.
   *
   * @param userAgent
   *            String of an user agent
   * @param builder
   *            Builder for an user agent information
   */
  private static void examineAsBrowser(final UserAgent.Builder builder, final Data data) {
    Matcher matcher;
    VersionNumber version = VersionNumber.UNKNOWN;
    for (final Entry<BrowserPattern, Browser> entry : data.getPatternToBrowserMap().entrySet()) {
      matcher = entry.getKey().getPattern().matcher(builder.getUserAgentString());
      if (matcher.find()) {

        entry.getValue().copyTo(builder);

        // try to get the browser version from the first subgroup
        if (matcher.groupCount() > ZERO_MATCHING_GROUPS) {
          version = VersionNumber.parseVersion(matcher.group(1) != null ? matcher.group(1) : "");
        }
        builder.setVersionNumber(version);

        break;
      }
    }
  }

  /**
   * Examines the user agent string whether it is a robot.
   *
   * @param userAgent
   *            String of an user agent
   * @param builder
   *            Builder for an user agent information
   * @return {@code true} if it is a robot, otherwise {@code false}
   */
  private static boolean examineAsRobot(final UserAgent.Builder builder, final Data data) {
    boolean isRobot = false;
    VersionNumber version;
    for (final Robot robot : data.getRobots()) {
      if (robot.getUserAgentString().equals(builder.getUserAgentString())) {
        isRobot = true;
        robot.copyTo(builder);

        // try to get the version from the last found group
        version = VersionNumber.parseLastVersionNumber(robot.getName());
        builder.setVersionNumber(version);

        break;
      }
    }
    return isRobot;
  }

  /**
   * Examines the user agent string whether has a specific device category.
   *
   * @param userAgent
   *            String of an user agent
   * @param builder
   *            Builder for an user agent information
   */
  private static void examineDeviceCategory(final UserAgent.Builder builder, final Data data) {

    // a robot will be classified as 'Other'
    if (UserAgentType.ROBOT == builder.getType()) {
      final DeviceCategory category = findDeviceCategoryByValue(Category.OTHER, data);
      builder.setDeviceCategory(category);
      return;
    }

    // classification depends on matching order
    for (final Entry<DevicePattern, Device> entry : data.getPatternToDeviceMap().entrySet()) {
      final Matcher matcher = entry.getKey().getPattern().matcher(builder.getUserAgentString());
      if (matcher.find()) {
        final Category category = Category.evaluate(entry.getValue().getName());
        final DeviceCategory deviceCategory = findDeviceCategoryByValue(category, data);
        builder.setDeviceCategory(deviceCategory);
        return;
      }
    }

    // an unknown user agent type should lead to an unknown device
    if (UserAgentType.UNKNOWN == builder.getType()) {
      builder.setDeviceCategory(DeviceCategory.EMPTY);
      return;
    }

    // if no pattern is available but the type is Other, Library, Validator or UA Anonymizer
    // than classify it as 'Other'
    if (UserAgentType.OTHER == builder.getType() || UserAgentType.LIBRARY == builder.getType()
        || UserAgentType.VALIDATOR == builder.getType() || UserAgentType.USERAGENT_ANONYMIZER == builder.getType()) {
      final DeviceCategory category = findDeviceCategoryByValue(Category.OTHER, data);
      builder.setDeviceCategory(category);
      return;
    }

    // if no pattern is available but the type is a mobile or WAP browser than classify it as 'Smartphone'
    if (UserAgentType.MOBILE_BROWSER == builder.getType() || UserAgentType.WAP_BROWSER == builder.getType()) {
      final DeviceCategory category = findDeviceCategoryByValue(Category.SMARTPHONE, data);
      builder.setDeviceCategory(category);
      return;
    }

    final DeviceCategory category = findDeviceCategoryByValue(Category.PERSONAL_COMPUTER, data);
    builder.setDeviceCategory(category);
  }

  /**
   * Examines the operating system of the user agent string, if not available.
   *
   * @param userAgent
   *            String of an user agent
   * @param builder
   *            Builder for an user agent information
   */
  private static void examineOperatingSystem(final UserAgent.Builder builder, final Data data) {
    if (net.sf.uadetector.OperatingSystem.EMPTY.equals(builder.getOperatingSystem())) {
      for (final Entry<OperatingSystemPattern, OperatingSystem> entry : data.getPatternToOperatingSystemMap().entrySet()) {
        final Matcher matcher = entry.getKey().getPattern().matcher(builder.getUserAgentString());
        if (matcher.find()) {
          entry.getValue().copyTo(builder);
          break;
        }
      }
    }
  }

  private static DeviceCategory findDeviceCategoryByValue(@Nonnull final Category category, @Nonnull final Data data) {
    for (final Device device : data.getDevices()) {
      if (category == device.getCategory()) {
        return new DeviceCategory(category, device.getIcon(), device.getInfoUrl(), device.getName());
      }
    }
    return DeviceCategory.EMPTY;
  }

  /**
   * Gets the data store of this parser.
   *
   * @return data store of this parser
   */
  protected abstract DataStore getDataStore();

  @Override
  public String getDataVersion() {
    return getDataStore().getData().getVersion();
  }

  @Override
  public UserAgent parse(final String userAgent) {
    final UserAgent.Builder builder = new UserAgent.Builder(userAgent);

    // work during the analysis always with the same reference of data
    final Data data = getDataStore().getData();

    if (!examineAsRobot(builder, data)) {
      examineAsBrowser(builder, data);
      examineOperatingSystem(builder, data);
    }
    examineDeviceCategory(builder, data);
    return builder.build();
  }

  @Override
  public void shutdown() {
    // nothing to shutdown
  }

}
TOP

Related Classes of net.sf.uadetector.parser.AbstractUserAgentStringParser

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.