http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConstraintServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConstraintServiceImpl.java
 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConstraintServiceImpl.java
new file mode 100644
index 0000000..8583175
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ConstraintServiceImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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 java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins;
+import org.apache.logging.log4j.catalog.jpa.dao.ConstraintRepository;
+import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Repository
+@Transactional
+public class ConstraintServiceImpl implements ConstraintService {
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    @Autowired
+    private ConstraintRepository constraintRepository;
+
+    @Override
+    public Set<String> getConstraintTypes() {
+        return ConstraintPlugins.getInstance().getConstraintMap().keySet();
+    }
+
+    @Override
+    public List<ConstraintModel> getConstraints() {
+        return constraintRepository.findAll();
+    }
+
+    @Override
+    public Optional<ConstraintModel> getConstraint(Long constraintId) {
+        return constraintRepository.findOne(constraintId);
+    }
+
+    @Override
+    public ConstraintModel saveConstraint(ConstraintModel constraint) {
+        return constraintRepository.save(constraint);
+    }
+
+    @Override
+    public void deleteConstraint(Long constraintId) {
+        constraintRepository.deleteById(constraintId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventService.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventService.java
 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventService.java
new file mode 100644
index 0000000..5382545
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventService.java
@@ -0,0 +1,35 @@
+/*
+ * 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 java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.logging.log4j.catalog.jpa.model.EventModel;
+
+/**
+ * 
+ */
+public interface EventService {
+    List<EventModel> getEvents(int startPage, int itemsPerPage, String 
sortColumn, String direction);
+    List<EventModel> getEvents();
+    Map<String, EventModel> getEventMap();
+    Optional<EventModel> getEvent(Long eventId);
+    EventModel saveEvent(EventModel event);
+    void deleteEvent(Long eventId);
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventServiceImpl.java
 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventServiceImpl.java
new file mode 100644
index 0000000..f7852b5
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/EventServiceImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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 java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.catalog.jpa.dao.EventRepository;
+import org.apache.logging.log4j.catalog.jpa.model.EventModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Repository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Repository
+@Transactional
+public class EventServiceImpl extends AbstractPagingAndSortingService 
implements EventService {
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    @Autowired
+    private EventRepository eventRepository;
+
+    @Override
+    public List<EventModel> getEvents() {
+        return eventRepository.findAll();
+    }
+
+    @Override
+    public List<EventModel> getEvents(int startPage, int itemsPerPage, String 
sortColumn, String direction) {
+        Pageable pageable = createPageRequest(startPage, itemsPerPage, 
sortColumn, direction);
+        Page<EventModel> page = eventRepository.findAll(pageable);
+        return page.getContent();
+    }
+
+    @Override
+    public Map<String, EventModel> getEventMap() {
+        List<EventModel> events = getEvents();
+        Map<String, EventModel> eventMap = new HashMap<>(events.size());
+        for (EventModel event : events) {
+            eventMap.put(event.getName(), event);
+        }
+        return eventMap;
+    }
+
+    @Override
+    public Optional<EventModel> getEvent(Long eventId) {
+        return eventRepository.findOne(eventId);
+    }
+
+    @Override
+    public EventModel saveEvent(EventModel event) {
+        return eventRepository.save(event);
+    }
+
+    @Override
+    public void deleteEvent(Long eventId) {
+        eventRepository.deleteById(eventId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductService.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductService.java
 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductService.java
new file mode 100644
index 0000000..4263090
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.jpa.model.ProductModel;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ProductService {
+    List<ProductModel> getProducts(int startPage, int itemsPerPage, String 
sortColumn, String direction);
+    List<ProductModel> getProducts();
+    Optional<ProductModel> getProduct(Long productId);
+    ProductModel saveProduct(ProductModel product);
+    void deleteProduct(Long productId);
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductServiceImpl.java
 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductServiceImpl.java
new file mode 100644
index 0000000..92ed9a4
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/main/java/org/apache/logging/log4j/catalog/jpa/service/ProductServiceImpl.java
@@ -0,0 +1,68 @@
+/*
+ * 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 java.util.List;
+import java.util.Optional;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.catalog.jpa.dao.ProductRepository;
+import org.apache.logging.log4j.catalog.jpa.model.ProductModel;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Repository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Repository
+@Transactional
+public class ProductServiceImpl extends AbstractPagingAndSortingService 
implements ProductService {
+    private static final Logger LOGGER = LogManager.getLogger();
+
+    @Autowired
+    private ProductRepository productRepository;
+
+    @Override
+    public List<ProductModel> getProducts() {
+        return productRepository.findAll();
+    }
+
+    @Override
+    public List<ProductModel> getProducts(int startPage, int itemsPerPage, 
String sortColumn, String direction) {
+        Pageable pageable = createPageRequest(startPage, itemsPerPage, 
sortColumn, direction);
+        Page<ProductModel> page = productRepository.findAll(pageable);
+        return page.getContent();
+    }
+
+    @Override
+    public Optional<ProductModel> getProduct(Long productId) {
+        return productRepository.findOne(productId);
+    }
+
+    @Override
+    public ProductModel saveProduct(ProductModel product) {
+        return productRepository.save(product);
+    }
+
+    @Override
+    public void deleteProduct(Long productId) {
+        productRepository.deleteById(productId);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/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
new file mode 100644
index 0000000..1618e73
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/main/resources/sql/schema.sql
@@ -0,0 +1,121 @@
+/*
+ * 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/f0884aeb/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
new file mode 100644
index 0000000..8e2a7a5
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-jpa/src/test/java/org/apache/logging/log4j/catalog/jpa/CatalogTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+package org.apache.logging.log4j.catalog.jpa;
+
+import java.util.List;
+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.config.ApplicationConfiguration;
+import org.apache.logging.log4j.catalog.jpa.dao.AttributeRepository;
+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.model.AttributeModel;
+import org.apache.logging.log4j.catalog.jpa.model.EventAttributeModel;
+import org.apache.logging.log4j.catalog.jpa.model.EventModel;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlGroup;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.AnnotationConfigContextLoader;
+import static org.junit.Assert.*;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = 
{ApplicationConfiguration.class})
+@SqlGroup({
+        @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = 
"classpath:sql/beforeTestRun.sql"),
+        @Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = 
"classpath:sql/afterTestRun.sql")
+})
+@Repository
+public class CatalogTest {
+
+    @Autowired
+    AttributeRepository attributeRepository;
+    @Autowired
+    CategoryRepository categoryRepository;
+    @Autowired
+    EventRepository eventRepository;
+    @Autowired
+    private CatalogService catalogService;
+
+    @BeforeClass
+    public static void initTest() {
+        try {
+            System.setProperty("environment", "lab");
+            System.setProperty("site", "dev1");
+            System.setProperty("applicationName", "CatalogService");
+        } catch (RuntimeException ex) {
+            throw ex;
+        }
+    }
+
+    @Test
+    public void testRetrieveEvents() {
+        List<EventModel> events = eventRepository.findAll();
+        assertNotNull(events);
+        assertFalse(events.isEmpty());
+        assertEquals(4, events.size());
+    }
+
+    @Test
+    public void testRetrieveEvent() {
+        Optional<EventModel> optEvent = eventRepository.findOne(1L);
+        assertTrue(optEvent.isPresent());
+        EventModel event = optEvent.get();
+        assertNotNull(event);
+        assertEquals("login", event.getName());
+    }
+
+    @Test
+    public void testAddAndUpdateEvent() {
+        EventModel event = new EventModel();
+        event.setName("test" + System.nanoTime());
+        event.setDisplayName("Test -- " + System.nanoTime());
+        event.setDescription("foo");
+
+        AttributeModel attr = new AttributeModel();
+        attr.setName("Attr1 -- " + System.nanoTime());
+        attr.setDisplayName("Attribute #1 -- " + System.nanoTime());
+        attr.setDescription("Test Attribute");
+        attr.setDataType(DataType.BOOLEAN);
+        attr.setIndexed(true);
+        attr.setRequestContext(true);
+        attr.setRequired(true);
+        attr.setSortable(true);
+        attr = attributeRepository.save(attr);
+        AttributeModel attr2 = new AttributeModel();
+        attr2.setName("Attr2 -- " + System.nanoTime());
+        attr2.setDisplayName("Attribute #2 -- " + System.nanoTime());
+        attr2.setDescription("Test Attribute Number 2");
+        attr2.setDataType(DataType.BOOLEAN);
+        attr2.setIndexed(false);
+        attr2.setRequestContext(false);
+        attr2.setRequired(false);
+        attr2.setSortable(false);
+        attr2 = attributeRepository.save(attr2);
+        EventAttributeModel eventAttribute = new EventAttributeModel();
+        eventAttribute.setAttribute(attr);
+        eventAttribute.setEvent(event);
+        eventAttribute.setRequired(true);
+        event.addEventAttribute(eventAttribute);
+        EventModel persisted = null;
+        try {
+            persisted = eventRepository.save(event);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            fail();
+        }
+        assertNotNull(persisted);
+        assertNotNull(persisted.getId());
+        assertTrue(event.equals(persisted));
+        assertNotNull(persisted.getAttributes());
+        assertFalse(persisted.getAttributes().isEmpty());
+        assertEquals(event.getAttributes().size(), 
persisted.getAttributes().size());
+        eventAttribute = new EventAttributeModel();
+        eventAttribute.setAttribute(attr2);
+        eventAttribute.setEvent(persisted);
+        eventAttribute.setRequired(false);
+        persisted.addEventAttribute(eventAttribute);
+        Long id = persisted.getId();
+        try {
+            persisted = eventRepository.save(event);
+        } catch (Throwable ex) {
+            ex.printStackTrace();
+            fail();
+        }
+        assertNotNull(persisted);
+        assertNotNull(persisted.getId());
+        assertTrue(persisted.getId().equals(id));
+        assertNotNull(persisted.getAttributes());
+        assertFalse(persisted.getAttributes().isEmpty());
+        assertEquals(event.getAttributes().size(), 
persisted.getAttributes().size());
+    }
+
+    @Test
+    public void testModifyEvent() {
+
+    }
+
+    @Test
+    public void testDeleteEvent() {
+
+    }
+
+    @Test
+    public void testRetrieveAttributes() {
+        List<AttributeModel> attributes = attributeRepository.findAll();
+        assertNotNull(attributes);
+        assertFalse(attributes.isEmpty());
+        assertEquals(10, attributes.size());
+    }
+
+    @Test
+    public void testRetrieveAttribute() {
+        Optional<AttributeModel> optAttr = attributeRepository.findOne(1L);
+        assertTrue(optAttr.isPresent());
+        AttributeModel attr = optAttr.get();
+        assertNotNull(attr);
+        assertEquals("accountNumber", attr.getName());
+    }
+
+    @Test
+    public void testAddAttribute() {
+
+    }
+
+    @Test
+    public void testModifyAttribute() {
+    }
+
+    @Test
+    public void testDeleteAttribute() {
+    }
+
+    @Test
+    public void testRetrieveCatalog() {
+        CatalogData data = catalogService.getCatalogData();
+        assertNotNull("No catalog data was returned", data);
+        assertEquals("Incorrect number of products", 1, 
data.getProducts().size());
+        assertEquals("Incorrect number of events", 4, data.getEvents().size());
+        assertEquals("Incorrect number of attributes", 10, 
data.getAttributes().size());
+        assertEquals("Incorrect number of categories", 2, 
data.getCategories().size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/test/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-jpa/src/test/resources/log4j2.xml 
b/log4j-catalog/log4j-catalog-jpa/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..1c4bcca
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/test/resources/log4j2.xml
@@ -0,0 +1,45 @@
+<?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</property>
+  </properties>
+  <MarkerFilter marker="FLOW" 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_HH}-%i">
+      <PatternLayout>
+        <MarkerPatternSelector defaultPattern="%d [%t] %-5p %C{1.}.%M:%L - 
%m%n">
+          <PatternMatch key="FLOW" pattern="%d [%t] %-5p -------- %C{1.}.%M:%L 
%msg --------%n"/>
+        </MarkerPatternSelector>
+      </PatternLayout>
+      <Policies>
+        <SizeBasedTriggeringPolicy size="30 MB"/>
+      </Policies>
+      <DefaultRolloverStrategy min="1" max="20"/>
+    </RollingFile>
+  </Appenders>
+  <Loggers>
+    <Root level="debug">
+      <AppenderRef ref="log4j" />
+    </Root>
+  </Loggers>
+</Configuration>

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/afterTestRun.sql
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/afterTestRun.sql 
b/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/afterTestRun.sql
new file mode 100644
index 0000000..b9fe1d2
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/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/f0884aeb/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/beforeTestRun.sql
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/beforeTestRun.sql 
b/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/beforeTestRun.sql
new file mode 100644
index 0000000..95be80a
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-jpa/src/test/resources/sql/beforeTestRun.sql
@@ -0,0 +1,58 @@
+/*
+ * 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 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 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 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 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);
+
+

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/pom.xml
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-war/pom.xml 
b/log4j-catalog/log4j-catalog-war/pom.xml
new file mode 100644
index 0000000..152421c
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-war/pom.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.apache.logging.log4j</groupId>
+               <artifactId>log4j-catalog</artifactId>
+               <version>1.0.0-SNAPSHOT</version>
+       </parent>
+       <artifactId>log4j-catalog-war</artifactId>
+       <packaging>war</packaging>
+
+       <name>Log4j Catalog Service</name>
+       <url>http://maven.apache.org</url>
+       <properties>
+               
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       </properties>
+       <dependencies>
+               <dependency>
+                       <groupId>jstl</groupId>
+                       <artifactId>jstl</artifactId>
+                       <version>1.2</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger2</artifactId>
+                       <exclusions>
+                               <exclusion>
+                                       <groupId>org.aspectj</groupId>
+                                       <artifactId>aspectjrt</artifactId>
+                               </exclusion>
+                       </exclusions>
+               </dependency>
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger-ui</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-catalog-git</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-catalog-jpa</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-catalog-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.httpcomponents</groupId>
+                       <artifactId>httpclient</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>commons-logging</groupId>
+                       <artifactId>commons-logging</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-context</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-context-support</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-web</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-webmvc</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-beans</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework</groupId>
+                       <artifactId>spring-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework.data</groupId>
+                       <artifactId>spring-data-rest-webmvc</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>javax.servlet</groupId>
+                       <artifactId>javax.servlet-api</artifactId>
+                       <version>3.0.1</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>javax</groupId>
+                       <artifactId>javaee-api</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.commons</groupId>
+                       <artifactId>commons-lang3</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-api</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.logging.log4j</groupId>
+                       <artifactId>log4j-web</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>com.fasterxml.jackson.core</groupId>
+                       <artifactId>jackson-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>com.fasterxml.jackson.core</groupId>
+                       <artifactId>jackson-databind</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>com.fasterxml.jackson.datatype</groupId>
+                       <artifactId>jackson-datatype-jsr310</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.mockito</groupId>
+                       <artifactId>mockito-core</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework.data</groupId>
+                       <artifactId>spring-data-jpa</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.modelmapper</groupId>
+                       <artifactId>modelmapper</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.modelmapper.extensions</groupId>
+                       <artifactId>modelmapper-spring</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.modelmapper.extensions</groupId>
+                       <artifactId>modelmapper-jackson</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.thymeleaf</groupId>
+                       <artifactId>thymeleaf</artifactId>
+               </dependency>
+               <dependency>
+                       <groupId>org.thymeleaf</groupId>
+                       <artifactId>thymeleaf-spring4</artifactId>
+
+               </dependency>
+       </dependencies>
+       <build>
+               <finalName>AuditCatalog</finalName>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-war-plugin</artifactId>
+                               <version>2.6</version>
+                               <configuration>
+                                       
<failOnMissingWebXml>false</failOnMissingWebXml>
+                               </configuration>
+                               <executions>
+                                       <execution>
+                                               <id>default-war</id>
+                                               <goals>
+                                                       <goal>war</goal>
+                                               </goals>
+                                               <phase>prepare-package</phase>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
+</project>

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/JsonObjectMapperFactory.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/JsonObjectMapperFactory.java
 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/JsonObjectMapperFactory.java
new file mode 100644
index 0000000..fdd0cb9
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/JsonObjectMapperFactory.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016 Nextiva, Inc. to Present.
+ * All rights reserved.
+ */
+package org.apache.logging.log4j.catalog.config;
+
+import java.io.IOException;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+
+/**
+ *  Extends Jackson ObjectMapper to support Java LocalDateTime.
+ */
+public final class JsonObjectMapperFactory {
+    /**
+     * Date/Time format.
+     */
+    private static final String LOCAL_DATE_TIME_FORMAT = "yyyyMMddHHmmss.SSS";
+
+    /**
+     * LocalDateTime formatter that converts to and from a format usable in 
REST requests.
+     */
+    private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = 
DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_FORMAT);
+
+    /**
+     * Date/Time format.
+     */
+    private static final String LOCAL_DATE_FORMAT = "yyyyMMdd";
+
+    /**
+     * LocalDateTime formatter that converts to and from a format usable in 
REST requests.
+     */
+    private static final DateTimeFormatter LOCAL_DATE_FORMATTER = 
DateTimeFormatter.ofPattern(LOCAL_DATE_FORMAT);
+
+    /**
+     * Date/Time format.
+     */
+    private static final String ZONED_DATE_TIME_FORMAT = "yyyyMMddHHmmss.SSSZ";
+
+    /**
+     * LocalDateTime formatter that converts to and from a format usable in 
REST requests.
+     */
+    public static final DateTimeFormatter ZONED_DATE_TIME_FORMATTER = 
DateTimeFormatter.ofPattern(ZONED_DATE_TIME_FORMAT);
+
+    private JsonObjectMapperFactory() {
+    }
+
+    /**
+     * Create an ObjectMapper using the standard LocalDateTime format.
+     * @return The ObjectMapper.
+     */
+    public static ObjectMapper createMapper() {
+        ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
+        DateTimeFormatter dateTimeFormatter = LOCAL_DATE_TIME_FORMATTER;
+        DateTimeFormatter dateFormatter = LOCAL_DATE_FORMATTER;
+        DateTimeFormatter zonedTimeFormatter = ZONED_DATE_TIME_FORMATTER;
+        SimpleModule module = new SimpleModule();
+        module.addSerializer(LocalDateTime.class, new 
JsonSerializer<LocalDateTime>() {
+            @Override
+            public void serialize(LocalDateTime localDateTime, JsonGenerator 
jsonGenerator,
+                    SerializerProvider serializerProvider) throws IOException, 
JsonProcessingException {
+                
jsonGenerator.writeString(dateTimeFormatter.format(localDateTime));
+            }
+        });
+        module.addDeserializer(LocalDateTime.class, new 
JsonDeserializer<LocalDateTime>() {
+            @Override
+            public LocalDateTime deserialize(JsonParser parser, 
DeserializationContext context) throws IOException {
+                String string = parser.getText().trim();
+                if (string.length() == 0) {
+                    return null;
+                }
+                try {
+                    return LocalDateTime.parse(string, dateTimeFormatter);
+                } catch (DateTimeException e) {
+                    throw JsonMappingException.from(parser,
+                            String.format("Failed to deserialize %s: (%s) %s",
+                                    handledType().getName(), 
e.getClass().getName(), e.getMessage()), e);
+                }
+            }
+        });
+        module.addSerializer(ZonedDateTime.class, new 
JsonSerializer<ZonedDateTime>() {
+            @Override
+            public void serialize(ZonedDateTime zonedDateTime, JsonGenerator 
jsonGenerator,
+                    SerializerProvider serializerProvider) throws IOException, 
JsonProcessingException {
+                
jsonGenerator.writeString(zonedTimeFormatter.format(zonedDateTime));
+            }
+        });
+        module.addDeserializer(ZonedDateTime.class, new 
JsonDeserializer<ZonedDateTime>() {
+            @Override
+            public ZonedDateTime deserialize(JsonParser parser, 
DeserializationContext context) throws IOException {
+                String string = parser.getText().trim();
+                if (string.length() == 0) {
+                    return null;
+                }
+                try {
+                    return ZonedDateTime.parse(string, zonedTimeFormatter);
+                } catch (DateTimeException e) {
+                    throw JsonMappingException.from(parser,
+                            String.format("Failed to deserialize %s: (%s) %s",
+                                    handledType().getName(), 
e.getClass().getName(), e.getMessage()), e);
+                }
+            }
+        });
+        module.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
+            @Override
+            public void serialize(LocalDate localDate, JsonGenerator 
jsonGenerator,
+                    SerializerProvider serializerProvider) throws IOException, 
JsonProcessingException {
+                jsonGenerator.writeString(dateFormatter.format(localDate));
+            }
+        });
+        module.addDeserializer(LocalDate.class, new 
JsonDeserializer<LocalDate>() {
+            @Override
+            public LocalDate deserialize(JsonParser parser, 
DeserializationContext context) throws IOException {
+                String string = parser.getText().trim();
+                if (string.length() == 0) {
+                    return null;
+                }
+                try {
+                    return LocalDate.parse(string, dateFormatter);
+                } catch (DateTimeException e) {
+                    throw JsonMappingException.from(parser,
+                            String.format("Failed to deserialize %s: (%s) %s",
+                                    handledType().getName(), 
e.getClass().getName(), e.getMessage()), e);
+                }
+            }
+        });
+        mapper.registerModule(module);
+        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, 
false);
+        mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+        return mapper;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/SwaggerConfig.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/SwaggerConfig.java
 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/SwaggerConfig.java
new file mode 100644
index 0000000..0b0f9c6
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/SwaggerConfig.java
@@ -0,0 +1,63 @@
+/*
+ * 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.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * This will configure Swagger to produce an API for all of our REST endpoints.
+ */
+@Configuration
+@EnableSwagger2
+@EnableWebMvc
+public class SwaggerConfig {
+    @Bean
+    public Docket api() {
+        return new Docket(DocumentationType.SWAGGER_2)
+            .apiInfo(apiInfo())
+            .select()
+            .apis(RequestHandlerSelectors.any())
+            .paths(PathSelectors.any())
+            .build()
+            .directModelSubstitute(LocalDate.class, java.sql.Date.class)
+            .directModelSubstitute(LocalDateTime.class, java.util.Date.class);
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("Catalog Service")
+                .description("Maintains the audit event catalog")
+                .termsOfServiceUrl("http://logging.apache.org";)
+                .contact("Apache Logging")
+                .license("1.0")
+                .licenseUrl("http://www.apache.org/licenses/";)
+                .version("1.0")
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebAppInitializer.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebAppInitializer.java
 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebAppInitializer.java
new file mode 100644
index 0000000..4e978c2
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebAppInitializer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.config;
+
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.ContextLoaderListener;
+import 
org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+public class WebAppInitializer implements WebApplicationInitializer {
+    private static final String APPLICATION_NAME = "CatalogService";
+
+    @Override
+    public void onStartup(ServletContext servletContext) throws 
ServletException {
+        servletContext.setInitParameter("applicationName", APPLICATION_NAME);
+        System.setProperty("applicationName", APPLICATION_NAME);
+        AnnotationConfigWebApplicationContext rootContext = new 
AnnotationConfigWebApplicationContext();
+        rootContext.setDisplayName(APPLICATION_NAME);
+        rootContext.register(WebMvcAppContext.class);
+        servletContext.addListener(new ContextLoaderListener(rootContext));
+
+        ServletRegistration.Dynamic restServlet = 
servletContext.addServlet("dispatcherServlet", new 
DispatcherServlet(rootContext));
+        restServlet.setLoadOnStartup(1);
+        restServlet.addMapping("/*");
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
new file mode 100644
index 0000000..2eae80d
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
@@ -0,0 +1,312 @@
+/*
+ * 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.config;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.UserInfo;
+import org.apache.logging.log4j.catalog.api.dao.CatalogDao;
+import org.apache.logging.log4j.catalog.git.dao.GitCatalogDao;
+import org.apache.logging.log4j.catalog.security.LocalAuthorizationInterceptor;
+import org.apache.logging.log4j.catalog.jpa.service.ConfigurationService;
+import org.eclipse.jgit.api.TransportConfigCallback;
+import org.eclipse.jgit.transport.JschConfigSessionFactory;
+import org.eclipse.jgit.transport.OpenSshConfig;
+import org.eclipse.jgit.transport.SshSessionFactory;
+import org.eclipse.jgit.transport.SshTransport;
+import org.eclipse.jgit.transport.Transport;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.eclipse.jgit.util.FS;
+import 
org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.support.ResourceBundleMessageSource;
+import org.springframework.http.converter.HttpMessageConverter;
+import 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.servlet.ViewResolver;
+import 
org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import 
org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import 
org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import 
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.view.InternalResourceViewResolver;
+import org.springframework.web.servlet.view.JstlView;
+import org.thymeleaf.spring4.SpringTemplateEngine;
+import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
+import org.thymeleaf.spring4.view.ThymeleafView;
+import org.thymeleaf.spring4.view.ThymeleafViewResolver;
+import org.thymeleaf.templatemode.TemplateMode;
+
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+
+@Configuration
+@EnableWebMvc
+@EnableScheduling
+@ComponentScan(basePackages = {"org.apache.logging.log4j.catalog"})
+@PropertySource("classpath:catalog-${env:}config.properties")
+public class WebMvcAppContext extends WebMvcConfigurerAdapter implements 
ApplicationContextAware {
+
+    @Autowired
+    ConfigurationService configurationService;
+
+    private ApplicationContext applicationContext;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) 
throws BeansException {
+        this.applicationContext = applicationContext;
+    }
+
+    @Override
+    public void 
configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
+        configurer.enable();
+    }
+
+    @Override
+    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
+        super.addResourceHandlers(registry);
+        
registry.addResourceHandler("/images/**").addResourceLocations("/images/");
+        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
+        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
+        
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
+        
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+    }
+
+    @Override
+    public void addViewControllers(ViewControllerRegistry registry) {
+        registry.addViewController("products").setViewName("products");
+        registry.addViewController("categories").setViewName("categories");
+        registry.addViewController("events").setViewName("events");
+        registry.addViewController("attributes").setViewName("attributes");
+    }
+
+    @Override
+    public void configureMessageConverters(List<HttpMessageConverter<?>> 
converters) {
+        converters.add(jsonMessageConverter());
+    }
+
+
+    /*
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(localAuthorizationInterceptor())
+                .addPathPatterns("/**")
+                .excludePathPatterns("/swagger**")
+                .excludePathPatterns("/v2/api-docs**")
+                .excludePathPatterns("/configuration/security**")
+                .excludePathPatterns("/configuration/ui**")
+                .excludePathPatterns("/webjars/**");
+    }
+    */
+
+    @Bean
+    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
+        DefaultAdvisorAutoProxyCreator proxyCreator = new 
DefaultAdvisorAutoProxyCreator();
+        proxyCreator.setProxyTargetClass(true);
+        return proxyCreator;
+    }
+
+    @Bean
+    public ViewResolver internalResourceViewResolver() {
+        InternalResourceViewResolver viewResolver = new 
InternalResourceViewResolver();
+        viewResolver.setViewClass(JstlView.class);
+        viewResolver.setPrefix("/WEB-INF/views/");
+        viewResolver.setSuffix(".jsp");
+        viewResolver.setOrder(10);
+        return viewResolver;
+    }
+
+    @Bean
+    public MessageSource messageSource() {
+        ResourceBundleMessageSource messageSource = new 
ResourceBundleMessageSource();
+        messageSource.setBasename("messages");
+        return messageSource;
+    }
+
+    @Bean
+    public LocalAuthorizationInterceptor localAuthorizationInterceptor() {
+
+        return new 
LocalAuthorizationInterceptor(configurationService.getCatalogServiceAuthToken());
+    }
+
+    @Bean
+    public ObjectMapper objectMapper() {
+        return JsonObjectMapperFactory.createMapper();
+    }
+
+    @Bean
+    public MappingJackson2HttpMessageConverter jsonMessageConverter() {
+        return new MappingJackson2HttpMessageConverter(objectMapper());
+    }
+
+    @Value("${gitUserName")
+    private String gitUserName;
+
+    @Value("${gitPassword:#{null}}")
+    private String gitPassword;
+
+    @Value("${gitPassPhrase:#{null}}")
+    private String gitPassPhrase;
+
+    @Value("${localRepoUrl:#{null}}")
+    private String localRepoUrl;
+
+    @Value("${privateKeyPath:#{null}}")
+    private String privateKeyPath;
+
+    @Value("${remoteRepoUrl}")
+    private String remoteRepoUrl;
+
+    @Value("${remoteRepoCatalogPath:#{null}}")
+    private String remoteRepoCatalogPath;
+
+    @Bean
+    public CatalogDao catalogDao() {
+        GitCatalogDao dataSource = new GitCatalogDao();
+        if (isNotBlank(gitUserName) && isNotBlank(gitPassword)) {
+            dataSource.setCredentialsProvider(new 
UsernamePasswordCredentialsProvider(gitUserName, gitPassword));
+        }
+        TransportConfigCallback transportConfigCallback = new 
TransportConfigCallback() {
+            final SshSessionFactory sshSessionFactory = new 
JschConfigSessionFactory() {
+                @Override
+                protected JSch createDefaultJSch( FS fs ) throws JSchException 
{
+                    JSch defaultJSch = super.createDefaultJSch( fs );
+                    if (isNotBlank(privateKeyPath)) {
+                        defaultJSch.addIdentity(privateKeyPath);
+                    }
+                    return defaultJSch;
+                }
+
+                @Override
+                protected void configure(OpenSshConfig.Host host, Session 
session) {
+                    session.setConfig("StrictHostKeyChecking", "no");
+                    if (isNotBlank(gitPassPhrase)) {
+                        session.setUserInfo(new UserInfo() {
+                            @Override
+                            public String getPassphrase() {
+                                return gitPassPhrase;
+                            }
+
+                            @Override
+                            public String getPassword() {return null;}
+
+                            @Override
+                            public boolean promptPassword(String message) 
{return false;}
+
+                            @Override
+                            public boolean promptPassphrase(String message) 
{return true;}
+
+                            @Override
+                            public boolean promptYesNo(String message) {return 
false;}
+
+                            @Override
+                            public void showMessage(String message) {}
+                        });
+
+                    }
+                }
+            };
+            @Override
+            public void configure(Transport transport) {
+                SshTransport sshTransport = ( SshTransport )transport;
+                sshTransport.setSshSessionFactory( sshSessionFactory );
+
+            }
+        };
+        if (isNotBlank(localRepoUrl)) {
+            dataSource.setLocalRepoPath(localRepoUrl);
+        } else {
+            String localRepoPath = System.getProperty("java.io.tmpdir") + 
"/audit/catalog";
+            File file = new File(localRepoPath);
+            File parent = file.getParentFile();
+            parent.mkdirs();
+            dataSource.setLocalRepoPath(localRepoPath);
+        }
+        dataSource.setTransportConfigCallback(transportConfigCallback);
+        dataSource.setRemoteRepoUri(remoteRepoUrl);
+        if (isNotBlank(remoteRepoCatalogPath)) {
+            dataSource.setCatalogPath(remoteRepoCatalogPath);
+        }
+        return dataSource;
+    }
+
+    @Bean
+    public SpringResourceTemplateResolver templateResolver(){
+        // SpringResourceTemplateResolver automatically integrates with 
Spring's own
+        // resource resolution infrastructure, which is highly recommended.
+        SpringResourceTemplateResolver templateResolver = new 
SpringResourceTemplateResolver();
+        templateResolver.setApplicationContext(this.applicationContext);
+        templateResolver.setPrefix("/WEB-INF/templates/");
+        templateResolver.setSuffix(".html");
+        // HTML is the default value, added here for the sake of clarity.
+        templateResolver.setTemplateMode(TemplateMode.HTML);
+        // Template cache is true by default. Set to false if you want
+        // templates to be automatically updated when modified.
+        templateResolver.setCacheable(true);
+        return templateResolver;
+    }
+
+    @Bean
+    public SpringTemplateEngine templateEngine(){
+        // SpringTemplateEngine automatically applies SpringStandardDialect and
+        // enables Spring's own MessageSource message resolution mechanisms.
+        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
+        templateEngine.setTemplateResolver(templateResolver());
+        // Enabling the SpringEL compiler with Spring 4.2.4 or newer can
+        // speed up execution in most scenarios, but might be incompatible
+        // with specific cases when expressions in one template are reused
+        // across different data types, so this flag is "false" by default
+        // for safer backwards compatibility.
+        templateEngine.setEnableSpringELCompiler(true);
+        return templateEngine;
+    }
+
+    @Bean
+    public ThymeleafViewResolver thymeleafViewResolver(){
+        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
+        viewResolver.setTemplateEngine(templateEngine());
+        // NOTE 'order' and 'viewNames' are optional
+        viewResolver.setOrder(1);
+        viewResolver.setViewNames(new String[] {"products", "categories", 
"events", "attributes"});
+        return viewResolver;
+    }
+
+    @Bean
+    @Scope("prototype")
+    public ThymeleafView mainView() {
+        ThymeleafView view = new ThymeleafView("index"); // templateName = 
'main'
+        view.setStaticVariables(
+                Collections.singletonMap("footer", "The ACME Fruit Company"));
+        return view;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/f0884aeb/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/controller/AttributeController.java
----------------------------------------------------------------------
diff --git 
a/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/controller/AttributeController.java
 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/controller/AttributeController.java
new file mode 100644
index 0000000..bd93a00
--- /dev/null
+++ 
b/log4j-catalog/log4j-catalog-war/src/main/java/org/apache/logging/log4j/catalog/controller/AttributeController.java
@@ -0,0 +1,183 @@
+package org.apache.logging.log4j.catalog.controller;
+
+import javax.annotation.PostConstruct;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.catalog.api.Attribute;
+import org.apache.logging.log4j.catalog.api.Constraint;
+import org.apache.logging.log4j.catalog.api.ListResponse;
+import org.apache.logging.log4j.catalog.api.plugins.ConstraintPlugins;
+import org.apache.logging.log4j.catalog.jpa.converter.AttributeConverter;
+import org.apache.logging.log4j.catalog.jpa.converter.AttributeModelConverter;
+import org.apache.logging.log4j.catalog.jpa.model.AttributeModel;
+import org.apache.logging.log4j.catalog.jpa.model.ConstraintModel;
+import org.apache.logging.log4j.catalog.jpa.service.AttributeService;
+import org.modelmapper.ModelMapper;
+import org.modelmapper.TypeToken;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Catalog Product controller
+ */
+
+@RequestMapping(value = "/api/attributes")
+@RestController
+public class AttributeController {
+    private static final Logger LOGGER = LogManager.getLogger();
+    private static ConstraintPlugins constraintPlugins = 
ConstraintPlugins.getInstance();
+
+    private ModelMapper modelMapper = new ModelMapper();
+
+    @Autowired
+    private AttributeService attributeService;
+
+    @Autowired
+    private AttributeModelConverter attributeModelConverter;
+
+    @Autowired
+    private AttributeConverter attributeConverter;
+
+    @PostConstruct
+    public void init() {
+        modelMapper.addConverter(attributeModelConverter);
+    }
+
+    @PostMapping(value = "/list")
+    public ResponseEntity<Map<String, Object>> 
attributeList(@RequestParam(value="jtStartIndex", required=false) Integer 
startIndex,
+                                                             
@RequestParam(value="jtPageSize", required=false) Integer pageSize,
+                                                             
@RequestParam(value="jtSorting", required=false) String sorting) {
+        Type listType = new TypeToken<List<Attribute>>() {}.getType();
+        Map<String, Object> response = new HashMap<>();
+        try {
+            List<Attribute> attributes = null;
+            if (startIndex == null || pageSize == null) {
+                attributes = modelMapper.map(attributeService.getAttributes(), 
listType);
+            } else {
+                int startPage = 0;
+                if (startIndex > 0) {
+                    startPage = startIndex / pageSize;
+                }
+                String sortColumn = "name";
+                String sortDirection = "ASC";
+                if (sorting != null) {
+                    String[] sortInfo = sorting.split(" ");
+                    sortColumn = sortInfo[0];
+                    if (sortInfo.length > 0) {
+                        sortDirection = sortInfo[1];
+                    }
+                }
+                attributes = 
modelMapper.map(attributeService.getAttributes(startPage, pageSize, sortColumn, 
sortDirection), listType);
+            }
+            if (attributes == null) {
+                attributes = new ArrayList<>();
+            }
+            response.put("Result", "OK");
+            response.put("Records", attributes);
+        } catch (Exception ex) {
+            response.put("Result", "FAILURE");
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
+    @PostMapping(value = "/create")
+    public ResponseEntity<Map<String, Object>> createAttribute(@RequestBody 
Attribute attribute) {
+        Map<String, Object> response = new HashMap<>();
+        try {
+            AttributeModel model = attributeConverter.convert(attribute);
+            model = attributeService.saveAttribute(model);
+            Attribute result = attributeModelConverter.convert(model);
+            response.put("Result", "OK");
+            response.put("Records", result);
+        } catch (Exception ex) {
+            response.put("Result", "FAILURE");
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
+    @PostMapping(value = "/update")
+    public ResponseEntity<Map<String, Object>> updateAttribute(@RequestBody 
Attribute attribute) {
+        Map<String, Object> response = new HashMap<>();
+        try {
+            AttributeModel model = attributeConverter.convert(attribute);
+            model = attributeService.saveAttribute(model);
+            Attribute result = attributeModelConverter.convert(model);
+            response.put("Result", "OK");
+            response.put("Records", result);
+        } catch (Exception ex) {
+            response.put("Result", "FAILURE");
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
+    @PostMapping(value = "/delete")
+    public ResponseEntity<Map<String, Object>> deleteAttribute(@RequestBody 
Attribute attribute) {
+        Map<String, Object> response = new HashMap<>();
+        try {
+            attributeService.deleteAttribute(attribute.getId());
+            response.put("Result", "OK");
+        } catch (Exception ex) {
+            response.put("Result", "FAILURE");
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
+    @GetMapping
+    public ResponseEntity<ListResponse<String>> getAttributeNames() {
+        List<AttributeModel> attributes = attributeService.getAttributes();
+        List<String> attributeNames;
+        if (attributes != null) {
+            attributeNames = new ArrayList<>(attributes.size());
+            for (AttributeModel model : attributes) {
+                attributeNames.add(model.getName());
+            }
+        } else {
+            attributeNames = new ArrayList<>();
+        }
+        ListResponse<String> response = new ListResponse<>();
+        response.setResult("OK");
+        response.setData(attributeNames);
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+
+    @PostMapping(value = "/constraints")
+    public ResponseEntity<Map<String, Object>> 
constraintList(@RequestParam("attributeId") Long attributeId) {
+        Type listType = new TypeToken<List<Constraint>>() {}.getType();
+        Map<String, Object> response = new HashMap<>();
+        try {
+            Optional<AttributeModel> optional = 
attributeService.getAttribute(attributeId);
+            List<Constraint> constraints = new ArrayList<>();
+            if (optional.isPresent()) {
+                Set<ConstraintModel> constraintModels = 
optional.get().getConstraints();
+                if (constraintModels != null) {
+                    for (ConstraintModel constraintModel : constraintModels) {
+                        Constraint constraint = new Constraint();
+                        
constraint.setConstraintType(constraintPlugins.findByName(constraintModel.getConstraintType()));
+                        constraint.setValue(constraintModel.getValue());
+                        constraints.add(constraint);
+                    }
+                }
+                response.put("Result", "OK");
+                response.put("Records", constraints);
+            }
+        } catch (Exception ex) {
+            response.put("Result", "FAILURE");
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
+    }
+}

Reply via email to