Commit 7eb4bafc by Johannes Stelzer

Search applications by name

Rename ApplicationStore methods to spring-data-style
parent 90758940
......@@ -31,6 +31,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
import com.hazelcast.config.Config;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import de.codecentric.boot.admin.controller.RegistryController;
import de.codecentric.boot.admin.model.Application;
......@@ -111,7 +112,9 @@ public class WebappConfig extends WebMvcConfigurerAdapter {
@Bean
@ConditionalOnMissingBean
public ApplicationStore applicationStore(HazelcastInstance hazelcast) {
return new HazelcastApplicationStore(hazelcast.<String, Application> getMap(hazelcastMapName));
IMap<String, Application> map = hazelcast.<String, Application> getMap(hazelcastMapName);
map.addIndex("name", false);
return new HazelcastApplicationStore(map);
}
}
......
......@@ -15,7 +15,7 @@
*/
package de.codecentric.boot.admin.controller;
import java.util.List;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.codecentric.boot.admin.model.Application;
......@@ -96,14 +97,17 @@ public class RegistryController {
}
/**
* List all registered applications.
* List all registered applications with name
*
* @return List.
*/
@RequestMapping(value = "/api/applications", method = RequestMethod.GET)
public List<Application> applications() {
LOGGER.debug("Deliver all registered applications");
public Collection<Application> applications(@RequestParam(value = "name", required = false) String name) {
LOGGER.debug("Deliver registered applications with name= {}", name);
if (name == null || name.isEmpty()) {
return registry.getApplications();
} else {
return registry.getApplicationsByName(name);
}
}
}
......@@ -17,7 +17,7 @@ package de.codecentric.boot.admin.registry;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Collection;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
......@@ -55,7 +55,7 @@ public class ApplicationRegistry {
Validate.notNull(applicationId, "ID must not be null");
Application newApp = new Application(app.getUrl(), app.getName(), applicationId);
Application oldApp = store.put(newApp);
Application oldApp = store.save(newApp);
if (oldApp == null) {
LOGGER.info("New Application {} registered ", newApp);
......@@ -90,8 +90,17 @@ public class ApplicationRegistry {
*
* @return List.
*/
public List<Application> getApplications() {
return store.getAll();
public Collection<Application> getApplications() {
return store.findAll();
}
/**
* Get a list of all registered applications.
*
* @return List.
*/
public Collection<Application> getApplicationsByName(String name) {
return store.findByName(name);
}
/**
......@@ -101,7 +110,7 @@ public class ApplicationRegistry {
* @return Application.
*/
public Application getApplication(String id) {
return store.get(id);
return store.find(id);
}
/**
......@@ -111,7 +120,7 @@ public class ApplicationRegistry {
* @return the unregistered Application
*/
public Application unregister(String id) {
Application app = store.remove(id);
Application app = store.delete(id);
LOGGER.info("Application {} unregistered ", app);
return app;
}
......
......@@ -15,7 +15,7 @@
*/
package de.codecentric.boot.admin.registry;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import de.codecentric.boot.admin.model.Application;
......@@ -31,7 +31,7 @@ public class HashingApplicationUrlIdGenerator implements ApplicationIdGenerator
public String generateId(Application a) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] bytes = digest.digest(a.getUrl().getBytes(Charset.forName("UTF-8")));
byte[] bytes = digest.digest(a.getUrl().getBytes(StandardCharsets.UTF_8));
return new String(encodeHex(bytes, 0, 8));
} catch (Exception e) {
throw new IllegalStateException(e);
......
......@@ -15,7 +15,7 @@
*/
package de.codecentric.boot.admin.registry.store;
import java.util.List;
import java.util.Collection;
import de.codecentric.boot.admin.model.Application;
......@@ -30,22 +30,28 @@ public interface ApplicationStore {
* @param app Application to store
* @return the Application associated previosly with the applications id.
*/
Application put(Application app);
Application save(Application app);
/**
* @return all Applications in the store;
*/
List<Application> getAll();
Collection<Application> findAll();
/**
* @param id the applications id
* @return the Application with the specified id;
*/
Application get(String id);
Application find(String id);
/**
* @param name the applications name
* @return all Applications with the specified name;
*/
Collection<Application> findByName(String name);
/**
* @param id id of the Application to be removed
* @return the Application associated previosly with the applications id.
*/
Application remove(String id);
Application delete(String id);
}
package de.codecentric.boot.admin.registry.store;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import com.hazelcast.core.IMap;
import com.hazelcast.query.Predicates;
import de.codecentric.boot.admin.model.Application;
......@@ -16,22 +16,27 @@ public class HazelcastApplicationStore implements ApplicationStore {
}
@Override
public Application put(Application app) {
public Application save(Application app) {
return store.putIfAbsent(app.getId(), app);
}
@Override
public List<Application> getAll() {
return new ArrayList<Application>(store.values());
public Collection<Application> findAll() {
return store.values();
}
@Override
public Application get(String id) {
public Application find(String id) {
return store.get(id);
}
@Override
public Application remove(String id) {
public Collection<Application> findByName(String name) {
return store.values(Predicates.equal("name", name));
}
@Override
public Application delete(String id) {
return store.remove(id);
}
......
......@@ -16,6 +16,7 @@
package de.codecentric.boot.admin.registry.store;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
......@@ -29,22 +30,33 @@ public class SimpleApplicationStore implements ApplicationStore {
private final ConcurrentHashMap<String, Application> map = new ConcurrentHashMap<>();
@Override
public Application put(Application app) {
public Application save(Application app) {
return map.putIfAbsent(app.getId(), app);
}
@Override
public List<Application> getAll() {
return new ArrayList<Application>(map.values());
public Collection<Application> findAll() {
return map.values();
}
@Override
public Application get(String id) {
public Application find(String id) {
return map.get(id);
}
@Override
public Application remove(String id) {
public Collection<Application> findByName(String name) {
List<Application> result = new ArrayList<Application>();
for (Application a : map.values()) {
if (name.equals(a.getName())) {
result.add(a);
}
}
return result;
}
@Override
public Application delete(String id) {
return map.remove(id);
}
......
......@@ -16,14 +16,20 @@
package de.codecentric.boot.admin;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
......@@ -41,16 +47,22 @@ import de.codecentric.boot.admin.model.Application;
*/
public class AdminApplicationHazelcastTest {
@Configuration
@EnableAutoConfiguration
@EnableAdminServer
public static class TestAdminApplication {
}
private RestTemplate template = new TestRestTemplate();
private AnnotationConfigEmbeddedWebApplicationContext instance1;
private AnnotationConfigEmbeddedWebApplicationContext instance2;
private EmbeddedWebApplicationContext instance1;
private EmbeddedWebApplicationContext instance2;
@Before
public void setup() {
instance1 = (AnnotationConfigEmbeddedWebApplicationContext) SpringApplication.run(TestAdminApplication.class,
new String[] { "--server.port=0", "--spring.jmx.enabled=false" });
instance2 = (AnnotationConfigEmbeddedWebApplicationContext) SpringApplication.run(TestAdminApplication.class,
new String[] { "--server.port=0", "--spring.jmx.enabled=false" });
instance1 = (EmbeddedWebApplicationContext) SpringApplication.run(TestAdminApplication.class, new String[] {
"--server.port=0", "--spring.jmx.enabled=false" });
instance2 = (EmbeddedWebApplicationContext) SpringApplication.run(TestAdminApplication.class, new String[] {
"--server.port=0", "--spring.jmx.enabled=false" });
}
@After
......@@ -62,26 +74,58 @@ public class AdminApplicationHazelcastTest {
@Test
public void test() {
Application app = new Application("http://127.0.0.1", "Hazelcast Test");
Application app2 = new Application("http://127.0.0.1:2", "Hazelcast Test");
Application app3 = new Application("http://127.0.0.1:3", "Do not find");
// publish application on instance1
int port1 = instance1.getEmbeddedServletContainer().getPort();
ResponseEntity<Application> postResponse = template.postForEntity("http://localhost:" + port1
+ "/api/applications", app, Application.class);
// publish app on instance1
ResponseEntity<Application> postResponse = registerApp(app, instance1);
app = postResponse.getBody();
assertEquals(HttpStatus.CREATED, postResponse.getStatusCode());
assertNotNull(postResponse.getBody().getId());
assertNotNull(app.getId());
// retrieve application from instance2
int port2 = instance2.getEmbeddedServletContainer().getPort();
ResponseEntity<Application> getResponse = template.getForEntity("http://localhost:" + port2
+ "/api/application/" + postResponse.getBody().getId(), Application.class);
// publish app2 on instance2
ResponseEntity<Application> postResponse2 = registerApp(app2, instance2);
app2 = postResponse2.getBody();
assertEquals(HttpStatus.CREATED, postResponse.getStatusCode());
assertNotNull(app2.getId());
// retrieve app from instance2
ResponseEntity<Application> getResponse = getApp(app.getId(), instance2);
assertEquals(HttpStatus.OK, getResponse.getStatusCode());
assertEquals(postResponse.getBody(), getResponse.getBody());
assertEquals(app, getResponse.getBody());
// retrieve app and app2 from instance1 (but not app3)
app3 = registerApp(app3, instance1).getBody();
Collection<Application> apps = getAppByName("Hazelcast Test", instance1).getBody();
assertEquals(2, apps.size());
assertTrue(apps.contains(app));
assertTrue(apps.contains(app2));
assertFalse(apps.contains(app3));
}
@Configuration
@EnableAutoConfiguration
@EnableAdminServer
public static class TestAdminApplication {
private ResponseEntity<Application> getApp(String id, EmbeddedWebApplicationContext context) {
int port = context.getEmbeddedServletContainer().getPort();
ResponseEntity<Application> getResponse = template.getForEntity("http://localhost:" + port
+ "/api/application/" + id, Application.class);
return getResponse;
}
private ResponseEntity<Application> registerApp(Application app, EmbeddedWebApplicationContext context) {
int port = context.getEmbeddedServletContainer().getPort();
return template.postForEntity("http://localhost:" + port + "/api/applications", app, Application.class);
}
@SuppressWarnings("unchecked")
private ResponseEntity<Collection<Application>> getAppByName(String name, EmbeddedWebApplicationContext context) {
int port = context.getEmbeddedServletContainer().getPort();
ResponseEntity<?> getResponse = template.getForEntity("http://localhost:" + port
+ "/api/applications?name={name}", ApplicationList.class, Collections.singletonMap("name", name));
return (ResponseEntity<Collection<Application>>) getResponse;
}
public static class ApplicationList extends ArrayList<Application> {
private static final long serialVersionUID = 1L;
// needed for JSON deserialization
}
}
......@@ -45,7 +45,7 @@ import de.codecentric.boot.admin.config.EnableAdminServer;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestAdminApplication.class)
@WebAppConfiguration
@IntegrationTest({ "server.port=0", "spring.boot.admin.hazelcast.enable=false" })
@IntegrationTest({ "server.port=0" })
public class AdminApplicationTest {
RestTemplate restTemplate = new TestRestTemplate();
......
......@@ -16,8 +16,10 @@
package de.codecentric.boot.admin.controller;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.List;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
......@@ -107,12 +109,26 @@ public class RegistryControllerTest {
@Test
public void applications() {
Application app = new Application("http://localhost", "FOO");
controller.register(app);
app = controller.register(app).getBody();
List<Application> applications = controller.applications();
Collection<Application> applications = controller.applications(null);
assertEquals(1, applications.size());
assertTrue(applications.contains(app));
}
assertEquals(app.getName(), applications.get(0).getName());
assertEquals(app.getUrl(), applications.get(0).getUrl());
@Test
public void applicationsByName() {
Application app = new Application("http://localhost:2", "FOO");
app = controller.register(app).getBody();
Application app2 = new Application("http://localhost:1", "FOO");
app2 = controller.register(app2).getBody();
Application app3 = new Application("http://localhost:3", "BAR");
controller.register(app3).getBody();
Collection<Application> applications = controller.applications("FOO");
assertEquals(2, applications.size());
assertTrue(applications.contains(app));
assertTrue(applications.contains(app2));
assertFalse(applications.contains(app3));
}
}
......@@ -16,13 +16,15 @@
package de.codecentric.boot.admin.registry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import org.junit.Test;
import de.codecentric.boot.admin.model.Application;
import de.codecentric.boot.admin.registry.ApplicationRegistry;
import de.codecentric.boot.admin.registry.HashingApplicationUrlIdGenerator;
import de.codecentric.boot.admin.registry.store.SimpleApplicationStore;
public class ApplicationRegistryTest {
......@@ -70,8 +72,24 @@ public class ApplicationRegistryTest {
Application app = new Application("http://localhost:8080", "abc");
app = registry.register(app);
assertEquals(1, registry.getApplications().size());
assertEquals("http://localhost:8080", registry.getApplications().get(0).getUrl());
assertEquals("abc", registry.getApplications().get(0).getName());
Collection<Application> applications = registry.getApplications();
assertEquals(1, applications.size());
assertTrue(applications.contains(app));
}
@Test
public void getApplicationsByName() throws Exception {
Application app = new Application("http://localhost:8080", "abc");
app = registry.register(app);
Application app2 = new Application("http://localhost:8081", "abc");
app2 = registry.register(app2);
Application app3 = new Application("http://localhost:8082", "cba");
app3 = registry.register(app3);
Collection<Application> applications = registry.getApplicationsByName("abc");
assertEquals(2, applications.size());
assertTrue(applications.contains(app));
assertTrue(applications.contains(app2));
assertFalse(applications.contains(app3));
}
}
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