Commit 8a72ad86 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Implemented basic hook functionality

parent 3aac16a7
......@@ -28,6 +28,12 @@ The first super admin user must be added manually, then he/she will be able to a
The value `user_id` is the RAP user id.
## Hooks
It is possible to load external jar files in order to extend the GMS with custom functionalities (implementing the *Hook interfaces and annotating the class with `@org.springframework.stereotype.Component`). Currently only the `GroupsHook` is available.
External jar files need to be specified at application startup using the `LOADER_PATH` environment variable (this is a Spring feature).
## Developer notes
Backend and frontend are 2 separate applications:
......
......@@ -114,6 +114,26 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
<configuration>
<!-- creates a gms-lib jar that can be included as dependency in other projects -->
<classifier>lib</classifier>
<includes>
<include>**/**</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
......@@ -130,6 +150,8 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<!-- layout ZIP is necessary for loading external jar using PropertiesLauncher (used for hooks) -->
<layout>ZIP</layout>
</configuration>
</plugin>
<plugin>
......
......@@ -193,7 +193,7 @@ public class JWTWebServiceController {
@DeleteMapping(value = "/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE)
public void deleteGroup(@PathVariable("group") String groupParam, HttpServletResponse response) {
GroupEntity group = getGroupFromNames(extractGroupNames(groupParam));
groupsDAO.deleteGroupById(group.getId());
groupsDAO.deleteGroup(group);
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
......
......@@ -2,6 +2,7 @@ package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.model.GroupBreadcrumb;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.hook.GroupsHook;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
......@@ -21,6 +22,9 @@ import org.springframework.stereotype.Component;
@Component
public class GroupsDAO {
@Autowired(required = false)
protected GroupsHook groupsHook;
private final JdbcTemplate jdbcTemplate;
@Autowired
......@@ -30,6 +34,10 @@ public class GroupsDAO {
public GroupEntity createGroup(GroupEntity group) {
if (groupsHook != null) {
groupsHook.beforeCreate(group);
}
String sql = "INSERT INTO gms_group (id, name, path, is_leaf) VALUES (?, ?, ?, ?)";
jdbcTemplate.update(conn -> {
......@@ -46,6 +54,10 @@ public class GroupsDAO {
public GroupEntity updateGroup(GroupEntity group) {
if (groupsHook != null) {
groupsHook.beforeUpdate(group);
}
String sql = "UPDATE gms_group SET name = ?, path = ?, is_leaf = ? WHERE id = ?";
jdbcTemplate.update(conn -> {
......@@ -60,9 +72,14 @@ public class GroupsDAO {
return group;
}
public void deleteGroupById(String groupId) {
public void deleteGroup(GroupEntity group) {
if (groupsHook != null) {
groupsHook.beforeDelete(group);
}
String sql = "DELETE FROM gms_group WHERE id = ?";
jdbcTemplate.update(sql, groupId);
jdbcTemplate.update(sql, group.getId());
}
public Optional<GroupEntity> findGroupById(String groupId) {
......
......@@ -3,6 +3,7 @@ package it.inaf.ia2.gms.service;
import it.inaf.ia2.gms.persistence.GroupsDAO;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
......@@ -26,6 +27,10 @@ public class GroupNameService {
return getGroupsNames(groupsDAO.findGroupsByIds(groupIdentifiers));
}
public String getGroupCompleteName(GroupEntity group) {
return getGroupsNames(Collections.singletonList(group)).get(0);
}
/**
* Returns the list of the group complete names, given a list of GroupEntity
* objects.
......
......@@ -108,8 +108,8 @@ public class GroupsService {
membershipsDAO.deleteAllGroupsMembership(groupsToDeleteIds);
permissionsDAO.deleteAllGroupsPermissions(groupsToDeleteIds);
for (String groupId : groupsToDeleteIds) {
groupsDAO.deleteGroupById(groupId);
for (GroupEntity g : groupsToDelete) {
groupsDAO.deleteGroup(g);
}
loggingDAO.logAction("Group deleted, group_id=" + group.getId());
......
package it.inaf.ia2.gms.service.hook;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
public interface GroupsHook {
void beforeCreate(GroupEntity group);
void beforeUpdate(GroupEntity group);
void beforeDelete(GroupEntity group);
}
package it.inaf.ia2.gms;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.hook.GroupsHook;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HooksConfig {
@Bean
public GroupsHook groupsHook() {
return new GroupsHookTestImpl();
}
public static class GroupsHookTestImpl implements GroupsHook {
@Override
public void beforeCreate(GroupEntity group) {
}
@Override
public void beforeUpdate(GroupEntity group) {
}
@Override
public void beforeDelete(GroupEntity group) {
}
}
}
......@@ -151,7 +151,7 @@ public class JWTWebServiceControllerTest {
mockMvc.perform(delete("/ws/jwt/LBT.INAF"))
.andExpect(status().isNoContent());
verify(groupsDAO, times(1)).deleteGroupById(eq(inaf.getId()));
verify(groupsDAO, times(1)).deleteGroup(eq(inaf));
}
@Test
......
package it.inaf.ia2.gms.persistence;
import it.inaf.ia2.gms.DataSourceConfig;
import it.inaf.ia2.gms.HooksConfig;
import it.inaf.ia2.gms.model.GroupBreadcrumb;
import it.inaf.ia2.gms.persistence.model.GroupEntity;
import it.inaf.ia2.gms.service.hook.GroupsHook;
import java.util.List;
import java.util.Map;
import java.util.Optional;
......@@ -14,23 +16,32 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.mockito.internal.util.collections.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = DataSourceConfig.class)
@ContextConfiguration(classes = {DataSourceConfig.class, HooksConfig.class})
public class GroupsDAOTest {
@Autowired
private DataSource dataSource;
@Autowired
@SpyBean
private GroupsHook groupsHook;
private GroupsDAO dao;
@Before
public void setUp() {
dao = new GroupsDAO(dataSource);
dao.groupsHook = groupsHook;
}
@Test
......@@ -43,6 +54,8 @@ public class GroupsDAOTest {
root.setPath("");
dao.createGroup(root);
verify(groupsHook, times(1)).beforeCreate(eq(root));
GroupEntity lbt = new GroupEntity();
lbt.setId(getNewGroupId());
lbt.setName("LBT");
......@@ -118,6 +131,8 @@ public class GroupsDAOTest {
tng = dao.findGroupById(tng.getId()).get();
assertEquals(newName, tng.getName());
verify(groupsHook, times(1)).beforeUpdate(eq(tng));
// Breadcrumbs
List<GroupBreadcrumb> breadcrumbs = dao.getBreadcrumbs(lbt.getId() + "." + lbtInaf.getId());
assertEquals(3, breadcrumbs.size());
......@@ -126,9 +141,11 @@ public class GroupsDAOTest {
assertEquals(lbtInaf.getName(), breadcrumbs.get(2).getGroupName());
// Delete
dao.deleteGroupById(lbtInaf.getId());
dao.deleteGroup(lbtInaf);
groups = dao.getDirectSubGroups(lbt.getId());
assertTrue(groups.isEmpty());
verify(groupsHook, times(1)).beforeDelete(eq(lbtInaf));
}
private String getNewGroupId() {
......
Supports Markdown
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