Commit 934a2dbd authored by Piotr Gawron's avatar Piotr Gawron

Merge branch '1058-project-remove' into 'devel_14.0.x'

Resolve "this exception is not handled properly (on project remove)"

See merge request !1035
parents 93ecd1f5 f0d6d481
Pipeline #17973 passed with stage
in 14 minutes and 58 seconds
......@@ -5,6 +5,8 @@ minerva (14.0.6) stable; urgency=medium
annotators (#1047)
* Bug fix: if map has SHOW OVERVIEW, the legend/comment/clear were not
displayed at all (regresion 14.0.5, #1045)
* Bug fix: when there is a problem with database during removing project,
project removal doesn't hang (#1058)
-- Piotr Gawron <piotr.gawron@uni.lu> Wed, 18 Dec 2019 12:00:00 +0200
......
......@@ -83,7 +83,7 @@ public class Project implements Serializable {
private List<Layout> layouts = new ArrayList<>();
@Cascade({ CascadeType.SAVE_UPDATE })
@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "file_entry_id")
private UploadedFileEntry inputData;
......
......@@ -7,10 +7,12 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.dialect.Dialect;
import org.hibernate.query.NativeQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.map.model.ModelData;
import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
/**
* Data access object class for Project objects.
......@@ -20,7 +22,10 @@ import lcsb.mapviewer.model.map.model.ModelData;
*/
@Repository
public class ProjectDao extends BaseDao<Project> {
Logger logger = LogManager.getLogger(ProjectDao.class);
Logger logger = LogManager.getLogger();
@Autowired
private UploadedFileEntryDao uploadedFileEntryDao;
/**
* Default constructor.
......@@ -82,4 +87,14 @@ public class ProjectDao extends BaseDao<Project> {
return ((BigInteger) sqlQuery.getResultList().get(0)).longValue();
}
@Override
public void delete(Project project) {
super.delete(project);
if (project.getInputData() != null
&& getElementsByParameter("file_entry_id", project.getInputData().getId()).size() == 0) {
uploadedFileEntryDao.delete(uploadedFileEntryDao.getById(project.getInputData().getId()));
}
}
}
update project_table set file_entry_id = null where not file_entry_id in (select id from file_entry_table);
ALTER TABLE project_table ADD CONSTRAINT project_file_constraint FOREIGN KEY (file_entry_id)
REFERENCES public.file_entry_table (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION;
......@@ -290,7 +290,7 @@ public class ProjectService implements IProjectService {
}
modelService.removeModelFromCacheByProjectId(p.getProjectId());
} catch (HibernateException e) {
} catch (PersistenceException e) {
logger.error("Problem with database", e);
handleHibernateExceptionRemovingReporting(project, e);
} finally {
......@@ -591,7 +591,7 @@ public class ProjectService implements IProjectService {
* project that was being removed
* @param exception
*/
protected void handleHibernateExceptionRemovingReporting(Project originalProject, HibernateException exception) {
protected void handleHibernateExceptionRemovingReporting(Project originalProject, PersistenceException exception) {
// we need to open separate thread because current one thrown db exception
// and transaction is corrupted and will be rolledback
Thread reportInSeparateThread = new Thread(new Runnable() {
......
......@@ -2,6 +2,7 @@ package lcsb.mapviewer.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.nio.file.Files;
......@@ -179,4 +180,75 @@ public class ProjectControllerIntegrationTestWithoutTransaction extends Controll
}
}
@Test
public void addProjectWithInvalidFileId() throws Exception {
String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
new BasicNameValuePair("file-id", "-1"),
new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
new BasicNameValuePair("parser",
"lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"))));
RequestBuilder request = post("/projects/" + TEST_PROJECT)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(body)
.session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD));
mockMvc.perform(request).andExpect(status().isBadRequest());
}
@Test
public void removeProjectWithUsedFile() throws Exception {
String testProject2 = "test2";
User admin = userService.getUserByLogin(BUILT_IN_ADMIN_LOGIN);
try {
UploadedFileEntry fileEntry = createFileInSeparateThread(
new String(Files.readAllBytes(Paths.get("./src/test/resources/generic.xml")), "UTF-8"),
admin);
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/" + TEST_PROJECT)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(body)
.session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD));
mockMvc.perform(request).andExpect(status().is2xxSuccessful());
request = post("/projects/" + testProject2)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(body)
.session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD));
mockMvc.perform(request).andExpect(status().is2xxSuccessful());
callInSeparateThread(() -> {
try {
waitForProjectToFinishLoading(testProject2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
request = delete("/projects/" + testProject2)
.session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD));
mockMvc.perform(request).andExpect(status().is2xxSuccessful());
} finally {
callInSeparateThread(() -> {
try {
waitForProjectToFinishLoading(TEST_PROJECT);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
removeProjectInSeparateThread(TEST_PROJECT);
removeProjectInSeparateThread(testProject2);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment