Skip to content

Commit a1f3028

Browse files
authored
Added cached implementation (#2)
1 parent 0348871 commit a1f3028

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package ru.chermenin.ua
2+
3+
/**
4+
* Implementation of the parser with cached values.
5+
*
6+
* @param initialEntries initial size of the cache
7+
* @param maxEntries max count of entries in the cache
8+
*/
9+
class CachedUserAgentParser(initialEntries: Int = 1000, maxEntries: Int = 5000) {
10+
11+
private val cache = LRUCache<String, UserAgent>(initialEntries, maxEntries)
12+
13+
/**
14+
* Method to parse user agent string and return [UserAgent] object.
15+
*
16+
* @param userAgentString user agent string to parse
17+
* @return [UserAgent] object for the defined string
18+
*/
19+
fun parse(userAgentString: String): UserAgent {
20+
return cache.getOrPut(userAgentString) { UserAgent.parse(userAgentString) }
21+
}
22+
}
23+
24+
/**
25+
* Simple implementation of LRU cache class.
26+
*
27+
* @param initialEntries initial size of the cache
28+
* @param maxEntries max count of entries in the cache
29+
*/
30+
private class LRUCache<K, V>(private val initialEntries: Int, private val maxEntries: Int) :
31+
LinkedHashMap<K, V>(initialEntries, 0.8f, true) {
32+
33+
override fun removeEldestEntry(eldest: Map.Entry<K, V>?): Boolean {
34+
return size > maxEntries
35+
}
36+
}

src/main/kotlin/ru/chermenin/ua/UserAgent.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,24 @@ class UserAgent private constructor(private val userAgentString: String) {
9999
override fun toString(): String {
100100
return "$device / $os / $browser"
101101
}
102+
103+
override fun equals(other: Any?): Boolean {
104+
if (this === other) return true
105+
if (javaClass != other?.javaClass) return false
106+
107+
other as UserAgent
108+
109+
if (os != other.os) return false
110+
if (browser != other.browser) return false
111+
if (device != other.device) return false
112+
113+
return true
114+
}
115+
116+
override fun hashCode(): Int {
117+
var result = os.hashCode()
118+
result = 31 * result + browser.hashCode()
119+
result = 31 * result + (device.hashCode())
120+
return result
121+
}
102122
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package ru.chermenin.ua
2+
3+
import org.junit.Test
4+
import kotlin.test.assertFalse
5+
import kotlin.test.assertTrue
6+
7+
class CachedUserAgentParserTest {
8+
9+
private val iPhoneString = "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3"
10+
private val iPadString = "Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"
11+
private val galaxyTabString = "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
12+
private val galaxyS3String = "Mozilla/5.0 (Linux; U; Android 4.0.4; en-gb; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
13+
14+
@Test
15+
fun testCachedParser() {
16+
val parser = CachedUserAgentParser(1, 3)
17+
18+
val iPhone = parser.parse(iPhoneString)
19+
val iPad = parser.parse(iPadString)
20+
val galaxyTab = parser.parse(galaxyTabString)
21+
22+
assertTrue("iPhone UA object must be the same") { iPhone === parser.parse(iPhoneString) }
23+
assertTrue("iPad UA object must be the same") { iPad === parser.parse(iPadString) }
24+
assertTrue("galaxyTab UA object must be the same") { galaxyTab === parser.parse(galaxyTabString) }
25+
26+
val galaxyS3 = parser.parse(galaxyS3String)
27+
28+
assertTrue("iPad UA object must be the same") { iPad === parser.parse(iPadString) }
29+
assertTrue("galaxyTab UA object must be the same") { galaxyTab === parser.parse(galaxyTabString) }
30+
assertTrue("galaxyS3 UA object must be the same") { galaxyS3 === parser.parse(galaxyS3String) }
31+
assertFalse("iPhone UA object already must not be the same") { iPhone === parser.parse(iPhoneString) }
32+
}
33+
}

0 commit comments

Comments
 (0)