Jelajahi Sumber

Merged version (not tested yet)

Lukas Cerny 5 tahun lalu
induk
melakukan
d8b9a9089b
100 mengubah file dengan 18327 tambahan dan 0 penghapusan
  1. 1 0
      .gitignore
  2. 276 0
      pom.xml
  3. 1193 0
      src/main/db/functions.sql
  4. 1254 0
      src/main/db/iso.sql
  5. 798 0
      src/main/db/sequence.sql
  6. 166 0
      src/main/java/cz/hsrs/db/ChartGenerator.java
  7. 127 0
      src/main/java/cz/hsrs/db/ConnectionManager.java
  8. 70 0
      src/main/java/cz/hsrs/db/DBChartUtils.java
  9. 176 0
      src/main/java/cz/hsrs/db/DBJsonUtils.java
  10. 10 0
      src/main/java/cz/hsrs/db/DBObject.java
  11. 307 0
      src/main/java/cz/hsrs/db/DatabaseFeedOperation.java
  12. 34 0
      src/main/java/cz/hsrs/db/UserManagemant.java
  13. 61 0
      src/main/java/cz/hsrs/db/model/Alert.java
  14. 114 0
      src/main/java/cz/hsrs/db/model/AlertEvent.java
  15. 77 0
      src/main/java/cz/hsrs/db/model/AlertQuery.java
  16. 72 0
      src/main/java/cz/hsrs/db/model/Group.java
  17. 87 0
      src/main/java/cz/hsrs/db/model/IgnitionStatus.java
  18. 17 0
      src/main/java/cz/hsrs/db/model/NoItemFoundException.java
  19. 128 0
      src/main/java/cz/hsrs/db/model/Observation.java
  20. 191 0
      src/main/java/cz/hsrs/db/model/Phenomenon.java
  21. 80 0
      src/main/java/cz/hsrs/db/model/Road.java
  22. 199 0
      src/main/java/cz/hsrs/db/model/Sensor.java
  23. 82 0
      src/main/java/cz/hsrs/db/model/TrackData.java
  24. 65 0
      src/main/java/cz/hsrs/db/model/Unit.java
  25. 91 0
      src/main/java/cz/hsrs/db/model/UnitDriver.java
  26. 69 0
      src/main/java/cz/hsrs/db/model/UnitHolder.java
  27. 462 0
      src/main/java/cz/hsrs/db/model/UnitPosition.java
  28. 89 0
      src/main/java/cz/hsrs/db/model/UnitTrack.java
  29. 63 0
      src/main/java/cz/hsrs/db/model/composite/AggregateObservation.java
  30. 55 0
      src/main/java/cz/hsrs/db/model/composite/LastPosition.java
  31. 149 0
      src/main/java/cz/hsrs/db/model/composite/ObservationMedlov.java
  32. 65 0
      src/main/java/cz/hsrs/db/model/composite/ObservationValue.java
  33. 84 0
      src/main/java/cz/hsrs/db/model/composite/RealSensor.java
  34. 104 0
      src/main/java/cz/hsrs/db/model/composite/RealUnit.java
  35. 38 0
      src/main/java/cz/hsrs/db/model/composite/UnitObservation.java
  36. 122 0
      src/main/java/cz/hsrs/db/model/composite/UnitSensor.java
  37. 128 0
      src/main/java/cz/hsrs/db/model/composite/UnitSensorObservation.java
  38. 62 0
      src/main/java/cz/hsrs/db/model/custom/DBItemInfo.java
  39. 85 0
      src/main/java/cz/hsrs/db/model/custom/UnitPositionSimple.java
  40. 133 0
      src/main/java/cz/hsrs/db/model/insert/UnitInsert.java
  41. 113 0
      src/main/java/cz/hsrs/db/model/vgi/Envelope2D.java
  42. 129 0
      src/main/java/cz/hsrs/db/model/vgi/VgiCategory.java
  43. 135 0
      src/main/java/cz/hsrs/db/model/vgi/VgiDataset.java
  44. 183 0
      src/main/java/cz/hsrs/db/model/vgi/VgiMedia.java
  45. 301 0
      src/main/java/cz/hsrs/db/model/vgi/VgiObservation.java
  46. 130 0
      src/main/java/cz/hsrs/db/model/vgi/VgiObservationRdf.java
  47. 193 0
      src/main/java/cz/hsrs/db/pool/ConnectionPool.java
  48. 7 0
      src/main/java/cz/hsrs/db/pool/ConnectionPoolMBean.java
  49. 80 0
      src/main/java/cz/hsrs/db/pool/PooledConnection.java
  50. 225 0
      src/main/java/cz/hsrs/db/pool/SQLExecutor.java
  51. 263 0
      src/main/java/cz/hsrs/db/util/AlertUtil.java
  52. 798 0
      src/main/java/cz/hsrs/db/util/AnalystUtil.java
  53. 35 0
      src/main/java/cz/hsrs/db/util/DBUtil.java
  54. 72 0
      src/main/java/cz/hsrs/db/util/DataChecker.java
  55. 252 0
      src/main/java/cz/hsrs/db/util/DateUtil.java
  56. 129 0
      src/main/java/cz/hsrs/db/util/GroupUtil.java
  57. 80 0
      src/main/java/cz/hsrs/db/util/ManagementUtil.java
  58. 125 0
      src/main/java/cz/hsrs/db/util/ObservationUtil.java
  59. 559 0
      src/main/java/cz/hsrs/db/util/SensorUtil.java
  60. 67 0
      src/main/java/cz/hsrs/db/util/ServerUtil.java
  61. 235 0
      src/main/java/cz/hsrs/db/util/TrackUtil.java
  62. 354 0
      src/main/java/cz/hsrs/db/util/UnitUtil.java
  63. 409 0
      src/main/java/cz/hsrs/db/util/UserUtil.java
  64. 10 0
      src/main/java/cz/hsrs/db/util/Util.java
  65. 28 0
      src/main/java/cz/hsrs/db/util/UtilFactory.java
  66. 182 0
      src/main/java/cz/hsrs/db/util/VgiUtil.java
  67. 88 0
      src/main/java/cz/hsrs/db/util/factory/UnitPositionFactory.java
  68. 139 0
      src/main/java/cz/hsrs/db/vgi/util/VgiCategoryUtil.java
  69. 97 0
      src/main/java/cz/hsrs/db/vgi/util/VgiDatasetsUtil.java
  70. 206 0
      src/main/java/cz/hsrs/db/vgi/util/VgiMediaUtil.java
  71. 1013 0
      src/main/java/cz/hsrs/db/vgi/util/VgiObservationUtil.java
  72. 78 0
      src/main/java/cz/hsrs/db/vgi/util/VgiParams.java
  73. 34 0
      src/main/java/cz/hsrs/rest/SCListener.java
  74. 60 0
      src/main/java/cz/hsrs/rest/beans/VgiObservationBean.java
  75. 92 0
      src/main/java/cz/hsrs/rest/beans/VgiObservationRdfBean.java
  76. 22 0
      src/main/java/cz/hsrs/rest/beans/VgiObservationsRdfBean.java
  77. 31 0
      src/main/java/cz/hsrs/rest/util/BasicAuth.java
  78. 16 0
      src/main/java/cz/hsrs/rest/util/CorsFilter.java
  79. 91 0
      src/main/java/cz/hsrs/rest/util/ExportVgiRestUtil.java
  80. 151 0
      src/main/java/cz/hsrs/rest/util/RestUtil.java
  81. 68 0
      src/main/java/cz/hsrs/rest/util/VgiCategoryRestUtil.java
  82. 90 0
      src/main/java/cz/hsrs/rest/util/VgiDatasetRestUtil.java
  83. 660 0
      src/main/java/cz/hsrs/rest/util/VgiObservationRestUtil.java
  84. 132 0
      src/main/java/cz/hsrs/rest/vgi/ExportVgiRest.java
  85. 119 0
      src/main/java/cz/hsrs/rest/vgi/VgiCategoryRest.java
  86. 178 0
      src/main/java/cz/hsrs/rest/vgi/VgiDatasetRest.java
  87. 524 0
      src/main/java/cz/hsrs/rest/vgi/VgiObservationRest.java
  88. 214 0
      src/main/java/cz/hsrs/rest/vgi/VgiRest.java
  89. 269 0
      src/main/java/cz/hsrs/servlet/feeder/FeederServlet.java
  90. 39 0
      src/main/java/cz/hsrs/servlet/feeder/ServiceParameters.java
  91. 41 0
      src/main/java/cz/hsrs/servlet/lang/ChangeLangServlet.java
  92. 71 0
      src/main/java/cz/hsrs/servlet/lang/Labels.java
  93. 87 0
      src/main/java/cz/hsrs/servlet/provider/AlertService.java
  94. 357 0
      src/main/java/cz/hsrs/servlet/provider/AnalystService.java
  95. 129 0
      src/main/java/cz/hsrs/servlet/provider/ChartServlet.java
  96. 172 0
      src/main/java/cz/hsrs/servlet/provider/DBServlet.java
  97. 236 0
      src/main/java/cz/hsrs/servlet/provider/DataService.java
  98. 106 0
      src/main/java/cz/hsrs/servlet/provider/GroupService.java
  99. 102 0
      src/main/java/cz/hsrs/servlet/provider/MMService.java
  100. 137 0
      src/main/java/cz/hsrs/servlet/provider/ManagementService.java

+ 1 - 0
.gitignore

@@ -60,3 +60,4 @@ com_crashlytics_export_strings.xml
 crashlytics.properties
 crashlytics-build.properties
 
+.DS_Store

+ 276 - 0
pom.xml

@@ -0,0 +1,276 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>cz.hsrs.maplog</groupId>
+    <artifactId>DBService</artifactId>
+    <packaging>war</packaging>
+    <version>1.3.5-SNAPSHOT</version>
+    <name>dbservice Maven Webapp</name>
+    <url>http://maven.apache.org</url>
+
+    <build>
+        <finalName>${project.artifactId}-${project.version}</finalName>
+        <sourceDirectory>./src/main/java</sourceDirectory>
+        <testSourceDirectory>./src/test/java</testSourceDirectory>
+        <resources>
+            <resource>
+                <directory>./src/main/resources</directory>
+            </resource>
+        </resources>
+        <testResources>
+            <testResource>
+                <directory>./src/test/resources</directory>
+            </testResource>
+        </testResources>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>buildnumber-maven-plugin</artifactId>
+                <version>1.3</version>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>create</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <doCheck>false</doCheck>
+                    <doUpdate>false</doUpdate>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.tomcat.maven</groupId>
+                <artifactId>tomcat7-maven-plugin</artifactId>
+                <version>2.2</version>
+                <configuration>
+                    <url>http://foodie.lesprojekt.cz:8080/manager/text</url> 
+                    <server>foodietomcat</server>
+                    <path>/MapLog</path>
+                    <!--<path>/MapLogLV</path>-->
+                    <!--<path>/MapLogIT</path>-->
+                    <!--<path>/MapLogOT</path>-->
+                </configuration>
+            </plugin>
+
+<!--        <plugin>
+            <groupId>org.apache.tomcat.maven</groupId>
+            <artifactId>tomcat7-maven-plugin</artifactId>
+            <version>2.2</version>
+            <configuration>
+                <path>/SensLog</path>
+                <url>http://otn.bnhelp.cz/manager/text</url>
+                <server>otntomcat</server>
+            </configuration>
+        </plugin>
+-->
+<!--
+        <plugin>
+            <groupId>org.apache.tomcat.maven</groupId>
+            <artifactId>tomcat7-maven-plugin</artifactId>
+            <version>2.2</version>
+            <configuration>
+                <path>/MapLog</path>
+                <url>http://ft.lesprojekt.cz:8080/manager/text</url>
+                <server>foodietomcat</server>
+            </configuration>
+        </plugin>
+-->
+<!--
+        <plugin>
+            <groupId>org.apache.tomcat.maven</groupId>
+            <artifactId>tomcat7-maven-plugin</artifactId>
+            <version>2.2</version>
+            <configuration>
+                <path>/SensLog</path>
+                <url>http://foodie.wirelessinfo.cz/manager/text</url>
+                <server>foodiepoland</server>
+            </configuration>
+        </plugin>
+-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>2.0.2</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                        </manifest>
+                        <manifestEntries>
+                            <Implementation-Build>${buildNumber}</Implementation-Build>
+                        </manifestEntries>
+                    </archive>
+                    <warSourceExcludes>wwwlibs/**</warSourceExcludes>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <instrumentation>
+                        <ignores>
+                            <ignore>com.example.boringcode.*</ignore>
+                        </ignores>
+                        <excludes>
+                            <exclude>com/example/dullcode/**/*.class</exclude>
+                            <exclude>com/example/**/*Test.class</exclude>
+                        </excludes>
+                    </instrumentation>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>clean</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!-- ======================================================= -->
+                <!--     Compilation.                                        -->
+                <!-- ======================================================= -->
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>2.0.2</version>
+                    <configuration>
+                        <source>1.8</source>  <!-- The -source argument for the Java compiler. -->
+                        <target>1.8</target>  <!-- The -target argument for the Java compiler. -->
+                        <debug>true</debug>   <!-- Whether to include debugging information.   -->
+                        <encoding>UTF-8</encoding> <!-- The -encoding argument for the Java compiler. -->
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <dependencies>
+
+        <!-- Provided dependencies -->
+        <dependency>
+            <groupId>net.sf.jasperreports</groupId>
+            <artifactId>jasperreports</artifactId>
+            <version>4.5.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>javax</groupId>
+            <artifactId>javaee-api</artifactId>
+            <version>7.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sun.jersey.contribs</groupId>
+            <artifactId>jersey-multipart</artifactId>
+            <version>1.19.4</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.11.1</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>2.11.1</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.jersey.core</groupId>
+            <artifactId>jersey-server</artifactId>
+            <version>2.31</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sf.json-lib</groupId>
+            <artifactId>json-lib</artifactId>
+            <version>2.3</version>
+            <classifier>jdk15</classifier>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jfree</groupId>
+            <artifactId>jfreechart</artifactId>
+            <version>1.5.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.2.14</version>
+        </dependency>
+
+        <!-- Tests -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.5</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mortbay.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+            <version>7.0.0.pre5</version>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.build.resourceEncoding>UTF-8</project.build.resourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    </properties>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>cobertura-maven-plugin</artifactId>
+                <version>2.4</version>
+            </plugin>
+        </plugins>
+    </reporting>
+<!--
+    <scm>
+        <connection>scm:svn:svn://bnhelp.cz/maplog/tags/DBService-1.2</connection>
+        <developerConnection>scm:svn:svn://bnhelp.cz/maplog/tags/DBService-1.2</developerConnection>
+        <url>http://somerepository.com/view.cvs/tags/DBService-1.2</url>
+    </scm>
+-->
+    <scm>
+        <connection>scm:git:git+ssh://git@git.ccss.cz/ccss/maplogagri</connection>
+        <developerConnection>scm:git:git+ssh://git@git.ccss.cz/ccss/maplogagri</developerConnection>
+        <url>http://somerepository.com/view.cvs/tags/DBService-1.3</url>
+    </scm>
+
+    <repositories>
+        <repository>
+            <id>com.mvnrepository</id>
+            <name>mvnrepository</name>
+            <url>http://mvnrepository.com</url>
+        </repository>
+    </repositories>
+
+</project>

+ 1193 - 0
src/main/db/functions.sql

@@ -0,0 +1,1193 @@
+
+--
+-- TOC entry 744 (class 1255 OID 1412518)
+-- Dependencies: 1203 7 1065
+-- Name: _split_track(geometry, integer, timestamp with time zone); Type: FUNCTION; Schema: public; Owner: -
+--
+
+/* 
+ * Rozdeli track s gid bodem a casem
+ */
+CREATE FUNCTION maplog._split_track(point geometry, this_gid integer, this_time_stamp timestamp with time zone) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+DECLARE
+
+  track record;
+  fraction float;
+  subtrack1 geometry;
+  subtrack2 geometry;
+  newtrack  geometry;
+  helper_time_before timestamp with time zone;
+  helper_time_after timestamp with time zone;
+  numpts int;
+BEGIN
+
+	SELECT * INTO track FROM units_tracks WHERE gid = this_gid;
+
+	SELECT time_stamp INTO helper_time_before FROM units_positions 
+		WHERE unit_id = track.unit_id
+		AND time_stamp  < this_time_stamp ORDER BY time_stamp DESC LIMIT 1;
+	SELECT time_stamp INTO helper_time_after FROM units_positions 
+		WHERE unit_id = track.unit_id
+		AND time_stamp  > this_time_stamp ORDER BY time_stamp LIMIT 1;
+		
+
+	IF this_time_stamp = track.track_end THEN
+		-- pozice je na konci - staci umazat posledni
+		SELECT st_removepoint(track.the_geom, 0) INTO newtrack;
+
+	
+		
+		UPDATE units_tracks SET the_geom = newtrack, track_end = helper_time
+		WHERE gid = this_gid;
+		RETURN;
+	ELSE IF this_time_stamp = track.track_start THEN
+
+		-- pozice je na konci - staci umazat posledni
+		SELECT ST_NumPoints(track.the_geom) INTO numpts;
+		SELECT st_removepoint(track.the_geom, numpts) INTO newtrack;
+		
+		UPDATE units_tracks SET the_geom = newtrack, track_end = helper_time
+		WHERE gid = this_gid;
+		RETURN;
+		END IF;
+	END IF;
+
+	SELECT Line_Locate_Point(track.the_geom, point) INTO fraction;
+
+	SELECT line_substring(track.the_geom,0, fraction) INTO subtrack1;
+	SELECT line_substring(track.the_geom,fraction, 1) INTO subtrack2;	
+
+	
+	UPDATE units_tracks SET the_geom = subtrack1, track_end = helper_time_before
+	WHERE gid = this_gid;
+	
+	INSERT INTO units_tracks (the_geom, unit_id, track_start, track_end, is_closed)
+	VALUES (subtrack2, track.unit_id, helper_time_after, track.track_end, track.is_closed );
+
+  
+ 
+END
+$$;
+
+
+--
+
+CREATE FUNCTION maplog.add_alert() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_alert_id bigint; 
+description varchar;
+BEGIN 
+
+SELECT alert_id INTO this_alert_id FROM alerts WHERE alert_id = NEW.alert_id;
+
+IF this_alert_id IS NULL THEN
+   raise notice '% alert not found - adding automaticaly', NEW.alert_id;
+   
+   select into description 'default alert ' || EXTRACT(EPOCH FROM now())::varchar;
+   INSERT INTO alerts(alert_id, alert_description) 
+   values (NEW.alert_id, description);
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 23 (class 1255 OID 19024)
+-- Dependencies: 7 1203
+-- Name: add_gid_to_observation(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_gid_to_observation() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+last_unit_gid integer; 
+this_last_pos record;
+BEGIN 
+
+SELECT * INTO this_last_pos FROM last_units_positions WHERE unit_id = NEW.unit_id;
+    IF this_last_pos.time_stamp < NEW.time_stamp THEN
+	NEW.gid:=this_last_pos.gid;	
+    ELSE 
+	SELECT gid INTO last_unit_gid FROM units_positions 
+	WHERE units_positions.unit_id = NEW.unit_id AND
+	units_positions.time_stamp < NEW.time_stamp
+	ORDER BY units_positions.time_stamp DESC LIMIT 1;
+        NEW.gid:=last_unit_gid;	
+    END IF;
+    RETURN NEW;    
+END; 
+$$;
+
+
+--
+-- TOC entry 746 (class 1255 OID 19025)
+-- Dependencies: 7 1203
+-- Name: add_last_unit_position(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_last_unit_position() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$declare
+last_gid integer;
+last_timestamp timestamp;
+BEGIN 
+
+SELECT gid INTO last_gid FROM last_units_positions WHERE unit_id = NEW.unit_id;
+SELECT time_stamp INTO last_timestamp FROM last_units_positions WHERE unit_id = NEW.unit_id;
+
+-- if no track then create new
+IF last_gid  IS NULL THEN 
+--insert new last position
+	INSERT INTO last_units_positions values(NEW.gid, NEW.the_geom, NEW.unit_id, NEW.time_stamp);
+
+ELSE IF (last_timestamp < NEW.time_stamp) THEN
+-- update last position
+        UPDATE last_units_positions
+              SET the_geom = NEW.the_geom,
+               time_stamp = NEW.time_stamp ,
+               gid = NEW.gid,
+               dop = NEW.dop,
+               speed = NEW.speed
+               WHERE unit_id = NEW.unit_id;	
+END IF;
+END IF;
+RETURN NEW;
+END; $$;
+
+
+--
+-- TOC entry 2996 (class 0 OID 0)
+-- Dependencies: 746
+-- Name: FUNCTION add_last_unit_position(); Type: COMMENT; Schema: public; Owner: -
+--
+
+COMMENT ON FUNCTION maplog.add_last_unit_position() IS 'Addes or update newly inserted position into last_units_positions';
+
+
+--
+-- TOC entry 24 (class 1255 OID 19026)
+-- Dependencies: 7 1203
+-- Name: add_phenomenon(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_phenomenon() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_phenomenon_id character varying(100); 
+
+BEGIN 
+
+SELECT phenomenon_id INTO this_phenomenon_id FROM phenomenons WHERE phenomenon_id = NEW.phenomenon_id;
+
+IF this_phenomenon_id IS NULL THEN
+   raise notice 'phenomenon not found - adding automaticaly ';
+   INSERT INTO phenomenons(phenomenon_id, phenomenon_name, unit) 
+   values (NEW.phenomenon_id, 'Generated - TODO', 'Generated - TODO');
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 26 (class 1255 OID 19027)
+-- Dependencies: 1203 7
+-- Name: add_sensor(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_sensor() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_sensor_id bigint; 
+
+BEGIN 
+
+SELECT sensor_id INTO this_sensor_id FROM sensors WHERE sensor_id = NEW.sensor_id;
+
+IF this_sensor_id IS NULL THEN
+   raise notice '% sensor not found - adding automaticaly', NEW.sensor_id;
+   INSERT INTO sensors(sensor_id, phenomenon_id) 
+   values (NEW.sensor_id, 999999);
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 27 (class 1255 OID 19028)
+-- Dependencies: 1203 7
+-- Name: add_unit(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_unit() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_unit_id bigint; 
+
+BEGIN 
+
+SELECT unit_id INTO this_unit_id FROM units WHERE unit_id = NEW.unit_id;
+IF this_unit_id IS NULL THEN
+   raise notice '% unit not found - adding automaticaly', NEW.unit_id;
+   INSERT INTO units(unit_id, description) 
+   values (NEW.unit_id, 'automaticaly added unit');
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 41 (class 1255 OID 19029)
+-- Dependencies: 1203 7
+-- Name: add_unit_conf(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_unit_conf() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_unit_id bigint; 
+
+BEGIN 
+
+SELECT unit_id INTO this_unit_id FROM units_conf WHERE unit_id = NEW.unit_id;
+IF this_unit_id IS NULL THEN
+   
+   INSERT INTO units_conf(unit_id, min_distance, min_time_span) 
+   values (NEW.unit_id, 20, '1 hour');
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 28 (class 1255 OID 80907)
+-- Dependencies: 7 1203
+-- Name: add_unit_to_admin(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_unit_to_admin() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_group_id int; 
+admin_group_id int;
+admin_name varchar;
+BEGIN 
+admin_name='admin';
+
+SELECT group_id INTO this_group_id FROM units_to_groups WHERE unit_id = NEW.unit_id;
+IF this_group_id IS NULL THEN
+
+   SELECT id INTO this_group_id FROM groups 
+   WHERE group_name = admin_name;
+
+	IF this_group_id IS NULL THEN
+		INSERT INTO groups(group_name)
+		VALUES (admin_name);
+		SELECT id INTO this_group_id FROM groups 
+		WHERE group_name = admin_name;
+	END IF;
+
+   INSERT INTO units_to_groups(group_id, unit_id) 
+   values (this_group_id, NEW.unit_id);
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 42 (class 1255 OID 19030)
+-- Dependencies: 1203 7
+-- Name: add_unit_to_sensor(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_unit_to_sensor() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+utos record;
+BEGIN 
+
+SELECT * INTO utos FROM units_to_sensors WHERE unit_id = NEW.unit_id
+AND sensor_id = NEW.sensor_id;
+
+IF utos IS NULL THEN    
+   raise notice 'unit_to_sensor not found - adding automaticaly';  
+   INSERT INTO units_to_sensors(unit_id, sensor_id) 
+   values (NEW.unit_id, NEW.sensor_id);
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 43 (class 1255 OID 19031)
+-- Dependencies: 1203 7
+-- Name: add_unit_track_conf(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.add_unit_track_conf() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_unit_id bigint; 
+
+BEGIN 
+
+SELECT unit_id INTO this_unit_id FROM units_tracks_conf WHERE unit_id = NEW.unit_id;
+IF this_unit_id IS NULL THEN
+   
+   INSERT INTO units_tracks_conf(unit_id, max_distance, max_time_span) 
+   values (NEW.unit_id, 1000, '12 hours');
+   RETURN NEW;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+
+
+--
+-- TOC entry 167 (class 1255 OID 90580)
+-- Dependencies: 7 1203
+-- Name: addpositiontotrack(integer, integer, integer); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.addpositiontotrack(trackid integer, positionid integer, positionplace integer) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+track_geom geometry;
+this_position record;
+this_track record;
+trackPoints int;
+BEGIN 
+
+SELECT * INTO this_track FROM units_tracks WHERE gid = trackid;
+SELECT * INTO this_position FROM units_positions WHERE gid = positionid;
+
+IF positionplace = 0 AND this_track.track_start >= this_position.time_stamp THEN
+        --dej na zacatek a nahrad pocatecni cas
+	UPDATE units_tracks 
+	SET 
+	the_geom = addPoint(this_track.the_geom, this_position.the_geom, positionplace),
+	track_start =  this_position.time_stamp
+	WHERE gid=this_track.gid;
+	return true;
+ELSEIF this_track.track_end <= this_position.time_stamp 
+	AND ST_NumPoints(this_track.the_geom)<=positionplace THEN
+	--dej na konec a nahrad koncovej cas
+	UPDATE units_tracks 
+	SET 
+	the_geom = addPoint(this_track.the_geom, this_position.the_geom),
+	track_end =  this_position.time_stamp
+	WHERE gid=this_track.gid;
+	return true;
+
+ELSEIF this_track.track_start < this_position.time_stamp AND 
+	this_position.time_stamp < this_track.track_end 
+	THEN
+-- dej doprostred
+        UPDATE units_tracks 
+	SET 
+	the_geom = addPoint(this_track.the_geom, this_position.the_geom, positionplace)	
+	WHERE gid=this_track.gid;
+	return true;
+ELSE 
+RETURN false;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 30 (class 1255 OID 19097)
+-- Dependencies: 7 1203
+-- Name: consider_insert_position(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.consider_insert_position() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+this_units_conf record;
+this_position record;
+dist double precision;
+last_post geometry;
+this_time_span interval;
+
+BEGIN 
+
+SELECT * INTO this_units_conf FROM units_conf WHERE unit_id = NEW.unit_id;
+SELECT * INTO this_position FROM last_units_positions WHERE unit_id = NEW.unit_id;
+
+dist = distance_sphere(this_position.the_geom, NEW.the_geom);
+this_time_span = NEW.time_stamp - this_position.time_stamp;
+
+IF (dist < this_units_conf.min_distance AND (this_time_span < this_units_conf.min_time_span))THEN
+    raise notice 'Positiont of Unit % is too close ', NEW.unit_id;
+   RETURN NULL;
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+--
+-- TOC entry 745 (class 1255 OID 1412167)
+-- Dependencies: 7 1203
+-- Name: consider_insert_position2(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.consider_insert_position2() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+this_units_conf record;
+last_position record;
+before_position record;
+dist double precision;
+dist2 double precision;
+last_post geometry;
+this_time_span interval;
+
+BEGIN 
+
+SELECT * INTO this_units_conf FROM units_conf WHERE unit_id = NEW.unit_id;
+SELECT * INTO last_position FROM last_units_positions WHERE unit_id = NEW.unit_id;
+
+dist = distance_sphere(last_position.the_geom, NEW.the_geom);
+
+IF (dist < this_units_conf.min_distance AND NEW.speed<this_units_conf.min_speed)
+   THEN
+   SELECT * INTO before_position FROM units_positions WHERE 
+   unit_id = NEW.unit_id 
+   AND time_stamp < last_position.time_stamp ORDER BY time_stamp DESC limit 1;
+   dist2 = distance_sphere(last_position.the_geom, before_position.the_geom);
+	
+	IF (dist2 < this_units_conf.min_distance AND 
+	    before_position.speed < this_units_conf.min_speed AND
+	    last_position.speed   < this_units_conf.min_speed) THEN
+		UPDATE units_positions
+		SET time_stamp = NEW.time_stamp
+		WHERE gid = last_position.gid;
+		RETURN NULL;
+	ELSE
+		RETURN NEW;
+	END IF;
+   
+ELSE
+-- if unit exist than do nothing
+RETURN NEW;
+END IF;
+END; 
+$$;
+
+
+
+CREATE FUNCTION maplog.copy_ignition_status() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$ DECLARE
+ last_status record;
+ tomorrow timestamp with time zone;
+BEGIN
+IF new.sensor_id = 330040000 THEN 
+ SELECT * INTO last_status FROM public.last_ignition_status WHERE unit_id = NEW.unit_id;
+ SELECT CURRENT_TIMESTAMP + INTERVAL '1 day' INTO  tomorrow;
+ IF last_status IS NULL THEN
+  INSERT INTO last_ignition_status VALUES (NEW.observation_id, NEW.gid, NEW.time_stamp, NEW.observed_value, NEW.unit_id);
+ ELSE 
+  IF last_status.time_stamp < NEW.time_stamp AND NEW.time_stamp < tomorrow THEN
+    IF last_status.value <> NEW.observed_value THEN
+      INSERT INTO ignition_status VALUES (last_status.observation_id, last_status.gid, last_status.time_stamp, last_status.value, last_status.unit_id);
+      DELETE FROM last_ignition_status WHERE unit_id = last_status.unit_id;
+      INSERT INTO last_ignition_status VALUES (NEW.observation_id, NEW.gid, NEW.time_stamp, NEW.observed_value, NEW.unit_id);
+    ELSE
+      UPDATE last_ignition_status SET observation_id = NEW.observation_id, gid = NEW.gid, time_stamp = NEW.time_stamp WHERE unit_id = NEW.unit_id;
+    END IF;
+  ELSE
+    INSERT INTO ignition_status VALUES (NEW.observation_id, NEW.gid, NEW.time_stamp, NEW.observed_value, NEW.unit_id);
+  END IF;
+ END IF;
+END IF;
+RETURN NEW;
+END; $$;
+
+
+
+
+CREATE FUNCTION maplog.delete_sensor() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+BEGIN 
+
+DELETE FROM observations WHERE sensor_id=OLD.sensor_id;
+DELETE FROM units_to_sensors WHERE sensor_id=OLD.sensor_id;
+
+RETURN OLD;
+
+END; 
+$$;
+
+
+--
+-- TOC entry 232 (class 1255 OID 19108)
+-- Dependencies: 7 1203
+-- Name: delete_unit(integer); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.delete_unit(this_unit_id integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+declare
+track_gid integer; 
+
+BEGIN 
+
+DELETE FROM running_tracks WHERE unit_id = this_unit_id;
+DELETE FROM units_tracks WHERE unit_id = this_unit_id;
+DELETE FROM observations WHERE unit_id = this_unit_id;
+DELETE FROM last_units_positions WHERE unit_id = this_unit_id;
+DELETE FROM units_positions WHERE unit_id = this_unit_id;
+DELETE FROM units WHERE unit_id = this_unit_id;
+
+END; 
+$$;
+
+
+CREATE FUNCTION maplog.do_track() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+track_gid integer; 
+last_timestamp timestamp;
+old_geom geometry;
+line_geom geometry;
+
+BEGIN 
+
+SELECT time_stamp INTO last_timestamp FROM last_units_positions WHERE unit_id = NEW.unit_id;
+
+track_gid := get_unit_running_track_gid(NEW.unit_id) ;
+RAISE NOTICE 'found %', track_gid;
+-- if no track then create new
+IF track_gid IS NULL THEN 
+	RAISE NOTICE 'no track';
+	SELECT INTO track_gid nextval('units_tracks_gid_seq');
+	line_geom = MakeLine(NEW.the_geom);
+
+	INSERT INTO units_tracks(gid, the_geom, unit_id, track_start) 
+	values (track_gid, line_geom, NEW.unit_id, NEW.time_stamp);
+
+	RAISE NOTICE 'adding %', track_gid;
+	
+	INSERT INTO running_tracks(unit_id, gid)
+	values(NEW.unit_id, track_gid);
+	RETURN NEW;
+
+ELSE IF (last_timestamp < NEW.time_stamp) THEN
+-- track is already running
+        SELECT the_geom INTO STRICT old_geom FROM units_tracks WHERE gid=track_gid;
+	
+	UPDATE units_tracks SET the_geom = addPoint(old_geom, NEW.the_geom) WHERE gid=track_gid;
+
+RETURN NEW;
+END IF;
+END IF;
+RETURN NEW;
+END; 
+$$;
+
+
+--
+-- TOC entry 44 (class 1255 OID 19117)
+-- Dependencies: 7 1203
+-- Name: do_track2(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.do_track2() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+position_from_end bigint;
+track_gid integer; 
+last_timestamp timestamp;
+old_geom geometry;
+line_geom geometry;
+point_position integer;
+point_number integer;
+
+BEGIN 
+
+--get position where to put new point
+ 
+SELECT gid INTO track_gid FROM running_tracks WHERE unit_id=NEW.unit_id;
+
+
+
+RAISE NOTICE 'found %', track_gid;
+-- if no track then create new
+IF track_gid IS NULL THEN 
+	RAISE NOTICE 'no track';
+	SELECT INTO track_gid nextval('units_tracks_gid_seq');
+	line_geom = MakeLine(NEW.the_geom);
+
+	INSERT INTO units_tracks(gid, the_geom, unit_id, track_start) 
+	values (track_gid, line_geom, NEW.unit_id, NEW.time_stamp);
+
+	RAISE NOTICE 'adding %', track_gid;
+	
+	INSERT INTO running_tracks(unit_id, gid)
+	values(NEW.unit_id, track_gid);
+	RETURN NEW;
+
+ELSE 
+
+-- track is already running
+	SELECT count(gid) INTO position_from_end FROM units_positions 
+	WHERE 
+	time_stamp > NEW.time_stamp AND
+	unit_id = NEW.unit_id;
+
+	IF position_from_end = 0 THEN
+
+		SELECT the_geom INTO STRICT old_geom FROM units_tracks WHERE gid=track_gid
+		AND unit_id=NEW.unit_id;
+		UPDATE units_tracks 
+			SET the_geom = addPoint(old_geom, NEW.the_geom),
+			    track_end = NEW.time_stamp
+		 WHERE gid=track_gid;
+     
+	
+	ELSE
+-- calculate position
+		SELECT st_numpoints(the_geom) INTO point_number FROM units_tracks 
+		WHERE gid = track_gid AND unit_id=NEW.unit_id;
+
+		point_position := point_number - position_from_end;
+			IF point_position < 0 THEN 
+				point_position := 0; 
+			END IF;
+	
+		SELECT the_geom INTO STRICT old_geom FROM units_tracks WHERE gid=track_gid
+		AND unit_id=NEW.unit_id;
+	
+		UPDATE units_tracks SET the_geom = addPoint(old_geom, NEW.the_geom, point_position) WHERE gid=track_gid;
+	END IF;
+
+
+RETURN NEW;
+
+END IF;
+RETURN NEW;
+END; 
+$$;
+
+
+CREATE FUNCTION maplog.generate_positions() RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+declare
+lastx double precision;
+lasty double precision;
+newx double precision;
+newy double precision;
+unit record;
+timenow timestamp;
+geom text;
+BEGIN 
+
+ FOR unit IN SELECT * FROM units LOOP
+	SELECT x(the_geom) INTO lastx FROM last_units_positions WHERE unit_id = unit.unit_id;
+	SELECT y(the_geom) INTO lasty FROM last_units_positions WHERE unit_id = unit.unit_id;
+    
+	newx := lastx + (random()*0.002) - (random()*0.002);
+        newy := lasty + (random()*0.002) - (random()*0.002);
+        SELECT now() INTO timenow;
+	
+	 geom := 'POINT(' || newx::text || ' ' || newy::text || ')'; 
+
+        INSERT INTO units_positions(the_geom, unit_id, time_stamp) 
+        values ( GeomFromText((geom),4326), unit.unit_id, timenow);
+        raise notice 'Add Positiont for Unit %', unit.unit_id;
+ END LOOP;
+
+
+END ;
+$$;
+
+
+--
+-- TOC entry 166 (class 1255 OID 22479)
+-- Dependencies: 1203 7
+-- Name: generate_units(integer); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.generate_units(number_of_units integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_unit_id integer;
+x  double precision;
+y  double precision;
+geom text;
+timenow timestamp;
+BEGIN 
+this_unit_id := 1;
+ WHILE (this_unit_id < number_of_units) LOOP
+	
+	x := 14 + this_unit_id * 0.01;
+        y := 50 ;
+        SELECT now() INTO timenow;
+	
+	geom := 'POINT(' || x::text || ' ' || y::text || ')'; 
+
+        INSERT INTO units_positions(the_geom, unit_id, time_stamp) 
+        values ( GeomFromText((geom),4326), this_unit_id, timenow);
+        raise notice 'Add Positiont for Unit %', this_unit_id;
+
+         this_unit_id:=this_unit_id+1;
+ END LOOP;
+
+
+END ;
+$$;
+
+
+
+CREATE FUNCTION maplog.get_unit_running_track_gid(this_unit_id integer) RETURNS integer
+    LANGUAGE plpgsql
+    AS $$
+declare
+tracks_gid integer; 
+
+BEGIN 
+SELECT gid  INTO tracks_gid FROM running_tracks WHERE unit_id=this_unit_id LIMIT 1;
+return tracks_gid;
+END; 
+$$;
+
+
+--
+-- TOC entry 293 (class 1255 OID 19196)
+-- Dependencies: 1203 7
+-- Name: get_unit_running_track_gid(bigint); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.get_unit_running_track_gid(this_unit_id bigint) RETURNS integer
+    LANGUAGE plpgsql
+    AS $$
+declare
+tracks_gid integer; 
+
+BEGIN 
+SELECT gid  INTO tracks_gid FROM running_tracks WHERE unit_id=this_unit_id LIMIT 1;
+return tracks_gid;
+END; 
+$$;
+
+
+--
+CREATE FUNCTION maplog.mergetracks(track1_gid integer, track2_gid integer) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+declare
+track1 record;
+track2 record;
+newtrack geometry;
+BEGIN 
+SELECT * INTO track1 FROM units_tracks WHERE gid = track1_gid;	
+SELECT * INTO track2 FROM units_tracks WHERE gid = track2_gid;	
+
+if (track1.track_start < track2.track_end AND track1.track_end = track2.track_start) THEN
+
+	SELECT linemerge(collect(the_geom)) INTO newtrack
+	FROM
+	(SELECT track1.the_geom AS the_geom
+	UNION
+	SELECT track2.the_geom AS the_geom) AS the_geom;
+
+	UPDATE units_tracks
+	SET
+	the_geom=newtrack,
+	track_start=track1.track_start,
+	track_end= track2.track_end
+	WHERE gid=track1_gid;
+
+	DELETE FROM units_tracks WHERE  gid=track2_gid;
+	return true;
+
+END IF;
+return false;
+END; 
+$$;
+
+
+--
+-- TOC entry 737 (class 1255 OID 1410624)
+-- Dependencies: 1203 7
+-- Name: ml_update_times(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.ml_update_times() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_first_obs timestamp; 
+this_last_obs timestamp; 
+
+BEGIN 
+
+SELECT first_obs INTO this_first_obs FROM units_to_sensors WHERE sensor_id = NEW.sensor_id
+AND unit_id = NEW.unit_id;
+
+SELECT last_obs INTO this_last_obs FROM units_to_sensors WHERE sensor_id = NEW.sensor_id
+AND unit_id = NEW.unit_id;
+
+IF this_first_obs IS NULL OR this_last_obs IS NULL THEN
+	IF this_first_obs IS NULL THEN
+	raise notice '% sensor metadata not found - adding from observations', NEW.sensor_id;
+		SELECT time_stamp INTO this_first_obs FROM observations 
+		WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id ORDER BY time_stamp limit 1;
+	
+	UPDATE units_to_sensors 
+	SET first_obs = this_first_obs WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id;  
+	END IF;
+
+	IF this_last_obs IS NULL THEN
+	raise notice '% sensor metadata not found - adding from observations', NEW.sensor_id;
+		SELECT time_stamp INTO this_last_obs FROM observations 
+		WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id ORDER BY time_stamp DESC limit 1;
+	
+	UPDATE units_to_sensors 
+	SET last_obs = this_last_obs WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id;  
+	END IF;	
+ELSE 
+	IF NEW.time_stamp < this_first_obs THEN
+	UPDATE units_to_sensors 
+	SET first_obs = NEW.time_stamp WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id;  
+	END IF;
+
+
+	IF NEW.time_stamp > this_last_obs THEN
+	UPDATE units_to_sensors 
+	SET last_obs = NEW.time_stamp WHERE sensor_id = NEW.sensor_id AND unit_id = NEW.unit_id;  
+	END IF;
+	RETURN NEW;
+END IF;	
+RETURN NEW;
+END; 
+$$;
+
+
+--
+
+CREATE FUNCTION maplog.on_delete_alert() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+DELETE FROM alert_events WHERE alert_id = OLD.alert_id;
+DELETE FROM alert_queries WHERE alert_id = OLD.alert_id;
+
+return OLD;
+END; 
+$$;
+
+
+--
+-- TOC entry 740 (class 1255 OID 1411912)
+-- Dependencies: 7 1203
+-- Name: on_delete_alert_query(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.on_delete_alert_query() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+DELETE FROM alert_queries_to_units WHERE query_id = OLD.query_id;
+
+return OLD;
+END; 
+$$;
+
+
+--
+-- TOC entry 742 (class 1255 OID 1412050)
+-- Dependencies: 7 1203
+-- Name: on_delete_driver(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.on_delete_driver() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+
+
+DELETE FROM units_to_drivers WHERE driver_id = OLD.driver_id;
+return OLD;
+END; 
+$$;
+
+
+--
+-- TOC entry 45 (class 1255 OID 90640)
+-- Dependencies: 7 1203
+-- Name: on_delete_group(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.on_delete_group() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+
+
+DELETE FROM units_to_groups WHERE group_id = OLD.id;
+UPDATE system_users
+SET group_id=NULL WHERE group_id=OLD.id;
+return OLD;
+END; 
+$$;
+
+
+--
+-- TOC entry 46 (class 1255 OID 80993)
+-- Dependencies: 7 1203
+-- Name: on_delete_position(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.on_delete_position() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+
+DELETE FROM observations WHERE gid = OLD.gid;
+DELETE FROM last_units_positions WHERE gid = OLD.gid;
+
+return OLD;
+END; 
+$$;
+
+
+--
+-- TOC entry 741 (class 1255 OID 19290)
+-- Dependencies: 7 1203
+-- Name: on_delete_unit(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.on_delete_unit() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+
+BEGIN 
+
+DELETE FROM alert_events WHERE unit_id = OLD.unit_id;
+DELETE FROM alert_queries_to_units WHERE unit_id = OLD.unit_id;
+DELETE FROM units_tracks WHERE unit_id = OLD.unit_id;
+DELETE FROM last_ignition_status WHERE unit_id = OLD.unit_id;
+DELETE FROM ignition_status WHERE unit_id = OLD.unit_id;
+DELETE FROM observations WHERE unit_id = OLD.unit_id;
+DELETE FROM units_to_sensors WHERE unit_id = OLD.unit_id;
+DELETE FROM last_units_positions WHERE unit_id = OLD.unit_id;
+DELETE FROM units_conf WHERE unit_id = OLD.unit_id;
+DELETE FROM units_tracks_conf WHERE unit_id = OLD.unit_id;
+DELETE FROM units_positions WHERE unit_id = OLD.unit_id;
+DELETE FROM observations_recent WHERE unit_id = OLD.unit_id;
+DELETE FROM units_positions_recent WHERE unit_id = OLD.unit_id;
+DELETE FROM units_to_groups WHERE unit_id = OLD.unit_id;
+DELETE FROM units_to_drivers WHERE unit_id = OLD.unit_id;
+return OLD;
+END; 
+$$;
+
+
+
+CREATE FUNCTION maplog.sos_check_tracks(this_unit_id bigint, time_now timestamp without time zone) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+declare
+track_gid integer; 
+this_track_end timestamp;
+this_max_time interval;
+BEGIN 
+
+SELECT gid INTO track_gid  
+FROM running_tracks WHERE unit_id = this_unit_id;
+
+
+SELECT track_end INTO this_track_end 
+FROM units_tracks WHERE gid = track_gid;
+
+SELECT max_time_span INTO this_max_time
+FROM units_tracks_conf WHERE unit_id = this_unit_id;
+
+IF this_max_time IS NOT NULL AND ((time_now - this_track_end ) > this_max_time) THEN 
+
+	DELETE FROM running_tracks WHERE gid = track_gid;
+RETURN TRUE;
+END IF;
+ RETURN FALSE;
+
+END; 
+$$;
+
+
+--
+-- TOC entry 429 (class 1255 OID 19355)
+-- Dependencies: 7 1203
+-- Name: sos_check_tracks(); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.sos_check_tracks() RETURNS integer
+    LANGUAGE plpgsql
+    AS $$
+declare
+time_now timestamp;
+i integer;
+row record;
+
+BEGIN 
+i:=0;
+time_now:= now();
+FOR row IN SELECT * FROM units
+LOOP
+PERFORM sos_check_tracks(row.unit_id, time_now) ;
+i:=i+1;
+END LOOP;
+RETURN i;
+END; 
+$$;
+
+
+
+
+--
+-- TOC entry 717 (class 1255 OID 90583)
+-- Dependencies: 7 1203
+-- Name: starttrack(integer); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.starttrack(position_gid integer) RETURNS void
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_position record;
+line_geom geometry;
+BEGIN 
+SELECT * INTO this_position FROM units_positions WHERE gid = position_gid;
+	line_geom = MakeLine(this_position.the_geom);
+
+	INSERT INTO units_tracks(the_geom, unit_id, track_start, track_end)
+	values (line_geom, this_position.unit_id, this_position.time_stamp, this_position.time_stamp);
+
+END; 
+$$;
+
+
+--
+-- TOC entry 716 (class 1255 OID 90642)
+-- Dependencies: 1203 7
+-- Name: starttrack(timestamp without time zone, bigint); Type: FUNCTION; Schema: public; Owner: -
+--
+
+CREATE FUNCTION maplog.starttrack(this_time_stamp timestamp without time zone, this_unit_id bigint) RETURNS boolean
+    LANGUAGE plpgsql
+    AS $$
+declare
+this_position record;
+line_geom geometry;
+BEGIN 
+SELECT * INTO this_position FROM units_positions 
+WHERE time_stamp = this_time_stamp AND unit_id = this_unit_id;
+	line_geom = MakeLine(this_position.the_geom);
+
+	IF this_position.gid IS NOT NULL THEN
+	INSERT INTO units_tracks(the_geom, unit_id, track_start, track_end)
+	values (line_geom, this_position.unit_id, this_position.time_stamp, this_position.time_stamp);
+	return true;
+	ELSE
+		return false;
+	END IF;
+
+END; 
+$$;
+
+
+
+CREATE FUNCTION maplog.update_group() RETURNS trigger
+    LANGUAGE plpgsql
+    AS $$
+declare
+super_group record;
+
+BEGIN
+
+IF NEW.parent_group_id IS NOT NULL THEN
+	SELECT * INTO super_group FROM groups WHERE id = NEW.parent_group_id;
+	UPDATE groups
+               SET has_children = true
+               WHERE groups.id = NEW.parent_group_id    ;  
+      RETURN NEW;       
+ELSE
+RETURN NEW;
+END IF;
+END;
+
+$$;
+

+ 1254 - 0
src/main/db/iso.sql

@@ -0,0 +1,1254 @@
+
+SET search_path = maplog;
+
+ALTER TABLE maplog.geom_alerts_conf ALTER COLUMN geom_alerts_conf_id SET DEFAULT nextval('maplog.geom_alerts_conf_geom_alerts_conf_id_seq'::regclass);
+
+
+--
+-- TOC entry 2779 (class 2604 OID 19892)
+-- Dependencies: 2430 2429
+-- Name: id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.groups ALTER COLUMN id SET DEFAULT nextval('maplog.groups_id_seq'::regclass);
+
+
+--
+-- TOC entry 2780 (class 2604 OID 19893)
+-- Dependencies: 2432 2431
+-- Name: gid; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.last_units_positions ALTER COLUMN gid SET DEFAULT nextval('maplog.last_units_positions_gid_seq'::regclass);
+
+
+--
+-- TOC entry 2781 (class 2604 OID 19894)
+-- Dependencies: 2434 2433
+-- Name: obs_alerts_conf_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.obs_alerts_conf ALTER COLUMN obs_alerts_conf_id SET DEFAULT nextval('maplog.obs_alerts_conf_obs_alerts_conf_id_seq'::regclass);
+
+
+--
+-- TOC entry 2782 (class 2604 OID 19895)
+-- Dependencies: 2436 2435
+-- Name: observation_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.observations ALTER COLUMN observation_id SET DEFAULT nextval('maplog.observations_observation_id_seq'::regclass);
+
+
+--
+-- TOC entry 2784 (class 2604 OID 19896)
+-- Dependencies: 2441 2440
+-- Name: sensor_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.sensors ALTER COLUMN sensor_id SET DEFAULT nextval('maplog.sensors_sensor_id_seq'::regclass);
+
+
+--
+-- TOC entry 2785 (class 2604 OID 19897)
+-- Dependencies: 2444 2443
+-- Name: user_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.system_users ALTER COLUMN user_id SET DEFAULT nextval('maplog.system_users_user_id_seq'::regclass);
+
+
+--
+-- TOC entry 2791 (class 2604 OID 19898)
+-- Dependencies: 2462 2445
+-- Name: holder_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.unit_holders ALTER COLUMN holder_id SET DEFAULT nextval('maplog.users_user_id_seq'::regclass);
+
+
+--
+-- TOC entry 2802 (class 2604 OID 19900)
+-- Dependencies: 2453 2452
+-- Name: gid; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.units_positions ALTER COLUMN gid SET DEFAULT nextval('maplog.units_positions_gid_seq'::regclass);
+
+
+
+
+--
+-- TOC entry 2803 (class 2604 OID 19902)
+-- Dependencies: 2455 2454
+-- Name: id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.units_to_groups ALTER COLUMN id SET DEFAULT nextval('maplog.units_to_groups_id_seq'::regclass);
+
+
+--
+-- TOC entry 2805 (class 2604 OID 19903)
+-- Dependencies: 2461 2458
+-- Name: gid; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.units_tracks ALTER COLUMN gid SET DEFAULT nextval('maplog.units_tracks_gid_seq'::regclass);
+
+
+--
+-- TOC entry 2808 (class 2604 OID 19904)
+-- Dependencies: 2460 2459
+-- Name: units_tracks_settings_id; Type: DEFAULT; Schema: public; Owner: -
+--
+
+ALTER TABLE maplog.units_tracks_conf ALTER COLUMN units_tracks_settings_id SET DEFAULT nextval('maplog.units_tracks_conf_units_tracks_settings_id_seq'::regclass);
+
+
+--
+-- TOC entry 2897 (class 2606 OID 1411887)
+-- Dependencies: 2477 2477
+-- Name: alert_event_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.alert_events
+    ADD CONSTRAINT alert_event_pk PRIMARY KEY (alert_event_id);
+
+
+--
+-- TOC entry 2893 (class 2606 OID 1411875)
+-- Dependencies: 2476 2476
+-- Name: alert_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.alerts
+    ADD CONSTRAINT alert_pk PRIMARY KEY (alert_id);
+
+
+--
+-- TOC entry 2902 (class 2606 OID 1411930)
+-- Dependencies: 2479 2479
+-- Name: alert_queries_to_units_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.alert_queries_to_units
+    ADD CONSTRAINT alert_queries_to_units_pkey PRIMARY KEY (id);
+
+
+--
+-- TOC entry 2899 (class 2606 OID 1411918)
+-- Dependencies: 2478 2478
+-- Name: alert_query_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.alert_queries
+    ADD CONSTRAINT alert_query_pk PRIMARY KEY (query_id);
+
+
+--
+-- TOC entry 2895 (class 2606 OID 1411877)
+-- Dependencies: 2476 2476
+-- Name: alerts_alert_description_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.alerts
+    ADD CONSTRAINT alerts_alert_description_key UNIQUE (alert_description);
+
+
+--
+-- TOC entry 2831 (class 2606 OID 19906)
+-- Dependencies: 2433 2433
+-- Name: alerts_conf_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.obs_alerts_conf
+    ADD CONSTRAINT alerts_conf_pk PRIMARY KEY (obs_alerts_conf_id);
+
+
+
+--
+-- TOC entry 2821 (class 2606 OID 19908)
+-- Dependencies: 2426 2426
+-- Name: geom_alerts_conf_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.geom_alerts_conf
+    ADD CONSTRAINT geom_alerts_conf_pk PRIMARY KEY (geom_alerts_conf_id);
+
+
+--
+-- TOC entry 2823 (class 2606 OID 19910)
+-- Dependencies: 2428 2428 2428 2428 2428
+-- Name: geometry_columns_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.geometry_columns
+    ADD CONSTRAINT geometry_columns_pk PRIMARY KEY (f_table_catalog, f_table_schema, f_table_name, f_geometry_column);
+
+
+--
+-- TOC entry 2825 (class 2606 OID 19912)
+-- Dependencies: 2429 2429
+-- Name: group_id_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.groups
+    ADD CONSTRAINT group_id_pk PRIMARY KEY (id);
+
+
+--
+-- TOC entry 2904 (class 2606 OID 1412015)
+-- Dependencies: 2480 2480
+-- Name: last_status_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.last_ignition_status
+    ADD CONSTRAINT last_status_pk PRIMARY KEY (observation_id);
+
+
+--
+-- TOC entry 2827 (class 2606 OID 19914)
+-- Dependencies: 2431 2431
+-- Name: last_units_positions_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.last_units_positions
+    ADD CONSTRAINT last_units_positions_pk PRIMARY KEY (gid);
+
+
+--
+-- TOC entry 2924 (class 2606 OID 1472762)
+-- Dependencies: 2492 2492 2492
+-- Name: obs_to_obs_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.obs_to_obs
+    ADD CONSTRAINT obs_to_obs_pkey PRIMARY KEY (main_obs_id, sec_obs_id);
+
+
+
+
+--
+-- TOC entry 2834 (class 2606 OID 19918)
+-- Dependencies: 2435 2435
+-- Name: observation_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.observations
+    ADD CONSTRAINT observation_pk PRIMARY KEY (observation_id);
+
+
+--
+-- TOC entry 2838 (class 2606 OID 1443286)
+-- Dependencies: 2435 2435 2435 2435
+-- Name: observations_time_stamp_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.observations
+    ADD CONSTRAINT observations_time_stamp_key UNIQUE (time_stamp, sensor_id, unit_id);
+
+
+--
+-- TOC entry 2846 (class 2606 OID 19920)
+-- Dependencies: 2438 2438
+-- Name: phenomenon_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.phenomenons
+    ADD CONSTRAINT phenomenon_pk PRIMARY KEY (phenomenon_id);
+
+
+--
+-- TOC entry 2916 (class 2606 OID 1412303)
+-- Dependencies: 2486 2486
+-- Name: rights_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.rights
+    ADD CONSTRAINT rights_pkey PRIMARY KEY (rights_id);
+
+
+--
+-- TOC entry 2918 (class 2606 OID 1412305)
+-- Dependencies: 2486 2486
+-- Name: rights_role_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.maplog.rights
+    ADD CONSTRAINT rights_role_key UNIQUE (user_role);
+
+
+
+--
+-- TOC entry 2851 (class 2606 OID 19924)
+-- Dependencies: 2440 2440
+-- Name: sensor_id; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.sensors
+    ADD CONSTRAINT sensor_id PRIMARY KEY (sensor_id);
+
+
+--
+-- TOC entry 2891 (class 2606 OID 113872)
+-- Dependencies: 2468 2468
+-- Name: sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.sessions
+    ADD CONSTRAINT sessions_pkey PRIMARY KEY (session_id);
+
+
+
+--
+-- TOC entry 2908 (class 2606 OID 1412033)
+-- Dependencies: 2481 2481
+-- Name: status_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.ignition_status
+    ADD CONSTRAINT status_pk PRIMARY KEY (observation_id);
+
+
+--
+-- TOC entry 2854 (class 2606 OID 19928)
+-- Dependencies: 2440 2440
+-- Name: unique_name; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.sensors
+    ADD CONSTRAINT unique_name UNIQUE (sensor_name);
+
+
+--
+-- TOC entry 2910 (class 2606 OID 1412066)
+-- Dependencies: 2483 2483 2483
+-- Name: unit_drivers_fname_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.unit_drivers
+    ADD CONSTRAINT unit_drivers_fname_key UNIQUE (fname, lname);
+
+
+--
+-- TOC entry 2912 (class 2606 OID 1412064)
+-- Dependencies: 2483 2483
+-- Name: unit_drivers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.unit_drivers
+    ADD CONSTRAINT unit_drivers_pkey PRIMARY KEY (driver_id);
+
+
+--
+-- TOC entry 2860 (class 2606 OID 1412287)
+-- Dependencies: 2445 2445
+-- Name: unit_holders_holder_name_key; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.unit_holders
+    ADD CONSTRAINT unit_holders_holder_name_key UNIQUE (holder_name);
+
+
+--
+-- TOC entry 2829 (class 2606 OID 19930)
+-- Dependencies: 2431 2431
+-- Name: unit_id_unique; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.last_units_positions
+    ADD CONSTRAINT unit_id_unique UNIQUE (unit_id);
+
+
+--
+-- TOC entry 2864 (class 2606 OID 19932)
+-- Dependencies: 2446 2446
+-- Name: unit_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units
+    ADD CONSTRAINT unit_pk PRIMARY KEY (unit_id);
+
+
+--
+-- TOC entry 2872 (class 2606 OID 19934)
+-- Dependencies: 2452 2452
+-- Name: unit_position_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_positions
+    ADD CONSTRAINT unit_position_pk PRIMARY KEY (gid);
+
+
+--
+-- TOC entry 2878 (class 2606 OID 19936)
+-- Dependencies: 2454 2454 2454
+-- Name: unit_to_group; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_to_groups
+    ADD CONSTRAINT unit_to_group UNIQUE (group_id, unit_id);
+
+
+--
+-- TOC entry 2866 (class 2606 OID 19938)
+-- Dependencies: 2447 2447
+-- Name: units_conf_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_conf
+    ADD CONSTRAINT units_conf_pk PRIMARY KEY (unit_id);
+
+
+--
+-- TOC entry 2868 (class 2606 OID 19940)
+-- Dependencies: 2448 2448
+-- Name: units_history_points_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_positions_recent
+    ADD CONSTRAINT units_history_points_pk PRIMARY KEY (gid);
+
+
+
+--
+-- TOC entry 2914 (class 2606 OID 1412080)
+-- Dependencies: 2485 2485
+-- Name: units_to_drivers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_to_drivers
+    ADD CONSTRAINT units_to_drivers_pkey PRIMARY KEY (id);
+
+
+--
+-- TOC entry 2880 (class 2606 OID 19944)
+-- Dependencies: 2454 2454
+-- Name: units_to_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_to_groups
+    ADD CONSTRAINT units_to_groups_pkey PRIMARY KEY (id);
+
+
+--
+-- TOC entry 2882 (class 2606 OID 1410607)
+-- Dependencies: 2456 2456 2456
+-- Name: units_to_sensors_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_to_sensors
+    ADD CONSTRAINT units_to_sensors_pkey PRIMARY KEY (sensor_id, unit_id);
+
+
+--
+-- TOC entry 2889 (class 2606 OID 19946)
+-- Dependencies: 2459 2459
+-- Name: units_tracks_conf_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_tracks_conf
+    ADD CONSTRAINT units_tracks_conf_pk PRIMARY KEY (units_tracks_settings_id);
+
+
+--
+-- TOC entry 2887 (class 2606 OID 19948)
+-- Dependencies: 2458 2458
+-- Name: units_tracks_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.units_tracks
+    ADD CONSTRAINT units_tracks_pk PRIMARY KEY (gid);
+
+
+--
+-- TOC entry 2858 (class 2606 OID 19950)
+-- Dependencies: 2443 2443
+-- Name: user_id_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.system_users
+    ADD CONSTRAINT user_id_pk PRIMARY KEY (user_id);
+
+
+--
+-- TOC entry 2862 (class 2606 OID 19952)
+-- Dependencies: 2445 2445
+-- Name: user_pk; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
+--
+
+ALTER TABLE ONLY maplog.unit_holders
+    ADD CONSTRAINT user_pk PRIMARY KEY (holder_id);
+
+
+--
+-- TOC entry 2883 (class 1259 OID 90474)
+-- Dependencies: 2458
+-- Name: end_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX end_index ON maplog.units_tracks USING btree (track_end);
+
+
+--
+-- TOC entry 2900 (class 1259 OID 1411943)
+-- Dependencies: 2478
+-- Name: fki_alert_id_FK; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX "fki_alert_id_FK" ON maplog.alert_queries USING btree (alert_id);
+
+
+--
+-- TOC entry 2876 (class 1259 OID 19953)
+-- Dependencies: 2454
+-- Name: group_id_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX group_id_index ON maplog.units_to_groups USING btree (group_id);
+
+
+--
+-- TOC entry 2905 (class 1259 OID 1412044)
+-- Dependencies: 2481
+-- Name: ignition_i_gid; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX ignition_i_gid ON maplog.ignition_status USING btree (gid DESC NULLS LAST);
+
+
+--
+-- TOC entry 2906 (class 1259 OID 1412045)
+-- Dependencies: 2481
+-- Name: ignition_i_timestamp; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX ignition_i_timestamp ON maplog.ignition_status USING btree (time_stamp DESC NULLS LAST);
+
+
+--
+-- TOC entry 2832 (class 1259 OID 19954)
+-- Dependencies: 2435
+-- Name: observation_gid_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX observation_gid_index ON maplog.observations USING btree (gid);
+
+
+
+--
+-- TOC entry 2835 (class 1259 OID 19957)
+-- Dependencies: 2435
+-- Name: observation_sensor_id_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX observation_sensor_id_index ON maplog.observations USING btree (sensor_id);
+
+
+
+
+
+
+
+--
+-- TOC entry 2836 (class 1259 OID 19960)
+-- Dependencies: 2435
+-- Name: observations_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX observations_index ON maplog.observations USING btree (time_stamp);
+
+
+--
+-- TOC entry 2839 (class 1259 OID 19961)
+-- Dependencies: 2435
+-- Name: observations_unit_id; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX observations_unit_id ON maplog.observations USING btree (unit_id);
+
+
+
+
+--
+-- TOC entry 2852 (class 1259 OID 19963)
+-- Dependencies: 2440
+-- Name: sensors_phenomenon_id_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX sensors_phenomenon_id_index ON maplog.sensors USING btree (phenomenon_id);
+
+
+--
+-- TOC entry 2884 (class 1259 OID 90473)
+-- Dependencies: 2458
+-- Name: start_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX start_index ON maplog.units_tracks USING btree (track_start);
+
+
+--
+-- TOC entry 2885 (class 1259 OID 19964)
+-- Dependencies: 2458
+-- Name: tracks_gid_index; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX tracks_gid_index ON maplog.units_tracks USING btree (gid);
+
+
+--
+-- TOC entry 2873 (class 1259 OID 19965)
+-- Dependencies: 2452
+-- Name: unit_position_time_stamp; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX unit_position_time_stamp ON maplog.units_positions USING btree (time_stamp);
+
+
+--
+-- TOC entry 2874 (class 1259 OID 19966)
+-- Dependencies: 2056 2452
+-- Name: units_positins_gid; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX units_positins_gid ON maplog.units_positions USING gist (the_geom);
+
+
+--
+-- TOC entry 2875 (class 1259 OID 19967)
+-- Dependencies: 2452
+-- Name: units_positions_unit_id; Type: INDEX; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE INDEX units_positions_unit_id ON maplog.units_positions USING btree (unit_id);
+
+
+--
+-- TOC entry 2988 (class 2620 OID 1411903)
+-- Dependencies: 739 2477
+-- Name: add_alert; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_alert
+    BEFORE INSERT ON alert_events
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_alert();
+
+
+--
+-- TOC entry 2978 (class 2620 OID 19968)
+-- Dependencies: 41 2446
+-- Name: add_conf_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_conf_trigger
+    AFTER INSERT ON units
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit_conf();
+
+
+--
+-- TOC entry 2989 (class 2620 OID 1411904)
+-- Dependencies: 23 2477
+-- Name: add_gid_to_observation; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_gid_to_observation
+    BEFORE INSERT ON maplog.alert_events
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_gid_to_observation();
+
+
+--
+-- TOC entry 2969 (class 2620 OID 19969)
+-- Dependencies: 23 2435
+-- Name: add_gid_to_observation_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_gid_to_observation_trigger
+    BEFORE INSERT OR UPDATE ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_gid_to_observation();
+
+
+--
+-- TOC entry 2976 (class 2620 OID 19970)
+-- Dependencies: 24 2440
+-- Name: add_phenomenon_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_phenomenon_trigger
+    BEFORE INSERT OR UPDATE ON sensors
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_phenomenon();
+
+
+--
+-- TOC entry 2970 (class 2620 OID 19971)
+-- Dependencies: 26 2435
+-- Name: add_sensor; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_sensor
+    BEFORE INSERT OR UPDATE ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_sensor();
+
+
+--
+-- TOC entry 2981 (class 2620 OID 80912)
+-- Dependencies: 2446 28
+-- Name: add_to_admin; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_to_admin
+    AFTER INSERT OR UPDATE ON units
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit_to_admin();
+
+
+--
+-- TOC entry 2979 (class 2620 OID 19972)
+-- Dependencies: 2446 43
+-- Name: add_track_conf_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_track_conf_trigger
+    AFTER INSERT ON units
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit_track_conf();
+
+
+--
+-- TOC entry 2971 (class 2620 OID 19973)
+-- Dependencies: 2435 27
+-- Name: add_unit_triger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER add_unit_triger
+    BEFORE INSERT OR UPDATE ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit();
+
+
+--
+-- TOC entry 2975 (class 2620 OID 1412142)
+-- Dependencies: 2435 743
+-- Name: copy_ignition_status; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER copy_ignition_status
+    AFTER INSERT ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE copy_ignition_status();
+
+
+
+
+
+--
+-- TOC entry 2990 (class 2620 OID 1411924)
+-- Dependencies: 740 2478
+-- Name: delete_alert_query_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER delete_alert_query_trigger
+    BEFORE DELETE ON alert_queries
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_alert_query();
+
+
+--
+-- TOC entry 2987 (class 2620 OID 1411878)
+-- Dependencies: 738 2476
+-- Name: delete_alert_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER delete_alert_trigger
+    BEFORE DELETE ON alerts
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_alert();
+
+
+--
+-- TOC entry 2991 (class 2620 OID 1412067)
+-- Dependencies: 2483 742
+-- Name: delete_driver_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER delete_driver_trigger
+    BEFORE DELETE ON unit_drivers
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_driver();
+
+
+--
+-- TOC entry 2980 (class 2620 OID 19976)
+-- Dependencies: 2446 741
+-- Name: delete_unit_trigger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER delete_unit_trigger
+    BEFORE DELETE ON units
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_unit();
+
+
+--
+-- TOC entry 2985 (class 2620 OID 80996)
+-- Dependencies: 46 2452
+-- Name: on_delete; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER on_delete
+    BEFORE DELETE ON units_positions
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_position();
+
+
+--
+-- TOC entry 2968 (class 2620 OID 90641)
+-- Dependencies: 2429 45
+-- Name: on_delete; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER on_delete
+    BEFORE DELETE ON groups
+    FOR EACH ROW
+    EXECUTE PROCEDURE on_delete_group();
+
+
+--
+-- TOC entry 2977 (class 2620 OID 19978)
+-- Dependencies: 2440 35
+-- Name: on_delete_sensor; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER on_delete_sensor
+    BEFORE DELETE ON sensors
+    FOR EACH ROW
+    EXECUTE PROCEDURE delete_sensor();
+
+
+--
+-- TOC entry 2983 (class 2620 OID 19979)
+-- Dependencies: 2452 746
+-- Name: trig_add_last_pos; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER trig_add_last_pos
+    AFTER INSERT OR UPDATE ON units_positions
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_last_unit_position();
+
+
+--
+-- TOC entry 2986 (class 2620 OID 1412168)
+-- Dependencies: 2452 745
+-- Name: trig_cosider_add_pos2; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER trig_cosider_add_pos2
+    BEFORE INSERT ON units_positions
+    FOR EACH ROW
+    EXECUTE PROCEDURE consider_insert_position2();
+
+
+--
+-- TOC entry 2982 (class 2620 OID 19981)
+-- Dependencies: 27 2452
+-- Name: trig_unit; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER trig_unit
+    BEFORE INSERT OR UPDATE ON units_positions
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit();
+
+
+--
+-- TOC entry 2972 (class 2620 OID 19982)
+-- Dependencies: 42 2435
+-- Name: unit_to_sensor_triger; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER unit_to_sensor_triger
+    BEFORE INSERT OR UPDATE ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE add_unit_to_sensor();
+
+
+--
+-- TOC entry 2967 (class 2620 OID 19983)
+-- Dependencies: 122 2429
+-- Name: update_is_parent; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER update_is_parent
+    AFTER INSERT OR UPDATE ON groups
+    FOR EACH ROW
+    EXECUTE PROCEDURE update_group();
+
+
+--
+-- TOC entry 2974 (class 2620 OID 1410625)
+-- Dependencies: 2435 737
+-- Name: update_sensor_time; Type: TRIGGER; Schema: public; Owner: -
+--
+
+CREATE TRIGGER update_sensor_time
+    AFTER INSERT OR UPDATE ON observations
+    FOR EACH ROW
+    EXECUTE PROCEDURE ml_update_times();
+
+
+--
+-- TOC entry 2952 (class 2606 OID 1411888)
+-- Dependencies: 2477 2476 2892
+-- Name: alert_event_to_alert_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_events
+    ADD CONSTRAINT alert_event_to_alert_id_fk FOREIGN KEY (alert_id) REFERENCES alerts(alert_id);
+
+
+--
+-- TOC entry 2953 (class 2606 OID 1411893)
+-- Dependencies: 2477 2452 2871
+-- Name: alert_event_to_gid_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_events
+    ADD CONSTRAINT alert_event_to_gid_fk FOREIGN KEY (gid) REFERENCES units_positions(gid);
+
+
+--
+-- TOC entry 2954 (class 2606 OID 1411898)
+-- Dependencies: 2477 2446 2863
+-- Name: alert_event_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_events
+    ADD CONSTRAINT alert_event_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2955 (class 2606 OID 1411919)
+-- Dependencies: 2478 2476 2892
+-- Name: alert_id_FK; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_queries
+    ADD CONSTRAINT "alert_id_FK" FOREIGN KEY (alert_id) REFERENCES alerts(alert_id);
+
+
+--
+-- TOC entry 2929 (class 2606 OID 19984)
+-- Dependencies: 2433 2438 2845
+-- Name: alerts_conf_to_phenomenon_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.obs_alerts_conf
+    ADD CONSTRAINT alerts_conf_to_phenomenon_id_fk FOREIGN KEY (phenomenon_id) REFERENCES phenomenons(phenomenon_id);
+
+
+--
+-- TOC entry 2930 (class 2606 OID 19989)
+-- Dependencies: 2863 2446 2433
+-- Name: alerts_conf_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.obs_alerts_conf
+    ADD CONSTRAINT alerts_conf_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+
+
+--
+-- TOC entry 2925 (class 2606 OID 19994)
+-- Dependencies: 2426 2863 2446
+-- Name: geom_alerts_conf_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.geom_alerts_conf
+    ADD CONSTRAINT geom_alerts_conf_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2945 (class 2606 OID 19999)
+-- Dependencies: 2454 2429 2824
+-- Name: group_id_pk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_to_groups
+    ADD CONSTRAINT group_id_pk FOREIGN KEY (group_id) REFERENCES groups(id);
+
+
+--
+-- TOC entry 2927 (class 2606 OID 20004)
+-- Dependencies: 2452 2871 2431
+-- Name: last_pos_gid; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.last_units_positions
+    ADD CONSTRAINT last_pos_gid FOREIGN KEY (gid) REFERENCES units_positions(gid);
+
+
+--
+-- TOC entry 2958 (class 2606 OID 1412016)
+-- Dependencies: 2452 2480 2871
+-- Name: last_status_to_gid; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.last_ignition_status
+    ADD CONSTRAINT last_status_to_gid FOREIGN KEY (gid) REFERENCES units_positions(gid);
+
+
+--
+-- TOC entry 2959 (class 2606 OID 1412021)
+-- Dependencies: 2863 2480 2446
+-- Name: last_status_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.last_ignition_status
+    ADD CONSTRAINT last_status_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2928 (class 2606 OID 20009)
+-- Dependencies: 2431 2446 2863
+-- Name: last_units_positions_to_unit_name_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.last_units_positions
+    ADD CONSTRAINT last_units_positions_to_unit_name_fkey FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2966 (class 2606 OID 1472778)
+-- Dependencies: 2833 2492 2435
+-- Name: obs_to_obs_main_obs_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.obs_to_obs
+    ADD CONSTRAINT obs_to_obs_main_obs_id_fkey FOREIGN KEY (main_obs_id) REFERENCES observations(observation_id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- TOC entry 2965 (class 2606 OID 1472773)
+-- Dependencies: 2833 2435 2492
+-- Name: obs_to_obs_sec_obs_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.obs_to_obs
+    ADD CONSTRAINT obs_to_obs_sec_obs_id_fkey FOREIGN KEY (sec_obs_id) REFERENCES observations(observation_id) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+
+--
+-- TOC entry 2931 (class 2606 OID 20029)
+-- Dependencies: 2452 2435 2871
+-- Name: observation_to_gid; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.observations
+    ADD CONSTRAINT observation_to_gid FOREIGN KEY (gid) REFERENCES units_positions(gid);
+
+
+--
+-- TOC entry 2932 (class 2606 OID 20034)
+-- Dependencies: 2440 2850 2435
+-- Name: observation_to_sensor_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.observations
+    ADD CONSTRAINT observation_to_sensor_fk FOREIGN KEY (sensor_id) REFERENCES sensors(sensor_id);
+
+
+--
+-- TOC entry 2933 (class 2606 OID 20039)
+-- Dependencies: 2863 2446 2435
+-- Name: observation_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.observations
+    ADD CONSTRAINT observation_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2926 (class 2606 OID 20044)
+-- Dependencies: 2429 2824 2429
+-- Name: parent_group_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.groups
+    ADD CONSTRAINT parent_group_fk FOREIGN KEY (parent_group_id) REFERENCES groups(id);
+
+
+--
+-- TOC entry 2956 (class 2606 OID 1411931)
+-- Dependencies: 2898 2479 2478
+-- Name: query_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_queries_to_units
+    ADD CONSTRAINT query_id_fk FOREIGN KEY (query_id) REFERENCES alert_queries(query_id);
+
+
+--
+-- TOC entry 2947 (class 2606 OID 20054)
+-- Dependencies: 2456 2850 2440
+-- Name: sensor_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_to_sensors
+    ADD CONSTRAINT sensor_id_fk FOREIGN KEY (sensor_id) REFERENCES sensors(sensor_id);
+
+
+--
+-- TOC entry 2938 (class 2606 OID 20059)
+-- Dependencies: 2845 2440 2438
+-- Name: sensor_to_phenomenon_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.sensors
+    ADD CONSTRAINT sensor_to_phenomenon_fk FOREIGN KEY (phenomenon_id) REFERENCES phenomenons(phenomenon_id);
+
+
+--
+-- TOC entry 2951 (class 2606 OID 113873)
+-- Dependencies: 2857 2443 2468
+-- Name: sessions_system_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.sessions
+    ADD CONSTRAINT sessions_system_user_id_fkey FOREIGN KEY (system_user_id) REFERENCES system_users(user_id);
+
+
+--
+-- TOC entry 2960 (class 2606 OID 1412034)
+-- Dependencies: 2452 2481 2871
+-- Name: status_to_gid; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.ignition_status
+    ADD CONSTRAINT status_to_gid FOREIGN KEY (gid) REFERENCES units_positions(gid);
+
+
+--
+-- TOC entry 2961 (class 2606 OID 1412039)
+-- Dependencies: 2863 2481 2446
+-- Name: status_to_unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.ignition_status
+    ADD CONSTRAINT status_to_unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2939 (class 2606 OID 20064)
+-- Dependencies: 2429 2443 2824
+-- Name: system_users_group_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.system_users
+    ADD CONSTRAINT system_users_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id);
+
+
+--
+-- TOC entry 2941 (class 2606 OID 20069)
+-- Dependencies: 2863 2446 2447
+-- Name: unit_conf_to_unit_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_conf
+    ADD CONSTRAINT unit_conf_to_unit_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2948 (class 2606 OID 20074)
+-- Dependencies: 2446 2456 2863
+-- Name: unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_to_sensors
+    ADD CONSTRAINT unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2957 (class 2606 OID 1411936)
+-- Dependencies: 2479 2446 2863
+-- Name: unit_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.alert_queries_to_units
+    ADD CONSTRAINT unit_id_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2946 (class 2606 OID 20079)
+-- Dependencies: 2454 2446 2863
+-- Name: unit_id_pk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_to_groups
+    ADD CONSTRAINT unit_id_pk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2944 (class 2606 OID 20084)
+-- Dependencies: 2452 2446 2863
+-- Name: unit_position_to_unit_name_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_positions
+    ADD CONSTRAINT unit_position_to_unit_name_fkey FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+
+--
+-- TOC entry 2940 (class 2606 OID 20094)
+-- Dependencies: 2445 2446 2861
+-- Name: unit_to_user_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units
+    ADD CONSTRAINT unit_to_user_fk FOREIGN KEY (holder_id) REFERENCES unit_holders(holder_id);
+
+
+--
+-- TOC entry 2942 (class 2606 OID 20099)
+-- Dependencies: 2446 2863 2448
+-- Name: units_history_points_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_positions_recent
+    ADD CONSTRAINT units_history_points_fkey FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+--
+-- TOC entry 2950 (class 2606 OID 20109)
+-- Dependencies: 2863 2446 2459
+-- Name: units_tracks_conf_to_units_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_tracks_conf
+    ADD CONSTRAINT units_tracks_conf_to_units_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+--
+-- TOC entry 2949 (class 2606 OID 20114)
+-- Dependencies: 2863 2446 2458
+-- Name: units_tracks_to_units_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY maplog.units_tracks
+    ADD CONSTRAINT units_tracks_to_units_fk FOREIGN KEY (unit_id) REFERENCES units(unit_id);
+
+
+-- Completed on 2011-07-27 13:21:03 CEST
+
+--
+-- PostgreSQL database dump complete
+--
+

+ 798 - 0
src/main/db/sequence.sql

@@ -0,0 +1,798 @@
+
+CREATE SEQUENCE maplog.alert_events_alert_event_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- TOC entry 2477 (class 1259 OID 1411880)
+-- Dependencies: 2812 2813 2814 7
+-- Name: alert_events; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.alert_events (
+    alert_event_id integer DEFAULT nextval('maplog.alert_events_alert_event_id_seq'::regclass) NOT NULL,
+    time_stamp timestamp with time zone NOT NULL,
+    solved boolean DEFAULT false,
+    alert_id integer NOT NULL,
+    unit_id bigint NOT NULL,
+    gid integer,
+    solving boolean DEFAULT false NOT NULL
+);
+
+
+--
+-- TOC entry 2473 (class 1259 OID 1410750)
+-- Dependencies: 7
+-- Name: alert_queries_query_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.alert_queries_query_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2478 (class 1259 OID 1411913)
+-- Dependencies: 2815 7
+-- Name: alert_queries; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.alert_queries (
+    query_id integer DEFAULT nextval('maplog.alert_queries_query_id_seq'::regclass) NOT NULL,
+    query_string character varying(200),
+    alert_id integer NOT NULL
+);
+
+
+--
+-- TOC entry 2474 (class 1259 OID 1410752)
+-- Dependencies: 7
+-- Name: alert_queries_to_units_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.alert_queries_to_units_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2479 (class 1259 OID 1411925)
+-- Dependencies: 2816 7
+-- Name: alert_queries_to_units; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.alert_queries_to_units (
+    id integer DEFAULT nextval('maplog.alert_queries_to_units_id_seq'::regclass) NOT NULL,
+    query_id integer NOT NULL,
+    unit_id bigint NOT NULL,
+    last_status_alert_query boolean,
+    last_status_time_stamp timestamp with time zone
+);
+
+
+--
+-- TOC entry 2475 (class 1259 OID 1410754)
+-- Dependencies: 7
+-- Name: alerts_alert_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.alerts_alert_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2476 (class 1259 OID 1411870)
+-- Dependencies: 2811 7
+-- Name: alerts; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.alerts (
+    alert_id integer DEFAULT nextval('maplog.maplog.alerts_alert_id_seq'::regclass) NOT NULL,
+    alert_description character varying(100)
+);
+
+
+
+
+
+--
+-- TOC entry 2426 (class 1259 OID 19757)
+-- Dependencies: 7 1065
+-- Name: geom_alerts_conf; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.geom_alerts_conf (
+    geom_alerts_conf_id integer NOT NULL,
+    unit_id integer NOT NULL,
+    the_geom geometry NOT NULL,
+    relation character varying(3)
+);
+
+
+--
+-- TOC entry 2427 (class 1259 OID 19763)
+-- Dependencies: 7 2426
+-- Name: geom_alerts_conf_geom_alerts_conf_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.geom_alerts_conf_geom_alerts_conf_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3008 (class 0 OID 0)
+-- Dependencies: 2427
+-- Name: geom_alerts_conf_geom_alerts_conf_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.geom_alerts_conf_geom_alerts_conf_id_seq OWNED BY maplog.geom_alerts_conf.geom_alerts_conf_id;
+
+
+SET default_with_oids = true;
+
+--
+-- TOC entry 2428 (class 1259 OID 19765)
+-- Dependencies: 7
+-- Name: geometry_columns; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.geometry_columns (
+    f_table_catalog character varying(256) NOT NULL,
+    f_table_schema character varying(256) NOT NULL,
+    f_table_name character varying(256) NOT NULL,
+    f_geometry_column character varying(256) NOT NULL,
+    coord_dimension integer NOT NULL,
+    srid integer NOT NULL,
+    type character varying(30) NOT NULL
+);
+
+
+SET default_with_oids = false;
+
+--
+-- TOC entry 2429 (class 1259 OID 19771)
+-- Dependencies: 2778 7
+-- Name: groups; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.groups (
+    id integer NOT NULL,
+    group_name character varying(100),
+    parent_group_id integer,
+    has_children boolean DEFAULT false
+);
+
+
+--
+-- TOC entry 2430 (class 1259 OID 19775)
+-- Dependencies: 2429 7
+-- Name: groups_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.groups_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3009 (class 0 OID 0)
+-- Dependencies: 2430
+-- Name: groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.groups_id_seq OWNED BY maplog.groups.id;
+
+
+--
+-- TOC entry 2481 (class 1259 OID 1412029)
+-- Dependencies: 7
+-- Name: ignition_status; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.ignition_status (
+    observation_id integer NOT NULL,
+    gid integer,
+    time_stamp timestamp with time zone NOT NULL,
+    value double precision NOT NULL,
+    unit_id bigint NOT NULL
+);
+
+
+--
+-- TOC entry 2480 (class 1259 OID 1412011)
+-- Dependencies: 7
+-- Name: last_ignition_status; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.last_ignition_status (
+    observation_id integer NOT NULL,
+    gid integer,
+    time_stamp timestamp with time zone NOT NULL,
+    value double precision NOT NULL,
+    unit_id bigint NOT NULL
+);
+
+
+--
+-- TOC entry 2431 (class 1259 OID 19777)
+-- Dependencies: 1065 7
+-- Name: last_units_positions; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.last_units_positions (
+    gid integer NOT NULL,
+    the_geom geometry NOT NULL,
+    unit_id bigint NOT NULL,
+    time_stamp timestamp with time zone NOT NULL,
+    speed double precision,
+    dop double precision
+);
+
+
+--
+-- TOC entry 2432 (class 1259 OID 19783)
+-- Dependencies: 2431 7
+-- Name: last_units_positions_gid_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.last_units_positions_gid_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3010 (class 0 OID 0)
+-- Dependencies: 2432
+-- Name: last_units_positions_gid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.last_units_positions_gid_seq OWNED BY maplog.last_units_positions.gid;
+
+
+CREATE TABLE maplog.obs_alerts_conf (
+    obs_alerts_conf_id integer NOT NULL,
+    unit_id bigint NOT NULL,
+    phenomenon_id character varying(100) NOT NULL,
+    value double precision NOT NULL,
+    relation character varying(3)
+);
+
+
+--
+-- TOC entry 2434 (class 1259 OID 19788)
+-- Dependencies: 2433 7
+-- Name: obs_alerts_conf_obs_alerts_conf_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.obs_alerts_conf_obs_alerts_conf_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3012 (class 0 OID 0)
+-- Dependencies: 2434
+-- Name: obs_alerts_conf_obs_alerts_conf_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.obs_alerts_conf_obs_alerts_conf_id_seq OWNED BY maplog.obs_alerts_conf.obs_alerts_conf_id;
+
+
+--
+-- TOC entry 2492 (class 1259 OID 1472758)
+-- Dependencies: 7
+-- Name: obs_to_obs; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.obs_to_obs (
+    main_obs_id integer NOT NULL,
+    sec_obs_id integer NOT NULL
+);
+
+
+--
+-- TOC entry 2435 (class 1259 OID 19790)
+-- Dependencies: 7
+-- Name: observations; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.observations (
+    observation_id integer NOT NULL,
+    gid integer,
+    time_stamp timestamp with time zone NOT NULL,
+    observed_value double precision NOT NULL,
+    sensor_id bigint,
+    unit_id bigint NOT NULL
+);
+
+
+--
+-- TOC entry 2436 (class 1259 OID 19793)
+-- Dependencies: 7 2435
+-- Name: observations_observation_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.observations_observation_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3013 (class 0 OID 0)
+-- Dependencies: 2436
+-- Name: observations_observation_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.observations_observation_id_seq OWNED BY maplog.observations.observation_id;
+
+
+
+CREATE SEQUENCE maplog.phenomenons_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2438 (class 1259 OID 19798)
+-- Dependencies: 2783 7
+-- Name: phenomenons; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.phenomenons (
+    phenomenon_id character varying(100) DEFAULT nextval('maplog.phenomenons_id_seq'::regclass) NOT NULL,
+    phenomenon_name character varying(100) NOT NULL,
+    unit character varying(30) NOT NULL
+);
+
+
+--
+-- TOC entry 2486 (class 1259 OID 1412299)
+-- Dependencies: 7
+-- Name: rights; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.rights (
+    rights_id integer NOT NULL,
+    user_role character varying(20),
+    note_cz character varying(100)
+);
+
+
+
+
+--
+-- TOC entry 2440 (class 1259 OID 19804)
+-- Dependencies: 7
+-- Name: sensors; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.sensors (
+    sensor_id bigint NOT NULL,
+    sensor_name character varying(20),
+    sensor_type character varying(100),
+    phenomenon_id character varying(100) NOT NULL
+);
+
+
+--
+-- TOC entry 2441 (class 1259 OID 19807)
+-- Dependencies: 2440 7
+-- Name: sensors_sensor_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.sensors_sensor_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3014 (class 0 OID 0)
+-- Dependencies: 2441
+-- Name: sensors_sensor_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.sensors_sensor_id_seq OWNED BY maplog.sensors.sensor_id;
+
+
+--
+-- TOC entry 2468 (class 1259 OID 113867)
+-- Dependencies: 2810 7
+-- Name: sessions; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.sessions (
+    session_id character varying(100) NOT NULL,
+    system_user_id integer NOT NULL,
+    ip character(100),
+    time_stamp timestamp with time zone DEFAULT now()
+);
+
+
+
+--
+-- TOC entry 2452 (class 1259 OID 19852)
+-- Dependencies: 2801 7 1065
+-- Name: units_positions; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_positions (
+    gid integer NOT NULL,
+    the_geom geometry NOT NULL,
+    unit_id bigint NOT NULL,
+    time_stamp timestamp with time zone DEFAULT now() NOT NULL,
+    dop double precision,
+    speed double precision
+);
+
+
+
+--
+-- TOC entry 2458 (class 1259 OID 19873)
+-- Dependencies: 2804 7 1065
+-- Name: units_tracks; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_tracks (
+    gid integer NOT NULL,
+    the_geom geometry NOT NULL,
+    unit_id bigint NOT NULL,
+    track_start timestamp with time zone DEFAULT now(),
+    track_end timestamp with time zone,
+    is_closed boolean
+);
+
+
+
+CREATE TABLE maplog.system_users (
+    user_id integer NOT NULL,
+    user_name text NOT NULL,
+    user_real_name text,
+    user_password text,
+    group_id integer,
+    rights_id integer DEFAULT 0,
+    audio boolean DEFAULT false,
+    module_administrator boolean DEFAULT false,
+    module_log_book boolean DEFAULT false,
+    lang text DEFAULT 'cz'::text
+);
+
+
+--
+-- TOC entry 2444 (class 1259 OID 19821)
+-- Dependencies: 7 2443
+-- Name: system_users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.system_users_user_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3015 (class 0 OID 0)
+-- Dependencies: 2444
+-- Name: system_users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.system_users_user_id_seq OWNED BY maplog.system_users.user_id;
+
+
+--
+-- TOC entry 2482 (class 1259 OID 1412057)
+-- Dependencies: 7
+-- Name: unit_drivers_driver_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.unit_drivers_driver_id_seq
+    START WITH 1
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2483 (class 1259 OID 1412059)
+-- Dependencies: 2817 7
+-- Name: unit_drivers; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.unit_drivers (
+    driver_id integer DEFAULT nextval('maplog.unit_drivers_driver_id_seq'::regclass) NOT NULL,
+    holder_id integer,
+    title_prefix character varying(35),
+    fname character varying(24),
+    lname character varying(35),
+    title character varying(10),
+    phone character varying(16)
+);
+
+
+--
+-- TOC entry 2445 (class 1259 OID 19823)
+-- Dependencies: 7
+-- Name: unit_holders; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.unit_holders (
+    holder_id integer NOT NULL,
+    phone character varying(16),
+    icon_id integer,
+    holder_name character varying(255) NOT NULL,
+    address character varying(255),
+    email character varying(100),
+    www character varying(100)
+);
+
+
+--
+-- TOC entry 2446 (class 1259 OID 19826)
+-- Dependencies: 7
+-- Name: units; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units (
+    unit_id bigint NOT NULL,
+    holder_id integer,
+    description character varying(100)
+);
+
+
+--
+-- TOC entry 2447 (class 1259 OID 19829)
+-- Dependencies: 2792 2793 2794 2795 2796 7
+-- Name: units_conf; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_conf (
+    unit_id bigint NOT NULL,
+    min_distance double precision,
+    min_time_span interval,
+    is_active boolean DEFAULT true NOT NULL,
+    store_interval interval DEFAULT '7 days'::interval,
+    max_time_span interval DEFAULT '00:10:00'::interval NOT NULL,
+    provide_alerts boolean DEFAULT true NOT NULL,
+    min_speed double precision DEFAULT 2
+);
+
+
+--
+-- TOC entry 2448 (class 1259 OID 19834)
+-- Dependencies: 2797 7 1065
+-- Name: units_positions_recent; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_positions_recent (
+    gid integer NOT NULL,
+    the_geom geometry NOT NULL,
+    unit_id bigint NOT NULL,
+    time_stamp timestamp with time zone DEFAULT now() NOT NULL,
+    dop double precision,
+    polygon_gid integer
+);
+
+
+CREATE SEQUENCE maplog.units_positions_gid_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3018 (class 0 OID 0)
+-- Dependencies: 2453
+-- Name: units_positions_gid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.units_positions_gid_seq OWNED BY maplog.units_positions.gid;
+
+
+--
+-- TOC entry 2463 (class 1259 OID 27198)
+-- Dependencies: 7
+-- Name: units_to_auth_group_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.units_to_auth_group_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2484 (class 1259 OID 1412073)
+-- Dependencies: 7
+-- Name: units_to_drivers_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.units_to_drivers_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 2485 (class 1259 OID 1412075)
+-- Dependencies: 2818 7
+-- Name: units_to_drivers; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_to_drivers (
+    id integer DEFAULT nextval('maplog.units_to_drivers_id_seq'::regclass) NOT NULL,
+    unit_id bigint,
+    driver_id integer
+);
+
+
+--
+-- TOC entry 2454 (class 1259 OID 19861)
+-- Dependencies: 7
+-- Name: units_to_groups; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_to_groups (
+    id integer NOT NULL,
+    group_id integer,
+    unit_id bigint
+);
+
+
+--
+-- TOC entry 2455 (class 1259 OID 19864)
+-- Dependencies: 7 2454
+-- Name: units_to_groups_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.units_to_groups_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3019 (class 0 OID 0)
+-- Dependencies: 2455
+-- Name: units_to_groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.units_to_groups_id_seq OWNED BY maplog.units_to_groups.id;
+
+
+--
+-- TOC entry 2456 (class 1259 OID 19866)
+-- Dependencies: 7
+-- Name: units_to_sensors; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_to_sensors (
+    sensor_id bigint NOT NULL,
+    unit_id bigint NOT NULL,
+    first_obs timestamp with time zone,
+    last_obs timestamp with time zone
+);
+
+
+--
+-- TOC entry 2457 (class 1259 OID 19869)
+-- Dependencies: 2568 7
+-- Name: units_to_phenomenons; Type: VIEW; Schema: public; Owner: -
+--
+
+--
+-- TOC entry 2459 (class 1259 OID 19880)
+-- Dependencies: 2806 2807 7
+-- Name: units_tracks_conf; Type: TABLE; Schema: public; Owner: -; Tablespace: 
+--
+
+CREATE TABLE maplog.units_tracks_conf (
+    units_tracks_settings_id integer NOT NULL,
+    unit_id bigint,
+    max_time_span interval DEFAULT '1 day'::interval,
+    max_distance double precision DEFAULT 20
+);
+
+
+--
+-- TOC entry 2460 (class 1259 OID 19885)
+-- Dependencies: 2459 7
+-- Name: units_tracks_conf_units_tracks_settings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.units_tracks_conf_units_tracks_settings_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3020 (class 0 OID 0)
+-- Dependencies: 2460
+-- Name: units_tracks_conf_units_tracks_settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.units_tracks_conf_units_tracks_settings_id_seq OWNED BY maplog.units_tracks_conf.units_tracks_settings_id;
+
+
+--
+-- TOC entry 2461 (class 1259 OID 19887)
+-- Dependencies: 2458 7
+-- Name: units_tracks_gid_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.units_tracks_gid_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3021 (class 0 OID 0)
+-- Dependencies: 2461
+-- Name: units_tracks_gid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.units_tracks_gid_seq OWNED BY maplog.units_tracks.gid;
+
+
+--
+-- TOC entry 2462 (class 1259 OID 19889)
+-- Dependencies: 2445 7
+-- Name: users_user_id_seq; Type: SEQUENCE; Schema: public; Owner: -
+--
+
+CREATE SEQUENCE maplog.users_user_id_seq
+    INCREMENT BY 1
+    NO MAXVALUE
+    NO MINVALUE
+    CACHE 1;
+
+
+--
+-- TOC entry 3022 (class 0 OID 0)
+-- Dependencies: 2462
+-- Name: users_user_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
+--
+
+ALTER SEQUENCE maplog.users_user_id_seq OWNED BY maplog.unit_holders.holder_id;

+ 166 - 0
src/main/java/cz/hsrs/db/ChartGenerator.java

@@ -0,0 +1,166 @@
+package cz.hsrs.db;
+
+import java.awt.Color;
+import java.awt.geom.Ellipse2D;
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartUtilities;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.DateAxis;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.time.FixedMillisecond;
+import org.jfree.data.time.TimeSeries;
+import org.jfree.data.time.TimeSeriesCollection;
+import org.jfree.data.xy.XYDataset;
+
+import cz.hsrs.db.model.Sensor;
+import cz.hsrs.db.util.SensorUtil;
+
+public class ChartGenerator {
+
+	private String dir;
+	// private Map<Date,Double> data = null;
+	private SensorUtil util = new SensorUtil();
+
+	public ChartGenerator(String dir) {
+		super();
+
+		this.dir = dir;
+
+	}
+
+	public List<File> getUnitCharts(long unit_id, Date timestampFrom,
+			Date timestampTo, int width, int height) throws Exception {
+		List<Sensor> sensors = util.getSensors(unit_id);
+		List<File> files = new ArrayList<File>();
+		Sensor s = null;
+
+		for (Iterator<Sensor> i = sensors.iterator(); i.hasNext();) {
+			s = i.next();
+			File f = getSensorChart(s, unit_id, timestampFrom, timestampTo,
+					width, height);
+			files.add(f);
+
+		}
+
+		return files;
+	}
+
+	public File getSensorChart(Sensor sensor, long unit_id, Date timestampFrom,
+			Date timestampTo, int width, int height) throws Exception {
+
+		TimeSeriesCollection dataset = getDataset(sensor.getSensorId(), unit_id,
+				timestampFrom, timestampTo);
+
+		String label = sensor.getPhenomenon().getPhenomenonName() + " "
+				+ sensor.getPhenomenon().getUnit();
+		String title = "Unit: " + unit_id + " Sensor: " + sensor.getSensorId();
+
+		JFreeChart chart =createChart(title, label, dataset); 
+			
+		//	ChartFactory.createTimeSeriesChart(title, "Time",
+		//		label, dataset, true, false, false);
+
+		// chart.setBackgroundPaint(new Color(237, 245, 254));
+		chart.setBackgroundPaint(Color.WHITE);
+		String fileName = (new Long((new Date()).getTime())).toString();
+
+		File pngFile = File.createTempFile(fileName, ".png", new File(dir));
+
+		// pngFile.deleteOnExit();
+		// File pngFile = new File(dir+/"+ fileName + ".png");
+		ChartUtilities.saveChartAsPNG(pngFile, chart, width, height);
+		// System.out.println(pngFile.getAbsolutePath());
+		return pngFile;
+	}
+
+	private JFreeChart createChart(String title, String valuelabel, XYDataset dataset) { 
+   JFreeChart chart = ChartFactory.createTimeSeriesChart(
+		    title,  // title
+            "Date",             // x-axis label
+            valuelabel,         // y-axis label
+            dataset,            // data
+            true,               // create legend?
+            true,               // generate tooltips?
+            false               // generate URLs?
+        );
+
+        chart.setBackgroundPaint(Color.white);
+
+        XYPlot plot = (XYPlot) chart.getPlot();
+        plot.setBackgroundPaint(Color.lightGray);
+        plot.setDomainGridlinePaint(Color.white);
+        plot.setRangeGridlinePaint(Color.white);
+       // plot.se.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
+        plot.setDomainCrosshairVisible(true);
+        plot.setRangeCrosshairVisible(true);
+        
+        XYItemRenderer r = plot.getRenderer();
+        if (r instanceof XYLineAndShapeRenderer) {
+            XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) r;
+            
+            renderer.setSeriesShape(0, new Ellipse2D.Double(-1, -1, 2, 2));
+            renderer.setBaseShapesVisible(true);
+           /// renderer.setBaseShapesFilled(false);
+          //  renderer.setBaseShape(new Rectangle2D.Double(-23, -3, 10, 10) );
+        }
+        
+        DateAxis axis = (DateAxis) plot.getDomainAxis();
+        axis.setDateFormatOverride(new SimpleDateFormat("MM.dd. HH:mm"));       
+        
+        return chart;
+
+    }
+	/*public File getSensorChart(long sensor_id, long unit_id, Date timestampFrom,
+			Date timestampTo, int width, int height) throws Exception {
+	
+		XYDataset dataset = getDataset(sensor_id, unit_id, timestampFrom, timestampTo);
+
+		JFreeChart chart = ChartFactory.createTimeSeriesChart("todo", "Time",
+				"todo", dataset, true, false, false);
+
+		// chart.setBackgroundPaint(new Color(237, 245, 254));
+		chart.setBackgroundPaint(Color.WHITE);
+		String fileName = (new Long((new Date()).getTime())).toString();
+
+		File pngFile = File.createTempFile(fileName, ".png", new File(dir));
+
+		ChartUtilities.saveChartAsPNG(pngFile, chart, width, height);	
+		return pngFile;
+	}*/
+
+	private TimeSeriesCollection getDataset(long sensor_id, long unit_id,
+			Date timestampFrom, Date timestampTo) throws Exception {
+
+		TimeSeriesCollection dataset = new TimeSeriesCollection();		
+		Sensor sens = util.getSensorById(sensor_id);
+		String sens_name = sens.getSensorName();
+		
+		if (sens_name==null) {
+			sens_name = String.valueOf(sensor_id);
+		}
+		TimeSeries ts = new TimeSeries(sens_name, FixedMillisecond.class);
+
+		DBChartUtils util = new DBChartUtils();
+		Map<Date, Double> data = util.getObservationsBySensor(sensor_id,
+				unit_id, timestampFrom, timestampTo);
+
+		for (Iterator<Date> j = data.keySet().iterator(); j.hasNext();) {
+			Date time = (Date) j.next();
+			ts.add(new FixedMillisecond(time.getTime()), (Number) data
+					.get(time));
+		}
+		dataset.addSeries(ts);
+
+		return dataset;
+	}		
+}

+ 127 - 0
src/main/java/cz/hsrs/db/ConnectionManager.java

@@ -0,0 +1,127 @@
+package cz.hsrs.db;
+
+import java.beans.PropertyVetoException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import cz.hsrs.db.pool.SQLExecutor;
+
+class ConnectionManager {
+
+	private static Connection conn = null;
+	private static Connection connFeeder = null;
+	private static Properties prop;	
+	
+	private static String UnitsPositions_table;
+	private static String UnitsTracks_table;
+	private static String UnitsLastPositions_table;
+		
+	
+	public static Logger logger = Logger.getLogger(SQLExecutor.LOGGER_ID);
+	
+	@Deprecated
+	private ConnectionManager() {
+		
+	}
+
+	public static void setProperties(Properties proper) throws SQLException {
+
+			prop = proper;		
+			
+			UnitsPositions_table = prop.getProperty("UnitsPositions_table");
+			UnitsTracks_table = prop.getProperty("UnitsTracks_table");
+			UnitsLastPositions_table = prop.getProperty("UnitsLastPositions_table");
+		
+
+	}
+
+	public static String getUnitsPositions_table() {
+		return UnitsPositions_table;
+	}
+
+	public static String getUnitsTracks_table() {
+		return UnitsTracks_table;
+	}
+
+	public static String getUnitsLastPositions_table() {
+		return UnitsLastPositions_table;
+	}
+	
+  
+	public static synchronized Connection getConnectionnn() throws SQLException  {
+		if (conn == null || conn.isClosed()) {
+
+
+			// String propFile =
+			// "/home/jezekjan/code/workspace-web2/DBFeederService/WebContent/WEB-INF/database.properties";
+			// = new Properties();
+			// prop.load(new FileInputStream(propFile));
+			try {			
+				try {
+					Class.forName("org.postgresql.Driver").newInstance();
+				} catch (InstantiationException e) {
+					throw new SQLException(e);
+				} catch (IllegalAccessException e) {
+					// TODO Auto-generated catch block
+					throw new SQLException(e);
+				} catch (ClassNotFoundException e) {
+					// TODO Auto-generated catch block
+					throw new SQLException(e);
+				}
+				
+				conn = DriverManager
+						.getConnection((String) prop.get("Address"),
+								(String) prop.get("Username"), (String) prop
+										.get("Password"));					
+				return conn;
+			} catch (NullPointerException e) {
+				throw new NullPointerException(
+						"You have to setProperties before getting Connection");
+			}
+
+		} else
+			return conn;
+	}
+  
+	
+	public static synchronized Connection getConnectionFeeder() throws SQLException  {
+		if (connFeeder == null || connFeeder.isClosed()) {
+			try {			
+				try {
+					Class.forName("org.postgresql.Driver").newInstance();
+				} catch (InstantiationException e) {
+					throw new SQLException(e);
+				} catch (IllegalAccessException e) {
+					// TODO Auto-generated catch block
+					throw new SQLException(e);
+				} catch (ClassNotFoundException e) {
+					// TODO Auto-generated catch block
+					throw new SQLException(e);
+				}
+				
+				connFeeder = DriverManager
+						.getConnection((String) prop.get("Address"),
+								(String) prop.get("Username"), (String) prop
+										.get("Password"));					
+				return connFeeder;
+			} catch (NullPointerException e) {
+				throw new NullPointerException(
+						"You have to setProperties before getting Connection");
+			}
+
+		} else
+			return connFeeder;
+	}
+	
+	public static void closeConnection() throws SQLException {
+		conn.close();		
+	}
+	
+	public static void closeConnectionFeeder() throws SQLException {
+		conn.close();		
+	}
+}

+ 70 - 0
src/main/java/cz/hsrs/db/DBChartUtils.java

@@ -0,0 +1,70 @@
+package cz.hsrs.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import cz.hsrs.db.model.Phenomenon;
+import cz.hsrs.db.model.composite.UnitSensor;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.DBUtil;
+
+
+
+
+public class DBChartUtils extends DBUtil {
+	
+	
+
+	public DBChartUtils() throws SQLException {
+		
+	}
+
+	public Map<Double, Date> getObservationsByGID(int gid, Date from, Date to) {
+		return null;
+	}
+
+	public Map<Double, Date> getObservationsByUnit(long unit_id, Date from,
+			Date to) {
+		return null;
+	}
+
+	public Map<Date, Double> getObservationsBySensor(long sensor_id, long unit_id, Date from,
+			Date to) throws Exception {
+		Map<Date, Double> observations = new HashMap<Date, Double>();		
+		String queryObservations = "SELECT observed_value, time_stamp FROM observations WHERE "
+				+ "observations.sensor_id = "
+				+ sensor_id
+				+ " AND "
+				+ "observations.unit_id = "
+				+ unit_id
+				+ " AND "
+				+ "observations.time_stamp >= '"
+				+ format.format(from)
+				+ "' AND "
+				+ "observations.time_stamp <= '"
+				+ format.format(to)
+				+ "';";
+
+		//System.out.println(queryObservations);
+		ResultSet obs =  SQLExecutor.getInstance().executeQuery(queryObservations);
+
+		while (obs.next()) {
+		
+			observations.put(obs.getTimestamp(2), obs.getDouble(1));
+		}
+
+		return observations;
+	}
+
+	public Phenomenon getPhenomenonById(int id) {
+		return null;
+	}
+
+	public UnitSensor getSensorById(long id) {
+		return null;
+	}
+}

+ 176 - 0
src/main/java/cz/hsrs/db/DBJsonUtils.java

@@ -0,0 +1,176 @@
+package cz.hsrs.db;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.zip.GZIPOutputStream;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+public class DBJsonUtils {
+
+    /**
+     * Method writes given ResultSet into PrintWriter output as JSON
+     * @param writer output destination
+     * @param res ResultSet to write into writer
+     * @throws SQLException
+     */
+    public static void writeJSON(PrintWriter writer, ResultSet res) throws SQLException{
+        ResultSetMetaData rsmd = res.getMetaData();
+        int numColumns = rsmd.getColumnCount();
+        
+        writer.print("[");
+        boolean first = true;
+        
+        while (res.next()){
+            if (!first){
+                writer.println(",");
+                first = false;
+                }
+            else {
+                first=false;
+            }
+            JSONObject jsonObj = generateJSONObj(res, rsmd, numColumns);
+            writer.print(jsonObj);
+        }
+        writer.println("]");
+    }
+
+    private static JSONObject generateJSONObj(ResultSet rs, ResultSetMetaData rsmd, int numColumns){
+        JSONObject obj = new JSONObject();
+        try{
+            for (int i=1; i < numColumns+1; i++) {
+                String column_name = rsmd.getColumnName(i);
+
+                if(rsmd.getColumnType(i)==java.sql.Types.ARRAY){
+                    obj.put(column_name, rs.getArray(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.BIGINT){
+                    obj.put(column_name, rs.getLong(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.BOOLEAN){
+                    obj.put(column_name, rs.getBoolean(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.BLOB){
+                    obj.put(column_name, rs.getBlob(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.DOUBLE){
+                    obj.put(column_name, rs.getDouble(column_name)); 
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.FLOAT){
+                    obj.put(column_name, rs.getFloat(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.INTEGER){
+                    obj.put(column_name, rs.getInt(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.NVARCHAR){
+                    obj.put(column_name, rs.getNString(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.VARCHAR){
+                    obj.put(column_name, rs.getString(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.TINYINT){
+                    obj.put(column_name, rs.getInt(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.SMALLINT){
+                    obj.put(column_name, rs.getInt(column_name));
+                }
+                else if(rsmd.getColumnType(i)==java.sql.Types.TIMESTAMP){
+                    obj.put(column_name, rs.getTimestamp(column_name));
+                }
+                else{
+                    obj.put(column_name, rs.getString(column_name));
+                }
+            }
+        } catch (SQLException e){
+            e.printStackTrace();
+        }
+          return obj;
+    }
+
+    public static void writeJSON(PrintWriter writer, List<? extends DBObject> res ) throws SQLException{
+        writer.print("[");
+        boolean first=true;
+        Iterator<? extends DBObject> i = res.iterator();
+        while (i.hasNext()) {
+            if (!first){
+                writer.println(",");
+                first = false;
+            }
+            else {
+                first=false;
+            }
+            JSONObject jsonObj = JSONObject.fromObject(i.next());
+            writer.print(jsonObj);
+        }
+        writer.println("]");
+    }
+    
+    /**
+     * Method creates JSON from List of primitives
+     * @param writer where result should be written
+     * @param list of primitives
+     * @throws SQLException
+     */
+    public static void writeJSONfromList(PrintWriter writer, List<?> list) throws SQLException{
+        JSONArray jsonArr = JSONArray.fromObject(list);
+        writer.println(jsonArr);
+    }
+    
+    public static void writeJSONCompressed(GZIPOutputStream gzOut, List<? extends DBObject> res ) throws SQLException{
+        boolean first=true;
+        Iterator<? extends DBObject> i = res.iterator();
+        String row="";
+        row += "[";
+        try {
+            while (i.hasNext()){
+                JSONObject jsonObj = JSONObject.fromObject(i.next());
+                row += jsonObj;
+                if (i.hasNext()==true){
+                       row +=",\n";
+                }
+                else{
+                    row +="]";
+                }
+                first=false;
+                
+                gzOut.write(row.getBytes(), 0, row.getBytes().length);
+                gzOut.flush();
+            }
+            //String zprava = "\n Komprimovano!";
+            //gzOut.write(zprava.getBytes());
+            gzOut.close();
+        } catch (IOException e) {
+            throw new SQLException(e);
+        }
+    }
+    
+    public static void writeJSON(PrintWriter writer, DBObject element, ResultSet res ) throws SQLException{
+        try {
+            writer.print("[");
+            boolean first=true;
+            while (res.next()) {
+                    if (!first){
+                        writer.println(",");
+                        first = false;
+                        }
+                    else {
+                        first=false;
+                    }
+                DBObject gr = (element.getClass().newInstance()).getDBObject(res);
+                JSONObject jsonObj = JSONObject.fromObject(gr);
+                writer.print(jsonObj);
+            }
+            writer.println("]");
+        } catch (InstantiationException e) {
+            throw new SQLException(e);
+        } catch (IllegalAccessException e) {
+            throw new SQLException(e);
+        }
+    }
+}

+ 10 - 0
src/main/java/cz/hsrs/db/DBObject.java

@@ -0,0 +1,10 @@
+package cz.hsrs.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public interface DBObject{
+	public DBObject getDBObject(ResultSet set) throws SQLException;
+}
+
+	

+ 307 - 0
src/main/java/cz/hsrs/db/DatabaseFeedOperation.java

@@ -0,0 +1,307 @@
+package cz.hsrs.db;
+
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import cz.hsrs.db.model.AlertQuery;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Observation;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.AlertUtil;
+import cz.hsrs.track.TrackIgnitionSolver;
+import cz.hsrs.track.TrackSolver;
+
+public class DatabaseFeedOperation {
+
+    private static final Logger logger = Logger.getLogger(SQLExecutor.LOGGER_ID);
+
+    private static int transaction_size = 1;
+    private static int t = 0;
+    private static String insertTransaction = "BEGIN;";
+    private static final String SCHEMA_NAME = "public";
+
+    /**
+     * Method inserts new Observation to DB
+     * @param date when the observations was measured
+     * @param unit_id - id of unit
+     * @param sensor_id - id of sensor
+     * @param value - observed value, can be NaN
+     * @return true if observations was successfully inserted, false if it wasn't
+     */
+    public static synchronized boolean insertObservation(Date date, long unit_id, long sensor_id, Double value) throws SQLException {
+        Observation o = new Observation(date, value, sensor_id, unit_id);
+        boolean inserted;
+        if (sensor_id == TrackIgnitionSolver.IGNITION_SENSOR_ID) {
+            TrackIgnitionSolver solver = new TrackIgnitionSolver(o);
+            solver.solve();
+            inserted = o.insertToDb();
+        } else {
+            inserted = o.insertToDb();
+        }
+        return inserted;
+    }
+
+    /**
+     * Method inserts new position into DB
+     * @param unit_id - id of unit
+     * @param lat - latitude
+     * @param lon - longitude
+     * @param alt - altitude
+     * @param date - when positions was measured
+     * @return true is positions was successfully inserted, false elsewhere
+     */
+    public static synchronized boolean insertPosition(long unit_id, double lat, double lon, double alt, Date date) throws Exception {
+        return insertPosition(unit_id, lat, lon, alt, date, Double.NaN);
+    }
+
+    /**
+     * Method inserts new position into DB
+     * @param unit_id - id of unit
+     * @param lat - latitude
+     * @param lon - longitude
+     * @param date - when positions was measured
+     * @return true is positions was successfully inserted, false elsewhere
+     */
+    public static synchronized boolean insertPosition(long unit_id, double lat, double lon, Date date) throws Exception {
+        return insertPosition(unit_id, lat, lon, Double.NaN, date, Double.NaN);
+    }
+
+    /**
+     * Method inserts new position into DB
+     * @param unit_id - id of unit
+     * @param lat - latitude
+     * @param lon - longitude
+     * @param alt - altitude
+     * @param date - when positions was measured as Date
+     * @param speed - current speed of the unit
+     * @return true is positions was successfully inserted, false elsewhere
+     */
+    public static synchronized boolean insertPosition(long unit_id, double lat, double lon, double alt,
+                                                      Date date, double speed) throws SQLException {
+        boolean useTracks = false;
+        boolean inserted = false;
+
+        UnitPosition p = new UnitPosition(unit_id, lon, lat, alt, date, speed, "");
+        if(useTracks){
+            inserted = solve(p);
+        }
+        else{
+            inserted = p.insertToDb();
+        }
+        checkAlertQueries(p);
+        return inserted;
+    }
+
+    /**
+     * Method inserts new position into DB
+     * @param unit_id - id of unit
+     * @param lat - latitude of position
+     * @param lon - longitude of position
+     * @param alt - altitude of position
+     * @param dop - dilution of precision of the position
+     * @param date - when positions was measured
+     * @param speed - current speed of the unit
+     * @return true is positions was successfully inserted, false elsewhere
+     */
+    public static synchronized boolean insertPosition(long unit_id, double lat, double lon, double alt,
+                                                      double dop, Date date, double speed) throws SQLException {
+        boolean useTracks = false;
+        boolean inserted = false;
+
+        UnitPosition p = new UnitPosition(unit_id, lon, lat, alt, date, speed, dop, "");
+        if (useTracks){
+            inserted = solve(p);
+        }
+        else{
+            inserted = p.insertToDb();
+        }
+        checkAlertQueries(p);
+        return inserted;
+    }
+
+    /**
+     * Method inserts new position into DB and returns ID
+     * @param unit_id - id of unit
+     * @param lat - latitude of position
+     * @param lon - longitude of position
+     * @param alt - altitude of position
+     * @param dop - dilution of precision of the position
+     * @param date - when positions was measured
+     * @param speed - current speed of the unit
+     * @return gid of new position
+     */
+    public static synchronized int insertPositionByGid(long unit_id, double lat, double lon, double alt,
+                                                       double dop, Date date, double speed, String srid) throws SQLException {
+        boolean useTracks = true;
+        boolean inserted = false;
+
+        UnitPosition p = new UnitPosition(unit_id, lon, lat, alt, date, speed, dop, srid);
+        if (useTracks){
+            inserted = solve(p);
+        } else{
+            inserted = p.insertToDb();
+        }
+        checkAlertQueries(p);
+        if(inserted){
+            return p.getGid();
+        } else{
+            throw new SQLException("Position cannot be inserted!");
+        }
+    }
+
+    /**
+     * Method updates position in DB by given UnitPosition object
+     * @param p UnitPosition object containing values to be updated in DB
+     * @return true if UnitPosition was updated, false if not
+     * @throws SQLException
+     */
+    public static boolean updatePositionByGid(UnitPosition p) throws SQLException{
+        StringBuilder update = new StringBuilder();
+        update.append("UPDATE "+SCHEMA_NAME+".units_positions SET ");
+        update.append("the_geom = ").append(p.getPostgisString()).append(", ");
+        update.append("time_stamp = '").append(p.getTime_stamp()).append("', ");
+        // ------------- SPEED ------------------
+        String speedStr;
+        Double speed = p.getSpeed();
+        if(speed == null){
+            speedStr = "NULL";
+        }
+        else if(speed != null && Double.isNaN(speed)){
+            speedStr = "NULL";
+        }
+        else{
+            speedStr = String.valueOf(speed);
+        }
+        update.append("speed = ").append(speedStr).append(", ");
+        // ------------- DOP ------------------
+        String dopStr;
+        Double dop = p.getDop();
+        if(dop == null){
+            dopStr = "NULL";
+        }
+        else if(dop != null && Double.isNaN(dop)){
+            dopStr = "NULL";
+        }
+        else{
+            dopStr = String.valueOf(dop);
+        }
+        update.append("dop = ").append(dopStr);
+        // ------------- ALT ------------------
+        if(SQLExecutor.isAltitudeEnabled()){
+            String altStr;
+            Double alt = p.getAlt();
+            if(alt == null){
+                altStr = "NULL";
+            }
+            else if(alt != null && Double.isNaN(alt)){
+                altStr = "NULL";
+            }
+            else{
+                altStr = String.valueOf(alt);
+            }
+            update.append(", altitude = ").append(altStr).append(" ");
+        }
+        update.append("WHERE gid = ").append(p.getGid());
+        String query = update.toString();
+
+        int i = SQLExecutor.executeUpdate(query);
+        return i == 0 || i == 1;
+    }
+
+    /**
+     * Method inserts new position into DB and tries to solve track
+     * @param p new position as UnitPosition object
+     * @return true if position was successfully inserted, false elsewhere
+     */
+    private static synchronized boolean solve(UnitPosition p) throws SQLException {
+        try {
+            TrackSolver solver = new TrackSolver(p);
+            return solver.solve();
+        } catch (Exception e) {
+            throw new SQLException(e);
+        }
+    }
+
+    private static void addToTransaction(String query) throws SQLException {
+        insertTransaction = insertTransaction + "\n" + query;
+        t++;
+        if (t >= transaction_size) {
+            String insert = insertTransaction + "\n" + "COMMIT;";
+            t = 0;
+            insertTransaction = "BEGIN;";
+            insertStatement(insert);
+        }
+    }
+
+    private static synchronized void insertStatement(String insertStmt) throws SQLException {
+        try {
+            SQLExecutor.executeUpdate(insertStmt);
+            logger.log(Level.FINE, "SQL succesfull - " + insertStmt);
+        } catch (Exception e1) {
+            logger.log(Level.INFO, e1.getMessage(), "Statement = '" + insertStmt);
+            throw new SQLException(e1);
+        }
+    }
+
+    /**
+     * Method inserts new AlertEvent object to the DB
+     * @param date - when alert was detected, as Date
+     * @param unit_id - ID of unit
+     * @param alert_id - ID of Alert that was detected
+     */
+    public static synchronized void insertAlertEvent(Date date, long unit_id, int alert_id)
+            throws SQLException {
+        String insertStmt = " INSERT INTO "+SCHEMA_NAME+".alert_events (time_stamp, unit_id, alert_id) VALUES ("
+                + "'"
+                + date
+                + "'"
+                + ", "
+                + unit_id
+                + ", "
+                + "'"
+                + alert_id
+                + "');";
+        insertStatement(insertStmt);
+    }
+
+    public static synchronized void solvingAlertEvent(int event_id) throws SQLException {
+        String updateStmt = "UPDATE "+SCHEMA_NAME+".alert_events SET solving = 'true'"
+                + " WHERE alert_event_id = " + event_id + " ;";
+        insertStatement(updateStmt);
+    }
+
+    /**
+     * Method checks new Position of unit for stored AlertQueries
+     * @param pos - Current position of unit
+     */
+    private static void checkAlertQueries(UnitPosition pos) throws SQLException{
+        AlertUtil aUtil = new AlertUtil();
+        List<AlertQuery> queryList = aUtil.getAlertQueries(pos.getUnit_id());
+        if(!queryList.isEmpty()){
+            for (AlertQuery aQuery : queryList) {
+                try {
+                    boolean lastStatusAQ = aUtil.getAlertQueryLastStatus(aQuery, pos);
+                    boolean newStatusAQ = aUtil.checkAlertQuery(aQuery, pos);
+                    aUtil.setNewAlertQueryTimeStamp(aQuery, pos);
+                    if (newStatusAQ && !lastStatusAQ) {
+                        aUtil.setNewAlertQueryLastStatus(newStatusAQ, aQuery, pos);
+                    } else if (!newStatusAQ && lastStatusAQ) {
+                        aUtil.setNewAlertQueryLastStatus(newStatusAQ, aQuery, pos);
+                        insertAlertEvent(pos.internalGetTimestamp(), pos.getUnit_id(), aQuery.getAlertId());
+                    }
+                } catch (NoItemFoundException ex) {
+                    boolean newStatusAQ = aUtil.checkAlertQuery(aQuery, pos);
+                    aUtil.setNewAlertQueryLastStatus(newStatusAQ, aQuery, pos);
+                    aUtil.setNewAlertQueryTimeStamp(aQuery, pos);
+                    if (!newStatusAQ) {
+                        insertAlertEvent(pos.internalGetTimestamp(), pos.getUnit_id(), aQuery.getAlertId());
+                    }
+                }
+            }
+        }
+    }
+}

+ 34 - 0
src/main/java/cz/hsrs/db/UserManagemant.java

@@ -0,0 +1,34 @@
+package cz.hsrs.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class UserManagemant {
+
+	protected final Connection conn;
+	protected Statement stmt;
+
+	public UserManagemant(Connection conn) throws SQLException {
+
+		this.conn = conn;
+		stmt = conn.createStatement();
+
+	}
+
+	public void addSystemUser() throws SQLException {
+
+	}
+
+	public void addGroup() throws SQLException {
+
+	}
+
+	public void addUnitToGroup() throws SQLException {
+
+	}
+	
+	public void addUserToGroup() throws SQLException {
+
+	}
+}

+ 61 - 0
src/main/java/cz/hsrs/db/model/Alert.java

@@ -0,0 +1,61 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+/**
+ * @author mkepka
+ *
+ */
+public class Alert implements DBObject{
+
+	private int alertId;
+	private String description;
+	
+	public Alert(int alertId, String description) {
+		this.alertId = alertId;
+		this.description = description;
+	}
+	
+	public Alert(ResultSet set) throws SQLException{
+		this.alertId = set.getInt("alert_id");
+		this.description = set.getString("alert_description");
+	}
+	
+	public Alert() throws SQLException{
+		// TODO Auto-generated constructor stub
+	}
+
+	/**
+	 * @param alertId the alertId to set
+	 */
+	public void setAlertId(int alertId) {
+		this.alertId = alertId;
+	}
+	/**
+	 * @return the alertId
+	 */
+	public int getAlertId() {
+		return alertId;
+	}
+	/**
+	 * @param description the description to set
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	/**
+	 * @return the description
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		return new Alert(set);
+	}
+	
+}

+ 114 - 0
src/main/java/cz/hsrs/db/model/AlertEvent.java

@@ -0,0 +1,114 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * @author mkepka
+ * 
+ */
+public class AlertEvent implements DBObject{
+	
+	private int alertEventId;
+	private Date timeStamp;
+	private String timeString;
+	private boolean solving;
+	private boolean solved;
+	private long unitId;
+	private Alert alert;
+	private int gid;
+	
+	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");	
+	
+	public AlertEvent(Date timeStamp, boolean solved, boolean solving, long unit_id, Alert alert, int gid){
+		this.timeStamp=timeStamp;
+		this.timeString = format.format(timeStamp);
+		this.solved=solved;
+		this.solving = solving;
+		this.unitId=unit_id;
+		this.alert=alert;
+		this.gid = gid;
+	}
+	public AlertEvent(ResultSet set) throws SQLException{
+		this.alertEventId = set.getInt("alert_event_id");
+		this.timeStamp = new Date();
+		this.timeStamp.setTime(set.getTimestamp("time_stamp").getTime());
+
+		this.timeString = format.format(timeStamp);
+		this.alert = new Alert(set.getInt("alert_id"), set.getString("alert_description"));
+		this.solved=set.getBoolean("solved");
+		this.solving=set.getBoolean("solving");
+		this.unitId = set.getLong("unit_id");
+		this.gid = set.getInt("gid");
+	}
+	public AlertEvent() {
+		// TODO Auto-generated constructor stub
+	}
+	
+	/**
+	 * @return the alertEventId
+	 */
+	public int getAlertEventId() {
+		return alertEventId;
+	}
+	
+	/**
+	 * @return the timeStamp as Date
+	 */
+	public Date internalGetTimeStamp() {
+		return timeStamp;
+	}
+	/**
+	 * @return the timeStamp as String
+	 */
+	public String getTimeStamp(){
+		return timeString;
+	}
+	
+	/**
+	 * @return the solved
+	 */
+	public boolean isSolved() {
+		return solved;
+	}
+	/**
+	 * @return the solving
+	 */
+	public boolean isSolving() {
+		return solving;
+	}
+	/**
+	 * @return the unitId
+	 */
+	public long getUnitId() {
+		return unitId;
+	}
+	
+	/**
+	 * @return the alertId
+	 */
+	public Alert getAlert() {
+		return alert;
+	}
+	/**
+	 * @return the gid
+	 */
+	public int getGid(){
+		return gid;
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException{
+		return new AlertEvent(set);
+	}	
+}

+ 77 - 0
src/main/java/cz/hsrs/db/model/AlertQuery.java

@@ -0,0 +1,77 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+/**
+ * @author mkepka
+ *
+ */
+public class AlertQuery implements DBObject{
+
+	private int queryId;
+	private String query;
+	private int alertId;
+	
+	/*private boolean lastStatus;
+	private Date lastStatusTimeStamp;
+	
+	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");*/
+	
+	public AlertQuery(int queryId, String query, int alertId) {
+		this.queryId=queryId;
+		this.query = query;
+		this.alertId = alertId;
+	}
+	
+	/*public AlertQuery(int queryId, String query, int alertId, boolean lastStatus, Date timeStamp) {
+		this.queryId=queryId;
+		this.query = query;
+		this.alertId = alertId;
+		this.lastStatus = lastStatus;
+		this.lastStatusTimeStamp = timeStamp;
+	}*/
+	
+	public AlertQuery(ResultSet set) throws SQLException{
+		this.queryId = set.getInt("query_id");
+		this.query = set.getString("query_string");
+		this.alertId = set.getInt("alert_id");
+	}
+	
+	public AlertQuery() throws SQLException{
+		// TODO Auto-generated constructor stub
+	}
+
+	/**
+	 * @return the queryId
+	 */
+	public int getQueryId() {
+		return queryId;
+	}
+	public String getQuery(){
+		return query;
+	}
+	public int getAlertId(){
+		return alertId;
+	}
+
+	/*public boolean getLastStatus(){
+		return lastStatus;
+	}
+	
+	public Date getLastStatusTimeStamp(){
+		return lastStatusTimeStamp;
+	}*/
+	
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new AlertQuery(set);
+	}
+
+}

+ 72 - 0
src/main/java/cz/hsrs/db/model/Group.java

@@ -0,0 +1,72 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+
+
+public class Group implements DBObject{
+	 private int id ;
+	 private String group_name ;
+	 private int parent_group_id;
+	 private boolean has_children;
+	 
+	 public Group(){
+		 
+	 };
+	 public DBObject getDBObject(ResultSet set) throws SQLException{
+	    /*    this.id = set.getInt("id");
+	        this.group_name = set.getString("group_name");
+	        this.parent_group_id = set.getInt("parent_group_id");
+	        this.has_children = set.getBoolean("has_children");	*/			
+	        return new Group(set.getInt("id"), 
+	        		         set.getString("group_name"), 
+	        		         set.getInt("parent_group_id"),
+	        		         set.getBoolean("has_children"));
+	 }
+
+
+	public Group(int id, String group_name, int parent_group_id,
+			boolean has_children) {
+		super();
+		this.id = id;
+		this.group_name = group_name;
+		this.parent_group_id = parent_group_id;
+		this.has_children = has_children;
+	}
+
+
+	public int getId() {
+		return id;
+	}
+	
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	public String getGroup_name() {
+		return group_name;
+	}
+
+	public void setGroup_name(String group_name) {
+		this.group_name = group_name;
+	}
+
+	public int getParent_group_id() {
+		return parent_group_id;
+	}
+
+	public void setParent_group_id(int parent_group_id) {
+		this.parent_group_id = parent_group_id;
+	}
+
+	public boolean isHas_children() {
+		return has_children;
+	}
+
+	public void setHas_children(boolean has_children) {
+		this.has_children = has_children;
+	}
+}

+ 87 - 0
src/main/java/cz/hsrs/db/model/IgnitionStatus.java

@@ -0,0 +1,87 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * @author mkepka
+ *
+ */
+public class IgnitionStatus implements DBObject{
+
+	private int observationId;
+	private int gid;
+	private Date timeStamp;
+	private String timeString;
+	private boolean ignitionOn;
+	private long unitId;
+	
+	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+	
+	public IgnitionStatus(int observationId, int gid, Date timeStamp, double value, long unit_id){
+		this.observationId = observationId;
+		this.gid = gid;
+		this.timeStamp=timeStamp;
+		this.timeString = format.format(timeStamp);
+		if (value == 1){
+			this.ignitionOn=true;
+		}
+		else {
+			this.ignitionOn=false;
+		}
+		this.unitId=unit_id;		
+	}
+	public IgnitionStatus(ResultSet set) throws SQLException{
+		this.observationId = set.getInt("observation_id");
+		this.gid = set.getInt("gid");	
+		this.timeStamp = new Date();
+		this.timeStamp.setTime(set.getTimestamp("time_stamp").getTime());
+		this.timeString = format.format(timeStamp);
+		Double value;
+		try{
+			value = set.getDouble("value");
+		}catch(Exception e){
+			value = set.getDouble("observed_value");
+		}
+		if (value == 1){
+			this.ignitionOn=true;
+		}
+		else {
+			this.ignitionOn=false;
+		}
+		this.unitId = set.getLong("unit_id");		
+	}
+	public int getObservationId(){
+		return observationId;
+	}
+	public int getGid(){
+		return gid;
+	}
+	public String getTimeStamp(){
+		return timeString;
+	}
+	public Date internalGetTimeStamp(){
+		return timeStamp;
+	}
+	public boolean isIgnitionOn(){
+		return ignitionOn;
+	}
+	public long getUnitId(){
+		return unitId;
+	}
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new IgnitionStatus(set);
+	}	
+}

+ 17 - 0
src/main/java/cz/hsrs/db/model/NoItemFoundException.java

@@ -0,0 +1,17 @@
+package cz.hsrs.db.model;
+
+public class NoItemFoundException extends Exception {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
+	public NoItemFoundException(Exception e){
+		super(e);
+	}
+	public NoItemFoundException(String message){
+		super(message);
+	}
+
+}

+ 128 - 0
src/main/java/cz/hsrs/db/model/Observation.java

@@ -0,0 +1,128 @@
+package cz.hsrs.db.model;
+// default package
+// Generated 3.6.2008 8:30:06 by Hibernate Tools 3.2.2.GA
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * Observation generated by hbm2java
+ */
+public class Observation implements DBObject {
+
+    //private int id;
+    private long sensor_id;
+    private Date timeStamp;
+    private int gid;
+    private long unit_id;
+    private Double observedValue;
+    private final SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+    
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        return new Observation(set);
+    }
+    /**
+     * Constructor creates object with attributes
+     * @param timeStamp - time stamp when observation was measured
+     * @param observedValue - observed value, can be NaN
+     * @param sensor_id - id of sensor
+     * @param unit_id - id of unit
+     */
+    public Observation(Date timeStamp, Double observedValue, long sensor_id, long unit_id) {
+        super();
+        this.sensor_id = sensor_id;
+        this.timeStamp = timeStamp;
+        this.unit_id = unit_id;
+        this.observedValue = observedValue;
+    }
+
+    /**
+     * Constructor creates object from ResultSet
+     * @param set ResultSet with all mandatory attributes
+     * @throws SQLException
+     */
+    public Observation(ResultSet set) throws SQLException {
+        super();
+        this.sensor_id = set.getLong("sensor_id");
+        String time_string =  set.getString("time_stamp");
+        try {
+            timeStamp =  formater.parse(time_string+"00");
+        } catch (ParseException e) {
+            // Should never happpend
+            SQLExecutor.logger.log(Level.SEVERE, e.getMessage());
+        }
+        this.unit_id = set.getLong("unit_id");
+        this.observedValue = set.getDouble("observed_value");
+        this.gid = set.getInt("gid");
+    }
+    /**
+     * Empty constructor
+     */
+    public Observation() {
+    }    
+
+    public long getUnitId(){
+        return unit_id;
+    }
+    
+    public long getSensorId(){
+        return sensor_id;
+    }
+
+    public Date getTimeStamp() {
+        return timeStamp;
+    }
+
+    public int getGid() {
+        return gid;
+    }
+
+
+    public Double getObservedValue() {
+        return observedValue;
+    }
+
+    public void setObservedValue(Double observedValue) {
+        this.observedValue = observedValue;
+    }
+    
+    /**
+     * Method inserts Observation to database
+     * @return true if observations was successfully inserted, 
+     * false if it wasn't
+     * @throws SQLException
+     */
+    public boolean insertToDb() throws SQLException{
+        String ins = null;
+        if(this.observedValue.isNaN()){
+            ins = "INSERT INTO observations(time_stamp, observed_value, sensor_id, unit_id) VALUES ("
+                    + "'"+formater.format(this.timeStamp)+ "',"
+                    + " 'NaN',"
+                    + " "+this.sensor_id+","
+                    + " "+this.unit_id+");";
+        }
+        else{
+            ins = "INSERT INTO observations(time_stamp, observed_value, sensor_id, unit_id) VALUES ("
+                    + "'"+formater.format(this.timeStamp)+ "',"
+                    + " "+this.observedValue+","
+                    + " "+this.sensor_id+","
+                    + " "+this.unit_id+");";
+        }
+        int i = SQLExecutor.executeUpdate(ins);
+        /* Promyslet!! */
+        if (i == 1 || i == 0){
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+}

+ 191 - 0
src/main/java/cz/hsrs/db/model/Phenomenon.java

@@ -0,0 +1,191 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+// default package
+// Generated 3.6.2008 8:21:13 by Hibernate Tools 3.2.2.GA
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.util.SensorUtil;
+
+/**
+ * Phenomenon generated by hbm2java
+ */
+public class Phenomenon implements DBObject{
+
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        return new Phenomenon(set);
+    }
+
+    private String phenomenonId;
+    private String phenomenonName;
+    private String unit;
+
+    /**
+     * Constructor for creating object from ResultSet
+     * @param set
+     * @throws SQLException
+     */
+    public Phenomenon(ResultSet set) throws SQLException{
+        this.phenomenonId = set.getString("phenomenon_id");
+        this.phenomenonName = set.getString("phenomenon_name");
+        this.unit = set.getString("unit");
+    }
+
+    /**
+     * Constructor creates object from ID and UoM
+     * @param phenomenonId
+     * @param unit
+     * @param valuetype
+     */
+    public Phenomenon(String phenomenonId, String unit, String valuetype) {
+        this.phenomenonId = phenomenonId;
+        this.unit = unit;
+    }
+
+    /**
+     * Constructor creates object with all attributes
+     * @param phenomenonId
+     * @param phenomenonName
+     * @param unit
+     * @param valuetype
+     */
+    public Phenomenon(String phenomenonId, String phenomenonName, String unit, String valuetype) {
+        this.phenomenonId = phenomenonId;
+        this.phenomenonName = phenomenonName;
+        this.unit = unit;
+    }
+    
+    /**
+     * Constructor creates object without ID 
+     * @param phenomenonName
+     * @param unit
+     */
+    public Phenomenon(String phenomenonName, String unit) {
+        this.phenomenonName = phenomenonName;
+        this.unit = unit;
+    }
+    
+    /**
+     * Constructor for creating Phenomenon object that is already in DB
+     * @param phenomenonId
+     */
+    public Phenomenon(String phenomenonId) {
+        this.phenomenonId = phenomenonId;
+    }
+    
+    public String internalGetPhenomenonId() {
+        return this.phenomenonId;
+    }
+    
+    public String getPhenomenonId() {
+        return this.phenomenonId;
+    }
+    
+    public void internalSetPhenomenonId(String id){
+        this.phenomenonId = id;
+    }
+
+    public String getPhenomenonName() {
+        return this.phenomenonName;
+    }
+
+    public String getUnit() {
+        return this.unit;
+    }
+    
+    @Override
+    public String toString() {
+        return "[phenomenonId=" + phenomenonId + ", phenomenonName="
+                + phenomenonName + ", unit=" + unit + "]";
+    }
+
+    /**
+     * Method to insert new Phenomenon to DB
+     * @return instance of new Phenomenon with generated ID or Phenomenon that is already in DB
+     * @throws SQLException if an error occurs during inserting
+     * @throws NoItemFoundException 
+     */
+    public Phenomenon insertToDb() throws SQLException, NoItemFoundException {
+        SensorUtil sUtil = new SensorUtil();
+        if(this.phenomenonId != null){
+            Phenomenon phenDB = sUtil.getPhenomenonById(phenomenonId);
+            if(this.phenomenonName == null && this.unit == null){
+                if(phenDB == null){
+                    throw new NoItemFoundException("Phenomenon with given ID="+this.phenomenonId+" was not found!");
+                }
+                else {
+                    return phenDB;
+                }
+            } else if(this.phenomenonName != null && this.unit != null){
+                if(phenDB == null){
+                    // insert new
+                    int i = sUtil.insertNewPhenomenon(this);
+                    if (i == 1 || i == 0){
+                        return this;
+                    }
+                    else{
+                        throw new SQLException("Phenomenon was not inserted!");
+                    }
+                } else {
+                    if(phenDB.equals(this)){
+                        return this;
+                    } 
+                    else if(phenDB.getPhenomenonName().equalsIgnoreCase(phenomenonName)==true 
+                            && phenDB.getUnit().equalsIgnoreCase(unit) == false){
+                        // insert new
+                        int i = sUtil.insertNewPhenomenon(this);
+                        if (i == 1 || i == 0){
+                            return this;
+                        }
+                        else{
+                            throw new SQLException("Phenomenon was not inserted!");
+                        }
+                    }
+                    else{
+                        throw new SQLException("It is not possible to insert Phenomenon with given attributes!");
+                    }
+                }
+            }
+            else{
+                throw new SQLException("It is not possible to insert Phenomenon with given attributes!");
+            }
+        }
+        else{
+            if(this.phenomenonName != null && this.unit != null){
+                Phenomenon phenDB = sUtil.getPhenomenonByName(phenomenonName);
+                if(phenDB == null){
+                    // get new ID + insert new
+                    this.phenomenonId = sUtil.getNextPhenomenonId();
+                    int i = sUtil.insertNewPhenomenon(this);
+                    if (i == 1 || i == 0){
+                        return this;
+                    }
+                    else{
+                        throw new SQLException("Phenomenon was not inserted!");
+                    }
+                }
+                else{
+                    if(phenDB.getUnit().equalsIgnoreCase(unit)){
+                        return phenDB;
+                    }
+                    else{
+                        // get new ID + insert new
+                        this.phenomenonId = sUtil.getNextPhenomenonId();
+                        int i = sUtil.insertNewPhenomenon(this);
+                        if (i == 1 || i == 0){
+                            return this;
+                        }
+                        else{
+                            throw new SQLException("Phenomenon was not inserted!");
+                        }
+                    }
+                }
+            }
+            else{
+                throw new SQLException("It is not possible to insert Phenomenon with given attributes!");
+            }
+        }
+    }
+}

+ 80 - 0
src/main/java/cz/hsrs/db/model/Road.java

@@ -0,0 +1,80 @@
+package cz.hsrs.db.model;
+
+
+/**
+ *  gid serial NOT NULL,
+  cislo bigint,
+  oznaceni character varying(10),
+  poznamka character varying(50),
+  hskod character varying(4),
+  hsnazev character varying(50),
+  the_geom geometry,
+ * @author jezekjan
+ *
+ */
+
+public class Road {
+
+	int gid;
+	long cislo;
+	String oznaceni;
+	String poznamka;
+	String hskod;
+	String hsnazev;
+	double[] coords;
+	
+	
+	public Road(int gid, long cislo, String oznaceni, String poznamka,
+			String hskod, String hsnazev, double[] coords) {
+		super();
+		this.gid = gid;
+		this.cislo = cislo;
+		this.oznaceni = oznaceni;
+		this.poznamka = poznamka;
+		this.hskod = hskod;
+		this.hsnazev = hsnazev;
+		this.coords = coords;
+	}
+	public int getGid() {
+		return gid;
+	}
+	public void setGid(int gid) {
+		this.gid = gid;
+	}
+	public long getCislo() {
+		return cislo;
+	}
+	public void setCislo(long cislo) {
+		this.cislo = cislo;
+	}
+	public String getOznaceni() {
+		return oznaceni;
+	}
+	public void setOznaceni(String oznaceni) {
+		this.oznaceni = oznaceni;
+	}
+	public String getPoznamka() {
+		return poznamka;
+	}
+	public void setPoznamka(String poznamka) {
+		this.poznamka = poznamka;
+	}
+	public String getHskod() {
+		return hskod;
+	}
+	public void setHskod(String hskod) {
+		this.hskod = hskod;
+	}
+	public String getHsnazev() {
+		return hsnazev;
+	}
+	public void setHsnazev(String hsnazev) {
+		this.hsnazev = hsnazev;
+	}
+	public double[] getCoords() {
+		return coords;
+	}
+	public void setCoords(double[] coords) {
+		this.coords = coords;
+	} 
+}

+ 199 - 0
src/main/java/cz/hsrs/db/model/Sensor.java

@@ -0,0 +1,199 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.util.SensorUtil;
+
+public class Sensor implements DBObject {
+
+    private long sensorId;
+    private String sensorName;
+    private String sensorType;
+    private Phenomenon phenomenon;
+
+    /**
+     * Constructor creates object with all attributes and Phenomenon object
+     * @param sensorId
+     * @param sensorName
+     * @param sensorType
+     * @param phenomenon
+     */
+    public Sensor(long sensorId, String sensorName, String sensorType, Phenomenon phenomenon) {
+        super();
+        this.sensorId = sensorId;
+        this.sensorName = sensorName;
+        this.sensorType = sensorType;
+        this.phenomenon = phenomenon;
+    }
+    
+    /**
+     * Empty constructor for serialization
+     */
+    public Sensor(){
+    }
+    
+    /**
+     * Constructor for inserting new Sensor to DB
+     * @param sensorName
+     * @param sensorType
+     * @param phenomenon
+     */
+    public Sensor(String sensorName, String sensorType, Phenomenon phenomenon) {
+        super();
+        this.sensorName = sensorName;
+        this.sensorType = sensorType;
+        this.phenomenon = phenomenon;
+    }
+
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        this.sensorId = set.getLong("sensor_id");
+        this.sensorName = set.getString("sensor_name");
+        this.sensorType = set.getString("sensor_type");
+        SensorUtil sUtil = new SensorUtil();
+        this.phenomenon = sUtil.getPhenomenonById(set.getString("phenomenon_id"));
+        return this;
+    }
+
+    public long getSensorId() {
+        return sensorId;
+    }
+    public void internalSetSensorId(Long id){
+        this.sensorId = id;
+    }
+
+    public String getSensorName() {
+        return sensorName;
+    }
+
+    public String getSensorType() {
+        return sensorType;
+    }
+
+    public Phenomenon getPhenomenon() {
+        return phenomenon;
+    }
+    
+    @Override
+    public String toString() {
+        return "[sensorId=" + sensorId + ", sensorName=" + sensorName
+                + ", sensorType=" + sensorType + ", phenomenon=" + phenomenon
+                + "]";
+    }
+
+    /**
+     * Method to insert new Sensor to DB
+     * @return Sensor instance with generated ID
+     * @throws SQLException if an error occurs during inserting
+     * @throws NoItemFoundException 
+     */
+    public Sensor insertToDb(Long unitId) throws SQLException, NoItemFoundException {
+        SensorUtil sUtil = new SensorUtil();
+        if(this.sensorId != 0){
+            Sensor senDB = sUtil.getSensorByIdOrName(sensorId, null);
+            if(this.sensorName == null && this.sensorType == null && this.phenomenon == null){
+                if(senDB == null){
+                    throw new NoItemFoundException("Sensor with given ID="+this.sensorId+" was not found!");
+                }
+                else{
+                    // there is sensor with same ID in DB
+                    if(sUtil.isSensorPairedToUnit(sensorId, unitId) == false){
+                        sUtil.pairUnitToSensor(unitId, sensorId);
+                    }
+                    return senDB;
+                }
+            }
+            else if(this.sensorName != null && this.sensorType != null && this.phenomenon != null){
+                if(senDB == null){
+                    // insert new sensor + new phenomenon
+                    this.phenomenon = this.phenomenon.insertToDb();
+                    int i = sUtil.insertSensor(this);
+                    if (i == 1){
+                        sUtil.pairUnitToSensor(unitId, this.sensorId);
+                        return this;
+                    }
+                    else{
+                        throw new SQLException("Sensor was not inserted!");
+                    }
+                }
+                else{
+                    if(senDB.getSensorName().equalsIgnoreCase(sensorName) == true){
+                        if(senDB.getSensorType().equalsIgnoreCase(sensorType) == true && this.phenomenon.internalGetPhenomenonId() != null){
+                            if(senDB.getPhenomenon().internalGetPhenomenonId().equalsIgnoreCase(this.phenomenon.internalGetPhenomenonId())){
+                                // there is sensor with same name, type and phenomenon Id in DB
+                                if(sUtil.isSensorPairedToUnit(sensorId, unitId) == false){
+                                    sUtil.pairUnitToSensor(unitId, sensorId);
+                                }
+                                return senDB;
+                            }
+                            else{
+                                throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                            }
+                        }
+                        else{
+                            throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                        }
+                    }
+                    else if(senDB.getSensorName().equalsIgnoreCase(sensorName)==false && senDB.getSensorType().equalsIgnoreCase(sensorType) == false){
+                        throw new SQLException("It is not possible to insert Sensor with given attributes! There is Sensor with same ID.");
+                    }
+                    else{
+                        throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                    }
+                }
+            }
+            else{
+                throw new SQLException("It is not possible to insert Sensor with given attributes!");
+            }
+        }
+        else{
+            Sensor senDB = sUtil.getSensorByIdOrName(null, sensorName);
+            if(senDB == null){
+                // new ID + insert new sensor + insert phenomenon
+                this.phenomenon = this.phenomenon.insertToDb();
+                this.sensorId = sUtil.getNextSensorId();
+                int i = sUtil.insertSensor(this);
+                if (i == 1){
+                    sUtil.pairUnitToSensor(unitId, this.sensorId);
+                    return this;
+                }
+                else{
+                    throw new SQLException("Sensor was not inserted!");
+                }
+            }
+            else{
+                if(this.sensorType != null && this.phenomenon != null){
+                // check if there is same phenomenon in DB
+                    if(this.phenomenon.getPhenomenonName() != null && this.phenomenon.getUnit() != null){
+                        Phenomenon phenDB = sUtil.getPhenomenonByName(this.phenomenon.getPhenomenonName());
+                        if(phenDB != null){
+                            if(this.phenomenon.getUnit().equalsIgnoreCase(phenDB.getUnit())){
+                                this.phenomenon = phenDB;
+                            }
+                        }
+                    }
+                    if(senDB.getSensorType().equalsIgnoreCase(this.sensorType)==true && this.getPhenomenon().internalGetPhenomenonId() != null){
+                        if(senDB.getPhenomenon().internalGetPhenomenonId().equalsIgnoreCase(this.phenomenon.internalGetPhenomenonId())){
+                            // there is sensor with same name and type in DB
+                            if(sUtil.isSensorPairedToUnit(senDB.getSensorId(), unitId) == false){
+                                sUtil.pairUnitToSensor(unitId, senDB.getSensorId());
+                            }
+                            return senDB;
+                        }
+                        else{
+                            throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                        }
+                    }
+                    else{
+                        throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                    }
+                }
+                else{
+                    throw new SQLException("It is not possible to insert Sensor with given attributes!");
+                }
+            }
+        }
+    }
+}

+ 82 - 0
src/main/java/cz/hsrs/db/model/TrackData.java

@@ -0,0 +1,82 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class TrackData {
+	private int gid;	
+	private int numPts;	
+	private long unit_id;
+	private Date start;
+	private Date end;
+	private boolean is_closed;
+	
+	private final static String cGid="gid";
+	private final static String cUnit_id = "unit_id";
+	private final static String cStart = "track_start";
+	private final static String cEnd = "track_end";
+	private final static String cClosed = "is_closed";
+	
+	public final  static String SELECT = cGid +", "+ cUnit_id + ", "+ cStart +", "+ cEnd + ", " + cClosed + ", ST_NumPoints(the_geom) AS numpts ";
+	
+
+	public TrackData(){
+		
+	}
+	//private static 	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+ZZ");
+	
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		return new UnitTrack(set);			
+	}
+
+	public TrackData(ResultSet set) throws SQLException{
+		this.gid = set.getInt(cGid);
+		this.unit_id = set.getLong(cUnit_id);
+		this.is_closed = set.getBoolean(cClosed);
+		this.numPts = set.getInt("numpts");
+		/* set.getTimeStamp vraci Timestamp a ne Date a pak se to blbe formatuje */
+		this.start = new Date();
+		this.start.setTime(set.getTimestamp(cStart).getTime());
+		this.end =   new Date();
+		this.end.setTime(set.getTimestamp(cEnd).getTime());
+		
+			
+	}	
+
+	public int getGid() {
+		return gid;
+	}
+	
+	public int getNumPts() {
+		return numPts;
+	}
+	
+	public void setGid(int gid) {
+		this.gid = gid;
+	}
+
+	public long getUnit_id() {
+		return unit_id;
+	}
+	public void setUnit_id(long unit_id) {
+		this.unit_id = unit_id;
+	}
+	public Date getEnd() {
+		return end;
+	}
+
+	public Date getStart() {
+		return start;
+	}
+	
+	public boolean isClosed(){
+		return is_closed;
+	}
+}

+ 65 - 0
src/main/java/cz/hsrs/db/model/Unit.java

@@ -0,0 +1,65 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+public class Unit implements DBObject{
+	private long unitId;
+	private int holderId;
+	private String description;	
+	
+	public Unit(long unitId, int userId, String description) {
+		super();
+		this.unitId = unitId;
+		this.holderId = userId;
+		this.description = description;
+	}
+	
+	public Unit(long unitId, String description) {
+		super();
+		this.unitId = unitId;		
+		this.description = description;
+	}
+	
+	public Unit(){
+		
+	}
+	
+	public Unit(ResultSet set) throws SQLException {
+		this.unitId = set.getLong("unit_id");
+		this.description = set.getString("description");
+		this.holderId = set.getInt("holder_id");
+	}
+
+	public long getUnitId() {
+		return unitId;
+	}
+	public void setUnitId(long unitId) {
+		this.unitId = unitId;
+	}
+	public int getHolderId() {
+		return holderId;
+	}
+	public void setHolderId(int userId) {
+		this.holderId = userId;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new Unit(set);
+	}
+
+
+	
+	
+
+}

+ 91 - 0
src/main/java/cz/hsrs/db/model/UnitDriver.java

@@ -0,0 +1,91 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.util.UnitUtil;
+
+public class UnitDriver implements DBObject{
+	
+	private int id;
+	private UnitHolder holder;
+	private String fname;
+	private String lname;
+	private String title;
+	private String phone;
+
+	
+	private UnitDriver(ResultSet set){
+		
+	}
+	public UnitDriver(int id, UnitHolder holder, String fname, String lname,
+			String title, String phone) {
+		super();
+		this.id = id;
+		this.holder = holder;
+		this.fname = fname;
+		this.lname = lname;
+		this.title = title;
+		this.phone = phone;
+	}
+
+	public UnitDriver() {
+		super();
+		this.id = 0;
+		this.holder = null;
+		this.fname =  null;
+		this.lname =  null;
+		this.title =  null;
+		this.phone =  null;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public UnitHolder getHolder() {
+		return holder;
+	}
+
+	public String getFname() {
+		return fname;
+	}
+
+	public String getLname() {
+		return lname;
+	}
+
+
+
+	public String getTitle() {
+		return title;
+	}
+
+
+
+	public String getPhone() {
+		return phone;
+	}
+
+
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		UnitHolder h;
+		try {
+			h = (new UnitUtil())
+			.getUnitHolder(set.getLong("unit_id"));
+		} catch (NoItemFoundException e) {
+			// TODO Auto-generated catch block
+			h = null;
+		}
+		  return new UnitDriver(set.getInt("driver_id"), 
+                    h, 
+                    set.getString("fname"), 
+                    set.getString("lname"),
+                    set.getString("title"),
+                    set.getString("phone"));
+	}
+}

+ 69 - 0
src/main/java/cz/hsrs/db/model/UnitHolder.java

@@ -0,0 +1,69 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+public class UnitHolder implements DBObject{
+	private final int holder_id;	
+	private final String holder_name;
+	private final String phone;
+	private final String icon_id;
+	private final String address;
+	private final String email;
+	private final String www;
+	
+	public static String SELECT = " unit_holders.holder_id, unit_holders.holder_name, unit_holders.phone, unit_holders.icon_id, unit_holders.address, unit_holders.email, unit_holders.www ";
+
+
+	public UnitHolder(ResultSet set) throws SQLException {
+		holder_id = set.getInt("holder_id");		
+		holder_name = set.getString("holder_name");
+		phone = set.getString("phone");
+		icon_id = set.getString("icon_id");
+		address = set.getString("address");
+		email = set.getString("email");
+		www = set.getString("www");
+	}
+	
+	public String getHolderName() {
+		return holder_name;
+	}
+	public String getPhone() {
+		return phone;
+	}
+	public String getIcon_id() {
+		return icon_id;
+	}
+	public int getHolder_id() {
+		return holder_id;
+	}
+	/**
+	 * @return the address
+	 */
+	public String getAddress() {
+		return address;
+	}
+
+	/**
+	 * @return the email
+	 */
+	public String getEmail() {
+		return email;
+	}
+
+	/**
+	 * @return the www
+	 */
+	public String getWww() {
+		return www;
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new UnitHolder(set);
+	}
+
+}

+ 462 - 0
src/main/java/cz/hsrs/db/model/UnitPosition.java

@@ -0,0 +1,462 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.DateUtil;
+import cz.hsrs.db.util.UnitUtil;
+
+public class UnitPosition implements DBObject {
+
+    private final int gid;
+    private final long unit_id;
+    private final double x;
+    private final double y;
+    private final double alt;
+    private final String time_stamp;
+    private Date timeStamp;
+    private final double dop;
+    private final double speed;
+    private int group_id;
+    private final String geom;
+    private final String srid;
+    private final String time_received;
+    private final String first_timestamp;
+
+    public static final String SELECT = "gid, unit_id, time_stamp, st_x(the_geom), st_y(the_geom), speed, st_srid(the_geom) ";
+    private static final String SCHEMA_NAME = "public";
+    //private static final String ALTITUDE_COLUMN = "altitude";
+    //private static final String DATASET_TABLE_NAME = "units_positions";
+
+    /**
+     * Empty constructor initializes all attributes to null or zero
+     */
+    public UnitPosition() {
+        speed = Double.NaN;
+        dop = Double.NaN;
+        unit_id = 0;
+        gid = 0;
+        y = Double.NaN;
+        x = Double.NaN;
+        alt = Double.NaN;
+        time_stamp = null;
+        geom = null;
+        srid = null;
+        time_received = null;
+        first_timestamp = null;
+    }
+
+    /**
+     * Constructor instantiates new object from ResultSet, without altitude!
+     * @param set ResultSet with columns:
+     * gid, unit_id, time_stamp, speed, st_x, st_y, st_srid
+     * @throws SQLException
+     */
+    public UnitPosition(ResultSet set) throws SQLException {
+        this.gid = set.getInt("gid");
+        this.unit_id = set.getLong("unit_id");
+        this.time_stamp = set.getString("time_stamp");
+        this.speed = set.getDouble("speed");
+        this.x = set.getDouble("st_x");
+        this.y = set.getDouble("st_y");
+        this.alt = Double.NaN;
+        this.geom = createPointString(x, y);
+        this.srid = set.getString("st_srid");
+        this.dop = Double.NaN;
+        this.time_received = null;
+        this.first_timestamp = null;
+
+        UnitUtil uUtil = new UnitUtil();
+        this.group_id = uUtil.getGroupID(unit_id);
+    }
+
+    /**
+     * Constructor instantiates object from fields
+     * @param unitId - id of unit
+     * @param x - long coordinate
+     * @param y - lat coordinate
+     * @param timeStamp time stamp of position
+     * @throws SQLException
+     */
+    public UnitPosition(long unitId, double x, double y, Date timeStamp) throws SQLException {
+        this(unitId, x, y, 0, timeStamp, Double.NaN, "");
+    }
+
+    /**
+     * Constructor instantiates object from fields
+     * @param unitId - id of unit
+     * @param x - long coordinate
+     * @param y - lat coordinate
+     * @param alt - altitude coordinate
+     * @param timeStamp time stamp of position
+     * @throws SQLException
+     */
+    public UnitPosition(long unitId, double x, double y, double alt, Date timeStamp) throws SQLException {
+        this(unitId, x, y, alt, timeStamp, Double.NaN, "");
+    }
+
+    /**
+     * Constructor for creating UnitPosition from WebService
+     * @param unitId
+     * @param x
+     * @param y
+     * @param alt
+     * @param timeStamp
+     * @param speed
+     * @param srid
+     * @throws SQLException
+     */
+    public UnitPosition(long unitId, double x, double y, double alt, Date timeStamp, Double speed, String srid) throws SQLException {
+        super();
+        this.unit_id = unitId;
+        this.gid = getNextGid();
+        this.x = x;
+        this.y = y;
+        this.alt = alt;
+        this.geom = createPointString(x, y);
+        this.timeStamp = timeStamp;
+        this.speed = speed;
+        this.dop = Double.NaN;
+        this.srid = srid;
+
+        this.time_stamp = null;
+        this.time_received = null;
+        this.first_timestamp = null;
+    }
+
+    /**
+     * Constructor for creating UnitPosition object from WebService
+     * @param unitId
+     * @param x
+     * @param y
+     * @param alt
+     * @param timeStamp
+     * @param speed
+     * @param dop
+     * @param srid
+     * @throws SQLException
+     */
+    public UnitPosition(long unitId, double x, double y, double alt, Date timeStamp, Double speed, Double dop, String srid) throws SQLException {
+        super();
+        this.unit_id = unitId;
+        this.gid = getNextGid();
+        this.x = x;
+        this.y = y;
+        this.alt = alt;
+        this.geom = createPointString(x, y);
+        this.timeStamp = timeStamp;
+        this.speed = speed;
+        this.dop = dop;
+        this.srid = srid;
+
+        this.time_stamp = DateUtil.formatSecsTZ.format(timeStamp);
+        this.time_received = null;
+        this.first_timestamp = null;
+    }
+
+    /**
+     * Constructor for creating UnitPosition object from DB
+     * @param gid
+     * @param unit_id
+     * @param alt
+     * @param time_string
+     * @param dop
+     * @param speed
+     * @param geom
+     * @param srid
+     * @param receivedString
+     * @param firstTimestampString
+     */
+    public UnitPosition(int gid, long unit_id, double x, double y, double alt, String time_string, double dop, double speed,
+                        String srid, String receivedString, String firstTimestampString) {
+        this.gid = gid;
+        this.unit_id = unit_id;
+        this.x = x;
+        this.y = y;
+        this.alt = alt;
+        this.geom = null;
+        this.time_stamp = time_string;
+        this.dop = dop;
+        this.speed = speed;
+        this.srid = srid;
+
+        this.time_received = receivedString;
+        this.first_timestamp = firstTimestampString;
+    }
+
+    /**
+     * Constructor for updating UnitPosition from webservice
+     * @param gid
+     * @param unit_id
+     * @param x
+     * @param y
+     * @param alt
+     * @param timestamp
+     * @param dop
+     * @param speed
+     * @param srid
+     */
+    public UnitPosition(int gid, long unit_id, double x, double y, double alt, Date timestamp, double dop, double speed, String srid) {
+        this.gid = gid;
+        this.unit_id = unit_id;
+        this.x = x;
+        this.y = y;
+        this.alt = alt;
+        this.geom = this.createPointString(x, y);
+        this.timeStamp = timestamp;
+        this.dop = dop;
+        this.speed = speed;
+        this.srid = srid;
+
+        this.time_stamp = DateUtil.formatSecsTZ.format(timestamp);
+        this.time_received = null;
+        this.first_timestamp = null;
+    }
+
+    public double getSpeed() {
+        return speed;
+    }
+
+    public int getGroup_id() {
+        return group_id;
+    }
+
+    public double getX() {
+        return x;
+    }
+
+    public double getY() {
+        return y;
+    }
+
+    /**
+     * Method returns Altitude of the Positions
+     * @return double value if position is defined,
+     * NULL if altitude is NaN or null
+     */
+    public Double getAlt(){
+        if(Double.isNaN(alt)){
+            return null;
+        }
+        else{
+            return alt;
+        }
+    }
+
+    public String getSRID(){
+        return srid;
+    }
+
+    /**
+     * Inherited method converts content of ResultSet to UnitPosition object
+     */
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        return new UnitPosition(set);
+    }
+
+    /**
+     * Getter returns gid of unit_position
+     * @return gid
+     */
+    public int getGid() {
+        return gid;
+    }
+
+    /**
+     * Method returns geom as String:
+     * "POINT(x y)"
+     * @return String "POINT(x y)"
+     */
+    public String internalGetGeom() {
+        return geom;
+    }
+
+    /**
+     * Method returns time stamp of position as Date
+     * if Date time stamp is not set parses it from String time stamp
+     * processes String time stamp in case of using microseconds from DB
+     * @return timestamp of position as Date
+     * @throws SQLException
+     */
+    public Date internalGetTimestamp() throws SQLException {
+        if (timeStamp == null) {
+            try {
+                return DateUtil.parseTimestamp(time_stamp);
+            } catch (ParseException e) {
+                SQLExecutor.logger.log(Level.SEVERE, e.getMessage());
+                throw new SQLException("Timestamp of position is not present!");
+            }
+        }
+        else{
+            return timeStamp;
+        }
+    }
+
+    /**
+     * Getter returns Unit_ID
+     * @return unit_id
+     */
+    public long getUnit_id() {
+        return unit_id;
+    }
+
+    /**
+     * Method inserts new position into database
+     * @return true if positions was successfully inserted, false otherwise
+     * @throws SQLException is thrown if an Exception occurs during inserting
+     */
+    public boolean insertToDb() throws SQLException {
+        StringBuffer queryBuff= new StringBuffer();
+        if(SQLExecutor.isAltitudeEnabled()){
+            queryBuff.append("INSERT INTO "+SCHEMA_NAME+".units_positions(altitude, the_geom, unit_id, time_stamp, gid, speed, dop) VALUES (");
+            queryBuff.append(Double.isNaN(this.alt) ? "NULL, " : String.valueOf(this.alt)+", ");
+        }
+        else{
+            queryBuff.append("INSERT INTO "+SCHEMA_NAME+".units_positions(the_geom, unit_id, time_stamp, gid, speed, dop) VALUES (");
+        }
+        queryBuff.append("st_geomfromtext('"+ this.geom + "', "+(this.srid.isEmpty() ? "4326" : this.srid)+"), ");
+        queryBuff.append(this.unit_id + ", ");
+        queryBuff.append("timestamp with time zone '" + DateUtil.formatSecsTZ.format(this.timeStamp) + "', ");
+        queryBuff.append(this.gid + ", ");
+        queryBuff.append(Double.isNaN(this.speed) ? "NULL, " : String.valueOf(this.speed)+", ");
+        queryBuff.append(Double.isNaN(this.dop) ? "NULL" : String.valueOf(this.dop));
+        queryBuff.append(");");
+
+        String ins = queryBuff.toString();
+        int i = SQLExecutor.executeUpdate(ins);
+        /** If there is partitioning on table units_positions, function executeUpdate returns 0.
+         *  If there is only units_positions table, function executeUpdate returns 1.
+         */
+        if (i == 1 || i == 0){
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+
+    /**
+     * Method returns String to create geometry object in PostGIS
+     * "st_geomfromtext('POINT(x y)', SRID)";
+     * @return "st_geomfromtext('POINT(x y)', SRID)"; as String
+     */
+    public String getPostgisString() {
+        if(this.srid == null){
+            return "st_geomfromtext('" + this.geom + "', 4326)";
+        }
+        else{
+            if(this.srid.isEmpty()){
+                return "st_geomfromtext('" + this.geom + "', 4326)";
+            }
+            else{
+                return "st_geomfromtext('" + this.geom + "', "+this.srid+")";
+            }
+        }
+    }
+
+    private String createPointString(double x, double y) {
+        return new String("POINT(" + x + " " + y + ")");
+    }
+
+    /**
+     *
+     * @return the_geom
+     */
+    public String getPostgisGeomString() {
+        return this.geom;
+    }
+
+    /**
+     *
+     * @return the time_stamp
+     */
+    public String getTime_stamp() {
+        return time_stamp;
+    }
+
+    /**
+     * Method returns DOP value of Position
+     * @return the dop double value, NULL if dop is NaN or null
+     */
+    public Double getDop() {
+        if(Double.isNaN(dop)){
+            return null;
+        }
+        else{
+            return dop;
+        }
+    }
+
+    /**
+     * @return the srid
+     */
+    public String getSrid() {
+        return srid;
+    }
+
+    /**
+     * @return the time_received
+     * @throws ParseException
+     */
+    public Date internalGetTimeReceived() throws ParseException {
+        return DateUtil.parseTimestampMicro(this.time_received);
+    }
+
+    /**
+     * @return the time_received
+     */
+    public String getReceivedTimestampString() {
+        return this.time_received;
+    }
+
+    /**
+     * @return the first_timestamp
+     * @throws ParseException
+     */
+    public Date internalGetFirstTimestamp() throws ParseException {
+        return DateUtil.parseTimestampMicro(this.first_timestamp);
+    }
+
+    /**
+     * @return the firstTsString
+     */
+    public String getFirstTimesstamp() {
+        return this.first_timestamp;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "UnitPosition [unit_id=" + unit_id + ", gid=" + gid + ", speed="
+                + speed + ", x=" + x + ", y=" + y + ", alt=" + alt
+                + ", time_string=" + time_stamp + ", group_id=" + group_id
+                + ", srid=" + srid + "]";
+    }
+
+    /**
+     * Method get next value of sequence for GID
+     * @return next value of GID as integer
+     * @throws SQLException
+     */
+    private int getNextGid() throws SQLException{
+        try{
+            String queryGid = "SELECT nextval('"+SCHEMA_NAME+".units_positions_gid_seq'::regclass);";
+            ResultSet resId = SQLExecutor.getInstance().executeQuery(queryGid);
+            if(resId.next()){
+                return resId.getInt(1);
+            }
+            else{
+                throw new SQLException("Next value of GID cannot be selected!");
+            }
+        } catch(SQLException e){
+            throw new SQLException("Next value of GID cannot be selected!");
+        }
+    }
+}

+ 89 - 0
src/main/java/cz/hsrs/db/model/UnitTrack.java

@@ -0,0 +1,89 @@
+package cz.hsrs.db.model;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import cz.hsrs.db.DBObject;
+
+
+public class UnitTrack implements DBObject{
+
+	private int gid;
+	private String geom;
+	private long unit_id;
+	private String start;
+	private String end;
+	private int group_id;
+	
+	public UnitTrack(){
+		
+	}
+	//private static 	SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+ZZ");
+	
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		return new UnitTrack(set);			
+	}
+
+	public UnitTrack(ResultSet set) throws SQLException{
+		this.gid = set.getInt("gid");
+			
+			this.gid = set.getInt("gid");
+			this.unit_id = set.getLong("unit_id");
+			this.start = set.getString("track_start");
+			this.end = set.getString("track_end");
+			this.geom = set.getString("st_astext");
+			this.group_id = set.getInt("group_id");
+			
+	}
+	
+	public int getGroup_id() {
+		return group_id;
+	}
+
+	public void setGroup_id(int group_id) {
+		this.group_id = group_id;
+	}
+
+	public String getGeom() {
+		return geom;
+	}
+
+	public void setGeom(String geom) {
+		this.geom = geom;
+	}
+
+	public int getGid() {
+		return gid;
+	}
+	public void setGid(int gid) {
+		this.gid = gid;
+	}
+
+	public long getUnit_id() {
+		return unit_id;
+	}
+	public void setUnit_id(long unit_id) {
+		this.unit_id = unit_id;
+	}
+	public String getEnd() {
+		return end;
+	}
+
+	public void setEnd(String end) {
+		this.end = end;
+	}
+
+	public void setStart(String start) {
+		this.start = start;
+	}
+
+	public String getStart() {
+		return start;
+	}
+
+	
+}
+

+ 63 - 0
src/main/java/cz/hsrs/db/model/composite/AggregateObservation.java

@@ -0,0 +1,63 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.Observation;
+
+public class AggregateObservation  implements DBObject{
+	
+	private final double value;
+	private final Date time_stamp;
+	private int gid;
+	private final int count;
+
+//	public static final String SELECT = " avg(observed_value) as avg_value, date_trunc('day', time_stamp) AS dtrunc, count(*) AS count ";
+	
+	public static final SimpleDateFormat formater = new SimpleDateFormat(
+	"yyyy-MM-dd HH:mm:ssZ");
+	
+	public AggregateObservation() {
+		this(0,null,0);
+	}
+	public AggregateObservation(double value,  Date timeStamp, int count) {
+		super();
+		this.value = value;
+		this.time_stamp = timeStamp;
+		this.gid = gid;
+		this.count=count;
+	}
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		String time_string = set.getString("dtrunc");
+		Date time;
+		try {
+			time = formater.parse(time_string+"00");
+		} catch (ParseException e) {
+			throw new SQLException(e);
+		}
+		
+		return new AggregateObservation(set.getDouble("avg_value"),time , set.getInt("count"));
+	}
+	public int getCount() {
+		return count;
+	}
+	public double getValue() {
+		return value;
+	}
+	public Date internalGetInternalTime() {
+		return time_stamp;
+	}
+	
+	public String getTime() {
+		return formater.format(time_stamp);
+	}
+	
+	
+
+}

+ 55 - 0
src/main/java/cz/hsrs/db/model/composite/LastPosition.java

@@ -0,0 +1,55 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.AlertEvent;
+import cz.hsrs.db.model.UnitPosition;
+
+
+
+
+public class LastPosition implements DBObject{
+	
+	public static final String IS_RUNNING = "is_moving";
+
+	private final UnitPosition position;
+	private final List<AlertEvent> alertEvents;
+	private final Map attributes;
+	
+	
+	public LastPosition() {
+		super();
+		this.position = null;
+		this.attributes = null;
+		this.alertEvents = null;
+	}
+	
+	public LastPosition(UnitPosition position, Map attributes, List<AlertEvent> events) {
+		super();
+		this.position = position;
+		this.attributes = attributes;
+		this.alertEvents = events;
+	}
+	
+	public UnitPosition getPosition() {
+		return position;
+	}
+
+	public Map getAttributes() {
+		return attributes;
+	}
+
+	public List<AlertEvent> getAlertEvents(){
+		return alertEvents;
+	}
+	
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new LastPosition();
+	}
+}

+ 149 - 0
src/main/java/cz/hsrs/db/model/composite/ObservationMedlov.java

@@ -0,0 +1,149 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+/**
+ * @author mkepka
+ *
+ */
+public class ObservationMedlov implements DBObject{
+	
+	private int observationId;
+	private long unitId;
+	private long sensorId;
+	private String timeStamp;
+	private double observedValue;
+	private String sensorName;
+	private String unit;
+	private String phenomenonName;
+	private String phenomenonId;
+	private String theGeom;
+
+	
+	
+	/**
+	 * @param observationId
+	 * @param unitId
+	 * @param sensorId
+	 * @param timeStamp
+	 * @param observedValue
+	 * @param sensorName
+	 * @param unit
+	 * @param phenomenonName
+	 * @param phenomenonId
+	 * @param theGeom
+	 */
+	public ObservationMedlov(int observationId, long unitId, long sensorId,
+			String timeStamp, double observedValue, String sensorName,
+			String unit, String phenomenonName, String phenomenonId,
+			String theGeom) {
+		super();
+		this.observationId = observationId;
+		this.unitId = unitId;
+		this.sensorId = sensorId;
+		this.timeStamp = timeStamp;
+		this.observedValue = observedValue;
+		this.sensorName = sensorName;
+		this.unit = unit;
+		this.phenomenonName = phenomenonName;
+		this.phenomenonId = phenomenonId;
+		this.theGeom = theGeom;
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		
+		return new ObservationMedlov(set.getInt("observation_id"), 
+									 set.getLong("unit_id"), 
+									 set.getLong("sensor_id"),
+									 set.getString("time_stamp"), 
+									 set.getDouble("observed_value"), 
+									 set.getString("sensor_name"),
+									 set.getString("unit"), 
+									 set.getString("phenomenon_name"), 
+									 set.getString("phenomenon_id"),
+									 set.getString("the_geom"));
+	}
+	
+	public ObservationMedlov()throws SQLException {
+		
+	}
+
+	/**
+	 * @return the observationId
+	 */
+	public int getObservationId() {
+		return observationId;
+	}
+
+	/**
+	 * @return the unitId
+	 */
+	public long getUnitId() {
+		return unitId;
+	}
+
+	/**
+	 * @return the sensorId
+	 */
+	public long getSensorId() {
+		return sensorId;
+	}
+
+	/**
+	 * @return the timeStamp
+	 */
+	public String getTimeStamp() {
+		return timeStamp;
+	}
+
+	/**
+	 * @return the observedValue
+	 */
+	public double getObservedValue() {
+		return observedValue;
+	}
+
+	/**
+	 * @return the sensorName
+	 */
+	public String getSensorName() {
+		return sensorName;
+	}
+
+	/**
+	 * @return the unit
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * @return the phenomenonName
+	 */
+	public String getPhenomenonName() {
+		return phenomenonName;
+	}
+
+	/**
+	 * @return the phenomenonId
+	 */
+	public String getPhenomenonId() {
+		return phenomenonId;
+	}
+
+	/**
+	 * @return the theGeom
+	 */
+	public String getTheGeom() {
+		return theGeom;
+	}
+
+	 
+}

+ 65 - 0
src/main/java/cz/hsrs/db/model/composite/ObservationValue.java

@@ -0,0 +1,65 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class ObservationValue implements DBObject {
+
+    private final double value;
+    private Date time_stamp;
+    private final String time_string;
+    private int gid;
+
+    public static final SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+
+    public ObservationValue() {
+        this(0, null, 0);
+    }
+
+    public ObservationValue(double value, String timeStamp, int gid) {
+        super();
+        this.value = value;
+        this.time_string = timeStamp;
+        this.gid = gid;
+    }
+
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+
+        return new ObservationValue(set.getDouble("observed_value"), set.getString("time_stamp"), set.getInt("gid"));
+    }
+
+    public int getGid() {
+        return gid;
+    }
+
+    public void setGid(int gid) {
+        this.gid = gid;
+    }
+
+    public double getValue() {
+        return value;
+    }
+
+    public String getTime() {
+        return time_string;
+    }
+
+    public Date internalGetTime_stamp() {
+        if (time_stamp == null) {
+            try {
+                time_stamp = formater.parse(time_stamp + "00");
+            } catch (ParseException e) {
+                SQLExecutor.logger.log(Level.SEVERE, e.getMessage());
+            }
+        }
+        return time_stamp;
+    }
+}

+ 84 - 0
src/main/java/cz/hsrs/db/model/composite/RealSensor.java

@@ -0,0 +1,84 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.Phenomenon;
+
+/**
+ * Sensor generated by hbm2java
+ */
+public class RealSensor implements DBObject{
+
+	private long sensorId;
+	private String sensorName;
+	private String sensorType;
+	private Phenomenon phenomenon;
+	private final Date fromTime;
+	private final Date toTime;	
+	
+	public RealSensor(long sensorId, String sensorName, String sensorType,
+			Phenomenon phenomenon) {
+		super();
+		this.sensorId = sensorId;
+		this.sensorName = sensorName;
+		this.sensorType = sensorType;
+		this.phenomenon = phenomenon;
+		this.fromTime = null;
+		this.toTime = null;
+	}
+	
+	public RealSensor(long sensorId, String sensorName, String sensorType,
+			Phenomenon phenomenon, Date from, Date to) {
+		super();
+		this.sensorId = sensorId;
+		this.sensorName = sensorName;
+		this.sensorType = sensorType;
+		this.phenomenon = phenomenon;
+		this.fromTime = null;
+		this.toTime = null;
+	}
+	
+	public RealSensor(ResultSet set) throws SQLException{
+		super();		
+		this.sensorId = set.getLong("sensor_id");
+		this.sensorName = set.getString("sensor_name");
+		this.sensorType = set.getString("sensor_type");			
+		this.fromTime = set.getDate("fromTime");
+		this.toTime = set.getDate("toTime");
+	
+	}
+	
+	
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {	
+		return new RealSensor(set);
+	}
+
+	public long getSensorId() {
+		return sensorId;
+	}
+	public void setSensorId(long sensorId) {
+		this.sensorId = sensorId;
+	}
+	public String getSensorName() {
+		return sensorName;
+	}
+	public void setSensorName(String sensorName) {
+		this.sensorName = sensorName;
+	}
+	public String getSensorType() {
+		return sensorType;
+	}
+	public void setSensorType(String sensorType) {
+		this.sensorType = sensorType;
+	}
+	public Phenomenon getPhenomenon() {
+		return phenomenon;
+	}
+	public void setPhenomenon(Phenomenon phenomenon) {
+		this.phenomenon = phenomenon;
+	}
+}

+ 104 - 0
src/main/java/cz/hsrs/db/model/composite/RealUnit.java

@@ -0,0 +1,104 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.model.UnitDriver;
+import cz.hsrs.db.model.UnitHolder;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.custom.DBItemInfo;
+import cz.hsrs.db.util.UtilFactory;
+
+public class RealUnit implements DBObject{
+
+	private final Unit unit;
+	private final UnitPosition position ;
+	private final LastPosition lastpos;
+	private final List<UnitSensor> sensors;
+	private final UnitHolder holder;
+	private final List<UnitDriver> drivers;
+	
+	private final List<DBItemInfo> generalInfo;
+	
+	public RealUnit(){
+		unit = null;
+		sensors = null;
+		position = null;
+		holder = null;
+		lastpos = null;
+		generalInfo = null;
+		drivers = null;
+	}
+	
+	public RealUnit(ResultSet set) throws SQLException {
+		generalInfo = new ArrayList<DBItemInfo>();
+		
+		position = new UnitPosition(set);
+		UtilFactory fact = null;		
+		try {
+			fact = new UtilFactory();
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			//e.printStackTrace();
+		} 		
+		sensors = fact.sensorUtil.getUnitsSensors(position.getUnit_id());	
+		lastpos = fact.unitUtil.getLastPositionWithStatus(position);
+		UnitHolder h = null;
+		try {
+			h = fact.unitUtil.getUnitHolder(position.getUnit_id());
+		} catch (NoItemFoundException e) {
+			// TODO Auto-generated catch block
+			//e.printStackTrace();
+		}
+		holder = h;
+		
+		 try {
+			DBItemInfo info = new DBItemInfo("custom", "cars", position.getUnit_id(), "unit_id");
+			 generalInfo.add(info);
+		} catch (NoItemFoundException e) {
+			//ignore - leave infos empty
+		}
+		
+		drivers = fact.unitUtil.getUnitDrivers(position.getUnit_id());
+		unit = fact.unitUtil.getUnit(position.getUnit_id());
+	}
+
+
+	public LastPosition getLastpos() {
+		return lastpos;
+	}
+
+	private UnitPosition getPosition() {
+		return position;
+	}
+
+	public List<UnitSensor> getSensors() {
+		return sensors;
+	}
+
+	public UnitHolder getHolder() {
+		return holder;
+	}
+
+	public List<DBItemInfo> getGeneralInfo() {
+		return generalInfo;
+	}
+	@Override	
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new RealUnit(set);
+	}
+
+	public List<UnitDriver> getDrivers() {
+		return drivers;
+	}
+
+	public Unit getUnit(){
+		return unit;
+	}
+}

+ 38 - 0
src/main/java/cz/hsrs/db/model/composite/UnitObservation.java

@@ -0,0 +1,38 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.util.SensorUtil;
+
+public class UnitObservation implements DBObject {
+	
+	private final Unit unit;
+	private final UnitSensor sensor;
+	private final List<ObservationValue> values;
+	
+
+	private UnitObservation() {
+		super();
+		this.unit = null;
+		this.sensor = null;
+		this.values = null;
+	}
+
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		Unit unit = new Unit(0, 0,"");
+		UnitSensor sens = new UnitSensor();
+		SensorUtil util = new SensorUtil();
+		util.getSensorObservations(unit.getUnitId(), sens.getSensorId());
+		
+		//unit.get
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}

+ 122 - 0
src/main/java/cz/hsrs/db/model/composite/UnitSensor.java

@@ -0,0 +1,122 @@
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.Phenomenon;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.SensorUtil;
+
+/**
+ * Sensor generated by hbm2java
+ */
+public class UnitSensor implements DBObject{
+
+	private long sensorId;
+	private String sensorName;
+	private String sensorType;
+	private Phenomenon phenomenon;
+	
+	private String firstObservationTime;
+	private String lastObservationTime;
+	
+	
+	public UnitSensor(long sensorId, String sensorName, String sensorType,
+			Phenomenon phenomenon, long unitId) throws SQLException {
+		super();
+		this.sensorId = sensorId;
+		this.sensorName = sensorName;
+		this.sensorType = sensorType;
+		this.phenomenon = phenomenon;
+		this.firstObservationTime = findFirstObservationTimeDB(unitId, sensorId);
+		this.lastObservationTime = findLastObservationTimeDB(unitId, sensorId);
+	}
+	
+	public UnitSensor(ResultSet set) throws SQLException{
+		
+		this.sensorId = set.getLong("sensor_id");
+		this.sensorName = set.getString("sensor_name");
+		this.sensorType = set.getString("sensor_type");	
+		this.firstObservationTime = findFirstObservationTimeDB(set.getLong("unit_id"),sensorId);		
+		this.lastObservationTime = findLastObservationTimeDB(set.getLong("unit_id"),sensorId);
+		SensorUtil sUtil = new SensorUtil();		
+		this.phenomenon = sUtil.getPhenomenonById(set.getString("phenomenon_id"));		
+	}
+	
+	public UnitSensor() throws SQLException{
+		
+	}	
+	
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {	
+		return new UnitSensor(set);
+	}
+
+	public long getSensorId() {
+		return sensorId;
+	}
+	public void setSensorId(long sensorId) {
+		this.sensorId = sensorId;
+	}
+	public String getSensorName() {
+		return sensorName;
+	}
+	public void setSensorName(String sensorName) {
+		this.sensorName = sensorName;
+	}
+	public String getSensorType() {
+		return sensorType;
+	}
+	public void setSensorType(String sensorType) {
+		this.sensorType = sensorType;
+	}
+	public Phenomenon getPhenomenon() {
+		return phenomenon;
+	}
+	public void setPhenomenon(Phenomenon phenomenon) {
+		this.phenomenon = phenomenon;
+	}
+	public String getFirstObservationTime() {
+		return firstObservationTime;
+	}
+	public String getLastObservationTime() {
+		return lastObservationTime;
+	}
+
+	private String findFirstObservationTimeDB(long unitId, long sensorId) throws SQLException{
+		String query = "SELECT first_obs FROM units_to_sensors WHERE unit_id = "+unitId+" AND sensor_id = "+sensorId+";";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+		if(res.next() == true){
+			String time = res.getString(1);
+			boolean wasNull = res.wasNull();
+			if (wasNull == false){
+				return time;
+			}
+			else{
+				return "unknown";
+			}
+		}
+		else{
+			return "unknown";
+		}		
+	}
+	
+	private String findLastObservationTimeDB(long unitId, long sensorId) throws SQLException{
+		String query = "SELECT last_obs FROM units_to_sensors WHERE unit_id = "+unitId+" AND sensor_id = "+sensorId+";";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+		if(res.next() == true){
+			String time = res.getString(1);
+			boolean wasNull = res.wasNull();
+			if (wasNull == false){
+				return time;
+			}
+			else{
+				return "unknown";
+			}
+		}
+		else{
+			return "unknown";
+		}			
+	}	
+}

+ 128 - 0
src/main/java/cz/hsrs/db/model/composite/UnitSensorObservation.java

@@ -0,0 +1,128 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.composite;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.logging.Level;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * @author mkepka
+ *
+ */
+public class UnitSensorObservation implements DBObject{
+
+    private long sensorId;
+    private String timeStamp;
+    private Date time_stamp;
+    private int gid;
+    private long unitId;
+    private Double observedValue;
+    
+    private final SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+    
+    /**
+     * Empty constructor
+     */
+    public UnitSensorObservation(){
+    }
+    
+    /**
+     * Constructor for generating object from ResultSet 
+     */
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        return new UnitSensorObservation(set);
+    }
+    
+    /**
+     * Constructor creates object with attributes
+     * @param timeStamp - time stamp when observation was measured
+     * @param observedValue - observed value, can be NaN
+     * @param sensor_id - id of sensor
+     * @param unit_id - id of unit
+     */
+    public UnitSensorObservation(String timeStamp, Double observedValue, long sensor_id, long unit_id) {
+        this.sensorId = sensor_id;
+        this.timeStamp = timeStamp;
+        this.unitId = unit_id;
+        this.observedValue = observedValue;
+    }
+    
+    /**
+     * Constructor creates object from ResultSet
+     * @param set ResultSet with all mandatory attributes
+     * @throws SQLException
+     */
+    public UnitSensorObservation(ResultSet set) throws SQLException {
+        this.sensorId = set.getLong("sensor_id");
+        this.timeStamp = set.getString("time_stamp");
+        try {
+            this.time_stamp =  formater.parse(timeStamp+"00");
+        } catch (ParseException e) {
+            SQLExecutor.logger.log(Level.SEVERE, e.getMessage());
+        }
+        this.unitId = set.getLong("unit_id");
+        this.observedValue = set.getDouble("observed_value");
+        this.gid = set.getInt("gid");
+    }
+
+    /**
+     * @return the sensorId
+     */
+    public long getSensorId() {
+        return sensorId;
+    }
+
+    /**
+     * @return the timeStamp
+     */
+    public String getTimeStamp() {
+        return timeStamp;
+    }
+
+    /**
+     * @return the time_stamp as Date
+     */
+    public Date internalGetTime_stamp() {
+        return time_stamp;
+    }
+
+    /**
+     * @return the gid
+     */
+    public int getGid() {
+        return gid;
+    }
+
+    /**
+     * @return the unitId
+     */
+    public long getUnitId() {
+        return unitId;
+    }
+
+    /**
+     * @return the observedValue
+     */
+    public Double getObservedValue() {
+        return observedValue;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "UnitSensorObservation [sensorId=" + sensorId + ", timeStamp="
+                + timeStamp + ", gid=" + gid + ", unitId=" + unitId
+                + ", observedValue=" + observedValue + "]";
+    }
+}

+ 62 - 0
src/main/java/cz/hsrs/db/model/custom/DBItemInfo.java

@@ -0,0 +1,62 @@
+package cz.hsrs.db.model.custom;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class DBItemInfo implements DBObject {
+
+	private final Map<String, Object> properties;
+
+	private final Map<String, Long> fk;
+
+	public DBItemInfo() {
+		properties = null;
+		fk = null;
+	}
+	public DBItemInfo(String schema, String tableName, long id,
+			String forigenKeyName) throws NoItemFoundException{
+		properties = new HashMap<String, Object>();
+		fk = new HashMap<String, Long>();
+		try {
+			
+			String query = "SELECT * FROM " + schema + "." + tableName
+					+ " WHERE " + forigenKeyName + " = " + id;
+			ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+			if (res.next()) {
+				fk.put(forigenKeyName, id);
+			} else {
+				throw new NoItemFoundException("Can not find item for "+ query);
+			}
+			int count = res.getMetaData().getColumnCount();
+
+			for (int i = 1; i < count; i++) {
+				properties.put(res.getMetaData().getColumnName(i), res
+						.getObject(res.getMetaData().getColumnName(i)));
+			}
+		} catch (SQLException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+
+	/*public Map<String, Long> getFk() {
+		return new HashMap<String, Long>(fk);
+	}*/
+
+	public Map<String, Object> getProperties() {
+		return new HashMap<String, Object>(properties);
+	}
+
+	@Override
+	public DBObject getDBObject(ResultSet set) throws SQLException {
+		// TODO Auto-generated method stub
+		return new DBItemInfo();
+	}
+
+}

+ 85 - 0
src/main/java/cz/hsrs/db/model/custom/UnitPositionSimple.java

@@ -0,0 +1,85 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.custom;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import cz.hsrs.db.DBObject;
+
+/**
+ * Class for modeling simple unit_position
+ * @author mkepka
+ *
+ */
+public class UnitPositionSimple implements DBObject {
+
+    private final String time_stamp;
+    private final double x;
+    private final double y;
+    
+    /**
+     * Empty constructor for generating JSON 
+     */
+    public UnitPositionSimple(){
+        this.time_stamp = null;
+        this.x = Double.NaN;
+        this.y = Double.NaN;
+    }
+    
+    public UnitPositionSimple(ResultSet set) throws SQLException {
+        this.time_stamp = set.getString("time_stamp");
+        this.x = set.getDouble("st_x");
+        this.y = set.getDouble("st_y");
+    }
+    /**
+     * @param time_string
+     * @param x
+     * @param y
+     */
+    public UnitPositionSimple(String time_string, double x, double y) {
+        this.time_stamp = time_string;
+        this.x = x;
+        this.y = y;
+    }
+
+    /* (non-Javadoc)
+     * @see cz.hsrs.db.DBObject#getDBObject(java.sql.ResultSet)
+     */
+    @Override
+    public DBObject getDBObject(ResultSet set) throws SQLException {
+        return new UnitPositionSimple(set);
+    }
+
+    /**
+     * @return the time_string
+     */
+    public String getTime_stamp() {
+        return time_stamp;
+    }
+
+    /**
+     * @return the x
+     */
+    public double getX() {
+        return x;
+    }
+
+    /**
+     * @return the y
+     */
+    public double getY() {
+        return y;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "UnitPositionSimple [time_string=" + time_stamp + ", x=" + x
+                + ", y=" + y + "]";
+    }
+}

+ 133 - 0
src/main/java/cz/hsrs/db/model/insert/UnitInsert.java

@@ -0,0 +1,133 @@
+package cz.hsrs.db.model.insert;
+
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Sensor;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.util.UnitUtil;
+
+public class UnitInsert {
+    private Long unitId;
+    private String description;
+    private List<Sensor> sensors;
+    
+    /**
+     * Constructor creates object from attributes
+     * mainly used to insert new unit into DB
+     * @param description
+     * @param sensors
+     */
+    public UnitInsert(String description, List<Sensor> sensors) {
+        this.unitId = null;
+        this.description = description;
+        this.sensors = sensors;
+    }
+    
+    /**
+     * Constructor creates object from all attributes
+     * 
+     * @param description
+     * @param sensors
+     */
+    public UnitInsert(Long unitId, String description, List<Sensor> sensors) {
+        this.setUnitId(unitId);
+        this.description = description;
+        this.sensors = sensors;
+    }
+
+    public Long getUnitId() {
+        return unitId;
+    }
+
+    public void setUnitId(Long unitId) {
+        this.unitId = unitId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public List<Sensor> getSensors() {
+        return sensors;
+    }
+    
+    @Override
+    public String toString() {
+        return "[unitId=" + unitId + ", description=" + description
+                + ", sensors=" + sensors + "]";
+    }
+    
+    /**
+     * Method creates JSONObject representing Unit object
+     * @return
+     */
+    public JSONObject toJSON(){
+        JSONObject unit = new JSONObject();
+        unit.element("unit_id", this.unitId);
+        unit.element("description", this.description);
+        JSONArray sensArr = new JSONArray();
+        for(int i = 0; i<this.sensors.size(); i++){
+            sensArr.add(this.sensors.get(i));
+        }
+        unit.element("sensors", sensArr);
+        return unit;
+    }
+
+    /**
+     * Method inserts new unit to the DB
+     * @param groupId - id of group to be paired with
+     * @return UnitInsert object that were inserted in DB
+     * @throws SQLException
+     * @throws NoItemFoundException 
+     */
+    public UnitInsert insertUnitToDB(int groupId) throws SQLException, NoItemFoundException{
+        UnitUtil uUtil = new UnitUtil();
+        Unit unitDB = null;
+        Unit unitDBinG = null;
+        if(this.unitId == null){
+            this.unitId = uUtil.getNextUnitID();
+        }
+        /** check if there is same unit already in DB */
+        else{
+            unitDB = uUtil.getUnit(this.unitId);
+            unitDBinG = uUtil.getUnitByGroup(this.unitId, groupId);
+        }
+        /** there is not same unit in DB */
+        if(unitDBinG == null && unitDB == null){
+            uUtil.insertUnit(this.unitId, this.description);
+            uUtil.pairUnitToGroup(this.unitId, groupId);
+            
+            List<Sensor> insSensors = new LinkedList<Sensor>();
+            for(int s = 0; s < this.sensors.size(); s++){
+                Sensor insSen = sensors.get(s).insertToDb(this.unitId);
+                insSensors.add(insSen);
+            }
+            this.sensors = insSensors;
+            return this;
+        /** there is same unit in DB but not paired with this user */
+        } else if(unitDBinG == null && unitDB != null){
+            uUtil.pairUnitToGroup(this.unitId, groupId);
+            List<Sensor> insSensors = new LinkedList<Sensor>();
+            for(int s = 0; s < this.sensors.size(); s++){
+                Sensor insSen = sensors.get(s).insertToDb(this.unitId);
+                insSensors.add(insSen);
+            }
+            this.sensors = insSensors;
+            return this;
+        /** there is same unit in DB and it is paired to this user */     
+        } else{
+            List<Sensor> insSensors = new LinkedList<Sensor>();        
+            for(int s = 0; s < this.sensors.size(); s++){
+                Sensor insSen = sensors.get(s).insertToDb(this.unitId);
+                insSensors.add(insSen);
+            }
+            this.sensors = insSensors;
+            return this;
+        }
+    }
+}

+ 113 - 0
src/main/java/cz/hsrs/db/model/vgi/Envelope2D.java

@@ -0,0 +1,113 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.vgi;
+
+import java.text.ParseException;
+
+/**
+ * Class representing spatial Envelope of features
+ * to be selected
+ * @author mkepka
+ *
+ */
+public class Envelope2D {
+    private double xMin;
+    private double yMin;
+    private double xMax;
+    private double yMax;
+    private int SRID;
+    
+    /**
+     * Empty constructor for serialization
+     */
+    public Envelope2D(){
+    }
+    
+    /**
+     * @param xMin
+     * @param yMin
+     * @param xMax
+     * @param yMax
+     * @param sRID
+     */
+    public Envelope2D(double xMin, double yMin, double xMax, double yMax,
+            int sRID) {
+        this.xMin = xMin;
+        this.yMin = yMin;
+        this.xMax = xMax;
+        this.yMax = yMax;
+        SRID = sRID;
+    }
+
+    /**
+     * Constructor for parsing of array of coordinates from OpenLayers
+     * Correct format: [xmin, ymin, xmax, ymax, SRID]
+     * @param extentArray - extent of MapWindow in format
+     * @throws ParseException 
+     */
+    public Envelope2D(String extentArray) throws ParseException{
+        if(extentArray.contains("[") && extentArray.contains("]")){
+            String arr = extentArray.replace("[", ""); 
+            arr = arr.replace("]", "");
+            String[] parsed = arr.split(",");
+            if(parsed.length == 5){
+                this.xMin = Double.parseDouble(parsed[0]); 
+                this.yMin = Double.parseDouble(parsed[1]);
+                this.xMax = Double.parseDouble(parsed[2]);
+                this.yMax = Double.parseDouble(parsed[3]);
+                this.SRID = Integer.parseInt(parsed[4]);
+            }
+            else{
+                throw new ParseException("Extent does not contain correct number of coordinates!", 1);
+            }
+        }
+        else{
+            throw new ParseException("Extent string is not in correct format!", 1);
+        }
+    }
+
+    /**
+     * @return the xMin
+     */
+    public double getXMin() {
+        return xMin;
+    }
+
+    /**
+     * @return the yMin
+     */
+    public double getYMin() {
+        return yMin;
+    }
+
+    /**
+     * @return the xMax
+     */
+    public double getXMax() {
+        return xMax;
+    }
+
+    /**
+     * @return the yMax
+     */
+    public double getYMax() {
+        return yMax;
+    }
+
+    /**
+     * @return the sRID
+     */
+    public int getSRID() {
+        return SRID;
+    }
+    
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Envelope2D [xMin=" + xMin + ", yMin=" + yMin + ", xMax=" + xMax
+                + ", yMax=" + yMax + ", SRID=" + SRID + "]";
+    }
+}

+ 129 - 0
src/main/java/cz/hsrs/db/model/vgi/VgiCategory.java

@@ -0,0 +1,129 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.vgi;
+
+import cz.hsrs.db.vgi.util.VgiParams;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Class represents VgiCategory object
+ * creates characterization and hierarchy of VgiObservation
+ * @author mkepka
+ *
+ */
+@XmlRootElement
+public class VgiCategory {
+
+    @XmlElement(name = VgiParams.CATEGORY_ID_NAME)
+    private int categoryId;
+    @XmlElement(name = VgiParams.CATEGORY_NAME_NAME)
+    private String categoryName;
+    private String description;
+    @XmlElement(name = "parent_id")
+    private Integer parentId; // top-level categories has NULL
+    private Integer level;
+    private Integer lft;
+    private Integer rgt;
+    
+    /**
+     * Empty constructor
+     */
+    public VgiCategory(){
+    }
+    
+    /**
+     * Constructor creates instance from fields, for selecting from DB
+     * @param categoryId - ID of VgiCategory, mandatory
+     * @param categoryName - name of VgiCategory, optional
+     * @param description - description of VgiCategory, optional
+     * @param parentId - ID of parent VgiCategory, top-level VgiCategory has NULL parent
+     * @param level - ID of level of VgiCategory, can be NULL, top-level has 0
+     * @param lft - left value of preoder tree traversal, can be NULL
+     * @param rgt - right value of preoder tree traversal, can be NULL
+     */
+    public VgiCategory(int categoryId, String categoryName, String description,
+    		Integer parentId, Integer level, Integer lft, Integer rgt) {
+        this.categoryId = categoryId;
+        this.categoryName = categoryName;
+        this.description = description;
+        this.parentId = parentId;
+        this.level = level;
+        this.lft = lft;
+        this.rgt = rgt;
+    }
+
+    /**
+     * Constructor for insert new Category by user
+     * @param categoryName - name of VgiCategory, optional
+     * @param description - description of VgiCategory, optional
+     * @param parentId - ID of parent VgiCategory, top-level VgiCategory has NULL parent
+     */
+    public VgiCategory(String categoryName, String description, Integer parentId) {
+        this.categoryName = categoryName;
+        this.description = description;
+        this.parentId = parentId;
+    }
+
+    /**
+     * @return the categoryId
+     */
+    public int getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * @return the categoryName
+     */
+    public String getCategoryName() {
+        return categoryName;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return the parentId
+     */
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    /**
+     * @return the level
+     */
+    public Integer getLevel() {
+        return level;
+    }
+
+    /**
+     * @return the lft
+     */
+    public Integer internalGetLft() {
+        return lft;
+    }
+
+    /**
+     * @return the rgt
+     */
+    public Integer internalGetRgt() {
+        return rgt;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "CategoryVgi [category_id=" + categoryId + ", category_name="
+                + categoryName + ", description=" + description + ", parent_id="
+                + parentId + ", level=" + level + ", lft=" + lft + ", rgt="
+                + rgt + "]";
+    }
+}

+ 135 - 0
src/main/java/cz/hsrs/db/model/vgi/VgiDataset.java

@@ -0,0 +1,135 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.vgi;
+
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.vgi.util.VgiParams;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Class represents VgiDataset object
+ * representing group of VgiObservations 
+ * @author mkepka
+ *
+ */
+@XmlRootElement
+public class VgiDataset {
+
+    @XmlElement (name = VgiParams.DATASET_ID_NAME)
+    private int datasetId;
+    @XmlElement (name = VgiParams.DATASET_NAME_NAME)
+    private String datasetName;
+    private String description;
+    @XmlElement (name = VgiParams.USER_ID_NAME)
+    private int userId;
+    
+    /**
+     * Empty constructor
+     */
+    public VgiDataset(){
+    }
+    
+    /**
+     * @param datasetId
+     * @param datasetName
+     * @param description
+     * @param user_id
+     */
+    public VgiDataset(int datasetId, String datasetName, String description, int user_id) {
+        this.datasetId = datasetId;
+        this.datasetName = datasetName;
+        this.description = description;
+        this.userId = user_id;
+    }
+
+    /**
+     * @param datasetName
+     * @param description
+     * @param user_id
+     */
+    public VgiDataset(String datasetName, String description, int user_id) {
+        this.datasetName = datasetName;
+        this.description = description;
+        this.userId = user_id;
+    }
+
+    /**
+     * @param datasetId
+     * @param datasetName
+     * @param description
+     */
+    public VgiDataset(int datasetId, String datasetName, String description) {
+        this.datasetId = datasetId;
+        this.datasetName = datasetName;
+        this.description = description;
+    }
+
+    /**
+     * @return the datasetId
+     */
+    public int getDatasetId() {
+        return datasetId;
+    }
+
+    /**
+     * @return the datasetName
+     */
+    public String getDatasetName() {
+        return datasetName;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return the user_id
+     */
+    public int internalGetUser_id() {
+        return userId;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "VgiDataset [dataset_id=" + datasetId + ", dataset_name="
+                + datasetName + ", description=" + description + ", user_id="
+                + userId + "]";
+    }
+    
+    /**
+     * Method inserts new Dataset to the DB
+     * @return ID of the given dataset 
+     * @throws SQLException
+     */
+    public int insertToDB() throws SQLException{
+        try{
+            String newIdQuery = "SELECT nextval('vgi.vgi_datasets_dataset_id_seq'::regclass);";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(newIdQuery);
+            int newId = 0;
+            if(res.next()){
+                newId = res.getInt(1);
+            }
+            String ins = "INSERT INTO vgi.vgi_datasets(dataset_id, dataset_name, description, user_id)"
+                    + " VALUES ("+newId+", '"
+                    +this.datasetName+"', '"
+                    +this.description+"', "
+                    +this.userId+");";
+            SQLExecutor.executeUpdate(ins);
+            return newId;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+        
+    }
+}

+ 183 - 0
src/main/java/cz/hsrs/db/model/vgi/VgiMedia.java

@@ -0,0 +1,183 @@
+package cz.hsrs.db.model.vgi;
+
+import cz.hsrs.db.util.DateUtil;
+import cz.hsrs.db.vgi.util.VgiParams;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.text.ParseException;
+import java.util.Date;
+
+/**
+ * Class represents VgiMedia object
+ * containing connected media file to the VgiObservation
+ * @author mkepka
+ *
+ */
+@XmlRootElement
+public class VgiMedia {
+
+    @XmlElement(name = VgiParams.MEDIA_ID_NAME)
+    private int mediaId;
+    @XmlElement(name = VgiParams.OBS_VGI_ID_NAME)
+    private int obsId;
+    @XmlElement(name = VgiParams.TIME_RECEIVED_NAME)
+    private String timeReceivedString;
+    private Date timeReceived;
+    @XmlElement(name = VgiParams.OBSERVED_MEDIA_NAME)
+    private byte[] observedMedia;
+    private byte[] thumbnail;
+    private String datatype;
+    
+    /**
+     * Empty constructor
+     */
+    public VgiMedia(){
+    }
+    
+    /**
+     * Constructor for selecting only media file from DB
+     * @param mediaId
+     * @param obsId
+     * @param timeReceivedString
+     * @param observedMedia
+     * @param mediaDatatype
+     */
+    public VgiMedia(int mediaId, int obsId, String timeReceivedString,
+            byte[] observedMedia, String mediaDatatype) {
+        this.mediaId = mediaId;
+        this.obsId = obsId;
+        this.timeReceivedString = timeReceivedString;
+        this.observedMedia = observedMedia;
+        this.datatype = mediaDatatype;
+        try {
+            this.timeReceived = DateUtil.parseTimestampMicro(timeReceivedString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * Constructor for selecting only thumbnail of media file from DB
+     * @param mediaId
+     * @param obsId
+     * @param timeReceivedString
+     * @param mediaDatatype
+     * @param thumbnail
+     */
+    public VgiMedia(int mediaId, int obsId, String timeReceivedString, String mediaDatatype,
+            byte[] thumbnail) {
+        this.mediaId = mediaId;
+        this.obsId = obsId;
+        this.timeReceivedString = timeReceivedString;
+        this.thumbnail = thumbnail;
+        this.datatype = mediaDatatype;
+        try {
+            this.timeReceived = DateUtil.parseTimestampMicro(timeReceivedString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * Constructor for complete object selected form DB
+     * @param mediaId
+     * @param obsId
+     * @param timeReceivedString
+     * @param observedMedia
+     * @param mediaDatatype
+     */
+    public VgiMedia(int mediaId, int obsId, String timeReceivedString,
+            byte[] observedMedia, byte[] thumbnail, String mediaDatatype) {
+        this.mediaId = mediaId;
+        this.obsId = obsId;
+        this.timeReceivedString = timeReceivedString;
+        this.observedMedia = observedMedia;
+        this.thumbnail = thumbnail;
+        this.datatype = mediaDatatype;
+        try {
+            this.timeReceived = DateUtil.parseTimestampMicro(timeReceivedString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Constructor for Media file metadata
+     * @param mediaId - ID of VgiMedia
+     * @param obsId - ID of master VgiObservation
+     * @param timeReceivedString - time stamp when media was received to the DB
+     * @param mediaDatatype - data type of media file
+     */
+    public VgiMedia(int mediaId, int obsId, String timeReceivedString, String mediaDatatype) {
+        this.mediaId = mediaId;
+        this.obsId = obsId;
+        this.timeReceivedString = timeReceivedString;
+        this.datatype = mediaDatatype;
+        try {
+            this.timeReceived = DateUtil.parseTimestampMicro(timeReceivedString);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    /**
+     * @return the mediaId
+     */
+    public int getMediaId() {
+        return mediaId;
+    }
+
+    /**
+     * @return the obsId
+     */
+    public int getObsId() {
+        return obsId;
+    }
+
+    /**
+     * @return the timeReceivedString
+     */
+    public String getTimeReceivedString() {
+        return timeReceivedString;
+    }
+
+    /**
+     * 
+     * @return
+     */
+    public Long internalGetTimeReceivedMilis(){
+        return this.timeReceived.getTime();
+    }
+    
+    /**
+     * @return the observedMedia
+     */
+    public byte[] getObservedMedia() {
+        return observedMedia;
+    }
+    
+    /**
+     * @return the thumbnail
+     */
+    public byte[] getThumbnail() {
+        return thumbnail;
+    }
+
+    /**
+     * @return the mediaDatatype
+     */
+    public String getMediaDatatype() {
+        return datatype;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "VgiMedia [mediaId=" + mediaId + ", obsId=" + obsId
+                + ", timeReceivedString=" + timeReceivedString
+                + ", mediaDatatype=" + datatype + "]";
+    }
+}

+ 301 - 0
src/main/java/cz/hsrs/db/model/vgi/VgiObservation.java

@@ -0,0 +1,301 @@
+/**
+ * 
+ */
+package cz.hsrs.db.model.vgi;
+
+import cz.hsrs.db.vgi.util.VgiParams;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @author mkepka
+ *
+ */
+@XmlRootElement
+public class VgiObservation {
+
+    @XmlElement(name = VgiParams.OBS_VGI_ID_NAME)
+    private int obsVgiId;
+    private Integer gid;
+    private Double x;
+    private Double y;
+    private Double altitude;
+    private Double dop;
+    @XmlElement(name = VgiParams.TIMESTAMP_NAME)
+    private String timeString;
+    @XmlElement(name = VgiParams.CATEGORY_ID_NAME)
+    private int categoryId;
+    private String description;
+    private String attributes;
+    @XmlElement(name = VgiParams.DATASET_ID_NAME)
+    private int datasetId;
+    @XmlElement(name = VgiParams.UNIT_ID_NAME)
+    private long unitId;
+    @XmlElement(name = VgiParams.USER_ID_NAME)
+    private int userId;
+    @XmlElement(name = VgiParams.TIME_RECEIVED_NAME)
+    private String timeReceived;
+    @XmlElement(name = VgiParams.MEDIA_COUNT_NAME)
+    private int mediaCount;
+    @XmlElement(name = VgiParams.MEDIA_ID_NAME)
+    private int medId;
+    
+    /**
+     * Prepared list of attributes to be select from DB in following order:
+     * ov.obs_vgi_id
+     * ov.gid
+     * ov.time_stamp
+     * ov.category_id
+     * ov.description
+     * ov.attributes
+     * ov.dataset_id
+     * ov.unit_id
+     * ov.user_id
+     * ov.time_received
+     * ov.media_count
+     * st_x(up.the_geom)
+     * st_y(up.the_geom)
+     * up.altitude
+     * up.dop
+     */
+    public static final String SELECT_ATTRIBUTES = "SELECT ov.obs_vgi_id, ov.gid, ov.time_stamp,"
+            + " ov.category_id, ov.description, ov.attributes, ov.dataset_id, ov.unit_id, ov.user_id,"
+            + " ov.time_received, ov.media_count, st_x(up.the_geom), st_y(up.the_geom), up.altitude, up.dop";
+    /**
+     * Prepared list of attributes to be select from DB for GeoJSON in following order:
+     * ov.obs_vgi_id
+     * ov.gid
+     * ov.time_stamp
+     * ov.category_id
+     * ov.description
+     * ov.attributes
+     * ov.dataset_id
+     * ov.unit_id
+     * ov.user_id
+     * ov.time_received
+     * ov.media_count
+     * st_asgeojson(up.the_geom, 10)
+     * up.altitude
+     * up.dop
+     */
+    public static final String SELECT_ATTRIBUTES_GEOJSON = "SELECT ov.obs_vgi_id, ov.gid, ov.time_stamp,"
+            + " ov.category_id, ov.description, ov.attributes, ov.dataset_id, ov.unit_id, ov.user_id,"
+            + " ov.time_received, ov.media_count, st_asgeojson(up.the_geom, 10), up.altitude, up.dop";
+    
+    /**
+     * Empty constructor for serialization
+     */
+    public VgiObservation(){
+    }
+    
+    /**
+     * Short constructor for inserting new VgiObservation
+     * @param obsVgiId - ID of VgiObservation object
+     * @param medId - ID of VgiMedia object that was inserted together with VgiObservation
+     */
+    public VgiObservation(int obsVgiId, int medId){
+    	this.obsVgiId = obsVgiId;
+    	this.medId = medId;
+    }
+    
+    /**
+     * Constructor creates object from given fields 
+     * @param obsVgiId
+     * @param gid
+     * @param timeString
+     * @param categoryId
+     * @param description
+     * @param attributes
+     * @param datasetId
+     * @param unitId
+     * @param userId
+     * @param timeReceived
+     * @param mediaCount
+     */
+    public VgiObservation(int obsVgiId, Integer gid, String timeString,
+            int categoryId, String description, String attributes,
+            int datasetId, long unitId, int userId, String timeReceived,
+            int mediaCount) {
+        this.obsVgiId = obsVgiId;
+        this.gid = gid;
+        this.timeString = timeString;
+        this.categoryId = categoryId;
+        this.description = description;
+        this.attributes = attributes;
+        this.datasetId = datasetId;
+        this.unitId = unitId;
+        this.userId = userId;
+        this.timeReceived = timeReceived;
+        this.mediaCount = mediaCount;
+    }
+
+    /**
+     * Constructor creates object from given fields
+     * @param obsVgiId
+     * @param gid
+     * @param timeString
+     * @param categoryId
+     * @param description
+     * @param attributes
+     * @param datasetId
+     * @param unitId
+     * @param userId
+     * @param timeReceived
+     * @param mediaCount
+     * @param xCoord
+     * @param yCoord
+     * @param altitude
+     * @param dop
+     */
+    public VgiObservation(int obsVgiId, Integer gid, String timeString,
+            int categoryId, String description, String attributes,
+            int datasetId, long unitId, int userId, String timeReceived,
+            int mediaCount, double xCoord, double yCoord, double altCoord, 
+            double dop) {
+        this.obsVgiId = obsVgiId;
+        this.gid = gid;
+        this.timeString = timeString;
+        this.categoryId = categoryId;
+        this.description = description;
+        this.attributes = attributes;
+        this.datasetId = datasetId;
+        this.unitId = unitId;
+        this.userId = userId;
+        this.timeReceived = timeReceived;
+        this.mediaCount = mediaCount;
+        this.x = xCoord;
+        this.y = yCoord;
+        this.altitude = altCoord;
+        this.dop = dop;
+    }
+    
+    /**
+     * @return the obsVgiId
+     */
+    public int getObsVgiId() {
+        return obsVgiId;
+    }
+
+    /**
+     * @return the gid
+     */
+    public Integer getGid() {
+        return gid;
+    }
+
+    /**
+     * @return the timeString
+     */
+    public String getTimeString() {
+        return timeString;
+    }
+
+    /**
+     * @return the categoryId
+     */
+    public int getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return the attributes
+     */
+    public String getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * @return the datasetId
+     */
+    public int getDatasetId() {
+        return datasetId;
+    }
+
+    /**
+     * @return the unitId
+     */
+    public long getUnitId() {
+        return unitId;
+    }
+
+    /**
+     * @return the userId
+     */
+    public int getUserId() {
+        return userId;
+    }
+
+    /**
+     * @return the timeReceived
+     */
+    public String getTimeReceived() {
+        return timeReceived;
+    }
+
+    /**
+     * @return the mediaCount
+     */
+    public int getMediaCount() {
+        return mediaCount;
+    }
+    
+    /**
+     * @return the mediaCount
+     */
+    public int getMedId() {
+        return medId;
+    }
+    
+    /**
+     * 
+     * @return
+     */
+    public Double getX(){
+        return this.x;
+    }
+
+    /**
+     * 
+     * @return
+     */
+    public Double getY(){
+        return this.y;
+    }
+    
+    /**
+     * 
+     * @return
+     */
+    public Double getAltitude(){
+        return this.altitude;
+    }
+    
+    /**
+     * 
+     * @return
+     */
+    public Double getDOP(){
+        return this.dop;
+    }
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "VgiObservation [obs_vgi_id=" + obsVgiId + ", gid=" + gid
+                + ", time_string=" + timeString + ", category_id=" + categoryId
+                + ", description=" + description + ", attributes=" + attributes
+                + ", dataset_id=" + datasetId + ", unit_id=" + unitId
+                + ", user_id=" + userId + ", time_received=" + timeReceived
+                + ", media_count=" + mediaCount + ", x="+x+", y="+y
+                + ", altitude="+altitude+", dop="+dop+"]";
+    }
+}

+ 130 - 0
src/main/java/cz/hsrs/db/model/vgi/VgiObservationRdf.java

@@ -0,0 +1,130 @@
+package cz.hsrs.db.model.vgi;
+
+/**
+ * Model class representing VgiObservation for export to RDF format
+ * @author mkepka
+ *
+ */
+public class VgiObservationRdf {
+
+    private int obsVgiId;
+    private String dateString;
+    private int categoryId;
+    private String description;
+    private String name;
+    private int datasetId;
+    private long unitId;
+    private int userId;
+    private int mediaCount;
+    private String geom;
+    
+    /**
+     * @param obsVgiId
+     * @param dateString
+     * @param categoryId
+     * @param description
+     * @param name
+     * @param datasetId
+     * @param unitId
+     * @param userId
+     * @param mediaCount
+     */
+    public VgiObservationRdf(int obsVgiId, String dateString, int categoryId,
+            String description, String name, int datasetId, long unitId,
+            int userId, int mediaCount, String geomString) {
+        this.obsVgiId = obsVgiId;
+        this.dateString = dateString;
+        this.categoryId = categoryId;
+        this.description = description;
+        this.name = name;
+        this.datasetId = datasetId;
+        this.unitId = unitId;
+        this.userId = userId;
+        this.mediaCount = mediaCount;
+        this.geom = geomString;
+    }
+
+    /**
+     * @return the obsVgiId
+     */
+    public int getObsVgiId() {
+        return obsVgiId;
+    }
+
+    /**
+     * @return the dateString
+     */
+    public String getDateString() {
+        return dateString;
+    }
+
+    /**
+     * @return the categoryId
+     */
+    public int getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the datasetId
+     */
+    public int getDatasetId() {
+        return datasetId;
+    }
+
+    /**
+     * @return the unitId
+     */
+    public long getUnitId() {
+        return unitId;
+    }
+
+    /**
+     * @return the userId
+     */
+    public int getUserId() {
+        return userId;
+    }
+
+    /**
+     * @return the mediaCount
+     */
+    public int getMediaCount() {
+        return mediaCount;
+    }
+    
+    public String getGeom(){
+    	return geom;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "{\"obs_vgi_id\":"+obsVgiId+", "
+                + "\"date\":\""+dateString+"\", "
+                + "\"category_id\":"+categoryId+", "
+                + "\"description\":\""+description+"\", "
+                + "\"name\":"+name+"\", "
+                + "\"dataset_id\":"+datasetId+", "
+                + "\"unit_id\":"+unitId+", "
+                + "\"user_id\":"+userId+", "
+                + "\"media_count\":"+mediaCount+", "
+                + "\"geometry\":\""+geom+"\"}";
+    }
+}

+ 193 - 0
src/main/java/cz/hsrs/db/pool/ConnectionPool.java

@@ -0,0 +1,193 @@
+package cz.hsrs.db.pool;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Implementation of Connection pool.
+ *
+ * @author jezekjan
+ *
+ */
+class ConnectionPool implements ConnectionPoolMBean {
+
+	private final static List<PooledConnection> connections = new CopyOnWriteArrayList<PooledConnection>();
+
+	private final String url;
+	private final String user;
+	private final String password;
+
+	public static final String LOGGER_ID = "database_logger";
+
+	protected static Logger logger = Logger.getLogger(LOGGER_ID);
+
+	/* Time to close unused connection (if the pool has bigger size then minpoolsize) */
+	private long timeout = 5000;
+
+	/* maximal pool size (Default 8) */
+	private int maxpoolsize = 8;
+
+	/* time to wait if the pool is full and all connections are busy (Default 20) */
+	private int waittime = 20;
+
+	/* Minimal number of opened connections in the pool. These are still open even if they are not busy. (Default 3) */
+	private int minpoolsize = 3;
+
+	private final ConnectionReaper reaper;
+
+	protected ConnectionPool(String url, String user, String password) {
+		try {
+			Class.forName("org.postgresql.Driver").newInstance();
+		} catch (Exception e) {
+			logger.log(Level.SEVERE, e.getMessage(), e);
+		}
+		this.url = url;
+		this.user = user;
+		this.password = password;
+		reaper = new ConnectionReaper(this);
+		reaper.start();
+	}
+
+	public int getNumConnections() {
+		return connections.size();
+	}
+
+	public int getNumUsedConnections() throws InterruptedException {
+		int count = 0;
+		for (PooledConnection c : connections) {
+			if (c.inUse()) { count++; }
+		}
+		return count;
+	}
+
+	protected void setWaittime(int waittime) {
+		this.waittime = waittime;
+	}
+
+	protected synchronized void reapConnections() {
+		long stale = System.currentTimeMillis() - timeout;
+		for (PooledConnection conn : connections) {
+			if (!conn.inUse() && (connections.size() > minpoolsize)
+					&& (stale > conn.getLastUse())) {
+				logger.log(Level.INFO,
+						"Reaper is closing unused connection - number was: " + connections.size());
+				removeConnection(conn);
+			}
+		}
+	}
+
+	protected synchronized void closeConnections() {
+		for (PooledConnection connection : connections) {
+			removeConnection(connection);
+		}
+	}
+		
+
+	protected synchronized void removeConnection(PooledConnection conn) {
+		try {
+			conn.close();
+			if (conn.isClosed()) {
+				connections.remove(conn);
+				logger.log(Level.INFO, "Zavreno pripojeni. Pocet pripojeni: "+ connections.size());
+			}
+		} catch (SQLException e) {
+			logger.log(Level.INFO, e.getMessage());
+		}
+	}
+
+	protected synchronized PooledConnection getPooledConnection() throws SQLException {
+		PooledConnection c;
+		for (PooledConnection connection : connections) {
+			c = connection;
+			if (c.lease()) {
+				return c;
+			}
+		}
+
+		if (connections.size() < maxpoolsize) {
+			/* open new connection if possible */
+			Connection conn = DriverManager.getConnection(url, user, password);
+			conn.setAutoCommit(true);
+			c = new PooledConnection(conn);			
+			logger.log(Level.INFO, "Otevreno nove pripojeni cislo "
+					+ connections.size());
+			c.lease();
+			connections.add(c);
+			return c;
+
+			/* all connections are busy */
+		} else {
+			logger.log(Level.INFO, "pripojeni jsou zaneprazdeny - cekam");
+			for (int j = 0; j < waittime; j++) {
+				for (PooledConnection connection : connections) {
+					c = connection;
+					if (!c.inUse()) {
+						logger.log(Level.INFO, "Nalezeno uvolnene pripojeni");
+						c.lease();
+						return c;
+					}
+				}
+				try {
+					Thread.sleep(100);
+				} catch (InterruptedException e) {
+					logger.log(Level.SEVERE, "Nalezeno uvolnene pripojeni");
+				}
+			}
+			throw new SQLException(
+					"Maximum number of connection exceeded - try again later");
+		}
+	}
+
+	protected long getTimeout() {
+		return timeout;
+	}
+
+	protected void setTimeout(long timeout) {
+		this.timeout = timeout;
+	}
+
+	protected int getMaxPoolSize() {
+		return maxpoolsize;
+	}
+
+	protected void setMaxPoolSize(int poolsize) {
+		this.maxpoolsize = poolsize;
+	}
+
+	protected int getMinPoolSize() {
+		return minpoolsize;
+	}
+
+	protected void setMinPoolSize(int minpoolsize) {
+		this.minpoolsize = minpoolsize;
+	}
+
+	protected int getWaittime() {
+		return waittime;
+	}
+
+	static class ConnectionReaper extends Thread {
+		private final ConnectionPool pool;
+
+		ConnectionReaper(ConnectionPool pool) {
+			this.pool = pool;
+		}
+
+		public void run() {
+			while (true) {
+				try {
+					sleep(1000);
+				}  catch (InterruptedException e) {
+					e.printStackTrace();
+				}
+				pool.reapConnections();
+			}
+		}
+	}
+}

+ 7 - 0
src/main/java/cz/hsrs/db/pool/ConnectionPoolMBean.java

@@ -0,0 +1,7 @@
+package cz.hsrs.db.pool;
+
+public interface ConnectionPoolMBean {
+
+	public int getNumConnections();
+	public int getNumUsedConnections() throws InterruptedException ;
+}

+ 80 - 0
src/main/java/cz/hsrs/db/pool/PooledConnection.java

@@ -0,0 +1,80 @@
+package cz.hsrs.db.pool;
+
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * Wrapes the Connection object and provide methods for connection pooling
+ * @author jezekjan
+ *
+ */
+public class PooledConnection {    
+
+	private Connection conn;
+    private boolean inuse;
+    private long timestamp;
+
+
+    protected PooledConnection(Connection conn) throws SQLException {
+        this.conn=conn;       
+        this.conn.setAutoCommit(true);
+        this.inuse=false;
+        this.timestamp=0;
+    }
+
+    protected synchronized boolean lease() {
+       if(inuse)  {
+           return false;
+       } else {
+          inuse=true;        
+          return true;
+       }
+    }
+    protected boolean validate() {
+	try {
+            conn.getMetaData();
+        }catch (Exception e) {
+	    return false;
+	}
+	return true;
+    }
+
+    protected synchronized boolean inUse() {
+        return inuse;
+    }
+
+    protected synchronized long getLastUse() {
+    	if (inuse){
+    		return System.currentTimeMillis();
+    	}
+        return timestamp;
+    }
+
+    protected synchronized void release() {   
+    	  timestamp=System.currentTimeMillis();
+    	  inuse=false;
+    }
+    
+    protected synchronized void close() throws SQLException {     
+  	  conn.close();
+    }
+
+    protected void expireLease() {
+        inuse=false;
+    }
+
+    protected Connection getConnection() {
+        return conn;
+    }
+    
+    protected Statement createStatement() throws SQLException{    	
+    	return conn.createStatement();    	
+    }
+  
+    protected boolean isClosed() throws SQLException {
+        return conn.isClosed();
+    }
+}
+

+ 225 - 0
src/main/java/cz/hsrs/db/pool/SQLExecutor.java

@@ -0,0 +1,225 @@
+package cz.hsrs.db.pool;
+
+import java.io.InputStream;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+/**
+ * Class for executing sql commands. This class is responsible for proper
+ * Connections handling. This class is singleton.
+ *
+ * @author jezekjan
+ *
+ */
+public class SQLExecutor {
+
+    private static String UnitsPositions_table;
+    private static String UnitsTracks_table;
+    private static String UnitsLastPositions_table;
+
+    private static String Brand_picture;
+    private static Boolean Altitude_enabled;
+    private static Boolean Last_value;
+    private static Boolean Vgi_observation;
+    private static String configFile = null;
+
+    private static ConnectionPool mycp;
+    private static Properties prop;
+    private static SQLExecutor SQLEXEC;
+    public static final String LOGGER_ID = "database_logger";
+    public static Logger logger = Logger.getLogger(LOGGER_ID);
+
+    /*private SQLExecutor() {
+        try {
+            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+            ObjectName name = new ObjectName("cz.hsrs.db:type=ConnectionPool");
+            ConnectionPool mbean = SQLExecutor.getCoonectionPool();
+            mbs.registerMBean(mbean, name);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (prop == null) {
+            throw new NullPointerException(
+                    "You have to setProperties before getting Connection");
+        }
+    }*/
+
+    private SQLExecutor() {
+        if (prop == null) {
+            throw new NullPointerException(
+                    "You have to setProperties before getting Connection");
+        }
+    }
+
+    /**
+     * Method returns instance of the SQLExecutor class
+     * if the instance doesn't exist, it creates new instance
+     * @return instance of SQLExecutor class
+     */
+    public static synchronized SQLExecutor getInstance() {
+        if (SQLEXEC == null) {
+            SQLEXEC = new SQLExecutor();
+        }
+        return SQLEXEC;
+    }
+
+    /**
+     * Method sets properties from Properties object
+     * @param proper instance of Properties class with settings
+     */
+    public static void setProperties(Properties proper) {
+
+        prop = proper;
+        mycp = new ConnectionPool((String) prop.get("Address"),
+                (String) prop.get("Username"), (String) prop.get("Password"));
+        mycp.setMaxPoolSize(5);
+        mycp.setMinPoolSize(1);
+
+        UnitsPositions_table = prop.getProperty("UnitsPositions_table");
+        UnitsTracks_table = prop.getProperty("UnitsTracks_table");
+        UnitsLastPositions_table = prop.getProperty("UnitsLastPositions_table");
+        Brand_picture = prop.getProperty("Brand_picture");
+        // datamodel properties
+        Altitude_enabled = Boolean.parseBoolean(prop.getProperty("Altitude_enabled", "false"));
+        Last_value = Boolean.parseBoolean(prop.getProperty("Last_value_enabled"));
+        Vgi_observation = Boolean.parseBoolean(prop.getProperty("Vgi_observation_enabled"));
+    }
+
+    /**
+     * Executes SELECT
+     *
+     * @param sql
+     * @return a ResultSet object that contains the data produced by the given query; never null
+     * @throws SQLException
+     */
+    public ResultSet executeQuery(String sql) throws SQLException {
+        PooledConnection con = mycp.getPooledConnection();
+        ResultSet rs = null;
+        Statement st= null;
+        try {
+            st = con.createStatement();
+            rs = st.executeQuery(sql);
+            con.release();
+        } catch (SQLException e) {
+            mycp.removeConnection(con);
+            throw new SQLException(e);
+        }
+
+        return rs;
+    }
+
+    /**
+     * Executes UPDATE
+     *
+     * @param sql
+     * @return either (1) the row count for SQL DML statements
+     *         or (2) 0 for SQL statements that return nothing
+     * @throws SQLException
+     */
+    public static synchronized int executeUpdate(String sql) throws SQLException {
+        PooledConnection con = mycp.getPooledConnection();
+        int rs;
+        Statement st= null;
+        try {
+            st = con.createStatement();
+            rs = st.executeUpdate(sql);
+            con.release();
+        } catch (SQLException e) {
+            mycp.removeConnection(con);
+            throw new SQLException(e);
+        }
+        return rs;
+    }
+
+    /**
+     * Method insert row to table with one column with "bytea"
+     * @param sql PreparedStatement to insert row with one "?" parameter to insert InputStream
+     * @param is InputStream with file
+     * @param fileSize size of file in InputStream
+     * @throws SQLException Throws SQLException if an exception occurs during inserting
+     */
+    public static synchronized void insertStream(String sql, InputStream is, long fileSize) throws SQLException {
+        PooledConnection con = mycp.getPooledConnection();
+        PreparedStatement  ps = con.getConnection().prepareStatement(sql);
+        ps.setBinaryStream(1, is, (int)fileSize);
+        ps.execute();
+        con.release();
+    }
+
+    public static void close() {
+        mycp.closeConnections();
+    }
+
+    public static int getNumberOfConnection() {
+        return mycp.getNumConnections();
+    }
+
+    public static int getNumberOfUsedConnection() {
+        try {
+            return mycp.getNumUsedConnections();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    public static String getConfigFile() {
+        return configFile;
+    }
+
+    public static void setConfigFile(String configFile) {
+        SQLExecutor.configFile = configFile;
+    }
+
+    protected static ConnectionPool getConnectionPool() {
+        return mycp;
+    }
+
+    public static String getUnitsPositions_table() {
+        return UnitsPositions_table;
+    }
+
+    public static String getUnitsTracks_table() {
+        return UnitsTracks_table;
+    }
+
+    public static String getUnitsLastPositions_table() {
+        return UnitsLastPositions_table;
+    }
+
+    /**
+     * Method returns name of the picture for head of web pages
+     * @return name of the picture as String
+     */
+    public static String getBrand_picture_name(){
+        return Brand_picture;
+    }
+
+    /**
+     * Method returns boolean if storing of point altitude is enabled
+     * @return true if storing altitude is enabled, false if not
+     */
+    public static boolean isAltitudeEnabled(){
+        return Altitude_enabled;
+    }
+
+    /**
+     * Method returns boolean if are enabled last values of observations
+     * @return true if last values are enabled, false if they are disabled
+     */
+    public static Boolean isLastValueEnabled(){
+        return Last_value;
+    }
+
+    /**
+     * Method returns boolean if are enabled VGI observations
+     * @return true if VGI observations are enabled, false if they are disabled
+     */
+    public static Boolean isVgiObservationsEnabled(){
+        return Vgi_observation;
+    }
+}

+ 263 - 0
src/main/java/cz/hsrs/db/util/AlertUtil.java

@@ -0,0 +1,263 @@
+/**
+ * 
+ */
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import cz.hsrs.db.model.Alert;
+import cz.hsrs.db.model.AlertEvent;
+import cz.hsrs.db.model.AlertQuery;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * @author mkepka
+ *
+ */
+public class AlertUtil extends DBUtil{
+	
+	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+	private static String replacePattern= "xRPLCx";
+	
+	public AlertUtil() {		
+	}
+	
+	public int insertAlert(int alert_id, String description) throws SQLException {
+		String queryConf = "INSERT into alerts(alert_id, alert_description) values ("+ alert_id + ",'" + description + "');";
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+	
+	public int deleteAlert(int alert_id) throws SQLException {
+		String delete_alert = "DELETE FROM alerts WHERE alert_id = " + alert_id + ";";
+		return SQLExecutor.executeUpdate(delete_alert);
+	}
+	
+	public int deleteAlert(String description) throws SQLException {
+		String delete_alert = "DELETE FROM alerts WHERE alert_description = '" + description + "';";
+		return SQLExecutor.executeUpdate(delete_alert);
+	}
+
+	public List<Alert> getAlerts(long unit_ID) throws SQLException {		
+		String queryAlerts = "SELECT alerts.alert_id, alert_description"
+				+ " FROM alert_events, alerts"
+				+ " WHERE alert_events.unit_id =" + unit_ID 
+				+ " AND alert_events.alert_id = alerts.alert_id ;";
+		ResultSet res = stmt.executeQuery(queryAlerts);
+       
+		@SuppressWarnings("unchecked")
+		List<Alert> alertList = (List<Alert>)generateObjectList(new Alert(), res);
+		return alertList;
+ 
+	}
+	public int solveAlertEvent(int event_id) throws SQLException {
+		String queryConf = "UPDATE alert_events SET solved = true WHERE alert_event_id=" + event_id;
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+	
+	public int solveAlertEvent(String timestamp, long unit_id) throws SQLException {
+		String queryConf = "UPDATE alert_events SET solved = 'true' WHERE unit_id=" + unit_id+" AND time_stamp ='"+timestamp+"';";
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+	
+	public int solvingAlertEvent(String timestamp, long unit_id) throws SQLException{
+		String queryConf = "UPDATE alert_events SET solving = 'true' WHERE unit_id=" + unit_id+" AND time_stamp ='"+timestamp+"';";
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+	
+	public int getAlertId(String description) throws SQLException{
+		String alertQuery = "SELECT alert_id FROM alerts WHERE alert_description ='"+description+"';";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(alertQuery);
+		res.next();
+		return res.getInt("alert_id");
+	}
+	
+	public boolean provideAlerts(long unit_id) throws SQLException{
+		String query = "select provide_alerts from units_conf where unit_id=" +unit_id;
+		ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+		res.next();
+		return res.getBoolean(1);
+	}
+	public List<AlertEvent> getUnsolvedAlertEvents(long unit_id) throws SQLException{
+		String queryAlerts = "SELECT alert_event_id, time_stamp, alerts.alert_id, alert_description, solved, solving, gid, alert_events.unit_id"
+			+ " FROM alert_events, alerts"
+			+ " WHERE alert_events.unit_id = "+unit_id 
+			+ " AND alert_events.solved = 'false'"
+			+ " AND alert_events.alert_id = alerts.alert_id ;";
+
+		ResultSet res = SQLExecutor.getInstance().executeQuery(queryAlerts);
+   
+		@SuppressWarnings("unchecked")
+		List<AlertEvent> eventList = (List<AlertEvent>)generateObjectList(new AlertEvent(), res);
+		return eventList;
+		 		
+	}
+	public List<AlertEvent> getUnsolvingAlertEvent(long unit_id, int alert_id) throws SQLException{
+		String queryAlerts = "SELECT alert_event_id, time_stamp, alerts.alert_id, alert_description, solved, solving, gid, alert_events.unit_id"
+			+ " FROM alert_events, alerts"
+			+ " WHERE alert_events.unit_id = "+unit_id
+			+ " AND alert_events.solving = 'false'"
+			+ " AND alert_events.solved = 'false'"
+			+ " AND alert_events.alert_id = "+alert_id
+			+ " AND alert_events.alert_id = alerts.alert_id ;";
+		
+		ResultSet res = SQLExecutor.getInstance().executeQuery(queryAlerts);
+		
+		@SuppressWarnings("unchecked")
+		List<AlertEvent> eventList = (List<AlertEvent>)generateObjectList(new AlertEvent(), res);
+		return eventList;  
+	}
+	/**
+	 * @return List of AlertEvents from time to time including
+	 * @throws NoItemFoundException 
+	 *
+	 */
+	public List<AlertEvent> getAlertEventsByTime(long unit_id, String from, String to) throws SQLException{
+		String queryAlerts = "SELECT alert_event_id, time_stamp, alerts.alert_id, alert_description, solved, solving, gid, alert_events.unit_id"
+			+ " FROM alert_events, alerts, units "
+			+ "WHERE alert_events.unit_id = " + unit_id 
+			+ " AND alert_events.time_stamp >= '"+ from
+			+ "' AND alert_events.time_stamp <= '"+ to
+			+ "' AND alert_events.alert_id = alerts.alert_id ;";
+
+		ResultSet res = SQLExecutor.getInstance().executeQuery(queryAlerts);
+   
+		@SuppressWarnings("unchecked")
+		List<AlertEvent> eventList = (List<AlertEvent>)generateObjectList(new AlertEvent(), res);
+		return eventList;
+	}
+	// without status and timeStamp
+	public List<AlertQuery> getAlertQueries(long unit_id) throws SQLException{
+		String query = "SELECT aq.query_id, aq.query_string, aq.alert_id FROM alert_queries aq, alert_queries_to_units aqu" +
+				" WHERE aqu.unit_id = "+unit_id+" AND aqu.query_id = aq.query_id;";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+		@SuppressWarnings("unchecked")
+		List<AlertQuery> queryList =(List<AlertQuery>)generateObjectList(new AlertQuery(), res);
+		return queryList;
+	}
+	
+	// with status and timeStamp
+	/*public List<AlertQuery> getAlertQueries(long unit_id) throws SQLException{
+		String query = "SELECT aq.query_id, aq.query_string, aq.alert_id, aqu.last_status_alert_query, aqu.last_status_time_stamp FROM public.alert_queries aq, public.alert_queries_to_units aqu" +
+				" WHERE aqu.unit_id = "+unit_id+" AND aqu.query_id = aq.query_id;";
+		ResultSet res = stmt.executeQuery(query);
+		List<AlertQuery> queryList =(List<AlertQuery>)generateObjectList(new AlertQuery(), res);
+		return queryList;
+	}*/
+	/**
+	 * Method checks whether given UnitPosition matches given AlertQuery
+	 * @param aQuery - Object AlertQuery with query on given position
+	 * @param pos - Object UnitPosition with current position geometry
+	 * @return Returns boolean true if query with given position returns true
+	 * @throws SQLException Throws SQLException if an exception occurs while processing SQL in DBMS
+	 */
+	public boolean checkAlertQuery(AlertQuery aQuery, UnitPosition pos) throws SQLException{
+		String query = aQuery.getQuery();
+		//JDCConnection conn = SQLExecutor.getConnection();
+		//PreparedStatement pStmt = conn.prepareStatement(query);
+		//pStmt.setString(1, pos.internalGetGeom());
+		String completedQuery = query.replace(replacePattern, pos.internalGetGeom());
+	    ResultSet res = SQLExecutor.getInstance().executeQuery(completedQuery);
+	    //conn.release();
+	    // conn.close();
+		
+		if(res.next()==true){
+			return res.getBoolean(1);
+		}
+		else{
+			throw new SQLException("Exception in executing geometry query!");
+		}
+	}
+	
+	public boolean getAlertQueryLastStatus(AlertQuery aQuery, UnitPosition pos) throws NoItemFoundException, SQLException{	
+		String sql = "SELECT last_status_alert_query FROM alert_queries_to_units" +
+				" WHERE query_id = " + aQuery.getQueryId() +
+				" AND unit_id = "+pos.getUnit_id()+" ;";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(sql);
+		if(res.next() == true){
+			boolean status = res.getBoolean(1);
+			boolean wasNull = res.wasNull();
+			if (wasNull == false){
+				return status;
+			}
+			else{
+				throw new NoItemFoundException("getAlertQueryLastStatus for "
+						+ pos.getUnit_id() + " and " + aQuery.getQueryId()
+						+ " does not exist!");
+			}
+		}
+		else{
+			throw new NoItemFoundException("getAlertQueryLastStatus for "
+					+ pos.getUnit_id() + " and " + aQuery.getQueryId()
+					+ " does not exist!");
+		}
+	}
+
+	/**
+	 * Method gets last timestamp of status for given pair of AlertQuery and unit
+	 * @param aQuery - Object AlertQuery with queryId
+	 * @param pos - Object UnitPosition with unitId
+	 * @return - Returns last timestamp of query status as Date
+	 * @throws SQLException Throws SQLException if an exception occur while processing SQL in DBMS
+	 * @throws NoItemFoundException Throws Exception if there is no pair of queryId and unitId in DBMS 
+	 */
+	public Date getAlertQueryLastStatusTimeStamp(AlertQuery aQuery, UnitPosition pos) throws SQLException, NoItemFoundException{
+		String sql = "SELECT last_status_time_stamp FROM alert_queries_to_units" +
+		" WHERE query_id = " + aQuery.getQueryId() +
+		" AND unit_id = "+pos.getUnit_id()+" ;";
+		ResultSet res = SQLExecutor.getInstance().executeQuery(sql);
+		if(res.next()==true){
+			String timeStamp = res.getString(1);
+			boolean wasNull = res.wasNull();
+			if (wasNull == false){
+				try {
+					return format.parse(timeStamp+"00");
+				} catch (ParseException e) {
+					throw new SQLException(e);
+				}
+				//return timeStamp;
+			}
+			else{
+				throw new NoItemFoundException("getAlertQueryLastStatusTimeStamp for "
+						+ pos.getUnit_id() + " and " + aQuery.getQueryId()
+						+ " does not exist!");
+			}
+		}
+		else{
+			throw new NoItemFoundException("getAlertQueryLastStatusTimeStamp for "
+					+ pos.getUnit_id() + " and " + aQuery.getQueryId()
+					+ " does not exist!");
+		}	
+	}	
+
+	/**
+	 * Method sets new timestamp of last status of query
+	 * @param aQuery - Object AlertQuery with query
+	 * @param pos - Object UnitPosition with position geometry
+	 * @return Returns int from executeQuery method
+	 * @throws SQLException Throws SQLException if an exception occur while processing SQL in DBMS
+	 */
+	public int setNewAlertQueryTimeStamp(AlertQuery aQuery, UnitPosition pos) throws SQLException{
+		String queryConf = "UPDATE alert_queries_to_units SET last_status_time_stamp = '"+pos.getTime_stamp()+"' WHERE unit_id=" + pos.getUnit_id()+" AND query_id = " + aQuery.getQueryId() +";";
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+
+	/**
+	 * Method sets new status of AlertQuery to database
+	 * @param newStatus - New status of query as boolean
+	 * @param aQuery - Object AlertQuery with query
+	 * @param pos - Object UnitPosition with position geometry
+	 * @return Returns int from executeQuery method
+	 * @throws SQLException - Throws SQLException if an exception occur while processing SQL in DBMS
+	 */
+	public int setNewAlertQueryLastStatus(boolean newStatus, AlertQuery aQuery, UnitPosition pos) throws SQLException{
+		String queryConf = "UPDATE alert_queries_to_units SET last_status_alert_query = "+newStatus+" WHERE unit_id=" + pos.getUnit_id()+" AND query_id = " + aQuery.getQueryId() +";";
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+}

+ 798 - 0
src/main/java/cz/hsrs/db/util/AnalystUtil.java

@@ -0,0 +1,798 @@
+/**
+ * 
+ */
+package cz.hsrs.db.util;
+
+import java.sql.Array;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.PatternSyntaxException;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * Class for running analysis implemented in the database
+ * @author mkepka
+ *
+ */
+public class AnalystUtil extends DBUtil{
+
+    static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+
+    private final String ANALYST_SCHEMA = "computations";
+    private final String FOODIE_SCHEMA = "foodie";
+    
+    public AnalystUtil(){ }
+
+    /**
+     * Method runs analysis for calculating working time on particular sites
+     * @param userName id of user identifies available units
+     * @param date of the analysis
+     * @param unitId id of the unit for analysis
+     * @return ResultSet with results of the analysis 
+     * @throws SQLException
+     */
+    public ResultSet getWorkDurationOnSites(String userName, String date, long unitId) throws SQLException{
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        
+        if(isAffiliated){
+            if(date != null){
+                if(!date.isEmpty() && unitId != 0){
+                    String query = "SELECT calendar_date, unit_id, site_code, move_time, description, "
+                            + "rfid, description_cze, test_flow "
+                            + "FROM "+ANALYST_SCHEMA+".work_duration_sites_period('"+date+"', '"+date+"', "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameter date or unit_id was not defined!");
+                }
+            } else{
+                throw new SQLException("Parameter date was not defined!");
+            }
+        } else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+    
+    /**
+     * Method runs analysis for calculating working time on particular sites
+     * @param userName id of user identifies available units
+     * @param fromDate begin date of the period, if null it is substituted by toDate -7 days 
+     * @param toDate end date of the period, if null it is substituted by fromDate + 7 days
+     * @param unitId id of the unit for analysis
+     * @return ResultSet with results of the analysis 
+     * @throws SQLException
+     */
+    public ResultSet getWorkDurationOnSitesPeriod(String userName, String fromDate, String toDate, long unitId) throws SQLException{
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        
+        if(isAffiliated){
+            if(fromDate != null && toDate != null){
+                if(!fromDate.isEmpty() && !toDate.isEmpty() && unitId != 0){
+                    String query = "SELECT calendar_date, unit_id, site_code, move_time, description, "
+                            + "rfid, description_cze, test_flow "
+                            + "FROM "+ANALYST_SCHEMA+".work_duration_sites_period('"+fromDate+"', '"+toDate+"', "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameters dates or unit_id were not defined!");
+                }
+            }
+            else if(fromDate != null && toDate == null){
+                if(!fromDate.isEmpty() && unitId != 0){
+                    String query = "SELECT calendar_date, unit_id, site_code, move_time, description, "
+                            + "rfid, description_cze, test_flow "
+                            + "FROM "+ANALYST_SCHEMA+".work_duration_sites_period('"+fromDate+"', ('"+fromDate+"'::date + '7 day'::interval)::date, "+unitId+");";
+                    return stmt.executeQuery(query);
+                }
+                else{
+                    throw new SQLException("Parameters from_date or unit_id were not defined!");
+                }
+            }
+            else if(fromDate == null && toDate != null){
+                if(!toDate.isEmpty() && unitId != 0){
+                    String query = "SELECT calendar_date, unit_id, site_code, move_time, description, "
+                            + "rfid, description_cze, test_flow "
+                            + "FROM "+ANALYST_SCHEMA+".work_duration_sites_period(('"+toDate+"'::date - '7 day'::interval)::date, '"+toDate+"', "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameters to_date or unit_id were not defined!");
+                }
+            } else{
+                throw new SQLException("Parameters from_date and to_date were not defined!");
+            }
+        } else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+    
+    /**
+     * Method runs analysis for utilization of given tractor during given date 
+     * @param userName id of user identifies available units
+     * @param date date in which analysis should be run
+     * @param unitId id of the unit for analysis
+     * @return ResultSet with analysis result
+     * @throws SQLException
+     */
+    public ResultSet getUnitUtilization(String userName, String date, long unitId) throws SQLException{
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        
+        if(isAffiliated){
+            if(date != null){
+                if(!date.isEmpty()){
+                    String query = "SELECT calendar_date, unit_id, description, move_field, move_other, stand "
+                        + "FROM "+ANALYST_SCHEMA+".tractor_utilization_period('"+date+"'::date, '"+date+"'::date, "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameter date was not defined!");
+                }
+            } else{
+                throw new SQLException("Parameter toTime was not defined!");
+            }
+        } else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+    
+    /**
+     * Method runs analysis for utilization of given tractor during given period 
+     * @param userName id of user identifies available units
+     * @param fromDate begin date of the period, if null it is substituted by toDate -7 days 
+     * @param toDate end date of the period, if null it is substituted by fromDate + 7 days
+     * @param unitId id of the unit for analysis
+     * @return ResultSet with analysis result
+     * @throws SQLException
+     */
+    public ResultSet getUnitUtilizationInPeriod(String userName, String fromDate, String toDate, long unitId) throws SQLException{
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        
+        if(isAffiliated){
+            if(fromDate != null && toDate != null){
+                if(!fromDate.isEmpty() && !toDate.isEmpty()){
+                    String query = "SELECT calendar_date, unit_id, description, move_field, move_other, stand "
+                        + "FROM "+ANALYST_SCHEMA+".tractor_utilization_period('"+fromDate+"'::date, '"+toDate+"'::date, "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Time parameters were not correct!");
+                }
+            }
+            else if(fromDate != null && toDate == null){
+                if(!fromDate.isEmpty()){
+                    String query = "SELECT calendar_date, unit_id, description, move_field, move_other, stand "
+                        + "FROM "+ANALYST_SCHEMA+".tractor_utilization_period('"+fromDate+"'::date, ('"+fromDate+"'::date + '7 day'::interval)::date, "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameter \"from\" was not correct!");
+                }
+            }
+            else if(fromDate == null && toDate != null){
+                if(!toDate.isEmpty()){
+                    String query = "SELECT calendar_date, unit_id, description, move_field, move_other, stand "
+                            + "FROM "+ANALYST_SCHEMA+".tractor_utilization_period(('"+toDate+"'::date - '7 day'::interval)::date, '"+toDate+"'::date, "+unitId+");";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameter \"to\" was not correct!");
+                }
+            } else{
+                throw new SQLException("Wrong combination of time parameters!");
+            }
+        } else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+
+    /**
+     * Method runs analysis Working Log for given unitId in given date
+     * @param userName id of user to confirm that unitId is affiliated
+     * @param date in which analysis should be run 
+     * @param unitId id of the unit for analysis
+     * @param minStopDuration parameter for analysis - minimal duration of stop as hh:mm:ss 
+     * @param minWorkDuration parameter for analysis - minimal duration of work as hh:mm:ss
+     * @param allowedTimeOutside parameter for analysis - maximal duration of spent time outside field as hh:mm:ss
+     * @return ResultSet with analysis result
+     * @throws SQLException
+     */
+    public ResultSet getTractorWorkDay(String userName, String date, long unitId, String minStopDuration, String minWorkDuration, String allowedTimeOutside) throws SQLException{
+        if ((minStopDuration == null) || (minStopDuration != null && minStopDuration.isEmpty())){
+            minStopDuration = "00:05:00";
+        }
+        if ((minWorkDuration == null) || (minWorkDuration != null && minWorkDuration.isEmpty())){
+            minWorkDuration = "00:20:00";
+        }
+        if ((allowedTimeOutside == null) || (allowedTimeOutside != null && allowedTimeOutside.isEmpty())){
+            allowedTimeOutside = "00:03:00";
+        }
+        
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        if(isAffiliated){
+            if(date != null){
+                if(!date.isEmpty()){
+                    String query = "SELECT * FROM "+ANALYST_SCHEMA+".tractor_work_day('"+date+"', "+unitId+", '"+minStopDuration+"', '"+minWorkDuration+"', '"+allowedTimeOutside+"');";
+                    return stmt.executeQuery(query);
+                } else{
+                    throw new SQLException("Parameter date was not defined!");
+                }
+            } else{
+                throw new SQLException("Parameter date was not defined!");
+            }
+        } else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+    
+    /**
+     * Method gets result of analysis activities_field_overview() by specifying site by ID
+     * @param siteId Id of site
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getActivitiesFieldOverview(int siteId) throws SQLException{
+        String query = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview("+siteId+");";
+        return stmt.executeQuery(query);
+    }
+
+    /**
+     * Method gets result of analysis activities_field_overview() by specifying plot by ID
+     * @param plotId Id of plot
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getActivitiesFieldOverviewByPlot(int plotId) throws SQLException{
+        String query = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview("+plotId+");";
+        return stmt.executeQuery(query);
+    }
+
+    /**
+     * Method gets result of analysis activities_field_overview() by specifying plot by coordinates
+     * @param point coordinates inside of a plot
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getActivitiesFieldOverviewByPoint(String point) throws SQLException{
+        int plotId = getPlotIdByPoint(point);
+        return getActivitiesFieldOverview(plotId);
+    }
+    
+    /**
+     * Method gets result of analysis activities_field_overview_period() by specifying plot by ID
+     * @param plotId - ID of plot
+     * @param fromDate beginning of period, can be null
+     * @param toDate end of period, can be null
+     * @return ResultSet with result of analysis
+     * @throws SQLException 
+     */
+    public ResultSet getActivitiesFieldOverviewPeriod(int plotId, String fromDate, String toDate) throws SQLException{
+        String sql;
+        if(fromDate == null && toDate != null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview_period("+plotId+", null, '"+toDate+"');";
+        }
+        else if(fromDate != null && toDate == null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview_period("+plotId+", '"+fromDate+"', null);";
+        }
+        else if(fromDate != null && toDate != null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview_period("+plotId+", '"+fromDate+"', '"+toDate+"');";
+        }
+        else{
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".activities_field_overview_period("+plotId+", null, null);";
+        }
+        return stmt.executeQuery(sql);
+    }
+    
+    /**
+     * Method gets result of analysis activities_field_overview_period() by specifying plot by coordinates
+     * @param point coordinates inside of a plot
+     * @param fromDate beginning of period, can be null
+     * @param toDate end of period, can be null
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getActivitiesFieldOverviewPeriodByPoint(String point, String fromDate, String toDate) throws SQLException{
+        int plotId = getPlotIdByPoint(point);
+        return getActivitiesFieldOverviewPeriod(plotId, fromDate, toDate);
+    }
+    
+    /**
+     * 
+     * @param plotId
+     * @param unitId
+     * @param fromDate
+     * @param toDate
+     * @param propertyName
+     * @return
+     * @throws SQLException
+     */
+    public ResultSet getManagementZonesOverviewByPlotId(int plotId, long unitId, String fromDate, String toDate, String propertyName) throws SQLException {
+        String query; 
+        if (fromDate != null && toDate == null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview ("+plotId+", "+unitId+", '"+propertyName+"', '"+fromDate+"', NULL);";
+        } else if (fromDate == null && toDate != null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview ("+plotId+", "+unitId+", '"+propertyName+"', NULL, '"+toDate+"');";
+        } else {
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview ("+plotId+", "+unitId+", '"+propertyName+"', '"+fromDate+"', '"+toDate+"');";
+        }
+        return stmt.executeQuery(query);
+    }
+    
+    /**
+     * Method runs Management Zones Overview analysis
+     * @param plotId - ID of plot
+     * @param fromDate - beginning date
+     * @param toDate - end date
+     * @param propertyName - name of property to get overview
+     * @return
+     * @throws SQLException
+     */
+    public ResultSet getManagementZonesOverviewByPlotId2(int plotId, String fromDate, String toDate, String propertyName) throws SQLException {
+        String query; 
+        if (fromDate != null && toDate == null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview2 ("+plotId+", '"+propertyName+"', '"+fromDate+"', NULL);";
+        } else if (fromDate == null && toDate != null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview2 ("+plotId+", '"+propertyName+"', NULL, '"+toDate+"');";
+        } else {
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".management_zones_overview2 ("+plotId+", '"+propertyName+"', '"+fromDate+"', '"+toDate+"');";
+        }
+        return stmt.executeQuery(query);
+    }
+    
+    /**
+     * 
+     * @param point
+     * @param unitId
+     * @param fromDate
+     * @param toDate
+     * @param propertyName
+     * @return
+     * @throws SQLException
+     */
+    public ResultSet getManagementZonesOverviewByPoint(String point, long unitId, String fromDate, String toDate, String propertyName) throws SQLException {
+        int plotId = getPlotIdByPoint(point);
+        return getManagementZonesOverviewByPlotId(plotId, unitId, fromDate, toDate, propertyName);
+    }
+    
+    /**
+     * 
+     * @param point
+     * @param fromDate
+     * @param toDate
+     * @param propertyName
+     * @return
+     * @throws SQLException
+     */
+    public ResultSet getManagementZonesOverviewByPoint2(String point, String fromDate, String toDate, String propertyName) throws SQLException {
+        int plotId = getPlotIdByPoint(point);
+        return getManagementZonesOverviewByPlotId2(plotId, fromDate, toDate, propertyName);
+    }
+    
+    /**
+     * Method runs analysis for Daily Field Activities (daily_field_activities)
+     * @param plotId - ID of plot where activities took place
+     * @param fromDate - beginning of time range
+     * @param toDate - end of time range
+     * @return ResultSet containing analysis result 
+     * @throws SQLException 
+     */
+    public ResultSet getDailyFieldActivities(int plotId, String fromDate, String toDate) throws SQLException {
+        String query;
+        if(fromDate == null && toDate == null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".daily_field_activities("+plotId+", NULL, NULL);";
+        } else if(fromDate != null && toDate == null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".daily_field_activities("+plotId+", '"+fromDate+"', NULL);";
+        } else if(fromDate == null && toDate != null){
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".daily_field_activities("+plotId+", NULL, '"+toDate+"');";
+        } else {
+            query = "SELECT * FROM "+ANALYST_SCHEMA+".daily_field_activities("+plotId+", '"+fromDate+"', '"+toDate+"');";
+        }
+        return stmt.executeQuery(query);
+    }
+    
+    /**
+     * Method runs analysis for Daily Field Activities (daily_field_activities) by giving coordinates
+     * @param point - coordinates inside of a plot
+     * @param fromDate - beginning of time range
+     * @param toDate - end of time range
+     * @return ResultSet containing analysis result 
+     * @throws SQLException 
+     */
+    public ResultSet getDailyFieldActivitiesByPoint(String point, String fromDate, String toDate) throws SQLException {
+        int plotId = getPlotIdByPoint(point);
+        return getDailyFieldActivities(plotId, fromDate, toDate);
+    }
+    
+    /**
+     * Method gets result of analysis field_overview_fuel_summary() by specifying site by ID
+     * @param siteId ID of site
+     * @param fromDate beginning of period, can be null
+     * @param toDate end of period, can be null
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getFieldFuelSummary(int siteId, String fromDate, String toDate) throws SQLException{
+        String sql;
+        if(fromDate == null && toDate != null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".field_overview_fuel_summary("+siteId+", null, '"+toDate+"');";
+        }
+        else if(fromDate != null && toDate == null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".field_overview_fuel_summary("+siteId+", '"+fromDate+"', null);";
+        }
+        else if(fromDate != null && toDate != null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".field_overview_fuel_summary("+siteId+", '"+fromDate+"', '"+toDate+"');";
+        }
+        else{
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".field_overview_fuel_summary("+siteId+", null, null);";
+        }
+        return stmt.executeQuery(sql);
+    }
+    
+    /**
+     * Method gets result of analysis field_overview_fuel_summary() by specifying site by coordinates
+     * @param point coordinates inside of site
+     * @param fromDate beginning of period, can be null
+     * @param toDate end of period, can be null
+     * @return ResultSet with result of analysis
+     * @throws SQLException
+     */
+    public ResultSet getFieldFuelSummaryByPoint(String point, String fromDate, String toDate) throws SQLException{
+        int siteId = getSiteIdByPoint(point);
+        return getFieldFuelSummary(siteId, fromDate, toDate);
+    }
+    
+    /**
+     * Method checks if specified unit was active during given time period
+     * @param unit_id ID of unit
+     * @param fromDate beginning date of the period, can be null
+     * @param toDate end date of the period, can be null
+     * @return List of days with boolean true if unit was active, or false if not
+     * @throws SQLException 
+     */
+    public ResultSet isTractorActiveInPeriod(String userName, long unitId, String fromDate, String toDate) throws SQLException {
+        boolean isAffiliated = checkUnitAffiliation2User(userName, unitId);
+        if(isAffiliated){
+            String sql = "";
+            if(fromDate != null && toDate != null){
+                sql = "SELECT * FROM "+ANALYST_SCHEMA+".tractor_active_period("+unitId+", '"+fromDate+"', '"+toDate+"');";
+            }
+            else if(fromDate != null && toDate == null){
+                sql = "SELECT * FROM "+ANALYST_SCHEMA+".tractor_active_period("+unitId+", '"+fromDate+"', ('"+fromDate+"'::date + '1 day'::interval)::date);";
+            }
+            else if(fromDate == null && toDate != null){
+                sql = "SELECT * FROM "+ANALYST_SCHEMA+".tractor_active_period("+unitId+", ('"+toDate+"'::date - '1 day'::interval)::date, '"+toDate+"');";
+            }
+            else{
+                throw new SQLException("Any parameters from_date or to_date were not defined!");
+            }
+            return stmt.executeQuery(sql);
+        }else{
+            throw new SQLException("Specified unit does not belong in any group of the user!");
+        }
+    }
+    
+    /**
+     * Method gets array of active tractors during given period
+     * @param userName of user
+     * @param fromDate begin date of period
+     * @param toDate end date of period, if it is null, then end is now()
+     * @return List<Long> with unit_ids of active tractors
+     * @throws SQLException if problem occurs during execution of SQL
+     * @throws NoItemFoundException if user doesn't have groupId, should never happen
+     */
+    public List<Long> getActiveTractorsDuringPeriod(String userName, String fromDate, String toDate) throws SQLException, NoItemFoundException{
+        int groupId = UserUtil.getUserGroupId(userName);
+        return getActiveTractorsDuringPeriod(groupId, fromDate, toDate);
+    }
+    
+    /**
+     * Method gets array of active tractors during given period
+     * @param groupId id of group
+     * @param fromDate begin date of period
+     * @param toDate end date of period, if it is null, then end is now()
+     * @return List<Long> with unit_ids of active tractors
+     * @throws SQLException  if problem occurs during execution of SQL
+     */
+    public List<Long> getActiveTractorsDuringPeriod(int groupId, String fromDate, String toDate) throws SQLException{
+        String sql = "";
+        if(fromDate != null && toDate != null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".all_active_tractors_period("+groupId+", '"+fromDate+"', '"+toDate+"');";
+        }
+        else if(fromDate != null && toDate == null){
+            sql = "SELECT * FROM "+ANALYST_SCHEMA+".all_active_tractors_period("+groupId+", '"+fromDate+"', (select now())::date);";
+        }
+        else{
+            throw new SQLException("Parameter fromDate can't be null!");
+        }
+        ResultSet res = stmt.executeQuery(sql);
+        List<Long> idsList = new ArrayList<Long>();
+        if(res.next()){
+            Array ids = res.getArray(1);
+            if(ids != null){
+                idsList = Arrays.asList((Long[]) ids.getArray());
+            }
+            return idsList;
+        }
+        else{
+            return idsList;
+        }
+    }
+    
+    /**
+     * Method selects all management zones inside of given plot 
+     * in GeoJSON format
+     * @param plotId - ID of plot
+     * @return Management zones in GeoJSON format as JSONObject
+     * @throws SQLException
+     */
+    public JSONObject getManagementZonesGeoJSON(int plotId) throws SQLException{
+        String query = "SELECT management_zone_id, code, code_space, code_version, valid_from, valid_to,"
+                + " begin_life_span_version, end_life_span_zone, notes, plot_id,"
+                + " st_asgeojson(st_transform(geometry, 3857), 10, 2) FROM foodie_model_test.management_zone"
+                + " WHERE plot_id = "+plotId+";";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res != null){
+            LinkedList<JSONObject> mZonesList = new LinkedList<>();
+            while(res.next()){
+                // feature
+                JSONObject feature = new JSONObject();
+                feature.put("type", "Feature");
+                feature.put("geometry", res.getString("st_asgeojson"));
+                // properties
+                JSONObject properties = new JSONObject();
+                properties.put("management_zone_id", res.getInt("management_zone_id"));
+                properties.put("code", res.getString("code"));
+                properties.put("code_space", res.getString("code_space"));
+                properties.put("code_version", res.getString("code_version"));
+                properties.put("valid_from", res.getString("valid_from"));
+                properties.put("valid_to", res.getString("valid_to"));
+                properties.put("begin_life_span_version", res.getString("begin_life_span_version"));
+                properties.put("end_life_span_zone", res.getString("end_life_span_zone"));
+                properties.put("notes", res.getString("notes"));
+                properties.put("plot_id", res.getInt("plot_id"));
+                feature.put("properties", properties);
+                
+                mZonesList.add(feature);
+            }
+            JSONObject featureCollection = new JSONObject();
+            // Features
+            JSONArray featureList = new JSONArray();
+            featureList.addAll(mZonesList);
+            // FeatureCollection
+            featureCollection.put("type", "FeatureCollection");
+            featureCollection.put("features", featureList);
+            
+            return featureCollection;
+        }
+        else{
+            return new JSONObject();
+        }
+    }
+    
+    /**
+     * Method selects management zone according to given zoneId 
+     * in GeoJSON format
+     * @param zoneId - ID of zone
+     * @return Management zone in GeoJSON format as JSONObject
+     * @throws SQLException
+     * @throws NoItemFoundException 
+     */
+    public JSONObject getManagementZoneGeoJSON(int zoneId) throws SQLException, NoItemFoundException{
+        String query = "SELECT management_zone_id, code, code_space, code_version, valid_from, valid_to,"
+                + " begin_life_span_version, end_life_span_zone, notes, plot_id,"
+                + " st_asgeojson(st_transform(geometry, 3857), 8, 2) FROM foodie_model_test.management_zone"
+                + " WHERE management_zone_id = "+zoneId+";";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res != null){
+            if(res.next()){
+                // feature
+                JSONObject feature = new JSONObject();
+                feature.put("type", "Feature");
+                feature.put("geometry", res.getString("st_asgeojson"));
+                // properties
+                JSONObject properties = new JSONObject();
+                properties.put("management_zone_id", res.getInt("management_zone_id"));
+                properties.put("code", res.getString("code"));
+                properties.put("code_space", res.getString("code_space"));
+                properties.put("code_version", res.getString("code_version"));
+                properties.put("valid_from", res.getString("valid_from"));
+                properties.put("valid_to", res.getString("valid_to"));
+                properties.put("begin_life_span_version", res.getString("begin_life_span_version"));
+                properties.put("end_life_span_zone", res.getString("end_life_span_zone"));
+                properties.put("notes", res.getString("notes"));
+                properties.put("plot_id", res.getInt("plot_id"));
+                feature.put("properties", properties);
+                
+                return feature;
+            } else{
+                throw new NoItemFoundException("Any management zone wasn't found!");
+            }
+        } else{
+            throw new NoItemFoundException("Any management zone wasn't found!");
+        }
+    }
+    
+    /**
+     * Method selects management zone according to given zoneId 
+     * in GeoJSON format
+     * @param zoneId - ID of zone
+     * @return Management zone in GeoJSON format as JSONObject
+     * @throws SQLException
+     * @throws NoItemFoundException 
+     */
+    public JSONObject getManagementZoneGeoJSONByPoint(String point) throws SQLException, NoItemFoundException{
+        String[] coords = point.split(",");
+        double x = Double.parseDouble(coords[0]);
+        double y = Double.parseDouble(coords[1]);
+        
+        String query = "SELECT management_zone_id, code, code_space, code_version, valid_from, valid_to,"
+                    + " begin_life_span_version, end_life_span_zone, notes, plot_id,"
+                    + " st_asgeojson(st_transform(geometry, 3857), 8, 2)"
+                    + " FROM foodie_model_test.management_zone"
+                    + " WHERE ST_Intersects(geometry, ST_Transform(ST_SetSRID(ST_Point("+x+", "+y+"), 3857),"
+                            + " (SELECT distinct ST_SRID(geometry) as srid FROM foodie_model_test.management_zone)));";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res != null){
+            if(res.next()){
+                // feature
+                JSONObject feature = new JSONObject();
+                feature.put("type", "Feature");
+                feature.put("geometry", res.getString("st_asgeojson"));
+                // properties
+                JSONObject properties = new JSONObject();
+                properties.put("management_zone_id", res.getInt("management_zone_id"));
+                properties.put("code", res.getString("code"));
+                properties.put("code_space", res.getString("code_space"));
+                properties.put("code_version", res.getString("code_version"));
+                properties.put("valid_from", res.getString("valid_from"));
+                properties.put("valid_to", res.getString("valid_to"));
+                properties.put("begin_life_span_version", res.getString("begin_life_span_version"));
+                properties.put("end_life_span_zone", res.getString("end_life_span_zone"));
+                properties.put("notes", res.getString("notes"));
+                properties.put("plot_id", res.getInt("plot_id"));
+                feature.put("properties", properties);
+                
+                return feature;
+            } else{
+                throw new NoItemFoundException("Any management zone wasn't found!");
+            }
+        } else{
+            throw new NoItemFoundException("Any management zone wasn't found!");
+        }
+    }
+    
+    /**
+     * Method provides selection of all plots in GeoJSON format
+     * @return FeatureCollection of plots
+     */
+    public JSONObject getPlotsAsGeoJSON() throws SQLException{
+        String query = "SELECT plot_id, code, code_space, code_version, valid_from, valid_to,"
+                + " begin_life_span_version, end_life_span_version, description, origin_type_value_id,"
+                + " site_id, st_asgeojson(st_transform(geometry, 3857), 10, 2)"
+                + " FROM foodie_model_test.plot;";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res != null){
+            LinkedList<JSONObject> plotsList = new LinkedList<JSONObject>();
+            while(res.next()){
+                // feature
+                JSONObject feature = new JSONObject();
+                feature.put("type", "Feature");
+                feature.put("geometry", res.getString("st_asgeojson"));
+                // properties
+                JSONObject properties = new JSONObject();
+                properties.put("plot_id", res.getInt("plot_id"));
+                properties.put("code", res.getString("code"));
+                properties.put("code_space", res.getString("code_space"));
+                properties.put("code_version", res.getString("code_version"));
+                properties.put("valid_from", res.getString("valid_from"));
+                properties.put("valid_to", res.getString("valid_to"));
+                properties.put("begin_life_span_version", res.getString("begin_life_span_version"));
+                properties.put("end_life_span_version", res.getString("end_life_span_version"));
+                properties.put("description", res.getString("description"));
+                properties.put("origin_type_value_id", res.getInt("origin_type_value_id"));
+                properties.put("site_id", res.getInt("site_id"));
+                feature.put("properties", properties);
+                
+                plotsList.add(feature);
+            }
+            JSONObject featureCollection = new JSONObject();
+            // Features
+            JSONArray featureList = new JSONArray();
+            featureList.addAll(plotsList);
+            // FeatureCollection
+            featureCollection.put("type", "FeatureCollection");
+            featureCollection.put("features", featureList);
+            
+            return featureCollection;
+        }
+        else{
+            return new JSONObject();
+        }
+    }
+    
+    /**
+     * Method confirms that given unit belongs to given user
+     * by selecting affiliated units from database
+     * @param userName name of the user
+     * @param unitId id of unit
+     * @return true if given unit is in any group that user is connected to 
+     * @throws SQLException
+     */
+    public boolean checkUnitAffiliation2User(String userName, long unitId) throws SQLException{
+        UserUtil uUtil = new UserUtil();
+        boolean confirmed = false;
+        List<Unit> unitsOfUser = uUtil.getUnitsByUser(userName);
+        Iterator<Unit> unitsIter = unitsOfUser.iterator();
+        while (unitsIter.hasNext() && !confirmed){
+            if (unitsIter.next().getUnitId() == unitId){
+                confirmed = true;
+            }
+        }
+        return confirmed;
+    }
+    
+    /**
+     * Method finds site_id by giving point in map
+     * @param point coordinates in form "x,y"
+     * @return site_id from DB or 0 if identification failed
+     * @throws SQLException
+     */
+    private int getSiteIdByPoint(String point) throws SQLException{
+        int siteId = 0;
+        try {
+            String[] coords = point.split(",");
+            double x = Double.parseDouble(coords[0]);
+            double y = Double.parseDouble(coords[1]);
+            String query = "SELECT site_id FROM "+FOODIE_SCHEMA+".site_4326 WHERE ST_Intersects(the_geom, ST_Transform(ST_SetSRID(ST_Point("+x+", "+y+"),3857), 4326));";
+            ResultSet res = stmt.executeQuery(query);
+            if(res != null){
+                while (res.next()){
+                    siteId = res.getInt("site_id");
+                }
+            }
+        } catch (SQLException e) {
+            throw new SQLException(e.getMessage());
+        } catch(PatternSyntaxException e){
+            throw new SQLException("Input point doesn't contain mandatory values!");
+        } catch(NumberFormatException e){
+            throw new SQLException("Input point doesn't contain numbers!");
+        }
+        return siteId;
+    }
+    
+    /**
+     * "NOT FINAL VERSION YET"
+     * Method finds plot_id by giving point in map
+     * @param point coordinates in form "x,y"
+     * @return plot_id from DB or 0 if identification failed
+     * @throws SQLException
+     */
+    private int getPlotIdByPoint(String point) throws SQLException{
+        int plotId = 0;
+        try {
+            String[] coords = point.split(",");
+            double x = Double.parseDouble(coords[0]);
+            double y = Double.parseDouble(coords[1]);
+            
+            String query = "SELECT plot_id FROM foodie_model_test.plot"
+                    + " WHERE ST_Intersects(geometry, ST_Transform(ST_SetSRID(ST_Point("+x+", "+y+"),3857),"
+                        + "(SELECT distinct ST_SRID(geometry) as srid FROM foodie_model_test.plot)));";
+            ResultSet res = stmt.executeQuery(query);
+            if(res != null){
+                while (res.next()){
+                    plotId = res.getInt("plot_id");
+                }
+            }
+        } catch (SQLException e) {
+            throw new SQLException(e.getMessage());
+        } catch(PatternSyntaxException e){
+            throw new SQLException("Input point doesn't contain mandatory values!");
+        } catch(NumberFormatException e){
+            throw new SQLException("Input point doesn't contain numbers!");
+        }
+        return plotId;
+    }
+}

+ 35 - 0
src/main/java/cz/hsrs/db/util/DBUtil.java

@@ -0,0 +1,35 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import cz.hsrs.db.DBObject;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class DBUtil {
+
+	protected SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+	protected SQLExecutor stmt = SQLExecutor.getInstance();
+
+	protected String toDateString(Date date){	
+		return "TIMESTAMP '"+format.format(date)+"'";
+	}
+	
+	protected List<? extends DBObject> generateObjectList(DBObject element, ResultSet res) {
+		try {
+			List<DBObject> result = new LinkedList<>();
+			while (res.next()) {
+				DBObject dbob = (element.getClass().newInstance()).getDBObject(res);		
+				result.add(dbob);
+			}
+			return result;
+		} catch (SQLException | InstantiationException | IllegalAccessException e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+}

+ 72 - 0
src/main/java/cz/hsrs/db/util/DataChecker.java

@@ -0,0 +1,72 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.postgresql.util.PSQLException;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.TrackData;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class DataChecker  extends DBUtil{
+	
+	public void duplicatedDataDelete() throws SQLException{
+		String sel = "SELECT time_stamp, unit_id "+
+				   " FROM ( SELECT count(units_positions.gid) AS num, units_positions.time_stamp, units_positions.unit_id "+
+				 "          FROM units_positions "+
+				  "        GROUP BY units_positions.time_stamp, units_positions.unit_id) wrong "+
+				  " WHERE wrong.num > 1 ";
+		
+		ResultSet res = stmt.executeQuery(sel);
+		int i = 0;
+		String deltrans = "BEGIN; ";
+		while (res.next()) {
+			String sel2 =  "SELECT gid from units_positions where unit_id = "+ res.getLong("unit_id")
+							+ " AND time_stamp = '"+res.getString("time_stamp")+"'::timestamp";
+			
+			ResultSet res2 = SQLExecutor.getInstance().executeQuery(sel2);	
+			res2.next();
+			int delete =  res2.getInt("gid");
+			String del = "delete from units_positions where gid ="+delete + "; \n";
+
+
+			if (i<0) {
+				deltrans = deltrans + del;
+				i++;
+			} else {
+				deltrans = deltrans + " COMMIT;";
+				System.out.println("deleting ..." +deltrans );
+				try {
+					SQLExecutor.executeUpdate(deltrans);
+				} catch (PSQLException e) {
+					e.printStackTrace();
+				}
+				i = 0;
+				deltrans = "BEGIN; \n ";
+
+			}
+		}
+	}
+	public void checkTrack( long unit_id, Date time_stamp) throws SQLException, NoItemFoundException {
+		SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+		TrackData td = new TrackUtil().getTrack(unit_id, time_stamp);
+		/* select point from database **/
+		String sel_points  = "SELECT "+  UnitPosition.SELECT + " FROM units_positions WHERE time_stamp >= '" + formater.format(td.getStart()) + 
+		"' AND time_stamp <= '"+ formater.format(td.getEnd())+"' AND unit_id = "+ unit_id +";";
+		ResultSet res = stmt.executeQuery(sel_points);
+		List<UnitPosition> positions = (List<UnitPosition>)generateObjectList(new UnitPosition(), res);
+
+		for (UnitPosition pos : positions) {
+			System.out.println(pos.getGid() + ",  " + pos.getTime_stamp() + " " + pos.getX() + " " + pos.getY());
+		}
+		
+		
+	}
+		
+}

+ 252 - 0
src/main/java/cz/hsrs/db/util/DateUtil.java

@@ -0,0 +1,252 @@
+package cz.hsrs.db.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Utility class for parsing incoming timestamps as String to Date 
+ * @author mkepka
+ *
+ */
+public class DateUtil {
+
+    public static String patternSecs = "yyyy-MM-dd HH:mm:ss";
+    public static int patternSecsLen = 19;
+    /**
+     * yyyy-MM-dd HH:mm:ss
+     * length=19
+     */
+    public static SimpleDateFormat formatSecs = new SimpleDateFormat(patternSecs);
+    //--------------------------------------------------------------------------------------------
+    public static String patternSecsWT = "yyyy-MM-dd'T'HH:mm:ss";
+    public static int patternSecsWTLen = 19;
+    /**
+     * yyyy-MM-dd'T'HH:mm:ss
+     * length=19
+     */
+    public static SimpleDateFormat formatSecsWT = new SimpleDateFormat(patternSecsWT);
+    //--------------------------------------------------------------------------------------------
+    public static String patternMiliSecs = "yyyy-MM-dd HH:mm:ss.SSS";
+    public static int patternMiliSecsLen = 23;
+    /**
+     * yyyy-MM-dd HH:mm:ss.SSS
+     * length=23
+     */
+    public static SimpleDateFormat formatMiliSecs = new SimpleDateFormat(patternMiliSecs);
+    //--------------------------------------------------------------------------------------------
+    public static String patternMiliSecsWT = "yyyy-MM-dd'T'HH:mm:ss.SSS";
+    public static int patternMiliSecsWTLen = 23;
+    /**
+     * yyyy-MM-dd'T'HH:mm:ss.SSS
+     * length=23
+     */
+    public static SimpleDateFormat formatMiliSecsWT = new SimpleDateFormat(patternMiliSecsWT);
+    //--------------------------------------------------------------------------------------------
+    public static String patternSecsTZ = "yyyy-MM-dd HH:mm:ssZ";
+    public static int patternSecsTZLen = 24;
+    /**
+     * yyyy-MM-dd HH:mm:ssZ
+     * length=24
+     */
+    public static SimpleDateFormat formatSecsTZ = new SimpleDateFormat(patternSecsTZ);
+    //--------------------------------------------------------------------------------------------
+    public static String patternSecsTZwT = "yyyy-MM-dd'T'HH:mm:ssZ";
+    public static int patternSecsTZwTLen = 24;
+    /**
+     * yyyy-MM-ddTHH:mm:ssZ
+     * length=24
+     */
+    public static SimpleDateFormat formatSecsTZwT = new SimpleDateFormat(patternSecsTZwT);
+    //--------------------------------------------------------------------------------------------
+    public static String patternISO = "yyyy-MM-dd HH:mm:ssZZ:ZZ";
+    public static int patternISOLen = 25;
+    //--------------------------------------------------------------------------------------------
+    public static String patternMiliSecsTZ = "yyyy-MM-dd HH:mm:ss.SSSZ";
+    public static int patternMiliSecsTZLen = 28;
+    /**
+     * yyyy-MM-dd HH:mm:ss.SSSZ
+     * length=28
+     */
+    public static SimpleDateFormat formatMiliSecsTZ = new SimpleDateFormat(patternMiliSecsTZ);
+    //--------------------------------------------------------------------------------------------
+    public static String patternMiliSecsTZwT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
+    public int patternMiliSecsTZwTLen = 28;
+    /**
+     * yyyy-MM-ddTHH:mm:ss.SSSZ
+     * length=28
+     */
+    public static SimpleDateFormat formatMiliSecsTZwT = new SimpleDateFormat(patternMiliSecsTZwT);
+    //--------------------------------------------------------------------------------------------
+    public static String patternISOMilis = "yyyy-MM-dd HH:mm:ss.SSSZZ:ZZ";
+    public static int patternISOMilisLen = 29;
+    /**
+     * Method parses timestamp String to Date
+     * uses several patterns to test correct format
+     * @param time - timestamp as String
+     * @return Timestamp as Date
+     * @throws ParseException 
+     */
+    public static Date parseTimestamp(String time) throws ParseException{
+        boolean containsZ = time.contains("Z");
+        if(containsZ){
+            time = time.replace("Z", "+0000");
+        }
+        int len = time.length();
+        
+        char suffixTZ = time.charAt(len-3);
+        if(suffixTZ == '+' || suffixTZ == '-'){
+            time = time+"00";
+            len = time.length();
+        }
+        
+        boolean containsT = time.contains("T");
+        boolean containsSpace = time.contains(" ");
+        
+        if(len == patternSecsLen){
+            if(!containsT && containsSpace){
+                try {
+                    return formatSecs.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            }
+            else if(containsT && !containsSpace){
+                try {
+                    return formatSecsWT.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        }
+        else if(len == patternMiliSecsLen){
+            char dot = time.charAt(len-4);
+            boolean containsDot = false;
+            if(dot == '.'){
+                containsDot = true;
+            }
+            if(!containsT && containsSpace && containsDot){
+                try {
+                    return formatMiliSecs.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            }
+            else if(containsT && !containsSpace && containsDot){
+                try {
+                    return formatMiliSecsWT.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        }
+        else if(len == patternSecsTZLen){
+            if(!containsT && containsSpace){
+                try {
+                    return formatSecsTZ.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            }
+            else if(containsT && !containsSpace){
+                try {
+                    return formatSecsTZwT.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        }
+        else if(len == patternMiliSecsTZLen){
+            char dot = time.charAt(len-9);
+            boolean containsDot = false;
+            if(dot == '.'){
+                containsDot = true;
+            }
+            if(!containsT && containsSpace && containsDot){
+                try {
+                    return formatMiliSecsTZ.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            }
+            else if(containsT && !containsSpace && containsDot){
+                try {
+                    return formatMiliSecsTZwT.parse(time);
+                } catch (ParseException e) {
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        }
+        else if(len == patternISOLen){
+            char colonTZ = time.charAt(len-3);
+            if(colonTZ == ':'){
+                String part1 = time.substring(0, len-3);
+                String part2 = time.substring(len-2, len);
+                try{
+                    if(containsT){
+                        return formatSecsTZwT.parse(part1+part2);
+                    }else if(containsSpace){
+                        return formatSecsTZ.parse(part1+part2);
+                    } else{
+                        throw new ParseException("Unsupported pattern!", 0);
+                    }
+                } catch(ParseException e){
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        }
+        else if(len == patternISOMilisLen){
+            char colonTZ = time.charAt(len-3);
+            if(colonTZ == ':'){
+                String part1 = time.substring(0, len-3);
+                String part2 = time.substring(len-2, len);
+                try{
+                    if(containsT){
+                        return formatMiliSecsTZwT.parse(part1+part2);
+                    }else if(containsSpace){
+                        return formatMiliSecsTZ.parse(part1+part2);
+                    } else{
+                        throw new ParseException("Unsupported pattern!", 0);
+                    }
+                } catch(ParseException e){
+                    throw new ParseException(e.getMessage(), 0);
+                }
+            } else{
+                throw new ParseException("Unsupported pattern!", 0);
+            }
+        } else{
+            throw new ParseException("Unsupported pattern!", 0);
+        }
+    }
+    
+    /**
+     * yyyy-MM-dd HH:mm:ss.SSSsssZZZZZ
+     * @param microTime
+     * @throws ParseException 
+     */
+    public static Date parseTimestampMicro(String microTime) throws ParseException{
+        /* time string contains microseconds */
+        int len = microTime.length();
+        char suffixTZ = microTime.charAt(len-3);
+        if(suffixTZ == '+' || suffixTZ == '-'){
+            microTime = microTime+"00";
+            len = microTime.length();
+        }
+        
+        String milisTime = microTime.substring(0, patternMiliSecsLen);
+        String timeZone = microTime.substring(len-5, len);
+        
+        String subTime = ""+milisTime+timeZone;
+        return formatMiliSecsTZ.parse(subTime);
+    }
+}

+ 129 - 0
src/main/java/cz/hsrs/db/util/GroupUtil.java

@@ -0,0 +1,129 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import cz.hsrs.db.model.Group;
+import cz.hsrs.db.pool.SQLExecutor;
+
+public class GroupUtil extends ObservationUtil {
+
+    public GroupUtil() {
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<Group> getSuperGroups(String user_name)
+            throws SQLException {
+        String query = "SELECT groups.id, groups.group_name, groups.parent_group_id, groups.has_children"
+                + " FROM groups, system_users"
+                + " WHERE system_users.group_id = groups.id"
+                + " AND system_users.user_name = '" + user_name + "';";
+
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        return (List<Group>)generateObjectList(new Group(), res);
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<Group> getSubGroups(int parent_id)
+            throws SQLException {
+        String queryObservations = "SELECT groups.id, groups.group_name, groups.parent_group_id, groups.has_children"
+                + " FROM groups"
+                + " WHERE groups.parent_group_id = " + parent_id + ";";
+
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<Group>)generateObjectList(new Group(), res);
+    }
+
+    @SuppressWarnings("unchecked")
+    public  List<Group> getGroups(String user_name) throws SQLException {
+        String queryObservations = "SELECT groups.id, groups.group_name, groups.parent_group_id, groups.has_children"
+                + " FROM groups"
+                + " WHERE "+ this.getWhereStatemant(user_name, "groups.id") + ";";
+
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<Group>)generateObjectList(new Group(), res);
+    }
+
+    /** Return all ids that are owned by user name recursively. */
+    public List<Integer> getGroupIds(String user_name) throws SQLException {
+        String queryGroups = "SELECT group_id FROM system_users WHERE system_users.user_name = '"+user_name+"';";
+
+        ResultSet res = stmt.executeQuery(queryGroups);
+        res.next();
+        int id = res.getInt("group_id");
+        int this_id;
+
+        List<Integer> oldIds = new ArrayList<Integer>();
+        List<Integer> newIds = new ArrayList<Integer>();
+        List<Integer> finalIds = new ArrayList<Integer>();
+        oldIds.add(id);
+
+        while (oldIds.size() != 0) {
+            for (Integer oldId : oldIds) {
+                this_id = oldId;
+                finalIds.add(this_id);
+                queryGroups = "SELECT groups.id FROM groups WHERE "
+                        + "groups.parent_group_id = " + this_id + ";";
+                res = stmt.executeQuery(queryGroups);
+                while (res.next()) {
+                    newIds.add(res.getInt("id"));
+                }
+            }
+            oldIds.clear();
+            oldIds.addAll(newIds);
+            newIds.clear();
+        }
+        return finalIds;
+    }
+
+    /** Fills Where statement */
+    protected String getWhereStatemant(String user_name, String id_column) throws SQLException {
+        List<Integer> ids = getGroupIds(user_name);
+        String subquery = "";
+        for (Iterator<Integer> i = ids.iterator(); i.hasNext();) {
+            subquery = subquery + id_column + " = " + i.next();
+            if (i.hasNext()) {
+                subquery = subquery + " OR ";
+            }
+        }
+        return subquery;
+    }
+    
+    /**
+     * Method gets id of group by given name
+     * @param groupName - name of group
+     * @return id of group represents group.id
+     * @throws SQLException
+     */
+    public int getGroupIdByName(String groupName) throws SQLException{
+        String query = "SELECT id FROM groups WHERE group_name='"+groupName+"';";
+        ResultSet res = stmt.executeQuery(query);
+        if(res.next()){
+            return res.getInt(1);
+        } else{
+            throw new SQLException("Any group of given name doesn't exist!");
+        }
+    }
+
+    /**
+     * Method confirms that given group belongs to given user
+     * by selecting affiliated groups from database
+     * @param userName - name of user that is logged
+     * @param groupName - name of group
+     * @return true if given user is connected to given group, false otherwise
+     * @throws SQLException
+     */
+    public boolean checkGroupAffiliation2User(String userName, String groupName) throws SQLException{
+        int groupId = getGroupIdByName(groupName);
+        List<Integer> groupsOfUser = getGroupIds(userName);
+        for (Integer integer : groupsOfUser) {
+            if (integer == groupId) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 80 - 0
src/main/java/cz/hsrs/db/util/ManagementUtil.java

@@ -0,0 +1,80 @@
+package cz.hsrs.db.util;
+
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Phenomenon;
+import cz.hsrs.db.model.Sensor;
+import cz.hsrs.db.model.insert.UnitInsert;
+
+/**
+ * @author mkepka
+ */
+public class ManagementUtil extends DBUtil {
+	
+	public UnitInsert insertUnit(JSONObject payload, String username) throws NoItemFoundException, SQLException {
+		if(payload.containsKey("unit")){
+			JSONObject unitO = payload.getJSONObject("unit");
+			Long unitIdVal = unitO.containsKey("unit_id") ? unitO.getLong("unit_id") : null;
+	        String descVal = unitO.containsKey("description") ? unitO.getString("description") : null;
+
+	        List<Sensor> sensors = null;
+	        if(payload.containsKey("sensors")){
+	        	JSONArray sensorsArr = payload.getJSONArray("sensors");
+	            sensors = processSensors(sensorsArr);
+	        }
+
+	        if(unitIdVal == null && descVal == null){
+	        	throw new NoItemFoundException("Unit must be defined by ID or by description!");
+	        } else{
+	        	UnitInsert unit = new UnitInsert(unitIdVal, descVal, sensors);
+	            Integer groupId = UserUtil.getUserGroupId(username);
+                return unit.insertUnitToDB(groupId);
+	        }
+		} else {
+			throw new NoItemFoundException("Payload doesn't contain unit part!");
+		}
+	}
+
+    private List<Sensor> processSensors(JSONArray sensArr) throws NoItemFoundException{
+        List<Sensor> sensorsList = new LinkedList<Sensor>();
+        for(int i = 0;i < sensArr.size(); i++){
+            JSONObject sensorObj = sensArr.getJSONObject(i);
+            Long sensorId = sensorObj.containsKey("sensor_id") ? sensorObj.getLong("sensor_id") : null;
+            String sensorName = sensorObj.containsKey("sensor_name") ? sensorObj.getString("sensor_name") : null;
+            String sensorType = sensorObj.containsKey("sensor_type") ? sensorObj.getString("sensor_type") : null;
+
+            Phenomenon phen = null;
+            if(sensorObj.containsKey("phenomenon")){ 
+                JSONObject phenO = sensorObj.getJSONObject("phenomenon");
+                String phenId = phenO.containsKey("phenomenon_id") ? phenO.getString("phenomenon_id") : null;
+                String phenName = phenO.containsKey("phenomenon_name") ? phenO.getString("phenomenon_name") : null;
+                String uom = phenO.containsKey("uom") ? phenO.getString("uom") : null;
+
+                if((phenName == null && uom != null) || (phenName != null && uom == null)){
+                    throw new NoItemFoundException("Phenomenon must be defined by ID or by name and UoM!");
+                } else{
+                    phen = new Phenomenon(phenId, phenName, uom, null);
+                }
+            }
+            if(sensorName != null && sensorType != null && phen != null){
+                if(sensorId != null){
+                    sensorsList.add(new Sensor(sensorId, sensorName, sensorType, phen));
+                } else{
+                    sensorsList.add(new Sensor(sensorName, sensorType, phen));
+                }
+            } else{
+                if(sensorId != null){
+                    sensorsList.add(new Sensor(sensorId, null, null, null));
+                } else{
+                    throw new NoItemFoundException("Sensor must be defined by ID or by sensor_name, sensor_type and phenomenon!");
+                }
+            }
+        }
+        return sensorsList;
+    }
+}

+ 125 - 0
src/main/java/cz/hsrs/db/util/ObservationUtil.java

@@ -0,0 +1,125 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Observation;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.composite.ObservationMedlov;
+
+public class ObservationUtil extends SensorUtil {
+
+    private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+    
+    public ObservationUtil() {}
+    
+    public boolean insertObservation(Observation obs) throws SQLException{
+        return obs.insertToDb();
+    }
+    
+    public Observation getObservation(Date date, long unit_id, long sensor_id ) throws SQLException{
+        String query = "SELECT * FROM observations WHERE time_stamp = '" + FORMATTER.format(date) +"'"+
+                " AND unit_id = " + unit_id +
+                " AND sensor_id =" + sensor_id;
+        ResultSet res = stmt.executeQuery(query);
+        res.next();
+        return new Observation(res);
+    }
+    
+    public Observation getObservationBefore(UnitPosition p, long sensor_id) throws SQLException, NoItemFoundException{
+        UnitUtil ut = new UnitUtil();
+        int confTime = ut.getUnitConfTimeById(p.getUnit_id());
+        String q = "SELECT * FROM ("
+                + " SELECT * FROM observations"
+                    + " WHERE unit_id = " +p.getUnit_id() 
+                    + " AND sensor_id = "+ sensor_id
+                    + " AND time_stamp < timestamp'" + p.getTime_stamp() +"'"
+                    + " ORDER BY time_stamp DESC LIMIT 1)"
+                + " AS foo"
+                + " WHERE (timestamp'" + p.getTime_stamp()+ "' - time_stamp) < interval'"+confTime +" seconds';";
+        
+        ResultSet res = stmt.executeQuery(q);
+        if (res.next()) {
+            return new Observation(res);
+        } else
+            throw new NoItemFoundException("Last observation for " + p.getGid() + " not found.");
+    }
+
+    public UnitPosition getExactObservationPosition(int gid, long unit_id) throws SQLException, NoItemFoundException{
+        String query = "SELECT "+ UnitPosition.SELECT
+                        + " FROM last_units_positions"
+                        + " WHERE unit_id = "+unit_id
+                        + " AND gid = " + gid + ";";
+        ResultSet res = stmt.executeQuery(query);
+        
+        if (res.next()){
+            /* posledni pozice existuje */
+            return new UnitPosition(res);
+        } else {
+            String query2 = "SELECT "+ UnitPosition.SELECT
+                            + " FROM units_positions"
+                            + " WHERE unit_id = "+unit_id
+                            + " AND gid = " + gid+";";
+            ResultSet res2 = stmt.executeQuery(query2);
+            if (res2.next()){
+                return new UnitPosition(res2);
+            }
+        }
+        throw new NoItemFoundException(unit_id + " " +gid);
+    }
+    
+    public UnitPosition getExactObservationPosition(Date date, long unit_id) throws SQLException, NoItemFoundException{
+        String query = "SELECT "+ UnitPosition.SELECT
+                        + " FROM last_units_positions"
+                        + " WHERE unit_id = "+unit_id
+                        + " AND time_stamp = '" + FORMATTER.format(date)+"';";
+        ResultSet res = stmt.executeQuery(query);
+        
+        if (res.next()){
+            /* posledni pozice existuje */
+            return new UnitPosition(res);
+        } else {
+            String query2 = "SELECT "+ UnitPosition.SELECT
+                            + " FROM units_positions"
+                            + " WHERE unit_id = "+unit_id
+                            + " AND time_stamp = '" + FORMATTER.format(date)+"'"
+                            + " ORDER BY units_positions.time_stamp DESC LIMIT 1;";
+            ResultSet res2 = stmt.executeQuery(query2);
+            if (res2.next()){
+                return new UnitPosition(res2);
+            }
+        }
+        throw new NoItemFoundException(unit_id + FORMATTER.format(date));
+    }
+    
+    @SuppressWarnings("unchecked")
+    public List<ObservationMedlov> getObservationsMedlov(long unitIdFrom, long unitIdTo, String timeFrom, String timeTo) throws SQLException{
+        String query = "SELECT o.observation_id, o.unit_id, o.sensor_id, s.sensor_name, o.time_stamp, o.observed_value, p.unit, p.phenomenon_name, p.phenomenon_id, up.the_geom "+
+                        "FROM observations AS o " +
+                            "INNER JOIN sensors AS s ON s.sensor_id = o.sensor_id "+
+                            "INNER JOIN phenomenons AS p ON p.phenomenon_id = s.phenomenon_id "+
+                            "LEFT JOIN units_positions AS up ON o.gid = up.gid "+
+                        "WHERE o.time_stamp > '"+ timeFrom +"' AND o.time_stamp < '"+timeTo+"' "+
+                        "AND o.unit_id >= "+unitIdFrom+" AND o.unit_id <= "+unitIdTo +
+                        " ORDER BY o.time_stamp;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<ObservationMedlov>)generateObjectList(new ObservationMedlov(), res);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public List<ObservationMedlov> getObservationsMedlov(String timeFrom, String timeTo) throws SQLException{
+        String query = "SELECT o.observation_id, o.unit_id, o.sensor_id, s.sensor_name, o.time_stamp, o.observed_value, p.unit, p.phenomenon_name, p.phenomenon_id, up.the_geom "+
+                        "FROM observations AS o " +
+                            "INNER JOIN sensors AS s ON s.sensor_id = o.sensor_id "+
+                            "INNER JOIN phenomenons AS p ON p.phenomenon_id = s.phenomenon_id "+
+                            "LEFT JOIN units_positions AS up ON o.gid = up.gid "+
+                        "WHERE o.time_stamp > '"+ timeFrom +"' AND o.time_stamp < '"+timeTo+"' "+
+                        " ORDER BY o.time_stamp;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<ObservationMedlov>)generateObjectList(new ObservationMedlov(), res);
+    }
+}

+ 559 - 0
src/main/java/cz/hsrs/db/util/SensorUtil.java

@@ -0,0 +1,559 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+import cz.hsrs.db.model.Phenomenon;
+import cz.hsrs.db.model.Sensor;
+import cz.hsrs.db.model.composite.AggregateObservation;
+import cz.hsrs.db.model.composite.ObservationValue;
+import cz.hsrs.db.model.composite.UnitSensor;
+import cz.hsrs.db.model.composite.UnitSensorObservation;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * Class provides methods for publishing observations
+ * @author jezekjan
+ *
+ */
+public class SensorUtil extends TrackUtil {
+
+    /**
+     * Empty constructor
+     */
+    public SensorUtil() {
+        super();
+    }
+
+    /**
+     * Method gets list of sensors connected to given unit
+     * @param unit_id - identifier of unit
+     * @return list of UnitSensor objects represents sensors connected to given unit
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<UnitSensor> getUnitsSensors(long unit_id) throws SQLException {
+        String queryObservations = "SELECT *"
+                + " FROM sensors, units_to_sensors "
+                + "WHERE units_to_sensors.unit_id = " + unit_id
+                + " AND units_to_sensors.sensor_id = sensors.sensor_id;";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<UnitSensor>) generateObjectList(new UnitSensor(), res);
+    }
+    
+    /**
+     * Method gets list of sensors connected to given unit
+     * @param unit_id - identifier of unit
+     * @return list of Sensor objects represents sensors connected to given unit
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<Sensor> getSensors(long unit_id) throws SQLException {
+        String queryObservations = "SELECT *"
+                + " FROM sensors, units_to_sensors"
+                + " WHERE units_to_sensors.unit_id = " + unit_id
+                + " AND units_to_sensors.sensor_id = sensors.sensor_id ORDER BY sensors.sensor_id;";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<Sensor>) generateObjectList(new Sensor(), res);
+    }
+
+    /**
+     * Method gets description of sensor by given identifier
+     * @param sensor_id - identifier of sensor
+     * @return Sensor object with all attributes 
+     * @throws SQLException
+     */
+    public Sensor getSensorById(long sensor_id) throws SQLException {
+        String queryObservations = "SELECT * FROM sensors "
+                + "WHERE sensor_id = " + sensor_id + ";";
+        ResultSet res = stmt.executeQuery(queryObservations);
+
+        if (res.next()) {
+            return (Sensor) (new Sensor()).getDBObject(res);
+        } else {
+            throw new SQLException("Sensor " + sensor_id + " not found!");
+        }
+    }
+    
+    /**
+     * Method checks if there is sensor in DB, given by Id or sensor name
+     * @param sensorId - id of sensor
+     * @param sensorName - name of sensor
+     * @return Sensor object from DB or null if there is not sensor with given id nor name
+     * @throws SQLException
+     */
+    public Sensor getSensorByIdOrName(Long sensorId, String sensorName) throws SQLException {
+        if(sensorId == null && sensorName != null){
+            String query = "SELECT * FROM sensors WHERE sensor_name = '" + sensorName + "';";
+            ResultSet res = stmt.executeQuery(query);
+            if (res.next()) {
+                return (Sensor) (new Sensor()).getDBObject(res);
+            } else {
+                return null;
+            }
+        }
+        else if(sensorId != null && sensorName == null){
+            String query = "SELECT * FROM sensors WHERE sensor_id = " + sensorId + ";";
+            ResultSet res = stmt.executeQuery(query);
+            if (res.next()) {
+                return (Sensor) (new Sensor()).getDBObject(res);
+            } else {
+                return null;
+            }
+        } else{
+            throw new SQLException("Either sensor_id or sensor_name must be given!");
+        }
+    }
+
+    /**
+     * Method selects Sensor by given sensor_name, sensor_type and phenomenon_id
+     * @param sensorName 
+     * @param sensorType
+     * @param phenId
+     * @return Sensor object from DB if there is in DB, null if there is not
+     * @throws SQLException
+     */
+    public Sensor getSensorByNameAndTypeAndPhen(String sensorName, String sensorType, String phenId) throws SQLException {
+        String query = "SELECT * FROM sensors WHERE sensor_name = '" + sensorName + "'"
+                + " AND sensor_type = '"+sensorType+"' AND phenomenon_id = '"+phenId+"';";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return (Sensor) (new Sensor()).getDBObject(res);
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Method gets next value of sensor_id sequence
+     * @return next value of sensor_id or null if there is not possible to get next value
+     * @throws SQLException
+     */
+    public Long getNextSensorId() throws SQLException{
+        boolean exists = true;
+        Long newId = null;
+        while(exists){
+            try{
+                String selectId = "SELECT nextval('sensors_sensor_id_seq'::regclass);";
+                ResultSet resId = SQLExecutor.getInstance().executeQuery(selectId);
+                if(resId.next()){
+                    newId = resId.getLong(1);
+                } else{
+                    throw new SQLException("Sensor can't get new ID!");
+                }
+                Sensor isSame = this.getSensorByIdOrName(newId, null);
+                if(isSame == null){
+                    exists = false;
+                }
+            } catch(SQLException e){
+                throw new SQLException("Sensor can't get new ID!");
+            }
+        }
+        return newId;
+    }
+    
+    /**
+     * Method detects if given sensor is connected to given unit
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor
+     * @return true if given sensor is connected to given unit, false if not
+     * @throws SQLException
+     */
+    public boolean hasSensor(long unit_id, long sensor_id) throws SQLException {
+        String query = "SELECT * FROM units_to_sensors"
+                + " WHERE units_to_sensors.unit_id = " + unit_id
+                + " AND units_to_sensors.sensor_id = " + sensor_id;
+        ResultSet res = stmt.executeQuery(query);
+        return res.next();
+    }
+
+    /**
+     * Method gets list of observations for given unit-sensor pair and given time stamp interval
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor 
+     * @param from - begin time stamp of time range, optional
+     * @param to - end time stamp of time range, optional
+     * @return list of ObservationValue objects represents observations for given unit-sensor pair for given time stamps
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<ObservationValue> getSensorObservations(long unit_id, long sensor_id, String from, String to) throws SQLException {
+        if (from == null && to == null) {
+            return getSensorObservations(unit_id, sensor_id);
+        } else if (to == null && from != null) {
+            return getSensorObservationsFrom(unit_id, sensor_id, from);
+        } else if (to != null && from == null) {
+            return getSensorObservationsTo(unit_id, sensor_id, to);
+        } else {
+            String query = "SELECT gid, observed_value, time_stamp"
+                    + " FROM observations"
+                    + " WHERE unit_id = " + unit_id
+                    + " AND sensor_id = " + sensor_id 
+                    + " AND time_stamp > '" + from + "'"
+                    + " AND time_stamp < '" + to + "'";
+            ResultSet res = stmt.executeQuery(query);
+            return (List<ObservationValue>) generateObjectList(new ObservationValue(), res);
+        }
+    }
+
+    /**
+     * Method gets list of observations for given unit-sensor pair and given time stamp interval and trunc parameter
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor 
+     * @param from - begin time stamp of time range, mandatory
+     * @param to - end time stamp of time range, mandatory
+     * @param trunc - truncate parameter
+     * @return list of AggregateObservation objects represents observations for given unit-sensor pair for given time stamp and truncate
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<AggregateObservation> getSensorObservationsTrunc(long unit_id, long sensor_id, String from, String to, String trunc) throws SQLException {
+        String queryObservations = "SELECT"
+                + " avg(observed_value) as avg_value,"
+                + " date_trunc('" + trunc + "', time_stamp) AS dtrunc,"
+                + " count(*) AS count "
+                + " FROM observations WHERE unit_id = " + unit_id
+                + " AND sensor_id = " + sensor_id 
+                + " AND time_stamp >= '" + from + "'"
+                + " AND time_stamp <= '" + to + "'"
+                + " GROUP BY dtrunc ORDER BY dtrunc DESC;";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<AggregateObservation>) generateObjectList(new AggregateObservation(), res);
+    }
+
+    /**
+     * Method gets list of observations for given unit-sensor pair from given timestamp
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor 
+     * @param from - timestamp represents beginning of given time range
+     * @return list of ObservationValue objects represents observations for given unit-sensor pair from given time stamp
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    protected List<ObservationValue> getSensorObservationsFrom(long unit_id, long sensor_id, String from) throws SQLException {
+        String queryObservations = "SELECT gid, observed_value, time_stamp"
+                + " FROM observations WHERE unit_id = " + unit_id
+                + " AND sensor_id = " + sensor_id
+                + " AND time_stamp > '" + from + "'";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<ObservationValue>) generateObjectList(new ObservationValue(), res);
+    }
+
+    /**
+     * Method gets list of observations for given unit-sensor pair till given end timestamp
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor 
+     * @param to - timestamp represents end of given time range 
+     * @return list of ObservationValue objects represents observations for given unit-sensor pair until given time stamp
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    protected List<ObservationValue> getSensorObservationsTo(long unit_id, long sensor_id, String to) throws SQLException {
+        String queryObservations = "SELECT gid, observed_value, time_stamp"
+                + " FROM observations WHERE unit_id = " + unit_id
+                + " AND sensor_id = " + sensor_id
+                + " AND time_stamp < '" + to + "'";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<ObservationValue>) generateObjectList(new ObservationValue(), res);
+    }
+
+    /**
+     * Method gets list of observations for given unit-sensor pair
+     * @param unit_id - identifier of unit
+     * @param sensor_id - identifier of sensor 
+     * @return list of ObservationValue objects represents all observations for given unit-sensor pair
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<ObservationValue> getSensorObservations(long unit_id, long sensor_id) throws SQLException {
+        String queryObservations = "SELECT gid, observed_value, time_stamp"
+                    + " FROM observations WHERE unit_id = " + unit_id
+                    + " AND sensor_id = " + sensor_id + ";";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<ObservationValue>) generateObjectList(new ObservationValue(), res);
+    }
+    
+    /**
+     * Select phenomenon by given ID
+     * @param id - phenomenonId of phenomenon to select
+     * @return Phenomenon object if there is phenomenon in DB or null if there is not
+     * @throws SQLException
+     */
+    public Phenomenon getPhenomenonById(String id) throws SQLException {
+        String queryObservations = "SELECT * FROM phenomenons"
+                + " WHERE phenomenon_id = '" + id + "';";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        if (res.next()) {
+            return new Phenomenon(res);
+        } else
+            return null;
+    }
+    
+    /**
+     * Select phenomenon by given name
+     * @param phenName - name of phenomenon to select
+     * @return Phenomenon object if there is phenomenon in DB or null if there is not
+     * @throws SQLException
+     */
+    public Phenomenon getPhenomenonByName(String phenName) throws SQLException{
+        String query = "SELECT * FROM phenomenons WHERE phenomenon_name='"+phenName+"';";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res.next()){
+            return new Phenomenon(res);
+        } else{
+            return null;
+        }
+    }
+    
+    /**
+     * Method get next value of phenomenonId sequence
+     * @return next value of phenomenonId, null if there is not possible to get next value 
+     * @throws SQLException
+     */
+    public String getNextPhenomenonId() throws SQLException{
+        boolean exists = true;
+        String newId = null;
+        while(exists){
+            try{
+                String selectId = "SELECT nextval('phenomenons_id_seq'::regclass);";
+                ResultSet res = SQLExecutor.getInstance().executeQuery(selectId);
+                if(res.next()){
+                    newId = res.getString(1);
+                } else{
+                    throw new SQLException("Phenomenon can't get new ID!");
+                }
+                Phenomenon isSame = getPhenomenonById(newId);
+                if(isSame == null){
+                    exists = false;
+                }
+            } catch(SQLException e){
+                throw new SQLException("Phenomenon can't get new ID!");
+            }
+        }    
+        return newId;
+    }
+    
+    /**
+     * Method checks if there is same phenomenon already in the DB
+     * @param phen Phenomenon to be checked
+     * @return Phenomenon object that is already in the DB, null if there is not any 
+     * @throws SQLException
+     */
+    public Phenomenon isPhenomenonInDB(Phenomenon phen) throws SQLException{
+        if(phen.internalGetPhenomenonId() != null){
+            Phenomenon phenDB = getPhenomenonById(phen.internalGetPhenomenonId());
+            return phenDB;
+        } else if(phen.getPhenomenonName() != null && phen.getUnit() != null){
+            Phenomenon phenDB = getPhenomenonByName(phen.getPhenomenonName());
+            if(phenDB == null){
+                return null;
+            } else{
+                if(phen.internalGetPhenomenonId() == null){
+                    phen.internalSetPhenomenonId(phenDB.internalGetPhenomenonId());
+                }
+                return phenDB;
+            }
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Method checks if there is already same sensor in the DB
+     * @param sen Sensor to be checked
+     * @return Sensor object that is already in the DB, null if there is not any
+     * @throws SQLException 
+     */
+    public Sensor isSensorInDB(Sensor sen) throws SQLException{
+        if(sen.getSensorId() != 0){
+            return getSensorByIdOrName(sen.getSensorId(), null);
+        } else if(sen.getSensorName() != null
+                && sen.getSensorType() != null 
+                && sen.getPhenomenon() != null)
+        {
+            Sensor senDB = getSensorByIdOrName(null, sen.getSensorName());
+            if(senDB != null){
+                Sensor sensorSame = getSensorByNameAndTypeAndPhen(
+                        sen.getSensorName(), sen.getSensorType(),
+                        sen.getPhenomenon().internalGetPhenomenonId());
+                if(sensorSame == null){
+                    throw new SQLException("Sensor with given name is already registered!");
+                } else {
+                    return sensorSame;
+                }
+            } else {
+                return null;
+            }
+        } 
+        else{
+            return null;
+        }
+    }
+    
+    /**
+     * Method try tests if there is same Sensor in the DB
+     * @param sen Sensor object to be compared
+     * @return Sensor object from DB if there is same as given, null if there is not same
+     * @throws SQLException
+     */
+    public Sensor isSameSensorInDB(Sensor sen) throws SQLException{
+        if(sen.getSensorId() != 0){
+            return getSensorByIdOrName(sen.getSensorId(), null);
+        } else if(sen.getSensorName() != null
+                && sen.getSensorType() != null 
+                && sen.getPhenomenon() != null)
+        {
+            Sensor senDB = getSensorByIdOrName(null, sen.getSensorName());
+            if(senDB != null){
+                Sensor sensorSame = getSensorByNameAndTypeAndPhen(
+                        sen.getSensorName(), sen.getSensorType(),
+                        sen.getPhenomenon().internalGetPhenomenonId());
+                if(sensorSame == null){
+                    throw new SQLException("Sensor with given name is already registered!");
+                } else {
+                    return sensorSame;
+                }
+            } else {
+                return null;
+            }
+        } else{
+            return null;
+        }
+    }
+    
+    /**
+     * Method checks if given sensor is paired with given unit
+     * @param sensorId - id of sensor
+     * @param unitId - id of unit
+     * @return true if sensor is paired, false if not
+     * @throws SQLException
+     */
+    public boolean isSensorPairedToUnit(long sensorId, long unitId) throws SQLException{
+        String query = "SELECT sensor_id, unit_id FROM units_to_sensors WHERE unit_id ="+unitId+" AND sensor_id ="+sensorId+";";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        return res.next();
+    }
+    /**
+     * Method inserts new sensor in DB
+     * @param sen - Sensor to be inserted
+     * @return either (1) the row count for SQL DML statements or (2) 0 for SQL statements that return nothing
+     * @throws SQLException
+     */
+    public int insertSensor(Sensor sen) throws SQLException{
+        String ins = "INSERT INTO sensors (sensor_id, sensor_name, sensor_type, phenomenon_id)"
+                + " VALUES ("+sen.getSensorId()
+                +", '"+sen.getSensorName()
+                +"', '"+sen.getSensorType()
+                +"', '"+sen.getPhenomenon().internalGetPhenomenonId()+"');";
+        return SQLExecutor.executeUpdate(ins);
+    }
+    
+    /**
+     * Method pairs unit to sensor 
+     * @param unitId - id of unit
+     * @param sensorId - id of sensor
+     * @return either (1) the row count for SQL DML statements or (2) 0 for SQL statements that return nothing
+     * @throws SQLException
+     */
+    public int pairUnitToSensor(long unitId, long sensorId) throws SQLException{
+        String insUS = "INSERT INTO units_to_sensors(unit_id, sensor_id) VALUES("+unitId+", "+sensorId+");";
+        return SQLExecutor.executeUpdate(insUS);
+    }
+    
+    /**
+     * Method inserts new Phenomenon in DB
+     * @param phen Phenomenon object to be inserted, all attributes must by given
+     * @return either (1) the row count for SQL DML statements or (2) 0 for SQL statements that return nothing
+     * @throws SQLException 
+     */
+    public int insertNewPhenomenon(Phenomenon phen) throws SQLException{
+        String ins = "INSERT INTO phenomenons (phenomenon_id, phenomenon_name, unit)"
+                + " VALUES ('"+phen.internalGetPhenomenonId()
+                +"', '"+phen.getPhenomenonName()
+                +"', '"+phen.getUnit()+"');";
+        return SQLExecutor.executeUpdate(ins);
+    }
+
+    /**
+     * Method gets last observation for given unit-sensor pair
+     * @param unitId - identifier of unit
+     * @param sensorId - identifier of sensor 
+     * @return ResultSet object represents last observation for given unit-sensor pair
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+	public List<ObservationValue> getSensorLastObservation(long unitId, long sensorId) throws SQLException {
+        String query = "SELECT time_stamp, gid, observed_value"
+                    + " FROM units_to_sensors uts"
+                    + " LEFT JOIN observations o ON uts.last_obs = o.time_stamp"
+                    + " WHERE uts.unit_id = "+unitId
+                    + " AND uts.sensor_id = "+sensorId
+                    + " AND uts.sensor_id = o.sensor_id;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<ObservationValue>) generateObjectList(new ObservationValue(), res);
+    }
+    
+    /**
+     * Method gets list of last observations from all connected sensors for given unit
+     * @param unitId - identifier of unit
+     * @return list of UnitSensorObservation objects represents last observations from all connected sensors to given unit
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<UnitSensorObservation> getUnitSensorsLastObservations(long unitId) throws SQLException{
+        String query = "SELECT time_stamp, gid, observed_value, o.sensor_id, o.unit_id"
+                    + " FROM units_to_sensors uts"
+                    + " LEFT JOIN observations o ON uts.last_obs = o.time_stamp"
+                    + " WHERE uts.unit_id = " + unitId
+                    + " AND uts.sensor_id = o.sensor_id;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<UnitSensorObservation>) generateObjectList(new UnitSensorObservation(), res);
+    }
+    
+    /**
+     * Method gets list of last observations from all connected sensors to all units belonging to given group
+     * @param groupName - name of group
+     * @return list of UnitSensorObservation objects represents last observations from all connected sensors to all units
+     * belonging to given group
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<UnitSensorObservation> getUnitsSensorsLastObservations(String groupName) throws SQLException{
+        String query = "SELECT time_stamp, gid, observed_value, o.sensor_id, o.unit_id"
+                    + " FROM groups g, units_to_groups utg, units_to_sensors uts"
+                    + " LEFT JOIN observations o ON uts.last_obs = o.time_stamp"
+                    + " WHERE g.group_name = '"+groupName+"'"
+                    + " AND g.id = utg.group_id"
+                    + " AND utg.unit_id = uts.unit_id"
+                    + " AND uts.unit_id = o.unit_id"
+                    + " AND uts.sensor_id = o.sensor_id"
+                    + " ORDER BY uts.unit_id, uts.sensor_id;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<UnitSensorObservation>) generateObjectList(new UnitSensorObservation(), res);
+    }
+
+    /**
+     * Method gets list of last observations of given connected sensor of all units belonging to given group.
+     * @param groupName - name of group
+     * @param sensorId - identifier of sensor
+     * @return list of UnitSensorObservation objects represents last observations for given connected sensors to all units
+     * belonging to given group
+     * @throws SQLException
+     */
+    @SuppressWarnings("unchecked")
+    public List<UnitSensorObservation> getUnitsSensorsLastObservations(String groupName, long sensorId) throws SQLException{
+        String query = "SELECT time_stamp, gid, observed_value, o.sensor_id, o.unit_id"
+                + " FROM groups g, units_to_groups utg, units_to_sensors uts"
+                + " LEFT JOIN observations o ON uts.last_obs = o.time_stamp"
+                + " WHERE g.group_name = '"+groupName+"'"
+                + " AND g.id = utg.group_id"
+                + " AND utg.unit_id = uts.unit_id"
+                + " AND uts.sensor_id = "+sensorId
+                + " AND uts.unit_id = o.unit_id"
+                + " AND uts.sensor_id = o.sensor_id"
+                + " ORDER BY uts.unit_id, uts.sensor_id;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<UnitSensorObservation>) generateObjectList(new UnitSensorObservation(), res);
+    }
+}

+ 67 - 0
src/main/java/cz/hsrs/db/util/ServerUtil.java

@@ -0,0 +1,67 @@
+package cz.hsrs.db.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class ServerUtil extends DBUtil {
+
+	public ServerUtil() {}
+
+	public List<URL> getBackupUrl() throws SQLException, MalformedURLException {
+		LinkedList<URL> urls = new LinkedList<URL>();
+		String query = "SELECT * FROM server.backup_server;";
+		ResultSet res = stmt.executeQuery(query);
+		while (res.next()) {
+			urls.add(new URL(res.getString("url")));
+		}
+		return urls;
+	}
+
+	public void callServers(List<URL> urls, final String query)
+			throws MalformedURLException {
+		for (final URL url : urls) {
+			final URL urlreq = new URL(url.toString() + "?" + query);
+			(new CallServer(urlreq, System.out)).start();
+
+		}		
+
+	}
+
+	private static class CallServer extends Thread {
+
+		private final URL url;
+		private final PrintStream ps;
+		private final Map<String, String> resp;
+
+		CallServer(URL url, PrintStream ps) {
+			this.url = url;
+			this.ps = ps;
+			this.resp = new HashMap<>();
+		}
+
+		public void run() {
+			try {
+				final BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
+				ps.println(url.toString()+ "..." + in.readLine());
+			} catch (IOException e) {
+				ps.println(url.toString()+ "..." + e.getMessage());;				
+			}
+		}
+
+		public Map<String, String> getResp() {
+			return resp;
+		}				
+	}
+}

+ 235 - 0
src/main/java/cz/hsrs/db/util/TrackUtil.java

@@ -0,0 +1,235 @@
+package cz.hsrs.db.util;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Observation;
+import cz.hsrs.db.model.TrackData;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.composite.UnitSensor;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.track.TrackIgnitionSolver;
+
+public class TrackUtil extends UnitUtil {
+	
+	
+	public TrackUtil() {
+		super();
+	}
+	SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+	
+	
+	public int deleteRunningTrack(long unit_id) throws SQLException {
+		String queryConf = "delete from running_tracks where unit_id =" + unit_id;
+		return SQLExecutor.executeUpdate(queryConf);
+	}
+
+	public TrackData getNewerTrack(long unit_id, Date date) throws SQLException , NoItemFoundException {
+		String query = "SELECT " +
+				TrackData.SELECT +
+				" FROM units_tracks WHERE unit_id="
+				+ unit_id + " AND track_start > '" + formater.format(date)
+				+ "' ORDER BY track_start LIMIT 1; ";
+		ResultSet res = stmt.executeQuery(query);
+		if (res.next()){
+			return new TrackData(res);
+			} else throw new NoItemFoundException("getNewerTrack for "+unit_id+" "+date +" does not exist");
+	}
+	
+	public TrackData getOlderTrack(long unit_id, Date date) throws SQLException, NoItemFoundException {		
+		String query = "SELECT " +
+		 		TrackData.SELECT + 
+				" FROM units_tracks WHERE unit_id="
+				+ unit_id + " AND track_end < '" + formater.format(date)
+				+ "' ORDER BY track_end  DESC  LIMIT 1; ";
+		ResultSet res = stmt.executeQuery(query);
+		if (res.next()){
+			return new TrackData(res);
+		} else {
+			throw new NoItemFoundException("getOlderTrack for "+unit_id+" "+date +" does not exist");
+		}
+	}
+	
+	public UnitPosition getPositionByTime(long unit_id, Date date) throws SQLException, NoItemFoundException {
+		String query = "SELECT " +
+				UnitPosition.SELECT +
+				" FROM units_positions WHERE " +
+				"unit_id =" + unit_id + " AND " +
+				"time_stamp = '" +formater.format(date)+ "';";
+		ResultSet res = stmt.executeQuery(query);
+		if (res.next()){
+			return new UnitPosition(res);
+		} else {
+			throw new NoItemFoundException("getPositionByTime for "+unit_id+" "+date +" does not exist");
+		}
+		
+	}
+	
+	public boolean addToTrack(TrackData track, UnitPosition p) throws SQLException {
+		// zjisti pocet pozic pred v tracku 
+		
+		String query = "SELECT count(gid) FROM units_positions where time_stamp < '" +
+		p.internalGetTimestamp() +
+		"' AND time_stamp >= '" +
+		track.getStart() +
+		"' AND unit_id = " +
+		p.getUnit_id();  
+		ResultSet res = stmt.executeQuery(query);
+		res.next();
+		
+		//vloz na i-tou pozici
+		String update = "SELECT addPositionToTrack("+track.getGid() +","+ p.getGid()+","+ (res.getInt(1)) +");";
+		ResultSet res2 = stmt.executeQuery(update);
+		res2.next();
+		return res2.getBoolean(1);
+	}
+	
+	public boolean joinTrack(TrackData t1, TrackData t2) throws SQLException {
+		String qer = "SELECT mergetracks(" +
+				t1.getGid()+"," +
+				t2.getGid()+");";
+		ResultSet res = stmt.executeQuery(qer);
+		res.next();
+		return res.getBoolean(1);
+	}
+	
+
+	public int startTrack(UnitPosition pos1, UnitPosition pos2) throws SQLException {
+		String getGID = "SELECT nextval('units_tracks_gid_seq'::regclass)";
+		ResultSet resg = stmt.executeQuery(getGID);
+		resg.next();
+		int gid = resg.getInt(1);
+		
+		String  qer= " INSERT INTO units_tracks(gid, the_geom, unit_id, track_start, track_end) " +
+				"values (" +
+				gid+
+				", st_geomfromtext('LINESTRING("+ pos1.getX()+ " "+pos1.getY()+", "
+											 + pos2.getX()+ " "+pos2.getY()+")',4326), "
+				+ pos1.getUnit_id()+", "
+				+"timestamp with time zone '"+pos1.getTime_stamp()+"', "
+				+"timestamp with time zone '"+pos2.getTime_stamp()+"')";	
+		
+		SQLExecutor.executeUpdate(qer);
+		return gid;
+	}
+	
+	public boolean startTrack(UnitPosition pos) throws SQLException {
+		String  qer= "SELECT startTrack(timestamp with time zone'"+pos.internalGetTimestamp() +"',"+pos.getUnit_id()+")";
+		ResultSet res = stmt.executeQuery(qer);
+		res.next();
+		return res.getBoolean(1);
+	}
+	
+	
+	public boolean splitTrack(UnitPosition pos, TrackData track) throws SQLException {
+		String  qer = "SELECT _split_track("+ pos.getPostgisString()+", "+
+						track.getGid()+
+						", timestamp with time zone '"+pos.internalGetTimestamp() +"')";
+		ResultSet res = stmt.executeQuery(qer);
+		res.next();
+		return res.getBoolean(1);
+	}
+	
+	public boolean startTrackByIgnition(UnitPosition pos, boolean closed) throws SQLException {
+		ObservationUtil ut = new ObservationUtil();
+		UnitUtil uut = new UnitUtil();
+		Observation before = null;
+		try {
+			 before = ut.getObservationBefore(pos, TrackIgnitionSolver.IGNITION_SENSOR_ID);			
+		} catch (NoItemFoundException e) {
+			e.printStackTrace();
+		}
+		
+		String  qer= "SELECT startTrack2(timestamp with time zone '"+pos.internalGetTimestamp() +"',"+pos.getUnit_id()+", " + closed+ ")";
+		
+		ResultSet res = stmt.executeQuery(qer);
+		res.next();
+		
+		if (before!=null && before.getObservedValue()==0){
+			try {
+				UnitPosition bef = uut.getPositionByGid(before.getGid());
+				TrackData track = getTrack(pos.getUnit_id(), pos.internalGetTimestamp());
+				addToTrack(track, bef);
+			} catch (NoItemFoundException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		return res.getBoolean(1);
+	}
+	
+	public int setTrackIsClosedByIgnition(TrackData track, UnitPosition p, boolean closed) throws SQLException {
+		
+		UnitUtil u = new UnitUtil();
+		int interval = 0;
+		try {
+			interval = u.getUnitConfTimeById(p.getUnit_id());
+		} catch (NoItemFoundException e) {
+			e.printStackTrace();
+		}
+		if (( p.internalGetTimestamp().getSeconds() - track.getEnd().getSeconds())< interval){
+			addToTrack(track, p);
+		}
+		
+		String update = "UPDATE units_tracks SET is_closed ="+ closed+" WHERE gid = "+track.getGid();
+		return SQLExecutor.executeUpdate(update);
+		
+	}
+	public TrackData getTrack(long unit_id, Date time_stamp) throws SQLException, NoItemFoundException {
+		
+		String  qer= "SELECT "+TrackData.SELECT+" FROM units_tracks where unit_id =" +
+				unit_id + " AND track_start <= '"
+				+ time_stamp + "' AND track_end >= '"
+				+time_stamp+"'";			
+		ResultSet res = stmt.executeQuery(qer);
+		if (res.next()) {
+			return new TrackData(res);
+	  	} else {
+			throw new NoItemFoundException("getTrack for "+unit_id+" "+time_stamp +" does not exist");
+		}
+	}	
+	
+	public boolean hasTrack(long unit_id) throws SQLException {
+		String  qer= "SELECT gid FROM units_tracks where unit_id =" +
+				unit_id ;		
+		ResultSet res = stmt.executeQuery(qer);
+		return res.next();
+	}	
+	
+	public boolean hasTrack(long unit_id, Date time_stamp) throws SQLException {
+		String  qer= "SELECT gid FROM units_tracks where unit_id =" +
+				unit_id + " AND track_start <= '"
+				+ time_stamp + "' AND track_end >= '"
+				+time_stamp+"'";	
+		ResultSet res = stmt.executeQuery(qer);
+		return res.next();
+	}	
+	
+	
+	public int getTrackLenght(int gid) throws SQLException, NoItemFoundException {
+		String qer = "Select ST_NumPoints(the_geom) FROM units_tracks WHERE gid = "+gid;
+		ResultSet res = stmt.executeQuery(qer);
+		if (res.next()) {
+			return res.getInt(1);
+	  	} else {
+			throw new NoItemFoundException("getTrackLenght for "+gid+" does not exist");
+		}
+	}
+
+	/** Pro test pridat metodu na poictani bodu v tracku */
+	public boolean wasEngineOn(long unit_id, Date from, Date to) throws SQLException{
+		String sel = "SELECT observed_value FROM observations where unit_id =" + unit_id + " AND " +
+					" sensor_id = "+ TrackIgnitionSolver.IGNITION_SENSOR_ID + " AND " +
+					" time_stamp >= '" + formater.format(from) +"'::timestamp with time zone AND "+ 
+					" time_stamp <= '" + formater.format(to) +"'::timestamp with time zone AND "+
+					" observed_value = 1" ;
+		ResultSet res = stmt.executeQuery(sel);			
+		return res.next();
+	}
+}

+ 354 - 0
src/main/java/cz/hsrs/db/util/UnitUtil.java

@@ -0,0 +1,354 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import cz.hsrs.db.model.IgnitionStatus;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.model.UnitDriver;
+import cz.hsrs.db.model.UnitHolder;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.composite.LastPosition;
+import cz.hsrs.db.model.custom.DBItemInfo;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.factory.UnitPositionFactory;
+
+/**
+ * @author jezekjan
+ */
+public class UnitUtil extends DBUtil {
+    
+    private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+
+    public UnitUtil() {
+        super();
+    }
+
+    public int deleteUnit(long unit_id) throws SQLException {
+        String delete_unit = "DELETE FROM units WHERE unit_id = " + unit_id + ";";
+        return SQLExecutor.executeUpdate(delete_unit);
+    }
+
+    public int deleteHolder(int holder_id) throws SQLException {
+        String delete_unit = "DELETE FROM unit_holders WHERE holder_id =" + holder_id;
+        return SQLExecutor.executeUpdate(delete_unit);
+    }
+
+    public int deleteHolder(String hname) throws SQLException {
+        String delete_unit = "DELETE FROM unit_holders WHERE holder_name = '" + hname + "'";
+        return SQLExecutor.executeUpdate(delete_unit);
+    }
+
+    public int deleteDriver(int driver_id) throws SQLException {
+        String delete_driver = "DELETE FROM unit_drivers WHERE driver_id = '" + driver_id + "'";
+        return SQLExecutor.executeUpdate(delete_driver);
+    }
+    
+    public int deleteDriver(String fname, String lname) throws SQLException {
+        String delete_driver = "DELETE FROM unit_drivers WHERE fname = '" + fname + "' and lname = '" + lname +"'";
+        return SQLExecutor.executeUpdate(delete_driver);
+    }
+
+    public int insertUnit(long unit_id, String description) throws SQLException {
+        String queryConf = "INSERT into units(unit_id, description) values (" + unit_id + ",'" + description + "');";
+        return SQLExecutor.executeUpdate(queryConf);
+    }
+
+    /**
+     * Method pairs given unit to given group
+     * @param unitId of unit
+     * @param groupId of group
+     * @return either (1) the row count for SQL DML statements or (2) 0 for SQL statements that return nothing
+     * @throws SQLException
+     */
+    public int pairUnitToGroup(long unitId, int groupId) throws SQLException{
+        String insUtG = "INSERT INTO units_to_groups(unit_id, group_id) VALUES("+unitId+", "+groupId+");";
+        return SQLExecutor.executeUpdate(insUtG);
+    }
+    
+    public int getUnitConfTimeById(long unit_id) throws SQLException, NoItemFoundException {
+        String queryConf = "select extract(epoch from max_time_span) from units_conf where unit_id =" + unit_id;
+        ResultSet res = stmt.executeQuery(queryConf);
+        if (res.next()) {
+            return res.getInt(1);
+        } else
+            throw new NoItemFoundException("getUnitConfTimeById for " + unit_id + " not found.");
+    }
+
+    public boolean isRunning(long unit_id) throws SQLException {
+        String queryConf = "select unit_id from running_tracks where unit_id =" + unit_id;
+        ResultSet res = stmt.executeQuery(queryConf);
+        return res.next();
+    }
+
+    public UnitPosition getLastUnitPosition(long unit_id) throws SQLException, NoItemFoundException {
+        String queryConf = "select " + UnitPosition.SELECT + "from last_units_positions where unit_id =" + unit_id;
+        ResultSet res = stmt.executeQuery(queryConf);
+        if (res.next()) {
+            return new UnitPosition(res);
+        } else
+            throw new NoItemFoundException("Last position for " + unit_id + " not found.");
+    }
+
+    
+    public UnitPosition getPositionByGid(int gid) throws SQLException, NoItemFoundException {
+        String queryConf = "select " + UnitPosition.SELECT + "from units_positions where gid =" + gid;
+        ResultSet res = stmt.executeQuery(queryConf);
+        if (res.next()) {
+            return new UnitPosition(res);
+        } else
+            throw new NoItemFoundException("Last position for " + gid + " not found.");
+    }
+
+    public int changeUnitsTrackInterval(long unit_id, int milliseconds) throws SQLException {
+        String queryConf = "update units_conf SET max_time_span = interval '" + milliseconds + " milliseconds' where unit_id=" + unit_id;
+        return SQLExecutor.executeUpdate(queryConf);
+    }
+
+    public UnitHolder getUnitHolder(long unit_id) throws SQLException, NoItemFoundException {
+        String queryConf = "SELECT " + UnitHolder.SELECT
+                + "FROM unit_holders, units WHERE units.holder_id = unit_holders.holder_id AND "
+                + "units.unit_id = " + unit_id;
+
+        ResultSet res = stmt.executeQuery(queryConf);
+        if (res.next()) {
+            return new UnitHolder(res);
+        } else
+            throw new NoItemFoundException("getUnitHolder " + unit_id + " not found.");
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<UnitDriver> getUnitDrivers(long unit_id) throws SQLException {
+        String queryObservations = "select * "
+                + " from unit_drivers, units_to_drivers "
+                + "WHERE units_to_drivers.unit_id = " + unit_id
+                + " AND units_to_drivers.driver_id = unit_drivers.driver_id ";
+        ResultSet res = stmt.executeQuery(queryObservations);
+        return (List<UnitDriver>) generateObjectList(new UnitDriver(), res);
+    }
+
+    public LastPosition getLastPositionWithStatus(UnitPosition pos) throws SQLException {
+        UnitPositionFactory pf = new UnitPositionFactory(pos);
+        return pf.getLastPositionWithStatus();
+    }
+
+    public DBItemInfo getUnitInfo(String schema, String tableName, long id, String forigenKeyName) throws NoItemFoundException {
+        return new DBItemInfo(schema, tableName, id, forigenKeyName);
+
+    }
+
+    public void setProvideAlert(long unit_id, boolean provide) throws SQLException, NoItemFoundException{
+        String query = "UPDATE units_conf SET provide_alerts="+provide+" where unit_id = "+unit_id;
+        int i = SQLExecutor.executeUpdate(query);
+        if (i==0){
+            throw new NoItemFoundException(String.valueOf(unit_id));
+        }
+    }
+    
+    /**
+     * Method gets next value for unit_id, confirms if there is not any unit with same id in DB
+     * @return new unit_id if there is not same unit in DB or null if it is not possible o select new unit_id
+     * @throws SQLException
+     */
+    public Long getNextUnitID() throws SQLException{
+        boolean exists = true;
+        Long newId = null;
+        while(exists){
+            try{
+                String selectId = "SELECT nextval('units_unit_id'::regclass);";
+                ResultSet resId = SQLExecutor.getInstance().executeQuery(selectId);
+                if(resId.next()){
+                    newId = resId.getLong(1);
+                } else{
+                    return null;
+                }
+                Unit isSame = getUnit(newId);
+                if(isSame==null){
+                    exists = false;
+                }
+            } catch(SQLException e){
+                throw new SQLException("Unit can't get new ID!");
+            }
+        }
+        return newId;
+    }
+    
+    public Unit getUnit(long unit_id) throws SQLException {
+        String query = "SELECT holder_id, description FROM units WHERE unit_id = "
+                + unit_id;
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return new Unit(unit_id, res.getInt("holder_id"), res.getString("description"));
+        } else
+            return null;
+    }
+    
+    /**
+     * Method selects unit if there is unit with given unitId paired with given groupId
+     * @param unitId - id of unit
+     * @param groupId - id of group
+     * @return Unit object if there is the unit already in DB, null if there is not
+     * @throws SQLException
+     */
+    public Unit getUnitByGroup(long unitId, int groupId) throws SQLException {
+        String query = "SELECT holder_id, description FROM units u, units_to_groups utg"
+                + " WHERE u.unit_id = "+ unitId
+                + " AND utg.group_id = "+groupId
+                + " AND utg.unit_id = u.unit_id;";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return new Unit(unitId, res.getInt("holder_id"), res.getString("description"));
+        } else
+            return null;
+    }
+
+    public int getGroupID(long unit_id) throws SQLException {
+        String query = "SELECT group_id FROM units_to_groups WHERE unit_id= "
+                + unit_id + ";";
+        ResultSet res = stmt.executeQuery(query);
+        res.next();
+        return res.getInt("group_id");
+    }
+
+    /**
+     * function to get last valid ignition status for unit
+     * 
+     * @param unit_id - unit to get status
+     * @return IgnitionStatus valid for unit
+     * @throws SQLException
+     */
+    public IgnitionStatus getValidIgnitionStatus(long unit_id) throws SQLException {
+        String query = "SELECT * FROM last_ignition_status WHERE unit_id = " + unit_id + " ;";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return new IgnitionStatus(res);
+        } else {
+            return null;
+        }
+    }
+    
+    public UnitPosition getPositionBefore(long unit_id, Date date)throws SQLException, NoItemFoundException {
+        String dstring = FORMATTER.format(date);
+        String queryConf = "select " + UnitPosition.SELECT
+                + " from units_positions where time_stamp < timestamp with time zone'" + dstring+"' ORDER BY time_stamp DESC LIMIT 1";
+        ResultSet res = stmt.executeQuery(queryConf);
+        if (res.next()) {
+            return new UnitPosition(res);
+        } else
+            throw new NoItemFoundException("getPositionBefore " + unit_id + ", " + dstring + " not found.");
+    }
+
+    /**
+     * Function to get last ignition status from observations before time of
+     * unitPosition
+     * @param pos - UnitPosition
+     * @return IgnitionStatus for unit before time of UnitPosition
+     * @throws SQLException
+     * @throws NoItemFoundException
+     */
+    public IgnitionStatus getLastIgnitionStatus(UnitPosition pos) throws SQLException, NoItemFoundException {
+        String query = "SELECT observation_id, gid, observed_value, time_stamp, unit_id FROM observations"
+                + " WHERE sensor_id = 330040000"
+                + " AND unit_id = "
+                + pos.getUnit_id()
+                + " AND time_stamp < '"
+                + pos.getTime_stamp()
+                + "' "
+                + " ORDER BY time_stamp DESC LIMIT 1 ;";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return new IgnitionStatus(res);
+        } else {
+            throw new NoItemFoundException("getLastIgnitionStatus for "
+                    + pos.getUnit_id() + " and " + pos.getTime_stamp() + " does not exist!");
+        }
+    }
+
+    /**
+     * Function to get next ignition status from observations after time of
+     * unitPosition
+     * 
+     * @param pos
+     *            UnitPosition
+     * @return IgnitionStatus for unit after time of UnitPosition
+     * @throws SQLException
+     * @throws NoItemFoundException
+     */
+    public IgnitionStatus getNextIgnitionStatus(UnitPosition pos) throws SQLException, NoItemFoundException {
+        String query = "SELECT observation_id, gid, observed_value, time_stamp, unit_id FROM observations"
+                + " WHERE sensor_id = 330040000"
+                + " AND unit_id = "
+                + pos.getUnit_id()
+                + " AND time_stamp > '"
+                + pos.getTime_stamp() + "' " + " ORDER BY time_stamp LIMIT 1 ;";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return new IgnitionStatus(res);
+        } else {
+            throw new NoItemFoundException("getLastIgnitionStatus for "
+                    + pos.getUnit_id() + " and " + pos.getTime_stamp() + " does not exist!");
+        }
+    }
+    
+    /**
+     * Method selects observed value for given unit, sensor and position
+     * @param pos UnitPosition provides gid, unitId
+     * @param sensorId identifier of sensor as long
+     * @return Observed value as double
+     * @throws SQLException
+     */
+    public double getObservationValueOnPosition(UnitPosition pos, long sensorId) throws SQLException{
+        String query = "SELECT observed_value FROM observations"
+                + " WHERE unit_id = "+pos.getUnit_id()
+                + " AND sensor_id = "+sensorId
+                + " AND gid = "+pos.getGid()+";";
+        ResultSet res = stmt.executeQuery(query);
+        if (res != null){
+            return res.next() ? res.getDouble("observed_value") : Double.NaN;
+        } else {
+            throw new SQLException("An Exception occurs when executing SQL command!");
+        }
+    }
+    
+    /**
+     * Method gets last observation for given unit and sensor that not older than configuration time of unit 
+     * @param pos UnitPosition contains unitId and last position timestamp
+     * @param sensorId identifier of particular sensor
+     * @param confTime configuration time of unit
+     * @return last observation value as double if exists, NaN otherwise
+     * @throws SQLException
+     */
+    public double getLastObservationValueInConfTime(UnitPosition pos, long sensorId, int confTime) throws SQLException{
+        String query = "SELECT observed_value, time_stamp FROM observations"
+                +" WHERE sensor_id = "+sensorId+" AND unit_id = "+pos.getUnit_id()
+                +" GROUP BY observed_value, time_stamp"
+                +" HAVING (EXTRACT (epoch FROM (timestamp '"+pos.getTime_stamp()+"' - time_stamp))) < integer '"+confTime+"' "
+                +" ORDER BY time_stamp DESC LIMIT 1;";
+        ResultSet res = stmt.executeQuery(query);
+        if (res != null){
+            return res.next() ? res.getDouble("observed_value") : Double.NaN;
+        } else {
+            throw new SQLException("An Exception occurs when executing SQL command!");
+        }
+    }
+    
+    /**
+     * Method gets description from agricultural machinery table by given identifier  
+     * @param deviceId - identifier of the device
+     * @return description as String
+     * @throws SQLException
+     */
+    public String getDescriptionOfRfid(long deviceId) throws SQLException{
+        String query = "SELECT description_cze FROM agricultural_machinery WHERE id="+deviceId;
+        ResultSet res = stmt.executeQuery(query);
+        if (res != null){
+            return res.next() ? res.getString("description_cze") : "";
+        } else {
+            throw new SQLException("An Exception occurs when executing SQL command!");
+        }
+    }
+}

+ 409 - 0
src/main/java/cz/hsrs/db/util/UserUtil.java

@@ -0,0 +1,409 @@
+package cz.hsrs.db.util;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.Unit;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.composite.LastPosition;
+import cz.hsrs.db.pool.SQLExecutor;
+
+/**
+ * @author jezekjan
+ */
+public class UserUtil extends GroupUtil {
+
+    private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+
+    public UserUtil() {}
+
+    public String getUserLanguage(String user_name) throws SQLException, NoItemFoundException {
+        String select = "SELECT lang FROM system_users WHERE user_name = '"+user_name+"'";
+        ResultSet res = stmt.executeQuery(select);
+        if (res.next()) {
+            return res.getString(1);
+        } else
+            throw new NoItemFoundException("getUserLanguage " + user_name + " not found.");
+    }
+
+    public int getUserId(String userName) throws NoItemFoundException, SQLException{
+        String query = "SELECT user_id FROM system_users WHERE user_name = '"+userName+"';";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        if(res.next()){
+            return res.getInt(1);
+        } else{
+            throw new NoItemFoundException("User with given " + userName + " was not found.");
+        }
+    }
+
+    public int setUserLanguage(String user_name, String newLang) throws SQLException{
+        String query = "UPDATE system_users SET lang = '"+newLang+"' WHERE user_name = '"+user_name+"';";
+        return SQLExecutor.executeUpdate(query);
+    }
+    
+    public boolean getAudio(String user_name) throws SQLException, NoItemFoundException {
+        String select = "SELECT audio FROM system_users WHERE user_name = '"+user_name+"'";
+        ResultSet res = stmt.executeQuery(select);
+        if (res.next()) {
+            return res.getBoolean(1);
+        } else
+            throw new NoItemFoundException("getAudio " + user_name + " not found.");
+    }
+    @SuppressWarnings("unchecked")
+    public List<UnitPosition> getLastPositionsByUserName(String user_name) throws SQLException {
+        return (List<UnitPosition>) generateObjectList(new UnitPosition(), getLastPositionsByUserNameRes(user_name));
+    }
+    
+    @Deprecated
+    public String getRole(String user_name) throws SQLException, NoItemFoundException{
+        String query = "SELECT user_role FROM rights, system_users WHERE " +
+                "system_users.user_name = '"+user_name + "' AND "+
+                "system_users.rights_id = rights.rights_id";
+        ResultSet res = stmt.executeQuery(query);
+        if (res.next()) {
+            return res.getString(1);
+        } else
+            throw new NoItemFoundException("getUserPassword " + user_name + " not found.");
+    }
+    
+    /**
+     * Method select groupId of given user
+     * @return groupId as int or null if there is not any user with given userName
+     */
+    public static Integer getUserGroupId(String userName) throws SQLException{
+        String query = "SELECT group_id FROM system_users WHERE user_name ='"+userName+"';";
+        ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+        return res.next() ? res.getInt(1) : null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public List<LastPosition> getLastPositionWithStatus(String user_name) throws SQLException {
+        List<LastPosition> lastPositions = new ArrayList<>();
+        List<UnitPosition> positions = (List<UnitPosition>) generateObjectList(
+                new UnitPosition(), getLastPositionsByUserNameRes(user_name));
+
+        for (UnitPosition pos : positions) {
+            lastPositions.add((new UnitUtil()).getLastPositionWithStatus(pos));
+        }
+        return lastPositions;
+    }
+
+    public ResultSet getLastPositionsByUserNameRes(String user_name) throws SQLException {
+        /**
+         * select last_units_positions.gid, st_astext(the_geom),
+         * last_units_positions.unit_id, last_units_positions.time_stamp from
+         * last_units_positions, units_to_groups,system_users WHERE
+         * system_users.user_name = 'pepa' AND system_users.group_id=
+         * units_to_groups.group_id AND units_to_groups.unit_id =
+         * last_units_positions.unit_id ;
+         */
+        String last_pos_table = SQLExecutor.getUnitsLastPositions_table();
+        String queryObservations = "SELECT gid, st_x(the_geom), st_y(the_geom), st_srid(the_geom), speed, "
+                + last_pos_table
+                + ".unit_id, time_stamp, units_to_groups.group_id "
+                + "FROM "
+                + last_pos_table
+                + ", "
+                + "units_to_groups "
+                + " WHERE ("
+                + this.getWhereStatemant(user_name, "units_to_groups.group_id")
+                + ") AND units_to_groups.unit_id = "
+                + last_pos_table
+                + ".unit_id; ";
+        return stmt.executeQuery(queryObservations);
+    }
+
+    public ResultSet getLastPositionsByUserNameRes(String user_name, Long unit_id) throws SQLException {
+
+        if (unit_id == null) {
+            return getLastPositionsByUserNameRes(user_name);
+        } else {
+            String last_pos_table = SQLExecutor
+                    .getUnitsLastPositions_table();
+            String queryObservations = "SELECT gid, st_x(the_geom), st_y(the_geom), st_srid(the_geom), speed, "
+                    + last_pos_table
+                    + ".unit_id, time_stamp, units_to_groups.group_id "
+                    + "FROM "
+                    + last_pos_table
+                    + ", "
+                    + "units_to_groups "
+                    + " WHERE ("
+                    + this.getWhereStatemant(user_name,
+                            "units_to_groups.group_id")
+                    + ") AND units_to_groups.unit_id = "
+                    + last_pos_table
+                    + ".unit_id AND "
+                    + last_pos_table
+                    + ".unit_id = "
+                    + unit_id;
+
+            return stmt.executeQuery(queryObservations);
+        }
+    }
+
+    /** Get Positions by user name */
+    public ResultSet getPositionsByUserName(String user_name, Integer limit) throws SQLException {
+
+        String sqlLimit = "";
+        if (limit != null) {
+            if (limit == 1) {
+                return getLastPositionsByUserNameRes(user_name);
+            }
+            sqlLimit = "LIMIT " + limit;
+        }
+        String pos_table =  SQLExecutor.getUnitsPositions_table();
+        String queryObservations = "select gid, st_x(the_geom), st_y(the_geom), st_srid(the_geom), speed, "
+                + pos_table
+                + ".unit_id, time_stamp, units_to_groups.group_id  " + "from  "
+                + pos_table + ", units_to_groups " + "WHERE ("
+                + this.getWhereStatemant(user_name, "units_to_groups.group_id")
+                + ") AND units_to_groups.unit_id = " + pos_table + ".unit_id "
+                + " ORDER BY time_stamp DESC " + sqlLimit + " ;";
+
+        return stmt.executeQuery(queryObservations);
+    }
+
+    public ResultSet getTracksByUserName(String user_name, int limit) throws SQLException {
+        /**
+         * select gid, st_astext(the_geom) from units_tracks, units_to_groups,
+         * system_users WHERE system_users.user_name = 'pepa' AND
+         * system_users.group_id= units_to_groups.group_id AND
+         * units_to_groups.unit_id = units_tracks.unit_id ;
+         */
+
+        String tracks_table =  SQLExecutor.getUnitsTracks_table();
+        String queryObservations = "select gid, st_astext(the_geom), "
+                + tracks_table
+                + ".unit_id, track_start, track_end, units_to_groups.group_id "
+                + "from  " + tracks_table + "," + " units_to_groups"
+                + " WHERE ("
+                + this.getWhereStatemant(user_name, "units_to_groups.group_id")
+                + ") AND units_to_groups.unit_id = " + tracks_table
+                + ".unit_id order by track_end desc limit " + limit + "; ";
+
+        return stmt.executeQuery(queryObservations);
+    }
+
+    public String getUserPassword(String user_name) throws SQLException, NoItemFoundException {
+        String queryObservations = "select user_password from system_users WHERE user_name='" + user_name + "';";
+
+        ResultSet res = stmt.executeQuery(queryObservations);
+        if (res.next()) {
+            return res.getString(1);
+        } else
+            throw new NoItemFoundException("getUserPassword " + user_name + " not found.");
+    }
+
+    public int insertUser(String user_name, String pass) throws SQLException {
+        String insert = "insert into system_users(user_name, user_password) Values('" + user_name + "','" + pass + "');";
+        return SQLExecutor.executeUpdate(insert);
+    }
+
+    public int deleteUser(String user_name) throws SQLException {
+        String del = "DELETE FROM system_users WHERE user_name='" + user_name + "';";
+        return SQLExecutor.executeUpdate(del);
+    }
+
+    public int setUserSession(String user_name, String session_id, String IP) throws SQLException {
+        /* try to delete session if exists */
+        delUserSession(session_id);
+        
+        String getUsID = "SELECT user_id FROM system_users WHERE user_name = '" + user_name + "'";
+        ResultSet res = stmt.executeQuery(getUsID);
+        res.next();
+        int user_id = res.getInt(1);
+
+        String insert = "INSERT INTO sessions(session_id, system_user_id, ip) VALUES ("
+                + "'" + session_id + "'," + user_id + ",'" + IP + "')";
+        return SQLExecutor.executeUpdate(insert);
+    }
+
+    public int delUserSession(String session_id) throws SQLException {
+        String insert = "DELETE FROM sessions WHERE session_id ='" + session_id + "'";
+        return SQLExecutor.executeUpdate(insert);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public List<Unit> getUnitsByUser(String user_name) throws SQLException{
+        String query = "SELECT u.unit_id, u.holder_id, u.description " +
+                "FROM units u, units_to_groups utg, system_users su " +
+                "WHERE su.user_name = '"+user_name+"' " +
+                "AND su.group_id = utg.group_id " +
+                "AND utg.unit_id = u.unit_id;";
+        ResultSet res = stmt.executeQuery(query);
+        return (List<Unit>)generateObjectList(new Unit(), res);
+    }
+
+    public SimpleDateFormat getDateFormater() {
+        return FORMATTER;
+    }
+
+    /**
+     * Method returns positions of units in all groups for defined user collected in day defined by timeStamp parameter
+     * @param user_name is String username of logged user 
+     * @param timeStamp is day for which positions should be found
+     * @return ResultSet object with positions during one defined day
+     * @throws SQLException 
+     */
+    public ResultSet getPositionsByUserNameInDay2(String user_name, String timeStamp) throws SQLException {
+        if(timeStamp !=null){
+            String pos_table =  SQLExecutor.getUnitsPositions_table();
+            String query = "SELECT gid, "+pos_table+".unit_id, units_to_groups.group_id, "
+                    + "time_stamp, speed, st_x(the_geom), st_y(the_geom), st_srid(the_geom) "
+                    + "FROM "+pos_table+", units_to_groups "
+                    + "WHERE ("+this.getWhereStatemant(user_name, "units_to_groups.group_id")+") "
+                        + "AND units_to_groups.unit_id = "+pos_table+".unit_id "
+                        + "AND time_stamp > '"+timeStamp+"' AND time_stamp < timestamp '"+timeStamp+"' + INTERVAL '1 day' "
+                        + "ORDER BY time_stamp DESC;";
+            return stmt.executeQuery(query);
+        } else{
+            throw new SQLException("Parameter timestamp was not defined!");
+        }
+    }
+    
+    /**
+     * Method returns positions of units in all groups for defined user collected from defined timestamp parameter
+     * @param user_name is String username of logged user 
+     * @param fromTime is timestamp of the beginning
+     * @param unitId is identifier of unit
+     * @param ordering is order direction for results, can be ASC or DESC only
+     * @return ResultSet object with positions from defined timestamp, number is limited by range of 1 day!!!
+     * @throws SQLException
+     */
+    public ResultSet getPositionsByUserNameInDay(String user_name, String fromTime, long unitId, String ordering) throws SQLException {
+        if(fromTime != null){
+            String pos_table =  SQLExecutor.getUnitsPositions_table();
+            String query = "SELECT time_stamp, st_x(the_geom), st_y(the_geom), st_srid(the_geom) "
+                    + "FROM "+pos_table+" "
+                    + "WHERE "+pos_table+".unit_id = " + unitId + " "
+                        + "AND time_stamp >= '"+fromTime+"' AND time_stamp < '"+fromTime+"'::timestamp + '1 day'::interval "
+                        + "ORDER BY time_stamp "+ordering+";";
+
+            return stmt.executeQuery(query);
+        } else{
+            throw new SQLException("Parameter fromTime was not defined!");
+        }
+    }
+    
+    /**
+     * Method returns positions of units in all groups for defined user collected to defined timestamp parameter
+     * @param user_name is String username of logged user 
+     * @param toTime is timestamp of the end of range
+     * @param unitId is identifier of unit
+     * @param ordering is order direction for results, can be ASC or DESC only
+     * @return ResultSet object with positions to defined timestamp, number is limited by range of 1 day ago!!!
+     * @throws SQLException
+     */
+    public ResultSet getPositionsByUserNameDayBefore(String user_name, String toTime, long unitId, String ordering) throws SQLException {
+        if(toTime !=null){
+            String pos_table =  SQLExecutor.getUnitsPositions_table();
+            String query = "SELECT time_stamp, st_x(the_geom), st_y(the_geom), st_srid(the_geom) "
+                    + "FROM "+pos_table+" "
+                    + "WHERE "+pos_table+".unit_id = " + unitId + " "
+                        + "AND time_stamp >= '"+toTime+"'::timestamp - '1 day'::interval AND time_stamp < '"+toTime+"' "
+                        + "ORDER BY time_stamp "+ordering+";";
+
+            return stmt.executeQuery(query);
+        } else{
+            throw new SQLException("Parameter toTime was not defined!");
+        }
+    }
+    
+    /**
+     * Method returns positions of units in all groups for defined user collected during defined timeStamp parameters
+     * @param user_name is String username of logged user 
+     * @param fromTime is timestamp of the beginning
+     * @param toTime is timestamp of the end of range
+     * @param unitId is identifier of unit
+     * @param ordering is order direction for results, can be ASC or DESC only
+     * @return ResultSet object with positions between defined timestamps, number is limited by 50 000 rows!!!
+     * @throws SQLException
+     */
+    public ResultSet getPositionsByUserNameDuringRange(String user_name, String fromTime, String toTime, long unitId, String ordering) throws SQLException {
+        if(fromTime !=null && toTime !=null){
+            String pos_table =  SQLExecutor.getUnitsPositions_table();
+            String query = "SELECT time_stamp, st_x(the_geom), st_y(the_geom), st_srid(the_geom) "
+                    + "FROM "+pos_table+" "
+                    + "WHERE "+pos_table+".unit_id = " + unitId + " "
+                        + "AND time_stamp >= '"+fromTime+"' AND time_stamp < '"+toTime+"' "
+                        + "ORDER BY time_stamp "+ordering+" LIMIT 50000;";
+
+            return stmt.executeQuery(query);
+        } else{
+            throw new SQLException("Parameters fromTime and toTime were not defined!");
+        }
+    }
+    
+    /**
+     * Method returns positions of given unit for defined user collected during defined timestamp parameter, 
+     * modified for case of identical fromTime and toTime value
+     * @param user_name is String username of logged user 
+     * @param fromTime is timestamp of the beginning of range
+     * @param toTime is timestamp of the end of range
+     * @param unitId is identifier of unit
+     * @param ordering is order direction for results, can be ASC or DESC only
+     * @return ResultSet object with positions between defined timestamps, number is limited by 50 000 rows!!!
+     * @throws SQLException
+     */
+    public ResultSet getPositionsByUserNameDuringDay(String user_name, String fromTime, String toTime, long unitId, String ordering) throws SQLException {
+        if(fromTime !=null && toTime !=null){
+            if(fromTime.equalsIgnoreCase(toTime)){
+                String pos_table =  SQLExecutor.getUnitsPositions_table();
+                String query = "SELECT time_stamp, st_x(the_geom), st_y(the_geom), st_srid(the_geom) "
+                        + "FROM "+pos_table+" "
+                        + "WHERE "+pos_table+".unit_id = " + unitId + " "
+                            + "AND time_stamp >= '"+fromTime+"' AND time_stamp < '"+toTime+"'::timestamp + '1 day'::interval "
+                            + "ORDER BY time_stamp "+ordering+" LIMIT 50000;";
+                return stmt.executeQuery(query);
+            } else{
+                throw new SQLException("Parameters was not correctly defined!");
+            }
+        } else{
+            throw new SQLException("Parameter toTime was not defined!");
+        }
+    }
+    
+    /**
+     * Method returns positions of units in all groups for defined user collected during defined timeStamp parameters
+     * @param user_name user_name is String username of logged user 
+     * @param fromTime is timestamp of the beginning
+     * @param toTime is timestamp of the end of range
+     * @param unitId is identifier of unit
+     * @param ordering is order direction for results, can be ASC or DESC only
+     * @return ResultSet object with positions between defined timestamps, number is limited by 50 000 rows or to 1 day of collecting!!!
+     * @throws SQLException
+     */
+    public ResultSet getPositionsTimeRangeByUserName(String user_name, String fromTime, String toTime, Long unitId, String ordering) throws SQLException{
+        ResultSet res;
+        if(fromTime != null && toTime == null && unitId != null){
+            if(!fromTime.isEmpty()){
+                res = getPositionsByUserNameInDay(user_name, fromTime, unitId, ordering);
+            } else{
+                throw new SQLException("Wrong content of parameter from!");
+            }
+        } else if(fromTime == null && toTime != null && unitId != null){
+            if(!toTime.isEmpty()){
+                res = getPositionsByUserNameDayBefore(user_name, toTime, unitId, ordering);
+            } else{
+                throw new SQLException("Wrong content of parameter to!");
+            }
+        } else if(fromTime != null && toTime != null && unitId != null){
+            if(!fromTime.isEmpty() && !toTime.isEmpty()){
+                if(fromTime.equalsIgnoreCase(toTime)){
+                    res = getPositionsByUserNameDuringDay(user_name, fromTime, toTime, unitId, ordering);
+                } else{
+                    res = getPositionsByUserNameDuringRange(user_name, fromTime, toTime, unitId, ordering);
+                }
+            } else{
+                throw new SQLException("Wrong content of parameters from and to!");
+            }
+        } else{
+            throw new SQLException("Wrong combination of parameters from and to!");
+        }
+        return res;
+    }
+}

+ 10 - 0
src/main/java/cz/hsrs/db/util/Util.java

@@ -0,0 +1,10 @@
+package cz.hsrs.db.util;
+
+import java.sql.SQLException;
+
+public class Util extends GroupUtil{
+
+	public Util() throws SQLException{
+		super();
+	}
+}

+ 28 - 0
src/main/java/cz/hsrs/db/util/UtilFactory.java

@@ -0,0 +1,28 @@
+package cz.hsrs.db.util;
+
+/**
+ * Factory class that generates instances of all util classes
+ * @author jezekjan
+ *
+ */
+public class UtilFactory {
+	public TrackUtil trackUtil;
+	public UnitUtil unitUtil;
+	public UserUtil userUtil;
+	public GroupUtil groupUtil;
+	public SensorUtil sensorUtil;
+	public AlertUtil alertUtil;
+	public AnalystUtil analystUtil;
+	public ManagementUtil manUtil;
+	
+	public UtilFactory() {
+		trackUtil = new TrackUtil();
+		unitUtil= new UnitUtil();
+		userUtil= new UserUtil();
+		groupUtil= new GroupUtil();
+		sensorUtil= new SensorUtil();
+		alertUtil = new AlertUtil();
+		analystUtil = new AnalystUtil();
+		manUtil = new ManagementUtil();
+	}
+}

+ 182 - 0
src/main/java/cz/hsrs/db/util/VgiUtil.java

@@ -0,0 +1,182 @@
+package cz.hsrs.db.util;
+
+import cz.hsrs.db.pool.SQLExecutor;
+import org.apache.commons.io.IOUtils;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Date;
+
+public class VgiUtil {
+
+    /**
+     * Method inserts new POI to database and returns Id of this new POI
+     * @param titleValue String with value of Title parameter - need not be NULL
+     * @param descValue String with value of Description parameter
+     * @param catValue String with value of Category parameter
+     * @param statValue String value of Status parameter
+     * @param lonValue String with value of Longitude parameter - need not be NULL
+     * @param latValue String with value of Latitude parameter - need not be NULL
+     * @param timestampValue String with value of Timestamp parameter - need not be NULL
+     * @param startTimeValue String value of Start Timestamp parameter 
+     * @param userId String with name of user -  need not be NULL
+     * @return ID of new POI as long
+     * @throws SQLException Throws SQLException if an exception occurs during inserting
+     */
+    public static long insertPoi(String titleValue, String descValue, String catValue, String statValue, String lonValue, String latValue, String timestampValue, String startTimeValue, String userId) throws SQLException{
+        StringBuilder ins = new StringBuilder();
+        ins.append("SELECT poi.add_poi('").append(titleValue).append("', ");
+        if(descValue.isEmpty()){
+            ins.append("NULL, ");
+        } else{
+            ins.append("'").append(descValue).append("', ");
+        }
+        ins.append("'").append(catValue).append("', ");
+        ins.append("'").append(timestampValue).append("', ");
+        ins.append("'").append(userId).append("', ");
+        ins.append("'").append(lonValue).append("', ");
+        ins.append("'").append(latValue).append("', ");
+        if(startTimeValue.isEmpty()){
+            ins.append("NULL, ");
+        } else{
+            ins.append("'").append(startTimeValue).append("', ");
+        }
+        ins.append("'").append(statValue).append("');");
+        
+        ResultSet rs = SQLExecutor.getInstance().executeQuery(ins.toString());
+        if(rs.next()){ 
+            return rs.getLong(1);
+        } else{
+            throw new SQLException("An error occurs during inserting of new POI!");
+        }
+    }
+    
+    /**
+     * Method inserts new image connected to existing POI
+     * @param poiId Id of existing POI in database as long
+     * @param image InputStream with loaded image 
+     * @param fileSize size of image file in bytes as long 
+     * @throws SQLException Throws SQLException if an exception occurs during inserting
+     */
+    public static long insertPoiImage(long poiId, InputStream image, long fileSize) throws SQLException{
+        Date newDate = new Date();
+        long newImageId = newDate.getTime();
+        String query = "INSERT INTO poi.poi_image(image_id, image, ogc_fid) VALUES("+newImageId+", ?, "+poiId+");";
+        SQLExecutor.insertStream(query, image, fileSize);
+        return newImageId;
+    }
+    
+    /**
+     * Method inserts new image thumbnail connected to existing POI
+     * @param image InputStream with loaded image
+     * @param fileSize size of image file in bytes as long 
+     * @throws SQLException Throws SQLException if an exception occurs during inserting
+     */
+    public static void insertPoiImageThumbnail(long imageId, InputStream image, long fileSize) throws SQLException{
+        String query = "UPDATE poi.poi_image SET thumbnail = ? WHERE image_id = "+imageId+";";
+        SQLExecutor.insertStream(query, image, fileSize);
+    }
+
+    public static long testInsertPoi(String titleValue, String descValue, String catValue, String lonValue, String latValue, String timestampValue, String userId) throws SQLException{
+        String query = "SELECT poi.add_poi('"+titleValue+"', " +
+                "'"+descValue+"', " +
+                "'"+catValue+"', " +
+                "'"+timestampValue+"', " +
+                "'"+userId+"', " +
+                ""+lonValue+", " +
+                ""+latValue+");";
+        ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
+        if(rs.next()){
+            return rs.getLong(1);
+        } else{
+            throw new SQLException("An error occurs during inserting of new POI!");
+        }
+    }
+
+    public static File testSelectImage(long imageId, String path){
+        String query = "SELECT image, ogc_fid FROM poi.poi_image WHERE image_id ="+imageId+";";
+        
+        File selectedImage = null;
+        try {
+            ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
+            if(rs.next()){
+                InputStream is = rs.getBinaryStream("image");
+                selectedImage = new File(path+"/POI_"+imageId+".jpg");
+                FileOutputStream fOS = new FileOutputStream(selectedImage);
+                IOUtils.copy(is, fOS);
+                IOUtils.closeQuietly(fOS);
+            }
+        } catch (SQLException | IOException e) {
+            e.printStackTrace();
+        }
+        return selectedImage;
+    }
+
+    public static File testSelectThumbnail(long imageId, String path){
+        String query = "SELECT thumbnail, ogc_fid FROM poi.poi_image WHERE image_id ="+imageId+";";
+        
+        File selectedImage = null;
+        try {
+            ResultSet rs = SQLExecutor.getInstance().executeQuery(query);
+            if(rs.next()){
+                InputStream is = rs.getBinaryStream("thumbnail");
+                selectedImage = new File(path+"/POI_"+imageId+"_thumbnail.jpg");
+                FileOutputStream fOS = new FileOutputStream(selectedImage);
+                IOUtils.copy(is, fOS);
+                IOUtils.closeQuietly(fOS);
+            }
+        } catch (SQLException | IOException e) {
+            e.printStackTrace();
+        }
+        return selectedImage;
+    }
+    
+    /** Method rescale given image to given width and height */
+    public static BufferedImage rescale(BufferedImage masterImg, int widthDest, int heightDest){
+        Image resizedImg = masterImg.getScaledInstance(widthDest, heightDest, Image.SCALE_FAST);
+        BufferedImage rBimg = new BufferedImage(widthDest, heightDest, masterImg.getType());
+        Graphics2D g=rBimg.createGraphics();
+        g.drawImage(resizedImg, 0, 0, null);
+        g.dispose();
+        
+        return rBimg;
+    }
+    
+    /** Method rotated given image to given angle */
+    public static BufferedImage rotate(BufferedImage masterImg, int angle){
+        Dimension size = new Dimension(masterImg.getWidth(), masterImg.getHeight());
+        int masterWidth = masterImg.getWidth();
+        int masterHeight = masterImg.getHeight();
+        
+        double x = 0; //masterWidth / 2.0;
+        double y = 0; //masterHeight / 2.0;
+        switch (angle) {
+            case 0:
+                break;
+            case 180:
+                break;
+            case 90:
+            case 270:
+                size = new Dimension(masterImg.getHeight(), masterImg.getWidth());
+                x = (masterHeight - masterWidth) / 2.0;
+                y = (masterWidth - masterHeight) / 2.0;
+                break;
+        }
+
+        BufferedImage rotatedImg = new BufferedImage(size.width, size.height, masterImg.getTransparency());
+        Graphics2D g2d = rotatedImg.createGraphics();
+        AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+        at.rotate(Math.toRadians(angle), masterWidth / 2.0, masterHeight / 2.0);
+        g2d.drawImage(masterImg, at, null);
+        g2d.dispose();
+
+        return rotatedImg;
+    }
+}

+ 88 - 0
src/main/java/cz/hsrs/db/util/factory/UnitPositionFactory.java

@@ -0,0 +1,88 @@
+package cz.hsrs.db.util.factory;
+
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import cz.hsrs.db.model.AlertEvent;
+import cz.hsrs.db.model.IgnitionStatus;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.composite.LastPosition;
+import cz.hsrs.db.util.AlertUtil;
+import cz.hsrs.db.util.SensorUtil;
+import cz.hsrs.db.util.UnitUtil;
+
+/**
+ * Factory class - prida infomace k UnitPosition o tom jestli jednotk a jela, mela nastartovano, je stale online apod...
+ * @author jezekjan
+ *
+ */
+public class UnitPositionFactory {
+
+    private final LastPosition lp;
+    private final long rfidSensorId = 680010000;
+
+    public UnitPositionFactory(UnitPosition pos) throws SQLException{
+        UnitUtil ut = new UnitUtil();
+        AlertUtil aUtil = new AlertUtil();
+        SensorUtil sUtil = new SensorUtil();
+
+        int confTime = 0;
+        try {
+            confTime = ut.getUnitConfTimeById(pos.getUnit_id());
+        } catch (NoItemFoundException e) {
+            e.printStackTrace();
+        }
+        boolean isRunning;
+        boolean isOnline;
+        Map<String, Object> map = new HashMap<>();
+
+        /* Ma-li auto ignition tak dopln infomaci o klicku... kdyz je klicek on tak auto jede */
+        IgnitionStatus ignition = ut.getValidIgnitionStatus(pos.getUnit_id());
+        if (ignition!=null) {
+            boolean ignitionOn = ignition.isIgnitionOn();
+            map.put("ignition_on", ignitionOn);
+            isRunning = ignitionOn;
+        } 
+        /* Kdyz auto nema senzor na klicek urci se jestli jede podle casu posledni pozice */
+        else {
+            /* Kdyz je posledni pozice starsi nez confTime tak auto nejede */
+            isRunning = (new Date()).getTime() - pos.internalGetTimestamp().getTime() <= (confTime * 1000);
+        }
+        map.put(LastPosition.IS_RUNNING, isRunning);
+
+        /* Kdyz auto neposila po urcitou dobu pozice (5* conftime), bere se jako offline */
+        isOnline = ((new Date()).getTime() - pos.internalGetTimestamp().getTime()) <= 24 * 3600 * 1000;
+        map.put("is_online", isOnline);
+
+        /*Pouzivat pokud neni synchronizace mezi skutecnou posledni pozici a pozici u observace*/
+        if (sUtil.hasSensor(pos.getUnit_id(), rfidSensorId)){
+            double rfidValue = ut.getLastObservationValueInConfTime(pos, rfidSensorId, confTime);
+            boolean isNaN = Double.isNaN(rfidValue);
+            if(!isNaN){
+                long rfidValueL = (long) rfidValue;
+                String rfidDesc = ut.getDescriptionOfRfid(rfidValueL);
+                map.put("rfid_value", String.valueOf(rfidValueL));
+                map.put("rfid_desc", rfidDesc);
+            }
+        }
+        
+
+        /* alerty vlozim pouze pokud jednotka alerty poskytuje */
+        if (aUtil.provideAlerts(pos.getUnit_id())){
+            List<AlertEvent> events = aUtil.getUnsolvedAlertEvents(pos.getUnit_id());
+            lp = new LastPosition(pos, map, events);
+        } 
+        else {
+            lp = new LastPosition(pos, map, new LinkedList<AlertEvent>());
+        }
+    }
+
+    public LastPosition getLastPositionWithStatus(){
+        return lp;
+    }
+}

+ 139 - 0
src/main/java/cz/hsrs/db/vgi/util/VgiCategoryUtil.java

@@ -0,0 +1,139 @@
+package cz.hsrs.db.vgi.util;
+
+import cz.hsrs.db.model.vgi.VgiCategory;
+import cz.hsrs.db.pool.SQLExecutor;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class concentrates method for processing VGICategory objects
+ * @author mkepka
+ *
+ */
+public class VgiCategoryUtil {
+
+    private static final String SCHEMA_NAME = "vgi";
+    private static final String CATEGORY_TABLE_NAME = "observations_vgi_category";
+    
+    /**
+     * Method gets VGICategory object by given ID
+     * @param categoryId - ID of VgiCategory object
+     * @return VGICategory object
+     * @throws SQLException
+     */
+    public VgiCategory getVgiCategory(int categoryId) throws SQLException{
+        try{
+            String query = "SELECT category_id, category_name, description, parent_id, category_level, lft, rgt"
+                    + " FROM "+SCHEMA_NAME+"."+CATEGORY_TABLE_NAME+""
+                    + " WHERE category_id = "+categoryId+";";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            if(res.next()){
+                VgiCategory cat = new VgiCategory(
+                        res.getInt("category_id"),
+                        res.getString("category_name"),
+                        res.getString("description"),
+                        (res.getString("parent_id")!= null ? Integer.parseInt(res.getString("parent_id")) : null),
+                        (res.getString("category_level") != null ? Integer.valueOf(res.getString("category_level")) : null),
+                        (res.getString("lft") != null ? Integer.valueOf(res.getString("lft")) : null),
+                        (res.getString("rgt") != null ? Integer.valueOf(res.getString("rgt")) : null));
+                return cat;
+            }
+            else{
+                throw new SQLException("VgiCategory with given ID does not exist!");
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method gets List of VGICategory objects that 
+     * are descendants of VGICategory object by given ID
+     * @param categoryId - ID of VgiCategory object
+     * @return List of VGICategory objects
+     * @throws SQLException
+     */
+    public List<VgiCategory> getVgiCategoryDescendants(int categoryId) throws SQLException{
+        try{
+            String queryCat = "SELECT category_id, category_name, description, parent_id, category_level, lft, rgt"
+                    + " FROM "+SCHEMA_NAME+"."+CATEGORY_TABLE_NAME+""
+                    + " WHERE category_id = "+categoryId+";";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(queryCat);
+            if(res.next()){
+                VgiCategory catParent = new VgiCategory(
+                        res.getInt("category_id"),
+                        res.getString("category_name"),
+                        res.getString("description"),
+                        (res.getString("parent_id")!= null ? Integer.parseInt(res.getString("parent_id")) : null),
+                        (res.getString("category_level") != null ? Integer.valueOf(res.getString("category_level")) : null),
+                        (res.getString("lft") != null ? Integer.valueOf(res.getString("lft")) : null),
+                        (res.getString("rgt") != null ? Integer.valueOf(res.getString("rgt")) : null));
+                
+                LinkedList<VgiCategory> catList = new LinkedList<VgiCategory>();
+                String queryDesc;
+                if(catParent.internalGetLft() != null){
+                    queryDesc = "SELECT category_id, category_name, description, parent_id, category_level, lft, rgt"
+                            + " FROM "+SCHEMA_NAME+"."+CATEGORY_TABLE_NAME+""
+                            + " WHERE lft BETWEEN "+catParent.internalGetLft()+""
+                            + " AND "+catParent.internalGetRgt()+""
+                            + " ORDER BY category_id;";
+                }
+                else{
+                    queryDesc = "SELECT category_id, category_name, description, parent_id, category_level, lft, rgt"
+                            + " FROM "+SCHEMA_NAME+"."+CATEGORY_TABLE_NAME+""
+                            + " WHERE parent_id = "+catParent.getCategoryId()+""
+                            + " ORDER BY category_id;";
+                }
+                ResultSet resDesc = SQLExecutor.getInstance().executeQuery(queryDesc);
+                while(resDesc.next()){
+                    VgiCategory cat = new VgiCategory(
+                            resDesc.getInt("category_id"),
+                            resDesc.getString("category_name"),
+                            resDesc.getString("description"),
+                            (res.getString("parent_id")!= null ? Integer.parseInt(res.getString("parent_id")) : null),
+                            (res.getString("category_level") != null ? Integer.valueOf(res.getString("category_level")) : null),
+                            (res.getString("lft") != null ? Integer.valueOf(res.getString("lft")) : null),
+                            (res.getString("rgt") != null ? Integer.valueOf(res.getString("rgt")) : null));
+                    catList.add(cat);
+                }
+                return catList;
+            }
+            else{
+                throw new SQLException("VgiCategory with given ID does not exist!");
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method gets list of all VGICategory objects
+     * @return LinkedList of VGICategory objects
+     * @throws SQLException
+     */
+    public List<VgiCategory> getCategoriesList() throws SQLException{
+        try{
+            String query = "SELECT category_id, category_name, description, parent_id, category_level, lft, rgt"
+                    + " FROM "+SCHEMA_NAME+"."+CATEGORY_TABLE_NAME+" ORDER BY category_id;";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiCategory> catList = new LinkedList<VgiCategory>();
+            while(res.next()){
+                VgiCategory cat = new VgiCategory(
+                        res.getInt("category_id"),
+                        res.getString("category_name"),
+                        res.getString("description"),
+                        (res.getString("parent_id")!= null ? Integer.parseInt(res.getString("parent_id")) : null),
+                        (res.getString("category_level") != null ? Integer.valueOf(res.getString("category_level")) : null),
+                        (res.getString("lft") != null ? Integer.valueOf(res.getString("lft")) : null),
+                        (res.getString("rgt") != null ? Integer.valueOf(res.getString("rgt")) : null));
+                catList.add(cat);
+            }
+            return catList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 97 - 0
src/main/java/cz/hsrs/db/vgi/util/VgiDatasetsUtil.java

@@ -0,0 +1,97 @@
+package cz.hsrs.db.vgi.util;
+
+import cz.hsrs.db.model.vgi.VgiDataset;
+import cz.hsrs.db.pool.SQLExecutor;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class concentrates methods for processing VGIDataset objects
+ * @author mkepka
+ *
+ */
+public class VgiDatasetsUtil {
+    
+    private static final String SCHEMA_NAME = "vgi";
+    private static final String TABLE_NAME = "vgi_datasets";
+
+    /**
+     * Method for selecting specific VgiDataset object
+     * @param userId - Id user user
+     * @param datasetId - ID of VgiDataset object
+     * @return VgiDataset object with given parameters
+     * @throws SQLException
+     */
+    public VgiDataset getVgiDataset(int userId, int datasetId) throws SQLException{
+        try{
+            String query = "SELECT dataset_id, dataset_name, description"
+                    + " FROM "+SCHEMA_NAME+"."+TABLE_NAME+""
+                    + " WHERE user_id = "+userId+""
+                    + " AND dataset_id = "+datasetId+";";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            if(res.next()){
+                VgiDataset dat = new VgiDataset(
+                        res.getInt("dataset_id"), 
+                        res.getString("dataset_name"),
+                        res.getString("description"));
+                return dat;
+            }
+            else{
+                throw new SQLException("VGIDataset cannot be selected!");
+            }
+        } catch (SQLException e){
+            throw new SQLException("VGIDataset cannot be selected!");
+        }
+    }
+    
+    /**
+     * Method gets List of VGI Datasets by given user
+     * @param userId - ID of user as Integer
+     * @return LinkedList of VGIDatasets
+     * @throws SQLException
+     */
+    public List<VgiDataset> getDatasetsList(int userId) throws SQLException{
+        try{
+            String query = "SELECT dataset_id, dataset_name, description"
+                    + " FROM "+SCHEMA_NAME+"."+TABLE_NAME+""
+                    + " WHERE user_id = "+userId+""
+                    + " ORDER BY dataset_id;";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiDataset> datList = new LinkedList<VgiDataset>();
+            while(res.next()){
+                VgiDataset dat = new VgiDataset(
+                        res.getInt("dataset_id"), 
+                        res.getString("dataset_name"),
+                        res.getString("description"));
+                datList.add(dat);
+            }
+            return datList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method deletes VGIDataset object by given ID 
+     * and associated to given user
+     * @param userId - ID of user
+     * @param datasetId - ID of VgiDataset object
+     * @return Number of deleted rows, expected only 1
+     * @throws SQLException
+     */
+    public int deleteVgiDataset(int userId, int datasetId) throws SQLException{
+        try{
+            String query = "DELETE"
+                    + " FROM "+SCHEMA_NAME+"."+TABLE_NAME+""
+                    + " WHERE dataset_id ="+datasetId+""
+                    + " AND user_id = "+userId+";";
+            int row = SQLExecutor.executeUpdate(query);
+            return row;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 206 - 0
src/main/java/cz/hsrs/db/vgi/util/VgiMediaUtil.java

@@ -0,0 +1,206 @@
+/**
+ * 
+ */
+package cz.hsrs.db.vgi.util;
+
+import cz.hsrs.db.model.vgi.VgiMedia;
+import cz.hsrs.db.pool.SQLExecutor;
+
+import java.io.InputStream;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class concentrates methods for processing VgiMedia objects
+ * @author mkepka
+ *
+ */
+public class VgiMediaUtil {
+    
+    private static final String SCHEMA_NAME = "vgi";
+    private static final String MEDIA_TABLE_NAME = "observations_vgi_media";
+
+    /**
+     * Method inserts new VgiMedia to the DB
+     * @param obsId - ID of associated VGIObservation object, mandatory
+     * @param media - InputStream with media to be inserted, mandatory
+     * @param fileSize - size of media file to be inserted, mandatory 
+     * @param mediaType - data type of media, mandatory
+     * @return ID of inserted VgiMedia object
+     * @throws SQLException
+     */
+    public static int insertVgiMedia(int obsId, InputStream media, long fileSize, String mediaType) throws SQLException{
+        int newMedId = getNextVgiMediaID();
+        
+        String query = "INSERT INTO "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                + "(med_id, obs_vgi_id, observed_media, media_datatype)"
+                + " VALUES("+newMedId+", "+obsId+", ?, '"+mediaType+"');";
+        SQLExecutor.insertStream(query, media, fileSize);
+        
+        return newMedId;
+    }
+    
+    /**
+     * Method for inserting new thumbnail of existing VgiMedia file
+     * @param medId - ID of VgiMedia 
+     * @param media - thumbnail as InputStream
+     * @param fileSize - size of file
+     * @throws SQLException
+     */
+    public static void insertVgiMediaThumbnail(int medId, InputStream media, long fileSize) throws SQLException{
+        String query = "UPDATE "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                + " SET thumbnail = ? WHERE med_id = "+medId+";";
+        SQLExecutor.insertStream(query, media, fileSize);
+    }
+    
+    /**
+     * Method updates VgiMedia by given medId
+     * @param medId - ID of VgiMedia
+     * @param media - InputStream with media 
+     * @param fileSize - size of media file in bytes
+     * @param mediaType - data type of media, mandatory
+     * @throws SQLException
+     */
+    public static void updateVgiMedia(int medId, InputStream media, long fileSize, String mediaType) throws SQLException{
+        String query = "UPDATE "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+" SET"
+                + " observed_media = ?,"
+                + " media_datatype = "+mediaType
+                + " WHERE med_id = "+medId+";";
+        SQLExecutor.insertStream(query, media, fileSize);
+    }
+    
+   /**
+    * Method for selecting info of all connected VgiMedia to given master VgiObservation
+    * @param obsId - ID of master VgiObservation object
+    * @throws SQLException
+    */
+    public List<VgiMedia> getVgiMediaInfo(int obsId) throws SQLException{
+        try{
+            String select = "SELECT med_id, obs_vgi_id, time_received, media_datatype"
+                    + " FROM "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                    + " WHERE obs_vgi_id = "+obsId+";"; 
+            ResultSet rs = SQLExecutor.getInstance().executeQuery(select);
+            List<VgiMedia> mediaList = new LinkedList<VgiMedia>();
+            while (rs.next()) {
+                VgiMedia medium = new VgiMedia(
+                        rs.getInt("med_id"),
+                        rs.getInt("obs_vgi_id"),
+                        rs.getString("time_received"),
+                        rs.getString("media_datatype"));
+                mediaList.add(medium);
+            }
+            return mediaList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method for selecting VgiMedia of given master VgiObservation
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of VgiMedia
+     * @return VgiMedia object containing media file
+     * @throws SQLException
+     */
+    public VgiMedia getVgiMedia(int obsId, int mediaId) throws SQLException{
+        try{
+            String select = "SELECT med_id, obs_vgi_id, time_received, observed_media, media_datatype"
+                    + " FROM "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                    + " WHERE med_id = "+mediaId+""
+                    + " AND obs_vgi_id = "+obsId+";"; 
+            ResultSet rs = SQLExecutor.getInstance().executeQuery(select);
+            if (rs.next()) {
+                VgiMedia medium = new VgiMedia(
+                        rs.getInt("med_id"),
+                        rs.getInt("obs_vgi_id"),
+                        rs.getString("time_received"),
+                        rs.getBytes("observed_media"),
+                        rs.getString("media_datatype"));
+                return medium;
+            }
+            else{
+                throw new SQLException("VgiMedia with given ID cannot be selected!");
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method for deleting VgiMedia of given master VgiObservation
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of VgiMedia object
+     * @return true if VgiMedia object was deleted
+     * @throws SQLException
+     */
+    public static boolean deleteVgiMedia(int obsId, int mediaId) throws SQLException{
+        try{
+            String del = "DELETE"
+                    + " FROM "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                    + " WHERE med_id = "+mediaId+""
+                    + " AND obs_vgi_id = "+obsId+";"; 
+            int i = SQLExecutor.executeUpdate(del);
+            if (i == 1) {
+                return true;
+            }
+            else{
+                return false;
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+
+    /**
+     * Method provides selection of media file thumbnail that is stored in DB
+     * @param obsId - ID of VgiObservation
+     * @param mediaId - Id of media file
+     * @return VgiMedia object containing only thumbnail as bytea  
+     * @throws SQLException
+     */
+    public VgiMedia getVgiMediaThumbnail(Integer obsId, Integer mediaId) throws SQLException {
+        try{
+            String select = "SELECT med_id, obs_vgi_id, time_received, media_datatype, thumbnail"
+                    + " FROM "+SCHEMA_NAME+"."+MEDIA_TABLE_NAME+""
+                    + " WHERE med_id = "+mediaId+""
+                    + " AND obs_vgi_id = "+obsId+";"; 
+            ResultSet rs = SQLExecutor.getInstance().executeQuery(select);
+            if (rs.next()) {
+                VgiMedia medium = new VgiMedia(
+                        rs.getInt("med_id"),
+                        rs.getInt("obs_vgi_id"),
+                        rs.getString("time_received"),
+                        rs.getString("media_datatype"),
+                        rs.getBytes("thumbnail"));
+                return medium;
+            }
+            else{
+                throw new SQLException("VgiMedia with given ID cannot be selected!");
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects next value of VgiMedia ID 
+     * @return next value of ID
+     * @throws SQLException when new ID can be selected
+     */
+    private static int getNextVgiMediaID() throws SQLException{
+        try{
+            String selectId = "SELECT nextval('"+SCHEMA_NAME+".observations_vgi_media_med_id_seq'::regclass);";
+            ResultSet resId = SQLExecutor.getInstance().executeQuery(selectId);
+            if(resId.next()){
+                return resId.getInt(1);
+            }
+            else{
+                throw new SQLException("Media can't get new ID!");
+            }
+        } catch(SQLException e){
+            throw new SQLException("Media can't get new ID!");
+        }
+    }
+}

+ 1013 - 0
src/main/java/cz/hsrs/db/vgi/util/VgiObservationUtil.java

@@ -0,0 +1,1013 @@
+package cz.hsrs.db.vgi.util;
+
+import cz.hsrs.db.model.vgi.Envelope2D;
+import cz.hsrs.db.model.vgi.VgiObservation;
+import cz.hsrs.db.model.vgi.VgiObservationRdf;
+import cz.hsrs.db.pool.SQLExecutor;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Class concentrates methods for processing VGIObservation objects
+ * @author mkepka
+ *
+ */
+public class VgiObservationUtil {
+
+    private static final String VGI_SCHEMA_NAME = "vgi";
+    private static final String SENSLOG_SCHEMA_NAME = "public";
+    private static final String OBSERVATION_TABLE_NAME = "observations_vgi";
+    
+    public VgiObservationUtil(){
+    }
+    
+    /**
+     * Method inserts new VGI Observation object to the DB by given attributes
+     * @param gid - ID of position
+     * @param timestamp - Time stamp when observation was recorded - mandatory
+     * @param categoryId - Id of VgiCategory - mandatory
+     * @param description - Detailed description of observation - optional
+     * @param attributes - Other attributes in JSON format - optional
+     * @param unitId - Id of unit that recorded observation - mandatory
+     * @param userId - Id of user that recorded observation - mandatory
+     * @param datasetId - Id of VgiDataset - mandatory
+     * @return ID of inserted observation as integer
+     * @throws SQLException
+     */
+    public static int insertVgiObs(int gid, String timestamp, Integer categoryId, String description, 
+            String attributes, long unitId, int userId, int datasetId) throws SQLException{
+        int newId = getNextVgiObsID();
+        
+        StringBuffer ins = new StringBuffer();
+        ins.append("INSERT INTO "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+"(obs_vgi_id, gid, time_stamp, category_id,"
+                + " description, attributes, dataset_id, unit_id, user_id) VALUES(");
+        ins.append(newId+", ");
+        ins.append(gid+", ");
+        ins.append("'"+timestamp+"', ");
+        ins.append(categoryId+", ");
+        ins.append(description == null ? "NULL, " : "'"+description+"', ");
+        ins.append((attributes == null) || (attributes != null && attributes.isEmpty()) ? "NULL, " : "'"+attributes+"', ");
+        ins.append(datasetId+", ");
+        ins.append(unitId+", ");
+        ins.append(userId+"); ");
+        try{
+            String query = ins.toString();
+            SQLExecutor.executeUpdate(query);
+            return newId;
+        } catch (SQLException e){
+            throw new SQLException("An error occurs during inserting of new VgiObservation!");
+        }
+    }
+    
+    /**
+     * Method updates VGIObservation objects by given attributes
+     * @param obsId - ID of VGIObservation object to be updated
+     * @param gid - ID of position
+     * @param timestamp - Time stamp when observation was recorded - mandatory
+     * @param categoryId - Id of VgiCategory - mandatory
+     * @param description - Detailed description of observation - optional
+     * @param attributes - Other attributes in JSON format - optional
+     * @param unitId - Id of unit that recorded observation - mandatory
+     * @param userId - Id of user that recorded observation - mandatory
+     * @param datasetId - Id of VgiDataset - mandatory
+     * @return true if the VGIObservation object was updated
+     * @throws SQLException
+     */
+    public static boolean updateVgiObs(int obsId, int gid, String timestamp, Integer categoryId, String description, 
+            String attributes, long unitId, int userId, int datasetId) throws SQLException{
+        try{
+            StringBuffer ins = new StringBuffer();
+            ins.append("UPDATE "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" SET ");
+            ins.append("gid = "+gid+", ");
+            ins.append(timestamp != null ? "time_stamp = '"+timestamp+"', " : "");
+            ins.append(categoryId != null ? "category_id = "+categoryId+", " : "");
+            ins.append(description != null ? "description = '"+description+"', " : "");
+            ins.append((attributes != null && !attributes.isEmpty()) ? "attributes = '"+attributes+"', " : "");
+            ins.append("dataset_id = "+datasetId+", ");
+            ins.append("unit_id = "+unitId+", ");
+            ins.append("user_id = "+userId+" ");
+            ins.append("WHERE obs_vgi_id = "+obsId+";");
+            
+            String query = ins.toString();
+            SQLExecutor.executeUpdate(query);
+            return true;
+        } catch (SQLException e){
+            throw new SQLException("An error occurs during inserting of new POI!");
+        }
+    }
+    
+    /**
+     * Method gets specific VGIObservation object by given ID
+     * @param obsId - ID of VgiObservation object
+     * @param userId - ID of user that owns VgiObservation object
+     * @return VgiObservation object or null if any was not found
+     * @throws SQLException
+     */
+    public VgiObservation getVgiObservationByObsId(int obsId, int userId) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.user_id = "+userId+""
+                    + " AND ov.obs_vgi_id = "+obsId+""
+                    + " AND ov.gid = up.gid;";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            if(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                return obs;
+            }
+            else{
+                return null;
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation object by given ID in GeoJSON format
+     * @param obsId - ID of VgiObservation object
+     * @param userId - ID of user that owns given VgiObservation object
+     * @return VgiObservation object in GeoJSON format as JSONObject
+     * @throws SQLException
+     */
+    public JSONObject getVgiObservationByObsIdAsGeoJSON(int obsId, int userId) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.user_id = "+userId+""
+                    + " AND ov.obs_vgi_id = "+obsId+""
+                    + " AND ov.gid = up.gid;";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            JSONObject vgiObs = convertVgiObservationResultSet2GeoJSON(res);
+            return vgiObs;
+         } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation object by given ID prepared for RDF format
+     * @param obsId - ID of VgiObservation object
+     * @param userId - ID of user that owns given VgiObservation object
+     * @return VgiObservation object for RDF format
+     * @throws SQLException
+     */
+    public VgiObservationRdf getVgiObservationByObsIdForRdf(int obsId, int userId) throws SQLException{
+        try{
+            String query = "SELECT ov.obs_vgi_id, date(ov.time_stamp), ov.category_id, ov.description,"
+                    + " ov.attributes::json->>'name' AS name, ov.dataset_id, ov.unit_id, ov.user_id,"
+                    + " ov.media_count, st_astext(up.the_geom) AS geom"
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.user_id = "+userId+""
+                    + " AND ov.obs_vgi_id = "+obsId+""
+                    + " AND ov.gid = up.gid;";
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            if(res.next()){
+                VgiObservationRdf obs = new VgiObservationRdf(
+                        res.getInt("obs_vgi_id"),
+                        res.getString("date"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("name"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getInt("media_count"),
+                        res.getString("geom"));
+                return obs;
+            }
+            else{
+                return null;
+            }
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VGI observation objects by given filter parameters
+     * @param userId - user ID that has VgiObservation
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservation objects 
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUser(int userId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+"";
+            if(fromTime == null && toTime == null){
+                query = query 
+                        +";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation objects by given filter parameters
+     * @param userId - user ID that has VgiObservation
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException
+     */
+    public List<JSONObject> getVgiObservationsByUserAsJSON(int userId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+"";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List<VgiObservationRdf> object by user prepared for RDF format
+     * @param userId - ID of user that owns given VgiObservation object
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @param categoryId - ID of VgiCategory
+     * @param datasetId - ID of VgiDataset 
+     * @param extent - spatial extent that features should intersect 
+     * @param unitId - ID of unit that produced VgiObservation
+     * @return List<VgiObservationRdf> object for RDF format
+     * @throws SQLException
+     */
+    public List<VgiObservationRdf> getVgiObservationsByUserForRdf(int userId, String fromTime, String toTime, 
+            Integer categoryId, Integer datasetId, Envelope2D extent, Long unitId) throws SQLException{
+        try{
+            StringBuilder query = new StringBuilder();
+            query.append("SELECT ov.obs_vgi_id, date(ov.time_stamp), ov.category_id, ov.description,"
+                    + " ov.attributes::json->>'name' AS name, ov.dataset_id, ov.unit_id, ov.user_id,"
+                    + " ov.media_count, st_astext(up.the_geom) AS geom");
+            query.append(" FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up");
+            query.append(" WHERE ov.user_id = "+userId+"");
+            if(fromTime != null && !fromTime.isEmpty()){
+                query.append(" AND ov.time_stamp >= '"+fromTime+"'");
+            }
+            if(toTime != null && !toTime.isEmpty()){
+                query.append(" AND ov.time_stamp <= '"+toTime+"'");
+            }
+            if(categoryId != null){
+                query.append(" AND ov.category_id = "+categoryId+"");
+            }
+            if(datasetId != null){
+                query.append(" AND ov.dataset_id = "+datasetId+"");
+            }
+            if(extent != null){
+                query.append(" AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")");
+            }
+            if(unitId != null){
+                query.append(" AND ov.unit_id = "+unitId);
+            }
+            query.append(" AND ov.gid = up.gid;");
+            
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query.toString());
+            List<VgiObservationRdf> obsList = new ArrayList<VgiObservationRdf>(); 
+            while(res.next()){
+                VgiObservationRdf obs = new VgiObservationRdf(
+                        res.getInt("obs_vgi_id"),
+                        res.getString("date"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("name"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getInt("media_count"),
+                        res.getString("geom"));
+                obsList.add(obs);
+            }
+            return obsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation objects by given filter parameters
+     * @param userId - user ID that has VgiObservation
+     * @param categoryId - ID of VgiCategory
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUserByCategory(int userId, int categoryId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " ov.user_id = "+userId+""
+                    + " AND ov.category_id = "+categoryId+"";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation objects by given filter parameters
+     * @param userId - user ID that has VgiObservation
+     * @param categoryId - ID of VgiCategory
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException
+     */
+    public List<JSONObject> getVgiObservationsByUserByCategoryAsJSON(int userId, int categoryId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.category_id = "+categoryId+"";
+            if(fromTime == null && toTime == null){
+                query = query
+                        +";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects VgiObservation objects by given filter parameters
+     * @param userId - user ID that has VgiObservation
+     * @param datasetId - ID of VgiDataset
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUserByDataset(int userId, int datasetId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.dataset_id = "+datasetId+"";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters
+     * @param userId - ID of user that owns VgiObservation
+     * @param datasetId - ID of VgiDataset
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException
+     */
+    public List<JSONObject> getVgiObservationsByUserByDatasetAsJSON(int userId, int datasetId, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.dataset_id = "+datasetId+"";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUserByExtent(int userId, Envelope2D extent, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException 
+     */
+    public List<JSONObject> getVgiObservationsByUserByExtentAsJSON(int userId, Envelope2D extent, String fromTime, String toTime) throws SQLException {
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query 
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param unitId - ID of unit that produced VgiObservation
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException 
+     */
+    public List<JSONObject> getVgiObservationsByUserByUnitAsJSON(int userId, long unitId, String fromTime, String toTime) throws SQLException {
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.unit_id = "+unitId;
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query 
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param datasetId - ID of VgiDataset 
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUserByDatasetByExtent(int userId, int datasetId, Envelope2D extent, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.dataset_id = "+datasetId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param datasetId - ID of VgiDataset 
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException 
+     */
+    public List<JSONObject> getVgiObservationsByUserByDatasetByExtentAsJSON(int userId, int datasetId, Envelope2D extent, String fromTime, String toTime) throws SQLException {
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.dataset_id = "+datasetId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query 
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param datasetId - ID of VgiDataset 
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations
+     * @throws SQLException
+     */
+    public List<VgiObservation> getVgiObservationsByUserByCategoryByDatasetByExtent(int userId, int categoryId, int datasetId, Envelope2D extent, String fromTime, String toTime) throws SQLException{
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.category_id = "+categoryId+""
+                    + " AND ov.dataset_id = "+datasetId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<VgiObservation> vgiObsList = new LinkedList<VgiObservation>();
+            while(res.next()){
+                VgiObservation obs = new VgiObservation(
+                        res.getInt("obs_vgi_id"),
+                        res.getInt("gid"),
+                        res.getString("time_stamp"),
+                        res.getInt("category_id"),
+                        res.getString("description"),
+                        res.getString("attributes"),
+                        res.getInt("dataset_id"),
+                        res.getLong("unit_id"),
+                        res.getInt("user_id"),
+                        res.getString("time_received"),
+                        res.getInt("media_count"),
+                        res.getDouble("st_x"),
+                        res.getDouble("st_y"),
+                        res.getDouble("altitude"),
+                        res.getDouble("dop"));
+                vgiObsList.add(obs);
+            }
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method selects List of VgiObservation objects by given filter parameters 
+     * @param userId - ID of user that owns VgiObservation
+     * @param datasetId - ID of VgiDataset 
+     * @param extent - spatial extent that features should intersect 
+     * @param fromTime - beginning of time frame, optional
+     * @param toTime - end of time frame, optional
+     * @return List of VgiObservations in GeoJSON format
+     * @throws SQLException 
+     */
+    public List<JSONObject> getVgiObservationsByUserByCategoryByDatasetByExtentAsJSON(int userId, int categoryId, int datasetId, Envelope2D extent, String fromTime, String toTime) throws SQLException {
+        try{
+            String query = VgiObservation.SELECT_ATTRIBUTES_GEOJSON
+                    + " FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+" ov, "+SENSLOG_SCHEMA_NAME+".units_positions up"
+                    + " WHERE ov.gid = up.gid"
+                    + " AND ov.user_id = "+userId+""
+                    + " AND ov.category_id = "+categoryId+""
+                    + " AND ov.dataset_id = "+datasetId+""
+                    + " AND up.geom && ST_MakeEnvelope("+extent.getXMin()+", "+extent.getYMin()+", "+extent.getXMax()+", "+extent.getYMax()+", "+extent.getSRID()+")";
+            if(fromTime == null && toTime == null){
+                query = query
+                        + ";";
+            } else if(fromTime == null && toTime != null){
+                query = query 
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            } else if(fromTime != null && toTime == null){
+                query = query
+                        + " AND ov.time_stamp >= '"+fromTime+"';";
+            } else{
+                query = query 
+                        + " AND ov.time_stamp >= '"+fromTime+"'"
+                        + " AND ov.time_stamp <= '"+toTime+"';";
+            }
+            ResultSet res = SQLExecutor.getInstance().executeQuery(query);
+            LinkedList<JSONObject> vgiObsList = convertVgiObsResultSet2GeoJSON(res);
+            return vgiObsList;
+        } catch(SQLException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method deletes VGIObservation by given ID
+     * @param obsId - ID of VGIObservation object to be deleted
+     * @return true if VGIObs was deleted, false if not
+     * @throws SQLException
+     */
+    public static boolean deleteVgiObservation(int obsId) throws SQLException{
+        String query = "DELETE FROM "+VGI_SCHEMA_NAME+"."+OBSERVATION_TABLE_NAME+""
+                + " WHERE obs_vgi_id = "+obsId+";";
+        try{
+            int update = SQLExecutor.executeUpdate(query);
+            if(update > 0){
+                return true;
+            }
+            else{
+                return false;
+            }
+        } catch(SQLException e){
+            throw new SQLException("VGIObservation was not deleted!");
+        }
+    }
+    
+    /**
+     * Method selects next value of VgiObservation ID 
+     * @return next value of ID
+     * @throws SQLException when new ID can be selected
+     */
+    private static int getNextVgiObsID() throws SQLException{
+        try{
+            String selectId = "SELECT nextval('"+VGI_SCHEMA_NAME+".observations_vgi_obs_vgi_id_seq'::regclass);";
+            ResultSet resId = SQLExecutor.getInstance().executeQuery(selectId);
+            if(resId.next()){
+                return resId.getInt(1);
+            }
+            else{
+                throw new SQLException("Observation can't get new ID!");
+            }
+        } catch(SQLException e){
+            throw new SQLException("Observation can't get new ID!");
+        }
+    }
+    
+    /**
+     * Method converts given ResultSet with selected one VgiObservation object
+     * to JSONObject in GeoJSON format
+     * @param res - ResultSet containing one VgiObservation object
+     * @return VgiObservation object in GeoJSON format as JSONObject
+     * @throws SQLException
+     */
+    private JSONObject convertVgiObservationResultSet2GeoJSON(ResultSet res) throws SQLException{
+        if(res.next()){
+            // feature
+            JSONObject feature = new JSONObject();
+            feature.put("type", "Feature");
+            feature.put("geometry", res.getString("st_asgeojson"));
+            // properties
+            JSONObject properties = new JSONObject();
+            properties.put(VgiParams.ATTRIBUTES_NAME, res.getString("attributes") == null ? "" : res.getString("attributes"));
+            properties.put(VgiParams.CATEGORY_ID_NAME, res.getInt("category_id"));
+            properties.put(VgiParams.DATASET_ID_NAME, res.getInt("dataset_id"));
+            properties.put(VgiParams.DESCRIPTION_NAME, res.getString("description") == null ? "" : res.getString("description"));
+            properties.put(VgiParams.MEDIA_COUNT_NAME, res.getInt("media_count"));
+            properties.put(VgiParams.OBS_VGI_ID_NAME, res.getInt("obs_vgi_id"));
+            properties.put(VgiParams.TIMESTAMP_NAME, res.getString("time_stamp"));
+            properties.put(VgiParams.UNIT_ID_NAME, res.getLong("unit_id"));
+            properties.put(VgiParams.TIME_RECEIVED_NAME, res.getString("time_received"));
+            properties.put(VgiParams.ALT_NAME, res.getDouble("altitude"));
+            properties.put(VgiParams.DOP_NAME, res.getDouble("dop"));
+            feature.put("properties", properties);
+            return feature;
+        }
+        else{
+            return new JSONObject();
+        }
+    }
+    
+    /**
+     * Method converts given ResultSet with selected VgiObservation objects 
+     * to LinkedList of GeoJSON objects
+     * @param res - ResultSet containing VgiObservation objects
+     * @return LinkedList of VgiObservation objects in GeoJSON format
+     * @throws SQLException
+     */
+    private LinkedList<JSONObject> convertVgiObsResultSet2GeoJSON(ResultSet res) throws SQLException{
+        LinkedList<JSONObject> vgiObsList = new LinkedList<JSONObject>();
+        while(res.next()){
+            // feature
+            JSONObject feature = new JSONObject();
+            feature.put("type", "Feature");
+            feature.put("geometry", res.getString("st_asgeojson"));
+            // properties
+            JSONObject properties = new JSONObject();
+            properties.put(VgiParams.ATTRIBUTES_NAME, res.getString("attributes") == null ? "" : res.getString("attributes"));
+            properties.put(VgiParams.CATEGORY_ID_NAME, res.getInt("category_id"));
+            properties.put(VgiParams.DATASET_ID_NAME, res.getInt("dataset_id"));
+            properties.put(VgiParams.DESCRIPTION_NAME, res.getString("description") == null ? "" : res.getString("description"));
+            properties.put(VgiParams.MEDIA_COUNT_NAME, res.getInt("media_count"));
+            properties.put(VgiParams.OBS_VGI_ID_NAME, res.getInt("obs_vgi_id"));
+            properties.put(VgiParams.TIMESTAMP_NAME, res.getString("time_stamp"));
+            properties.put(VgiParams.UNIT_ID_NAME, res.getLong("unit_id"));
+            properties.put(VgiParams.TIME_RECEIVED_NAME, res.getString("time_received"));
+            properties.put(VgiParams.ALT_NAME, res.getDouble("altitude"));
+            properties.put(VgiParams.DOP_NAME, res.getDouble("dop"));
+            feature.put("properties", properties);
+            
+            vgiObsList.add(feature);
+        }
+        return vgiObsList;
+    }
+    
+    /**
+     * Method converts List of VgiObservations as JSONObjects 
+     * to one JSONObject representing FeatureCollection in GeoJSON format
+     * @param obsList - List of VgiObservations as JSONObjects
+     * @return JSONObject with FeatureCollection in GeoJSON format
+     */
+    public static JSONObject convertListVgiObservations2GeoJSON(List<JSONObject> obsList){
+        JSONObject featureCollection = new JSONObject();
+        // Features
+        JSONArray featureList = new JSONArray();
+        featureList.addAll(obsList);
+        
+        // FeatureCollection
+        featureCollection.put("type", "FeatureCollection");
+        featureCollection.put("features", featureList);
+        
+        return featureCollection;
+    }
+}

+ 78 - 0
src/main/java/cz/hsrs/db/vgi/util/VgiParams.java

@@ -0,0 +1,78 @@
+/**
+ * 
+ */
+package cz.hsrs.db.vgi.util;
+
+
+/**
+ * Class contains names of attributes for REST methods
+ * and Classes serialization
+ * @author mkepka
+ *
+ */
+public class VgiParams {
+
+	/*
+	 * VgiObservation
+	 */
+    public static final String OBS_VGI_ID_NAME = "obs_vgi_id";
+    public static final String DESCRIPTION_NAME = "description";
+    public static final String ATTRIBUTES_NAME = "attributes";
+    
+    /*
+     * Timestamp
+     */
+    public static final String TIMESTAMP_NAME = "time_stamp";
+    public static final String FROM_TIME_NAME = "from_time";
+    public static final String TO_TIME_NAME = "to_time";
+    public static final String TIME_RECEIVED_NAME = "time_received";
+    
+    /*
+     * Category
+     */
+    public static final String CATEGORY_ID_NAME = "category_id";
+    public static final String CATEGORY_NAME_NAME = "category_name";
+    
+    /*
+     * Dataset
+     */
+    public static final String DATASET_ID_NAME = "dataset_id";
+    public static final String DATASET_NAME_NAME = "dataset_name";
+    
+    /*
+     * Unit
+     */
+    public static final String UNIT_ID_NAME = "unit_id";
+    public static final String UUID_NAME = "uuid";
+    
+    /*
+     * Geometry
+     */
+    public static final String LAT_NAME = "lat";
+    public static final String LON_NAME = "lon";
+    public static final String ALT_NAME = "alt";
+    public static final String DOP_NAME = "dop";
+    public static final String EXTENT_NAME = "extent";
+    
+    /*
+     * Media
+     */
+    public static final String MEDIA_NAME = "media";
+    public static final String MEDIA_ID_NAME = "media_id";
+    public static final String MEDIA_TYPE_NAME = "media_type";
+    public static final String MEDIA_COUNT_NAME = "media_count";
+    public static final String OBSERVED_MEDIA_NAME = "observed_media";
+    
+    /*
+     * User
+     */
+    public static final String USER_NAME = "user_name";
+    public static final String USER_ID_NAME = "user_id";
+    
+    /*
+     * Format
+     */
+    public static final String FORMAT_NAME = "format";
+    public static final String FORMAT_GEOJSON_NAME = "geojson";
+    public static final String FORMAT_RDF_XML_NAME = "rdf+xml";
+}

+ 34 - 0
src/main/java/cz/hsrs/rest/SCListener.java

@@ -0,0 +1,34 @@
+package cz.hsrs.rest;
+
+import cz.hsrs.db.pool.SQLExecutor;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.io.FileInputStream;
+import java.util.Properties;
+
+/**
+ * 
+ * @author mkepka
+ *
+ */
+public class SCListener implements ServletContextListener {
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+        String propFile = sce.getServletContext().getRealPath("WEB-INF/database.properties");
+        Properties prop = new Properties();
+        try {
+            prop.load(new FileInputStream(propFile));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        sce.getServletContext().setAttribute("props", prop);
+        SQLExecutor.setProperties(prop);
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        SQLExecutor.close();
+    }
+}

+ 60 - 0
src/main/java/cz/hsrs/rest/beans/VgiObservationBean.java

@@ -0,0 +1,60 @@
+package cz.hsrs.rest.beans;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+
+public class VgiObservationBean {
+
+	@JsonProperty("obsId")
+    public int obsVgiId;
+    public Integer gid;
+    public String timeString;
+    public int categoryId;
+    public String description;
+    public String attributes;
+    public int datasetId;
+    public long unitId;
+    public int userId;
+    public String timeReceived;
+    public int mediaCount;
+    public String geoJSON;
+    
+    public VgiObservationBean() {}
+    
+    public VgiObservationBean(int obsVgiId, Integer gid, String timeString,
+            int categoryId, String description, String attributes,
+            int datasetId, long unitId, int userId, String timeReceived,
+            int mediaCount)
+    {
+        this.obsVgiId = obsVgiId;
+        this.gid = gid;
+        this.timeString = timeString;
+        this.categoryId = categoryId;
+        this.description = description;
+        this.attributes = attributes;
+        this.datasetId = datasetId;
+        this.unitId = unitId;
+        this.userId = userId;
+        this.timeReceived = timeReceived;
+        this.mediaCount = mediaCount;
+    }
+    
+    public VgiObservationBean(int obsVgiId, Integer gid, String timeString,
+            int categoryId, String description, String attributes,
+            int datasetId, long unitId, int userId, String timeReceived,
+            int mediaCount, String geomJson)
+    {
+        this.obsVgiId = obsVgiId;
+        this.gid = gid;
+        this.timeString = timeString;
+        this.categoryId = categoryId;
+        this.description = description;
+        this.attributes = attributes;
+        this.datasetId = datasetId;
+        this.unitId = unitId;
+        this.userId = userId;
+        this.timeReceived = timeReceived;
+        this.mediaCount = mediaCount;
+        this.geoJSON = geomJson;
+    }
+}

+ 92 - 0
src/main/java/cz/hsrs/rest/beans/VgiObservationRdfBean.java

@@ -0,0 +1,92 @@
+package cz.hsrs.rest.beans;
+
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlValue;
+
+public class VgiObservationRdfBean {
+
+    @XmlAttribute(name = "about", namespace="http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+    public String about;
+    
+    @XmlElement(name = "label", namespace = "http://www.w3.org/2000/01/rdf-schema")
+    public String label;
+    
+    @XmlElement(name = "asWKT", namespace = "http://www.opengis.net/ont/geosparql")
+    public KombiElement asWkt;
+    
+    @XmlElement(name = "identifier", namespace = "http://purl.org/dc/elements/1.1/")
+    public AttributeElement identifier;
+    
+    @XmlElement(name = "publisher", namespace = "http://purl.org/dc/elements/1.1/")
+    public String publisher;
+    
+    @XmlElement(name = "title", namespace = "http://purl.org/dc/elements/1.1/")
+    public String title;
+    
+    @XmlElement(name = "rights", namespace = "http://purl.org/dc/elements/1.1/")
+    public AttributeElement rights;
+    
+    @XmlElement(name = "source", namespace = "http://purl.org/dc/elements/1.1/")
+    public AttributeElement source;
+    
+    @XmlElement(name = "created", namespace = "http://purl.org/dc/terms/")
+    public KombiElement created;
+    
+    @XmlElement(name = "class", namespace = "http://www.openvoc.eu/poi")
+    public AttributeElement poiClass;
+
+    public VgiObservationRdfBean(){}
+    
+    public VgiObservationRdfBean(String geomAsWkt, int obsVgiId,
+            String name, long unitId, String timestamp, int categoryId)
+    {
+        String ID = "http://portal.sdi4apps.eu/SensLog/poi/#"+obsVgiId; // jaky zvolit ID?
+        this.about = ID;
+        this.label = name;
+        this.asWkt = new KombiElement("http://www.openlinksw.com/schemas/virtrdf#Geometry", geomAsWkt);
+        this.identifier = new AttributeElement(ID);
+        this.publisher = "SPOI (http://sdi4apps.eu/spoi)";
+        this.title = name;
+        this.rights = new AttributeElement("http://opendatacommons.org/licenses/odbl/1.0/");
+        this.source = new AttributeElement("http://portal.sdi4apps.eu/SensLog/unit/#"+unitId);
+        this.created = new KombiElement("http://www.w3.org/2001/XMLSchema#date", timestamp);
+        this.poiClass = new AttributeElement("http://portal.sdi4apps.eu/SensLog/category/#"+String.valueOf(categoryId));
+    }
+    
+    static class KombiElement{
+        private String att;
+        private String val;
+        
+        public KombiElement(){}
+        
+        public KombiElement(String thisAtt, String thisValue) {
+            this.att = thisAtt;
+            this.val = thisValue;
+        }
+        @XmlAttribute(name = "datatype", namespace="http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+        public String getThisAtt(){
+            return att; 
+        }
+        
+        @XmlValue
+        public String getValue(){
+            return val;
+        }
+    }
+    
+    static class AttributeElement{
+        private String att;
+        
+        public AttributeElement(){}
+        
+        public AttributeElement(String thisAtt) {
+            this.att = thisAtt;
+        }
+        @XmlAttribute(name = "resource", namespace="http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+        public String getThisAtt(){
+            return att; 
+        }
+    }
+
+}

+ 22 - 0
src/main/java/cz/hsrs/rest/beans/VgiObservationsRdfBean.java

@@ -0,0 +1,22 @@
+package cz.hsrs.rest.beans;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+@XmlRootElement(name = "RDF", namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+public class VgiObservationsRdfBean {
+    
+    private List<VgiObservationRdfBean> observations;
+    
+    public VgiObservationsRdfBean(){}
+    
+    public VgiObservationsRdfBean(List<VgiObservationRdfBean> observationList){
+        this.observations = observationList;
+    }
+    
+    @XmlElement(name = "Description", namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+    public List<VgiObservationRdfBean> getObsList(){
+        return this.observations;
+    }
+}

+ 31 - 0
src/main/java/cz/hsrs/rest/util/BasicAuth.java

@@ -0,0 +1,31 @@
+package cz.hsrs.rest.util;
+
+import javax.xml.bind.DatatypeConverter;
+
+/**
+ * Class that converts Basic authorization String to username/password pair 
+ * @author mkepka
+ *
+ */
+public class BasicAuth {
+
+	/**
+     * Decode the basic auth and convert it to array login/password
+     * @param auth The string encoded authentication
+     * @return The login (case 0), the password (case 1)
+     */
+    public static String[] decode(String auth) {
+        //Replacing "Basic THE_BASE_64" to "THE_BASE_64" directly
+        auth = auth.replaceFirst("[B|b]asic ", "");
+        //Decode the Base64 into byte[]
+        byte[] decodedBytes = DatatypeConverter.parseBase64Binary(auth);
+        //If the decode fails in any case
+        if(decodedBytes == null || decodedBytes.length == 0){
+            return null;
+        }
+        //Now we can convert the byte[] into a splitted array :
+        //  - the first one is login,
+        //  - the second one password
+        return new String(decodedBytes).split(":", 2);
+    }
+}

+ 16 - 0
src/main/java/cz/hsrs/rest/util/CorsFilter.java

@@ -0,0 +1,16 @@
+package cz.hsrs.rest.util;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+
+public class CorsFilter implements ContainerResponseFilter {
+
+    @Override
+    public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
+        requestContext.getHeaders().add("Access-Control-Allow-Origin", "*");
+        requestContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
+        requestContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
+        requestContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
+    }
+}

+ 91 - 0
src/main/java/cz/hsrs/rest/util/ExportVgiRestUtil.java

@@ -0,0 +1,91 @@
+package cz.hsrs.rest.util;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.vgi.Envelope2D;
+import cz.hsrs.db.model.vgi.VgiObservationRdf;
+import cz.hsrs.db.util.DateUtil;
+import cz.hsrs.db.util.UserUtil;
+import cz.hsrs.db.vgi.util.VgiObservationUtil;
+import cz.hsrs.rest.beans.VgiObservationRdfBean;
+
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Utility class processes requests received by ExportVgiRest class
+ * @author mkepka
+ *
+ */
+public class ExportVgiRestUtil {
+    
+    private final UserUtil userUt;
+    private final VgiObservationUtil oUtil;
+    
+    public ExportVgiRestUtil(){
+        userUt = new UserUtil();
+        oUtil = new VgiObservationUtil();
+    }
+
+    public List<VgiObservationRdfBean> processGetObservationExport(int obsId, String username) throws SQLException{
+        try{
+            int userId = userUt.getUserId(username);
+            VgiObservationRdf obs = oUtil.getVgiObservationByObsIdForRdf(obsId, userId);
+
+            List<VgiObservationRdfBean> obsList = new LinkedList<VgiObservationRdfBean>();
+            obsList.add(new VgiObservationRdfBean(
+                    obs.getGeom(),
+                    obs.getObsVgiId(),
+                    (obs.getName() != null)?obs.getName():"Observation_"+obs.getObsVgiId(),
+                    obs.getUnitId(),
+                    obs.getDateString(),
+                    obs.getCategoryId()));
+            return obsList;
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+
+    public List<VgiObservationRdfBean> processGetVgiObservationsExport(
+            String username, Integer categoryId, Integer datasetId,
+            String fromTime, String toTime, String extentArr, Long unitId) throws SQLException
+    {
+        try{
+            int userId = userUt.getUserId(username);
+            String from = null;
+            String to = null;
+            Envelope2D extent = null;
+            if(fromTime != null){
+                Date fromDate = DateUtil.parseTimestamp(fromTime);
+                from = DateUtil.formatMiliSecsTZ.format(fromDate);
+            }
+            if(toTime != null){
+                Date toDate = DateUtil.parseTimestamp(toTime);
+                to = DateUtil.formatMiliSecsTZ.format(toDate);
+            }
+            if(extentArr != null && !extentArr.isEmpty()){
+                extent = new Envelope2D(extentArr);
+            }
+            
+            List<VgiObservationRdf> obsList = oUtil.getVgiObservationsByUserForRdf(userId, from, to,
+                    categoryId, datasetId, extent, unitId);
+            List<VgiObservationRdfBean> obsBeanList = new LinkedList<VgiObservationRdfBean>();
+            if(!obsList.isEmpty()){
+                for (VgiObservationRdf obs : obsList) {
+                    obsBeanList.add(new VgiObservationRdfBean(
+                            obs.getGeom(),
+                            obs.getObsVgiId(),
+                            (obs.getName() != null) ? obs.getName() : "Observation_" + obs.getObsVgiId(),
+                            obs.getUnitId(),
+                            obs.getDateString(),
+                            obs.getCategoryId()));
+                }
+            }
+            return obsBeanList;
+        } catch(NoItemFoundException | ParseException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 151 - 0
src/main/java/cz/hsrs/rest/util/RestUtil.java

@@ -0,0 +1,151 @@
+package cz.hsrs.rest.util;
+
+import cz.hsrs.db.model.vgi.VgiObservation;
+import cz.hsrs.db.util.VgiUtil;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.sql.SQLException;
+
+/**
+ * Utility class with methods for inserting new POI
+ * @author mkepka
+ */
+public class RestUtil {
+
+    private static final int THUMBNAIL_RATIO = 8;
+    
+    public RestUtil() {}
+
+    
+    /**
+     * TEST method to load image file from database
+     * @param imageId id of image in database as String
+     * @return return true if image was loaded from database and saved as file to disc, or false 
+     */
+    public boolean testPoiLoad(String imageId, String path){
+        boolean loaded = false;
+        File imageOut = VgiUtil.testSelectImage(Long.parseLong(imageId), path);
+        VgiUtil.testSelectThumbnail(Long.parseLong(imageId), path);
+        if(imageOut != null){
+            if(imageOut.exists()){
+                loaded = imageOut.exists();
+            }
+        }
+        return loaded;
+    }
+
+    /**
+     * Method processes parameters received from Servlet
+     * 
+     * @param titleValue String with value of Title parameter
+     * @param descValue String with value of Description parameter
+     * @param catValue String with value of Category parameter
+     * @param statValue String with value of Status parameter
+     * @param lonValue String with value of Longitude parameter
+     * @param latValue String with value of Latitude parameter
+     * @param timestampValue String with value of Timestamp parameter
+     * @param startTimeValue String with value of StartTimestamp parameter
+     * @param userName String with name of user
+     * @param fileInStream InputStream with picture file 
+     * @param fileSize size of picture file in bytes
+     * @param rotationAng angle to rotate given picture
+     * @return true if parameters were stored successfully, or false if not
+     */
+    public boolean processPoi(String titleValue, String descValue, String catValue, String statValue,
+                              String lonValue, String latValue, String timestampValue, String startTimeValue,
+                              String userName, InputStream fileInStream, long fileSize, int rotationAng)
+    {
+        // fields of form
+        try {
+            if(titleValue != null && lonValue != null && latValue != null && userName != null && timestampValue != null){
+                if(titleValue.isEmpty() || lonValue.isEmpty() || latValue.isEmpty() || userName.isEmpty() && timestampValue.isEmpty()){
+                    return false;
+                } else{
+                    long poiId = VgiUtil.insertPoi(titleValue, descValue, catValue, statValue, lonValue, latValue, timestampValue, startTimeValue, userName);
+                    System.out.println("New POI (id="+poiId+") inserted!");
+                    
+                    if(fileInStream != null && fileSize > 0){
+                        BufferedImage photo = ImageIO.read(fileInStream);
+                        
+                        // rotate if necessary
+                        BufferedImage rotatedImage;
+                        if(rotationAng != 0){
+                            rotatedImage = VgiUtil.rotate(photo, rotationAng);
+                        }
+                        else{
+                            rotatedImage = photo;
+                        }
+                        
+                        // create thumbnail
+                        int tW = rotatedImage.getWidth()/THUMBNAIL_RATIO;
+                        int tH = rotatedImage.getHeight()/THUMBNAIL_RATIO;
+                        BufferedImage thumb = VgiUtil.rescale(rotatedImage, tW, tH);
+                        
+                        //write to database picture and its thumbnail
+                        ByteArrayOutputStream baosRot = new ByteArrayOutputStream();
+                        ImageIO.write(rotatedImage, "png", baosRot);
+                        byte[] rotArr = baosRot.toByteArray();
+                        InputStream isRot = new ByteArrayInputStream(rotArr);
+                        long imageId = VgiUtil.insertPoiImage(poiId, isRot, rotArr.length);
+                        
+                        ByteArrayOutputStream baosThumb = new ByteArrayOutputStream();
+                        ImageIO.write(thumb, "png", baosThumb);
+                        byte[] thumbArr = baosThumb.toByteArray();
+                        InputStream isThumb = new ByteArrayInputStream(thumbArr);
+                        VgiUtil.insertPoiImageThumbnail(imageId, isThumb, thumbArr.length);
+                        return true;
+                    } else{
+                        return true;
+                    }
+                }
+            } else{
+                return false;
+            }
+        } catch (SQLException | IOException e) {
+            System.err.println(e.getMessage());
+            return false;
+        }
+    }
+    
+    public void processCitiSense() throws Exception{
+        File jsonFile = new File("test/citi-sense_at8_07-08.json");
+        BufferedReader buff = new BufferedReader(new FileReader(jsonFile));
+        StringBuilder strBuff = new StringBuilder();
+        String line;
+        while((line = buff.readLine()) != null){
+            strBuff.append(line);
+        }
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        String content = strBuff.toString();
+        JSONArray jsonArr = JSONArray.fromObject(content);
+        for(int i = 0; i < jsonArr.size(); i++){
+            JSONObject meas = jsonArr.getJSONObject(i);
+            JSONObject atts = new JSONObject();
+            atts.accumulate("name", "AT_8 measurement");
+            atts.accumulate("observedproperty", meas.getString("observedproperty"));
+            atts.accumulate("value", meas.getDouble("value"));
+            atts.accumulate("uom", meas.getString("uom"));
+            VgiObservation obs = orUtil.processInsertVgiObs(
+            		meas.getString("measure_time"),
+            		2,
+            		"measurement from CITI-sense",
+            		atts.toString(),
+            		"8L",
+            		null,
+            		"citi",
+            		1,
+            		"10.48154", 
+            		"59.41901",
+            		null,
+            		null, 
+            		null, 
+            		null);
+            System.out.println(obs.getObsVgiId());
+        }
+        buff.close();
+    }
+}

+ 68 - 0
src/main/java/cz/hsrs/rest/util/VgiCategoryRestUtil.java

@@ -0,0 +1,68 @@
+package cz.hsrs.rest.util;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.vgi.VgiCategory;
+import cz.hsrs.db.util.UserUtil;
+import cz.hsrs.db.vgi.util.VgiCategoryUtil;
+
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Utility class for VgiCategoryRest services
+ * @author mkepka
+ *
+ */
+public class VgiCategoryRestUtil {
+
+    private final UserUtil userUt;
+    private final VgiCategoryUtil cUtil;
+
+    public VgiCategoryRestUtil(){
+        this.userUt = new UserUtil();
+        this.cUtil = new VgiCategoryUtil();
+    }
+    
+    /**
+     * Method processes GetVgiCategory by given categoryId
+     * @param categoryId - ID of category
+     * @param userName - name of user
+     * @return VgiCategory object if there is one in the DB
+     */
+    public VgiCategory processGetVgiCategory(int categoryId, String userName) throws SQLException{
+        try{
+            userUt.getUserId(userName);
+            return cUtil.getVgiCategory(categoryId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes GetVgiCategory by given categoryId
+     * @param categoryId - ID of category
+     * @param userName - name of user
+     * @return VgiCategory object if there is one in the DB
+     */
+    public List<VgiCategory> processGetVgiCategoryDescendants(int categoryId, String userName) throws SQLException{
+        try{
+            userUt.getUserId(userName);
+            return cUtil.getVgiCategoryDescendants(categoryId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes SelectVgiCategories by given user
+     * @return LinkedList of VgiCategory objects associated to given user
+     */
+    public List<VgiCategory> processGetVgiCategories(String userName) throws SQLException{
+        try{
+            userUt.getUserId(userName);
+            return cUtil.getCategoriesList();
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 90 - 0
src/main/java/cz/hsrs/rest/util/VgiDatasetRestUtil.java

@@ -0,0 +1,90 @@
+package cz.hsrs.rest.util;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.vgi.VgiDataset;
+import cz.hsrs.db.util.UserUtil;
+import cz.hsrs.db.vgi.util.VgiDatasetsUtil;
+import net.sf.json.JSONObject;
+
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Utility class for VgiDatasetRest services
+ * @author mkepka
+ *
+ */
+public class VgiDatasetRestUtil {
+
+    private UserUtil userUt;
+    private VgiDatasetsUtil dUtil;
+    
+    public VgiDatasetRestUtil(){
+        this.userUt = new UserUtil();
+        this.dUtil = new VgiDatasetsUtil();
+    }
+    
+    /**
+     * Method processes creating of new VgiDataset object
+     * and inserts it to the DB
+     * @param dataset object as JSON
+     * @return new ID of the VgiDataset in DB
+     */
+    public int processInsertVgiDataset(JSONObject dataset, String userName) throws SQLException {
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiDataset newDataset = new VgiDataset(
+                    dataset.getString("dataset_name"),
+                    dataset.getString("description"), 
+                    userId);
+            return newDataset.insertToDB();
+        } catch(SQLException | NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes GetVgiDataset by given datasetId
+     * @param datasetId - ID of dataset
+     * @param userName - name of user
+     * @return VgiDataset object if there is one in the DB
+     */
+    public VgiDataset processGetVgiDataset(int datasetId, String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            return dUtil.getVgiDataset(userId, datasetId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes SelectVgiDatasets by given user
+     * @param userName - name of user
+     * @return LinkedList of VGIDataset objects associated to given user
+     */
+    public List<VgiDataset> processGetVgiDatasets(String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            return dUtil.getDatasetsList(userId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes DeleteVgiDataset by given datasetID
+     * @param datasetId - ID of VgiDataset to be deleted
+     * @param userName - name of user
+     * @return true if VgiDataset was deleted, false if not
+     */
+    public boolean processDeleteVgiDataset(int datasetId, String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            int row = dUtil.deleteVgiDataset(userId, datasetId);
+            return row == 1;
+        } catch(SQLException | NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 660 - 0
src/main/java/cz/hsrs/rest/util/VgiObservationRestUtil.java

@@ -0,0 +1,660 @@
+package cz.hsrs.rest.util;
+
+import cz.hsrs.db.DatabaseFeedOperation;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.vgi.Envelope2D;
+import cz.hsrs.db.model.vgi.VgiMedia;
+import cz.hsrs.db.model.vgi.VgiObservation;
+import cz.hsrs.db.util.DateUtil;
+import cz.hsrs.db.util.UnitUtil;
+import cz.hsrs.db.util.UserUtil;
+import cz.hsrs.db.util.VgiUtil;
+import cz.hsrs.db.vgi.util.VgiMediaUtil;
+import cz.hsrs.db.vgi.util.VgiObservationUtil;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import org.apache.poi.util.IOUtils;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Utility class processes requests received by VgiObservationRest class
+ * @author mkepka
+ *
+ */
+public class VgiObservationRestUtil {
+
+    private static final int THUMBNAIL_WIDTH = 100;
+
+    private final UserUtil userUt;
+    private final UnitUtil unitUt;
+    private final VgiObservationUtil oUtil;
+    private final VgiMediaUtil mUtil;
+
+    public VgiObservationRestUtil(){
+        userUt = new UserUtil();
+        unitUt = new UnitUtil();
+        oUtil = new VgiObservationUtil();
+        mUtil = new VgiMediaUtil();
+    }
+    
+    /**
+     * Method processes creating of new VgiObservation object
+     * and inserts it to the DB 
+     * @param timestampValue - time stamp when observation was obtained, mandatory
+     * @param catValue - ID of VgiCategory, mandatory
+     * @param descValue - description of VgiObservation, optional
+     * @param attsValue - further attributes in JSON format as String
+     * @param datasetId - ID of VgiDataset, mandatory
+     * @param unitIdValue - ID of unit that has produced observation, mandatory if uuid is not present
+     * @param uuidValue - ID of device that has produced observation, mandatory if unitId is not present 
+     * @param userName - name of user that produced the observation, mandatory
+     * @param lonValue - Longitude of observation, mandatory
+     * @param latValue - Latitude of observation, mandatory
+     * @param altValue - Altitude of observation, optional
+     * @param dopValue - Dilution of precision, optional 
+     * @param fileInStream - InputStream with associated media, optional 
+     * @param mediaType - Data type of associated media file, mandatory
+     * @return ID of new VgiObservation object
+     */
+    public VgiObservation processInsertVgiObs(String timestampValue, Integer catValue, String descValue, String attsValue,
+            String unitIdValue, String uuidValue, String userName, Integer datasetId, String lonValue, String latValue, String altValue,
+            String dopValue, InputStream fileInStream, String mediaType) throws Exception
+    {
+        int obsId = 0;
+        int newGid = 0;
+        int newMedId = 0;
+        
+        // get userId from userName
+        int userId = userUt.getUserId(userName);
+        
+        // check of unitId
+        Long unitId;
+        if((unitIdValue == null || unitIdValue.isEmpty()) && (uuidValue == null || uuidValue.isEmpty())){
+            throw new Exception("ID of device has to be defined!");
+        } else if((unitIdValue != null && !unitIdValue.isEmpty()) && (uuidValue == null || uuidValue.isEmpty())){
+            unitId = Long.parseLong(unitIdValue);
+        } else if((unitIdValue == null || unitIdValue.isEmpty()) && (uuidValue != null && !uuidValue.isEmpty())){
+            unitId = new BigInteger(uuidValue, 16).longValue();
+        } else{
+            throw new Exception("Correct ID of device has to be defined!");
+        }
+        // check mandatory attributes and the geometry
+        if(lonValue != null && 
+            latValue != null &&
+            timestampValue != null &&
+            catValue != null &&
+            datasetId != null){
+            
+            Date posDate = DateUtil.parseTimestamp(timestampValue);
+            newGid = DatabaseFeedOperation.insertPositionByGid(
+                        unitId,
+                        Double.valueOf(latValue), 
+                        Double.valueOf(lonValue),
+                        (altValue != null && !altValue.isEmpty()) ? Double.valueOf(altValue) : Double.NaN,
+                        (dopValue != null && !dopValue.isEmpty()) ? Double.valueOf(dopValue) : Double.NaN,
+                        posDate, 
+                        Double.NaN, 
+                        "4326");
+            // ins observation
+            if(newGid != 0){
+                obsId = VgiObservationUtil.insertVgiObs(
+                            newGid, 
+                            DateUtil.formatSecsTZ.format(posDate), 
+                            catValue, 
+                            descValue, 
+                            attsValue, 
+                            unitId, 
+                            userId, 
+                            datasetId);
+                if(fileInStream != null){
+                    try{
+                        if(mediaType.startsWith("image/")){
+                            newMedId = insertImage(fileInStream, obsId, mediaType);
+                        } else{
+                            newMedId = insertMedia(obsId, fileInStream, mediaType);
+                        }
+                    } catch(Exception e){
+                        if(!e.getMessage().equalsIgnoreCase("Any media was given!")){
+                            throw new Exception (e.getMessage());
+                        }
+                    }
+                }
+                return new VgiObservation(obsId, newMedId);
+            } else{
+                throw new Exception("Mandatory attributes of VGIObservation have to be given!");
+            }
+        } else{
+            throw new Exception("Mandatory attributes of VGIObservation have to be given!");
+        }
+    }
+    
+    /**
+     * Method processes updating of stored VgiObservation object
+     * 
+     * @param obsId - ID of stored VgiObservation object to be updated
+     * @param timestampValue - time stamp when observation was obtained, mandatory
+     * @param catValue - ID of VgiCategory, mandatory
+     * @param descValue - description of VgiObservation, optional
+     * @param attsValue - further attributes in JSON format as String
+     * @param unitIdValue - ID of unit that has produced observation, mandatory if uuid is not present
+     * @param uuidValue - ID of device that has produced observation, mandatory if unitId is not present 
+     * @param userName - name of user that produced the observation, mandatory
+     * @param datasetId - ID of VgiDataset, mandatory
+     * @param lonValue - Longitude of observation, mandatory
+     * @param latValue - Latitude of observation, mandatory
+     * @param altValue - Altitude of observation, optional
+     * @param dopValue - Dilution of precision, optional
+     * @param fileInStream - InputStream with associated media, optional 
+     * @param mediaType - Data type of associated media file, mandatory
+     * @return true if VgiObservation was updated
+     */
+    public VgiObservation processUpdateVgiObs(Integer obsId, String timestampValue, Integer catValue, String descValue,
+            String attsValue, String unitIdValue, String uuidValue, String userName, Integer datasetId, String lonValue, String latValue, 
+            String altValue, String dopValue, InputStream fileInStream, String mediaType) throws Exception {
+        // get userId from userName
+        int userId = userUt.getUserId(userName);
+        boolean updated = false;
+        int newMedId = 0;
+        // check of ID of device
+        Long unitId = null;
+        if((unitIdValue == null || unitIdValue.isEmpty()) && (uuidValue == null || uuidValue.isEmpty())){
+            throw new Exception("ID of device has to be defined!");
+        }
+        else if((unitIdValue != null && !unitIdValue.isEmpty()) && (uuidValue == null || uuidValue.isEmpty())){
+            unitId = Long.parseLong(unitIdValue);
+        }
+        else if((unitIdValue == null || unitIdValue.isEmpty()) && (uuidValue != null && !uuidValue.isEmpty())){
+            unitId = new BigInteger(uuidValue, 16).longValue();
+        } else{
+            throw new Exception("Correct ID of device has to be defined!");
+        }
+        if(unitId != null) {
+            // check if there is VgiObservation to update
+            VgiObservation oldObs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(oldObs == null){
+                throw new SQLException("VGI Observation with given ID does not exist!");
+            }
+            else {
+                // check mandatory attributes and the geometry
+                if(lonValue != null &&
+                    latValue != null &&
+                    timestampValue != null &&
+                    catValue != null &&
+                    datasetId != null){
+
+                    Date newPosDate = DateUtil.parseTimestamp(timestampValue);
+                    UnitPosition oldPos = unitUt.getPositionByGid(oldObs.getGid());
+                    boolean updatedPos = false;
+                    int insGid;
+
+                    Double newLon = Double.parseDouble(lonValue);
+                    Double newLat = Double.parseDouble(latValue);
+                    Double newAlt = (altValue != null && !altValue.isEmpty()) ? Double.parseDouble(altValue) : Double.NaN;
+                    Double newDop = (dopValue != null && !dopValue.isEmpty()) ? Double.parseDouble(dopValue) : Double.NaN;
+                 // same position
+                    if(oldPos.getX() == newLon &&
+                        oldPos.getY() == newLat &&
+                        oldPos.getAlt() == newAlt &&
+                        oldPos.internalGetTimestamp() == newPosDate){
+                        // not necessary to update position
+                        updatedPos = true;
+                        insGid = oldPos.getGid();
+                    } else{
+                        Calendar cal = Calendar.getInstance();
+                        cal.setTime(newPosDate);
+                        int newMonth = cal.get(Calendar.MONTH);
+                        cal.setTime(oldPos.internalGetTimestamp());
+                        int oldMonth = cal.get(Calendar.MONTH);
+
+                        if(newMonth != oldMonth){
+                            // delete old one !!!
+
+                            //insert new with some equal attributes
+                            insGid = DatabaseFeedOperation.insertPositionByGid(
+                                    oldPos.getUnit_id(),
+                                    newLat,
+                                    newLon,
+                                    newAlt,
+                                    newDop,
+                                    newPosDate,
+                                    Double.NaN,
+                                    "4326");
+                        }
+                        else{
+                            UnitPosition newPos = new UnitPosition(oldPos.getGid(),
+                                    oldPos.getUnit_id(),
+                                    newLon,
+                                    newLat,
+                                    newAlt,
+                                    newPosDate,
+                                    newDop,
+                                    Double.NaN,
+                                    "4326");
+                            updatedPos = DatabaseFeedOperation.updatePositionByGid(newPos);
+                            insGid = oldPos.getGid();
+                        }
+                    }
+                    // update observation
+                    if(updatedPos){
+                        updated = VgiObservationUtil.updateVgiObs(
+                                obsId,
+                                insGid,
+                                DateUtil.formatSecsTZ.format(newPosDate),
+                                catValue,
+                                descValue,
+                                attsValue,
+                                unitId,
+                                userId,
+                                datasetId);
+                        if(fileInStream != null){
+                            try{
+                                if(mediaType.startsWith("image/")){
+                                    newMedId = insertImage(fileInStream, obsId, mediaType);
+                                }
+                                else{
+                                    newMedId = insertMedia(obsId, fileInStream, mediaType);
+                                }
+                            } catch(Exception e){
+                                if(!e.getMessage().equalsIgnoreCase("Any media was given!")){
+                                    throw new Exception (e.getMessage());
+                                }
+                            }
+                        }
+                        if(updated){
+                            return new VgiObservation(obsId, newMedId);
+                        } else{
+                            throw new Exception("VgiObservation cannot be updated!");
+                        }
+                    } else{
+                        throw new Exception("VgiObservation cannot be updated!");
+                    }
+                } else{
+                    throw new Exception("Mandatory attributes of VGIObservation have to be given!");
+                }
+            }
+        } else{
+            throw new Exception("ID of device has to be defined!");
+        }
+    }
+    
+    /**
+     * Method processes get VgiObservation object by given ID
+     * @param obsId - ID of VgiObservation object
+     * @param username - name of user
+     * @return VgiObservation object in GeoJSON format
+     */
+    public VgiObservation processGetVgiObservation(int obsId, String username) throws SQLException{
+        try{
+            int userId = userUt.getUserId(username);
+            return oUtil.getVgiObservationByObsId(obsId, userId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes get specific VgiObservation object by given ID
+     * in GeoJSON format
+     * @param obsId - ID of VgiObservation object
+     * @param username - name of user
+     * @return VgiObservation object in GeoJSON format
+     */
+    public JSONObject processGetVgiObservationAsJson(int obsId, String username) throws SQLException{
+        try{
+            int userId = userUt.getUserId(username);
+            return oUtil.getVgiObservationByObsIdAsGeoJSON(obsId, userId);
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /** Method processes get List of VgiObservation objects */
+    public List<VgiObservation> processGetVgiObservationsByUser(String userName, String fromTime, String toTime, 
+            Integer datasetId, Integer categoryId, String extentArr) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            String from = null;
+            String to = null;
+            if(fromTime != null){
+                Date fromDate = DateUtil.parseTimestamp(fromTime);
+                from = DateUtil.formatMiliSecsTZ.format(fromDate);
+            }
+            if(toTime != null){
+                Date toDate = DateUtil.parseTimestamp(toTime);
+                to = DateUtil.formatMiliSecsTZ.format(toDate);
+            }
+            List<VgiObservation> obsList = null;
+            if(datasetId == null && categoryId == null){
+                obsList = oUtil.getVgiObservationsByUser(userId, from, to);
+            }
+            else if(datasetId != null && categoryId == null){
+                obsList = oUtil.getVgiObservationsByUserByDataset(userId, datasetId, from, to);
+            }
+            else if(datasetId == null && categoryId != null){
+                obsList = oUtil.getVgiObservationsByUserByCategory(userId, categoryId, from, to);
+            }
+            else if(datasetId == null && categoryId == null && extentArr != null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByExtent(userId, extent, from, to);
+            }
+            else if(datasetId != null && categoryId == null && extentArr != null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByDatasetByExtent(userId, datasetId, extent, from, to);
+            }
+            else if(datasetId != null && categoryId != null && extentArr != null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByCategoryByDatasetByExtent(userId, categoryId, datasetId, extent, fromTime, toTime);
+            }
+            
+            return obsList;
+        } catch(NoItemFoundException | ParseException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes select of VgiObservation objects by given filter parameters as GeoJSON
+     * @param userName - name of user that owns VgiObservation objects
+     * @param fromTime - beginning of time range, ISO 8601 pattern, optional
+     * @param toTime - end of time range, ISO 8601 pattern, optional
+     * @param datasetId - ID of VgiDataset, optional
+     * @param categoryId - ID of VgiCategeory, optional
+     * @param unitId - Id of device that produced VgiObservations
+     * @return VgiObservation objects in GeoJSON format
+     */
+    public JSONObject processGetVgiObservationsByUserAsJson(String userName, String fromTime, String toTime, 
+            Integer datasetId, Integer categoryId, String extentArr, Long unitId) throws SQLException
+    {
+        try{
+            int userId = userUt.getUserId(userName);
+            String from = null;
+            String to = null;
+            if(fromTime != null){
+                Date fromDate = DateUtil.parseTimestamp(fromTime);
+                from = DateUtil.formatMiliSecsTZ.format(fromDate);
+            }
+            if(toTime != null){
+                Date toDate = DateUtil.parseTimestamp(toTime);
+                to = DateUtil.formatMiliSecsTZ.format(toDate);
+            }
+            List<JSONObject> obsList = null;
+            if(datasetId == null && categoryId == null && extentArr == null && unitId == null){
+                obsList = oUtil.getVgiObservationsByUserAsJSON(userId, from, to);
+            }
+            else if(datasetId != null && categoryId == null && extentArr == null && unitId == null){
+                obsList = oUtil.getVgiObservationsByUserByDatasetAsJSON(userId, datasetId, from, to);
+            }
+            else if(datasetId == null && categoryId != null && extentArr == null && unitId == null){
+                obsList = oUtil.getVgiObservationsByUserByCategoryAsJSON(userId, categoryId, from, to);
+            }
+            else if(datasetId == null && categoryId == null && extentArr != null && unitId == null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByExtentAsJSON(userId, extent, from, to);
+            }
+            else if(datasetId == null && categoryId == null && extentArr == null && unitId != null){
+                obsList = oUtil.getVgiObservationsByUserByUnitAsJSON(userId, unitId, from, to);
+            }
+            else if(datasetId != null && categoryId == null && extentArr != null && unitId == null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByDatasetByExtentAsJSON(userId, datasetId, extent, from, to);
+            }
+            else if(datasetId != null && categoryId != null && extentArr != null && unitId == null){
+                Envelope2D extent = new Envelope2D(extentArr);
+                obsList = oUtil.getVgiObservationsByUserByCategoryByDatasetByExtentAsJSON(userId, categoryId, datasetId, extent, fromTime, toTime);
+            }
+            return VgiObservationUtil.convertListVgiObservations2GeoJSON(obsList);
+        } catch(NoItemFoundException | JSONException | ParseException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes deleting of given VgiObservation
+     * @param obsId - ID of VgiObservation object to be deleted
+     * @param userName - name of user that owns given VgiObservation object
+     * @return true if VgiObservation was deleted
+     */
+    public boolean processDeleteVgiObservation(int obsId, String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                return VgiObservationUtil.deleteVgiObservation(obsId);
+            } else{
+                throw new SQLException("VGIObservation with given ID does not exist!");
+            }
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method inserts new VgiMedia to DB
+     * @param fileInStream - InputStream containing image file
+     * @param obsId - ID of associated VgiObservation object
+     * @param mediaType - Data type of media
+     * @return ID of new VgiMedia object
+     */
+    public int insertImage(InputStream fileInStream, int obsId, String mediaType) throws Exception{
+        if(fileInStream != null){
+            try{
+                BufferedImage photo = ImageIO.read(fileInStream);
+                if(photo != null && mediaType != null && !mediaType.isEmpty()){
+                    // parse media type
+                    String[] parsedMediaType = mediaType.split("/");
+                    String formatMediaType = parsedMediaType[1];
+
+                    BufferedImage thumb;
+                    double thumbRatio = 0;
+                    int tWidthOrig = photo.getWidth();
+                    if((tWidthOrig >= THUMBNAIL_WIDTH)){ // if original photo is wider than thumbnail width then rescale
+                        thumbRatio = (double) tWidthOrig/ (double) THUMBNAIL_WIDTH;
+                        double tWidth = tWidthOrig/thumbRatio;
+                        double tHeight = photo.getHeight()/thumbRatio;
+                        thumb = VgiUtil.rescale(photo, (int)tWidth, (int)tHeight);
+                    } else { // if original photo is narrow than thumbnail width then thumbnail == photo
+                        thumb = photo;
+                    }
+                    
+                    //write picture to database
+                    ByteArrayOutputStream baosImg = new ByteArrayOutputStream();
+                    ImageIO.write(photo, formatMediaType, baosImg);
+                    byte[] imgArr = baosImg.toByteArray();
+                    InputStream isImg = new ByteArrayInputStream(imgArr);
+                    int medId = VgiMediaUtil.insertVgiMedia(obsId, isImg, imgArr.length, mediaType);
+                    
+                    // write thumbnail to DB
+                    ByteArrayOutputStream baosThumb = new ByteArrayOutputStream();
+                    ImageIO.write(thumb, formatMediaType, baosThumb);
+                    byte[] thumbArr = baosThumb.toByteArray();
+                    InputStream isThumb = new ByteArrayInputStream(thumbArr);
+                    VgiMediaUtil.insertVgiMediaThumbnail(medId, isThumb, thumbArr.length);
+                    return medId;
+                } else{
+                    throw new Exception("Any media was given!");
+                }
+            } catch(IOException | SQLException e){
+                throw new Exception(e.getMessage());
+            }
+        } else{
+            throw new Exception("File must be given!");
+        }
+    }
+
+    /**
+     * Method inserts new VgiMedia to DB
+     * @param obsId - ID of associated VgiObservation object
+     * @param fileInStream - InputStream containing associated MediaFile 
+     * @param mediaType - MediaType of associated file
+     * @return ID of VgiMedia object that was inserted
+     */
+    public int insertMedia(int obsId, InputStream fileInStream, String mediaType) throws Exception{
+        if(fileInStream != null){
+            try{
+                byte[] mediaArr = IOUtils.toByteArray(fileInStream);
+                if(mediaArr != null && mediaArr.length != 0 && mediaType != null && !mediaType.isEmpty()){
+                    InputStream is = new ByteArrayInputStream(mediaArr);
+                    return VgiMediaUtil.insertVgiMedia(obsId, is, mediaArr.length, mediaType);
+                } else{
+                    throw new Exception("Any media was given!");
+                }
+            } catch(IOException | SQLException e){
+                throw new Exception(e.getMessage());
+            }
+        } else{
+            throw new Exception("Any file must be given!");
+        }
+    }
+    
+    /**
+     * Method processes update VgiMedia object in the DB
+     * @param obsId - ID of associated VgiObservation object
+     * @param mediaId - ID of VgiMedia object to be updated
+     * @param fileInStream - InputStream containing associated MediaFile 
+     * @param mediaType - MediaType of associated file
+     * @return true if VgiMedia object was updated
+     */
+    public boolean processUpdateVgiMedia(Integer obsId, Integer mediaId, InputStream fileInStream, String userName, String mediaType) throws Exception {
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                VgiMedia med = mUtil.getVgiMedia(obsId, mediaId);
+                if(med != null){
+                    byte[] mediaArr = IOUtils.toByteArray(fileInStream);
+                    if(mediaArr != null){
+                        InputStream is = new ByteArrayInputStream(mediaArr);
+                        VgiMediaUtil.updateVgiMedia(mediaId, is, mediaArr.length, mediaType);
+                        return true;
+                    } else{
+                        throw new Exception("Any media was given!");
+                    }
+                } else{
+                    throw new Exception("VgiMedia with given ID was not found!");
+                }
+            } else{
+                throw new Exception("VgiObservation with given ID was not found!");
+            }
+        } catch(Exception e){
+            throw new Exception(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes inserting of additional media file to given master VgiObservation
+     * @param obsId - ID of master VgiObservation
+     * @param file - media file as InputStream 
+     * @param mediaType - data type of media file
+     * @param userName - name of user that owns master VgiObsrevation
+     * @return ID of VgiMedia file that was inserted
+     */
+    public VgiObservation processInsertNextMedia(int obsId, InputStream file, String mediaType, String userName) throws Exception{
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null && file != null){
+                int newMedId;
+                if(mediaType.startsWith("image/")){
+                    newMedId = insertImage(file, obsId, mediaType);
+                } else{
+                    newMedId = insertMedia(obsId, file, mediaType);
+                }
+                return new VgiObservation(obsId, newMedId);
+            } else{
+                throw new Exception("VgiObservation with given ID of  was not found!");
+            }
+        } catch(Exception e){
+            throw new Exception(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes listing of all connected VgiMedia to given master VgiObservation
+     * @param obsId - ID of master VgiObservation
+     * @param userName -  name of user that owns VgiObservation
+     * @return List of VgiMedia with metadata about connected VgiMedia file
+     */
+    public List<VgiMedia> processListVgiMedia(Integer obsId, String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                return mUtil.getVgiMediaInfo(obsId);
+            } else{
+                throw new SQLException("VGIObservation with given ID does not exist!");
+            }
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+    
+    /**
+     * Method processes select of specified media file
+     * @param obsId - ID of master VgiObservation
+     * @param mediaId - ID of VgiMedia object
+     * @param userName - name of user that owns master VgiObservation
+     * @return VgiMedia object containing bytea with media file
+     */
+    public VgiMedia processGetVgiMedia(Integer obsId, Integer mediaId, String userName) throws SQLException{
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                return mUtil.getVgiMedia(obsId, mediaId);
+            } else{
+                throw new SQLException("VGIObservation with given ID does not exist!");
+            }
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+
+    public boolean processDeleteVgiMedia(Integer obsId, Integer mediaId, String userName) throws SQLException {
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                return VgiMediaUtil.deleteVgiMedia(obsId, mediaId);
+            } else{
+                throw new SQLException("VGIObservation with given ID does not exist!");
+            }
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+
+    /**
+     * Method processes select of thumbnail of specified media file
+     * @param obsId - ID of master VgiObservation
+     * @param mediaId - ID of VgiMedia object
+     * @param userName - name of user that owns master VgiObservation
+     * @return VgiMedia object containing only thumbnail of media file as bytea
+     */
+    public VgiMedia processGetVgiMediaThumbnail(Integer obsId, Integer mediaId, String userName) throws SQLException {
+        try{
+            int userId = userUt.getUserId(userName);
+            VgiObservation obs = oUtil.getVgiObservationByObsId(obsId, userId);
+            if(obs != null){
+                return mUtil.getVgiMediaThumbnail(obsId, mediaId);
+            }
+            else{
+                throw new SQLException("VGIObservation with given ID does not exist!");
+            }
+        } catch(NoItemFoundException e){
+            throw new SQLException(e.getMessage());
+        }
+    }
+}

+ 132 - 0
src/main/java/cz/hsrs/rest/vgi/ExportVgiRest.java

@@ -0,0 +1,132 @@
+package cz.hsrs.rest.vgi;
+
+import cz.hsrs.db.vgi.util.VgiParams;
+import cz.hsrs.rest.beans.VgiObservationRdfBean;
+import cz.hsrs.rest.beans.VgiObservationsRdfBean;
+import cz.hsrs.rest.util.ExportVgiRestUtil;
+import org.w3c.dom.Document;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.sql.SQLException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Class with services for exporting of VGIObservations
+ * @author mkepka
+ *
+ */
+@Path("/vgi/export")
+public class ExportVgiRest {
+
+    public ExportVgiRest(){
+        super();
+    }
+
+    @GET @Path("/observation")
+    public Response getObservationsExport(
+            @QueryParam(VgiParams.USER_NAME) String username,
+            @QueryParam(VgiParams.FORMAT_NAME) String format,
+            @QueryParam(VgiParams.DATASET_ID_NAME) Integer datasetId,
+            @QueryParam(VgiParams.CATEGORY_ID_NAME) Integer categoryId,
+            @QueryParam(VgiParams.FROM_TIME_NAME) String fromTime,
+            @QueryParam(VgiParams.TO_TIME_NAME) String toTime,
+            @QueryParam(VgiParams.EXTENT_NAME) String extent,
+            @QueryParam(VgiParams.UNIT_ID_NAME) Long unitId,
+            @Context HttpServletRequest request)
+    {
+        if(username != null){
+            ExportVgiRestUtil expUtil = new ExportVgiRestUtil();
+            try{
+                if(format != null && format.equalsIgnoreCase(VgiParams.FORMAT_RDF_XML_NAME)){
+                    List<VgiObservationRdfBean> obsList = expUtil.processGetVgiObservationsExport(username, categoryId, datasetId, fromTime, toTime, extent, unitId);
+                    return Response.ok(new VgiObservationsRdfBean(obsList))
+                            .header(HttpHeaders.CONTENT_TYPE, "application/rdf+xml;charset=utf-8")
+                            .header("Content-Disposition", "attachment; filename=SensLog-export-"+new Date().getTime()+".rdf")
+                            .build();
+                } else{
+                    return Response.status(Status.UNSUPPORTED_MEDIA_TYPE).entity("Unsupported export format.")
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                            .build();
+                }
+            } catch(SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID has to be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /** for testing: http://localhost:8080/rest/vgi/export/observation/646?user_name=tester&format=rdf%2Bxml */
+    @GET @Path("/observation/{"+VgiParams.OBS_VGI_ID_NAME+"}")
+    public Response getObservationExport(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @QueryParam(VgiParams.FORMAT_NAME) String format,
+            @QueryParam(VgiParams.USER_NAME) String username,
+            @Context HttpServletRequest request,
+            @Context HttpServletResponse response)
+    {
+        if(obsId != null && username != null){
+            ExportVgiRestUtil expUtil = new ExportVgiRestUtil();
+            try{
+                if(format != null && format.equalsIgnoreCase(VgiParams.FORMAT_RDF_XML_NAME)){
+                    List<VgiObservationRdfBean> obsList = expUtil.processGetObservationExport(obsId, username);
+                    return Response.ok(new VgiObservationsRdfBean(obsList))
+                            .header(HttpHeaders.CONTENT_TYPE, "application/rdf+xml;charset=utf-8")
+                            .header("Content-Disposition", "attachment; filename=SensLog-export-"+new Date().getTime()+".rdf")
+                            .build();
+                } else{
+                    return Response.status(Status.UNSUPPORTED_MEDIA_TYPE).entity("Unsupported export format.")
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                            .build();
+                }
+            } catch(SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID has to be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    public static class FeedReturnStreamingOutput implements StreamingOutput {
+        private final Document doc;
+        
+        public FeedReturnStreamingOutput(Document sourceDoc){
+            this.doc = sourceDoc;
+        }
+        
+        @Override
+        public void write(OutputStream output) throws IOException, WebApplicationException {
+            try {
+                // XML to Response
+                TransformerFactory transformerFactory = TransformerFactory.newInstance();
+                Transformer transformer = transformerFactory.newTransformer();
+                DOMSource source = new DOMSource(this.doc);
+                StreamResult result =  new StreamResult(output);
+                transformer.transform(source, result);
+                output.flush();
+            } catch (TransformerException e) {
+                throw new IOException(e.getMessage());
+            }
+        }
+    }
+}

+ 119 - 0
src/main/java/cz/hsrs/rest/vgi/VgiCategoryRest.java

@@ -0,0 +1,119 @@
+package cz.hsrs.rest.vgi;
+
+import cz.hsrs.db.model.vgi.VgiCategory;
+import cz.hsrs.db.vgi.util.VgiParams;
+import cz.hsrs.rest.util.VgiCategoryRestUtil;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Class with services managing VGICategory objects
+ * URL: /rest/vgi/category
+ * @author mkepka
+ */
+@Path("/vgi/category")
+public class VgiCategoryRest {
+
+    public VgiCategoryRest(){
+        super();
+    }
+    
+    /**
+     * Service for selecting specific VGICategory object by given ID
+     * URL: /rest/vgi/category/{category_id}?user_name=
+     * @param categoryId - ID of VGICategory
+     * @param userName - name of user
+     */
+    @GET @Path("/{"+VgiParams.CATEGORY_ID_NAME+"}")
+    public Response getVgiCategory(
+    		@PathParam(VgiParams.CATEGORY_ID_NAME) Integer categoryId,
+    		@QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        try{
+            if(categoryId != null && userName != null){
+                VgiCategoryRestUtil crUtil = new VgiCategoryRestUtil();
+                VgiCategory cat = crUtil.processGetVgiCategory(categoryId, userName);
+                return Response.ok(cat)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                        .build();
+            } else{
+                return Response.status(Status.BAD_REQUEST)
+                        .entity("Parameters both category_id and user_name have to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        } 
+    }
+    
+    /**
+     * Service for selecting all descendants of VGICategory object by given ID
+     * URL: /rest/vgi/category/{category_id}/descendants?user_name=
+     * @param categoryId - ID of parent VGICategory
+     * @param userName - name of user
+     * @return List of VGICategory objects that are descendants of given parent VGICategory
+     */
+    @GET @Path("/{"+VgiParams.CATEGORY_ID_NAME+"}/descendants")
+    public Response getVgiCategoryDescendants(
+    		@PathParam(VgiParams.CATEGORY_ID_NAME) Integer categoryId,
+    		@QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        try{
+            if(categoryId != null && userName != null){
+                VgiCategoryRestUtil crUtil = new VgiCategoryRestUtil();
+                List<VgiCategory> catList = crUtil.processGetVgiCategoryDescendants(categoryId, userName);
+                return Response.ok(catList)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                        .build();
+            } else{
+                return Response.status(Status.BAD_REQUEST)
+                        .entity("Parameters both category_id and user_name have to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        } 
+    }
+    
+    /**
+     * Service for selecting all VgiCategory objects 
+     * URL: /rest/vgi/category?user_name=
+     * @param userName - name of user
+     * @return List of VgiCategory objects as JSON
+     */
+    @GET
+    public Response selectCategories(@QueryParam(VgiParams.USER_NAME) String userName){
+        try{
+            if(userName != null){
+                VgiCategoryRestUtil crUtil = new VgiCategoryRestUtil();
+                List<VgiCategory> catList = crUtil.processGetVgiCategories(userName);
+                return Response.ok(catList)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                        .build();
+            } else{
+                return Response.status(Status.BAD_REQUEST).entity("No user was given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+}

+ 178 - 0
src/main/java/cz/hsrs/rest/vgi/VgiDatasetRest.java

@@ -0,0 +1,178 @@
+package cz.hsrs.rest.vgi;
+
+import cz.hsrs.db.model.vgi.VgiDataset;
+import cz.hsrs.db.util.DateUtil;
+import cz.hsrs.db.vgi.util.VgiParams;
+import cz.hsrs.rest.util.VgiDatasetRestUtil;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Class with services managing VGIDataset objects
+ * URL: /rest/vgi/dataset
+ * @author mkepka
+ *
+ */
+@Path("/vgi/dataset")
+public class VgiDatasetRest {
+
+    public VgiDatasetRest(){
+        super();
+    }
+    
+    /**
+     * Servlet catches rest/poi/test requests to test the connection to servlet
+     * URL: /rest/vgi/dataset/test
+     * @param testValue value of parameter test as String
+     * @param request incoming servlet as HttpServletRequest
+     * @return response of the servlet as String
+     */
+    @GET @Path("/test") @Produces("text/plain")
+    public String testPoi(@QueryParam("test") String testValue, @Context HttpServletRequest request) throws ParseException{
+        Date result = DateUtil.parseTimestamp(testValue);
+        return result.toString();
+    }
+    
+    /**
+     * Service for inserting new dataset 
+     * URL: /rest/vgi/dataset/insert?user_name=
+     * 
+     * Example of payload: 
+     * {"dataset_name":"testing dataset", "description":"test dataset for testing of insertion"}
+     * 
+     * @param payload - String with VgiDataset parameters
+     * @param userName - name of user
+     * @return
+     */
+    @POST @Consumes(MediaType.APPLICATION_JSON+";charset=utf-8")
+    public Response insertDataset(
+            String payload, 
+            @QueryParam(VgiParams.USER_NAME) String userName){
+        try{
+            if(payload != null){
+                JSONObject dataset = JSONObject.fromObject(payload);
+                VgiDatasetRestUtil drUtil = new VgiDatasetRestUtil();
+                int datasetId = drUtil.processInsertVgiDataset(dataset, userName);
+                
+                JSONObject resp = new JSONObject().accumulate(VgiParams.DATASET_ID_NAME, datasetId);
+                return Response.ok(resp)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            } else{
+                return Response.status(Status.BAD_REQUEST).entity("Any Dataset description was not given!").build();
+            }
+        } catch(JSONException | SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for selecting specific VgiDataset object by given ID
+     * URL: /rest/vgi/dataset/{dataset_id}?user_name=
+     * @param datasetId - ID of VGIDataset object
+     * @return VgiDataset object as JSON
+     */
+    @GET @Path("/{"+VgiParams.DATASET_ID_NAME+"}")
+    public Response getVgiDataset(
+            @PathParam(VgiParams.DATASET_ID_NAME) Integer datasetId,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        try{
+            if(datasetId != null && userName != null){
+                VgiDatasetRestUtil drUtil = new VgiDatasetRestUtil();
+                VgiDataset dataset = drUtil.processGetVgiDataset(datasetId, userName);
+                return Response.ok(dataset)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            } else{
+                return Response.status(Status.BAD_REQUEST)
+                        .entity("Parameters both dataset_id and user_name have to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for selecting VgiDatasets associated to given user 
+     * URL: /rest/vgi/dataset/select?user_name=
+     * @param userName - name of user
+     * @return List of VGIDatasets associated to the user as JSON
+     */
+    @GET
+    public Response selectVgiDatasets(@QueryParam(VgiParams.USER_NAME) String userName){
+        try{
+            if(userName != null && !userName.isEmpty()){
+                VgiDatasetRestUtil drUtil = new VgiDatasetRestUtil();
+                List<VgiDataset> dataList = drUtil.processGetVgiDatasets(userName);
+                return Response.ok(dataList)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            }
+            else{
+                return Response.status(Status.BAD_REQUEST).entity("No user was given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service deletes VgiDataset by given dataset_id
+     * URL: DELETE /rest/vgi/dataset/{dataset_id}?user_name=
+     * @param datasetId - ID of VgiDataset to be deleted
+     * @param userName - name of user
+     * @return HTTP OK if VgiDataset was deleted, HTTP Not Modified if it was not deleted
+     */
+    @DELETE @Path("/{"+VgiParams.DATASET_ID_NAME+"}")
+    public Response deleteVgiDataset(
+            @PathParam(VgiParams.DATASET_ID_NAME) Integer datasetId, 
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        try{
+            if(datasetId != null && userName != null){
+                VgiDatasetRestUtil drUtil = new VgiDatasetRestUtil();
+                boolean isDeleted = drUtil.processDeleteVgiDataset(datasetId, userName);
+                if(isDeleted){
+                    return Response.ok()
+                            .build();
+                } else {
+                    return Response.notModified()
+                            .build();
+                }
+            }
+            else{
+                return Response.status(Status.BAD_REQUEST).
+                        entity("Parameter dataset_id has to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+}

+ 524 - 0
src/main/java/cz/hsrs/rest/vgi/VgiObservationRest.java

@@ -0,0 +1,524 @@
+package cz.hsrs.rest.vgi;
+
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.vgi.VgiMedia;
+import cz.hsrs.db.model.vgi.VgiObservation;
+import cz.hsrs.db.vgi.util.VgiParams;
+import cz.hsrs.rest.util.VgiObservationRestUtil;
+import net.sf.json.JSONObject;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * Class with services managing VgiObservation objects
+ * URL: /rest/vgi/observation
+ * @author mkepka
+ */
+@Path("/vgi/observation")
+public class VgiObservationRest {
+
+    public VgiObservationRest(){
+        super();
+    }
+    
+    /**
+     * Service for inserting or updating VgiObservation 
+     * URL: /rest/vgi/observation?user_name=
+     * @param obsId - ID of VGIObservation, when specified UPDATE is provided
+     * @param timestampValue - time stamp when observation was obtained, mandatory
+     * @param catValue - ID of VgiCategory, mandatory
+     * @param descValue - description of VgiObservation, optional
+     * @param attsValue - further attributes in JSON format as String
+     * @param datasetIdValue - ID of VgiDataset, mandatory
+     * @param unitIdValue - ID of unit that has produced observation, mandatory if uuid is not present
+     * @param uuidValue - ID of device that has producing observation, mandatory if unitId is not present
+     * @param lonValue - Longitude of observation, mandatory
+     * @param latValue - Latitude of observation, mandatory
+     * @param altValue - Altitude of observation, optional
+     * @param dopValue - Dilution of precision of position, optional
+     * @param fileInStream - InputStream with associated media, optional
+     * @param fileDetail - FormDataContentDisposition describing associated media, optional 
+     * @param mediaType - Data type of associated media file, mandatory
+     * @param userName - name of user that produced the observation, mandatory
+     * @return ID of registered VgiObservation object
+     */
+    @POST @Consumes("multipart/form-data; charset=UTF-8")
+    public Response insertObservation(
+            @FormDataParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @FormDataParam(VgiParams.TIMESTAMP_NAME) String timestampValue,
+            @FormDataParam(VgiParams.CATEGORY_ID_NAME) Integer catValue,
+            @FormDataParam(VgiParams.DESCRIPTION_NAME) String descValue,
+            @FormDataParam(VgiParams.ATTRIBUTES_NAME) String attsValue,
+            @FormDataParam(VgiParams.DATASET_ID_NAME) Integer datasetIdValue,
+            @FormDataParam(VgiParams.UNIT_ID_NAME) String unitIdValue,
+            @FormDataParam(VgiParams.UUID_NAME) String uuidValue,
+            @FormDataParam(VgiParams.LON_NAME) String lonValue,
+            @FormDataParam(VgiParams.LAT_NAME) String latValue,
+            @FormDataParam(VgiParams.ALT_NAME) String altValue,
+            @FormDataParam(VgiParams.DOP_NAME) String dopValue,
+            @FormDataParam(VgiParams.MEDIA_NAME) InputStream fileInStream,
+            @FormDataParam(VgiParams.MEDIA_NAME) FormDataContentDisposition fileDetail,
+            @FormDataParam(VgiParams.MEDIA_TYPE_NAME) String mediaType,
+            @QueryParam(VgiParams.USER_NAME) String userName,
+            @Context HttpServletRequest request
+            )
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        try {
+            if(userName == null){
+                userName = "tester";
+            }
+            if(obsId == null){
+                // process INSERT
+                VgiObservation newObs = orUtil.processInsertVgiObs(
+                        timestampValue,
+                        catValue,
+                        descValue,
+                        attsValue,
+                        unitIdValue, uuidValue,
+                        userName,
+                        datasetIdValue,
+                        lonValue, latValue, altValue, dopValue,
+                        fileInStream, mediaType);
+                return Response.ok(newObs)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            } else{
+                // process UPDATE
+                VgiObservation updatedObs = orUtil.processUpdateVgiObs(obsId,
+                        timestampValue,
+                        catValue,
+                        descValue,
+                        attsValue,
+                        unitIdValue, uuidValue,
+                        userName,
+                        datasetIdValue,
+                        lonValue, latValue, altValue, dopValue,
+                        fileInStream, mediaType);
+                return Response.ok(updatedObs)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            }
+        } catch (Exception e) {
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for updating VgiObservation 
+     * URL: PUT /rest/vgi/observation/{obs_vgi_id}?user_name=
+     * @param obsId - ID of VGIObservation, when specified UPDATE is provided
+     * @param timestampValue - time stamp when observation was obtained, mandatory
+     * @param catValue - ID of VgiCategory, mandatory
+     * @param descValue - description of VgiObservation, optional
+     * @param attsValue - further attributes in JSON format as String
+     * @param datasetIdValue - ID of VgiDataset, mandatory
+     * @param unitIdValue - ID of unit that has produced observation, mandatory if uuid is not present
+     * @param uuidValue - ID of device that has producing observation, mandatory if unitId is not present
+     * @param lonValue - Longitude of observation, mandatory
+     * @param latValue - Latitude of observation, mandatory
+     * @param altValue - Altitude of observation, optional
+     * @param dopValue - Dilution of precision of position, optional
+     * @param fileInStream - InputStream with associated media, optional
+     * @param fileDetail - FormDataContentDisposition describing associated media, optional 
+     * @param mediaType - Data type of associated media file, mandatory
+     * @param userName - name of user that produced the observation, mandatory
+     * @return true if VgiObservation was updated, false if not 
+     */
+    @PUT @Path("/{"+VgiParams.OBS_VGI_ID_NAME+"}")
+    @Consumes("multipart/form-data; charset=UTF-8")
+    public Response updateObservation(
+            @FormDataParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @FormDataParam(VgiParams.TIMESTAMP_NAME) String timestampValue,
+            @FormDataParam(VgiParams.CATEGORY_ID_NAME) Integer catValue,
+            @FormDataParam(VgiParams.DESCRIPTION_NAME) String descValue,
+            @FormDataParam(VgiParams.ATTRIBUTES_NAME) String attsValue,
+            @FormDataParam(VgiParams.DATASET_ID_NAME) Integer datasetIdValue,
+            @FormDataParam(VgiParams.UNIT_ID_NAME) String unitIdValue,
+            @FormDataParam(VgiParams.UUID_NAME) String uuidValue,
+            @FormDataParam(VgiParams.LON_NAME) String lonValue,
+            @FormDataParam(VgiParams.LAT_NAME) String latValue,
+            @FormDataParam(VgiParams.ALT_NAME) String altValue,
+            @FormDataParam(VgiParams.DOP_NAME) String dopValue,
+            @FormDataParam(VgiParams.MEDIA_NAME) InputStream fileInStream,
+            @FormDataParam(VgiParams.MEDIA_NAME) FormDataContentDisposition fileDetail,
+            @FormDataParam(VgiParams.MEDIA_TYPE_NAME) String mediaType,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        try {
+            if(userName == null){
+                userName = "tester";
+            }
+            if(mediaType == null){
+                mediaType = "image/png";
+            }
+            if(obsId != null){
+                // process UPDATE
+                VgiObservation updatedObs = orUtil.processUpdateVgiObs(obsId,
+                        timestampValue,
+                        catValue,
+                        descValue,
+                        attsValue,
+                        unitIdValue, uuidValue,
+                        userName,
+                        datasetIdValue,
+                        lonValue, latValue, altValue, dopValue,
+                        fileInStream, mediaType);
+                return Response.ok(updatedObs)
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+                        .build();
+            } else{
+                return Response.serverError().entity("VgiObservation ID has to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch (Exception e) {
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for getting specific VgiObservation object 
+     * URL: /rest/vgi/observation/{obs_vgi_id}?user_name=
+     * @param obsId - ID of the VgiObservation object
+     * @param username - name of user
+     * @return VgiObservation object as JSON
+     */
+    @Path("/{"+VgiParams.OBS_VGI_ID_NAME+"}")
+    @GET
+    public Response getVgiObservation(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId, 
+            @QueryParam(VgiParams.USER_NAME) String username, 
+            @QueryParam(VgiParams.FORMAT_NAME) String format)
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        if(obsId != null && username != null){
+            try{
+                if(format != null && format.equalsIgnoreCase(VgiParams.FORMAT_GEOJSON_NAME)){
+                    JSONObject feature = orUtil.processGetVgiObservationAsJson(obsId, username);
+                    return Response.ok(feature)
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                            .build();
+                } else{
+                    VgiObservation obs = orUtil.processGetVgiObservation(obsId, username);
+                    return Response.ok(obs)
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                            .build();
+                }
+            } catch(SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID has to be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for selecting VGIObservations by given filter parameters
+     * URL: /rest/vgi/observation?user_name=&format=&dataset_id=&category_id=&fromTime=&toTime=&extent=&unit_id=
+     * @param userName - name of user, mandatory
+     * @param format - format of the response (optional), Values: geojson/json/null
+     * @param datasetId - ID of VgiDataset, optional
+     * @param categoryId - ID of VgiCategeory, optional
+     * @param fromTime - beginning of time range, ISO 8601 pattern, optional
+     * @param toTime - end of time range, ISO 8601 pattern, optional
+     * @param extent - Array of coordinates representing BBOX of map window, format: [xmin, ymin, xmax, ymax, SRID]
+     * @return
+     */
+    @GET
+    public Response selectVgiObservations(
+            @QueryParam(VgiParams.USER_NAME) String userName,
+            @QueryParam(VgiParams.FORMAT_NAME) String format,
+            @QueryParam(VgiParams.DATASET_ID_NAME) Integer datasetId,
+            @QueryParam(VgiParams.CATEGORY_ID_NAME) Integer categoryId,
+            @QueryParam(VgiParams.FROM_TIME_NAME) String fromTime,
+            @QueryParam(VgiParams.TO_TIME_NAME) String toTime,
+            @QueryParam(VgiParams.EXTENT_NAME) String extent,
+            @QueryParam(VgiParams.UNIT_ID_NAME) Long unitId)
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        try{
+            if(userName != null){
+                // response in GeoJSON
+                if(format != null && format.equalsIgnoreCase(VgiParams.FORMAT_GEOJSON_NAME)){
+                    JSONObject featureColl = orUtil.processGetVgiObservationsByUserAsJson(userName, fromTime, toTime, datasetId, categoryId, extent, unitId);
+                    return Response.ok(featureColl, MediaType.APPLICATION_JSON+";charset=utf-8")
+                            .build();
+                } else{ // response in pure JSON
+                    List<VgiObservation> obsList = orUtil.processGetVgiObservationsByUser(userName, fromTime, toTime, datasetId, categoryId, extent);
+                    return Response.ok(obsList)
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                            .build();
+                }
+            } else{
+                return Response.status(Status.BAD_REQUEST)
+                        .entity("Parameter user_name has to be given!")
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch(SQLException e){
+            return Response.serverError().entity(e.getMessage())
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for deleting VGIObservation by given ID
+     * URL: /rest/vgi/observation/{obs_vgi_id}?user_name=
+     * @param obsId - ID of VGIObservation to be deleted
+     * @param userName - name of user which owns VGIObservation object
+     * @return HTTP OK response
+     */
+    @DELETE @Path("/{"+VgiParams.OBS_VGI_ID_NAME+"}")
+    public Response deleteVgiObservation(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        if(obsId != null && userName != null){
+            try{
+                boolean isDeleted = orUtil.processDeleteVgiObservation(obsId, userName);
+                if(isDeleted){
+                    return Response.ok().build();
+                } else{
+                    return Response.serverError().entity("VGIObservation was not deleted!")
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                            .build();
+                }
+            } catch(Exception e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for inserting additional media file to master VgiObservation
+     * URL: /rest/vgi/observation/{obs_vgi_id}/media?user_name=
+     * @param obsId - ID of master VgiObservation
+     * @param mediaType - data type of media file
+     * @param fileInStream - InputStream containing media file
+     * @param fileDetail - metadata of media file 
+     * @param userName - name of user that owns VgiObservation
+     * @return true if media file was inserted
+     */
+    @POST @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media")
+    @Consumes("multipart/form-data; charset=UTF-8")
+    public Response insertVgiMedia(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @FormDataParam(VgiParams.MEDIA_TYPE_NAME) String mediaType,
+            @FormDataParam(VgiParams.MEDIA_NAME) InputStream fileInStream, 
+            @FormDataParam(VgiParams.MEDIA_NAME) FormDataContentDisposition fileDetail,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        if(obsId != null && userName != null && fileInStream != null){
+            try{
+                VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+                VgiObservation insertedObs = orUtil.processInsertNextMedia(obsId, fileInStream, userName, mediaType);
+                return Response.ok(insertedObs, MediaType.APPLICATION_JSON)
+                        .build();
+            } catch(Exception e){
+                return Response.serverError().entity(e.getMessage())
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("Any media and VGIObservation ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for listing description of all connected media files to given VgiObservation
+     * URL: /rest/vgi/observation/{obs_vgi_id}/media?user_name=
+     * @param obsId - ID of master VgiObservation object
+     * @param userName - name of user that owns VgiObservation object
+     * @return List of description of all connected VgiMedia objects
+     * @throws SQLException
+     */
+    @GET @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media")
+    public Response listVgiMedia(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @QueryParam(VgiParams.USER_NAME) String userName) throws SQLException
+    {
+        if(obsId != null && userName != null){
+            VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+            List<VgiMedia> media = orUtil.processListVgiMedia(obsId, userName);
+            return Response.ok(media)
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON+";charset=utf-8")
+                    .build();
+        } else{
+            return Response.serverError().entity("VGIObservation ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for getting connected media file
+     * URL: /rest/vgi/observation/{obs_vgi_id}/media/{media_id}?user_name=
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of connected VgiMedia
+     * @param userName - name of user that owns VgiObservation object
+     * @return VgiMedia object as output stream
+     * @throws SQLException
+     */
+    @GET @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media/{"+VgiParams.MEDIA_ID_NAME+"}")
+    public Response getVgiMedia(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @PathParam(VgiParams.MEDIA_ID_NAME) Integer mediaId,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        if(obsId != null && mediaId != null && userName != null){
+            try{
+                VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+                VgiMedia medium = orUtil.processGetVgiMedia(obsId, mediaId, userName);
+                return Response.ok(new ByteArrayInputStream(medium.getObservedMedia()))
+                        .header(HttpHeaders.CONTENT_TYPE, medium.getMediaDatatype())
+                        .build();
+            } catch (SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID and VGIMedia ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for getting thumbnail of connected media file
+     * URL: /rest/vgi/observation/{obs_vgi_id}/media/{media_id}?user_name=
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of connected VgiMedia
+     * @param userName - name of user that owns VgiObservation object
+     * @return VgiMedia object as output stream
+     * @throws SQLException
+     */
+    @GET @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media/{"+VgiParams.MEDIA_ID_NAME+"}/thumbnail")
+    public Response getVgiMediaThumbnail(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @PathParam(VgiParams.MEDIA_ID_NAME) Integer mediaId,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        if(obsId != null && mediaId != null && userName != null){
+            try{
+                VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+                VgiMedia medium = orUtil.processGetVgiMediaThumbnail(obsId, mediaId, userName);
+                return Response.ok(new ByteArrayInputStream(medium.getThumbnail()))
+                        .header(HttpHeaders.CONTENT_TYPE, medium.getMediaDatatype())
+                        .build();
+            } catch (SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID and VGIMedia ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for updating connected media file
+     * URL: PUT /rest/vgi/observation/{obs_vgi_id}/media/{media_id}?user_name=
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of connected VgiMedia
+     * @param userName - name of user that owns VgiObservation object
+     * @return VgiMedia object as output stream
+     * @throws SQLException
+     */
+    @PUT @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media/{"+VgiParams.MEDIA_ID_NAME+"}")
+    @Consumes("multipart/form-data; charset=UTF-8")
+    public Response updateVgiMedia(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @PathParam(VgiParams.MEDIA_ID_NAME) Integer mediaId,
+            @FormDataParam(VgiParams.MEDIA_TYPE_NAME) String mediaType,
+            @FormDataParam(VgiParams.MEDIA_NAME) InputStream fileInStream, 
+            @FormDataParam(VgiParams.MEDIA_NAME) FormDataContentDisposition fileDetail,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        if(obsId != null && mediaId != null && userName != null && fileInStream != null) {
+            try{
+                VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+                boolean updated = orUtil.processUpdateVgiMedia(obsId, mediaId, fileInStream, userName, mediaType);
+                return Response.ok(String.valueOf(updated), MediaType.TEXT_PLAIN).build();
+            } catch(Exception e){
+                return Response.serverError().entity(e.getMessage())
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("Any media and VGIObservation ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+    
+    /**
+     * Service for deleting connected media file
+     * URL: /rest/vgi/observation/{obs_vgi_id}/media/{media_id}?user_name=
+     * @param obsId - ID of master VgiObservation object
+     * @param mediaId - ID of connected VgiMedia
+     * @param userName - name of user that owns VgiObservation object
+     * @return VgiMedia object as output stream
+     * @throws SQLException
+     */
+    @DELETE @Path("{"+VgiParams.OBS_VGI_ID_NAME+"}/media/{"+VgiParams.MEDIA_ID_NAME+"}")
+    public Response deleteVgiMedia(
+            @PathParam(VgiParams.OBS_VGI_ID_NAME) Integer obsId,
+            @PathParam(VgiParams.MEDIA_ID_NAME) Integer mediaId,
+            @QueryParam(VgiParams.USER_NAME) String userName)
+    {
+        if(obsId != null && mediaId != null && userName != null){
+            try{
+                VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+                boolean isDeleted = orUtil.processDeleteVgiMedia(obsId, mediaId, userName);
+                if(isDeleted){
+                    return Response.ok().build();
+                } else{
+                    return Response.serverError().entity("VgiMedia was not deleted!")
+                            .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                            .build();
+                }
+            } catch (SQLException e){
+                return Response.serverError().entity(e.getMessage())
+                        .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } else{
+            return Response.serverError().entity("VGIObservation ID and VGIMedia ID must be given!")
+                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)
+                    .build();
+        }
+    }
+}

+ 214 - 0
src/main/java/cz/hsrs/rest/vgi/VgiRest.java

@@ -0,0 +1,214 @@
+package cz.hsrs.rest.vgi;
+
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+import cz.hsrs.db.model.vgi.VgiObservation;
+import cz.hsrs.rest.util.BasicAuth;
+import cz.hsrs.rest.util.RestUtil;
+import cz.hsrs.rest.util.VgiObservationRestUtil;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.Arrays;
+
+@Path("/vgi")
+public class VgiRest {
+
+    @Context ServletContext context;
+
+    public VgiRest(){
+        super();
+    }
+
+    /**
+     * Servlet catches rest/poi/test requests to test the connection to servlet
+     * @param testValue value of parameter test as String
+     * @param request incoming servlet as HttpServletRequest
+     * @return response of the servlet as String
+     */
+    @GET @Path("/test") @Produces("text/plain")
+    public String testPoi(@QueryParam("test") String testValue, @Context HttpServletRequest request) {
+    	BigInteger bi = new BigInteger(testValue, 16);
+    	long biL = bi.longValue();
+    	long result = hexToLong(testValue.getBytes());
+    	String original = Long.toHexString(result);
+        return "Original: "+testValue+"\n"
+        		+"Long parse: "+ biL +"\n"
+    			+"Long: "+ result +"\n"
+        		+"ByteHex: "+original;
+    }
+
+    /**
+     * Servlet catches rest/poi/test requests to test the connection to servlet
+     * @param request incoming servlet as HttpServletRequest
+     * @return response of the servlet as String
+     */
+    @GET @Path("/testciti") @Produces("text/plain")
+    public String testCitiSense(@Context HttpServletRequest request) throws Exception{
+        RestUtil rUtil = new RestUtil();
+        try {
+            rUtil.processCitiSense();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return "true";
+    }
+
+
+    /**
+     * Servlet catches rest/poi/testload requests to load images from database according to given imageId
+     * @param imageIdValue ID of image in the database
+     * @return true if image exists
+     */
+    @GET @Path("/testload") @Produces("text/plain")
+    public String testPoiLoad(@QueryParam("imageId") String imageIdValue) {
+        RestUtil rUtil = new RestUtil();
+        String path = context.getRealPath("images");
+        boolean exists = rUtil.testPoiLoad(imageIdValue, path);
+        return String.valueOf(exists);
+    }
+    
+    /**
+     * Method consumes POI insert request from client application, transfer parameters to process util and returns response TRUE 
+     * if insert was successful 
+     * @param titleValue String with value of Title parameter
+     * @param descValue String with value of Description parameter
+     * @param catValue String with value of Category parameter
+     * @param statValue String with value of Status parameter
+     * @param lonValue String with value of Longitude parameter
+     * @param latValue String with value of Latitude parameter
+     * @param timestampValue String with value of Timestamp parameter
+     * @param startTimestampValue String with value of StartTimestamp parameter
+     * @param fileInStream InputStream with picture file 
+     * @param fileDetail FormDataContentDisposition with description of picture file
+     * @param fileSize String with size of picture file in bytes
+     * @param rotationangle String angle to rotate picture to position in which was taken
+     * @param request 
+     * @return Returns true or false as String if inserting was finished right
+     */
+    @POST @Path("/insert")
+    @Consumes("multipart/form-data; charset=UTF-8") @Produces("text/plain")
+    public String post(
+            @FormDataParam("title") String titleValue,
+            @FormDataParam("description") String descValue,
+            @FormDataParam("category") String catValue,
+            @FormDataParam("status") String statValue,
+            @FormDataParam("lon") String lonValue,
+            @FormDataParam("lat") String latValue,
+            @FormDataParam("timestamp") String timestampValue,
+            @FormDataParam("starttimestamp") String startTimestampValue,
+            @FormDataParam("picture") InputStream fileInStream,
+            @FormDataParam("picture") FormDataContentDisposition fileDetail,
+            @FormDataParam("picturesize") String fileSize,
+            @FormDataParam("rotationangle") String rotationAng,
+            @Context HttpServletRequest request)
+    {
+        String[] login = BasicAuth.decode(request.getHeader("authorization"));
+        String userName = login[0];
+        RestUtil rUtil = new RestUtil();
+        
+        if(fileSize != null){
+            boolean isStored = rUtil.processPoi(titleValue, descValue, catValue, statValue, lonValue, latValue, timestampValue, startTimestampValue, userName, fileInStream, Long.valueOf(fileSize), Integer.valueOf(rotationAng));
+            return String.valueOf(isStored);
+        } else{
+            boolean isStored = rUtil.processPoi(titleValue, descValue, catValue, statValue, lonValue, latValue, timestampValue, startTimestampValue, userName, fileInStream, 0, 0);
+            return String.valueOf(isStored);
+        }
+    }
+
+    @POST @Path("/insobs") @Consumes("multipart/form-data; charset=UTF-8")
+    public Response insertObservation(
+            @FormDataParam("obs_vgi_id") Integer obsId,
+            @FormDataParam("timestamp") String timestampValue,
+            @FormDataParam("category") Integer catValue,
+            @FormDataParam("description") String descValue,
+            @FormDataParam("attributes") String attsValue,
+            @FormDataParam("dataset") Integer datasetIdValue,
+            @FormDataParam("unitId") String unitIdValue,
+            @FormDataParam("lon") String lonValue,
+            @FormDataParam("lat") String latValue,
+            @FormDataParam("alt") String altValue,
+            @FormDataParam("dop") String dopValue,
+            @FormDataParam("media") InputStream fileInStream,
+            @FormDataParam("media") FormDataContentDisposition fileDetail,
+            @FormDataParam("media_type") String mediaType,
+            @QueryParam("user_name") String userName)
+    {
+        VgiObservationRestUtil orUtil = new VgiObservationRestUtil();
+        try {
+        	if(userName == null){
+        		userName = "tester";
+        	}
+            if(mediaType == null){
+            	mediaType = "image/png";
+            }
+
+            if(obsId == null){
+            	VgiObservation newObs = orUtil.processInsertVgiObs(timestampValue, catValue, descValue, attsValue,
+                        unitIdValue, null, userName, datasetIdValue, lonValue, latValue, altValue, dopValue, 
+                        fileInStream, mediaType);
+                return Response.ok(String.valueOf(newObs.getObsVgiId()), MediaType.TEXT_PLAIN)
+                        .build();
+            } else{
+            	VgiObservation inserted = orUtil.processUpdateVgiObs(obsId, timestampValue, catValue, descValue, attsValue,
+                        unitIdValue, null, userName, datasetIdValue, lonValue, latValue, altValue, dopValue, 
+                        fileInStream, mediaType);
+                return Response.ok(String.valueOf(inserted.getObsVgiId()), MediaType.TEXT_PLAIN)
+                        .build();
+            }
+        } catch (Exception e) {
+            return Response.serverError().entity(e.getMessage()).build();
+        }
+    }
+
+    private long hexToLong(byte[] bytes) {
+		if (bytes.length > 16) {
+			throw new IllegalArgumentException("Byte array too long (max 16 elements)");
+		}
+		long v = 0;
+		for (int i = 0; i < bytes.length; i += 2) {
+			byte b1 = (byte) (bytes[i] & 0xFF);
+			b1 -= 48;
+			if (b1 > 9) b1 -= 39;
+			if (b1 < 0 || b1 > 15) {
+				throw new IllegalArgumentException("Illegal hex value: " + bytes[i]);
+			}
+			b1 <<=4;
+			byte b2 = (byte) (bytes[i + 1] & 0xFF);
+			b2 -= 48;
+			if (b2 > 9) b2 -= 39;
+			if (b2 < 0 || b2 > 15) {
+				throw new IllegalArgumentException("Illegal hex value: " + bytes[i + 1]);
+			}
+			v |= (((b1 & 0xF0) | (b2 & 0x0F))) & 0x00000000000000FFL ;
+			if (i + 2 < bytes.length) v <<= 8;
+		}
+		return v;
+	}
+
+	private byte[] longToHex(final long l) {
+		long v = l & 0xFFFFFFFFFFFFFFFFL;
+		byte[] result = new byte[16];
+		Arrays.fill(result, 0, result.length, (byte)0);
+		for (int i = 0; i < result.length; i += 2) {
+			byte b = (byte) ((v & 0xFF00000000000000L) >> 56);
+			byte b2 = (byte) (b & 0x0F);
+			byte b1 = (byte) ((b >> 4) & 0x0F);
+			if (b1 > 9) b1 += 39;
+			b1 += 48;
+			if (b2 > 9) b2 += 39;
+			b2 += 48;
+			result[i] = (byte) (b1 & 0xFF);
+			result[i + 1] = (byte) (b2 & 0xFF);
+			v <<= 8;
+		}
+		return result;
+	}
+}

+ 269 - 0
src/main/java/cz/hsrs/servlet/feeder/FeederServlet.java

@@ -0,0 +1,269 @@
+package cz.hsrs.servlet.feeder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.DatabaseFeedOperation;
+import cz.hsrs.db.model.AlertEvent;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.AlertUtil;
+import cz.hsrs.db.util.ServerUtil;
+
+
+public class FeederServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
+    static final long serialVersionUID = 1L;
+
+    public static Logger logger = Logger.getLogger(SQLExecutor.LOGGER_ID);
+    private static final List<URL> BACKUP_URLS = new LinkedList<>();
+    
+
+    private static String getTimeZone(){
+        Calendar cal = Calendar.getInstance();
+        int z = ((cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000)/60);
+        return "+0"+String.valueOf(z).subSequence(0, 1)+"00";
+    }
+
+    protected void doGet(HttpServletRequest request,
+            HttpServletResponse response) throws ServletException, IOException {
+
+        /* Forward request to other servers */
+        try {
+            ServerUtil ut = new ServerUtil();
+            ut.callServers(BACKUP_URLS, request.getQueryString());
+        } catch (Exception e) {
+            logger.log(Level.WARNING, e.getMessage() + " query: " + request.getQueryString(), e);
+        }
+        
+        /* Insert observation request */
+        if (request.getParameter(ServiceParameters.OPERATION).equals(ServiceParameters.INSERT_OBSERVATION)) {
+            PrintWriter out = response.getWriter();
+            try {
+                out.print(insObservation(request));
+            } catch (Exception e) {
+                logger.log(Level.WARNING, e.getMessage() + " query: "+ request.getQueryString(), e);
+                out.print(false);
+            }
+        }
+        
+        /* Insert position request */
+        else if (request.getParameter(ServiceParameters.OPERATION).equals(ServiceParameters.INSERT_POSITION)) {
+            PrintWriter out = response.getWriter();
+            try {
+                out.print(insPosition(request));
+            } catch (Exception e) {
+                logger.log(Level.WARNING, e.getMessage()+" query: "+request.getQueryString(), e);
+                out.print(false);
+            }
+        }
+
+        /* Insert new alert event request */
+        else if (request.getParameter(ServiceParameters.OPERATION).equals(ServiceParameters.INSERT_ALERT_EVENT)) {
+            PrintWriter out = response.getWriter();
+            try {
+                out.print(insAlertEvent(request)); // depends on existing older event!!!
+            } catch (Exception e) {
+                logger.log(Level.WARNING, e.getMessage() + " query: " + request.getQueryString(), e);
+                out.print(false);
+            }
+        } 
+        /* Set solving parameter of alert event request */
+        else if (request.getParameter(ServiceParameters.OPERATION).equals(ServiceParameters.SOLVING_ALERT_EVENT)) {
+            PrintWriter out = response.getWriter();
+            try {
+                insSolvingAlertEvent(request);
+                out.print(true);
+            } catch (Exception e) {
+                logger.log(Level.WARNING, e.getMessage() + " query: " + request.getQueryString(), e);
+                out.print(false);
+            }
+        } else if (request.getParameter(ServiceParameters.OPERATION).equals("RESET")) {
+            SQLExecutor.close();
+            init();
+            response.sendRedirect("./monitor.jsp");
+
+        } else if (request.getParameter(ServiceParameters.OPERATION).equals("SLEEP")) {
+            try {
+                Thread.sleep(20000);
+                PrintWriter out = response.getWriter();
+                out.print("uzzzz....");
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+        /* Insert position via insert.jsp page form */
+        if (request.getParameter(ServiceParameters.OPERATION).equals(ServiceParameters.INSERT_POSITION)) {
+            PrintWriter out = response.getWriter();
+            try {
+                insPosition(request);
+                out.print("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><title>Insert title here</title></head>");
+                out.print(true);
+                out.print("<div><a href=\"./vypis.jsp?unit_id="+request.getParameter(ServiceParameters.UNIT_ID)+"\">Back to the list of graphs</a></div>");
+                out.print("</body></html>");
+            } catch (Exception e) {
+                out.print(false);
+            }
+        }
+    }
+
+    public static Date parse(String dateString) throws ParseException {
+        final SimpleDateFormat formaterT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
+        final SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ");
+
+        if(dateString.contains("T")){
+            try {
+                return formaterT.parse(dateString);
+            } catch (ParseException e) {
+                try{
+                    return formaterT.parse(dateString+getTimeZone());
+                } catch (ParseException e1){
+                    throw new ParseException(e1.getMessage(), 1);
+                }
+            }
+        }
+        else{
+            try {
+                return formater.parse(dateString);
+            } catch (ParseException e) {
+                try{
+                    return formater.parse(dateString+getTimeZone());
+                } catch (ParseException e1){
+                    throw new ParseException(e1.getMessage(), 1);
+                }
+            }
+        }
+    }
+
+    protected boolean insObservation(HttpServletRequest request) throws SQLException, ParseException {
+        double value = Double.parseDouble(request.getParameter(ServiceParameters.VALUE));
+        String time = request.getParameter(ServiceParameters.DATE);
+        long unit_id = Long.parseLong(request.getParameter(ServiceParameters.UNIT_ID));
+        long sensor_id = Long.parseLong(request.getParameter(ServiceParameters.SENSOR_ID));
+
+        Date date = parse(time);// "2008-01-02 12:00:00");    
+        return DatabaseFeedOperation.insertObservation(date, unit_id, sensor_id, value);
+    }
+    
+    /**
+     * Method insert new position in database
+     * @param request HTTP request with parameters
+     * @throws SQLException while parsing request
+     */
+    protected boolean insPosition(HttpServletRequest request) throws SQLException {
+        boolean inserted;
+        /* Mandatory lat and lon */
+        double lat = Double.parseDouble(request.getParameter(ServiceParameters.LAT));
+        double lon = Double.parseDouble(request.getParameter(ServiceParameters.LON));
+
+        /* Optional alt */
+        double alt = Double.NaN;
+        if (request.getParameter(ServiceParameters.ALT) != null && !request.getParameter(ServiceParameters.ALT).isEmpty()) {
+            alt = Double.parseDouble(request.getParameter(ServiceParameters.ALT));
+        }
+
+        /* Optional speed */
+        double speed = Double.NaN;
+        if (request.getParameter(ServiceParameters.SPEED) != null && !request.getParameter(ServiceParameters.SPEED).isEmpty()) {
+            speed = Double.parseDouble(request.getParameter(ServiceParameters.SPEED));
+        }
+
+        /* Mandatory unit_id */
+        long unit_id = Long.parseLong(request.getParameter(ServiceParameters.UNIT_ID));
+
+        /* Mandatory date */
+        String date = request.getParameter(ServiceParameters.DATE);
+        if(date.contains("T")){
+            date = date.replace("T", " ");
+        }
+        Date time;
+        try {
+            time = parse(date);
+        } catch (ParseException e) {
+            throw new SQLException(e);
+        }
+
+        /* DOP is voluntary parameter */
+        if (request.getParameter(ServiceParameters.DOP) != null && !request.getParameter(ServiceParameters.DOP).isEmpty()) {
+            double dop = Double.parseDouble(request.getParameter(ServiceParameters.DOP));
+            inserted = DatabaseFeedOperation.insertPosition(unit_id, lat, lon, alt, dop, time, speed);
+        } else {
+            inserted = DatabaseFeedOperation.insertPosition(unit_id, lat, lon, alt, time, speed);
+        }
+        return inserted;
+    }
+
+    public void init() throws ServletException {
+        String propFile = getServletContext().getRealPath("WEB-INF/database.properties");
+        Properties prop = new Properties();
+        try {
+            prop.load(new FileInputStream(propFile));
+            SQLExecutor.setProperties(prop);
+        } catch (Exception e) {
+            logger.log(Level.SEVERE, e.getMessage(), e);
+        }
+
+        /* Initialize logging properties */
+        try {
+            FileInputStream fstrem = new FileInputStream(new File(getServletContext().getRealPath("WEB-INF/logging.properties")));
+            LogManager.getLogManager().readConfiguration(fstrem);
+            logger.log(Level.INFO, "Logging inialized Succesefully!");
+        } catch (SecurityException | IOException e1) {
+            logger.log(Level.SEVERE, e1.getMessage());
+        }
+
+        SQLExecutor.setProperties(prop);
+        super.init();
+    }
+
+    /**
+     * Method processes insertAlertEvent request
+     * @param request - HTTP GET request
+     * @throws Exception throws exception while parsing time stamp 
+     */
+    protected boolean insAlertEvent(HttpServletRequest request) throws Exception {
+        String time = request.getParameter(ServiceParameters.DATE);
+        long unit_id = Long.parseLong(request.getParameter(ServiceParameters.UNIT_ID));
+        int alert_id = Integer.parseInt(request.getParameter(ServiceParameters.ALERT_ID));
+
+        AlertUtil aUtil = new AlertUtil();
+        List<AlertEvent> eventList = aUtil.getUnsolvingAlertEvent(unit_id, alert_id);
+
+        boolean notOlderEvent = eventList.isEmpty();
+        if (notOlderEvent) {
+            Date date = parse(time);// "2008-01-02 12:00:00");
+            DatabaseFeedOperation.insertAlertEvent(date, unit_id, alert_id);
+        }
+        return notOlderEvent;
+    }
+
+    /**
+     * Method processes insert solving parameter request
+     * @param request HTTP get request
+     * @throws Exception while parsing alert_event_id
+     */
+    protected void insSolvingAlertEvent(HttpServletRequest request)    throws Exception {
+        int event_id = Integer.parseInt(request.getParameter(ServiceParameters.ALERT_EVENT_ID));
+        DatabaseFeedOperation.solvingAlertEvent(event_id);
+    }
+}

+ 39 - 0
src/main/java/cz/hsrs/servlet/feeder/ServiceParameters.java

@@ -0,0 +1,39 @@
+package cz.hsrs.servlet.feeder;
+
+public class ServiceParameters {
+
+	public static String OPERATION = "Operation";
+
+	// --- FeederServlet ---
+	public static String INSERT_OBSERVATION = "InsertObservation";
+	public static String INSERT_POSITION = "InsertPosition";
+	public static String INSERT_POI = "InsertPOI";
+	public static String INSERT_ALERT_EVENT = "InsertAlertEvent";
+	public static String SOLVING_ALERT_EVENT = "SolvingAlertEvent";
+
+
+	public static String UNIT_ID = "unit_id";
+	public static String SENSOR_ID = "sensor_id";
+	public static String PHENOMEN_ID = "phenomenon_id";
+	public static String LAT = "lat";
+	public static String LON = "lon";
+	public static String ALT = "alt";
+	public static String SPEED = "speed";
+	public static String DOP = "dop";
+	public static String VALUE = "value";
+	public static String DATE = "date";
+	public static String FROM = "from";
+	public static String TO = "to";
+	public static final String TRUNC = "trunc";
+
+
+	public static String ALERT_ID = "alert_id";
+	public static String ALERT_EVENT_ID = "alert_event_id";
+	public static final String USER = "user";
+	public static final String GROUP = "group";
+
+	// --- SensorService ---
+	public static final String GET_SENSORS = "GetSensors";
+	public static final String GET_OBSERVATIONS = "GetObservations";
+	public static final String GET_LAST_OBSERVATIONS = "GetLastObservations";
+}

+ 41 - 0
src/main/java/cz/hsrs/servlet/lang/ChangeLangServlet.java

@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package cz.hsrs.servlet.lang;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.servlet.provider.DBServlet;
+import cz.hsrs.servlet.security.JSPHelper;
+import cz.hsrs.servlet.security.LoginUser;
+
+/**
+ * Servlet to change languages on pages
+ * @author MiKe
+ *
+ */
+public class ChangeLangServlet extends DBServlet{
+
+	private static final long serialVersionUID = 1L;
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+		String lang = req.getParameter("lang");
+		String coming =  req.getParameter("coming");
+
+		Cookie[] cookies = req.getCookies();
+		for (Cookie cookie : cookies) {
+			if (cookie.getName().equalsIgnoreCase("language")) {
+				cookie.setValue(lang);
+				cookie.setPath("/");
+				resp.addCookie(cookie);
+			}
+		}	
+	
+		LoginUser user = (LoginUser) req.getSession().getAttribute(JSPHelper.USERATTRIBUTE);
+		user.setUserLanguage(lang);
+		JSPHelper.redirect(resp, req.getContextPath() + coming);
+	}	
+}

+ 71 - 0
src/main/java/cz/hsrs/servlet/lang/Labels.java

@@ -0,0 +1,71 @@
+package cz.hsrs.servlet.lang;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+
+public class Labels {
+
+    public static String map = "MAP";
+    public static String administration = "ADMINISTRATION";
+    public static String logbook = "LOGBOOK";
+    public static String mapW = "MAPWORLD";
+    public static String adress = "ADRESS";
+    public static String loginas = "LOGINAS";
+    public static String contact = "CONTACT";
+    public static String intro = "INTRODUCTION";
+    public static String logout = "LOGOUT";
+
+    final Map<String, String> cz;
+    final Map<String, String> en;
+
+    static Labels l;
+
+    private Labels() {
+        cz = new HashMap<>();
+        en = new HashMap<>();
+        cz.put(map, "Mapa");
+        en.put(map, "Map");
+        cz.put(administration, "Administrace");
+        en.put(administration, "Administration");
+        cz.put(logbook, "Kniha jízd");
+        en.put(logbook, "Traveling Book");
+        cz.put(mapW, "Mapa - Evropa");
+        en.put(mapW, "Map - Europe");
+        cz.put(adress, "Adresa");
+        en.put(adress, "Adress");
+        cz.put(loginas, "Přihlášen jako:");
+        en.put(loginas, "Logged in as:");
+        cz.put(contact, "Kontakt");
+        en.put(contact, "Contact");
+        cz.put(intro, "Úvod");
+        en.put(intro, "Intro");
+        cz.put(logout, "Odhlásit");
+        en.put(logout, "Logout");
+
+
+    }
+
+    public static Labels getLabels() {
+        if (l == null) {
+            l = new Labels();
+        }
+        return l;
+    }
+
+    public Map<String, String> get(String l) {
+        return l.equals("cz") ? cz : en;
+    }
+
+    public Map<String, String> get(Cookie[] c) {
+        if(c != null){
+            for (Cookie cookie : c) {
+                if (cookie.getName().equalsIgnoreCase("language")) {
+                    return get(cookie.getValue());
+                }
+            }
+        }
+        return en;
+    }
+}

+ 87 - 0
src/main/java/cz/hsrs/servlet/provider/AlertService.java

@@ -0,0 +1,87 @@
+/**
+ * 
+ */
+package cz.hsrs.servlet.provider;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+import java.util.List;
+
+import javax.naming.AuthenticationException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.model.AlertEvent;
+import cz.hsrs.db.util.UtilFactory;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+import cz.hsrs.servlet.security.LoginUser;
+
+/**
+ * Servlet handling request for alerts
+ * @author mkepka
+ */
+public class AlertService extends DBServlet{
+    private static final long serialVersionUID = 1L;
+    
+    public static final String GET_ALERTS = "GetAlerts";
+    public static final String GET_ALERT_EVENTS_BY_TIME = "GetAlertEventsByTime";
+    
+    private UtilFactory db;
+    
+    public void init() throws ServletException {
+        super.init();
+        try {
+            db = new UtilFactory();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+    
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        super.doGet(request, response);
+
+        RequestParameters params = new RequestParameters(request);
+
+        try {
+            getAuthenticatedLoginUser(request);
+        } catch (AuthenticationException e1) {
+            throw new ServletException("Authentication failure for request "+ request.getQueryString());
+        }
+
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        PrintWriter out = response.getWriter();
+        try {
+            if (request.getParameter(ServiceParameters.OPERATION).equals(GET_ALERTS)) {
+                DBJsonUtils.writeJSON(out, db.alertUtil.getAlerts(params.getUnitId()));
+            }
+            else if (request.getParameter(ServiceParameters.OPERATION).equals(GET_ALERT_EVENTS_BY_TIME)) {
+                List<AlertEvent> events = db.alertUtil.getAlertEventsByTime(params.getUnitId(), params.from, params.to);
+                DBJsonUtils.writeJSON(out, events);
+            } else {
+                throw new ServletException("Wrong request "+request.getQueryString());
+            }
+        } catch (SQLException e) {
+            solveGetException(e, out);
+        }
+    }
+
+    static class RequestParameters {
+        private final long unitId;
+        private final String from;
+        private final String to;
+
+        RequestParameters(HttpServletRequest request) throws NullPointerException {
+            Object uid = request.getParameter("unit_id");
+            this.unitId = uid != null ? Long.parseLong(uid.toString()) : null;
+            this.from = request.getParameter("from");
+            this.to = request.getParameter("to");
+        }
+
+        public long getUnitId() {
+            return unitId;
+        }
+    }
+}

+ 357 - 0
src/main/java/cz/hsrs/servlet/provider/AnalystService.java

@@ -0,0 +1,357 @@
+/**
+ * 
+ */
+package cz.hsrs.servlet.provider;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.util.UtilFactory;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+
+/**
+ * @author mkepka
+ *
+ */
+public class AnalystService extends DBServlet{
+
+    private static final long serialVersionUID = 1L;
+    private UtilFactory db;
+    
+    public static final String GET_WORK_ON_SITES = "GetWorkOnSites";
+    public static final String GET_TRACTOR_UTILIZATION = "GetTractorUtilization";
+    public static final String GET_TRACTOR_WORKDAY = "GetTractorWorkday";
+    public static final String GET_FIELD_OVERVIEW = "GetActivitiesFieldOverview";
+    public static final String GET_FIELD_OVERVIEW_POINT = "GetActivitiesFieldOverviewByPoint";
+    public static final String GET_FIELD_OVERVIEW_PERIOD = "GetActivitiesFieldOverviewPeriod";
+    public static final String GET_FIELD_OVERVIEW_FUEL = "GetFieldFuelSummary";
+    public static final String GET_TRACTOR_ACTIVE_PERIOD = "GetTractorActivePeriod";
+    public static final String GET_ACTIVE_TRACTORS_PERIOD = "GetActiveTractorsPeriod";
+    public static final String GET_MANAGEMENT_ZONES_OVERVIEW = "GetManagementZonesOverview";
+    public static final String GET_MANAGEMENT_ZONES_OVERVIEW_2 = "GetManagementZonesOverview2";
+    public static final String GET_MANAGEMENT_ZONES_OVERVIEW_POINT = "GetManagementZonesOverviewByPoint";
+    public static final String GET_MANAGEMENT_ZONES_OVERVIEW_POINT_2 = "GetManagementZonesOverviewByPoint2";
+    public static final String GET_DAILY_FIELD_ACTIVITIES = "GetDailyFieldActivities";
+    public static final String GET_DAILY_FIELD_ACTIVITIES_POINT = "GetDailyFieldActivitiesByPoint";
+    public static final String GET_PLOTS_GEOM = "GetPlotsGeom";
+    public static final String GET_MAN_ZONES_GEOM = "GetManagementZonesGeom";
+    public static final String GET_MAN_ZONE_GEOM = "GetManagementZoneGeom";
+    public static final String GET_MAN_ZONE_GEOM_POINT = "GetManagementZoneGeomByPoint";
+    
+    public AnalystService(){
+        super();
+    }
+    
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        super.doGet(request, response);
+        
+        /* For FarmTelemetry purpose only temporary
+         * AnalystService?Operation=GetWorkOnSites&user=telemetry&unit_id=356173060289134&date=2015-11-13
+         * AnalystService?Operation=GetWorkOnSites&user=telemetry&unit_id=356173060289134&from=2015-11-13&to=2015-11-15
+         * 
+         * AnalystService?Operation=GetTractorUtilization&user=telemetry&unit_id=356173060289134&date=2015-11-13 
+         * AnalystService?Operation=GetTractorUtilization&user=telemetry&unit_id=356173060289134&from=2015-11-13&to=2015-11-15
+         * 
+         * AnalystService?Operation=GetTractorWorkday&user=telemetry&unit_id=356173060289134&&date=2015-11-13
+         * AnalystService?Operation=GetTractorWorkday&user=telemetry&unit_id=356173060289134&date=2015-11-20&minstop=00:05:00&minwork=00:20:00&outtime=00:03:00
+         * 
+         * AnalystService?Operation=GetActivitiesFieldOverview&user=telemetry&site_id=
+         * AnalystService?Operation=GetActivitiesFieldOverview&user=telemetry&plot_id=38
+         * AnalystService?Operation=GetActivitiesFieldOverviewByPoint&user=telemetry&point=1937361.9561476,6372948.5040346
+         * AnalystService?Operation=GetActivitiesFieldOverviewPeriod&user=telemetry&point=1937361.9561476,6372948.5040346&from=2016-05-10&to=2016-05-13
+         * 
+         * AnalystService?Operation=GetFieldFuelSummary&user=telemetry&point=1937361.9561476,6372948.5040346&from=2016-05-10&to=2016-05-13
+         * 
+         * AnalystService?Operation=GetManagementZonesOverview&user=telemetry&plot_id=38&unit_id=356173060289134&from=2015-11-20&to=2015-11-30&property_name=yield potential 5m
+         * AnalystService?Operation=GetManagementZonesOverview&user2=telemetry&plot_id=38&from=2015-11-20&to=2015-11-30&property_name=yield potential 5m
+         * 
+         * AnalystService?Operation=GetManagementZonesOverviewByPoint&user=telemetry&point=1937361.9561476,6372948.5040346&unit_id=356173060289134&from=2015-11-20&to=2015-11-30&property_name=yield potential 5m
+         * AnalystService?Operation=GetManagementZonesOverviewByPoint2&user=telemetry&point=1937361.9561476,6372948.5040346&from=2015-11-20&to=2015-11-30&property_name=yield potential 5m
+         * 
+         * AnalystService?Operation=GetDailyFieldActivities&user=telemetry&plot_id=38&from=2015-11-20&to=2015-11-30
+         * AnalystService?Operation=GetDailyFieldActivitiesByPoint&user=telemetry&point=1937361.9561476,6372948.5040346&from=2015-11-20&to=2015-11-30
+         * 
+         * AnalystService?Operation=GetActiveTractorsPeriod&from=2016-05-29&to=2016-06-02&user=telemetry
+         * 
+         * AnalystService?Operation=GetPlotsGeom&user=telemetry
+         * AnalystService?Operation=GetManagementZonesGeom&user=telemetry&plot_id=8
+         * AnalystService?Operation=GetManagementZoneGeom&user=telemetry&zone_id=60
+         * AnalystService?Operation=GetManagementZoneGeomByPoint&user=telemetry&point=1942324.5738307,6365182.80917219
+         * 
+         */
+        RequestParameters params = new RequestParameters(request);
+        String user = params.getUsername();
+        if(user == null){
+            throw new ServletException("Authentication fairlure for request "+ request.getQueryString());
+        }
+        else{
+            try {
+                String testLang = db.userUtil.getUserLanguage(user);
+                if(testLang.isEmpty()){
+                    throw new ServletException("Authentication fairlure for request "+ request.getQueryString());
+                }
+            } catch (SQLException | NoItemFoundException e1) {
+                throw new ServletException("Authentication fairlure for request "+ request.getQueryString());
+            }
+        }
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.setContentType("application/json; charset=UTF-8");
+
+        PrintWriter out = response.getWriter();
+        try{
+            // request GetWorkOnSites
+            switch (request.getParameter(ServiceParameters.OPERATION)) {
+                case GET_WORK_ON_SITES: {
+                    if (params.getDate() != null) {
+                        if (!params.getDate().isEmpty()) {
+                            DBJsonUtils.writeJSON(out, db.analystUtil.getWorkDurationOnSites(user, params.getDate(), params.getUnit_id()));
+                        } else {
+                            throw new ServletException("Given parameter \"date\" is empty! In request:" + request.getQueryString());
+                        }
+                    } else if (params.getFromDate() != null || params.getToDate() != null) {
+                        if (!params.getFromDate().isEmpty() || !params.getToDate().isEmpty()) {
+                            DBJsonUtils.writeJSON(out, db.analystUtil.getWorkDurationOnSitesPeriod(user, params.getFromDate(), params.getToDate(), params.getUnit_id()));
+                        } else {
+                            throw new ServletException("Given parameters \"from\" and \"to\" are empty! In request:" + request.getQueryString());
+                        }
+                    } else {
+                        throw new ServletException("Wrong combination of parameters! In request:" + request.getQueryString());
+                    }
+                } break;
+                // request GetTractorUtilization
+                case GET_TRACTOR_UTILIZATION: {
+                    if (params.getDate() != null) {
+                        if (!params.getDate().isEmpty()) {
+                            DBJsonUtils.writeJSON(out, db.analystUtil.getUnitUtilization(user, params.getDate(), params.getUnit_id()));
+                        } else {
+                            throw new ServletException("Given parameter \"date\" is empty! In request:" + request.getQueryString());
+                        }
+                    } else if (params.getFromDate() != null || params.getToDate() != null) {
+                        if (!params.getFromDate().isEmpty() || !params.getToDate().isEmpty()) {
+                            DBJsonUtils.writeJSON(out, db.analystUtil.getUnitUtilizationInPeriod(user, params.getFromDate(), params.getToDate(), params.getUnit_id()));
+                        } else {
+                            throw new ServletException("Given parameters \"from\" and \"to\" are empty! In request:" + request.getQueryString());
+                        }
+                    } else {
+                        throw new ServletException("Wrong combination of parameters! In request:" + request.getQueryString());
+                    }
+                } break;
+                // request GetTractorWorkday
+                case GET_TRACTOR_WORKDAY: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getTractorWorkDay(user, params.getDate(), params.getUnit_id(), params.getMinStopDuration(), params.getMinWorkDuration(), params.getAllowedTimeOutside()));
+                } break;
+                // request GetActivitiesFieldOverview
+                case GET_FIELD_OVERVIEW: {
+                    if (params.getSiteId() != null) {
+                        DBJsonUtils.writeJSON(out, db.analystUtil.getActivitiesFieldOverview(params.getSiteId()));
+                    } else if (params.getPlotId() != null) {
+                        DBJsonUtils.writeJSON(out, db.analystUtil.getActivitiesFieldOverviewByPlot(params.getPlotId()));
+                    }
+                } break;
+                // request GetActivitiesFieldOverviewByPoint
+                case GET_FIELD_OVERVIEW_POINT: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getActivitiesFieldOverviewByPoint(params.getPoint()));
+                } break;
+                // request GetActivitiesFieldOverviewPeriod
+                case GET_FIELD_OVERVIEW_PERIOD: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getActivitiesFieldOverviewPeriodByPoint(params.getPoint(), params.getFromDate(), params.getToDate()));
+                } break;
+                // request GetFieldFuelSummary
+                case GET_FIELD_OVERVIEW_FUEL: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getFieldFuelSummaryByPoint(params.getPoint(), params.getFromDate(), params.getToDate()));
+                } break;
+                // GetTractorActivePeriod
+                case GET_TRACTOR_ACTIVE_PERIOD: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.isTractorActiveInPeriod(user, params.getUnit_id(), params.getFromDate(), params.getToDate()));
+                } break;
+                // GetActiveTractorsPeriod
+                case GET_ACTIVE_TRACTORS_PERIOD: {
+                    DBJsonUtils.writeJSONfromList(out, db.analystUtil.getActiveTractorsDuringPeriod(user, params.getFromDate(), params.getToDate()));
+                } break;
+                // GetManagementZonesOverview with tractor
+                case GET_MANAGEMENT_ZONES_OVERVIEW: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getManagementZonesOverviewByPlotId(params.getPlotId(), params.getUnit_id(), params.getFromDate(), params.getToDate(), params.getPropertyName()));
+                } break;
+                // GetManagementZonesOverview without tractor
+                case GET_MANAGEMENT_ZONES_OVERVIEW_2: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getManagementZonesOverviewByPlotId2(params.getPlotId(), params.getFromDate(), params.getToDate(), params.getPropertyName()));
+                } break;
+                // GetManagementZonesOverviewByPoint with tractor
+                case GET_MANAGEMENT_ZONES_OVERVIEW_POINT: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getManagementZonesOverviewByPoint(params.getPoint(), params.getUnit_id(), params.getFromDate(), params.getToDate(), params.getPropertyName()));
+                } break;
+                // GetManagementZonesOverviewByPoint without tractor
+                case GET_MANAGEMENT_ZONES_OVERVIEW_POINT_2: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getManagementZonesOverviewByPoint2(params.getPoint(), params.getFromDate(), params.getToDate(), params.getPropertyName()));
+                } break;
+                // GetDailyFieldActivities
+                case GET_DAILY_FIELD_ACTIVITIES: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getDailyFieldActivities(params.getPlotId(), params.getFromDate(), params.getToDate()));
+                } break;
+                // GetDailyFieldActivitiesByPoint
+                case GET_DAILY_FIELD_ACTIVITIES_POINT: {
+                    DBJsonUtils.writeJSON(out, db.analystUtil.getDailyFieldActivitiesByPoint(params.getPoint(), params.getFromDate(), params.getToDate()));
+                } break;
+                // GetPlotsGeom
+                case GET_PLOTS_GEOM: {
+                    out.write(db.analystUtil.getPlotsAsGeoJSON().toString());
+                } break;
+                // GetManagementZonesGeom
+                case GET_MAN_ZONES_GEOM: {
+                    out.write(db.analystUtil.getManagementZonesGeoJSON(params.getPlotId()).toString());
+                } break;
+                // GetManagementZoneGeom
+                case GET_MAN_ZONE_GEOM: {
+                    out.write(db.analystUtil.getManagementZoneGeoJSON(params.getZoneId()).toString());
+                } break;
+                // GetManagementZoneGeomByPoint
+                case GET_MAN_ZONE_GEOM_POINT: {
+                    out.write(db.analystUtil.getManagementZoneGeoJSONByPoint(params.getPoint()).toString());
+                } break;
+                default:
+                    throw new NullPointerException("No operation specified.");
+            }
+        } catch (SQLException | NoItemFoundException e){
+            solveGetException(e, out);
+        }
+    }
+
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        
+        try {
+            db = new UtilFactory();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+
+    static class RequestParameters {
+
+        private final long unit_id;
+        private final String date;
+        private final String fromDate;
+        private final String toDate;
+        private final String username;
+        private final String minStopDuration;
+        private final String minWorkDuration;
+        private final String allowedTimeOutside;
+        private final Integer siteId;
+        private final Integer plotId;
+        private final Integer zoneId;
+        private final String point;
+        private final String propertyName;
+
+        RequestParameters(HttpServletRequest request) throws NullPointerException {
+            Object uid = request.getParameter("unit_id");
+            this.unit_id = uid != null ? Long.parseLong(uid.toString()) : -1;
+
+            Object dateO = request.getParameter("date");
+            this.date = dateO != null ? dateO.toString() : null;
+
+            Object fromO = request.getParameter("from");
+            this.fromDate = fromO != null ? fromO.toString() : null;
+
+            Object toO = request.getParameter("to");
+            this.toDate = toO != null ? toO.toString() : null;
+
+            Object userO = request.getParameter("user");
+            this.username = userO != null ? userO.toString() : null;
+
+            Object minStopO = request.getParameter("minstop");
+            this.minStopDuration = minStopO != null ? minStopO.toString() : null;
+
+            Object minWorkO = request.getParameter("minwork");
+            this.minWorkDuration = minWorkO != null ? minWorkO.toString() : null;
+
+            Object timeOutO = request.getParameter("outtime");
+            this.allowedTimeOutside = timeOutO != null ? timeOutO.toString() : null;
+
+            Object siteIdO = request.getParameter("site_id");
+            this.siteId = siteIdO != null ? Integer.valueOf(siteIdO.toString()) : null;
+
+            Object plotIdO = request.getParameter("plot_id");
+            this.plotId = plotIdO != null ? Integer.valueOf(plotIdO.toString()) : null;
+
+            Object zoneIdO = request.getParameter("zone_id");
+            this.zoneId = zoneIdO != null ? Integer.valueOf(zoneIdO.toString()) : null;
+
+            Object pointO = request.getParameter("point");
+            this.point = pointO != null ? pointO.toString() : null;
+
+            Object propertyO = request.getParameter("property_name");
+            this.propertyName = propertyO != null ? propertyO.toString() : null;
+        }
+
+        public long getUnit_id() {
+            return unit_id;
+        }
+        
+        public String getDate(){
+            return date;
+        }
+        
+        public String getFromDate(){
+            return fromDate;
+        }
+        
+        public String getToDate(){
+            return toDate;
+        }
+        
+        public String getUsername(){
+            return username;
+        }
+
+        public String getMinStopDuration() {
+            return minStopDuration;
+        }
+
+        public String getMinWorkDuration() {
+            return minWorkDuration;
+        }
+
+        public String getAllowedTimeOutside() {
+            return allowedTimeOutside;
+        }
+
+        public Integer getSiteId(){
+            return siteId;
+        }
+
+        public Integer getPlotId(){
+            return plotId;
+        }
+
+        public Integer getZoneId(){
+            return zoneId;
+        }
+
+        public String getPoint() {
+            return point;
+        }
+
+        public String getPropertyName() {
+            return propertyName;
+        }
+
+        @Override
+        public String toString() {
+            return "RequestParameters [unit_id=" + unit_id + ", date=" + date
+                         + ", fromDate=" + fromDate + ", toDate=" + toDate
+                         + ", username=" + username + ", minStopDuration="
+                         + minStopDuration + ", minWorkDuration=" + minWorkDuration
+                         + ", allowedTimeOutside=" + allowedTimeOutside
+                         + ", siteId=" + siteId + ", point=" + point + "]";
+          }
+    }
+}

+ 129 - 0
src/main/java/cz/hsrs/servlet/provider/ChartServlet.java

@@ -0,0 +1,129 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.ChartGenerator;
+import cz.hsrs.db.DBChartUtils;
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.SensorUtil;
+
+/**
+ * Servlet implementation class ChartServlet
+ */
+public class ChartServlet extends HttpServlet {
+
+	static final long serialVersionUID = 1L;
+
+	public static final String FROMTIME = "fromtime";
+	public static final String TOTIME = "totime";
+	public static final String PHENOMENON = "phenomenon";
+	public static final String SENSOR_ID = "sensor_id";
+	public static final String UNIT_ID = "unit_id";
+	public static final String GID = "gid";
+	public static final String OPERATION = "operation";
+	public static final String SERVICE = "service";
+	public static final String REQUEST = "request";
+	public static final String HEIGHT = "height";
+	public static final String WIDTH = "width";
+
+	private final String chartDir = "";
+
+	private static File pngFile;
+
+		// http://localhost:8080/DBService/ChartServlet?operation=GetPNG&sensor_id=20&width=500&height=300
+
+
+	public ChartServlet() {
+		super();
+	}
+
+
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		processRequest(request, response);
+	}
+
+	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		processRequest(request, response);
+	}
+
+	protected void processRequest(HttpServletRequest request,
+			HttpServletResponse response) throws ServletException, IOException {
+		try {
+			if (request.getParameter(ChartServlet.OPERATION).equals("GetPNG")) {
+				if (pngFile != null) {
+					pngFile.delete();
+				}
+				pngFile = generateTargetLink(request);
+				RequestDispatcher rd = request
+				.getRequestDispatcher(chartDir + pngFile.getName());
+				rd.forward(request, response);
+			} else if (request.getParameter(ChartServlet.OPERATION).equals("GetObservation")) {
+				throw new NullPointerException("Not yet implemented.");
+			} else {
+				throw new NullPointerException("No operation specified.");
+			}
+		} catch (Exception e) {
+			request.setAttribute("exception", e);
+			RequestDispatcher rd = request.getRequestDispatcher("/errorpage.jsp");
+			rd.forward(request, response);
+		}
+
+	}
+
+	protected File generateTargetLink(HttpServletRequest request) throws Exception {
+
+		String fromTime = request.getParameter(ChartServlet.FROMTIME);
+		String toTime = request.getParameter(ChartServlet.TOTIME);
+		String sensor_id = request.getParameter(ChartServlet.SENSOR_ID);
+		String unit_id = request.getParameter(ChartServlet.UNIT_ID);
+		String height = request.getParameter(ChartServlet.HEIGHT);
+		String width =  request.getParameter(ChartServlet.WIDTH);
+
+		Date dateFrom, dateTo;
+		if (fromTime == null && toTime == null) {
+			Date d = new Date();
+			dateFrom = new Date(d.getTime() - (1000 * 60 * 60 * 24 * 7));
+			dateTo = new Date(d.getTime());
+		} else {
+			final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
+			dateFrom = new Date(format.parse(fromTime).getTime());
+			dateTo = new Date(format.parse(toTime).getTime());
+		}
+		
+		int h = Integer.parseInt(height);
+		int w = Integer.parseInt(width);	
+		long s_id = Long.parseLong(sensor_id);
+		long u_id = Long.parseLong(unit_id);
+		
+		String dir = getServletContext().getRealPath(chartDir);
+		ChartGenerator chg = new ChartGenerator(dir);
+
+		SensorUtil sens = new SensorUtil();
+		return chg.getSensorChart(sens.getSensorById(s_id), u_id, dateFrom, dateTo, w, h);
+
+	}
+
+	@Override
+	public void init() throws ServletException {
+		super.init();
+		String propFile = getServletContext().getRealPath("WEB-INF/database.properties");
+		Properties prop = new Properties();
+		try {
+			prop.load(new FileInputStream(propFile));
+			SQLExecutor.setProperties(prop);
+		} catch (Exception e) {
+			throw new ServletException(e.getMessage());
+		}
+	}
+}

+ 172 - 0
src/main/java/cz/hsrs/servlet/provider/DBServlet.java

@@ -0,0 +1,172 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+import javax.naming.AuthenticationException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.pool.SQLExecutor;
+import cz.hsrs.db.util.UserUtil;
+import cz.hsrs.servlet.security.JSPHelper;
+import cz.hsrs.servlet.security.LoginUser;
+
+public abstract class DBServlet extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+    public static String VERSION;
+    public static String BUILD;
+
+    protected static Logger logger = Logger.getLogger(SQLExecutor.LOGGER_ID);
+
+    @Override
+    public void destroy() {
+        try {
+             SQLExecutor.close();
+        } catch (Exception e) {
+            logger.log(Level.SEVERE, e.getMessage(), e);
+        }
+        super.destroy();
+    }
+
+    public void solveGetException(Exception e, PrintWriter out) throws ServletException {
+        if (e instanceof SQLException) {
+            out.print(e.getMessage());
+        }
+        
+        logger.log(Level.WARNING, e.getMessage(), e);
+        
+        try {
+            logger.log(Level.WARNING, "Going to destroy connections...");
+            logger.log(Level.WARNING,e.getMessage(), e);
+            throw new ServletException("Wrong request ", e);
+        } catch (Exception e1) {
+            e.printStackTrace();
+            logger.log(Level.WARNING, e.getMessage(), e);
+            throw new ServletException(e);
+        }
+    }
+
+    @Override
+    public void init() throws ServletException {
+        setDataBaseConnection();
+
+        try {
+            String conffile = "logging.properties";
+            if (SQLExecutor.getConfigFile()!=null) {
+                conffile  = SQLExecutor.getConfigFile();
+            }
+            FileInputStream fstrem = new FileInputStream(
+                new File(getServletContext().getRealPath("WEB-INF/"+conffile)));
+            LogManager.getLogManager().readConfiguration(fstrem);
+            LogManager.getLogManager().addLogger(logger);
+        
+        } catch (SecurityException | IOException e1) {
+            logger.log(Level.INFO, e1.getMessage());
+        }
+        
+        logger.log(Level.INFO, "Logging inialized Succesefully!");
+        
+        /* get version number */
+        try {
+            String appServerHome = getServletContext().getRealPath("/");
+            File manifestFile = new File(appServerHome, "META-INF/MANIFEST.MF");
+
+            Manifest mf = new Manifest();
+            mf.read(new FileInputStream(manifestFile));
+
+            Attributes atts = mf.getMainAttributes();
+
+            VERSION = atts.getValue("Implementation-Version");
+            BUILD = atts.getValue("Implementation-Build");
+        } catch (IOException e) {
+            logger.log(Level.INFO, e.getMessage());
+        }
+
+        super.init();
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        // TODO Auto-generated method stub
+        req.setCharacterEncoding("UTF-8");
+        resp.setCharacterEncoding("UTF-8");
+    }
+
+    protected void setDataBaseConnection() {
+        String propFile = getServletContext().getRealPath("WEB-INF/database.properties");
+        Properties prop = new Properties();
+        try {
+            prop.load(new FileInputStream(propFile));
+            SQLExecutor.setProperties(prop);
+        } catch (Exception e) {
+            logger.log(Level.SEVERE, e.getMessage(), e);
+        }
+    }
+
+    @Deprecated
+    protected String getAuthenticatedUser(HttpServletRequest request) throws AuthenticationException {
+        LoginUser user = ((LoginUser) request.getSession().getAttribute(JSPHelper.USERATTRIBUTE));
+        if (user == null) {
+            if (request.getRemoteHost().equals("127.0.0.1")
+                    && request.getParameter("user") != null) {
+                return request.getParameter("user");
+            } else
+                throw new AuthenticationException(
+                        "Authentication fairlure for request "
+                                + request.getQueryString());
+        }
+        if (user.isAuthenticated()) {
+            return user.getUserName();
+        } else {
+            throw new AuthenticationException(
+                    "Authentication fairlure for request "
+                            + request.getQueryString());
+        }
+    }
+
+    protected LoginUser getAuthenticatedLoginUser(HttpServletRequest request) throws AuthenticationException {
+        LoginUser user = ((LoginUser) request.getSession().getAttribute(JSPHelper.USERATTRIBUTE));
+        if(user != null){
+            if (user.isAuthenticated()) {
+                return user;
+            } else {
+                throw new AuthenticationException("Authentication fairlure for request " + request.getQueryString());
+            }
+        }
+        else{
+            String remoteHost = request.getRemoteHost();
+            if ((remoteHost.equals("127.0.0.1") || remoteHost.equals("localhost")) && request.getParameter("user") != null) {
+                try {
+                    UserUtil uUtil = new UserUtil();
+                    String userName = request.getParameter(JSPHelper.USERATTRIBUTE);
+                    String pass = uUtil.getUserPassword(userName);
+                    LoginUser userLocal = new LoginUser(request);
+
+                    if(userLocal.athenticate(userName, pass)){
+                        return userLocal;
+                    } else{
+                        throw new AuthenticationException("Authentication fairlure for request " + request.getQueryString());
+                    }
+                } catch (Exception e) {
+                    throw new AuthenticationException("Authentication fairlure for request " + request.getQueryString());
+                }
+            } else{
+                throw new AuthenticationException("Authentication fairlure for request " + request.getQueryString());
+            }
+        }
+    }
+}

+ 236 - 0
src/main/java/cz/hsrs/servlet/provider/DataService.java

@@ -0,0 +1,236 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.UnitPosition;
+import cz.hsrs.db.model.UnitTrack;
+import cz.hsrs.db.model.composite.LastPosition;
+import cz.hsrs.db.model.composite.RealUnit;
+import cz.hsrs.db.model.custom.UnitPositionSimple;
+import cz.hsrs.db.util.UtilFactory;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+
+/**
+ * Servlet implementation class DataService
+ * 
+ * http://localhost:8080/DBService/DataService?Operation=GetDataByUserName&user=
+ * pepa&limit=100
+ */
+public class DataService extends DBServlet {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ASC = "ASC";
+    private static final String DESC = "DESC";
+
+    public static final String GET_TRACK = "GetTracks";
+    public static final String GET_LAST_POSTION = "GetLastPositions";
+    public static final String GET_LAST_POSTION_WITH_STATUS = "GetLastPositionsWithStatus";
+    public static final String GET_UNITS = "GetUnits";
+    public static final String GET_RECENT_TRACK = "GetRecentTracks";
+    public static final String GET_POSITIONS = "GetPositions";
+    public static final String GET_POSITIONS_RANGE = "GetPositionsDay";
+    public static final String GET_UNITS_LIST = "GetUnitsList";
+
+    private UtilFactory db;
+
+    public DataService() {
+        super();
+    }
+
+
+    protected void doGet(HttpServletRequest request,
+            HttpServletResponse response) throws ServletException, IOException {
+        super.doGet(request, response);
+        RequestParameters params = new RequestParameters(request);
+        
+        /* For FarmTelemetry purpose only temporary */
+       
+        String user = params.getUser();
+        if(user == null){
+            throw new ServletException("Authentication failure, no user specified for request: "+ request.getQueryString());
+        }
+        else{
+            try {
+                String testLang = db.userUtil.getUserLanguage(user);
+                if(testLang.isEmpty()){
+                    throw new ServletException("Authentication failure for request "+ request.getQueryString());
+                }
+            } catch (SQLException | NoItemFoundException e1) {
+                throw new ServletException("Authentication failure for request "+ request.getQueryString());
+            }
+        }
+
+
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        /*
+         * /DataService?Operation=GetUnits&user=telemetry&unit_id=356173060488215
+         * /DataService?Operation=GetTracks&user=telemetry&limit=500
+         * /DataService?Operation=GetLastPositions&user=telemetry
+         * /DataService?Operation=GetLastPositionsWithStatus&user=telemetry
+         * /DataService?Operation=GetRecentTracks&user=telemetry
+         * /DataService?Operation=GetPositions&user=telemetry&limit=500
+         * /DataService?Operation=GetPositionsDay&user=telemetry&unit_id=356173060488215&fromTime=2016-02-01&toTime=2016-02-04&ordering=desc
+         * /DataService?Operation=GetUnitsList&user=telemetry
+         */
+        PrintWriter out = response.getWriter();
+        try {
+            switch (request.getParameter(ServiceParameters.OPERATION)) {
+                case GET_UNITS: {
+                    DBJsonUtils.writeJSON(out, new RealUnit(), db.userUtil.getLastPositionsByUserNameRes(params.getUser(), params.getUnitId()));
+                } break;
+                case GET_TRACK: {
+                    DBJsonUtils.writeJSON(out, new UnitTrack(), db.userUtil.getTracksByUserName(params.getUser(), params.limit));
+                } break;
+                case GET_LAST_POSTION: {
+                    DBJsonUtils.writeJSON(out, db.userUtil.getLastPositionsByUserName(params.getUser()));
+                } break;
+                case GET_LAST_POSTION_WITH_STATUS: {
+                    List<LastPosition> posList = db.userUtil.getLastPositionWithStatus(params.getUser());
+                    DBJsonUtils.writeJSON(out, posList);
+                } break;
+                case GET_RECENT_TRACK: {
+                    DBJsonUtils.writeJSON(out, new UnitTrack(), db.userUtil.getTracksByUserName(params.getUser(), 1000));
+                } break;
+                case GET_POSITIONS: {
+                    DBJsonUtils.writeJSON(out, new UnitPosition(), db.userUtil.getPositionsByUserName(params.getUser(), params.limit));
+                } break;
+                case GET_POSITIONS_RANGE: {
+                    DBJsonUtils.writeJSON(out, new UnitPositionSimple(), db.userUtil.getPositionsTimeRangeByUserName(params.getUser(), params.fromTime, params.toTime, params.getUnitId(), params.getOrdering()));
+                } break;
+                case GET_UNITS_LIST: {
+                    DBJsonUtils.writeJSON(out, db.userUtil.getUnitsByUser(params.getUser()));
+                } break;
+                default:
+                    throw new NullPointerException("No operation specified.");
+            }
+        } catch (SQLException e) {
+            solveGetException(e, out);
+        }
+    }
+
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        
+        try {
+            db = new UtilFactory();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+    
+
+    /**
+     * Request Parameter subclass
+     * Parses parameter from the request
+     * @author jezekjan
+     *
+     */
+    static class RequestParameters {
+        private String user;
+        private String fromTime;
+        private String toTime;
+        private Integer limit;
+        private Long unitId;
+        private String ordering;
+
+        RequestParameters(HttpServletRequest request) throws NullPointerException{
+            Object userO = request.getParameter("user");
+            if(userO != null){
+                user = userO.toString();
+            }
+            Object limO = request.getParameter("limit");
+            if (limO != null) {
+                limit = Integer.parseInt(limO.toString());
+            }
+
+            Object fromTimeO = request.getParameter("fromTime");
+            if (fromTimeO != null) {
+                fromTime = fromTimeO.toString();
+            }
+            Object toTimeO = request.getParameter("toTime");
+            if (toTimeO != null) {
+                toTime = toTimeO.toString();
+            }
+            Object orderingO = request.getParameter("ordering");
+            if (orderingO != null) {
+                String orderingS = orderingO.toString();
+                if(orderingS.isEmpty()){
+                    ordering = ASC;
+                } else{
+                    ordering = orderingS.equalsIgnoreCase(DESC) ? DESC : ASC;
+                }
+            }else{
+                ordering = ASC;
+            }
+            Object unitO = request.getParameter("unit_id");
+            unitId = unitO != null ? Long.parseLong(unitO.toString()) : null;
+        }
+
+        public Long getUnitId() {
+            return unitId;
+        }
+
+        public void setUnitId(long unitId) {
+            this.unitId = unitId;
+        }
+        
+        public String getUser() {
+            return user;
+        }
+
+        public void setUser(String user) {
+            this.user = user;
+        }
+
+        public Integer getLimit() {
+            return limit;
+        }
+
+        public void setLimit(Integer limit) {
+            this.limit = limit;
+        }
+
+        public String getFromTime() {
+            return fromTime;
+        }
+
+        public void setFromTime(String fromTime) {
+            this.fromTime = fromTime;
+        }
+
+        public String getToTime() {
+            return toTime;
+        }
+
+        public void setToTime(String toTime) {
+            this.toTime = toTime;
+        }
+
+        public String getOrdering() {
+            return ordering;
+        }
+
+        public void setOrdering(String ordering) {
+            this.ordering = ordering;
+        }
+
+        @Override
+        public String toString() {
+            return "RequestParameters [user=" + user + ", fromTime=" + fromTime
+                    + ", toTime=" + toTime + ", limit=" + limit + ", unit_id="
+                    + unitId + ", ordering=" + ordering + "]";
+        }
+    }
+}

+ 106 - 0
src/main/java/cz/hsrs/servlet/provider/GroupService.java

@@ -0,0 +1,106 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+
+import javax.naming.AuthenticationException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.util.UtilFactory;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+import cz.hsrs.servlet.security.LoginUser;
+
+/**
+ * Servlet implementation class GroupService
+ */
+public class GroupService extends DBServlet{
+    private static final long serialVersionUID = 1L;
+    
+    public static final String GET_SUPER_GROUPS = "GetSuperGroups";    
+    public static final String GET_SUB_GROUPS = "GetSubGroups";    
+    public static final String GET_GROUPS = "GetGroups";
+
+    private UtilFactory db;
+       
+    /** @see HttpServlet#HttpServlet() */
+    public GroupService() { super(); }
+
+    public void init() throws ServletException {
+        super.init();
+        
+        try {
+            db = new UtilFactory();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+    /** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response */
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        super.doGet(request, response);
+        RequestParameters params = new RequestParameters(request);
+
+        LoginUser loggedUser;
+        try {
+            loggedUser = getAuthenticatedLoginUser(request);
+            String userName = loggedUser.getUserName();
+            params.setUser(userName);
+        } catch (AuthenticationException e1) {
+            throw new ServletException("Authentication failure for request "+ request.getQueryString());
+        }
+
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
+        // params.setUSER("");
+
+        PrintWriter out = response.getWriter();
+        try {
+            switch (request.getParameter(ServiceParameters.OPERATION)) {
+                case GET_GROUPS:
+                    DBJsonUtils.writeJSON(out, db.groupUtil.getGroups(params.getUser()));
+                    break;
+                case GET_SUPER_GROUPS:
+                    DBJsonUtils.writeJSON(out, db.groupUtil.getSuperGroups(params.getUser()));
+                    break;
+                case GET_SUB_GROUPS:
+                    DBJsonUtils.writeJSON(out, db.groupUtil.getSubGroups(params.getGroupId()));
+                    break;
+                default:
+                    throw new NullPointerException("No operation specified.");
+            }
+        } catch (SQLException e) {
+            solveGetException(e, out);
+        }
+    }
+
+    static class RequestParameters {
+        private String user;
+        private int groupId;
+
+        RequestParameters(HttpServletRequest request) throws NullPointerException{
+            Object id = request.getParameter("parent_group");
+            this.groupId = id != null ? Integer.parseInt(id.toString()) : -1;
+        }
+
+        public String getUser() {
+            return user;
+        }
+
+        public int getGroupId() {
+            return groupId;
+        }
+
+        public void setGroupId(int groupId) {
+            this.groupId = groupId;
+        }
+
+        public void setUser(String user) {
+            this.user = user;
+        }
+    }
+}

+ 102 - 0
src/main/java/cz/hsrs/servlet/provider/MMService.java

@@ -0,0 +1,102 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+import java.util.zip.GZIPOutputStream;
+
+import javax.naming.AuthenticationException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.util.ObservationUtil;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+
+/**
+ * @author mkepka
+ *
+ */
+public class MMService extends DBServlet{
+
+	/* MMService?Operation=GetObservations&unit_from=32768&unit_to=32773&time_from=2011-01-06+00%3A00%3A05&time_to=2011-01-06+00%3A05%3A05 */
+	private static final long serialVersionUID = 1L;	
+	public static final String GET_OBSERVATIONS = "GetObservations";	
+	private ObservationUtil oUtil;
+	
+	public void init() throws ServletException {
+		super.init();
+
+		try {
+			oUtil = new ObservationUtil();
+		} catch (Exception e) {
+			throw new ServletException(e);
+		}
+	}
+	
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		super.doGet(request, response);
+
+		try {
+			getAuthenticatedLoginUser(request);
+		} catch (AuthenticationException e) {
+			throw new ServletException(e);
+		}
+
+		RequestParameters params = new RequestParameters(request);
+		PrintWriter out = response.getWriter();
+		try {
+			if (request.getParameter(ServiceParameters.OPERATION).equals(GET_OBSERVATIONS)) {
+				if(params.getUnitFrom()!= null && params.getUnitTo()!= null){
+					DBJsonUtils.writeJSON(out, oUtil.getObservationsMedlov(params.getUnitFrom(), params.getUnitTo(), params.getTimeFrom(), params.getTimeTo()));
+				}
+				else if(params.getUnitFrom()== null && params.getUnitTo()== null){
+					DBJsonUtils.writeJSON(out, oUtil.getObservationsMedlov(params.getTimeFrom(), params.getTimeTo()));
+				}
+				else{
+					throw new ServletException("Wrong request "+request.getQueryString());
+				}
+			}
+			else {
+				throw new ServletException("Wrong request "+request.getQueryString());
+			}
+		} catch (SQLException e) {
+			solveGetException(e, out);
+		}
+	}
+
+	private boolean canGzip(HttpServletRequest request){
+		String accEnc = request.getHeader("Accept-Encoding");
+		return accEnc != null && accEnc.contains("gzip");
+	}
+	
+	static class RequestParameters {
+
+		private final String time_from, time_to;
+		private final Long unit_from, unit_to;
+
+		RequestParameters(HttpServletRequest request) throws NullPointerException {
+			Object uIdFrom = request.getParameter("unit_from");
+			unit_from = uIdFrom != null ? Long.parseLong(uIdFrom.toString()) : null;
+			Object uIdTo = request.getParameter("unit_from");
+			unit_to = uIdTo != null ? Long.parseLong(uIdTo.toString()) : null;
+			time_from = request.getParameter("time_from");
+			time_to = request.getParameter("time_to");
+		}
+
+		public Long getUnitFrom() {
+			return unit_from;
+		}
+		public Long getUnitTo() {
+			return unit_to;
+		}
+		public String getTimeFrom(){
+			return time_from;			
+		}
+		public String getTimeTo(){
+			return time_to;			
+		}
+	}
+}

+ 137 - 0
src/main/java/cz/hsrs/servlet/provider/ManagementService.java

@@ -0,0 +1,137 @@
+package cz.hsrs.servlet.provider;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.sql.SQLException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+
+import cz.hsrs.db.DBJsonUtils;
+import cz.hsrs.db.model.UnitTrack;
+import net.sf.json.JSON;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import net.sf.json.JSONSerializer;
+import net.sf.json.JsonConfig;
+import net.sf.json.util.CycleDetectionStrategy;
+
+import cz.hsrs.db.model.NoItemFoundException;
+import cz.hsrs.db.model.insert.UnitInsert;
+import cz.hsrs.db.util.UtilFactory;
+import cz.hsrs.servlet.feeder.ServiceParameters;
+
+/**
+ * @author mkepka
+ *
+ */
+public class ManagementService extends DBServlet {
+
+    private static final long serialVersionUID = 1L;
+    private static final String jsonContent = "application/json";
+
+    public static final String INS_UNIT = "InsertUnit";
+    public static final String INS_SENSOR = "InsertSensor";
+    
+    private UtilFactory db;
+    
+    public ManagementService(){
+        super();
+    }
+    
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        
+        try {
+            db = new UtilFactory();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+    
+    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+        RequestParameters params = new RequestParameters(request);
+        String user = params.getUSER();
+        if(user == null){
+            throw new ServletException("Authentication failure, no user specified for request: "+ request.getQueryString());
+        }
+        else{
+            try {
+                String testLang = db.userUtil.getUserLanguage(user);
+                if(testLang.isEmpty()){
+                    throw new ServletException("Authentication failure for request "+ request.getQueryString());
+                }
+            } catch (SQLException | NoItemFoundException e1) {
+                throw new ServletException("Authentication failure for request "+ request.getQueryString());
+            }
+        }
+        
+        /* Setting response headers */
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        
+        PrintWriter out = response.getWriter();
+        try {
+            if (request.getParameter(ServiceParameters.OPERATION).equals(INS_UNIT)) {
+                if(request.getContentLength() > 0){
+                    String contentHeader = request.getHeader(HttpHeaders.CONTENT_TYPE);
+                    if(contentHeader != null && contentHeader.toLowerCase().contains(jsonContent)){
+                        response.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
+                        JSONObject payload = readPayload(request);
+                        UnitInsert responseO = db.manUtil.insertUnit(payload, user);
+                        
+                        JsonConfig cfg = new JsonConfig();
+                        cfg.setIgnoreTransientFields(true);
+                        cfg.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
+                        JSON json = JSONSerializer.toJSON(responseO, cfg);
+                        
+                        json.write(out);
+                    }
+                } else {
+                    throw new ServletException("Request doesn't contain any content!");
+                }
+            // } else if (request.getParameter(ServiceParameters.OPERATION).equals(INS_SENSOR)) {
+                // DBJsonUtils.writeJSON(out, new UnitTrack(), db.userUtil.getTracksByUserName(params.getUSER(),params.LIMIT));
+            } else {
+                throw new ServletException("No operation specified!");
+            }
+        } catch (Exception e) {
+            response.addHeader(HttpHeaders.CONTENT_TYPE, "plain/text");
+            solveGetException(e, out);
+        }
+    }
+
+    private JSONObject readPayload(HttpServletRequest request) throws Exception{
+        StringBuilder jb = new StringBuilder();
+        String line;
+        try {
+            BufferedReader reader = request.getReader();
+            while ((line = reader.readLine()) != null) {
+                jb.append(line);
+            }
+            return JSONObject.fromObject(jb.toString());
+        } catch (IOException e) {
+            throw new Exception(e.getMessage()); 
+        } catch (JSONException e){
+            throw new JSONException(e.getMessage());
+        }
+    }
+
+
+    static class RequestParameters {
+        private final String user;
+        
+        RequestParameters(HttpServletRequest request) throws NullPointerException{
+            Object userO = request.getParameter("user");
+            this.user = userO != null ? userO.toString() : "";
+        }
+        
+        public String getUSER() {
+            return user;
+        }
+    }
+}

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini