diff --git a/.classpath b/.classpath index 2fde9ee..db0444e 100644 --- a/.classpath +++ b/.classpath @@ -5,26 +5,19 @@ - - - - - - + - - + - @@ -44,22 +37,13 @@ - - - - + + + - - - - - - - - diff --git a/.gitignore b/.gitignore index e6d545e..9255f6f 100644 --- a/.gitignore +++ b/.gitignore @@ -21,10 +21,12 @@ etc/ivy/ivy.jar restMapping.xml /out /output/ +bin/start_network.bat +bin/start_network.sh # IntelliJ .idea/ # Eclipse .metadata -.idea/workspace.xml \ No newline at end of file +.idea/workspace.xml diff --git a/bin/JOOQGeneration/run.bat b/bin/JOOQGeneration/run.bat index 07f809b..a78426e 100644 --- a/bin/JOOQGeneration/run.bat +++ b/bin/JOOQGeneration/run.bat @@ -1 +1 @@ -java -classpath ../../lib/jooq-3.6.2.jar;../../lib/jooq-meta-3.6.2.jar;../../lib/jooq-codegen-3.6.2.jar;../../lib/mysql-connector-java-5.1.6.jar;. org.jooq.util.GenerationTool /activitytracker_generation_info.xml +java -classpath ../../lib/jooq-3.8.2.jar;../../lib/jooq-meta-3.8.2.jar;../../lib/jooq-codegen-3.8.2.jar;../../lib/mysql-connector-java-5.1.6.jar;. org.jooq.util.GenerationTool /activitytracker_generation_info.xml diff --git a/bin/JOOQGeneration/run.sh b/bin/JOOQGeneration/run.sh index be8eeea..f6d6d0b 100644 --- a/bin/JOOQGeneration/run.sh +++ b/bin/JOOQGeneration/run.sh @@ -1 +1 @@ -java -classpath ../../lib/jooq-3.4.2.jar:../../lib/jooq-meta-3.4.2.jar:../../lib/jooq-codegen-3.4.2.jar:../../lib/mysql-connector-java-5.1.33.jar:. org.jooq.util.GenerationTool /reqbaz_generation_info.xml \ No newline at end of file +java -classpath ../../lib/jooq-3.8.2.jar:../../lib/jooq-meta-3.8.2.jar:../../lib/jooq-codegen-3.8.2.jar:../../lib/mysql-connector-java-5.1.6.jar:. org.jooq.util.GenerationTool /reqbaz_generation_info.xml \ No newline at end of file diff --git a/bin/start_network.bat b/bin/start_network.bat deleted file mode 100644 index 1330bfa..0000000 --- a/bin/start_network.bat +++ /dev/null @@ -1,15 +0,0 @@ -:: this script is autogenerated by 'ant - startscripts' - :: it starts a LAS2peer node providing the service 'de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService' of this project - :: pls execute it from the bin folder of your deployment by double-clicking on it - - %~d0 - cd %~p0 - cd .. - set BASE=%CD% - set CLASSPATH="%BASE%/lib/*;" - - java -cp %CLASSPATH% i5.las2peer.tools.L2pNodeLauncher -p 9012 uploadStartupDirectory startService('de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService@0.1','Passphrase') startWebConnector interactive - pause - - \ No newline at end of file diff --git a/bin/start_network.sh b/bin/start_network.sh deleted file mode 100644 index b4f0878..0000000 --- a/bin/start_network.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - - # this script is autogenerated by 'ant startscripts' - # it starts a LAS2peer node providing the service 'de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService' of this project - # pls execute it from the root folder of your deployment, e. g. ./bin/start_network.sh - - java -cp "lib/*" i5.las2peer.tools.L2pNodeLauncher -p 9012 uploadStartupDirectory startService\(\'de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService@0.1\',\'Passphrase\'\) startWebConnector interactive - - \ No newline at end of file diff --git a/etc/activitytracker_demo_data.sql b/etc/activitytracker_demo_data.sql index 2abcd3a..60dc90e 100644 --- a/etc/activitytracker_demo_data.sql +++ b/etc/activitytracker_demo_data.sql @@ -18,7 +18,7 @@ VALUES NULL, 'http://localhost:8080/bazaar/components/1', 'COMPONENT', 'http://localhost:8080/bazaar/users/2'), ('6', '2015-10-21 10:00:00', 'CREATE', 'http://localhost:8080/bazaar/projects/2', 'PROJECT', 'http://localhost:5000/#!/projects/2', NULL, NULL, 'http://localhost:8080/bazaar/users/2'), - ('7', '2015-10-21 07:00:00', 'CREATE', 'http://localhost:8080/bazaar/components/2', 'COMPONENT', + ('7', '2015-10-21 10:00:00', 'CREATE', 'http://localhost:8080/bazaar/components/2', 'COMPONENT', 'http://localhost:5000/#!/projects/2/components/2', 'http://localhost:8080/bazaar/projects/2', 'PROJECT', 'http://localhost:8080/bazaar/users/2'), ('8', '2015-10-21 11:00:00', 'CREATE', 'http://localhost:8080/bazaar/requirements/2', 'REQUIREMENT', diff --git a/etc/ant_configuration/service.properties b/etc/ant_configuration/service.properties index 3349308..0ad55a4 100644 --- a/etc/ant_configuration/service.properties +++ b/etc/ant_configuration/service.properties @@ -3,4 +3,4 @@ service.name=de.rwth.dbis.acis.activitytracker.service service.path=de/rwth/dbis/acis/activitytracker/service service.class=ActivityTrackerService service.passphrase=Passphrase -service.dependencies= +service.dependencies= \ No newline at end of file diff --git a/etc/de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService.properties b/etc/de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService.properties index 99228cf..bb728d9 100644 --- a/etc/de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService.properties +++ b/etc/de.rwth.dbis.acis.activitytracker.service.ActivityTrackerService.properties @@ -3,3 +3,4 @@ dbPassword=reqbaz dbUrl=jdbc:mysql://localhost:3306/reqbaztrack lang=BAZAAR_LANG country=BAZAAR_COUNTRY +baseURL=https://localhost:8080/activities/ diff --git a/etc/ivy/ivy.xml b/etc/ivy/ivy.xml index 6ca9af2..1acadcc 100644 --- a/etc/ivy/ivy.xml +++ b/etc/ivy/ivy.xml @@ -9,9 +9,11 @@ - - - + + + + + diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/ActivityTrackerService.java b/src/main/de/rwth/dbis/acis/activitytracker/service/ActivityTrackerService.java index ffa236f..a548ea0 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/ActivityTrackerService.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/ActivityTrackerService.java @@ -1,6 +1,5 @@ package de.rwth.dbis.acis.activitytracker.service; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.gson.Gson; import com.google.gson.JsonParser; import de.rwth.dbis.acis.activitytracker.service.dal.DALFacade; @@ -9,6 +8,7 @@ import de.rwth.dbis.acis.activitytracker.service.dal.entities.ActivityEx; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PageInfo; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.Pageable; +import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PaginationResult; import de.rwth.dbis.acis.activitytracker.service.exception.ActivityTrackerException; import de.rwth.dbis.acis.activitytracker.service.exception.ErrorCode; import de.rwth.dbis.acis.activitytracker.service.exception.ExceptionHandler; @@ -25,12 +25,7 @@ import i5.las2peer.restMapper.tools.XMLCheck; import i5.las2peer.security.Context; import io.swagger.annotations.*; -import io.swagger.jaxrs.Reader; -import io.swagger.models.Swagger; -import io.swagger.util.Json; import org.apache.commons.dbcp2.*; -import org.apache.commons.pool2.ObjectPool; -import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; @@ -43,9 +38,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URI; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -53,7 +46,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.logging.Level; /** * LAS2peer Activity Service @@ -85,11 +77,11 @@ public class ActivityTrackerService extends Service { protected String dbUrl; protected String lang; protected String country; + protected String baseURL; private DataSource dataSource; - // TODO: see http://layers.dbis.rwth-aachen.de/jira/browse/LAS-298 - // private final L2pLogger logger = L2pLogger.getInstance(ActivityTrackerService.class.getName()); + private final L2pLogger logger = L2pLogger.getInstance(ActivityTrackerService.class.getName()); public ActivityTrackerService() throws Exception { setFieldValues(); @@ -113,80 +105,102 @@ public ActivityTrackerService() throws Exception { }) //TODO add filter public HttpResponse getActivities( - @ApiParam(value = "Page number", required = false) @DefaultValue("0") @QueryParam("page") int page, - @ApiParam(value = "Elements of components by page", required = false) @DefaultValue("10") @QueryParam("per_page") int perPage, - @ApiParam(value = "User access token", required = false) @DefaultValue("") @QueryParam("access_token") String accessToken) { - List activities = new ArrayList(); - List activitiesEx = new ArrayList(); - DALFacade dalFacade = null; - int getObjectCount = 0; + @ApiParam(value = "Before cursor pagination", required = false) @DefaultValue("-1") @QueryParam("before") int before, + @ApiParam(value = "After cursor pagination", required = false) @DefaultValue("-1") @QueryParam("after") int after, + @ApiParam(value = "Limit of elements of components", required = false) @DefaultValue("10") @QueryParam("limit") int limit, + @ApiParam(value = "User authorization token", required = false) @DefaultValue("") @HeaderParam("authorization") String authorizationToken) { - PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); - cm.setMaxTotal(20); - CloseableHttpClient httpclient = HttpClients.custom() - .setConnectionManager(cm) - .build(); + DALFacade dalFacade = null; try { + if (before != -1 && after != -1) { + ExceptionHandler.getInstance().throwException(ExceptionLocation.ACTIVITIESERVICE, ErrorCode.WRONG_PARAMETER, "both: before and after parameter not possible"); + } + int cursor = before != -1 ? before : after; + Pageable.SortDirection sortDirection = after != -1 ? Pageable.SortDirection.ASC : Pageable.SortDirection.DESC; + + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + cm.setMaxTotal(20); + CloseableHttpClient httpclient = HttpClients.custom() + .setConnectionManager(cm) + .build(); + dalFacade = getDBConnection(); Gson gson = new Gson(); ExecutorService executor = Executors.newCachedThreadPool(); - while (activitiesEx.size() < perPage && getObjectCount < 5) { - Pageable pageInfo = new PageInfo(page, perPage); + int getObjectCount = 0; + PaginationResult activities; + List activitiesEx = new ArrayList<>(); + Pageable pageInfo = new PageInfo(cursor, limit, "", sortDirection); + while (activitiesEx.size() < limit && getObjectCount < 5) { + pageInfo = new PageInfo(cursor, limit, "", sortDirection); activities = dalFacade.findActivities(pageInfo); getObjectCount++; - page++; - activitiesEx.addAll(getObjectBodies(httpclient, executor, accessToken, activities)); + cursor = sortDirection == Pageable.SortDirection.ASC ? cursor + limit : cursor - limit; + if (cursor < 0) { + cursor = 0; + } + activitiesEx.addAll(getObjectBodies(httpclient, executor, authorizationToken, activities.getElements())); } executor.shutdown(); - if (activitiesEx.size() > perPage) { - activitiesEx = activitiesEx.subList(0, perPage); + if (activitiesEx.size() > limit) { + activitiesEx = activitiesEx.subList(0, limit); } - return new HttpResponse(gson.toJson(activitiesEx), HttpURLConnection.HTTP_OK); + PaginationResult activitiesExResult = new PaginationResult<>(pageInfo, activitiesEx); + + HttpResponse response = new HttpResponse(gson.toJson(activitiesExResult.getElements()), HttpURLConnection.HTTP_OK); + Map parameter = new HashMap<>(); + parameter.put("limit", String.valueOf(limit)); + response = this.addPaginationToHtppResponse(activitiesExResult, "", parameter, response); + + return response; + + } catch (ActivityTrackerException atException) { + return new HttpResponse(ExceptionHandler.getInstance().toJSON(atException), HttpURLConnection.HTTP_INTERNAL_ERROR); } catch (Exception ex) { - ActivityTrackerException atException = ExceptionHandler.getInstance().convert(ex, ExceptionLocation.ACTIVITIESERVICE, ErrorCode.UNKNOWN, ""); + ActivityTrackerException atException = ExceptionHandler.getInstance().convert(ex, ExceptionLocation.ACTIVITIESERVICE, ErrorCode.UNKNOWN, ex.getMessage()); return new HttpResponse(ExceptionHandler.getInstance().toJSON(atException), HttpURLConnection.HTTP_INTERNAL_ERROR); } finally { closeDBConnection(dalFacade); } } - private List getObjectBodies(CloseableHttpClient httpclient, ExecutorService executor, String accessToken, + private List getObjectBodies(CloseableHttpClient httpclient, ExecutorService executor, String authorizationToken, List activities) throws Exception { - List activitiesEx = new ArrayList(); - Map> dataFutures = new HashMap>(); - Map> parentDataFutures = new HashMap>(); - Map> userFutures = new HashMap>(); + List activitiesEx = new ArrayList<>(); + Map> dataFutures = new HashMap<>(); + Map> parentDataFutures = new HashMap<>(); + Map> userFutures = new HashMap<>(); JsonParser parser = new JsonParser(); for (int i = 0; i < activities.size(); i++) { Activity activity = activities.get(i); if (activity.getDataUrl() != null && !activity.getDataUrl().isEmpty()) { URIBuilder uriBuilder = new URIBuilder(activity.getDataUrl()); - if (!accessToken.isEmpty()) { - uriBuilder.setParameter("access_token", accessToken); - } URI uri = uriBuilder.build(); HttpGet httpget = new HttpGet(uri); + if (!authorizationToken.isEmpty()) { + httpget.addHeader("authorization", authorizationToken); + } dataFutures.put(activity.getId(), executor.submit(new HttpRequestCallable(httpclient, httpget))); } if (activity.getParentDataUrl() != null && !activity.getParentDataUrl().isEmpty()) { URIBuilder uriBuilder = new URIBuilder(activity.getParentDataUrl()); - if (!accessToken.isEmpty()) { - uriBuilder.setParameter("access_token", accessToken); - } URI uri = uriBuilder.build(); HttpGet httpget = new HttpGet(uri); + if (!authorizationToken.isEmpty()) { + httpget.addHeader("authorization", authorizationToken); + } parentDataFutures.put(activity.getId(), executor.submit(new HttpRequestCallable(httpclient, httpget))); } if (activity.getUserUrl() != null && !activity.getUserUrl().isEmpty()) { URIBuilder uriBuilder = new URIBuilder(activity.getUserUrl()); - if (!accessToken.isEmpty()) { - uriBuilder.setParameter("access_token", accessToken); - } URI uri = uriBuilder.build(); HttpGet httpget = new HttpGet(uri); + if (!authorizationToken.isEmpty()) { + httpget.addHeader("authorization", authorizationToken); + } userFutures.put(activity.getId(), executor.submit(new HttpRequestCallable(httpclient, httpget))); } } @@ -252,6 +266,55 @@ public HttpResponse createActivity(@ApiParam(value = "Activity" + } } + public HttpResponse addPaginationToHtppResponse(PaginationResult paginationResult, String path, Map httpParameter, + HttpResponse httpResponse) throws URISyntaxException { + httpResponse.setHeader("X-Limit", String.valueOf(paginationResult.getPageable().getLimit())); + + if (paginationResult.getPageable().getSortDirection() == Pageable.SortDirection.ASC) { + if (paginationResult.getPrevCursor() != -1) { + httpResponse.setHeader("X-Cursor-Before", String.valueOf(paginationResult.getPrevCursor())); + } + if (paginationResult.getNextCursor() != -1) { + httpResponse.setHeader("X-Cursor-After", String.valueOf(paginationResult.getNextCursor())); + } + } else { + if (paginationResult.getNextCursor() != -1) { + httpResponse.setHeader("X-Cursor-Before", String.valueOf(paginationResult.getNextCursor())); + } + if (paginationResult.getPrevCursor() != -1) { + httpResponse.setHeader("X-Cursor-After", String.valueOf(paginationResult.getPrevCursor())); + } + } + + URIBuilder uriBuilder = new URIBuilder(baseURL + path); + for (Map.Entry entry : httpParameter.entrySet()) { + uriBuilder.addParameter(entry.getKey(), entry.getValue()); + } + String links = new String(); + if (paginationResult.getPageable().getSortDirection() == Pageable.SortDirection.ASC) { + if (paginationResult.getPrevCursor() != -1) { + URIBuilder uriBuilderTemp = new URIBuilder(uriBuilder.build()); + links = links.concat("<" + uriBuilderTemp.addParameter("before", String.valueOf(paginationResult.getPrevCursor())).build() + ">; rel=\"prev\","); + } + if (paginationResult.getNextCursor() != -1) { + URIBuilder uriBuilderTemp = new URIBuilder(uriBuilder.build()); + links = links.concat("<" + uriBuilderTemp.addParameter("after", String.valueOf(paginationResult.getNextCursor())).build() + ">; rel=\"next\""); + } + } else { + if (paginationResult.getNextCursor() != -1) { + URIBuilder uriBuilderTemp = new URIBuilder(uriBuilder.build()); + links = links.concat("<" + uriBuilderTemp.addParameter("before", String.valueOf(paginationResult.getNextCursor())).build() + ">; rel=\"prev\","); + } + if (paginationResult.getPrevCursor() != -1) { + URIBuilder uriBuilderTemp = new URIBuilder(uriBuilder.build()); + links = links.concat("<" + uriBuilderTemp.addParameter("after", String.valueOf(paginationResult.getPrevCursor())).build() + ">; rel=\"next\""); + } + } + + httpResponse.setHeader("Link", links); + return httpResponse; + } + // ////////////////////////////////////////////////////////////////////////////////////// // Methods required by the LAS2peer framework. // ////////////////////////////////////////////////////////////////////////////////////// @@ -301,11 +364,14 @@ public String getRESTMapping() { } private static DataSource setupDataSource(String dbUrl, String dbUserName, String dbPassword) { - ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(dbUrl, dbUserName, dbPassword); - PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); - ObjectPool connectionPool = new GenericObjectPool<>(poolableConnectionFactory); - poolableConnectionFactory.setPool(connectionPool); - PoolingDataSource dataSource = new PoolingDataSource<>(connectionPool); + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName("com.mysql.jdbc.Driver"); + dataSource.setUrl(dbUrl); + dataSource.setUsername(dbUserName); + dataSource.setPassword(dbPassword); + dataSource.setValidationQuery("SELECT 1;"); + dataSource.setTestOnBorrow(true); // test each connection when borrowing from the pool with the validation query + dataSource.setMaxConnLifetimeMillis(1000 * 60 * 60); // max connection life time 1h. mysql drops connection after 8h. return dataSource; } diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacade.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacade.java index a588cda..da85bfe 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacade.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacade.java @@ -2,15 +2,14 @@ import de.rwth.dbis.acis.activitytracker.service.dal.entities.Activity; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.Pageable; +import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PaginationResult; import de.rwth.dbis.acis.activitytracker.service.exception.ActivityTrackerException; -import java.sql.Connection; -import java.util.List; public interface DALFacade { void close(); - List findActivities(Pageable pageable) throws ActivityTrackerException; + PaginationResult findActivities(Pageable pageable) throws ActivityTrackerException; Activity createActivity(Activity activity) throws ActivityTrackerException; } diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacadeImpl.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacadeImpl.java index 219bb87..2148cab 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacadeImpl.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/DALFacadeImpl.java @@ -2,16 +2,14 @@ import de.rwth.dbis.acis.activitytracker.service.dal.entities.Activity; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.Pageable; +import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PaginationResult; import de.rwth.dbis.acis.activitytracker.service.dal.repositories.ActivityRepository; import de.rwth.dbis.acis.activitytracker.service.dal.repositories.ActivityRepositoryImpl; -import de.rwth.dbis.acis.activitytracker.service.dal.transform.ActivityTransformator; import de.rwth.dbis.acis.activitytracker.service.exception.ActivityTrackerException; import org.jooq.*; import org.jooq.impl.DSL; import javax.sql.DataSource; -import java.sql.Connection; -import java.util.Iterator; import java.util.List; public class DALFacadeImpl implements DALFacade { @@ -25,13 +23,13 @@ public DALFacadeImpl(DataSource dataSource, SQLDialect dialect) { } public void close() { - dslContext.close(); + dslContext.close(); } @Override - public List findActivities(Pageable pageable) throws ActivityTrackerException{ - List activities = activityRepository.findAll(pageable); + public PaginationResult findActivities(Pageable pageable) throws ActivityTrackerException { + PaginationResult activities = activityRepository.findAll(pageable); return activities; } diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/Activity.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/Activity.java index 0e5a2a1..a9da9ce 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/Activity.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/Activity.java @@ -4,7 +4,6 @@ public class Activity extends EntityBase { - private final int id; private final Date creationTime; private final String activityAction; private final String dataUrl; @@ -14,10 +13,6 @@ public class Activity extends EntityBase { private final String parentDataType; private final String userUrl; - @Override - public int getId() { - return id; - } public Date getCreationTime() { return creationTime; @@ -52,7 +47,7 @@ public String getUserUrl() { } protected Activity(Builder builder) { - this.id = builder.id; + super(builder); this.creationTime = builder.creationTime; this.activityAction = builder.activityAction; this.dataUrl = builder.dataUrl; diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/EntityBase.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/EntityBase.java index 4c14127..0183c12 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/EntityBase.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/entities/EntityBase.java @@ -4,7 +4,20 @@ public abstract class EntityBase implements IdentifiedById { + private final int id; + + public EntityBase(Activity.Builder builder) { + this.id = builder.id; + } + + @Override + public int getId() { + return id; + } + public String toJSON() { return new Gson().toJson(this); } + + // TODO: Add an abstract Builder to avoid import Activity.Builder here } diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PageInfo.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PageInfo.java index 971bc80..045ce56 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PageInfo.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PageInfo.java @@ -2,33 +2,35 @@ public class PageInfo implements Pageable { - private final int pageNumber; - private final int pageSize; + private final int cursor; + private final int limit; + private final String filter; private final SortDirection sortDirection; - public PageInfo(int pageNumber, int pageSize) { - this(pageNumber, pageSize, SortDirection.DEFAULT); + public PageInfo(int cursor, int limit, String filter) { + this(cursor, limit, filter, SortDirection.DEFAULT); } - public PageInfo(int pageNumber, int pageSize, SortDirection sortDirection) { - this.pageNumber = pageNumber; - this.pageSize = pageSize; + public PageInfo(int cursor, int limit, String filter, SortDirection sortDirection) { + this.cursor = cursor; + this.limit = limit; + this.filter = filter; this.sortDirection = sortDirection; } @Override - public int getOffset() { - return pageNumber * pageSize; + public int getCursor() { + return cursor; } @Override - public int getPageNumber() { - return pageNumber; + public int getLimit() { + return limit; } @Override - public int getPageSize() { - return pageSize; + public String getFilter() { + return filter; } @Override diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/Pageable.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/Pageable.java index e97f7c7..f5b4764 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/Pageable.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/Pageable.java @@ -1,15 +1,16 @@ package de.rwth.dbis.acis.activitytracker.service.dal.helpers; public interface Pageable { - int getOffset(); + int getCursor(); - int getPageNumber(); + int getLimit(); - int getPageSize(); + String getFilter(); SortDirection getSortDirection(); - public enum SortDirection { + enum SortDirection { DEFAULT, ASC, DESC } + } diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PaginationResult.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PaginationResult.java new file mode 100644 index 0000000..9a34e58 --- /dev/null +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/helpers/PaginationResult.java @@ -0,0 +1,44 @@ +package de.rwth.dbis.acis.activitytracker.service.dal.helpers; + + +import de.rwth.dbis.acis.activitytracker.service.dal.entities.EntityBase; + +import java.util.List; + +public class PaginationResult { + + private Pageable pageable; + private List elements; + + public PaginationResult(Pageable pageable, List elements) { + this.pageable = pageable; + this.elements = elements; + } + + public Pageable getPageable() { + return pageable; + } + + public List getElements() { + return elements; + } + + public int getPrevCursor() { + if (this.getElements().isEmpty()) { + return -1; + } else { + return this.getElements().get(0).getId(); + } + + } + + public int getNextCursor() { + if (this.getElements().isEmpty()) { + return -1; + } else { + return this.getElements().get(this.getElements().size() - 1).getId(); + } + } + +} + diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/Repository.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/Repository.java index c49d8b0..6f4647f 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/Repository.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/Repository.java @@ -2,6 +2,7 @@ import de.rwth.dbis.acis.activitytracker.service.dal.entities.EntityBase; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.Pageable; +import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PaginationResult; import de.rwth.dbis.acis.activitytracker.service.exception.ActivityTrackerException; import java.util.List; @@ -35,18 +36,19 @@ public interface Repository { /** * @param pageable - * @return all the entities currently in the database + * @return PaginationResult with all the entities currently in the database * @throws ActivityTrackerException */ - public List findAll(Pageable pageable) throws ActivityTrackerException; + public PaginationResult findAll(Pageable pageable) throws ActivityTrackerException; + /** * @param searchTerm * @param pageable - * @return all the entities currently in the database matching the searchTerm + * @return PaginationResult with all the entities currently in the database matching the searchTerm * @throws ActivityTrackerException */ - public List searchAll(String searchTerm, Pageable pageable) throws ActivityTrackerException; + public PaginationResult searchAll(String searchTerm, Pageable pageable) throws ActivityTrackerException; /** * @param id of the entity we are looking for diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/RepositoryImpl.java b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/RepositoryImpl.java index de89856..52966e0 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/RepositoryImpl.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/dal/repositories/RepositoryImpl.java @@ -2,17 +2,20 @@ import de.rwth.dbis.acis.activitytracker.service.dal.entities.EntityBase; import de.rwth.dbis.acis.activitytracker.service.dal.helpers.Pageable; +import de.rwth.dbis.acis.activitytracker.service.dal.helpers.PaginationResult; import de.rwth.dbis.acis.activitytracker.service.dal.transform.Transformator; import de.rwth.dbis.acis.activitytracker.service.exception.ActivityTrackerException; import de.rwth.dbis.acis.activitytracker.service.exception.ErrorCode; import de.rwth.dbis.acis.activitytracker.service.exception.ExceptionHandler; import de.rwth.dbis.acis.activitytracker.service.exception.ExceptionLocation; import org.jooq.*; +import org.jooq.Condition; import org.jooq.exception.DataAccessException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.locks.*; public class RepositoryImpl implements Repository { @@ -83,7 +86,7 @@ public E delete(int id) throws ActivityTrackerException { public List findAll() throws ActivityTrackerException { List entries = null; try { - entries = new ArrayList(); + entries = new ArrayList<>(); List queryResults = jooq.selectFrom(transformator.getTable()).fetchInto(transformator.getRecordClass()); @@ -100,63 +103,84 @@ public List findAll() throws ActivityTrackerException { /** * @param pageable - * @return all the entities currently in the database + * @return PaginationResult with all the entities currently in the database * @throws ActivityTrackerException */ @Override - public List findAll(Pageable pageable) throws ActivityTrackerException { - List entries = null; + public PaginationResult findAll(Pageable pageable) throws ActivityTrackerException { + PaginationResult result = null; try { - entries = new ArrayList(); + List entries = new ArrayList<>(); + + Condition condition = transformator.getTableId().notEqual(-1); + if (pageable.getCursor() != -1) { + if (pageable.getSortDirection() == Pageable.SortDirection.ASC) { + condition = transformator.getTableId().greaterThan(pageable.getCursor()); + } else { + condition = transformator.getTableId().lessThan(pageable.getCursor()); + } + } List queryResults = jooq.selectFrom(transformator.getTable()) + .where(condition) .orderBy(transformator.getSortFields(pageable.getSortDirection())) - .limit(pageable.getPageSize()) - .offset(pageable.getOffset()) + .limit(pageable.getLimit()) .fetchInto(transformator.getRecordClass()); for (R queryResult : queryResults) { E entry = transformator.mapToEntity(queryResult); entries.add(entry); } + + result = new PaginationResult<>(pageable, entries); } catch (DataAccessException e) { ExceptionHandler.getInstance().convertAndThrowException(e, ExceptionLocation.REPOSITORY, ErrorCode.UNKNOWN, e.getMessage()); } - return entries; + return result; } /** * @param searchTerm * @param pageable - * @return all the entities currently in the database matching the searchTerm + * @return PaginationResult with all the entities currently in the database matching the searchTerm * @throws ActivityTrackerException */ @Override - public List searchAll(String searchTerm, Pageable pageable) throws ActivityTrackerException { - List entries = null; + public PaginationResult searchAll(String searchTerm, Pageable pageable) throws ActivityTrackerException { + PaginationResult result = null; try { - entries = new ArrayList(); + List entries = new ArrayList<>(); + + Condition condition = transformator.getTableId().notEqual(-1); + if (pageable.getCursor() != -1) { + if (pageable.getSortDirection() == Pageable.SortDirection.ASC) { + condition = transformator.getTableId().greaterThan(pageable.getCursor()); + } else { + condition = transformator.getTableId().lessThan(pageable.getCursor()); + } + } String likeExpression = "%" + searchTerm + "%"; List queryResults = jooq.selectFrom(transformator.getTable()) - .where(transformator.getSearchFields(likeExpression)) + .where(transformator.getSearchFields(likeExpression)).and(condition) .orderBy(transformator.getSortFields(pageable.getSortDirection())) - .limit(pageable.getPageSize()) - .offset(pageable.getOffset()) + .limit(pageable.getLimit()) .fetchInto(transformator.getRecordClass()); for (R queryResult : queryResults) { E entry = transformator.mapToEntity(queryResult); entries.add(entry); } + + result = new PaginationResult<>(pageable, entries); } catch (ActivityTrackerException ex) { ExceptionHandler.getInstance().convertAndThrowException(ex); } catch (Exception e) { ExceptionHandler.getInstance().convertAndThrowException(e, ExceptionLocation.REPOSITORY, ErrorCode.UNKNOWN); } - return entries; + return result; } /** diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/exception/ErrorCode.java b/src/main/de/rwth/dbis/acis/activitytracker/service/exception/ErrorCode.java index 360ee19..052f74f 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/exception/ErrorCode.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/exception/ErrorCode.java @@ -7,7 +7,8 @@ public enum ErrorCode { AUTHORIZATION("003", "This user is not authorized to use this method"), DB_COMM("004", "Error during communicating to database. Possibly wrong connection parameters"), NOT_FOUND("005", "The item was not found"), - NETWORK_PROBLEM("006", "Error while trying to receive activity content"); + NETWORK_PROBLEM("006", "Error while trying to receive activity content"), + WRONG_PARAMETER("006", "Wrong paramer given"); private final String code; private final String message; diff --git a/src/main/de/rwth/dbis/acis/activitytracker/service/network/HttpRequestCallable.java b/src/main/de/rwth/dbis/acis/activitytracker/service/network/HttpRequestCallable.java index 32a35dc..cd5663a 100644 --- a/src/main/de/rwth/dbis/acis/activitytracker/service/network/HttpRequestCallable.java +++ b/src/main/de/rwth/dbis/acis/activitytracker/service/network/HttpRequestCallable.java @@ -26,9 +26,6 @@ public class HttpRequestCallable implements Callable { private final HttpContext context; private final HttpGet httpget; - // TODO: see http://layers.dbis.rwth-aachen.de/jira/browse/LAS-298 - //private final L2pLogger logger = L2pLogger.getInstance(ActivityTrackerService.class.getName()); - public HttpRequestCallable(CloseableHttpClient httpClient, HttpGet httpget) { this.httpClient = httpClient; this.context = new BasicHttpContext(); @@ -36,7 +33,7 @@ public HttpRequestCallable(CloseableHttpClient httpClient, HttpGet httpget) { } @Override - public Object call() throws Exception, ActivityTrackerException { + public Object call() throws Exception { String responseBody = new String(); CloseableHttpResponse response = null; try { @@ -61,10 +58,12 @@ public Object call() throws Exception, ActivityTrackerException { IOUtils.copy(entity.getContent(), writer); responseBody = writer.toString(); } + } catch (ActivityTrackerException ate) { + throw ate; } catch (Exception e) { - // logger.log(Level.SEVERE, e.toString(), e); throw ExceptionHandler.getInstance().convert(e, ExceptionLocation.NETWORK, ErrorCode.UNKNOWN, ""); - } finally { + } + finally { if (response != null) { response.close(); }