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