/* * Copyright 2012 - 2014 Anton Tananaev (anton.tananaev@gmail.com) * * Licensed 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.traccar.model; import java.io.File; import java.io.StringReader; import java.net.URL; import java.net.URLClassLoader; import java.sql.*; import java.util.*; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.traccar.helper.AdvancedConnection; import org.traccar.helper.DriverDelegate; import org.traccar.helper.Log; import org.traccar.helper.NamedParameterStatement; import org.xml.sax.InputSource; /** * Database abstraction class */ public class DatabaseDataManager implements DataManager { public DatabaseDataManager(Properties properties) throws Exception { initDatabase(properties); } /** * Database statements */ private NamedParameterStatement queryGetDevices; private NamedParameterStatement queryAddPosition; private NamedParameterStatement queryUpdateLatestPosition; private String queryAddPositionTemplate; private String queryUpdateLatestPositionTemplate; private AdvancedConnection globalConnection; /** * Initialize database */ private void initDatabase(Properties properties) throws Exception { // Load driver String driver = properties.getProperty("database.driver"); if (driver != null) { String driverFile = properties.getProperty("database.driverFile"); if (driverFile != null) { URL url = new URL("jar:file:" + new File(driverFile).getAbsolutePath() + "!/"); URLClassLoader cl = new URLClassLoader(new URL[]{url}); Driver d = (Driver) Class.forName(driver, true, cl).newInstance(); DriverManager.registerDriver(new DriverDelegate(d)); } else { Class.forName(driver); } } // Connect database String url = properties.getProperty("database.url"); String user = properties.getProperty("database.user"); String password = properties.getProperty("database.password"); AdvancedConnection connection = new AdvancedConnection(url, user, password); globalConnection = connection; // Load statements from configuration String query; query = properties.getProperty("database.selectDevice"); if (query != null) { queryGetDevices = new NamedParameterStatement(connection, query); } query = properties.getProperty("database.insertPosition"); queryAddPositionTemplate = query; if (query != null) { queryAddPosition = new NamedParameterStatement(connection, query); } query = properties.getProperty("database.updateLatestPosition"); queryUpdateLatestPositionTemplate = query; if (query != null) { queryUpdateLatestPosition = new NamedParameterStatement(connection, query); } } @Override public synchronized List getDevices() throws SQLException { List deviceList = new LinkedList(); if (queryGetDevices != null) { queryGetDevices.prepare(); ResultSet result = queryGetDevices.executeQuery(); while (result.next()) { Device device = new Device(); device.setId(result.getLong("id")); device.setImei(result.getString("imei")); device.setDatabase(result.getString("database")); deviceList.add(device); } } return deviceList; } /** * Devices cache */ private Map devices; private Map devices_id; @Override public Device getDeviceByImei(String imei) throws SQLException { if (devices == null || !devices.containsKey(imei)) { devices = new HashMap(); for (Device device : getDevices()) { devices.put(device.getImei(), device); } } return devices.get(imei); } @Override public Device getDeviceById(Long id) throws SQLException { if (devices_id == null || !devices_id.containsKey(id)) { devices_id = new HashMap(); for (Device device : getDevices()) { devices_id.put(device.getId(), device); } } return devices_id.get(id); } @Override public synchronized Long addPosition(Position position) throws SQLException { if (queryAddPositionTemplate.contains("_database_")) { String query = queryAddPositionTemplate; query = query.replace("_database_", this.getDeviceById(position.getDeviceId()).getDatabase()); if (query != null) { queryAddPosition = new NamedParameterStatement(globalConnection, query); } } if (queryAddPosition != null) { queryAddPosition.prepare(Statement.RETURN_GENERATED_KEYS); queryAddPosition.setLong("device_id", position.getDeviceId()); queryAddPosition.setTimestamp("time", position.getTime()); queryAddPosition.setBoolean("valid", position.getValid()); queryAddPosition.setDouble("altitude", position.getAltitude()); queryAddPosition.setDouble("latitude", position.getLatitude()); queryAddPosition.setDouble("longitude", position.getLongitude()); queryAddPosition.setDouble("speed", position.getSpeed()); queryAddPosition.setDouble("course", position.getCourse()); queryAddPosition.setString("address", position.getAddress()); queryAddPosition.setString("extended_info", position.getExtendedInfo()); // DELME: Temporary compatibility support XPath xpath = XPathFactory.newInstance().newXPath(); try { InputSource source = new InputSource(new StringReader(position.getExtendedInfo())); String index = xpath.evaluate("/info/index", source); if (!index.isEmpty()) { queryAddPosition.setLong("id", Long.valueOf(index)); } else { queryAddPosition.setLong("id", null); } source = new InputSource(new StringReader(position.getExtendedInfo())); String power = xpath.evaluate("/info/power", source); if (!power.isEmpty()) { queryAddPosition.setDouble("power", Double.valueOf(power)); } else { queryAddPosition.setLong("power", null); } } catch (XPathExpressionException e) { Log.warning("Error in XML: " + position.getExtendedInfo(), e); queryAddPosition.setLong("id", null); queryAddPosition.setLong("power", null); } queryAddPosition.executeUpdate(); ResultSet result = queryAddPosition.getGeneratedKeys(); if (result != null && result.next()) { return result.getLong(1); } } return null; } @Override public void updateLatestPosition(Position position, Long positionId ) throws SQLException { if (queryUpdateLatestPositionTemplate.contains("_database_")) { String query = queryUpdateLatestPositionTemplate; query = query.replace("_database_", this.getDeviceById(position.getDeviceId()).getDatabase()); if (query != null) { queryUpdateLatestPosition = new NamedParameterStatement(globalConnection, query); } } if (queryUpdateLatestPosition != null) { queryUpdateLatestPosition.prepare(); queryUpdateLatestPosition.setLong("device_id", position.getDeviceId()); queryUpdateLatestPosition.setLong("id", positionId); queryUpdateLatestPosition.setTimestamp("time", position.getTime()); queryUpdateLatestPosition.setBoolean("valid", position.getValid()); queryUpdateLatestPosition.setDouble("altitude", position.getAltitude()); queryUpdateLatestPosition.setDouble("latitude", position.getLatitude()); queryUpdateLatestPosition.setDouble("longitude", position.getLongitude()); queryUpdateLatestPosition.setDouble("speed", position.getSpeed()); queryUpdateLatestPosition.setDouble("course", position.getCourse()); queryUpdateLatestPosition.setString("address", position.getAddress()); queryUpdateLatestPosition.setString("extended_info", position.getExtendedInfo()); // DELME: Temporary compatibility support XPath xpath = XPathFactory.newInstance().newXPath(); try { InputSource source = new InputSource(new StringReader(position.getExtendedInfo())); String index = xpath.evaluate("/info/index", source); if (!index.isEmpty()) { queryUpdateLatestPosition.setLong("id", Long.valueOf(index)); } else { queryUpdateLatestPosition.setLong("id", null); } source = new InputSource(new StringReader(position.getExtendedInfo())); String power = xpath.evaluate("/info/power", source); if (!power.isEmpty()) { queryUpdateLatestPosition.setDouble("power", Double.valueOf(power)); } else { queryUpdateLatestPosition.setLong("power", null); } } catch (XPathExpressionException e) { Log.warning("Error in XML: " + position.getExtendedInfo(), e); queryUpdateLatestPosition.setLong("id", null); queryUpdateLatestPosition.setLong("power", null); } queryUpdateLatestPosition.executeUpdate(); } } }