UdgerParser.java
1/*
2 UdgerParser - Java agent string parser based on Udger https://udger.com/products/local_parser
3
4 author The Udger.com Team (info@udger.com)
5 copyright Copyright (c) Udger s.r.o.
6 license GNU Lesser General Public License
7 link https://udger.com/products
8*/
9package org.udger.parser;
10
11import org.sqlite.SQLiteConfig;
12
13import java.io.Closeable;
14import java.io.File;
15import java.io.IOException;
16import java.lang.ref.SoftReference;
17import java.net.Inet4Address;
18import java.net.Inet6Address;
19import java.net.InetAddress;
20import java.net.UnknownHostException;
21import java.sql.*;
22import java.util.*;
23import java.util.logging.Logger;
24import java.util.regex.Matcher;
25import java.util.regex.Pattern;
26
30public class UdgerParser implements Closeable {
31
32 private static final Logger LOG = Logger.getLogger(UdgerParser.class.getName());
33
34 private static final String DB_FILENAME = "udgerdb_v3.dat";
35 private static final String UDGER_UA_DEV_BRAND_LIST_URL = "https://udger.com/resources/ua-list/devices-brand-detail?brand=";
36 private static final String ID_CRAWLER = "crawler";
37 private static final Pattern PAT_UNPERLIZE = Pattern.compile("^/?(.*?)/si$");
38
42 public static class ParserDbData {
43
44 private WordDetector clientWordDetector;
45 private WordDetector deviceWordDetector;
46 private WordDetector osWordDetector;
47
48 private List<IdRegString> clientRegstringList;
49 private List<IdRegString> osRegstringList;
50 private List<IdRegString> deviceRegstringList;
51
52 private volatile boolean prepared = false;
53
54 private final String dbFileName;
55
56 public ParserDbData(String dbFileName) {
57 this.dbFileName = dbFileName;
58 }
59
60 protected void prepare(Connection connection) throws SQLException {
61 if (!prepared) {
62 synchronized (this) {
63 if (!prepared) {
64 clientRegstringList = prepareRegexpStruct(connection, "udger_client_regex");
65 osRegstringList = prepareRegexpStruct(connection, "udger_os_regex");
66 deviceRegstringList = prepareRegexpStruct(connection, "udger_deviceclass_regex");
67
68 clientWordDetector = createWordDetector(connection, "udger_client_regex", "udger_client_regex_words");
69 deviceWordDetector = createWordDetector(connection, "udger_deviceclass_regex", "udger_deviceclass_regex_words");
70 osWordDetector = createWordDetector(connection, "udger_os_regex", "udger_os_regex_words");
71 prepared = true;
72 }
73 }
74 }
75 }
76
77 }
78
79 private static class ClientInfo {
80 private Integer clientId;
81 private Integer classId;
82 }
83
84 private static class IdRegString {
85 int id;
86 int wordId1;
87 int wordId2;
88 Pattern pattern;
89 }
90
91 private static class MatcherWithIdRegString {
92 private final Matcher matcher;
93 private final IdRegString irs;
94
95 private MatcherWithIdRegString(Matcher matcher, IdRegString irs) {
96 this.matcher = matcher;
97 this.irs = irs;
98 }
99 }
100
101 private ParserDbData parserDbData;
102
103 private Connection connection;
104
105 private final Map<String, SoftReference<Pattern>> regexCache = new HashMap<>();
106
107 private Map<String, PreparedStatement> preparedStmtMap = new HashMap<>();
108
110
111 private boolean osParserEnabled = true;
112 private boolean deviceParserEnabled = true;
113 private boolean deviceBrandParserEnabled = true;
114 private boolean inMemoryEnabled = false;
115
121 public UdgerParser(ParserDbData parserDbData) {
122 this(parserDbData, 10000);
123 }
124
131 public UdgerParser(ParserDbData parserDbData, int cacheCapacity) {
132 this.parserDbData = parserDbData;
133 if (cacheCapacity > 0) {
134 cache = new LRUCache<>(cacheCapacity);
135 }
136 }
137
145 public UdgerParser(ParserDbData parserDbData, boolean inMemoryEnabled, int cacheCapacity) {
146 this(parserDbData, cacheCapacity);
147 this.inMemoryEnabled = inMemoryEnabled;
148 }
149
150 @Override
151 public void close() throws IOException {
152 try {
153 for (PreparedStatement preparedStmt : preparedStmtMap.values()) {
154 preparedStmt.close();
155 }
156 preparedStmtMap.clear();
157 if (connection != null && !connection.isClosed()) {
158 connection.close();
159 connection = null;
160 }
161 if (cache != null) {
162 cache.clear();
163 }
164 regexCache.clear();
165 } catch (SQLException e) {
166 throw new IOException(e.getMessage());
167 }
168 }
169
177 public boolean isValid(int timeoutMillis) throws IOException {
178 try {
179 return connection == null || connection.isValid(timeoutMillis);
180 } catch (SQLException e) {
181 throw new IOException("Failed to validate connection within " + timeoutMillis + " millis.", e);
182 }
183 }
184
195 public UdgerUaResult parseUa(String uaString) throws SQLException {
196
197 UdgerUaResult ret;
198
199 if (cache != null) {
200 ret = cache.get(uaString);
201 if (ret != null) {
202 return ret;
203 }
204 }
205
206 ret = new UdgerUaResult(uaString);
207
208 prepare();
209
210 ClientInfo clientInfo = clientDetector(uaString, ret);
211
212 if (!"Crawler".equals(ret.getUaClass())) {
213 if (osParserEnabled) {
214 osDetector(uaString, ret, clientInfo);
215 }
216
217 if (deviceParserEnabled) {
218 deviceDetector(uaString, ret, clientInfo);
219 }
220
221 if (deviceBrandParserEnabled) {
222 if (ret.getOsFamilyCode() != null && !ret.getOsFamilyCode().isEmpty()) {
223 fetchDeviceBrand(uaString, ret);
224 }
225 }
226 }
227
228 if (cache != null) {
229 cache.put(uaString, ret);
230 }
231
232 return ret;
233 }
234
243 public UdgerIpResult parseIp(String ipString) throws SQLException, UnknownHostException {
244
245 UdgerIpResult ret = new UdgerIpResult(ipString);
246
247 InetAddress addr = InetAddress.getByName(ipString);
248 Long ipv4int = null;
249 String normalizedIp = null;
250
251 if (addr instanceof Inet4Address) {
252 ipv4int = 0L;
253 for (byte b : addr.getAddress()) {
254 ipv4int = ipv4int << 8 | (b & 0xFF);
255 }
256 normalizedIp = addr.getHostAddress();
257 } else if (addr instanceof Inet6Address) {
258 normalizedIp = addr.getHostAddress().replaceAll("((?:(?:^|:)0+\\b){2,}):?(?!\\S*\\b\\1:0+\\b)(\\S*)", "::$2");
259 }
260
261 ret.setIpClassification("Unrecognized");
262 ret.setIpClassificationCode("unrecognized");
263
264 if (normalizedIp != null) {
265
266 prepare();
267
268 try (ResultSet ipRs = getFirstRow(UdgerSqlQuery.SQL_IP, normalizedIp)) {
269 if (ipRs != null && ipRs.next()) {
270 fetchUdgerIp(ipRs, ret);
271 if (!ID_CRAWLER.equals(ret.getIpClassificationCode())) {
272 ret.setCrawlerFamilyInfoUrl("");
273 }
274 }
275 }
276
277 if (ipv4int != null) {
278 ret.setIpVer(4);
279 ResultSet dataCenterRs = getFirstRow(UdgerSqlQuery.SQL_DATACENTER, ipv4int, ipv4int);
280 fetchDataCenterAndCloseRs(dataCenterRs, ret);
281 } else {
282 ret.setIpVer(6);
283 int[] ipArray = ip6ToArray((Inet6Address) addr);
284 ResultSet dataCenterRs = getFirstRow(UdgerSqlQuery.SQL_DATACENTER_RANGE6,
285 ipArray[0], ipArray[0],
286 ipArray[1], ipArray[1],
287 ipArray[2], ipArray[2],
288 ipArray[3], ipArray[3],
289 ipArray[4], ipArray[4],
290 ipArray[5], ipArray[5],
291 ipArray[6], ipArray[6],
292 ipArray[7], ipArray[7]
293 );
294 fetchDataCenterAndCloseRs(dataCenterRs, ret);
295 }
296 }
297
298 return ret;
299 }
300
301 private void fetchDataCenterAndCloseRs(ResultSet dataCenterRs, UdgerIpResult ret) throws SQLException {
302 if (dataCenterRs != null) {
303 try {
304 if (dataCenterRs.next()) {
305 fetchDataCenter(dataCenterRs, ret);
306 }
307 } finally {
308 dataCenterRs.close();
309 }
310 }
311 }
312
318 public boolean isOsParserEnabled() {
319 return osParserEnabled;
320 }
321
335 public void setOsParserEnabled(boolean osParserEnabled) {
336 this.osParserEnabled = osParserEnabled;
337 }
338
344 public boolean isDeviceParserEnabled() {
345 return deviceParserEnabled;
346 }
347
361 public void setDeviceParserEnabled(boolean deviceParserEnabled) {
362 this.deviceParserEnabled = deviceParserEnabled;
363 }
364
370 public boolean isDeviceBrandParserEnabled() {
371 return deviceBrandParserEnabled;
372 }
373
387 public void setDeviceBrandParserEnabled(boolean deviceBrandParserEnabled) {
388 this.deviceBrandParserEnabled = deviceBrandParserEnabled;
389 }
390
391 private static WordDetector createWordDetector(Connection connection, String regexTableName, String wordTableName) throws SQLException {
392
393 Set<Integer> usedWords = new HashSet<>();
394
395 addUsedWords(usedWords, connection, regexTableName, "word_id");
396 addUsedWords(usedWords, connection, regexTableName, "word2_id");
397
398 WordDetector result = new WordDetector();
399
400 try (final Statement statement = connection.createStatement();
401 final ResultSet rs = statement.executeQuery("SELECT * FROM " + wordTableName)) {
402 if (rs != null) {
403 while (rs.next()) {
404 int id = rs.getInt("id");
405 if (usedWords.contains(id)) {
406 String word = rs.getString("word").toLowerCase();
407 result.addWord(id, word);
408 }
409 }
410 }
411 }
412 return result;
413 }
414
415 private static void addUsedWords(Set<Integer> usedWords, Connection connection, String regexTableName, String wordIdColumn) throws SQLException {
416 try (Statement statement = connection.createStatement();
417 ResultSet rs = statement.executeQuery("SELECT " + wordIdColumn + " FROM " + regexTableName)) {
418 if (rs != null) {
419 while (rs.next()) {
420 usedWords.add(rs.getInt(wordIdColumn));
421 }
422 }
423 }
424 }
425
426 private MatcherWithIdRegString findMatcherIdRegString(String uaString, Set<Integer> foundClientWords, List<IdRegString> list) {
427 for (IdRegString irs : list) {
428 if ((irs.wordId1 == 0 || foundClientWords.contains(irs.wordId1)) &&
429 (irs.wordId2 == 0 || foundClientWords.contains(irs.wordId2))) {
430 Matcher matcher = irs.pattern.matcher(uaString);
431 if (matcher.find())
432 return new MatcherWithIdRegString(matcher, irs);
433 }
434 }
435 return null;
436 }
437
438 private static List<IdRegString> prepareRegexpStruct(Connection connection, String regexpTableName) throws SQLException {
439 List<IdRegString> ret = new ArrayList<>();
440 try (Statement statement = connection.createStatement();
441 ResultSet rs = statement.executeQuery("SELECT rowid, regstring, word_id, word2_id FROM " + regexpTableName + " ORDER BY sequence")) {
442 if (rs != null) {
443 while (rs.next()) {
444 IdRegString irs = new IdRegString();
445 irs.id = rs.getInt("rowid");
446 irs.wordId1 = rs.getInt("word_id");
447 irs.wordId2 = rs.getInt("word2_id");
448 String regex = rs.getString("regstring");
449 Matcher m = PAT_UNPERLIZE.matcher(regex);
450 if (m.matches()) {
451 regex = m.group(1);
452 }
453 irs.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
454 ret.add(irs);
455 }
456 }
457 }
458 return ret;
459 }
460
461 private ClientInfo clientDetector(String uaString, UdgerUaResult ret) throws SQLException {
462 ClientInfo clientInfo = new ClientInfo();
463 try (ResultSet userAgentRs1 = getFirstRow(UdgerSqlQuery.SQL_CRAWLER, uaString)) {
464 if (userAgentRs1 != null && userAgentRs1.next()) {
465 fetchUserAgent(userAgentRs1, ret);
466 clientInfo.classId = 99;
467 clientInfo.clientId = -1;
468 } else {
469 MatcherWithIdRegString mwirs = findMatcherIdRegString(uaString, parserDbData.clientWordDetector.findWords(uaString), parserDbData.clientRegstringList);
470 if (mwirs != null) {
471 try (ResultSet userAgentRs2 = getFirstRow(UdgerSqlQuery.SQL_CLIENT, mwirs.irs.id)) {
472 if (userAgentRs2 != null && userAgentRs2.next()) {
473 fetchUserAgent(userAgentRs2, ret);
474 clientInfo.classId = ret.getClassId();
475 clientInfo.clientId = ret.getClientId();
476 patchVersions(mwirs.matcher, ret);
477 }
478 }
479 } else {
480 ret.setUaClass("Unrecognized");
481 ret.setUaClassCode("unrecognized");
482 }
483 }
484 }
485 return clientInfo;
486 }
487
488 private void osDetector(String uaString, UdgerUaResult ret, ClientInfo clientInfo) throws SQLException {
489 MatcherWithIdRegString mwirs = findMatcherIdRegString(uaString, parserDbData.osWordDetector.findWords(uaString), parserDbData.osRegstringList);
490 if (mwirs != null) {
491 try (ResultSet opSysRs = getFirstRow(UdgerSqlQuery.SQL_OS, mwirs.irs.id)) {
492 if (opSysRs != null && opSysRs.next()) {
493 fetchOperatingSystem(opSysRs, ret);
494 }
495 }
496 } else {
497 if (clientInfo.clientId != null && clientInfo.clientId != 0) {
498 try (ResultSet opSysRs = getFirstRow(UdgerSqlQuery.SQL_CLIENT_OS, clientInfo.clientId.toString())) {
499 if (opSysRs != null && opSysRs.next()) {
500 fetchOperatingSystem(opSysRs, ret);
501 }
502 }
503 }
504 }
505 }
506
507 private void deviceDetector(String uaString, UdgerUaResult ret, ClientInfo clientInfo) throws SQLException {
508 MatcherWithIdRegString mwirs = findMatcherIdRegString(uaString, parserDbData.deviceWordDetector.findWords(uaString), parserDbData.deviceRegstringList);
509 if (mwirs != null) {
510 try (ResultSet devRs = getFirstRow(UdgerSqlQuery.SQL_DEVICE, mwirs.irs.id)) {
511 if (devRs != null && devRs.next()) {
512 fetchDevice(devRs, ret);
513 }
514 }
515 } else {
516 if (clientInfo.classId != null && clientInfo.classId != -1) {
517 try (ResultSet devRs = getFirstRow(UdgerSqlQuery.SQL_CLIENT_CLASS, clientInfo.classId.toString())) {
518 if (devRs != null && devRs.next()) {
519 fetchDevice(devRs, ret);
520 }
521 }
522 }
523 }
524 }
525
526 private void fetchDeviceBrand(String uaString, UdgerUaResult ret) throws SQLException {
527 PreparedStatement preparedStatement = preparedStmtMap.get(UdgerSqlQuery.SQL_DEVICE_REGEX);
528 if (preparedStatement == null) {
529 preparedStatement = connection.prepareStatement(UdgerSqlQuery.SQL_DEVICE_REGEX);
530 preparedStmtMap.put(UdgerSqlQuery.SQL_DEVICE_REGEX, preparedStatement);
531 }
532 preparedStatement.setObject(1, ret.getOsFamilyCode());
533 preparedStatement.setObject(2, ret.getOsCode());
534 try (ResultSet devRegexRs = preparedStatement.executeQuery()) {
535 if (devRegexRs != null) {
536 while (devRegexRs.next()) {
537 String devId = devRegexRs.getString("id");
538 String regex = devRegexRs.getString("regstring");
539 if (devId != null && regex != null) {
540 Pattern patRegex = getRegexFromCache(regex);
541 Matcher matcher = patRegex.matcher(uaString);
542 if (matcher.find()) {
543 try (ResultSet devNameListRs = getFirstRow(UdgerSqlQuery.SQL_DEVICE_NAME_LIST, devId, matcher.group(1))) {
544 if (devNameListRs != null && devNameListRs.next()) {
545 ret.setDeviceMarketname(devNameListRs.getString("marketname"));
546 ret.setDeviceBrand(devNameListRs.getString("brand"));
547 ret.setDeviceBrandCode(devNameListRs.getString("brand_code"));
548 ret.setDeviceBrandHomepage(devNameListRs.getString("brand_url"));
549 ret.setDeviceBrandIcon(devNameListRs.getString("icon"));
550 ret.setDeviceBrandIconBig(devNameListRs.getString("icon_big"));
551 ret.setDeviceBrandInfoUrl(UDGER_UA_DEV_BRAND_LIST_URL + devNameListRs.getString("brand_code"));
552 break;
553 }
554 }
555 }
556 }
557 }
558 }
559 }
560 }
561
562
563 private int[] ip6ToArray(Inet6Address addr) {
564 int ret[] = new int[8];
565 byte[] bytes = addr.getAddress();
566 for (int i = 0; i < 8; i++) {
567 ret[i] = ((bytes[i * 2] << 8) & 0xff00) | (bytes[i * 2 + 1] & 0xff);
568 }
569 return ret;
570 }
571
572 private void prepare() throws SQLException {
573 connect();
574 parserDbData.prepare(connection);
575 }
576
577 private void connect() throws SQLException {
578 if (connection == null) {
579 SQLiteConfig config = new SQLiteConfig();
580 config.setReadOnly(true);
581 if (inMemoryEnabled) {
582 // we cannot use read only for in memory DB since we need to populate this DB from the file.
583 connection = DriverManager.getConnection("jdbc:sqlite::memory:");
584 File dbfile = new File(parserDbData.dbFileName);
585 try (Statement statement = connection.createStatement()) {
586 statement.executeUpdate("restore from " + dbfile.getPath());
587 } catch (Exception e) {
588 LOG.warning("Error re-constructing in memory data base from Db file " + dbfile);
589 }
590 } else {
591 connection = DriverManager.getConnection("jdbc:sqlite:" + parserDbData.dbFileName, config.toProperties());
592 }
593 }
594 }
595
596 private Pattern getRegexFromCache(String regex) {
597 SoftReference<Pattern> patRegex = regexCache.get(regex);
598 if (patRegex == null || patRegex.get() == null) {
599 Matcher m = PAT_UNPERLIZE.matcher(regex);
600 if (m.matches()) {
601 regex = m.group(1);
602 }
603 patRegex = new SoftReference<>(Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL));
604 regexCache.put(regex, patRegex);
605 }
606 return patRegex.get();
607 }
608
609 private ResultSet getFirstRow(String query, Object... params) throws SQLException {
610 PreparedStatement preparedStatement = preparedStmtMap.get(query);
611 if (preparedStatement == null) {
612 preparedStatement = connection.prepareStatement(query);
613 preparedStmtMap.put(query, preparedStatement);
614 }
615 for (int i = 0; i < params.length; i++) {
616 preparedStatement.setObject(i + 1, params[i]);
617 }
618 preparedStatement.setMaxRows(1);
619 return preparedStatement.executeQuery();
620 }
621
622
623 private void fetchUserAgent(ResultSet rs, UdgerUaResult ret) throws SQLException {
624 ret.setClassId(rs.getInt("class_id"));
625 ret.setClientId(rs.getInt("client_id"));
626 ret.setCrawlerCategory(nvl(rs.getString("crawler_category")));
627 ret.setCrawlerCategoryCode(nvl(rs.getString("crawler_category_code")));
628 ret.setCrawlerLastSeen(nvl(rs.getString("crawler_last_seen")));
629 ret.setCrawlerRespectRobotstxt(nvl(rs.getString("crawler_respect_robotstxt")));
630 ret.setUa(nvl(rs.getString("ua")));
631 ret.setUaClass(nvl(rs.getString("ua_class")));
632 ret.setUaClassCode(nvl(rs.getString("ua_class_code")));
633 ret.setUaEngine(nvl(rs.getString("ua_engine")));
634 ret.setUaFamily(nvl(rs.getString("ua_family")));
635 ret.setUaFamilyCode(nvl(rs.getString("ua_family_code")));
636 ret.setUaFamilyHomepage(nvl(rs.getString("ua_family_homepage")));
637 ret.setUaFamilyIcon(nvl(rs.getString("ua_family_icon")));
638 ret.setUaFamilyIconBig(nvl(rs.getString("ua_family_icon_big")));
639 ret.setUaFamilyInfoUrl(nvl(rs.getString("ua_family_info_url")));
640 ret.setUaFamilyVendor(nvl(rs.getString("ua_family_vendor")));
641 ret.setUaFamilyVendorCode(nvl(rs.getString("ua_family_vendor_code")));
642 ret.setUaFamilyVendorHomepage(nvl(rs.getString("ua_family_vendor_homepage")));
643 ret.setUaUptodateCurrentVersion(nvl(rs.getString("ua_uptodate_current_version")));
644 ret.setUaVersion(nvl(rs.getString("ua_version")));
645 ret.setUaVersionMajor(nvl(rs.getString("ua_version_major")));
646 }
647
648 private void fetchOperatingSystem(ResultSet rs, UdgerUaResult ret) throws SQLException {
649 ret.setOsFamily(nvl(rs.getString("os_family")));
650 ret.setOs(nvl(rs.getString("os")));
651 ret.setOsCode(nvl(rs.getString("os_code")));
652 ret.setOsFamilyCode(nvl(rs.getString("os_family_code")));
653 ret.setOsFamilyVendorHomepage(nvl(rs.getString("os_family_vendor_homepage")));
654 ret.setOsFamilyVendor(nvl(rs.getString("os_family_vendor")));
655 ret.setOsFamilyVendorCode(nvl(rs.getString("os_family_vendor_code")));
656 ret.setOsHomePage(nvl(rs.getString("os_home_page")));
657 ret.setOsIcon(nvl(rs.getString("os_icon")));
658 ret.setOsIconBig(nvl(rs.getString("os_icon_big")));
659 ret.setOsInfoUrl(nvl(rs.getString("os_info_url")));
660 }
661
662 private void fetchDevice(ResultSet rs, UdgerUaResult ret) throws SQLException {
663 ret.setDeviceClass(nvl(rs.getString("device_class")));
664 ret.setDeviceClassCode(nvl(rs.getString("device_class_code")));
665 ret.setDeviceClassIcon(nvl(rs.getString("device_class_icon")));
666 ret.setDeviceClassIconBig(nvl(rs.getString("device_class_icon_big")));
667 ret.setDeviceClassInfoUrl(nvl(rs.getString("device_class_info_url")));
668 }
669
670 private void patchVersions(Matcher lastPatternMatcher, UdgerUaResult ret) {
671 if (lastPatternMatcher != null) {
672 String version = "";
673 if (lastPatternMatcher.groupCount() >= 1) {
674 version = lastPatternMatcher.group(1);
675 if (version == null) {
676 version = "";
677 }
678 }
679 ret.setUaVersion(version);
680 String versionSegments[] = version.split("\\.");
681 if (versionSegments.length > 0) {
682 ret.setUaVersionMajor(version.split("\\.")[0]);
683 } else {
684 ret.setUaVersionMajor("");
685 }
686 ret.setUa((ret.getUa() != null ? ret.getUa() : "") + " " + version);
687 } else {
688 ret.setUaVersion("");
689 ret.setUaVersionMajor("");
690 }
691 }
692
693 private void fetchUdgerIp(ResultSet rs, UdgerIpResult ret) throws SQLException {
694 ret.setCrawlerCategory(nvl(rs.getString("crawler_category")));
695 ret.setCrawlerCategoryCode(nvl(rs.getString("crawler_category_code")));
696 ret.setCrawlerFamily(nvl(rs.getString("crawler_family")));
697 ret.setCrawlerFamilyCode(nvl(rs.getString("crawler_family_code")));
698 ret.setCrawlerFamilyHomepage(nvl(rs.getString("crawler_family_homepage")));
699 ret.setCrawlerFamilyIcon(nvl(rs.getString("crawler_family_icon")));
700 ret.setCrawlerFamilyInfoUrl(nvl(rs.getString("crawler_family_info_url")));
701 ret.setCrawlerFamilyVendor(nvl(rs.getString("crawler_family_vendor")));
702 ret.setCrawlerFamilyVendorCode(nvl(rs.getString("crawler_family_vendor_code")));
703 ret.setCrawlerFamilyVendorHomepage(nvl(rs.getString("crawler_family_vendor_homepage")));
704 ret.setCrawlerLastSeen(nvl(rs.getString("crawler_last_seen")));
705 ret.setCrawlerName(nvl(rs.getString("crawler_name")));
706 ret.setCrawlerRespectRobotstxt(nvl(rs.getString("crawler_respect_robotstxt")));
707 ret.setCrawlerVer(nvl(rs.getString("crawler_ver")));
708 ret.setCrawlerVerMajor(nvl(rs.getString("crawler_ver_major")));
709 ret.setIpCity(nvl(rs.getString("ip_city")));
710 ret.setIpClassification(nvl(rs.getString("ip_classification")));
711 ret.setIpClassificationCode(nvl(rs.getString("ip_classification_code")));
712 ret.setIpCountry(nvl(rs.getString("ip_country")));
713 ret.setIpCountryCode(nvl(rs.getString("ip_country_code")));
714 ret.setIpHostname(nvl(rs.getString("ip_hostname")));
715 ret.setIpLastSeen(nvl(rs.getString("ip_last_seen")));
716 }
717
718 private String nvl(String v) {
719 return v != null ? v : "";
720 }
721
722 private void fetchDataCenter(ResultSet rs, UdgerIpResult ret) throws SQLException {
723 ret.setDataCenterHomePage(nvl(rs.getString("datacenter_homepage")));
724 ret.setDataCenterName(nvl(rs.getString("datacenter_name")));
725 ret.setDataCenterNameCode(nvl(rs.getString("datacenter_name_code")));
726 }
727
728}
void setDeviceParserEnabled(boolean deviceParserEnabled)
UdgerParser(ParserDbData parserDbData, int cacheCapacity)
UdgerIpResult parseIp(String ipString)
boolean isValid(int timeoutMillis)
UdgerUaResult parseUa(String uaString)
void setOsParserEnabled(boolean osParserEnabled)
void setDeviceBrandParserEnabled(boolean deviceBrandParserEnabled)
UdgerParser(ParserDbData parserDbData, boolean inMemoryEnabled, int cacheCapacity)
UdgerParser(ParserDbData parserDbData)