You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2017/10/09 03:26:38 UTC

[2/2] logging-log4j-audit git commit: Interim work on dynamic catalog

Interim work on dynamic catalog


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/commit/1deb7eba
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/tree/1deb7eba
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/diff/1deb7eba

Branch: refs/heads/master
Commit: 1deb7ebaf47a99677ccb4ef3a5cfb80ae01423f6
Parents: d5b3c5b
Author: Ralph Goers <rg...@nextiva.com>
Authored: Sun Oct 8 20:26:29 2017 -0700
Committer: Ralph Goers <rg...@nextiva.com>
Committed: Sun Oct 8 20:26:29 2017 -0700

----------------------------------------------------------------------
 .../log4j/audit/catalog/CatalogManagerImpl.java |  10 +-
 .../audit/catalog/StringCatalogReader.java      |   9 +
 log4j-audit/log4j-audit-war/pom.xml             |   4 +
 .../service/catalog/AuditCatalogManager.java    | 156 ++++++++++++
 .../audit/service/config/WebMvcAppContext.java  |   6 +-
 .../service/controller/CatalogController.java   | 119 +++++++--
 .../src/main/resources/log4j2.xml               |   6 +-
 .../log4j/audit/service/CatalogTest.java        |  68 +++++
 .../src/test/resources/catalog.json             | 193 ++++++++++++++
 .../src/test/resources/log4j2-test.xml          |  80 ++++++
 .../src/test/resources/sql/afterTestRun.sql     |  24 ++
 .../test/resources/sql/beforeTestRun.sql.sav    |  64 +++++
 .../src/test/resources/sql/schema.sql           | 135 ++++++++++
 .../log4j/catalog/api/CatalogReader.java        |   7 +
 .../catalog/api/dao/ClassPathCatalogReader.java |  19 ++
 .../catalog/api/dao/FileCatalogReader.java      |  15 +-
 .../catalog/api/dao/JsonCatalogReader.java      |   7 +
 .../catalog/api/service/CatalogService.java     |  26 --
 .../log4j/catalog/git/dao/GitCatalogDao.java    |  12 +
 .../jpa/config/ApplicationConfiguration.java    |  34 ---
 .../catalog/jpa/dao/CatalogRepository.java      |  22 ++
 .../log4j/catalog/jpa/model/CatalogModel.java   |  53 ++++
 .../catalog/jpa/service/CatalogService.java     |  31 +++
 .../catalog/jpa/service/CatalogServiceImpl.java |  20 +-
 .../jpa/service/ConfigurationService.java       |  31 ---
 .../src/main/resources/sql/schema.sql           | 121 ---------
 .../logging/log4j/catalog/jpa/CatalogTest.java  |   2 +-
 .../jpa/config/ApplicationConfiguration.java    |  34 +++
 .../src/test/resources/sql/schema.sql           | 121 +++++++++
 log4j-catalog/log4j-catalog-war/pom.xml         |   4 +
 .../catalog/config/ConfigurationService.java    |  31 +++
 .../log4j/catalog/config/WebMvcAppContext.java  |   1 -
 .../catalog/controller/CatalogController.java   | 251 -------------------
 .../src/main/resources/sql/schema.sql           | 121 +++++++++
 pom.xml                                         |   6 +-
 35 files changed, 1348 insertions(+), 495 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java b/log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java
index f5ce826..4fbf50e 100644
--- a/log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java
+++ b/log4j-audit/log4j-audit-api/src/main/java/org/apache/logging/log4j/audit/catalog/CatalogManagerImpl.java
@@ -50,6 +50,8 @@ public class CatalogManagerImpl implements CatalogManager {
 
     private static final String REQCTX = "ReqCtx_";
 
+    protected CatalogData catalogData;
+
     public CatalogManagerImpl(CatalogReader catalogReader) {
         try {
             infoMap = initializeData(catalogReader);
@@ -94,15 +96,15 @@ public class CatalogManagerImpl implements CatalogManager {
         JsonFactory factory = new JsonFactory();
         factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
         ObjectMapper mapper = new ObjectMapper(factory);
-        CatalogData data = mapper.readValue(catalog, CatalogData.class);
-        for (Attribute attr : data.getAttributes()) {
+        catalogData = mapper.readValue(catalog, CatalogData.class);
+        for (Attribute attr : catalogData.getAttributes()) {
             if (attr.isRequestContext()) {
                 requestContextAttributes.put(attr.getName(), attr);
             }
             attributeMap.put(attr.getName(), attr);
         }
-        Map<String, CatalogInfo> map = new HashMap<>(data.getEvents().size());
-        for (Event event : data.getEvents()) {
+        Map<String, CatalogInfo> map = new HashMap<>(catalogData.getEvents().size());
+        for (Event event : catalogData.getEvents()) {
             CatalogInfo info = new CatalogInfo();
             info.event = event;
             List<String> required = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-api/src/test/java/org/apache/logging/log4j/audit/catalog/StringCatalogReader.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-api/src/test/java/org/apache/logging/log4j/audit/catalog/StringCatalogReader.java b/log4j-audit/log4j-audit-api/src/test/java/org/apache/logging/log4j/audit/catalog/StringCatalogReader.java
index db027bf..cb45645 100644
--- a/log4j-audit/log4j-audit-api/src/test/java/org/apache/logging/log4j/audit/catalog/StringCatalogReader.java
+++ b/log4j-audit/log4j-audit-api/src/test/java/org/apache/logging/log4j/audit/catalog/StringCatalogReader.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.audit.catalog;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.PrintStream;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -52,6 +53,8 @@ public class StringCatalogReader implements CatalogReader {
 
     private final Map<String, Attribute> attributeMap = new HashMap<>();
 
+    private final LocalDateTime lastUpdated;
+
     public StringCatalogReader() throws Exception {
         JsonFactory factory = new JsonFactory();
         factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
@@ -63,6 +66,7 @@ public class StringCatalogReader implements CatalogReader {
         PrintStream ps = new PrintStream(new FileOutputStream(file));
         ps.print(json);
         ps.close();
+        lastUpdated = LocalDateTime.now();
     }
 
     @Override
@@ -112,6 +116,11 @@ public class StringCatalogReader implements CatalogReader {
         return null;
     }
 
+    @Override
+    public LocalDateTime getLastUpdated() {
+        return lastUpdated;
+    }
+
     private CatalogData createCatalogData() {
         CatalogData catalogData = new CatalogData();
         List<Product> products = new ArrayList<>();

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/pom.xml b/log4j-audit/log4j-audit-war/pom.xml
index 5eff84f..ab31010 100644
--- a/log4j-audit/log4j-audit-war/pom.xml
+++ b/log4j-audit/log4j-audit-war/pom.xml
@@ -107,6 +107,10 @@
 			<groupId>org.apache.logging.log4j</groupId>
 			<artifactId>log4j-core</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-jcl</artifactId>
+		</dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-slf4j-impl</artifactId>

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java
new file mode 100644
index 0000000..6e11f97
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/catalog/AuditCatalogManager.java
@@ -0,0 +1,156 @@
+package org.apache.logging.log4j.audit.service.catalog;
+
+import javax.annotation.PostConstruct;
+import java.sql.Timestamp;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.audit.catalog.CatalogManagerImpl;
+import org.apache.logging.log4j.catalog.api.Attribute;
+import org.apache.logging.log4j.catalog.api.CatalogReader;
+import org.apache.logging.log4j.catalog.api.Category;
+import org.apache.logging.log4j.catalog.api.Event;
+import org.apache.logging.log4j.catalog.api.Product;
+import org.apache.logging.log4j.catalog.api.dao.CatalogDao;
+import org.apache.logging.log4j.catalog.jpa.model.CatalogModel;
+import org.apache.logging.log4j.catalog.jpa.service.CatalogService;
+import org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter;
+import org.apache.logging.log4j.catalog.jpa.converter.CategoryConverter;
+import org.apache.logging.log4j.catalog.jpa.converter.EventConverter;
+import org.apache.logging.log4j.catalog.jpa.converter.ProductConverter;
+import org.apache.logging.log4j.catalog.jpa.model.AttributeModel;
+import org.apache.logging.log4j.catalog.jpa.model.CategoryModel;
+import org.apache.logging.log4j.catalog.jpa.model.EventModel;
+import org.apache.logging.log4j.catalog.jpa.model.ProductModel;
+import org.apache.logging.log4j.catalog.jpa.service.AttributeService;
+import org.apache.logging.log4j.catalog.jpa.service.CategoryService;
+import org.apache.logging.log4j.catalog.jpa.service.EventService;
+import org.apache.logging.log4j.catalog.jpa.service.ProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class AuditCatalogManager extends CatalogManagerImpl {
+
+    private static Logger logger = LogManager.getLogger();
+
+    @Autowired
+    private CatalogService catalogService;
+
+    @Autowired
+    AttributeService attributeService;
+
+    @Autowired
+    EventService eventService;
+
+    @Autowired
+    CategoryService categoryService;
+
+    @Autowired
+    ProductService productService;
+
+    @Autowired
+    CatalogDao catalogDao;
+
+    @Autowired
+    AttributeConverter attributeConverter;
+
+    @Autowired
+    EventConverter eventConverter;
+
+    @Autowired
+    CategoryConverter categoryConverter;
+
+    @Autowired
+    ProductConverter productConverter;
+
+    private final CatalogReader catalogReader;
+
+
+    public AuditCatalogManager(CatalogReader catalogReader) {
+        super(catalogReader);
+        this.catalogReader = catalogReader;
+    }
+
+    @PostConstruct
+    public void initialize() {
+        CatalogModel catalogModel = catalogService.getCatalogModel();
+        if (catalogModel == null) {
+            catalogModel = new CatalogModel();
+            initialize(catalogModel);
+        } else if (catalogModel.getLastUpdate().toLocalDateTime().isBefore(catalogReader.getLastUpdated())) {
+            initialize(catalogModel);
+        }
+    }
+
+    private void initialize(CatalogModel catalogModel) {
+        logger.debug("Updating static catalog");
+
+        logger.debug("Loading attributes");
+        List<AttributeModel> attributeModels = new ArrayList<>();
+        Map<String, Attribute> attributeMap = new HashMap<>();
+        for (Attribute attribute : catalogData.getAttributes()) {
+            AttributeModel model = attributeConverter.convert(attribute);
+            attributeService.saveAttribute(model);
+            attributeModels.add(model);
+            attributeMap.put(attribute.getName(), attribute);
+        }
+        attributeModels.stream().filter(m->!attributeMap.containsKey(m.getName()));
+        for (AttributeModel attributeModel : attributeModels) {
+            if (!attributeMap.containsKey(attributeModel.getName())) {
+                attributeService.deleteAttribute(attributeModel.getId());
+            }
+        }
+        eventConverter.setAttributes(attributeModels);
+        Map<String, Event> eventMap = new HashMap<>();
+        List<EventModel> eventModels = new ArrayList<>();
+        logger.debug("Loading events");
+        for (Event event : catalogData.getEvents()) {
+            logger.debug("Processing Event: {}", event);
+            EventModel model = eventConverter.convert(event);
+            eventMap.put(event.getName(), event);
+            eventModels.add(model);
+            eventService.saveEvent(model);
+        }
+        for (EventModel eventModel : eventModels) {
+            if (!eventMap.containsKey(eventModel.getName())) {
+                eventService.deleteEvent(eventModel.getId());
+            }
+        }
+        List<CategoryModel> categoryModels = new ArrayList<>();
+        Map<String, Category> categoryMap = new HashMap<>();
+        logger.debug("Loading categories");
+        for (Category category : catalogData.getCategories()) {
+            CategoryModel model = categoryConverter.convert(category);
+            categoryModels.add(model);
+            categoryMap.put(category.getName(), category);
+            categoryService.saveCategory(model);
+        }
+        for (CategoryModel categoryModel : categoryModels) {
+            if (!categoryMap.containsKey(categoryModel.getName())) {
+                categoryService.deleteCategory(categoryModel.getId());
+            }
+        }
+        List<ProductModel> productModels = new ArrayList<>();
+        Map<String, Product> productMap = new HashMap<>();
+        logger.debug("loading products");
+        for (Product product : catalogData.getProducts()) {
+            ProductModel model = productConverter.convert(product);
+            productModels.add(model);
+            productMap.put(product.getName(), product);
+            productService.saveProduct(model);
+        }
+        for (ProductModel productModel : productModels) {
+            if (!productMap.containsKey(productModel.getName())) {
+                productService.deleteProduct(productModel.getId());
+            }
+        }
+
+        catalogModel.setLastUpdate(Timestamp.from(Instant.now()));
+        catalogService.saveCatalog(catalogModel);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/config/WebMvcAppContext.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/config/WebMvcAppContext.java b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/config/WebMvcAppContext.java
index a5c9e1c..332b744 100644
--- a/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/config/WebMvcAppContext.java
+++ b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/config/WebMvcAppContext.java
@@ -26,7 +26,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.audit.AuditLogger;
 import org.apache.logging.log4j.audit.catalog.CatalogManager;
-import org.apache.logging.log4j.audit.catalog.CatalogManagerImpl;
+import org.apache.logging.log4j.audit.service.catalog.AuditCatalogManager;
 import org.apache.logging.log4j.audit.service.security.LocalAuthorizationInterceptor;
 import org.apache.logging.log4j.audit.util.JsonObjectMapperFactory;
 import org.apache.logging.log4j.catalog.api.dao.CatalogDao;
@@ -60,7 +60,7 @@ import org.springframework.web.servlet.view.JstlView;
 @Configuration
 @EnableWebMvc
 @EnableScheduling
-@ComponentScan(basePackages = {"org.apache.logging.log4j.audit.service"})
+@ComponentScan(basePackages = {"org.apache.logging.log4j.catalog.jpa", "org.apache.logging.log4j.audit.service"})
 //@ImportResource("classpath*:propertySources.xml")
 public class WebMvcAppContext extends WebMvcConfigurerAdapter {
 
@@ -163,7 +163,7 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter {
 
     @Bean
     public CatalogManager catalogManager() {
-        return new CatalogManagerImpl(catalogReader());
+        return new AuditCatalogManager(catalogReader());
     }
 
     @Bean

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/controller/CatalogController.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/controller/CatalogController.java b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/controller/CatalogController.java
index cc7dfe9..48251be 100644
--- a/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/controller/CatalogController.java
+++ b/log4j-audit/log4j-audit-war/src/main/java/org/apache/logging/log4j/audit/service/controller/CatalogController.java
@@ -106,7 +106,7 @@ public class CatalogController {
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
-    @ApiOperation(value = "Create a catalog Attribute", notes = "Creates a catalog attribute", tags = {"Catalog"})
+    @ApiOperation(value = "List catalog Attributes", notes = "List catalog attributes for a catalog id", tags = {"Catalog"})
     @GetMapping(value = "{catalogId}/attributes")
     public ResponseEntity<List<Attribute>> getAttributes(@ApiParam(value = "catalog id", required = true) @PathVariable String catalogId,
                                                          @RequestParam(value = "startIndex", required = false) Integer startIndex,
@@ -144,7 +144,7 @@ public class CatalogController {
         Optional<AttributeModel> optional = attributeService.getAttribute(catalogId, name);
         if (!optional.isPresent()) {
             LOGGER.warn("Unable to locate attribute {} in catalog {}", name, catalogId);
-            return new ResponseEntity(HttpStatus.NOT_FOUND);
+            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
         }
         Attribute attribute = attributeModelConverter.convert(optional.get());
         return new ResponseEntity<>(attribute, HttpStatus.OK);
@@ -164,7 +164,7 @@ public class CatalogController {
         }
         AttributeModel model = attributeConverter.convert(attribute);
         model = attributeService.saveAttribute(model);
-        return new ResponseEntity(attributeModelConverter.convert(model), HttpStatus.CREATED);
+        return new ResponseEntity<>(attributeModelConverter.convert(model), HttpStatus.CREATED);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -182,7 +182,7 @@ public class CatalogController {
         }
         AttributeModel model = attributeConverter.convert(attribute);
         model = attributeService.saveAttribute(model);
-        return new ResponseEntity(attributeModelConverter.convert(model), HttpStatus.OK);
+        return new ResponseEntity<>(attributeModelConverter.convert(model), HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -190,13 +190,43 @@ public class CatalogController {
     @DeleteMapping(value = "/attribute/{id}")
     public ResponseEntity<?> deleteAttribute(@RequestParam("id") Long attributeId) {
         attributeService.deleteAttribute(attributeId);
-        return new ResponseEntity(HttpStatus.OK);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+    @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
+    @ApiOperation(value = "List catalog Events", notes = "Lists catalog events for a catalog id", tags = {"Catalog"})
+    @GetMapping(value = "{catalogId}/events")
+    public ResponseEntity<List<Event>> getEvents(@ApiParam(value = "catalog id", required = true) @PathVariable String catalogId,
+                                                         @RequestParam(value = "startIndex", required = false) Integer startIndex,
+                                                         @RequestParam(value = "pageSize", required = false) Integer pageSize,
+                                                         @RequestParam(value = "sortCol", required= false) String sortColumn,
+                                                         @RequestParam(value = "sortDir", required = false) String sortDirection) {
+        Type listType = new TypeToken<List<Event>>() {}.getType();
+        List<Event> events = null;
+        if (startIndex == null || pageSize == null) {
+            events = eventModelMapper.map(eventService.getEvents(catalogId), listType);
+        } else {
+            sortDirection = validateSortDirection(sortDirection);
+            if (sortColumn == null || sortColumn.length() == 0) {
+                sortColumn = "name";
+            }
+            int startPage = 0;
+            if (startIndex > 0) {
+                startPage = startIndex / pageSize;
+            }
+            events = eventModelMapper.map(eventService.getEvents(startPage, pageSize, sortColumn,
+                    sortDirection), listType);
+        }
+        if (events == null) {
+            events = new ArrayList<>();
+        }
+        return new ResponseEntity<>(events, HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
     @ApiOperation(value = "Create a catalog Event", notes = "Creates a catalog event", tags = {"Catalog"})
     @PostMapping(value = "/event", consumes=Versions.V1_0_VALUE, produces=Versions.V1_0_VALUE)
-    public ResponseEntity<Attribute> createEvent(@ApiParam(value = "event", required = true) @RequestBody Event event) {
+    public ResponseEntity<Event> createEvent(@ApiParam(value = "event", required = true) @RequestBody Event event) {
         if (event.getCatalogId() == null) {
             throw new IllegalArgumentException("A catalog id is required to create an event.");
         }
@@ -205,7 +235,7 @@ public class CatalogController {
         }
         EventModel model = eventConverter.convert(event);
         model = eventService.saveEvent(model);
-        return new ResponseEntity(eventModelConverter.convert(model), HttpStatus.CREATED);
+        return new ResponseEntity<>(eventModelConverter.convert(model), HttpStatus.CREATED);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -220,7 +250,7 @@ public class CatalogController {
         }
         EventModel model = eventConverter.convert(event);
         model = eventService.saveEvent(model);
-        return new ResponseEntity(eventModelConverter.convert(model), HttpStatus.OK);
+        return new ResponseEntity<>(eventModelConverter.convert(model), HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -228,7 +258,37 @@ public class CatalogController {
     @DeleteMapping(value = "/event/{id}")
     public ResponseEntity<?> deleteEvent(@RequestParam("id") Long eventId) {
         eventService.deleteEvent(eventId);
-        return new ResponseEntity(HttpStatus.OK);
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+    @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
+    @ApiOperation(value = "List catalog Products", notes = "Lists catalog products for a catalog id", tags = {"Catalog"})
+    @GetMapping(value = "{catalogId}/products")
+    public ResponseEntity<List<Product>> getProducts(@ApiParam(value = "catalog id", required = true) @PathVariable String catalogId,
+                                                 @RequestParam(value = "startIndex", required = false) Integer startIndex,
+                                                 @RequestParam(value = "pageSize", required = false) Integer pageSize,
+                                                 @RequestParam(value = "sortCol", required= false) String sortColumn,
+                                                 @RequestParam(value = "sortDir", required = false) String sortDirection) {
+        Type listType = new TypeToken<List<Product>>() {}.getType();
+        List<Product> products = null;
+        if (startIndex == null || pageSize == null) {
+            products = productModelMapper.map(productService.getProducts(catalogId), listType);
+        } else {
+            sortDirection = validateSortDirection(sortDirection);
+            if (sortColumn == null || sortColumn.length() == 0) {
+                sortColumn = "name";
+            }
+            int startPage = 0;
+            if (startIndex > 0) {
+                startPage = startIndex / pageSize;
+            }
+            products = productModelMapper.map(productService.getProducts(startPage, pageSize, sortColumn,
+                    sortDirection), listType);
+        }
+        if (products == null) {
+            products = new ArrayList<>();
+        }
+        return new ResponseEntity<>(products, HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -243,7 +303,7 @@ public class CatalogController {
         }
         ProductModel model = productConverter.convert(product);
         model = productService.saveProduct(model);
-        return new ResponseEntity(productModelConverter.convert(model), HttpStatus.CREATED);
+        return new ResponseEntity<>(productModelConverter.convert(model), HttpStatus.CREATED);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -258,7 +318,7 @@ public class CatalogController {
         }
         ProductModel model = productConverter.convert(product);
         model = productService.saveProduct(model);
-        return new ResponseEntity(productModelConverter.convert(model), HttpStatus.OK);
+        return new ResponseEntity<>(productModelConverter.convert(model), HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -266,9 +326,38 @@ public class CatalogController {
     @DeleteMapping(value = "/product/{id}")
     public ResponseEntity<?> deleteProduct(@RequestParam("id") Long productId) {
         productService.deleteProduct(productId);
-        return new ResponseEntity(HttpStatus.OK);
+        return new ResponseEntity<>(HttpStatus.OK);
     }
 
+    @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
+    @ApiOperation(value = "List catalog Categories", notes = "Lists catalog categories for a catalog id", tags = {"Catalog"})
+    @GetMapping(value = "{catalogId}/categories")
+    public ResponseEntity<List<Category>> getCategories(@ApiParam(value = "catalog id", required = true) @PathVariable String catalogId,
+                                                     @RequestParam(value = "startIndex", required = false) Integer startIndex,
+                                                     @RequestParam(value = "pageSize", required = false) Integer pageSize,
+                                                     @RequestParam(value = "sortCol", required= false) String sortColumn,
+                                                     @RequestParam(value = "sortDir", required = false) String sortDirection) {
+        Type listType = new TypeToken<List<Category>>() {}.getType();
+        List<Category> categories = null;
+        if (startIndex == null || pageSize == null) {
+            categories = categoryModelMapper.map(categoryService.getCategories(catalogId), listType);
+        } else {
+            sortDirection = validateSortDirection(sortDirection);
+            if (sortColumn == null || sortColumn.length() == 0) {
+                sortColumn = "name";
+            }
+            int startPage = 0;
+            if (startIndex > 0) {
+                startPage = startIndex / pageSize;
+            }
+            categories = categoryModelMapper.map(categoryService.getCategories(startPage, pageSize, sortColumn,
+                    sortDirection), listType);
+        }
+        if (categories == null) {
+            categories = new ArrayList<>();
+        }
+        return new ResponseEntity<>(categories, HttpStatus.OK);
+    }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
     @ApiOperation(value = "Create a catalog Category", notes = "Creates a catalog category", tags = {"Catalog"})
@@ -282,7 +371,7 @@ public class CatalogController {
         }
         CategoryModel model = categoryConverter.convert(category);
         model = categoryService.saveCategory(model);
-        return new ResponseEntity(categoryModelConverter.convert(model), HttpStatus.CREATED);
+        return new ResponseEntity<>(categoryModelConverter.convert(model), HttpStatus.CREATED);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -297,7 +386,7 @@ public class CatalogController {
         }
         CategoryModel model = categoryConverter.convert(category);
         model = categoryService.saveCategory(model);
-        return new ResponseEntity(categoryModelConverter.convert(model), HttpStatus.OK);
+        return new ResponseEntity<>(categoryModelConverter.convert(model), HttpStatus.OK);
     }
 
     @ApiImplicitParams( {@ApiImplicitParam(dataType = "String", name = "Authorization", paramType = "header")})
@@ -305,7 +394,7 @@ public class CatalogController {
     @DeleteMapping(value = "/category/{id}")
     public ResponseEntity<?> deleteCategory(@RequestParam("id") Long categoryId) {
         categoryService.deleteCategory(categoryId);
-        return new ResponseEntity(HttpStatus.OK);
+        return new ResponseEntity<>(HttpStatus.OK);
     }
 
     private String validateSortDirection(String sortDirection) {

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/main/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/main/resources/log4j2.xml b/log4j-audit/log4j-audit-war/src/main/resources/log4j2.xml
index 5abe300..4ac45e4 100644
--- a/log4j-audit/log4j-audit-war/src/main/resources/log4j2.xml
+++ b/log4j-audit/log4j-audit-war/src/main/resources/log4j2.xml
@@ -20,7 +20,7 @@
         <property name="LOG_DIR">${sys:catalina.home}/logs/AuditService</property>
     </properties>
     <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
-    <MarkerFilter marker="Audit" omMatch="ACCEPT" onMisMatch="NEUTRAL"/>
+    <MarkerFilter marker="Audit" onMatch="ACCEPT" onMisMatch="NEUTRAL"/>
     <Appenders>
         <Console name="Console" target="SYSTEM_OUT">
             <PatternLayout pattern="%d{ABSOLUTE} %-5level # %class.%method %m%n" />
@@ -70,10 +70,10 @@
         <Logger name="org.apache.logging.log4j.audit" level="info" additivity="false">
             <AppenderRef ref="log4j"/>
         </Logger>
-        <Logger name="AuditLogger" level="trace" additivty="false">
+        <Logger name="AuditLogger" level="trace" additivity="false">
             <AppenderRef ref="audit"/>
         </Logger>
-        <Root level="warn">
+        <Root level="DEBUG">
             <AppenderRef ref="log4j" />
         </Root>
     </Loggers>

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/java/org/apache/logging/log4j/audit/service/CatalogTest.java
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/java/org/apache/logging/log4j/audit/service/CatalogTest.java b/log4j-audit/log4j-audit-war/src/test/java/org/apache/logging/log4j/audit/service/CatalogTest.java
new file mode 100644
index 0000000..4902aba
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/java/org/apache/logging/log4j/audit/service/CatalogTest.java
@@ -0,0 +1,68 @@
+package org.apache.logging.log4j.audit.service;
+
+import java.util.List;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.CollectionType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import org.apache.logging.log4j.audit.service.config.WebMvcAppContext;
+import org.apache.logging.log4j.catalog.api.Attribute;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import static org.junit.Assert.*;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {WebMvcAppContext.class}, loader=AnnotationConfigWebContextLoader.class)
+@WebAppConfiguration
+public class CatalogTest {
+
+    private MockMvc mockMvc;
+
+    @Autowired
+    private WebApplicationContext wac;
+
+    @Before
+    public void setUp() {
+        mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
+    }
+
+    @Test
+    public void testCreationOfANewProjectSucceeds() throws Exception {
+
+        String result = mockMvc.perform(
+                get("/catalog/TEST/attributes")
+                        .accept(Versions.V1_0))
+                .andExpect(status().is(HttpStatus.OK.value()))
+                .andReturn().getResponse().getContentAsString();
+        assertNotNull("No result returned for TEST catalog", result);
+        ObjectMapper objectMapper = new ObjectMapper();
+        CollectionType typeReference =
+                TypeFactory.defaultInstance().constructCollectionType(List.class, Attribute.class);
+        List<Attribute> attributes = objectMapper.readValue(result, typeReference);
+        assertNotNull("Result is not a list", attributes);
+        assertEquals("Incorrect number of attributes in list", 0, attributes.size());
+        result = mockMvc.perform(
+                get("/catalog/DEFAULT/attributes")
+                .accept(Versions.V1_0))
+                .andExpect(status().is(HttpStatus.OK.value()))
+                .andReturn().getResponse().getContentAsString();
+        assertNotNull("No result returned for DEFAULT catalog", result);
+
+        attributes = objectMapper.readValue(result, typeReference);
+        assertNotNull("Result is not a list", attributes);
+        assertEquals("Incorrect number of attributes in list", 10, attributes.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/resources/catalog.json
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/resources/catalog.json b/log4j-audit/log4j-audit-war/src/test/resources/catalog.json
new file mode 100644
index 0000000..2bee559
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/resources/catalog.json
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+{
+  "products" : [ {
+    "name" : "banking",
+    "displayName" : "Banking",
+    "description" : "Fictional banking product",
+    "events" : [ "login", "transfer", "deposit", "billPay" ]
+  } ],
+  "categories" : [ {
+    "name" : "account",
+    "displayName" : "Account",
+    "description" : "Events related to accounts",
+    "events" : [ "transfer", "deposit" ]
+  }, {
+    "name" : "billPay",
+    "displayName" : "Bill Pay",
+    "description" : "Events related to bill payment",
+    "events" : [ "billPay" ]
+  } ],
+  "events" : [ {
+    "name" : "login",
+    "displayName" : "Login",
+    "description" : "User Login",
+    "aliases" : null,
+    "attributes" : null
+  }, {
+    "name" : "transfer",
+    "displayName" : "Transfer",
+    "description" : "Transfer between accounts",
+    "aliases" : null,
+    "attributes" : [ {"name" : "toAccount", "required" : true}, {"name" : "fromAccount", "required" : true},
+      {"name" :"amount", "required" : true} ]
+  }, {
+    "name" : "deposit",
+    "displayName" : "Deposit",
+    "description" : "Deposit funds",
+    "aliases" : null,
+    "attributes" : [ {"name" : "account", "required" : true}, {"name" : "amount", "required" : true} ]
+  }, {
+    "name" : "billPay",
+    "displayName" : "Bill Pay",
+    "description" : "Payment of a bill",
+    "aliases" : null,
+    "attributes" : [ {"name" : "fromAccount", "required" : true}, {"name" : "payee", "required" : true},
+        {"name" : "amount", "required" : true} ]
+  } ],
+  "attributes" : [ {
+    "name" : "accountNumber",
+    "displayName" : "Account Number",
+    "description" : "Company account number",
+    "dataType" : "INT",
+    "indexed" : true,
+    "sortable" : true,
+    "required" : true,
+    "requestContext" : true,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "ipAddress",
+    "displayName" : "IP Address",
+    "description" : "IP Address of the caller",
+    "dataType" : "STRING",
+    "indexed" : true,
+    "sortable" : true,
+    "required" : false,
+    "requestContext" : true,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : [ {
+      "constraintType" : {
+        "name" : "pattern"
+      },
+      "value" : "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
+    } ]
+  }, {
+    "name" : "userId",
+    "displayName" : "UserId",
+    "description" : "Id of the User",
+    "dataType" : "INT",
+    "indexed" : true,
+    "sortable" : true,
+    "required" : true,
+    "requestContext" : true,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "loginId",
+    "displayName" : "LoginId",
+    "description" : "Id user logs in with",
+    "dataType" : "INT",
+    "indexed" : true,
+    "sortable" : true,
+    "required" : true,
+    "requestContext" : true,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "hostName",
+    "displayName" : "Host Name",
+    "description" : "Name of the server",
+    "dataType" : "STRING",
+    "indexed" : true,
+    "sortable" : true,
+    "required" : false,
+    "requestContext" : true,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "toAccount",
+    "displayName" : "To Account Number",
+    "description" : "Destination account",
+    "dataType" : "INT",
+    "indexed" : false,
+    "sortable" : false,
+    "required" : true,
+    "requestContext" : false,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : [ {
+      "constraintType" : {
+        "name" : "minValue"
+      },
+      "value" : "1"
+    } ]
+  }, {
+    "name" : "fromAccount",
+    "displayName" : "From Account Number",
+    "description" : "Source of funds",
+    "dataType" : "INT",
+    "indexed" : false,
+    "sortable" : false,
+    "required" : true,
+    "requestContext" : false,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "amount",
+    "displayName" : "Amount",
+    "description" : "Amount to transfer",
+    "dataType" : "BIG_DECIMAL",
+    "indexed" : false,
+    "sortable" : false,
+    "required" : true,
+    "requestContext" : false,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "account",
+    "displayName" : "Account Number",
+    "description" : "Accopunt number",
+    "dataType" : "INT",
+    "indexed" : false,
+    "sortable" : false,
+    "required" : true,
+    "requestContext" : false,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  }, {
+    "name" : "payee",
+    "displayName" : "Payee",
+    "description" : "Recipient of payment",
+    "dataType" : "STRING",
+    "indexed" : false,
+    "sortable" : false,
+    "required" : true,
+    "requestContext" : false,
+    "examples" : null,
+    "aliases" : null,
+    "constraints" : null
+  } ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/resources/log4j2-test.xml
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/resources/log4j2-test.xml b/log4j-audit/log4j-audit-war/src/test/resources/log4j2-test.xml
new file mode 100644
index 0000000..7d8a2b4
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/resources/log4j2-test.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements. See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache license, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License. You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the license for the specific language governing permissions and
+  ~ limitations under the license.
+  -->
+<Configuration status="ERROR">
+  <properties>
+    <property name="LOG_DIR">target/logs/AuditService</property>
+  </properties>
+  <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
+  <MarkerFilter marker="Audit" onMatch="ACCEPT" onMisMatch="NEUTRAL"/>
+  <Appenders>
+    <Console name="Console" target="SYSTEM_OUT">
+      <PatternLayout pattern="%d{ABSOLUTE} %-5level # %class.%method %m%n" />
+    </Console>
+
+    <RollingFile name="log4j" fileName="${LOG_DIR}/log4j.txt" filePattern="${LOG_DIR}/archive/log4j.txt.%d{yyyyMMdd_HHmmss}-%i">
+      <PatternLayout>
+        <MarkerPatternSelector defaultPattern="%d [%t] %-5p %X{loginId, userId, ipAddress, corpAcctNumber} %C{1.}.%M:%L - %m%n">
+          <PatternMatch key="FLOW" pattern="%d [%t] %-5p %X{loginId, userId, ipAddress, corpAcctNumber} -------- %C{1.}.%M:%L %msg --------%n"/>
+        </MarkerPatternSelector>
+      </PatternLayout>
+      <Policies>
+        <SizeBasedTriggeringPolicy size="30 MB"/>
+      </Policies>
+      <!-- A max of 20 will allow 20 files per second with the date pattern specified on the RollingFile declaration.
+           Hopefully that is a ridiculous value -->
+      <DefaultRolloverStrategy min="1" max="20">
+        <Delete basePath="${LOG_DIR}/archive">
+          <!-- Nested conditions: the inner condition is only evaluated on files for which the outer conditions are true. -->
+          <IfFileName glob="log4j.txt.*">
+            <!-- Only allow 1 GB of files to accumulate -->
+            <IfAccumulatedFileSize exceeds="1 GB"/>
+          </IfFileName>
+        </Delete>
+      </DefaultRolloverStrategy>
+    </RollingFile>
+    <RollingFile name="audit" fileName="${LOG_DIR}/audit.log" filePattern="${LOG_DIR}/archive/audit.log.%d{yyyyMMdd_HHmmss}-%i">
+      <RFC5424Layout enterpriseNumber="18060" includeMDC="true" mdcId="RequestContext" appName="Platform"
+                     mdcPrefix="ReqCtx_"/>
+      <Policies>
+        <SizeBasedTriggeringPolicy size="30 MB"/>
+      </Policies>
+      <!-- A max of 20 will allow 20 files per second with the date pattern specified on the RollingFile declaration.
+           Hopefully that is a ridiculous value -->
+      <DefaultRolloverStrategy min="1" max="20">
+        <Delete basePath="${LOG_DIR}/archive">
+          <!-- Nested conditions: the inner condition is only evaluated on files for which the outer conditions are true. -->
+          <IfFileName glob="audit.log.*">
+            <!-- Only allow 1 GB of files to accumulate -->
+            <IfAccumulatedFileSize exceeds="1 GB"/>
+          </IfFileName>
+        </Delete>
+      </DefaultRolloverStrategy>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.audit" level="info" additivity="false">
+      <AppenderRef ref="log4j"/>
+    </Logger>
+    <Logger name="AuditLogger" level="trace" additivity="false">
+      <AppenderRef ref="audit"/>
+    </Logger>
+    <Root level="DEBUG">
+      <AppenderRef ref="log4j" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/resources/sql/afterTestRun.sql
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/resources/sql/afterTestRun.sql b/log4j-audit/log4j-audit-war/src/test/resources/sql/afterTestRun.sql
new file mode 100644
index 0000000..b9fe1d2
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/resources/sql/afterTestRun.sql
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+DELETE FROM PRODUCT_EVENTS;
+DELETE FROM CATEGORY_EVENTS;
+DELETE FROM EVENT_ATTRIBUTES;
+DELETE FROM CATALOG_PRODUCT;
+DELETE FROM CATALOG_CATEGORY;
+DELETE FROM CATALOG_EVENT;
+DELETE FROM ATTRIBUTE_CONSTRAINT;
+DELETE FROM ATTRIBUTE_EXAMPLES;
+DELETE FROM EVENT_ATTRIBUTE;

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/resources/sql/beforeTestRun.sql.sav
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/resources/sql/beforeTestRun.sql.sav b/log4j-audit/log4j-audit-war/src/test/resources/sql/beforeTestRun.sql.sav
new file mode 100644
index 0000000..612ae00
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/resources/sql/beforeTestRun.sql.sav
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+INSERT INTO CATALOG_PRODUCT VALUES (1, 'DEFAULT', 'banking', 'Banking', 'Fictional banking product');
+
+INSERT INTO EVENT_ATTRIBUTE VALUES (1, 'DEFAULT', 'accountNumber', 'Account Number', 'Company account number', 'int', 'Y', 'Y', 'Y', 'Y');
+INSERT INTO EVENT_ATTRIBUTE VALUES (2, 'DEFAULT', 'ipAddress', 'IP Address', 'IP address of the caller', 'string', 'Y', 'Y', 'N', 'Y');
+INSERT INTO EVENT_ATTRIBUTE VALUES (3, 'DEFAULT', 'userId', 'UserId', 'Id of the user', 'int', 'Y', 'Y', 'Y', 'Y');
+INSERT INTO EVENT_ATTRIBUTE VALUES (4, 'DEFAULT', 'loginId', 'LoginId', 'Id user logs in with', 'string', 'Y', 'Y', 'Y', 'Y');
+INSERT INTO EVENT_ATTRIBUTE VALUES (5, 'DEFAULT', 'hostName', 'Host Name', 'Name of the server', 'string', 'Y', 'Y', 'N', 'Y');
+INSERT INTO EVENT_ATTRIBUTE VALUES (6, 'DEFAULT', 'fromAccount', 'From Account Number', 'Source of funds', 'int', 'N', 'N', 'Y', 'N');
+INSERT INTO EVENT_ATTRIBUTE VALUES (7, 'DEFAULT', 'toAccount', 'To Account Number', 'Destination account', 'int', 'N', 'N', 'Y', 'N');
+INSERT INTO EVENT_ATTRIBUTE VALUES (8, 'DEFAULT', 'amount', 'Amount', 'Amount to transfer', 'bigDecimal', 'N', 'N', 'Y', 'N');
+INSERT INTO EVENT_ATTRIBUTE VALUES (9, 'DEFAULT', 'account', 'Account Number', 'Account number', 'int', 'N', 'N', 'Y', 'N');
+INSERT INTO EVENT_ATTRIBUTE VALUES (10, 'DEFAULT', 'payee', 'Payee', 'Recipient of payment', 'string', 'N', 'N', 'Y', 'N');
+INSERT INTO EVENT_ATTRIBUTE VALUES (11, 'TEST', 'balance', 'Balance', 'Account balance', 'bigDecimal', 'N', 'N', 'N', 'N');
+
+INSERT INTO ATTRIBUTE_EXAMPLES VALUES (2, '127.0.0.1')
+
+INSERT INTO CATALOG_EVENT VALUES (1, 'DEFAULT', 'login', 'Login', 'User login');
+INSERT INTO CATALOG_EVENT VALUES (2, 'DEFAULT', 'transfer', 'Transfer', 'Transfer between accounts');
+INSERT INTO CATALOG_EVENT VALUES (3, 'DEFAULT', 'deposit', 'Deposit', 'Deposit funds');
+INSERT INTO CATALOG_EVENT VALUES (4, 'DEFAULT', 'billPay', 'Bill Pay', 'Payment of a bill');
+INSERT INTO CATALOG_EVENT VALUES (5, 'TEST', 'listAccounts', 'Accounts', 'List of accounts');
+
+INSERT INTO EVENT_ATTRIBUTES VALUES (1, 2, 6, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (2, 2, 7, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (3, 2, 8, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (4, 3, 8, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (5, 3, 9, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (6, 4, 10, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (7, 4, 8, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (8, 5, 9, 'Y');
+INSERT INTO EVENT_ATTRIBUTES VALUES (9, 5, 11, 'Y');
+
+INSERT INTO ATTRIBUTE_CONSTRAINT VALUES (1, 2, 'pattern', '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$');
+
+INSERT INTO PRODUCT_EVENTS VALUES (1, 1);
+INSERT INTO PRODUCT_EVENTS VALUES (1, 2);
+INSERT INTO PRODUCT_EVENTS VALUES (1, 3);
+INSERT INTO PRODUCT_EVENTS VALUES (1, 5);
+
+INSERT INTO CATALOG_CATEGORY VALUES (1, 'DEFAULT', 'account', 'Account', 'Events related to accounts');
+INSERT INTO CATALOG_CATEGORY VALUES (2, 'DEFAULT', 'billPay', 'Bill Pay', 'Events related to bill payment');
+
+INSERT INTO CATEGORY_EVENTS VALUES (1, 1);
+INSERT INTO CATEGORY_EVENTS VALUES (1, 2);
+INSERT INTO CATEGORY_EVENTS VALUES (1, 3);
+INSERT INTO CATEGORY_EVENTS VALUES (2, 4);
+INSERT INTO CATEGORY_EVENTS VALUES (1, 5);
+
+

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-audit/log4j-audit-war/src/test/resources/sql/schema.sql
----------------------------------------------------------------------
diff --git a/log4j-audit/log4j-audit-war/src/test/resources/sql/schema.sql b/log4j-audit/log4j-audit-war/src/test/resources/sql/schema.sql
new file mode 100644
index 0000000..78e5475
--- /dev/null
+++ b/log4j-audit/log4j-audit-war/src/test/resources/sql/schema.sql
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+CREATE TABLE CATALOG
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  LAST_UPDATE TIMESTAMP NOT NULL
+);
+
+CREATE TABLE EVENT_ATTRIBUTE
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  CATALOG_ID VARCHAR(64) NOT NULL,
+  NAME VARCHAR(64) NOT NULL,
+  DISPLAY_NAME VARCHAR(64) NOT NULL,
+  DESCRIPTION VARCHAR(1024),
+  DATATYPE VARCHAR(64),
+  INDEXED CHAR,
+  SORTABLE CHAR,
+  REQUIRED CHAR,
+  REQUEST_CONTEXT CHAR
+);
+
+CREATE INDEX ATTRIBUTE_NAME ON EVENT_ATTRIBUTE(NAME);
+
+CREATE UNIQUE INDEX IDX_ATTR_CATID_NAME ON EVENT_ATTRIBUTE(CATALOG_ID, NAME);
+
+CREATE TABLE ATTRIBUTE_EXAMPLES
+(
+  ATTRIBUTE_ID BIGINT NOT NULL,
+  EXAMPLE VARCHAR(64),
+  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
+);
+
+CREATE TABLE ATTRIBUTE_ALIASES
+(
+  ATTRIBUTE_ID BIGINT NOT NULL,
+  ALIAS VARCHAR(64),
+  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
+);
+
+CREATE TABLE ATTRIBUTE_CONSTRAINT
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  ATTRIBUTE_ID BIGINT NOT NULL,
+  CONSTRAINT_TYPE VARCHAR(32) NOT NULL,
+  VALUE VARCHAR(256),
+  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
+);
+
+CREATE TABLE CATALOG_EVENT
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  CATALOG_ID VARCHAR(64) NOT NULL,
+  NAME VARCHAR(64) NOT NULL,
+  DISPLAY_NAME VARCHAR(64) NOT NULL,
+  DESCRIPTION VARCHAR(1024)
+);
+
+CREATE INDEX EVENT_NAME ON CATALOG_EVENT(NAME);
+
+CREATE UNIQUE INDEX IDX_EVENT_CATID_NAME ON CATALOG_EVENT(CATALOG_ID, NAME);
+
+CREATE TABLE EVENT_ALIASES
+(
+  EVENT_ID BIGINT NOT NULL,
+  ALIAS VARCHAR(64) NOT NULL,
+  FOREIGN KEY  (EVENT_ID) REFERENCES CATALOG_EVENT(ID),
+);
+
+CREATE TABLE EVENT_ATTRIBUTES
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  EVENT_ID BIGINT NOT NULL,
+  ATTRIBUTE_ID BIGINT NOT NULL,
+  IS_REQUIRED CHAR NOT NULL,
+  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID),
+  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID)
+);
+
+CREATE TABLE CATALOG_CATEGORY
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  CATALOG_ID VARCHAR(64) NOT NULL,
+  NAME VARCHAR(64) NOT NULL,
+  DISPLAY_NAME VARCHAR(64) NOT NULL,
+  DESCRIPTION VARCHAR(1024)
+
+);
+
+CREATE INDEX CATEGORY_NAME ON CATALOG_CATEGORY(NAME);
+
+CREATE UNIQUE INDEX IDX_CATEGORY_CATID_NAME ON CATALOG_CATEGORY(CATALOG_ID, NAME);
+
+CREATE TABLE CATEGORY_EVENTS
+(
+  CATEGORY_ID BIGINT NOT NULL,
+  EVENT_ID BIGINT NOT NULL,
+  FOREIGN KEY (CATEGORY_ID) REFERENCES CATALOG_CATEGORY(ID),
+  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID)
+);
+
+CREATE TABLE CATALOG_PRODUCT
+(
+  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
+  CATALOG_ID VARCHAR(64) NOT NULL,
+  NAME VARCHAR(64) NOT NULL,
+  DISPLAY_NAME VARCHAR(64) NOT NULL,
+  DESCRIPTION VARCHAR(1024)
+
+);
+
+CREATE INDEX PRODUCT_NAME ON CATALOG_PRODUCT(NAME);
+
+CREATE UNIQUE INDEX IDX_PRODUCT_CATID_NAME ON CATALOG_PRODUCT(CATALOG_ID, NAME);
+
+CREATE TABLE PRODUCT_EVENTS
+(
+  PRODUCT_ID BIGINT NOT NULL,
+  EVENT_ID BIGINT NOT NULL,
+  FOREIGN KEY (PRODUCT_ID) REFERENCES CATALOG_PRODUCT(ID),
+  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID)
+);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/CatalogReader.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/CatalogReader.java b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/CatalogReader.java
index 91c75ed..d00f8e0 100644
--- a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/CatalogReader.java
+++ b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/CatalogReader.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.catalog.api;
 
+import java.time.LocalDateTime;
 import java.util.Map;
 
 /**
@@ -69,4 +70,10 @@ public interface CatalogReader {
      * @return
      */
     Product getProduct(String name);
+
+    /**
+     * Returns the last update time of the catalog.
+     * @return The last update time of the catalog.
+     */
+    LocalDateTime getLastUpdated();
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/ClassPathCatalogReader.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/ClassPathCatalogReader.java b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/ClassPathCatalogReader.java
index 0548545..77e1171 100644
--- a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/ClassPathCatalogReader.java
+++ b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/ClassPathCatalogReader.java
@@ -20,6 +20,10 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.net.URLConnection;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.Collection;
 import java.util.Map;
 
@@ -43,6 +47,7 @@ public class ClassPathCatalogReader extends AbstractCatalogReader {
     private static final String DEFAULT_CATALOG_FILE = "catalog.json";
 
     private final String catalog;
+    private final LocalDateTime lastUpdated;
 
     public ClassPathCatalogReader(Map<String, String> attributes) throws IOException {
         String catalogFile = attributes != null ?
@@ -60,6 +65,15 @@ public class ClassPathCatalogReader extends AbstractCatalogReader {
         }
 
         catalog = readCatalog(catalogURL);
+        LocalDateTime localDateTime = null;
+        try {
+            URLConnection connection = catalogURL.openConnection();
+            localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(connection.getLastModified()),
+                    ZoneId.systemDefault());
+        } catch (IOException ioe) {
+            LOGGER.warn("Unable to open connection to {}", catalogURL.toString());
+        }
+        lastUpdated = localDateTime;
         JsonFactory factory = new JsonFactory();
         factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
         ObjectMapper objectMapper = new ObjectMapper(factory);
@@ -86,4 +100,9 @@ public class ClassPathCatalogReader extends AbstractCatalogReader {
     public String readCatalog() {
         return catalog;
     }
+
+    @Override
+    public LocalDateTime getLastUpdated() {
+        return lastUpdated;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/FileCatalogReader.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/FileCatalogReader.java b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/FileCatalogReader.java
index 4f32d05..7b07e19 100644
--- a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/FileCatalogReader.java
+++ b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/FileCatalogReader.java
@@ -18,7 +18,11 @@ package org.apache.logging.log4j.catalog.api.dao;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.Map;
 
 import com.fasterxml.jackson.core.JsonFactory;
@@ -40,6 +44,7 @@ public class FileCatalogReader extends AbstractCatalogReader {
     private static final String DEFAULT_CATALOG_FILE = "src/main/resources/catalog.json";
 
     private final String catalog;
+    private LocalDateTime lastUpdated;
 
     public FileCatalogReader(Map<String, String> attributes) throws IOException {
         StringBuilder catalogPath = new StringBuilder();
@@ -66,7 +71,10 @@ public class FileCatalogReader extends AbstractCatalogReader {
             LOGGER.warn("No catalogFile attribute was provided. Using {}", DEFAULT_CATALOG_FILE);
             catalogPath.append(DEFAULT_CATALOG_FILE);
         }
-        byte[] encoded = Files.readAllBytes(Paths.get(catalogPath.toString()));
+        Path path = Paths.get(catalogPath.toString());
+        lastUpdated = LocalDateTime.ofInstant(Instant.ofEpochMilli(path.toFile().lastModified()),
+                ZoneId.systemDefault());
+        byte[] encoded = Files.readAllBytes(path);
         catalog = new String(encoded, StandardCharsets.UTF_8);
         JsonFactory factory = new JsonFactory();
         factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
@@ -87,4 +95,9 @@ public class FileCatalogReader extends AbstractCatalogReader {
     public String readCatalog() {
         return catalog;
     }
+
+    @Override
+    public LocalDateTime getLastUpdated() {
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/JsonCatalogReader.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/JsonCatalogReader.java b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/JsonCatalogReader.java
index d7ef00d..c07cd67 100644
--- a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/JsonCatalogReader.java
+++ b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/dao/JsonCatalogReader.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.catalog.api.dao;
 
+import java.time.LocalDateTime;
+
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -64,4 +66,9 @@ public class JsonCatalogReader extends AbstractCatalogReader {
             return null;
         }
     }
+
+    @Override
+    public LocalDateTime getLastUpdated() {
+        return catalogReader.getLastUpdated();
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/service/CatalogService.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/service/CatalogService.java b/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/service/CatalogService.java
deleted file mode 100644
index 93a3672..0000000
--- a/log4j-catalog/log4j-catalog-api/src/main/java/org/apache/logging/log4j/catalog/api/service/CatalogService.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.catalog.api.service;
-
-import org.apache.logging.log4j.catalog.api.CatalogData;
-
-/**
- * Catalog Service methods.
- */
-public interface CatalogService {
-    CatalogData getCatalogData();
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-git/src/main/java/org/apache/logging/log4j/catalog/git/dao/GitCatalogDao.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-git/src/main/java/org/apache/logging/log4j/catalog/git/dao/GitCatalogDao.java b/log4j-catalog/log4j-catalog-git/src/main/java/org/apache/logging/log4j/catalog/git/dao/GitCatalogDao.java
index c31cf2d..edadb9d 100644
--- a/log4j-catalog/log4j-catalog-git/src/main/java/org/apache/logging/log4j/catalog/git/dao/GitCatalogDao.java
+++ b/log4j-catalog/log4j-catalog-git/src/main/java/org/apache/logging/log4j/catalog/git/dao/GitCatalogDao.java
@@ -19,6 +19,9 @@ package org.apache.logging.log4j.catalog.git.dao;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
 
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonParser;
@@ -104,6 +107,15 @@ public class GitCatalogDao extends AbstractCatalogReader implements CatalogDao {
     }
 
     @Override
+    public LocalDateTime getLastUpdated() {
+        if (localRepo == null) {
+            updateRepo();
+        }
+        return LocalDateTime.ofInstant(Instant.ofEpochMilli(catalogFile.lastModified()),
+                ZoneId.systemDefault());
+    }
+
+    @Override
     public synchronized CatalogData read() {
         updateRepo();
         if (catalogFile == null || !catalogFile.exists() || !catalogFile.canRead()) {

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
deleted file mode 100644
index b6bdb6d..0000000
--- a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.catalog.jpa.config;
-
-import org.apache.logging.log4j.catalog.api.service.CatalogService;
-import org.apache.logging.log4j.catalog.jpa.service.CatalogServiceImpl;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-
-@Configuration
-@ComponentScan(basePackages = { "org.apache.logging.log4j.catalog" })
-@Import(HibernatgeDataSourceConfig.class)
-public class ApplicationConfiguration {
-    @Bean
-    public CatalogService catalogService() {
-        return new CatalogServiceImpl();
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/dao/CatalogRepository.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/dao/CatalogRepository.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/dao/CatalogRepository.java
new file mode 100644
index 0000000..ad7b7d2
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/dao/CatalogRepository.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.catalog.jpa.dao;
+
+import org.apache.logging.log4j.catalog.jpa.model.CatalogModel;
+
+public interface CatalogRepository extends BaseRepository<CatalogModel, Long> {
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/CatalogModel.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/CatalogModel.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/CatalogModel.java
new file mode 100644
index 0000000..343438f
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/model/CatalogModel.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.catalog.jpa.model;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.sql.Timestamp;
+
+@Entity
+@Table(name = "CATALOG")
+public class CatalogModel {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    @Column(name = "ID", updatable = false, nullable = false)
+    private Long id;
+    @Column(name = "LAST_UPDATE")
+    private Timestamp lastUpdate;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Timestamp getLastUpdate() {
+        return lastUpdate;
+    }
+
+    public void setLastUpdate(Timestamp lastUpdate) {
+        this.lastUpdate = lastUpdate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogService.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogService.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogService.java
new file mode 100644
index 0000000..82a718c
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.catalog.jpa.service;
+
+import org.apache.logging.log4j.catalog.api.CatalogData;
+import org.apache.logging.log4j.catalog.jpa.model.CatalogModel;
+
+/**
+ * Catalog Service methods.
+ */
+public interface CatalogService {
+    CatalogData getCatalogData();
+
+    CatalogModel getCatalogModel();
+
+    void saveCatalog(CatalogModel catalogModel);
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogServiceImpl.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogServiceImpl.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogServiceImpl.java
index 7d53bc8..d9a40b1 100644
--- a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogServiceImpl.java
+++ b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/CatalogServiceImpl.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.catalog.jpa.service;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -26,16 +27,17 @@ import org.apache.logging.log4j.catalog.api.Category;
 import org.apache.logging.log4j.catalog.api.Event;
 import org.apache.logging.log4j.catalog.api.Product;
 import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins;
-import org.apache.logging.log4j.catalog.api.service.CatalogService;
 import org.apache.logging.log4j.catalog.jpa.converter.AttributeModelConverter;
 import org.apache.logging.log4j.catalog.jpa.converter.CategoryModelConverter;
 import org.apache.logging.log4j.catalog.jpa.converter.EventModelConverter;
 import org.apache.logging.log4j.catalog.jpa.converter.ProductModelConverter;
 import org.apache.logging.log4j.catalog.jpa.dao.AttributeRepository;
+import org.apache.logging.log4j.catalog.jpa.dao.CatalogRepository;
 import org.apache.logging.log4j.catalog.jpa.dao.CategoryRepository;
 import org.apache.logging.log4j.catalog.jpa.dao.EventRepository;
 import org.apache.logging.log4j.catalog.jpa.dao.ProductRepository;
 import org.apache.logging.log4j.catalog.jpa.model.AttributeModel;
+import org.apache.logging.log4j.catalog.jpa.model.CatalogModel;
 import org.apache.logging.log4j.catalog.jpa.model.CategoryModel;
 import org.apache.logging.log4j.catalog.jpa.model.EventModel;
 import org.apache.logging.log4j.catalog.jpa.model.ProductModel;
@@ -67,6 +69,8 @@ public class CatalogServiceImpl implements CatalogService {
     private CategoryModelConverter categoryModelConverter;
     @Autowired
     private ProductModelConverter productModelConverter;
+    @Autowired
+    private CatalogRepository catalogRepository;
 
 
     public CatalogData getCatalogData() {
@@ -118,4 +122,18 @@ public class CatalogServiceImpl implements CatalogService {
     public Optional<CategoryModel> getCategory(long id) {
         return categoryRepository.findOne(id);
     }
+
+    @Override
+    public CatalogModel getCatalogModel() {
+        List<CatalogModel> catalogModels = catalogRepository.findAll();
+        if (catalogModels != null && catalogModels.size() > 0) {
+            return catalogModels.get(0);
+        }
+        return null;
+    }
+
+    @Override
+    public void saveCatalog(CatalogModel catalogModel) {
+        catalogRepository.save(catalogModel);
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConfigurationService.java b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConfigurationService.java
deleted file mode 100644
index ac21e70..0000000
--- a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConfigurationService.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.catalog.jpa.service;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-
-@Service
-public class ConfigurationService {
-
-    @Value("${catalogServiceAuthToken:cbade18f-437a-412c-b0c5-9e246ee23ca6}")
-    private String catalogServiceAuthToken;
-
-    public String getCatalogServiceAuthToken() {
-        return catalogServiceAuthToken;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/main/resources/sql/schema.sql
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/main/resources/sql/schema.sql b/log4j-catalog/log4j-catalog-jpa/src/main/resources/sql/schema.sql
deleted file mode 100644
index 1618e73..0000000
--- a/log4j-catalog/log4j-catalog-jpa/src/main/resources/sql/schema.sql
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2001-2005 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-CREATE TABLE EVENT_ATTRIBUTE
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  CATALOG_ID VARCHAR(64) NOT NULL,
-  NAME VARCHAR(64) NOT NULL,
-  DISPLAY_NAME VARCHAR(64) NOT NULL,
-  DESCRIPTION VARCHAR(1024),
-  DATATYPE VARCHAR(64),
-  INDEXED CHAR,
-  SORTABLE CHAR,
-  REQUIRED CHAR,
-  REQUEST_CONTEXT CHAR
-);
-
-CREATE INDEX ATTRIBUTE_NAME ON EVENT_ATTRIBUTE(NAME);
-
-CREATE TABLE ATTRIBUTE_EXAMPLES
-(
-  ATTRIBUTE_ID BIGINT NOT NULL,
-  EXAMPLE VARCHAR(64),
-  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
-);
-
-CREATE TABLE ATTRIBUTE_ALIASES
-(
-  ATTRIBUTE_ID BIGINT NOT NULL,
-  ALIAS VARCHAR(64),
-  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
-);
-
-CREATE TABLE ATTRIBUTE_CONSTRAINT
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  ATTRIBUTE_ID BIGINT NOT NULL,
-  CONSTRAINT_TYPE VARCHAR(32) NOT NULL,
-  VALUE VARCHAR(256),
-  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID),
-);
-
-CREATE TABLE CATALOG_EVENT
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  CATALOG_ID VARCHAR(64) NOT NULL,
-  NAME VARCHAR(64) NOT NULL,
-  DISPLAY_NAME VARCHAR(64) NOT NULL,
-  DESCRIPTION VARCHAR(1024)
-);
-
-CREATE INDEX EVENT_NAME ON CATALOG_EVENT(NAME);
-
-CREATE TABLE EVENT_ALIASES
-(
-  EVENT_ID BIGINT NOT NULL,
-  ALIAS VARCHAR(64) NOT NULL,
-  FOREIGN KEY  (EVENT_ID) REFERENCES CATALOG_EVENT(ID),
-);
-
-CREATE TABLE EVENT_ATTRIBUTES
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  EVENT_ID BIGINT NOT NULL,
-  ATTRIBUTE_ID BIGINT NOT NULL,
-  IS_REQUIRED CHAR NOT NULL,
-  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID),
-  FOREIGN KEY (ATTRIBUTE_ID) REFERENCES EVENT_ATTRIBUTE(ID)
-);
-
-CREATE TABLE CATALOG_CATEGORY
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  CATALOG_ID VARCHAR(64) NOT NULL,
-  NAME VARCHAR(64) NOT NULL,
-  DISPLAY_NAME VARCHAR(64) NOT NULL,
-  DESCRIPTION VARCHAR(1024)
-
-);
-
-CREATE INDEX CATEGORY_NAME ON CATALOG_CATEGORY(NAME);
-
-CREATE TABLE CATEGORY_EVENTS
-(
-  CATEGORY_ID BIGINT NOT NULL,
-  EVENT_ID BIGINT NOT NULL,
-  FOREIGN KEY (CATEGORY_ID) REFERENCES CATALOG_CATEGORY(ID),
-  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID)
-);
-
-CREATE TABLE CATALOG_PRODUCT
-(
-  ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
-  CATALOG_ID VARCHAR(64) NOT NULL,
-  NAME VARCHAR(64) NOT NULL,
-  DISPLAY_NAME VARCHAR(64) NOT NULL,
-  DESCRIPTION VARCHAR(1024)
-
-);
-
-CREATE INDEX PRODUCT_NAME ON CATALOG_PRODUCT(NAME);
-
-CREATE TABLE PRODUCT_EVENTS
-(
-  PRODUCT_ID BIGINT NOT NULL,
-  EVENT_ID BIGINT NOT NULL,
-  FOREIGN KEY (PRODUCT_ID) REFERENCES CATALOG_PRODUCT(ID),
-  FOREIGN KEY (EVENT_ID) REFERENCES CATALOG_EVENT(ID)
-);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java b/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java
index 8e2a7a5..bfd3f45 100644
--- a/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java
+++ b/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java
@@ -20,7 +20,7 @@ import java.util.Optional;
 
 import org.apache.logging.log4j.catalog.api.CatalogData;
 import org.apache.logging.log4j.catalog.api.DataType;
-import org.apache.logging.log4j.catalog.api.service.CatalogService;
+import org.apache.logging.log4j.catalog.jpa.service.CatalogService;
 import org.apache.logging.log4j.catalog.jpa.config.ApplicationConfiguration;
 import org.apache.logging.log4j.catalog.jpa.dao.AttributeRepository;
 import org.apache.logging.log4j.catalog.jpa.dao.CategoryRepository;

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/1deb7eba/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java b/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
new file mode 100644
index 0000000..4a1555c
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/config/ApplicationConfiguration.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.catalog.jpa.config;
+
+import org.apache.logging.log4j.catalog.jpa.service.CatalogService;
+import org.apache.logging.log4j.catalog.jpa.service.CatalogServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+@Configuration
+@ComponentScan(basePackages = { "org.apache.logging.log4j.catalog" })
+@Import(HibernatgeDataSourceConfig.class)
+public class ApplicationConfiguration {
+    @Bean
+    public CatalogService catalogService() {
+        return new CatalogServiceImpl();
+    }
+}