diff --git a/README.md b/README.md index 332cff6..d352d09 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ import ua_parser.Client; System.out.println(c.os.minor); // => "1" System.out.println(c.device.family); // => "iPhone" + System.out.println(c.device.brand); // => "Apple" + System.out.println(c.device.model); // => "iPhone" ``` ## Publish to Sonatype OSSRH and Maven Central Repository diff --git a/pom.xml b/pom.xml index 9c083f5..ea02d8a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,6 @@ jar 1.4.1-SNAPSHOT User Agent Parser for Java - Java implementation of the UA Parser library. Derives operating system, browser and device metadata from a user-agent string. This library consumes the regular expression @@ -93,9 +92,31 @@ 1.7 + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + + true + + + + maven-assembly-plugin + + + + com.allen.capturewebdata.Main + + + + jar-with-dependencies + + + - + + ossrh @@ -118,7 +139,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.0 + 3.0.1 attach-javadocs diff --git a/src/main/java/ua_parser/Device.java b/src/main/java/ua_parser/Device.java index 81c37cb..648d9fe 100644 --- a/src/main/java/ua_parser/Device.java +++ b/src/main/java/ua_parser/Device.java @@ -25,32 +25,42 @@ */ public class Device { public final String family; + public final String brand; + public final String model; - public Device(String family) { - this.family = family; - } + public Device(String family, String brand, String model) { + this.family = family; + this.brand = brand; + this.model = model; + } public static Device fromMap(Map m) { - return new Device((String) m.get("family")); + return new Device(m.get("family"), m.get("brand"), m.get("model")); } @Override public boolean equals(Object other) { - if (other == this) return true; if (!(other instanceof Device)) return false; Device o = (Device) other; - return (this.family != null && this.family.equals(o.family)) || this.family == o.family; + return (((this.family != null && this.family.equals(o.family)) || this.family == o.family) && + ((this.brand != null && this.brand.equals(o.brand)) || this.brand == o.brand ) && + ((this.model != null && this.model.equals(o.model)) || this.model == o.model )); } @Override public int hashCode() { - return family == null ? 0 : family.hashCode(); + int h = family == null ? 0 : family.hashCode(); + h += brand == null ? 0 : brand.hashCode(); + h += model == null ? 0 : model.hashCode(); + return h; } @Override public String toString() { - return String.format("{\"family\": %s}", - family == null ? Constants.EMPTY_STRING : '"' + family + '"'); + return String.format("{\"family\": %s, \"brand\": %s, \"model\": %s}", + family == null ? Constants.EMPTY_STRING : '"' + family + '"', + brand == null ? Constants.EMPTY_STRING : '"' + brand + '"', + model == null ? Constants.EMPTY_STRING : '"' + model + '"'); } } \ No newline at end of file diff --git a/src/main/java/ua_parser/DeviceParser.java b/src/main/java/ua_parser/DeviceParser.java index 300647e..dc6aca7 100644 --- a/src/main/java/ua_parser/DeviceParser.java +++ b/src/main/java/ua_parser/DeviceParser.java @@ -39,15 +39,17 @@ public Device parse(String agentString) { return null; } - String device = null; + Device device = null; for (DevicePattern p : patterns) { if ((device = p.match(agentString)) != null) { break; } } - if (device == null) device = "Other"; + if (device != null) { + return device; + } - return new Device(device); + return new Device("Other", null, null); } public static DeviceParser fromList(List> configList) { @@ -60,59 +62,89 @@ public static DeviceParser fromList(List> configList) { protected static DevicePattern patternFromMap(Map configMap) { String regex = configMap.get("regex"); + String regex_flag = configMap.get("regex_flag"); + Pattern pattern; if (regex == null) { throw new IllegalArgumentException("Device is missing regex"); - } - Pattern pattern = "i".equals(configMap.get("regex_flag")) // no ohter flags used (by now) - ? Pattern.compile(regex, Pattern.CASE_INSENSITIVE) : Pattern.compile(regex); - return new DevicePattern(pattern, configMap.get("device_replacement")); + } + if (null != regex_flag && regex_flag.equals("i")) { + pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + } + else { + pattern = Pattern.compile(regex); + } + + return new DevicePattern(pattern, + configMap.get("device_replacement"), + configMap.get("brand_replacement"), + configMap.get("model_replacement")); } protected static class DevicePattern { - private static final Pattern SUBSTITUTIONS_PATTERN = Pattern.compile("\\$\\d"); private final Pattern pattern; - private final String deviceReplacement; + private final String familyReplacement; + private final String brandReplacement; + private final String modelReplacement; + private final Pattern patternCut = Pattern.compile("(?=\\$([0-9]))"); + private final Pattern patternNum = Pattern.compile(".*\\$([0-9]).*"); - public DevicePattern(Pattern pattern, String deviceReplacement) { + public DevicePattern(Pattern pattern, + String familyReplacement, + String brandReplacement, + String modelReplacement) { this.pattern = pattern; - this.deviceReplacement = deviceReplacement; + this.familyReplacement = familyReplacement; + this.brandReplacement = brandReplacement; + this.modelReplacement = modelReplacement; } - public String match(String agentString) { + public Device match(String agentString) { + String family = null, brand = null, model = null; Matcher matcher = pattern.matcher(agentString); + if (!matcher.find()) { return null; } - String device = null; - if (deviceReplacement != null) { - if (deviceReplacement.contains("$")) { - device = deviceReplacement; - for (String substitution : getSubstitutions(deviceReplacement)) { - int i = Integer.valueOf(substitution.substring(1)); - String replacement = matcher.groupCount() >= i && matcher.group(i) != null - ? Matcher.quoteReplacement(matcher.group(i)) : ""; - device = device.replaceFirst("\\" + substitution, replacement); - } - device = device.trim(); - } else { - device = deviceReplacement; - } - } else if (matcher.groupCount() >= 1) { - device = matcher.group(1); + + family = multiReplace(familyReplacement, matcher); + family = "".equals(family) ? null : family; + if (familyReplacement == null && matcher.groupCount() > 0 && matcher.group(1) != null){ + family = matcher.group(1); } - return device; + brand = multiReplace(brandReplacement, matcher); + brand = "".equals(brand) ? null : brand; + + model = multiReplace(modelReplacement, matcher); + model = "".equals(model) ? null : model; + if (modelReplacement == null && matcher.groupCount() > 0 && matcher.group(1) != null){ + model = matcher.group(1); + } + + //System.out.println("MATCHED:\"" + agentString + "\" WITH " + pattern + " RESULTING IN" + new Device(family, brand, model)); + return new Device(family, brand, model); } - - private List getSubstitutions(String deviceReplacement) { - Matcher matcher = SUBSTITUTIONS_PATTERN.matcher(deviceReplacement); - List substitutions = new ArrayList(); - while (matcher.find()) { - substitutions.add(matcher.group()); + + private String multiReplace(String input, Matcher matcher){ + String output = ""; + + if (null != input) { + String[] cut = patternCut.split(input); + for (int i=0; i= markerPos && matcher.group(markerPos) != null) { + cut[i] = cut[i].replaceFirst("\\$"+markerPos, Matcher.quoteReplacement(matcher.group(markerPos))); + } + else { + cut[i] = cut[i].replaceFirst("\\$"+markerPos, ""); + } + } + output += cut[i]; + } } - return substitutions; + return output.trim(); } - } - } \ No newline at end of file diff --git a/src/main/java/ua_parser/UserAgentParser.java b/src/main/java/ua_parser/UserAgentParser.java index 37392d1..72d9234 100644 --- a/src/main/java/ua_parser/UserAgentParser.java +++ b/src/main/java/ua_parser/UserAgentParser.java @@ -29,7 +29,6 @@ */ public class UserAgentParser { private final List patterns; - public UserAgentParser(List patterns) { this.patterns = patterns; } diff --git a/src/test/java/ua_parser/DeviceTest.java b/src/test/java/ua_parser/DeviceTest.java index 0ecfba4..01821cb 100644 --- a/src/test/java/ua_parser/DeviceTest.java +++ b/src/test/java/ua_parser/DeviceTest.java @@ -23,12 +23,14 @@ public class DeviceTest extends DataTest { @Override protected Device getRandomInstance(long seed, StringGenerator g) { random.setSeed(seed); - String family = g.getString(256); - return new Device(family); + String family = g.getString(256), + brand = (random.nextBoolean() ? g.getString(8): null), + model = (random.nextBoolean() ? g.getString(8): null); + return new Device(family,brand,model); } @Override protected Device getBlankInstance() { - return new Device(null); + return new Device(null,null,null); } } \ No newline at end of file diff --git a/src/test/java/ua_parser/ParserTest.java b/src/test/java/ua_parser/ParserTest.java index 7887266..a5189e9 100644 --- a/src/test/java/ua_parser/ParserTest.java +++ b/src/test/java/ua_parser/ParserTest.java @@ -81,10 +81,10 @@ public void testParseAll() { Client expected1 = new Client(new UserAgent("Firefox", "3", "5", "5"), new OS("Mac OS X", "10", "4", null, null), - new Device("Other")); + new Device("Other",null,null)); Client expected2 = new Client(new UserAgent("Mobile Safari", "5", "1", null), new OS("iOS", "5", "1", "1", null), - new Device("iPhone")); + new Device("iPhone","Apple","iPhone")); assertThat(parser.parse(agentString1), is(expected1)); assertThat(parser.parse(agentString2), is(expected2)); diff --git a/uap-core b/uap-core index 49b141f..02b7172 160000 --- a/uap-core +++ b/uap-core @@ -1 +1 @@ -Subproject commit 49b141ffe86d5138c332f733d6b2007675bbeb43 +Subproject commit 02b7172f6ee33913fb973ce801cf379e961defbd