diff --git a/CHANGELOG b/CHANGELOG index 8d21a978c95fa2fc39af973c2a0d23cc053a8153..ee5360ff151a257f66920f37480c01d56ff7268d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ minerva (14.0.0~beta.0) unstable; urgency=low reaction (#908) * Bug fix: user with modify access to the project can edit it in admin panel (#901) + * Bug fix: creating project with too long name hung (#916) -- Piotr Gawron <piotr.gawron@uni.lu> Mon, 21 Aug 2019 21:00:00 +0200 diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/map/LayoutDao.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/map/LayoutDao.java index dcced37ff20799cb39e4dd4e363d3f8310136dc5..188f6e329eae824ece97577235e11c3ce98acb78 100644 --- a/persist/src/main/java/lcsb/mapviewer/persist/dao/map/LayoutDao.java +++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/map/LayoutDao.java @@ -26,16 +26,6 @@ public class LayoutDao extends BaseDao<Layout> { return layouts; } - public long getCountByUser(User user) { - CriteriaBuilder builder = getSession().getCriteriaBuilder(); - CriteriaQuery<Long> criteria = builder.createQuery(Long.class); - Root<Layout> root = criteria.from(Layout.class); - - criteria.where(builder.equal(root.get("creator"), user)); - criteria.select(builder.count(root)); - return getSession().createQuery(criteria).getSingleResult(); - } - public Layout getLayoutByName(Project project, String name) { List<Layout> layouts = getElementsByParameter("project_id", project.getId()); for (Layout layout : layouts) { diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java index 8948958f37e87b7d8616c38f294b361f27ed355d..8428dae4f18c88cb1960a23d8514eb8b0dd8b7bc 100644 --- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java +++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java @@ -94,7 +94,6 @@ public class LayoutDaoTest extends PersistTestFunctions { projectDao.add(project); - assertEquals(0, layoutDao.getCountByUser(user)); assertEquals(0, layoutDao.getLayoutsByProject(project).size()); assertNull(layoutDao.getLayoutByName(project, tempName)); @@ -113,7 +112,6 @@ public class LayoutDaoTest extends PersistTestFunctions { assertEquals(1, layoutDao.getLayoutsByProject(project).size()); assertNotNull(layoutDao.getLayoutByName(project, tempName)); - assertEquals(1, layoutDao.getCountByUser(user)); assertNull(layout.getInputData()); diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java index 43103b52b0bbbc24b366023e79bbe20229111b5c..56a3eed9cf20a84469eb5ac8c6dcc2b70c3a561c 100644 --- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java +++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java @@ -334,9 +334,11 @@ public class ProjectRestImpl extends BaseRestImpl { throws QueryException, IOException, SecurityException { Project project = getProjectService().getProjectByProjectId(projectId); if (project != null) { - logger.debug(project.getProjectId()); throw new ObjectExistsException("Project with given id already exists"); } + if (projectId.length() > 255) { + throw new QueryException("projectId is too long"); + } CreateProjectParams params = new CreateProjectParams(); String directory = computePathForProject(projectId, path); String fileId = getFirstValue(data.get("file-id")); @@ -721,6 +723,7 @@ public class ProjectRestImpl extends BaseRestImpl { public String content; @SuppressWarnings("unused") public String level; + public LogEntry(int id, String content, String level) { this.id = id; this.content = content; diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java index cb26f8ee298305cd264b726c94b130562602d5cf..8b9bf83a11257e4029ee73b1554ca29d89aec3b7 100644 --- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java +++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java @@ -316,101 +316,108 @@ public class ProjectService implements IProjectService { } @Override - public void createProject(final CreateProjectParams params) throws SecurityException { + public void createProject(final CreateProjectParams params) { // this count down is used to wait for asynchronous thread to initialize // data in the db (probably it would be better to move the initialization to // main thread) final CountDownLatch waitForInitialData = new CountDownLatch(1); + final List<Throwable> problems = new ArrayList<>(); + Thread computations = new Thread(new Runnable() { @Override public void run() { - if (params.isAsync()) { - // because we are running this in separate thread we need to open a - // new session for db connection - dbUtils.createSessionForCurrentThread(); - } - - Project project = createProjectFromParams(params); - projectDao.add(project); - if (params.isAsync()) { - projectDao.commit(); - } - waitForInitialData.countDown(); - double[] outOfMemoryBuffer; - MinervaLoggerAppender appender = MinervaLoggerAppender.createAppender(); try { - logger.debug("Running: " + params.getProjectId() + "; " + params.getProjectFile()); - outOfMemoryBuffer = new double[OUT_OF_MEMORY_BACKUP_BUFFER_SIZE]; - for (int i = 0; i < OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; i++) { - outOfMemoryBuffer[i] = Math.random() * OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; + if (params.isAsync()) { + // because we are running this in separate thread we need to open a + // new session for db connection + dbUtils.createSessionForCurrentThread(); } - UploadedFileEntry file = params.getProjectFile(); - project.setInputData(file); - - createModel(params, project); - Model originalModel = project.getModels().iterator().next().getModel(); - new CreateHierarchyCommand(originalModel, generator.computeZoomLevels(originalModel), - generator.computeZoomFactor(originalModel)).execute(); - for (Model model : originalModel.getSubmodels()) { - new CreateHierarchyCommand(model, generator.computeZoomLevels(model), generator.computeZoomFactor(model)) - .execute(); + Project project = createProjectFromParams(params); + projectDao.add(project); + if (params.isAsync()) { + projectDao.commit(); } + waitForInitialData.countDown(); + double[] outOfMemoryBuffer; + MinervaLoggerAppender appender = MinervaLoggerAppender.createAppender(); + try { + logger.debug("Running: " + params.getProjectId() + "; " + params.getProjectFile()); + outOfMemoryBuffer = new double[OUT_OF_MEMORY_BACKUP_BUFFER_SIZE]; + for (int i = 0; i < OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; i++) { + outOfMemoryBuffer[i] = Math.random() * OUT_OF_MEMORY_BACKUP_BUFFER_SIZE; + } - createImages(project, params); + UploadedFileEntry file = params.getProjectFile(); + project.setInputData(file); - for (Layout layout : project.getLayouts()) { - for (DataOverlayImageLayer imageLayer : layout.getDataOverlayImageLayers()) { - String[] tmp = imageLayer.getDirectory().split("[\\\\/]"); - imageLayer.setDirectory(tmp[tmp.length - 1]); + createModel(params, project); + Model originalModel = project.getModels().iterator().next().getModel(); + new CreateHierarchyCommand(originalModel, generator.computeZoomLevels(originalModel), + generator.computeZoomFactor(originalModel)).execute(); + for (Model model : originalModel.getSubmodels()) { + new CreateHierarchyCommand(model, generator.computeZoomLevels(model), generator.computeZoomFactor(model)) + .execute(); } - } - projectDao.update(project); + createImages(project, params); - if (params.isAnalyzeAnnotations()) { - analyzeAnnotations(originalModel, params); - } - MinervaLoggerAppender.unregisterLogEventStorage(appender); - project.addLoggingInfo(appender); + for (Layout layout : project.getLayouts()) { + for (DataOverlayImageLayer imageLayer : layout.getDataOverlayImageLayers()) { + String[] tmp = imageLayer.getDirectory().split("[\\\\/]"); + imageLayer.setDirectory(tmp[tmp.length - 1]); + } + } - if (params.isCacheModel()) { - cacheData(originalModel, params); - } + projectDao.update(project); - updateProjectStatus(project, ProjectStatus.DONE, IProgressUpdater.MAX_PROGRESS, params); - if (project.getNotifyEmail() != null && !project.getNotifyEmail().equals("")) { - try { - sendSuccesfullEmail(originalModel); - } catch (MessagingException e) { - logger.error(e, e); + if (params.isAnalyzeAnnotations()) { + analyzeAnnotations(originalModel, params); } - } + MinervaLoggerAppender.unregisterLogEventStorage(appender); + project.addLoggingInfo(appender); - logger.info("Project " + project.getProjectId() + " created successfully."); - } catch (HibernateException e) { - outOfMemoryBuffer = null; - logger.error("Problem with database", e); - handleHibernateExceptionReporting(params, e); - } catch (Exception e) { - outOfMemoryBuffer = null; - handleCreateProjectException(params, e); - } catch (OutOfMemoryError oome) { - // release some memory - outOfMemoryBuffer = null; - logger.error("Out of memory", oome); - if (project != null) { - project.setErrors("Out of memory: " + oome.getMessage()); - } - updateProjectStatus(project, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params); - } finally { - if (params.isAsync()) { - // close the transaction for this thread - dbUtils.closeSessionForCurrentThread(); + if (params.isCacheModel()) { + cacheData(originalModel, params); + } + + updateProjectStatus(project, ProjectStatus.DONE, IProgressUpdater.MAX_PROGRESS, params); + if (project.getNotifyEmail() != null && !project.getNotifyEmail().equals("")) { + try { + sendSuccesfullEmail(originalModel); + } catch (MessagingException e) { + logger.error(e, e); + } + } + + logger.info("Project " + project.getProjectId() + " created successfully."); + } catch (HibernateException e) { + outOfMemoryBuffer = null; + logger.error("Problem with database", e); + handleHibernateExceptionReporting(params, e); + } catch (Exception e) { + outOfMemoryBuffer = null; + handleCreateProjectException(params, e); + } catch (OutOfMemoryError oome) { + // release some memory + outOfMemoryBuffer = null; + logger.error("Out of memory", oome); + if (project != null) { + project.setErrors("Out of memory: " + oome.getMessage()); + } + updateProjectStatus(project, ProjectStatus.FAIL, IProgressUpdater.MAX_PROGRESS, params); + } finally { + if (params.isAsync()) { + // close the transaction for this thread + dbUtils.closeSessionForCurrentThread(); + } + MinervaLoggerAppender.unregisterLogEventStorage(appender); } - MinervaLoggerAppender.unregisterLogEventStorage(appender); + } catch (Throwable t) { + problems.add(t); + waitForInitialData.countDown(); } } @@ -424,7 +431,10 @@ public class ProjectService implements IProjectService { try { waitForInitialData.await(); } catch (InterruptedException e1) { - logger.error(e1, e1); + problems.add(e1); + } + if (problems.size() > 0) { + throw new RuntimeException(problems.get(0)); } } diff --git a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java index 3983113dc8a4d9a79f3d97abb9a21e439bbf5d3f..ad197888d835bfa4fdfcf2a0299853b3c6164664 100644 --- a/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java +++ b/web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java @@ -249,6 +249,13 @@ abstract public class ControllerIntegrationTest { }); } + protected void removeFileInSeparateThread(UploadedFileEntry fileEntry) throws Exception { + callInSeparateThread(() -> { + fileDao.delete(fileDao.getById(fileEntry.getId())); + return null; + }); + } + protected UploadedFileEntry createFileInSeparateThread(String content, User user) throws Exception { return callInSeparateThread(() -> { return createFile(content, user); diff --git a/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTestWithoutTransaction.java b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTestWithoutTransaction.java index a1f33cbaa925c2109e3bba25c974a688a5d8518f..0ce88ed33af6c30d41caf310c4c2266a6356969b 100644 --- a/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTestWithoutTransaction.java +++ b/web/src/test/java/lcsb/mapviewer/web/ProjectControllerIntegrationTestWithoutTransaction.java @@ -62,7 +62,7 @@ public class ProjectControllerIntegrationTestWithoutTransaction extends Controll mockMvc.perform(request).andExpect(status().is2xxSuccessful()); } finally { - callInSeparateThread(()->{ + callInSeparateThread(() -> { try { waitForProjectToFinishLoading(TEST_PROJECT); } catch (InterruptedException e) { @@ -74,4 +74,31 @@ public class ProjectControllerIntegrationTestWithoutTransaction extends Controll } } + @Test + public void addInvalidProject() throws Exception { + User admin = userService.getUserByLogin(BUILT_IN_ADMIN_LOGIN); + UploadedFileEntry fileEntry = createFileInSeparateThread( + new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"), + admin); + try { + String invalidId = "aaaaaaaaxvncnbvscbnmcnbmccbnsbnsdsnbmdsvbnmsdvnbmsdbmnbndvmsbnmsvdnbmnmbdsvnbmdsvxncbmbnmscbnzdnbnabnsbnamsdbmnsadbmnasdbnmnbmsadbnmasdnbasdbnmsadnbnbmsadbnmadsnbmadsnbnbsadnbmadsbnndsabnbmdasbnmdsajqwrhgjrwhjghgjwerghjwreghwewnjnnbbbnbnbmbnbnzcmnnbmzcnmbcsbnmcsnbcnbzmnbczxnbmczxnbmcxznbcnxbmznbmxzcnbzcxnnbcxznbmzcnbczxnbmnbzcxnbmcznnczbnbzcnbmzcbnmbncznbcznbcz"; + + String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList( + new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())), + new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"), + new BasicNameValuePair("parser", + "lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser")))); + + RequestBuilder request = post("/projects/" + invalidId) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .content(body) + .session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD)); + + mockMvc.perform(request).andExpect(status().isBadRequest()); + + } finally { + removeFileInSeparateThread(fileEntry); + } + } + }