Skip to content

Commit

Permalink
'#1487 First version of nominating task that queries a configured
Browse files Browse the repository at this point in the history
nominatim
server for a related address of a georeferenced item.
  • Loading branch information
patrickdalla committed Jul 10, 2023
1 parent 3ae5c93 commit 967fbd9
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 4 deletions.
1 change: 1 addition & 0 deletions iped-api/src/main/java/iped/localization/Messages.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static ResourceBundle getExternalBundle(String bundleName, Locale locale)
} catch (URISyntaxException e1) {
e1.printStackTrace();
}
file = new File(System.getProperty("user.dir")+ "/iped/localization");
if (file != null && !file.exists()) {
File baseFile = new File(System.getProperty("user.dir"));
do {
Expand Down
8 changes: 6 additions & 2 deletions iped-app/resources/config/IPEDConfig.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ enableAudioTranscription = false
# Enables carving. "addUnallocated" must be enabled to unallocated area be searched.
# By default carving runs on almost every item in the case.
# File types to be searched and retrieved can be set in file "conf/CarvingConfig.txt"
enableCarving = false
enableCarving = true

# Enables carving that retrieves known files from the LED base, based on the beginning (64K) of the file.
# It's necessary to enable "addUnallocated" and to configure "hashesDB" (with LED hashes data imported).
Expand Down Expand Up @@ -133,6 +133,10 @@ enableVideoThumbs = true
# Advanced configurations can be found at conf/DocThumbsConfig.txt.
enableDocThumbs = false

# Enables nominatim address resolving of geo locations
# Server settings can be modified in file "conf/NominatimConfig.txt"
enableNominatimLocationResolving = true

# Enables HTML report generation on automatic extractions or from selected items.
# Generation settings can be modified in file "conf/HTMLReportConfig.txt"
enableHTMLReport = true
enableHTMLReport = true
14 changes: 14 additions & 0 deletions iped-app/resources/config/conf/NominatimConfig.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#host name of the nominatim server
hostName=10.65.6.2

#port of the nominatim server service
hostPort=8080

#protocol of the nominatim server service (http or https)
protocol=http

#protocol of the nominatim server service (http or https)
connectionPoolSize=auto

#Query to be passed via URL to test if service is available at task init
serviceTestUrlQuery=/?country=brazil
2 changes: 1 addition & 1 deletion iped-app/resources/config/conf/TaskInstaller.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
<task class="iped.engine.task.PhotoDNALookup"></task>
<task script="NSFWNudityDetectTask.py"></task>
<task script="FaceRecognitionTask.py"></task>
<task script="SearchHardwareWallets.py"></task>

<!--Carving must be installed before IndexTask because it sets hasChildren property in parent items-->
<task class="iped.engine.task.carver.LedCarveTask"></task>
Expand All @@ -49,6 +48,7 @@

<task class="iped.engine.task.FragmentLargeBinaryTask"></task>
<task class="iped.engine.task.EntropyTask"></task>
<task class="iped.geo.nominatim.NominatimTask"></task>
<task class="iped.engine.task.MinIOTask"></task>
<task class="iped.engine.task.index.ElasticSearchIndexTask"></task>
<task class="iped.engine.task.index.IndexTask"></task>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ public void processTaskConfig(Path resource) throws IOException {
processProperties(properties);
}

abstract void processProperties(UTF8Properties properties);
public abstract void processProperties(UTF8Properties properties);

}
86 changes: 86 additions & 0 deletions iped-geo/src/main/java/iped/geo/nominatim/NominatimConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package iped.geo.nominatim;

import iped.engine.config.AbstractTaskPropertiesConfig;
import iped.utils.UTF8Properties;

public class NominatimConfig extends AbstractTaskPropertiesConfig {
private static final long serialVersionUID = 1L;

public static final String ENABLE_PARAM = "enableNominatimLocationResolving";
private static final String CONF_FILE = "NominatimConfig.txt";

String protocol = "http";
String hostName = "10.65.6.2";
String hostPort = "8080";
int connectionPoolSize;
String serviceTestUrlQuery = "/";

private boolean enableNominatim = false;

@Override
public void processProperties(UTF8Properties properties) {
String value = properties.getProperty("protocol"); //$NON-NLS-1$
if (value != null) {
protocol = value.trim();
}

value = properties.getProperty("hostName"); //$NON-NLS-1$
if (value != null) {
hostName = value.trim();
}

value = properties.getProperty("serviceTestUrlQuery"); //$NON-NLS-1$
if (value != null) {
serviceTestUrlQuery = value.trim();
}

value = properties.getProperty("hostPort"); //$NON-NLS-1$
if (value != null) {
hostPort = Integer.toString(Integer.valueOf(value.trim()));
}

value = properties.getProperty("connectionPoolSize"); // $NON-NLS-1$
if (value != null && !value.trim().equalsIgnoreCase("auto")) { //$NON-NLS-1$
connectionPoolSize = Integer.valueOf(value.trim());
} else {
connectionPoolSize = Math.max((int) Math.ceil((float) Runtime.getRuntime().availableProcessors()), 2);
}
}

@Override
public String getTaskEnableProperty() {
// TODO Auto-generated method stub
return ENABLE_PARAM;
}

@Override
public String getTaskConfigFileName() {
// TODO Auto-generated method stub
return CONF_FILE;
}

public String getProtocol() {
return protocol;
}

public String getHostName() {
return hostName;
}

public String getHostPort() {
return hostPort;
}

public int getConnectionPoolSize() {
return connectionPoolSize;
}

public boolean isEnableNominatim() {
return enableNominatim;
}

public String getServiceTestUrlQuery() {
return serviceTestUrlQuery;
}

}
190 changes: 190 additions & 0 deletions iped-geo/src/main/java/iped/geo/nominatim/NominatimTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package iped.geo.nominatim;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.http.HeaderElement;
import org.apache.http.HeaderElementIterator;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import iped.configuration.Configurable;
import iped.data.IItem;
import iped.engine.config.ConfigurationManager;
import iped.engine.task.AbstractTask;
import iped.geo.parsers.GeofileParser;
import iped.properties.ExtraProperties;

public class NominatimTask extends AbstractTask {

private static Logger LOGGER = LoggerFactory.getLogger(NominatimTask.class);

static final String NOMINATIM_METADATA = "nominatim:geojson";
protected static final long CUSTOM_KEEP_ALIVE = 5000;

/* The http connection pool is static to be used application wide */
static PoolingHttpClientConnectionManager cm = null;
static ConnectionKeepAliveStrategy myStrategy;
static IdleConnectionMonitorThread staleMonitor;
static CloseableHttpClient httpClient;

AtomicInteger count = new AtomicInteger(0);

static String baseUrl = "";

static boolean unresolvedServer = true;

private NominatimConfig nominatimConfig;

@Override
public List<Configurable<?>> getConfigurables() {
return Arrays.asList(new NominatimConfig());
}

@Override
public void init(ConfigurationManager configurationManager) throws Exception {
count.incrementAndGet();
if (cm == null) {
nominatimConfig = (NominatimConfig) configurationManager.findObject(NominatimConfig.class);

cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(nominatimConfig.getConnectionPoolSize());
myStrategy = new ConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
return Long.parseLong(value) * 1000;
}
}
return CUSTOM_KEEP_ALIVE;
}
};

try {
httpClient = HttpClients.custom().setKeepAliveStrategy(myStrategy)
.setConnectionManager(cm).build();
String defaultTestCountry = "brazil";
baseUrl = nominatimConfig.getProtocol() + "://" + nominatimConfig.getHostName() + ":"
+ nominatimConfig.getHostPort();
HttpGet get = new HttpGet(baseUrl + nominatimConfig.getServiceTestUrlQuery());
try (CloseableHttpResponse response = httpClient.execute(get)) {
unresolvedServer = false;
} catch (ClientProtocolException cpe) {
unresolvedServer = true;
}
} catch (Exception e) {
unresolvedServer = true;
}

/* thread to monitor connections closed by the host */
staleMonitor = new IdleConnectionMonitorThread(cm);
staleMonitor.start();
}
}

@Override
public void finish() throws Exception {
int remaining = count.decrementAndGet();

if (remaining == 0) {
httpClient.close();
staleMonitor.shutdown();
cm.shutdown();
}
}

@Override
protected void process(IItem evidence) throws Exception {
if (!unresolvedServer) {
String featureString = evidence.getMetadata().get(GeofileParser.FEATURE_STRING);

if (featureString == null || featureString.length() < 5) {
String location = evidence.getMetadata().get(ExtraProperties.LOCATIONS);

if (location != null && location.length() >= 1) {
String[] locs = location.split(";"); //$NON-NLS-1$
String lat = locs[0].trim();
String longit = locs[1].trim();

try {
HttpGet get = new HttpGet(baseUrl + "/reverse?format=geojson&lat=" + lat + "&lon=" + longit);
try (CloseableHttpResponse response = httpClient.execute(get)) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()))) {
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}

evidence.getMetadata().add(NOMINATIM_METADATA, content.toString());
}
}
} catch (ClientProtocolException cpe) {
cpe.printStackTrace();
LOGGER.warn(cpe.getMessage());
} catch (Exception e) {
LOGGER.warn(e.getMessage());
e.printStackTrace();
}
}
}
}
}

class IdleConnectionMonitorThread extends Thread {
private final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;

public IdleConnectionMonitorThread(PoolingHttpClientConnectionManager connMgr) {
super();
this.connMgr = connMgr;
}

@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(CUSTOM_KEEP_ALIVE);
connMgr.closeExpiredConnections();
connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
shutdown();
}
}

public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}

}

0 comments on commit 967fbd9

Please sign in to comment.