Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for device brand and model. #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/main/java/ua_parser/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
int h = userAgent == null ? 0 : userAgent.hashCode();
h += os == null ? 0 : os.hashCode();
h += device == null ? 0 : device.hashCode();
return h;
int result = userAgent != null ? userAgent.hashCode() : 0;
result = 31 * result + (os != null ? os.hashCode() : 0);
result = 31 * result + (device != null ? device.hashCode() : 0);
return result;
}

@Override
Expand Down
27 changes: 21 additions & 6 deletions src/main/java/ua_parser/Device.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@
*/
public class Device {
public final String family;
public final String brand;
public final String model;

public Device(String family) {
public Device(String family, String brand, String model) {
this.family = family;
this.brand = brand;
this.model = model;
}

public static Device fromMap(Map<String, String> m) {
return new Device((String) m.get("family"));
return new Device(m.get("family"), m.get("brand"), m.get("model"));
}

@Override
Expand All @@ -40,17 +44,28 @@ public boolean equals(Object other) {
if (!(other instanceof Device)) return false;

Device o = (Device) other;
return (this.family != null && this.family.equals(o.family)) || this.family == o.family;

if (brand != null ? !brand.equals(o.brand) : o.brand != null) return false;
if (this.family != null ? !this.family.equals(o.family) : o.family != null) return false;
if (model != null ? !model.equals(o.model) : o.model != null) return false;

return true;
}

@Override
public int hashCode() {
return family == null ? 0 : family.hashCode();
int result = family != null ? family.hashCode() : 0;
result = 31 * result + (brand != null ? brand.hashCode() : 0);
result = 31 * result + (model != null ? model.hashCode() : 0);
return result;
}

@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 + '"');
}

}
99 changes: 80 additions & 19 deletions src/main/java/ua_parser/DeviceParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* @author Steve Jiang (@sjiang) <gh at iamsteve com>
*/
public class DeviceParser {
List<DevicePattern> patterns;
final List<DevicePattern> patterns;

public DeviceParser(List<DevicePattern> patterns) {
this.patterns = patterns;
Expand All @@ -39,15 +39,14 @@ public Device parse(String agentString) {
return null;
}

String device = null;
Device device;
for (DevicePattern p : patterns) {
if ((device = p.match(agentString)) != null) {
break;
return device;
}
}
if (device == null) device = "Other";

return new Device(device);
return new Device("Other", null, null);
}

public static DeviceParser fromList(List<Map<String,String>> configList) {
Expand All @@ -60,40 +59,102 @@ public static DeviceParser fromList(List<Map<String,String>> configList) {

protected static DevicePattern patternFromMap(Map<String, String> configMap) {
String regex = configMap.get("regex");
String regex_flag = configMap.get("regex_flag");
if (regex == null) {
throw new IllegalArgumentException("Device is missing regex");
}
return new DevicePattern(Pattern.compile(regex),
configMap.get("device_replacement"));

Pattern pattern;
if (regex_flag != null && regex_flag.equals("i")) {
pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
} else {
pattern = Pattern.compile(regex);
}

/**
* To maintains backwards compatibility the familyReplacement
* field has been named "device_replacement"
*/
return new DevicePattern(pattern,
configMap.get("device_replacement"),
configMap.get("brand_replacement"),
configMap.get("model_replacement"));
}

protected static class DevicePattern {
private final Pattern pattern;
private final String familyReplacement;
private final String brandReplacement;
private final String modelReplacement;

public DevicePattern(Pattern pattern, String familyReplacement) {
private static final Pattern GROUP_PATTERN = Pattern.compile("\\$(\\d+)");

public DevicePattern(Pattern pattern, String familyReplacement, String brandReplacement, String modelReplacement) {
this.pattern = pattern;
this.familyReplacement = familyReplacement;
this.brandReplacement = brandReplacement;
this.modelReplacement = modelReplacement;
}

private String performReplacement(Matcher matcher, String replacement) {
int count = matcher.groupCount();
StringBuffer buffer = new StringBuffer();
Matcher replaceMatcher = GROUP_PATTERN.matcher(replacement);
while (replaceMatcher.find()) {
String group = null;
try {
int id = Integer.parseInt(replaceMatcher.group(1));
if (id >= 0 && id <= count) {
group = matcher.group(id);
}
}
catch (NumberFormatException ignored) {}
catch (IllegalArgumentException ignored) {}
catch (IndexOutOfBoundsException ignored) {}
replaceMatcher.appendReplacement(buffer, group == null ? "" : Matcher.quoteReplacement(group));
}
replacement = buffer.toString();
return replacement;
}

public String match(String agentString) {
private String replace(Matcher matcher, String replacement, int position) {
if (replacement == null) {
if (position > 0) {
replacement = "$" + position;
} else {
return null;
}
}

if (replacement.contains("$")) {
replacement = performReplacement(matcher, replacement);
}
replacement = replacement.trim();
if (replacement.length() == 0) {
return null;
} else {
return replacement;
}
}

public Device match(String agentString) {

Matcher matcher = pattern.matcher(agentString);

if (!matcher.find()) {
return null;
}

String family = null;
if (familyReplacement != null) {
if (familyReplacement.contains("$1") && matcher.groupCount() >= 1 && matcher.group(1) != null) {
family = familyReplacement.replaceFirst("\\$1", Matcher.quoteReplacement(matcher.group(1)));
} else {
family = familyReplacement;
}
} else if (matcher.groupCount() >= 1) {
family = matcher.group(1);
String family = replace(matcher, familyReplacement, 1);
String brand = replace(matcher, brandReplacement, -1);
String model = replace(matcher, modelReplacement, 1);

if (family != null) {
return new Device(family, brand, model);
} else {
return null;
}
return family;

}
}

Expand Down
14 changes: 7 additions & 7 deletions src/main/java/ua_parser/OS.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
int h = family == null ? 0 : family.hashCode();
h += major == null ? 0 : major.hashCode();
h += minor == null ? 0 : minor.hashCode();
h += patch == null ? 0 : patch.hashCode();
h += patchMinor == null ? 0 : patchMinor.hashCode();
return h;
int result = family != null ? family.hashCode() : 0;
result = 31 * result + (major != null ? major.hashCode() : 0);
result = 31 * result + (minor != null ? minor.hashCode() : 0);
result = 31 * result + (patch != null ? patch.hashCode() : 0);
result = 31 * result + (patchMinor != null ? patchMinor.hashCode() : 0);
return result;
}

@Override
@Override
public String toString() {
return String.format("{\"family\": %s, \"major\": %s, \"minor\": %s, \"patch\": %s, \"patch_minor\": %s}",
family == null ? Constants.EMPTY_STRING : '"' + family + '"',
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/ua_parser/UserAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
int h = family == null ? 0 : family.hashCode();
h += major == null ? 0 : major.hashCode();
h += minor == null ? 0 : minor.hashCode();
h += patch == null ? 0 : patch.hashCode();
return h;
int result = family != null ? family.hashCode() : 0;
result = 31 * result + (major != null ? major.hashCode() : 0);
result = 31 * result + (minor != null ? minor.hashCode() : 0);
result = 31 * result + (patch != null ? patch.hashCode() : 0);
return result;
}

@Override
Expand Down
6 changes: 4 additions & 2 deletions src/test/java/ua_parser/DeviceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ public class DeviceTest extends DataTest<Device> {
protected Device getRandomInstance(long seed, StringGenerator g) {
random.setSeed(seed);
String family = g.getString(256);
return new Device(family);
String brand = g.getString(256);
String model = g.getString(256);
return new Device(family, brand, model);
}

@Override
protected Device getBlankInstance() {
return new Device(null);
return new Device(null, null, null);
}
}
8 changes: 5 additions & 3 deletions src/test/java/ua_parser/ParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -100,7 +100,9 @@ public void testReplacementQuoting() throws Exception {
+ " os_replacement: 'CatOS 9000'\n"
+ "device_parsers:\n"
+ " - regex: 'CashPhone-([\\$0-9]+)\\.(\\d+)\\.(\\d+)'\n"
+ " device_replacement: 'CashPhone $1'\n";
+ " device_replacement: 'CashPhone $1'\n"
+ " brand_replacement: 'CashPhone'\n"
+ " model_replacement: '$1'\n";

Parser testParser = parserFromStringConfig(testConfig);
Client result = testParser.parse("ABC12\\34 (CashPhone-$9.0.1 CatOS OH-HAI=/^.^\\=)");
Expand Down