aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2015-05-02 18:51:34 +1200
committerAnton Tananaev <anton.tananaev@gmail.com>2015-05-02 18:51:34 +1200
commitaf72af207613c80b8d66814d30644e4228e9b9e6 (patch)
tree56409810df0967976dce60799180fbee41e82439
parent44da47950bdd75be57714158fd8a6d59c94460b5 (diff)
downloadtrackermap-server-af72af207613c80b8d66814d30644e4228e9b9e6.tar.gz
trackermap-server-af72af207613c80b8d66814d30644e4228e9b9e6.tar.bz2
trackermap-server-af72af207613c80b8d66814d30644e4228e9b9e6.zip
Refactor data manager code
-rw-r--r--src/org/traccar/database/DataManager.java342
-rw-r--r--src/org/traccar/database/ObjectConverter.java19
-rw-r--r--src/org/traccar/database/PermissionsManager.java5
-rw-r--r--src/org/traccar/database/QueryBuilder.java310
-rw-r--r--src/org/traccar/database/ResultSetConverter.java80
-rw-r--r--src/org/traccar/http/DeviceServlet.java4
-rw-r--r--src/org/traccar/model/Device.java7
-rw-r--r--src/org/traccar/model/Factory.java22
-rw-r--r--src/org/traccar/model/Permission.java33
-rw-r--r--web/DeviceDialog.js72
10 files changed, 573 insertions, 321 deletions
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index 33de88876..5473c6c77 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -17,21 +17,16 @@ package org.traccar.database;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.io.File;
-import java.io.StringReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.*;
import java.util.*;
import javax.json.JsonArray;
import javax.sql.DataSource;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
import org.traccar.helper.DriverDelegate;
-import org.traccar.helper.Log;
import org.traccar.model.Device;
+import org.traccar.model.Permission;
import org.traccar.model.Position;
-import org.xml.sax.InputSource;
public class DataManager {
@@ -198,109 +193,98 @@ public class DataManager {
private void createDatabaseSchema() throws SQLException {
Connection connection = dataSource.getConnection();
- try {
- Statement statement = connection.createStatement();
- try {
-
- ResultSet result = connection.getMetaData().getTables(
- connection.getCatalog(), null, null, null);
-
- boolean exist = false;
- while (result.next()) {
- if (result.getString("TABLE_NAME").equalsIgnoreCase("traccar1")) {
- exist = true;
- break;
- }
- }
-
- if (!exist) {
-
- statement.executeUpdate(
- "CREATE TABLE user (" +
- "id INT PRIMARY KEY AUTO_INCREMENT," +
- "email VARCHAR(1024) NOT NULL UNIQUE," +
- "password VARCHAR(1024) NOT NULL," +
- "salt VARCHAR(1024) NOT NULL," +
- "readonly BOOLEAN DEFAULT false NOT NULL," +
- "admin BOOLEAN DEFAULT false NOT NULL," +
- "map VARCHAR(1024) DEFAULT 'osm' NOT NULL," +
- "language VARCHAR(1024) DEFAULT 'en' NOT NULL," +
- "distance_unit VARCHAR(1024) DEFAULT 'km' NOT NULL," +
- "speed_unit VARCHAR(1024) DEFAULT 'kmh' NOT NULL," +
- "latitude DOUBLE DEFAULT 0 NOT NULL," +
- "longitude DOUBLE DEFAULT 0 NOT NULL," +
- "zoom INT DEFAULT 0 NOT NULL);" +
-
- "CREATE TABLE device (" +
- "id INT PRIMARY KEY AUTO_INCREMENT," +
- "name VARCHAR(1024) NOT NULL," +
- "unique_id VARCHAR(1024) NOT NULL UNIQUE," +
- "status VARCHAR(1024)," +
- "last_update TIMESTAMP," +
- "position_id INT," +
- "data_id INT);" +
-
- "CREATE TABLE user_device (" +
- "user_id INT NOT NULL," +
- "device_id INT NOT NULL," +
- "read BOOLEAN DEFAULT true NOT NULL," +
- "write BOOLEAN DEFAULT true NOT NULL," +
- "FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE," +
- "FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE);" +
-
- "CREATE INDEX user_device_user_id ON user_device(user_id);" +
-
- "CREATE TABLE position (" +
- "id INT PRIMARY KEY AUTO_INCREMENT," +
- "protocol VARCHAR(1024)," +
- "device_id INT NOT NULL," +
- "server_time TIMESTAMP NOT NULL," +
- "device_time TIMESTAMP NOT NULL," +
- "fix_time TIMESTAMP NOT NULL," +
- "valid BOOLEAN NOT NULL," +
- "latitude DOUBLE NOT NULL," +
- "longitude DOUBLE NOT NULL," +
- "altitude DOUBLE NOT NULL," +
- "speed DOUBLE NOT NULL," +
- "course DOUBLE NOT NULL," +
- "address VARCHAR(1024)," +
- "other VARCHAR(8192) NOT NULL," +
- "FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE);" +
-
- "CREATE TABLE data (" +
- "id INT PRIMARY KEY AUTO_INCREMENT," +
- "protocol VARCHAR(1024)," +
- "device_id INT NOT NULL," +
- "server_time TIMESTAMP NOT NULL," +
- "device_time TIMESTAMP NOT NULL," +
- "other VARCHAR(8192) NOT NULL," +
- "FOREIGN KEY (device_id) REFERENCES device(id));" +
-
- "ALTER TABLE device ADD " +
- "FOREIGN KEY (position_id) REFERENCES position(id);" +
-
- "ALTER TABLE device ADD " +
- "FOREIGN KEY (data_id) REFERENCES data(id);" +
-
- "CREATE TABLE server (" +
- "id INT PRIMARY KEY AUTO_INCREMENT," +
- "registration BOOLEAN NOT NULL," +
- "latitude DOUBLE NOT NULL," +
- "longitude DOUBLE NOT NULL," +
- "zoom INT NOT NULL);" +
-
- "CREATE TABLE traccar1 (" +
- "id INT PRIMARY KEY AUTO_INCREMENT);");
-
- addUser("admin", "admin", true);
- }
-
- } finally {
- statement.close();
+ ResultSet result = connection.getMetaData().getTables(
+ connection.getCatalog(), null, null, null);
+
+ boolean exist = false;
+ while (result.next()) {
+ if (result.getString("TABLE_NAME").equalsIgnoreCase("traccar1")) {
+ exist = true;
+ break;
}
- } finally {
- connection.close();
}
+ if (!exist) {
+ return;
+ }
+
+ QueryBuilder.create(dataSource,
+ "CREATE TABLE user (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT," +
+ "email VARCHAR(1024) NOT NULL UNIQUE," +
+ "password VARCHAR(1024) NOT NULL," +
+ "salt VARCHAR(1024) NOT NULL," +
+ "readonly BOOLEAN DEFAULT false NOT NULL," +
+ "admin BOOLEAN DEFAULT false NOT NULL," +
+ "map VARCHAR(1024) DEFAULT 'osm' NOT NULL," +
+ "language VARCHAR(1024) DEFAULT 'en' NOT NULL," +
+ "distanceUnit VARCHAR(1024) DEFAULT 'km' NOT NULL," +
+ "speedUnit VARCHAR(1024) DEFAULT 'kmh' NOT NULL," +
+ "latitude DOUBLE DEFAULT 0 NOT NULL," +
+ "longitude DOUBLE DEFAULT 0 NOT NULL," +
+ "zoom INT DEFAULT 0 NOT NULL);" +
+
+ "CREATE TABLE device (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT," +
+ "name VARCHAR(1024) NOT NULL," +
+ "uniqueId VARCHAR(1024) NOT NULL UNIQUE," +
+ "status VARCHAR(1024)," +
+ "lastUpdate TIMESTAMP," +
+ "positionId INT," +
+ "dataId INT);" +
+
+ "CREATE TABLE user_device (" +
+ "userId INT NOT NULL," +
+ "deviceId INT NOT NULL," +
+ "read BOOLEAN DEFAULT true NOT NULL," +
+ "write BOOLEAN DEFAULT true NOT NULL," +
+ "FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE," +
+ "FOREIGN KEY (deviceId) REFERENCES device(id) ON DELETE CASCADE);" +
+
+ "CREATE INDEX user_device_user_id ON user_device(userId);" +
+
+ "CREATE TABLE position (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT," +
+ "protocol VARCHAR(1024)," +
+ "deviceId INT NOT NULL," +
+ "serverTime TIMESTAMP NOT NULL," +
+ "deviceTime TIMESTAMP NOT NULL," +
+ "fixTime TIMESTAMP NOT NULL," +
+ "valid BOOLEAN NOT NULL," +
+ "latitude DOUBLE NOT NULL," +
+ "longitude DOUBLE NOT NULL," +
+ "altitude DOUBLE NOT NULL," +
+ "speed DOUBLE NOT NULL," +
+ "course DOUBLE NOT NULL," +
+ "address VARCHAR(1024)," +
+ "other VARCHAR(8192) NOT NULL," +
+ "FOREIGN KEY (deviceId) REFERENCES device(id) ON DELETE CASCADE);" +
+
+ "CREATE TABLE data (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT," +
+ "protocol VARCHAR(1024)," +
+ "deviceId INT NOT NULL," +
+ "serverTime TIMESTAMP NOT NULL," +
+ "deviceTime TIMESTAMP NOT NULL," +
+ "other VARCHAR(8192) NOT NULL," +
+ "FOREIGN KEY (deviceId) REFERENCES device(id));" +
+
+ "ALTER TABLE device ADD " +
+ "FOREIGN KEY (positionId) REFERENCES position(id);" +
+
+ "ALTER TABLE device ADD " +
+ "FOREIGN KEY (dataId) REFERENCES data(id);" +
+
+ "CREATE TABLE server (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT," +
+ "registration BOOLEAN NOT NULL," +
+ "latitude DOUBLE NOT NULL," +
+ "longitude DOUBLE NOT NULL," +
+ "zoom INT NOT NULL);" +
+
+ "CREATE TABLE traccar1 (" +
+ "id INT PRIMARY KEY AUTO_INCREMENT);").executeUpdate();
+
+ addUser("admin", "admin", true);
}
public long login(String email, String password) throws SQLException {
@@ -346,137 +330,47 @@ public class DataManager {
}
}
- public Collection<Map.Entry<Long, Long>> getPermissions() throws SQLException {
-
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "SELECT user_id, device_id FROM user_device;");
- try {
- ResultSet resultSet = statement.executeQuery();
-
- List<Map.Entry<Long, Long>> result = new LinkedList<Map.Entry<Long, Long>>();
- while (resultSet.next()) {
- result.add(new AbstractMap.SimpleEntry<Long, Long>(
- resultSet.getLong(1), resultSet.getLong(2)));
- }
-
- return result;
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ public Collection<Permission> getPermissions() throws SQLException {
+ return QueryBuilder.create(dataSource,
+ "SELECT userId, deviceId FROM user_device;")
+ .executeQuery(new Permission());
}
- public JsonArray getDevices(long userId) throws SQLException {
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "SELECT * FROM device WHERE id IN (" +
- "SELECT device_id FROM user_device WHERE user_id = ?);");
- try {
- statement.setLong(1, userId);
-
- ResultSet result = statement.executeQuery();
-
- List<Device> list = new LinkedList<Device>();
- while (result.next()) {
- Device device = new Device();
- device.fromRecord(result);
- list.add(device);
- }
-
- return ObjectConverter.arrayToJson(list);
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ public Collection<Device> getDevices(long userId) throws SQLException {
+ return QueryBuilder.create(dataSource,
+ "SELECT * FROM device WHERE id IN (" +
+ "SELECT deviceId FROM user_device WHERE userId = :userId);")
+ .setLong("userId", userId)
+ .executeQuery(new Device());
}
public void addDevice(Device device) throws SQLException {
-
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "INSERT INTO device (name, unique_id) VALUES (?, ?);",
- Statement.RETURN_GENERATED_KEYS);
- try {
- statement.setString(1, device.getName());
- statement.setString(2, device.getUniqueId());
-
- statement.executeUpdate();
-
- ResultSet result = statement.getGeneratedKeys();
- if (result.next()) {
- device.setId(result.getLong(1));
- }
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ device.setId(QueryBuilder.create(dataSource,
+ "INSERT INTO device (name, uniqueId) VALUES (:name, :uniqueId);")
+ .setObject(device)
+ .executeUpdate());
}
public void updateDevice(Device device) throws SQLException {
-
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "UPDATE device SET name = ?, unique_id = ? WHERE id = ?;");
- try {
- statement.setString(1, device.getName());
- statement.setString(2, device.getUniqueId());
- statement.setLong(3, device.getId());
-
- statement.executeUpdate();
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ QueryBuilder.create(dataSource,
+ "UPDATE device SET name = :name, uniqueId = :uniqueId WHERE id = :id;")
+ .setObject(device)
+ .executeUpdate();
}
public void removeDevice(Device device) throws SQLException {
-
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "DELETE FROM device WHERE id = ?;");
- try {
- statement.setLong(1, device.getId());
-
- statement.executeUpdate();
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ QueryBuilder.create(dataSource,
+ "DELETE FROM device WHERE id = :id;")
+ .setObject(device)
+ .executeUpdate();
}
public void linkDevice(long userId, long deviceId) throws SQLException {
-
- Connection connection = dataSource.getConnection();
- try {
- PreparedStatement statement = connection.prepareStatement(
- "INSERT INTO user_device (user_id, device_id) VALUES (?, ?);");
- try {
- statement.setLong(1, userId);
- statement.setLong(2, deviceId);
-
- statement.executeUpdate();
- } finally {
- statement.close();
- }
- } finally {
- connection.close();
- }
+ QueryBuilder.create(dataSource,
+ "INSERT INTO user_device (userId, deviceId) VALUES (:userId, :deviceId);")
+ .setLong("userId", userId)
+ .setLong("deviceId", deviceId)
+ .executeUpdate();
}
}
diff --git a/src/org/traccar/database/ObjectConverter.java b/src/org/traccar/database/ObjectConverter.java
index 8d6e73123..7852c88f4 100644
--- a/src/org/traccar/database/ObjectConverter.java
+++ b/src/org/traccar/database/ObjectConverter.java
@@ -45,10 +45,6 @@ public class ObjectConverter {
return array.build();
}
- private static String getColumnName(String key) {
- return key.replaceAll("([A-Z])", "_$1").toLowerCase();
- }
-
private static boolean hasColumn(ResultSet resultSet, String columnName) throws SQLException {
ResultSetMetaData metaData = resultSet.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
@@ -67,9 +63,8 @@ public class ObjectConverter {
}
public static String getString(ResultSet record, String key) throws SQLException {
- String column = getColumnName(key);
- if (hasColumn(record, column)) {
- return record.getString(column);
+ if (hasColumn(record, key)) {
+ return record.getString(key);
}
return null;
}
@@ -88,9 +83,8 @@ public class ObjectConverter {
}
public static long getLong(ResultSet record, String key) throws SQLException {
- String column = getColumnName(key);
- if (hasColumn(record, column)) {
- return record.getLong(column);
+ if (hasColumn(record, key)) {
+ return record.getLong(key);
}
return 0;
}
@@ -111,9 +105,8 @@ public class ObjectConverter {
}
public static Date getDate(ResultSet record, String key) throws SQLException {
- String column = getColumnName(key);
- if (hasColumn(record, column)) {
- return record.getDate(column);
+ if (hasColumn(record, key)) {
+ return record.getDate(key);
}
return null;
}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 16ddd336d..e889afb06 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -23,6 +23,7 @@ import java.util.Map;
import java.util.Set;
import org.traccar.Context;
import org.traccar.helper.Log;
+import org.traccar.model.Permission;
public class PermissionsManager {
@@ -42,8 +43,8 @@ public class PermissionsManager {
public final void refresh() {
permissions.clear();
try {
- for (Map.Entry<Long, Long> entry : Context.getDataManager().getPermissions()) {
- getNotNull(entry.getKey()).add(entry.getValue());
+ for (Permission permission : Context.getDataManager().getPermissions()) {
+ getNotNull(permission.getUserId()).add(permission.getDeviceId());
}
} catch (SQLException error) {
Log.warning(error);
diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java
new file mode 100644
index 000000000..29a737f20
--- /dev/null
+++ b/src/org/traccar/database/QueryBuilder.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2015 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.database;
+
+import java.beans.Introspector;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+import org.traccar.model.Factory;
+
+public class QueryBuilder {
+
+ private final Map<String, List<Integer>> indexMap;
+ private final PreparedStatement statement;
+
+ private QueryBuilder(DataSource dataSource, String query) throws SQLException {
+ indexMap = new HashMap<String, List<Integer>>();
+ statement = dataSource.getConnection().prepareStatement(
+ parse(query, indexMap), Statement.RETURN_GENERATED_KEYS);
+ }
+
+ private static String parse(String query, Map<String, List<Integer>> paramMap) {
+
+ int length = query.length();
+ StringBuilder parsedQuery = new StringBuilder(length);
+ boolean inSingleQuote = false;
+ boolean inDoubleQuote = false;
+ int index = 1;
+
+ for (int i = 0; i < length; i++) {
+
+ char c = query.charAt(i);
+
+ // String end
+ if (inSingleQuote) {
+ if (c == '\'') {
+ inSingleQuote = false;
+ }
+ } else if (inDoubleQuote) {
+ if (c == '"') {
+ inDoubleQuote = false;
+ }
+ } else {
+
+ // String begin
+ if (c == '\'') {
+ inSingleQuote = true;
+ } else if (c == '"') {
+ inDoubleQuote = true;
+ } else if (c == ':' && i + 1 < length
+ && Character.isJavaIdentifierStart(query.charAt(i + 1))) {
+
+ // Identifier name
+ int j = i + 2;
+ while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) {
+ j++;
+ }
+
+ String name = query.substring(i + 1, j);
+ c = '?';
+ i += name.length();
+ name = name.toLowerCase();
+
+ // Add to list
+ List<Integer> indexList = paramMap.get(name);
+ if (indexList == null) {
+ indexList = new LinkedList<Integer>();
+ paramMap.put(name, indexList);
+ }
+ indexList.add(index);
+
+ index++;
+ }
+ }
+
+ parsedQuery.append(c);
+ }
+
+ return parsedQuery.toString();
+ }
+
+ public static QueryBuilder create(DataSource dataSource, String query) throws SQLException {
+ return new QueryBuilder(dataSource, query);
+ }
+
+ private List<Integer> indexes(String name) {
+ name = name.toLowerCase();
+ List<Integer> result = indexMap.get(name);
+ if (result == null) {
+ result = new LinkedList<Integer>();
+ }
+ return result;
+ }
+
+ public QueryBuilder setBoolean(String name, boolean value) throws SQLException {
+ for (int i : indexes(name)) {
+ statement.setBoolean(i, value);
+ }
+ return this;
+ }
+
+ public QueryBuilder setInteger(String name, int value) throws SQLException {
+ for (int i : indexes(name)) {
+ statement.setInt(i, value);
+ }
+ return this;
+ }
+
+ public QueryBuilder setLong(String name, long value) throws SQLException {
+ for (int i : indexes(name)) {
+ statement.setLong(i, value);
+ }
+ return this;
+ }
+
+ public QueryBuilder setDouble(String name, double value) throws SQLException {
+ for (int i : indexes(name)) {
+ statement.setDouble(i, value);
+ }
+ return this;
+ }
+
+ public QueryBuilder setString(String name, String value) throws SQLException {
+ for (int i : indexes(name)) {
+ if (value == null) {
+ statement.setNull(i, Types.VARCHAR);
+ } else {
+ statement.setString(i, value);
+ }
+ }
+ return this;
+ }
+
+ public QueryBuilder setDate(String name, Date value) throws SQLException {
+ for (int i : indexes(name)) {
+ if (value == null) {
+ statement.setNull(i, Types.TIMESTAMP);
+ } else {
+ statement.setTimestamp(i, new Timestamp(value.getTime()));
+ }
+ }
+ return this;
+ }
+
+ public QueryBuilder setObject(Object object) throws SQLException {
+
+ Method[] methods = object.getClass().getMethods();
+
+ for (Method method : methods) {
+ if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
+ String name = method.getName().substring(3);
+ try {
+ if (method.getReturnType().equals(boolean.class)) {
+ return setBoolean(name, (Boolean) method.invoke(object));
+ } else if (method.getReturnType().equals(int.class)) {
+ return setInteger(name, (Integer) method.invoke(object));
+ } else if (method.getReturnType().equals(long.class)) {
+ return setLong(name, (Long) method.invoke(object));
+ } else if (method.getReturnType().equals(double.class)) {
+ return setDouble(name, (Double) method.invoke(object));
+ } else if (method.getReturnType().equals(String.class)) {
+ return setString(name, (String) method.invoke(object));
+ } else if (method.getReturnType().equals(Date.class)) {
+ return setDate(name, (Date) method.invoke(object));
+ }
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ }
+
+ return this;
+ }
+
+ private interface ResultSetProcessor<T> {
+ public void process(T object, ResultSet resultSet) throws SQLException;
+ }
+
+ public <T extends Factory> Collection<T> executeQuery(T prototype) throws SQLException {
+ List<T> result = new LinkedList<T>();
+
+ List<ResultSetProcessor<T>> processors = new LinkedList<ResultSetProcessor<T>>();
+
+ Method[] methods = prototype.getClass().getMethods();
+
+ for (final Method method : methods) {
+ if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) {
+
+ final String name = method.getName().substring(3);
+ Class<?> parameterType = method.getParameterTypes()[0];
+
+ if (parameterType.equals(boolean.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getBoolean(name));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ } else if (parameterType.equals(int.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getInt(name));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ } else if (parameterType.equals(long.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getLong(name));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ } else if (parameterType.equals(double.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getDouble(name));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ } else if (parameterType.equals(String.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, resultSet.getString(name));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ } else if (parameterType.equals(Date.class)) {
+ processors.add(new ResultSetProcessor<T>() {
+ @Override
+ public void process(T object, ResultSet resultSet) throws SQLException {
+ try {
+ method.invoke(object, new Date(resultSet.getTimestamp(name).getTime()));
+ } catch (IllegalAccessException error) {
+ } catch (InvocationTargetException error) {
+ }
+ }
+ });
+ }
+ }
+ }
+
+ ResultSet resultSet = statement.executeQuery();
+
+ while (resultSet.next()) {
+ T object = (T) prototype.create();
+ for (ResultSetProcessor<T> processor : processors) {
+ processor.process(object, resultSet);
+ }
+ result.add(object);
+ }
+
+ return result;
+ }
+
+ public long executeUpdate() throws SQLException {
+
+ statement.executeUpdate();
+ ResultSet resultSet = statement.getGeneratedKeys();
+ if (resultSet.next()) {
+ return resultSet.getLong(1);
+ }
+ return 0;
+ }
+
+}
diff --git a/src/org/traccar/database/ResultSetConverter.java b/src/org/traccar/database/ResultSetConverter.java
deleted file mode 100644
index 2bac01393..000000000
--- a/src/org/traccar/database/ResultSetConverter.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2015 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.database;
-
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import javax.json.Json;
-import javax.json.JsonArray;
-import javax.json.JsonArrayBuilder;
-import javax.json.JsonObjectBuilder;
-
-public class ResultSetConverter {
-
- public static JsonArray convert(ResultSet rs) throws SQLException {
-
- JsonArrayBuilder json = Json.createArrayBuilder();
- ResultSetMetaData rsmd = rs.getMetaData();
-
- while (rs.next()) {
-
- int numColumns = rsmd.getColumnCount();
- JsonObjectBuilder obj = Json.createObjectBuilder();
-
- for (int i = 1; i <= numColumns; i++) {
-
- String columnName = rsmd.getColumnName(i).toLowerCase();
-
- switch (rsmd.getColumnType(i)) {
- case java.sql.Types.BIGINT:
- obj.add(columnName, rs.getInt(columnName));
- break;
- case java.sql.Types.BOOLEAN:
- obj.add(columnName, rs.getBoolean(columnName));
- break;
- case java.sql.Types.DOUBLE:
- obj.add(columnName, rs.getDouble(columnName));
- break;
- case java.sql.Types.FLOAT:
- obj.add(columnName, rs.getFloat(columnName));
- break;
- case java.sql.Types.INTEGER:
- obj.add(columnName, rs.getInt(columnName));
- break;
- case java.sql.Types.NVARCHAR:
- obj.add(columnName, rs.getNString(columnName));
- break;
- case java.sql.Types.VARCHAR:
- obj.add(columnName, rs.getString(columnName));
- break;
- case java.sql.Types.DATE:
- obj.add(columnName, ObjectConverter.dateFormat.format(rs.getDate(columnName)));
- break;
- case java.sql.Types.TIMESTAMP:
- obj.add(columnName, ObjectConverter.dateFormat.format(rs.getTimestamp(columnName)));
- break;
- default:
- break;
- }
- }
-
- json.add(obj.build());
- }
-
- return json.build();
- }
-}
diff --git a/src/org/traccar/http/DeviceServlet.java b/src/org/traccar/http/DeviceServlet.java
index 64f7836a4..98f00b320 100644
--- a/src/org/traccar/http/DeviceServlet.java
+++ b/src/org/traccar/http/DeviceServlet.java
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.traccar.Context;
+import org.traccar.database.ObjectConverter;
import org.traccar.helper.Log;
import org.traccar.model.Device;
@@ -60,7 +61,8 @@ public class DeviceServlet extends HttpServlet {
try {
result.add("success", true);
- result.add("data", Context.getDataManager().getDevices(userId));
+ result.add("data", ObjectConverter.arrayToJson(
+ Context.getDataManager().getDevices(userId)));
} catch(SQLException error) {
result.add("success", false);
result.add("error", error.getMessage());
diff --git a/src/org/traccar/model/Device.java b/src/org/traccar/model/Device.java
index 067d80f36..7af1e8084 100644
--- a/src/org/traccar/model/Device.java
+++ b/src/org/traccar/model/Device.java
@@ -26,7 +26,12 @@ import org.traccar.database.Convertable;
import org.traccar.database.ObjectConverter;
import org.traccar.helper.Log;
-public class Device implements Convertable {
+public class Device implements Convertable, Factory {
+
+ @Override
+ public Device create() {
+ return new Device();
+ }
private long id;
public long getId() { return id; }
diff --git a/src/org/traccar/model/Factory.java b/src/org/traccar/model/Factory.java
new file mode 100644
index 000000000..5af946a2b
--- /dev/null
+++ b/src/org/traccar/model/Factory.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2015 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;
+
+public interface Factory {
+
+ public Object create();
+
+}
diff --git a/src/org/traccar/model/Permission.java b/src/org/traccar/model/Permission.java
new file mode 100644
index 000000000..d8854a549
--- /dev/null
+++ b/src/org/traccar/model/Permission.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 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;
+
+public class Permission implements Factory {
+
+ @Override
+ public Permission create() {
+ return new Permission();
+ }
+
+ private long userId;
+ public long getUserId() { return userId; }
+ public void setUserId(long userId) { this.userId = userId; }
+
+ private long deviceId;
+ public long getDeviceId() { return deviceId; }
+ public void setDeviceId(long deviceId) { this.deviceId = deviceId; }
+
+}
diff --git a/web/DeviceDialog.js b/web/DeviceDialog.js
new file mode 100644
index 000000000..e0016d790
--- /dev/null
+++ b/web/DeviceDialog.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 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.
+ */
+
+Ext.define('DeviceForm', {
+ extend: 'Ext.form.Panel',
+ xtype: 'device-form',
+
+ defaultType: 'textfield',
+ bodyPadding: Styles.panel_padding,
+
+ defaults: { anchor: '100%' },
+
+ url: '/api/device/add',
+ jsonSubmit: true,
+
+ items: [{
+ allowBlank: false,
+ fieldLabel: Strings.device_name,
+ name: 'name'
+ }, {
+ allowBlank: false,
+ fieldLabel: Strings.device_identifier,
+ name: 'uniqueId'
+ }],
+
+ buttons: [{
+ text: Strings.dialog_create,
+ handler: function() {
+ var win = this.up('window');
+ var form = this.up('form').getForm();
+ if (form.isValid()) {
+ form.submit({
+ success: function() {
+ win.close();
+ win.onUpdate();
+ },
+ failure: function() {
+ win.close();
+ }
+ });
+ }
+ }
+ }, {
+ text: Strings.dialog_cancel,
+ handler: function() {
+ this.up('window').close();
+ }
+ }]
+});
+
+Ext.define('DeviceDialog', {
+ extend: 'Ext.window.Window',
+
+ modal: true,
+
+ title: Strings.device_dialog,
+
+ items: [{ xtype: 'device-form' }]
+});