Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
minerva
core
Commits
b347fdd6
Commit
b347fdd6
authored
Aug 12, 2020
by
Piotr Gawron
Browse files
Merge branch 'conflict-in-update-preferences' into 'devel_15.0.x'
Conflict in update preferences See merge request
!1228
parents
e1e83c29
d8c5562b
Pipeline
#30953
passed with stage
in 14 minutes and 41 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CHANGELOG
View file @
b347fdd6
...
@@ -3,6 +3,8 @@ minerva (15.0.3) stable; urgency=medium
...
@@ -3,6 +3,8 @@ minerva (15.0.3) stable; urgency=medium
issues
(#
1315
)
issues
(#
1315
)
*
Bug
fix
:
when
there
is
a
problem
with
minerva
deployment
on
tomcat
proper
*
Bug
fix
:
when
there
is
a
problem
with
minerva
deployment
on
tomcat
proper
warning
message
is
presented
in
admin
panel
(#
1332
)
warning
message
is
presented
in
admin
panel
(#
1332
)
*
Bug
fix
:
API
call
updating
user
preferences
did
not
handle
properly
conflicts
on
new
gui
properties
(#
1326
)
--
Piotr
Gawron
<
piotr
.
gawron
@
uni
.
lu
>
Wed
,
8
Jul
2020
16
:
00
:
00
+
0200
--
Piotr
Gawron
<
piotr
.
gawron
@
uni
.
lu
>
Wed
,
8
Jul
2020
16
:
00
:
00
+
0200
...
...
rest-api/src/main/java/lcsb/mapviewer/api/BaseController.java
View file @
b347fdd6
...
@@ -39,6 +39,8 @@ public abstract class BaseController {
...
@@ -39,6 +39,8 @@ public abstract class BaseController {
return
createErrorResponse
(
"Object not found."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
NOT_FOUND
);
return
createErrorResponse
(
"Object not found."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
NOT_FOUND
);
}
else
if
(
e
instanceof
ObjectExistsException
)
{
}
else
if
(
e
instanceof
ObjectExistsException
)
{
return
createErrorResponse
(
"Object already exists."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
CONFLICT
);
return
createErrorResponse
(
"Object already exists."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
CONFLICT
);
}
else
if
(
e
instanceof
UpdateConflictException
)
{
return
createErrorResponse
(
"There is a conflict with another query. Try again later."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
CONFLICT
);
}
else
if
(
e
instanceof
OperationNotAllowedException
)
{
}
else
if
(
e
instanceof
OperationNotAllowedException
)
{
return
createErrorResponse
(
"Operation not allowed."
,
e
.
getMessage
(),
new
HttpHeaders
(),
return
createErrorResponse
(
"Operation not allowed."
,
e
.
getMessage
(),
new
HttpHeaders
(),
HttpStatus
.
METHOD_NOT_ALLOWED
);
HttpStatus
.
METHOD_NOT_ALLOWED
);
...
...
rest-api/src/main/java/lcsb/mapviewer/api/UpdateConflictException.java
0 → 100644
View file @
b347fdd6
package
lcsb.mapviewer.api
;
/**
* Thrown when object cannot be updated over API due to conflicting queries.
*
* @author Piotr Gawron
*
*/
public
class
UpdateConflictException
extends
QueryException
{
/**
*
*/
private
static
final
long
serialVersionUID
=
1L
;
/**
* Default constructor.
*
* @param message
* error message
*/
public
UpdateConflictException
(
String
message
)
{
super
(
message
);
}
/**
* Constructor with error message and parent exception.
*
* @param message
* error message
* @param reason
* parent exception that caused this one
*/
public
UpdateConflictException
(
String
message
,
Exception
reason
)
{
super
(
message
,
reason
);
}
}
rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
View file @
b347fdd6
...
@@ -5,6 +5,7 @@ import java.util.*;
...
@@ -5,6 +5,7 @@ import java.util.*;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
import
org.apache.logging.log4j.Logger
;
import
org.hibernate.exception.ConstraintViolationException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.access.AccessDeniedException
;
import
org.springframework.security.access.AccessDeniedException
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.security.core.GrantedAuthority
;
...
@@ -25,7 +26,7 @@ import lcsb.mapviewer.model.user.*;
...
@@ -25,7 +26,7 @@ import lcsb.mapviewer.model.user.*;
import
lcsb.mapviewer.model.user.annotator.*
;
import
lcsb.mapviewer.model.user.annotator.*
;
import
lcsb.mapviewer.services.interfaces.ILayoutService
;
import
lcsb.mapviewer.services.interfaces.ILayoutService
;
@Transactional
@Transactional
(
rollbackFor
=
UpdateConflictException
.
class
)
@Service
@Service
public
class
UserRestImpl
extends
BaseRestImpl
{
public
class
UserRestImpl
extends
BaseRestImpl
{
...
@@ -606,6 +607,13 @@ public class UserRestImpl extends BaseRestImpl {
...
@@ -606,6 +607,13 @@ public class UserRestImpl extends BaseRestImpl {
return
getUser
(
login
,
"preferences"
);
return
getUser
(
login
,
"preferences"
);
}
catch
(
IllegalArgumentException
e
)
{
}
catch
(
IllegalArgumentException
e
)
{
throw
new
QueryException
(
"Invalid input"
,
e
);
throw
new
QueryException
(
"Invalid input"
,
e
);
}
catch
(
Exception
e
)
{
if
(
e
.
getCause
()
instanceof
ConstraintViolationException
)
{
if
(
e
.
getCause
().
getCause
().
getMessage
().
contains
(
"duplicate key value violates unique constraint"
))
{
throw
new
UpdateConflictException
(
"Conflict when updating preferences."
,
e
);
}
}
throw
e
;
}
}
}
}
...
...
web/src/test/java/lcsb/mapviewer/web/ControllerIntegrationTest.java
View file @
b347fdd6
...
@@ -93,7 +93,7 @@ abstract public class ControllerIntegrationTest {
...
@@ -93,7 +93,7 @@ abstract public class ControllerIntegrationTest {
private
LayoutDao
layoutDao
;
private
LayoutDao
layoutDao
;
@Autowired
@Autowired
pr
ivate
DbUtils
dbUtils
;
pr
otected
DbUtils
dbUtils
;
private
MinervaLoggerAppender
appender
;
private
MinervaLoggerAppender
appender
;
private
ExecutorService
executorService
;
private
ExecutorService
executorService
;
...
...
web/src/test/java/lcsb/mapviewer/web/UserControllerIntegrationTestWithoutTransaction.java
View file @
b347fdd6
package
lcsb.mapviewer.web
;
package
lcsb.mapviewer.web
;
import
static
org
.
junit
.
Assert
.*;
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
.
post
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
import
java.util.
Arrays
;
import
java.util.
*
;
import
org.apache.commons.lang3.mutable.MutableBoolean
;
import
org.apache.http.client.entity.UrlEncodedFormEntity
;
import
org.apache.http.client.entity.UrlEncodedFormEntity
;
import
org.apache.http.message.BasicNameValuePair
;
import
org.apache.http.message.BasicNameValuePair
;
import
org.apache.http.util.EntityUtils
;
import
org.apache.http.util.EntityUtils
;
...
@@ -20,6 +23,8 @@ import org.springframework.test.annotation.Rollback;
...
@@ -20,6 +23,8 @@ import org.springframework.test.annotation.Rollback;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
;
import
org.springframework.test.web.servlet.RequestBuilder
;
import
org.springframework.test.web.servlet.RequestBuilder
;
import
lcsb.mapviewer.model.user.User
;
import
lcsb.mapviewer.model.user.UserGuiPreference
;
import
lcsb.mapviewer.services.interfaces.IUserService
;
import
lcsb.mapviewer.services.interfaces.IUserService
;
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
@RunWith
(
SpringJUnit4ClassRunner
.
class
)
...
@@ -28,8 +33,6 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
...
@@ -28,8 +33,6 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
private
static
final
String
TEST_USER_PASSWORD
=
"test_pass"
;
private
static
final
String
TEST_USER_PASSWORD
=
"test_pass"
;
private
static
final
String
TEST_USER_LOGIN
=
"test_user"
;
private
static
final
String
TEST_USER_LOGIN
=
"test_user"
;
private
static
final
String
ADMIN_PASSWORD
=
"admin"
;
private
static
final
String
ADMIN_LOGIN
=
"admin"
;
Logger
logger
=
LogManager
.
getLogger
();
Logger
logger
=
LogManager
.
getLogger
();
@Autowired
@Autowired
private
IUserService
userService
;
private
IUserService
userService
;
...
@@ -41,7 +44,7 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
...
@@ -41,7 +44,7 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
@Test
@Test
public
void
createUser
()
throws
Exception
{
public
void
createUser
()
throws
Exception
{
try
{
try
{
MockHttpSession
session
=
createSession
(
ADMIN_LOGIN
,
ADMIN_PASSWORD
);
MockHttpSession
session
=
createSession
(
BUILT_IN_TEST_ADMIN_LOGIN
,
BUILT_IN_TEST_
ADMIN_PASSWORD
);
String
body
=
EntityUtils
.
toString
(
new
UrlEncodedFormEntity
(
Arrays
.
asList
(
String
body
=
EntityUtils
.
toString
(
new
UrlEncodedFormEntity
(
Arrays
.
asList
(
new
BasicNameValuePair
(
"login"
,
TEST_USER_LOGIN
),
new
BasicNameValuePair
(
"login"
,
TEST_USER_LOGIN
),
...
@@ -60,4 +63,66 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
...
@@ -60,4 +63,66 @@ public class UserControllerIntegrationTestWithoutTransaction extends ControllerI
removeUserInSeparateThread
(
userService
.
getUserByLogin
(
TEST_USER_LOGIN
));
removeUserInSeparateThread
(
userService
.
getUserByLogin
(
TEST_USER_LOGIN
));
}
}
}
}
@Test
public
void
createGuiPreferencesTwice
()
throws
Exception
{
MockHttpSession
session
=
createSession
(
BUILT_IN_TEST_ADMIN_LOGIN
,
BUILT_IN_TEST_ADMIN_PASSWORD
);
try
{
createUserInSeparateThread
(
TEST_USER_LOGIN
,
TEST_USER_PASSWORD
);
callInSeparateThread
(()->{
RequestBuilder
request
=
patch
(
"/users/"
+
TEST_USER_LOGIN
+
":updatePreferences"
)
.
contentType
(
MediaType
.
APPLICATION_JSON
)
.
content
(
"{\"preferences\":{}}"
)
.
session
(
session
);
try
{
mockMvc
.
perform
(
request
)
.
andExpect
(
status
().
is2xxSuccessful
());
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
null
;
});
MutableBoolean
exceptionHappened
=
new
MutableBoolean
(
false
);
List
<
Thread
>
threads
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
String
body
=
"{\"preferences\":{\"gui-preferences\":{\"test\":\"val"
+
i
+
"\"}}}"
;
Thread
thread
=
new
Thread
(
new
Runnable
()
{
@Override
public
void
run
()
{
dbUtils
.
createSessionForCurrentThread
();
try
{
RequestBuilder
request
=
patch
(
"/users/"
+
TEST_USER_LOGIN
+
":updatePreferences"
)
.
contentType
(
MediaType
.
APPLICATION_JSON
)
.
content
(
body
)
.
session
(
session
);
int
status
=
mockMvc
.
perform
(
request
).
andReturn
().
getResponse
().
getStatus
();
assertNotEquals
(
500
,
status
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
exceptionHappened
.
setTrue
();
}
finally
{
dbUtils
.
closeSessionForCurrentThread
();
}
}
});
threads
.
add
(
thread
);
thread
.
start
();
}
for
(
Thread
thread
:
threads
)
{
thread
.
join
();
}
assertFalse
(
exceptionHappened
.
getValue
());
}
finally
{
removeUserInSeparateThread
(
userService
.
getUserByLogin
(
TEST_USER_LOGIN
));
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment