You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2019/05/15 17:35:07 UTC
[unomi] branch master updated: [UNOMI-228] Replace user agent detector library
This is an automated email from the ASF dual-hosted git repository.
shuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git
The following commit(s) were added to refs/heads/master by this push:
new 9901d95 [UNOMI-228] Replace user agent detector library
9901d95 is described below
commit 9901d95898c515942f754255ba2bd3d6fcbdbbf3
Author: Francois Papon <fp...@apache.org>
AuthorDate: Sat Apr 20 19:53:20 2019 +0400
[UNOMI-228] Replace user agent detector library
---
itests/pom.xml | 33 +------
.../test/java/org/apache/unomi/itests/BaseIT.java | 40 +-------
package/pom.xml | 13 +--
performance-tests/pom.xml | 36 +------
.../apache/unomi/performancetests/BasicTest.java | 52 ++---------
plugins/request/pom.xml | 86 ++++++++++++++---
.../request/actions/SetRemoteHostInfoAction.java | 52 ++++++-----
.../unomi/plugins/request/useragent/UserAgent.java | 86 +++++++++++++++++
.../useragent/UserAgentDetectorServiceImpl.java | 76 +++++++++++++++
.../resources/OSGI-INF/blueprint/blueprint.xml | 6 ++
.../request/actions/UserAgentDetectorTest.java | 104 +++++++++++++++++++++
pom.xml | 34 ++++++-
services/pom.xml | 14 +++
.../resources/OSGI-INF/blueprint/blueprint.xml | 1 -
14 files changed, 439 insertions(+), 194 deletions(-)
diff --git a/itests/pom.xml b/itests/pom.xml
index fad2656..5f04b9a 100644
--- a/itests/pom.xml
+++ b/itests/pom.xml
@@ -30,10 +30,9 @@
<dependencies>
<dependency>
<groupId>org.apache.unomi</groupId>
- <artifactId>unomi-kar</artifactId>
- <classifier>features</classifier>
+ <artifactId>unomi</artifactId>
<version>${project.version}</version>
- <type>xml</type>
+ <type>tar.gz</type>
<scope>test</scope>
</dependency>
<dependency>
@@ -64,34 +63,6 @@
</dependency>
<dependency>
- <groupId>org.apache.karaf.features</groupId>
- <artifactId>standard</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.karaf.cellar</groupId>
- <artifactId>apache-karaf-cellar</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.web</groupId>
- <artifactId>pax-web-features</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf.karaf</groupId>
- <artifactId>apache-cxf</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index eede503..039fb51 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -47,42 +47,13 @@ public abstract class BaseIT {
@Configuration
public Option[] config() throws InterruptedException {
- MavenArtifactUrlReference karafUrl = maven()
- .groupId("org.apache.karaf")
- .artifactId("apache-karaf")
- .version("4.1.5")
- .type("tar.gz");
- MavenUrlReference karafStandardRepo = maven()
- .groupId("org.apache.karaf.features")
- .artifactId("standard")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafCellarRepo = maven()
- .groupId("org.apache.karaf.cellar")
- .artifactId("apache-karaf-cellar")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafPaxWebRepo = maven()
- .groupId("org.ops4j.pax.web")
- .artifactId("pax-web-features")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafCxfRepo = maven()
- .groupId("org.apache.cxf.karaf")
- .artifactId("apache-cxf")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference contextServerRepo = maven()
+ MavenArtifactUrlReference karafUrl = maven()
.groupId("org.apache.unomi")
- .artifactId("unomi-kar")
- .classifier("features")
- .type("xml")
+ .artifactId("unomi")
+ .type("tar.gz")
.versionAsInProject();
+
MavenUrlReference routerRepo = maven()
.groupId("org.apache.unomi")
.artifactId("unomi-router-karaf-feature")
@@ -132,9 +103,6 @@ public abstract class BaseIT {
systemProperty("org.apache.unomi.hazelcast.tcp-ip.members").value("127.0.0.1"),
systemProperty("org.apache.unomi.hazelcast.tcp-ip.interface").value("127.0.0.1"),
systemProperty("unomi.autoStart").value("true"),
- features(karafCxfRepo, "cxf"),
- features(karafCellarRepo, "cellar"),
- features(contextServerRepo, "unomi-kar"),
features(routerRepo, "unomi-router-karaf-feature"),
CoreOptions.bundleStartLevel(100),
CoreOptions.frameworkStartLevel(100)
diff --git a/package/pom.xml b/package/pom.xml
index 9dad3f6..1cb567a 100644
--- a/package/pom.xml
+++ b/package/pom.xml
@@ -345,6 +345,7 @@
<library>mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.stax-api-1.2/${servicemix.specs.version};type:=endorsed;export:=true</library>
<library>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xalan/${xalan.bundle.version};type:=endorsed;export:=true</library>
<library>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xalan-serializer/${xalan-serializer.bundle.version};type:=endorsed;export:=true</library>
+ <library>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jsr305/${jsr305.bundle.version};type:=endorsed;export:=true</library>
<library>mvn:javax.annotation/javax.annotation-api/1.2;type:=endorsed;export:=true</library>
<library>mvn:org.apache.servicemix.specs/org.apache.servicemix.specs.activator/${servicemix.specs.version};type:=default;export:=true</library>
@@ -361,18 +362,6 @@
<profiles>
<profile>
- <id>integration-tests</id>
- <dependencies>
- <dependency>
- <groupId>org.apache.unomi</groupId>
- <artifactId>unomi-itests</artifactId>
- <version>${project.version}</version>
- <classifier>features</classifier>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </profile>
- <profile>
<id>src</id>
<build>
<plugins>
diff --git a/performance-tests/pom.xml b/performance-tests/pom.xml
index 9371753..b844b39 100644
--- a/performance-tests/pom.xml
+++ b/performance-tests/pom.xml
@@ -34,41 +34,11 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.apache.karaf.features</groupId>
- <artifactId>standard</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.web</groupId>
- <artifactId>pax-web-features</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
- <dependency>
- <groupId>org.apache.karaf.features</groupId>
- <artifactId>enterprise</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
- <dependency>
- <groupId>org.apache.karaf.features</groupId>
- <artifactId>spring</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
- <dependency>
- <groupId>org.apache.cxf.karaf</groupId>
- <artifactId>apache-cxf</artifactId>
- <classifier>features</classifier>
- <type>xml</type>
- </dependency>
- <dependency>
<groupId>org.apache.unomi</groupId>
- <artifactId>unomi-kar</artifactId>
- <classifier>features</classifier>
+ <artifactId>unomi</artifactId>
<version>${project.version}</version>
- <type>xml</type>
+ <type>tar.gz</type>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
diff --git a/performance-tests/src/test/java/org/apache/unomi/performancetests/BasicTest.java b/performance-tests/src/test/java/org/apache/unomi/performancetests/BasicTest.java
index f260109..be3d7fe 100644
--- a/performance-tests/src/test/java/org/apache/unomi/performancetests/BasicTest.java
+++ b/performance-tests/src/test/java/org/apache/unomi/performancetests/BasicTest.java
@@ -80,59 +80,25 @@ public class BasicTest {
@Configuration
public Option[] config() {
MavenArtifactUrlReference karafUrl = maven()
- .groupId("org.apache.karaf")
- .artifactId("apache-karaf")
- .version("4.1.5")
- .type("tar.gz");
-
- MavenUrlReference karafStandardRepo = maven()
- .groupId("org.apache.karaf.features")
- .artifactId("standard")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafPaxWebRepo = maven()
- .groupId("org.ops4j.pax.web")
- .artifactId("pax-web-features")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafSpringRepo = maven()
- .groupId("org.apache.karaf.features")
- .artifactId("spring")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafCxfRepo = maven()
- .groupId("org.apache.cxf.karaf")
- .artifactId("apache-cxf")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference karafEnterpriseRepo = maven()
- .groupId("org.apache.karaf.features")
- .artifactId("enterprise")
- .classifier("features")
- .type("xml")
- .versionAsInProject();
- MavenUrlReference contextServerRepo = maven()
.groupId("org.apache.unomi")
- .artifactId("unomi-kar")
- .classifier("features")
- .type("xml")
+ .artifactId("unomi")
+ .type("tar.gz")
.versionAsInProject();
+ String localRepository = System.getProperty("org.ops4j.pax.url.mvn.localRepository");
+ if (localRepository == null) {
+ localRepository = "";
+ }
+
return new Option[]{
KarafDistributionOption.debugConfiguration("5005", false),
+ KarafDistributionOption.logLevel(LogLevel.INFO),
+ KarafDistributionOption.editConfigurationFilePut("etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.localRepository", localRepository),
karafDistributionConfiguration()
.frameworkUrl(karafUrl)
.unpackDirectory(new File("target/exam"))
.useDeployFolder(false),
keepRuntimeFolder(),
- KarafDistributionOption.features(karafStandardRepo, "wrap")
- KarafDistributionOption.features(karafPaxWebRepo, "war"),
- KarafDistributionOption.features(karafCxfRepo, "cxf"),
- KarafDistributionOption.features(contextServerRepo, "unomi-kar"),
// we need to wrap the HttpComponents libraries ourselves since the OSGi bundles provided by the project are incorrect
wrappedBundle(mavenBundle("org.apache.httpcomponents",
"httpcore").versionAsInProject()),
diff --git a/plugins/request/pom.xml b/plugins/request/pom.xml
index 6c91d13..9fde026 100644
--- a/plugins/request/pom.xml
+++ b/plugins/request/pom.xml
@@ -30,6 +30,14 @@
<description>Request reading actions plugin for the Apache Unomi Context Server</description>
<packaging>bundle</packaging>
+ <properties>
+ <yauaa.version>5.9</yauaa.version>
+ <kryo.version>2.24.0</kryo.version>
+ <minlog.version>1.3.1</minlog.version>
+ <prefixmap>1.1</prefixmap>
+ <objenesis.version>2.1</objenesis.version>
+ </properties>
+
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
@@ -43,18 +51,6 @@
</dependency>
<dependency>
- <groupId>net.sf.uadetector</groupId>
- <artifactId>uadetector-resources</artifactId>
- <version>2014.11-jahia1</version>
- </dependency>
-
- <dependency>
- <groupId>net.sf.uadetector</groupId>
- <artifactId>uadetector-core</artifactId>
- <version>0.9.23-jahia1</version>
- </dependency>
-
- <dependency>
<groupId>net.sf.qualitycheck</groupId>
<artifactId>quality-check</artifactId>
<version>1.3</version>
@@ -104,6 +100,66 @@
<version>1.3</version>
</dependency>
+ <dependency>
+ <groupId>nl.basjes.parse.useragent</groupId>
+ <artifactId>yauaa</artifactId>
+ <version>${yauaa.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.esotericsoftware.kryo</groupId>
+ <artifactId>kryo</artifactId>
+ <version>${kryo.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.esotericsoftware</groupId>
+ <artifactId>minlog</artifactId>
+ <version>${minlog.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>nl.basjes.collections</groupId>
+ <artifactId>prefixmap</artifactId>
+ <version>1.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-text</artifactId>
+ <version>1.6</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-collections4</artifactId>
+ <version>4.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.objenesis</groupId>
+ <artifactId>objenesis</artifactId>
+ <version>${objenesis.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.6.6</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
@@ -120,6 +176,12 @@
org.apache.log;resolution:=optional,
org.apache.log4j;resolution:=optional,
sun.misc;resolution:=optional,
+ sun.nio.ch;resolution:=optional,
+ kotlin.reflect;resolution:=optional,
+ kotlin.reflect.jvm;resolution:=optional,
+ nl.basjes.shaded.com.google.errorprone.annotations;resolution:=optional,
+ nl.basjes.shaded.com.google.errorprone.annotations.concurrent;resolution:=optional,
+ org.checkerframework.checker.nullness.qual;resolution:=optional,
*
</Import-Package>
</instructions>
diff --git a/plugins/request/src/main/java/org/apache/unomi/plugins/request/actions/SetRemoteHostInfoAction.java b/plugins/request/src/main/java/org/apache/unomi/plugins/request/actions/SetRemoteHostInfoAction.java
index 05687e8..cc1c5ae 100644
--- a/plugins/request/src/main/java/org/apache/unomi/plugins/request/actions/SetRemoteHostInfoAction.java
+++ b/plugins/request/src/main/java/org/apache/unomi/plugins/request/actions/SetRemoteHostInfoAction.java
@@ -20,20 +20,6 @@ package org.apache.unomi.plugins.request.actions;
import com.maxmind.geoip2.DatabaseReader;
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.CityResponse;
-import net.sf.uadetector.ReadableUserAgent;
-import net.sf.uadetector.UserAgentStringParser;
-import net.sf.uadetector.service.UADetectorServiceFactory;
-import org.apache.http.conn.util.InetAddressUtils;
-import org.apache.unomi.api.Event;
-import org.apache.unomi.api.Session;
-import org.apache.unomi.api.actions.Action;
-import org.apache.unomi.api.actions.ActionExecutor;
-import org.apache.unomi.api.services.EventService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.PostConstruct;
-import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
@@ -42,10 +28,24 @@ import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.http.conn.util.InetAddressUtils;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.actions.Action;
+import org.apache.unomi.api.actions.ActionExecutor;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.plugins.request.useragent.UserAgent;
+import org.apache.unomi.plugins.request.useragent.UserAgentDetectorServiceImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class SetRemoteHostInfoAction implements ActionExecutor {
private static final Logger logger = LoggerFactory.getLogger(SetRemoteHostInfoAction.class.getName());
+ private UserAgentDetectorServiceImpl userAgentDetectorService;
+
private DatabaseReader databaseReader;
private String pathToGeoLocationDatabase;
@@ -58,6 +58,14 @@ public class SetRemoteHostInfoAction implements ActionExecutor {
private double defaultLatitude = 46.1884341;
private double defaultLongitude = 6.1282508;
+ public UserAgentDetectorServiceImpl getUserAgentDetectorService() {
+ return userAgentDetectorService;
+ }
+
+ public void setUserAgentDetectorService(UserAgentDetectorServiceImpl userAgentDetectorService) {
+ this.userAgentDetectorService = userAgentDetectorService;
+ }
+
public void setPathToGeoLocationDatabase(String pathToGeoLocationDatabase) {
this.pathToGeoLocationDatabase = pathToGeoLocationDatabase;
}
@@ -150,14 +158,14 @@ public class SetRemoteHostInfoAction implements ActionExecutor {
logger.error("Cannot lookup IP", e);
}
- UserAgentStringParser parser = UADetectorServiceFactory.getResourceModuleParser();
- ReadableUserAgent agent = parser.parse(httpServletRequest.getHeader("User-Agent"));
- session.setProperty("operatingSystemFamily", agent.getOperatingSystem().getFamilyName());
- session.setProperty("operatingSystemName", agent.getOperatingSystem().getName());
- session.setProperty("userAgentName", agent.getName());
- session.setProperty("userAgentVersion", agent.getVersionNumber().toVersionString());
- session.setProperty("userAgentNameAndVersion", session.getProperty("userAgentName") + "@@" + session.getProperty("userAgentVersion"));
- session.setProperty("deviceCategory", agent.getDeviceCategory().getName());
+
+ UserAgent agent =userAgentDetectorService.parseUserAgent(httpServletRequest.getHeader("User-Agent"));
+ session.setProperty("operatingSystemFamily", agent.getOperatingSystemFamily());
+ session.setProperty("operatingSystemName", agent.getOperatingSystemName());
+ session.setProperty("userAgentName", agent.getUserAgentName());
+ session.setProperty("userAgentVersion", agent.getUserAgentVersion());
+ session.setProperty("userAgentNameAndVersion", agent.getUserAgentNameAndVersion());
+ session.setProperty("deviceCategory", agent.getDeviceCategory());
return EventService.SESSION_UPDATED;
}
diff --git a/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgent.java b/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgent.java
new file mode 100644
index 0000000..69f83b8
--- /dev/null
+++ b/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgent.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.unomi.plugins.request.useragent;
+
+/**
+ * Basic information about a User Agent
+ */
+public class UserAgent {
+
+ private String operatingSystemFamily;
+ private String operatingSystemName;
+ private String userAgentName;
+ private String userAgentVersion;
+ private String deviceCategory;
+
+ public String getOperatingSystemFamily() {
+ return operatingSystemFamily;
+ }
+
+ public void setOperatingSystemFamily(String operatingSystemFamily) {
+ this.operatingSystemFamily = operatingSystemFamily;
+ }
+
+ public String getOperatingSystemName() {
+ return operatingSystemName;
+ }
+
+ public void setOperatingSystemName(String operatingSystemName) {
+ this.operatingSystemName = operatingSystemName;
+ }
+
+ public String getUserAgentName() {
+ return userAgentName;
+ }
+
+ public void setUserAgentName(String userAgentName) {
+ this.userAgentName = userAgentName;
+ }
+
+ public String getUserAgentVersion() {
+ return userAgentVersion;
+ }
+
+ public void setUserAgentVersion(String userAgentVersion) {
+ this.userAgentVersion = userAgentVersion;
+ }
+
+ public String getDeviceCategory() {
+ return deviceCategory;
+ }
+
+ public void setDeviceCategory(String deviceCategory) {
+ this.deviceCategory = deviceCategory;
+ }
+
+ public String getUserAgentNameAndVersion() {
+ return this.userAgentName + "@@" + this.userAgentVersion;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("User-Agent { \n");
+ sb.append("agent.name: " + this.getUserAgentName() + ",\n");
+ sb.append("agent.version: " + this.getUserAgentVersion() + ",\n");
+ sb.append("operatingsystem.family: " + this.getOperatingSystemFamily() + ",\n");
+ sb.append("operatingsystem.name: " + this.getOperatingSystemName() + ",\n");
+ sb.append("device.category: " + this.getDeviceCategory() + " \n}");
+ return super.toString();
+ }
+}
diff --git a/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgentDetectorServiceImpl.java b/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgentDetectorServiceImpl.java
new file mode 100644
index 0000000..cba6a3f
--- /dev/null
+++ b/plugins/request/src/main/java/org/apache/unomi/plugins/request/useragent/UserAgentDetectorServiceImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.unomi.plugins.request.useragent;
+
+import nl.basjes.parse.useragent.UserAgentAnalyzer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author fpapon@apache.org
+ */
+public class UserAgentDetectorServiceImpl {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserAgentDetectorServiceImpl.class.getName());
+
+ private UserAgentAnalyzer userAgentAnalyzer;
+
+ public void postConstruct() {
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+ this.userAgentAnalyzer = UserAgentAnalyzer
+ .newBuilder()
+ .hideMatcherLoadStats()
+ .withCache(10000)
+ .withField(nl.basjes.parse.useragent.UserAgent.OPERATING_SYSTEM_CLASS)
+ .withField(nl.basjes.parse.useragent.UserAgent.OPERATING_SYSTEM_NAME)
+ .withField(nl.basjes.parse.useragent.UserAgent.AGENT_NAME)
+ .withField(nl.basjes.parse.useragent.UserAgent.AGENT_VERSION)
+ .withField(nl.basjes.parse.useragent.UserAgent.DEVICE_CLASS)
+ .build();
+ this.userAgentAnalyzer.immediateInitialization();
+ this.userAgentAnalyzer.initializeMatchers();
+ } finally {
+ Thread.currentThread().setContextClassLoader(tccl);
+ }
+ logger.info("UserAgentDetector service initialized.");
+ }
+
+ public void preDestroy() {
+ userAgentAnalyzer = null;
+ logger.info("UserAgentDetector service shutdown.");
+ }
+
+ public UserAgent parseUserAgent(String header) {
+ nl.basjes.parse.useragent.UserAgent yauaaAgent = userAgentAnalyzer.parse(header);
+
+ UserAgent userAgent = new UserAgent();
+ userAgent.setDeviceCategory(yauaaAgent.getValue(nl.basjes.parse.useragent.UserAgent.DEVICE_CLASS));
+ userAgent.setOperatingSystemFamily(yauaaAgent.getValue(nl.basjes.parse.useragent.UserAgent.OPERATING_SYSTEM_CLASS));
+ userAgent.setOperatingSystemName(yauaaAgent.getValue(nl.basjes.parse.useragent.UserAgent.OPERATING_SYSTEM_NAME));
+ userAgent.setUserAgentName(yauaaAgent.getValue(nl.basjes.parse.useragent.UserAgent.AGENT_NAME));
+ userAgent.setUserAgentVersion(yauaaAgent.getValue(nl.basjes.parse.useragent.UserAgent.AGENT_VERSION));
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(userAgent.toString());
+ }
+
+ return userAgent;
+ }
+}
diff --git a/plugins/request/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/plugins/request/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 7411399..9b48229 100644
--- a/plugins/request/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/plugins/request/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -67,6 +67,8 @@
</service-properties>
<bean class="org.apache.unomi.plugins.request.actions.SetRemoteHostInfoAction"
init-method="postConstruct">
+ <property name="userAgentDetectorService" ref="userAgentDetectorServiceImpl"/>
+
<property name="pathToGeoLocationDatabase" value="${request.ipDatabase.location}"/>
<property name="defaultSessionCountryCode" value="${defaultSessionCountryCode}"/>
@@ -81,4 +83,8 @@
</bean>
</service>
+ <bean id="userAgentDetectorServiceImpl" class="org.apache.unomi.plugins.request.useragent.UserAgentDetectorServiceImpl"
+ init-method="postConstruct" destroy-method="preDestroy">
+ </bean>
+
</blueprint>
diff --git a/plugins/request/src/test/java/org/apache/unomi/plugins/request/actions/UserAgentDetectorTest.java b/plugins/request/src/test/java/org/apache/unomi/plugins/request/actions/UserAgentDetectorTest.java
new file mode 100644
index 0000000..4733c4e
--- /dev/null
+++ b/plugins/request/src/test/java/org/apache/unomi/plugins/request/actions/UserAgentDetectorTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.unomi.plugins.request.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.apache.unomi.plugins.request.useragent.UserAgent;
+import org.apache.unomi.plugins.request.useragent.UserAgentDetectorServiceImpl;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class UserAgentDetectorTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(UserAgentDetectorTest.class);
+
+ private UserAgentDetectorServiceImpl userAgentDetectorService;
+
+ @Before
+ public void init() {
+ long start = System.currentTimeMillis();
+ this.userAgentDetectorService = new UserAgentDetectorServiceImpl();
+ this.userAgentDetectorService.postConstruct();
+ long end = System.currentTimeMillis();
+ logger.info("Duration starting user agent (in msec) > {}", (end - start));
+ }
+
+ @After
+ public void end() {
+ this.userAgentDetectorService.preDestroy();
+ }
+
+ @Test
+ public void testFirstUserAgentDetection() {
+ String header = "Mozilla/5.0 (Linux; Android 7.0; Nexus 6 Build/NBD90Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36";
+
+ long start = System.currentTimeMillis();
+ UserAgent agent = this.userAgentDetectorService.parseUserAgent(header);
+ long end = System.currentTimeMillis();
+ logger.info("Duration user agent parsing (in msec) > {}", (end - start));
+ logger.info(agent.toString());
+ }
+
+ @Test
+ public void testUserAgentDetectionPerformance() throws InterruptedException {
+ int workerCount = 5000000;
+ ExecutorService executorService = Executors.newFixedThreadPool(3000);
+
+ for (int cpt = 1; cpt < 6; cpt++) {
+ logger.info("Execution " + cpt + "/5");
+ executeWorker(executorService, workerCount);
+ }
+ }
+
+ private void executeWorker(ExecutorService executorService, int workerCount) throws InterruptedException {
+ List<Callable<Object>> callables = new ArrayList<>(workerCount);
+ long startTime = System.currentTimeMillis();
+ for (int i = 0; i < workerCount; i++) {
+ callables.add(new AgentWorker(this.userAgentDetectorService));
+ }
+ executorService.invokeAll(callables);
+ long totalTime = System.currentTimeMillis() - startTime;
+ logger.info("AgentWorker workers completed execution in " + totalTime + "ms");
+ }
+
+ private class AgentWorker implements Callable<Object> {
+
+ String header = "Mozilla/5.0 (Linux; Android 7.0; Nexus 6 Build/NBD90Z) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36";
+ UserAgentDetectorServiceImpl service;
+
+ public AgentWorker(UserAgentDetectorServiceImpl userAgentDetectorService) {
+ this.service = userAgentDetectorService;
+ }
+
+ @Override
+ public Object call() {
+ this.service.parseUserAgent(header);
+ return null;
+ }
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 8ba671b..67f51f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,6 +83,7 @@
<!-- Librairies for Karaf packaging -->
<xerces.version>2.11.0_1</xerces.version>
<servicemix.specs.version>2.9.0</servicemix.specs.version>
+ <jsr305.bundle.version>3.0.2_1</jsr305.bundle.version>
<xalan.bundle.version>2.7.2_3</xalan.bundle.version>
<xalan-serializer.bundle.version>2.7.2_1</xalan-serializer.bundle.version>
<jna.version>4.5.0</jna.version>
@@ -281,10 +282,6 @@
<name>Apache ServiceMix M2</name>
<url>http://svn.apache.org/repos/asf/servicemix/m2-repo/</url>
</repository>
- <repository>
- <id>jahia.3rdparty</id>
- <url>https://devtools.jahia.com/nexus/content/repositories/thirdparty-releases/</url>
- </repository>
<!-- Apache snapshots -->
<repository>
<id>apache-snapshots</id>
@@ -323,6 +320,35 @@
</profile>
<profile>
+ <id>ci-build-itests</id>
+ <activation>
+ <property>
+ <name>maven.repo.local</name>
+ </property>
+ </activation>
+ <modules>
+ <module>itests</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>MavenTest</exclude>
+ </excludes>
+ <systemPropertyVariables>
+ <org.ops4j.pax.url.mvn.localRepository>${maven.repo.local}</org.ops4j.pax.url.mvn.localRepository>
+ <org.ops4j.pax.logging.DefaultServiceLog.level>INFO</org.ops4j.pax.logging.DefaultServiceLog.level>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
<id>performance-tests</id>
<activation>
<activeByDefault>false</activeByDefault>
diff --git a/services/pom.xml b/services/pom.xml
index 7c494ef..fa6e67d 100644
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -139,6 +139,20 @@
<version>4.3.0</version>
</dependency>
+ <!-- Unit tests -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.6.6</version>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
<build>
diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 9569e67..e09a38b 100644
--- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -382,5 +382,4 @@
</service-properties>
</service>
-
</blueprint>