You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/11/29 13:47:49 UTC

[syncope] branch 2_1_X updated: [SYNCOPE-1511] Enhancements for PostgreSQL JSONB and MySQL JSON

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/2_1_X by this push:
     new f320dff  [SYNCOPE-1511] Enhancements for PostgreSQL JSONB and MySQL JSON
f320dff is described below

commit f320dff58d5f98c60ea6716755d491148eaec372
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Fri Nov 29 14:47:15 2019 +0100

    [SYNCOPE-1511] Enhancements for PostgreSQL JSONB and MySQL JSON
---
 archetype/pom.xml                                  |   5 +-
 .../apache/syncope/common/lib/to/AuditEntryTO.java |  15 +-
 .../syncope/common/lib/types/AuditLoggerName.java  |   2 +-
 .../syncope/common/rest/api/beans/AuditQuery.java  | 150 +++++++++++-----
 .../syncope/common/rest/api/beans/TaskQuery.java   |   2 -
 .../common/rest/api/service/AuditService.java      |   4 +-
 .../org/apache/syncope/core/logic/AuditLogic.java  |  14 +-
 .../syncope/core/logic/init/LoggerLoader.java      |  22 ++-
 .../syncope/core/persistence/api/dao/AuditDAO.java |  20 ++-
 .../core/persistence/api/entity/AuditEntry.java    |   5 +-
 .../jpa/dao/AbstractJPAJSONAuditDAO.java           | 125 +++++++++++++
 .../persistence/jpa/dao/MyJPAJSONAuditDAO.java     |  53 ++++++
 .../persistence/jpa/dao/PGJPAJSONAuditDAO.java     |  59 ++++++
 .../src/main/resources/audit/audit_myjson.sql}     |   6 +-
 .../src/main/resources/audit/audit_pgjsonb.sql}    |   5 +-
 .../resources/myjson/domains/Master.properties     |   2 +-
 .../main/resources/myjson/persistence.properties   |   1 +
 .../resources/pgjsonb/domains/Master.properties    |   2 +-
 .../main/resources/pgjsonb/persistence.properties  |   1 +
 .../core/persistence/jpa/dao/JPAAuditDAO.java      | 200 +++++++++++----------
 .../src/main/resources/audit/audit.sql             |   2 -
 .../src/main/resources/audit/audit_sqlserver.sql   |   9 +-
 .../src/main/resources/persistence.properties      |   1 +
 .../src/main/resources/persistenceContext.xml      |   1 +
 .../core/provisioning/api/AuditEntryImpl.java      |  26 +--
 .../provisioning/api/data/AuditDataBinder.java     |   2 +-
 .../java/data/AuditDataBinderImpl.java             |  28 +--
 .../java/job/report/AuditReportlet.java            |   4 +-
 .../core/rest/cxf/service/AuditServiceImpl.java    |   7 +-
 .../src/main/resources/persistence.properties.all  |   1 +
 .../main/resources/persistence.properties.myjson   |   1 +
 .../main/resources/persistence.properties.pgjsonb  |   1 +
 .../src/main/resources/persistence.properties      |   1 +
 fit/core-reference/pom.xml                         |   5 +-
 .../resources/elasticsearch/persistence.properties |   1 +
 .../resources/myjson/domains/Master.properties     |   2 +-
 .../src/main/resources/oracle/Dockerfile           |   2 +-
 .../resources/pgjsonb/domains/Master.properties    |   2 +-
 .../org/apache/syncope/fit/core/AuditITCase.java   |  17 +-
 .../systemadministration/dbms.adoc                 |  26 ++-
 40 files changed, 579 insertions(+), 253 deletions(-)

diff --git a/archetype/pom.xml b/archetype/pom.xml
index a83babb..07b6aa1 100644
--- a/archetype/pom.xml
+++ b/archetype/pom.xml
@@ -42,7 +42,7 @@ under the License.
       <extension>
         <groupId>org.apache.maven.archetype</groupId>
         <artifactId>archetype-packaging</artifactId>
-        <version>3.1.1</version>
+        <version>3.1.2</version>
       </extension>
     </extensions>
 
@@ -51,7 +51,7 @@ under the License.
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-archetype-plugin</artifactId>
-          <version>3.1.1</version>
+          <version>3.1.2</version>
           <extensions>true</extensions>
         </plugin>
       </plugins>
@@ -146,6 +146,7 @@ under the License.
         <directory>../core/persistence-jpa-json/src/main/resources/</directory>
         <includes>
           <include>META-INF/*</include>
+          <include>audit/*</include>
         </includes>
         <targetPath>${project.build.outputDirectory}/archetype-resources/core/src/main/resources</targetPath>
       </resource>
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AuditEntryTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AuditEntryTO.java
index fbaf0ca..9d183e6 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AuditEntryTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AuditEntryTO.java
@@ -18,21 +18,18 @@
  */
 package org.apache.syncope.common.lib.to;
 
-import org.apache.syncope.common.lib.BaseBean;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.BaseBean;
 
 @XmlRootElement(name = "audit")
 @XmlType
-public class AuditEntryTO extends BaseBean implements EntityTO  {
-    private static final long serialVersionUID = 1215115961911228005L;
+public class AuditEntryTO extends BaseBean implements EntityTO {
 
-    private final List<String> inputs = new ArrayList<>();
+    private static final long serialVersionUID = 1215115961911228005L;
 
     private String who;
 
@@ -44,6 +41,8 @@ public class AuditEntryTO extends BaseBean implements EntityTO  {
 
     private String before;
 
+    private final List<String> inputs = new ArrayList<>();
+
     private String output;
 
     private Date date;
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
index da30563..a8d6f2a 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
@@ -43,7 +43,7 @@ public class AuditLoggerName implements Serializable {
         return domain + "." + loggerName;
     }
 
-    private final AuditElements.EventCategoryType type;
+    private final EventCategoryType type;
 
     private final String category;
 
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
index 5523afa..5992024 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/AuditQuery.java
@@ -18,66 +18,49 @@
  */
 package org.apache.syncope.common.rest.api.beans;
 
-import javax.ws.rs.QueryParam;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Schema;
 import java.util.ArrayList;
 import java.util.List;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.QueryParam;
 import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.rest.api.service.JAXRSService;
 
 public class AuditQuery extends AbstractQuery {
 
     private static final long serialVersionUID = -2863334226169614417L;
 
-    private String key;
-
-    private final List<AuditElements.Result> results = new ArrayList<>();
-
-    private final List<String> events = new ArrayList<>();
-
-    public String getKey() {
-        return key;
-    }
-
-    @QueryParam("key")
-    public void setKey(final String key) {
-        this.key = key;
-    }
-
-    public List<AuditElements.Result> getResults() {
-        return results;
-    }
+    public static class Builder extends AbstractQuery.Builder<AuditQuery, Builder> {
 
-    @QueryParam("results")
-    public void setResults(final List<AuditElements.Result> results) {
-        if (results != null) {
-            this.results.addAll(results);
+        public Builder(final String entityKey) {
+            super();
+            getInstance().setEntityKey(entityKey);
         }
-    }
 
-    public List<String> getEvents() {
-        return events;
-    }
-
-    @QueryParam("events")
-    public void setEvents(final List<String> events) {
-        if (events != null) {
-            this.events.addAll(events);
+        @Override
+        protected AuditQuery newInstance() {
+            return new AuditQuery();
         }
-    }
 
-    public static class Builder extends AbstractQuery.Builder<AuditQuery, Builder> {
+        public Builder type(final AuditElements.EventCategoryType type) {
+            getInstance().setType(type);
+            return this;
+        }
 
-        public Builder key(final String keyword) {
-            getInstance().setKey(keyword);
+        public Builder category(final String category) {
+            getInstance().setCategory(category);
             return this;
         }
 
-        public Builder results(final List<AuditElements.Result> results) {
-            getInstance().setResults(results);
+        public Builder subcategory(final String subcategory) {
+            getInstance().setSubcategory(subcategory);
             return this;
         }
 
-        public Builder result(final AuditElements.Result result) {
-            getInstance().getResults().add(result);
+        public Builder event(final String event) {
+            getInstance().getEvents().add(event);
             return this;
         }
 
@@ -86,14 +69,91 @@ public class AuditQuery extends AbstractQuery {
             return this;
         }
 
-        public Builder event(final String event) {
-            getInstance().getEvents().add(event);
+        public Builder result(final AuditElements.Result result) {
+            getInstance().setResult(result);
             return this;
         }
+    }
 
-        @Override
-        protected AuditQuery newInstance() {
-            return new AuditQuery();
+    private String entityKey;
+
+    private AuditElements.EventCategoryType type;
+
+    private String category;
+
+    private String subcategory;
+
+    private final List<String> events = new ArrayList<>();
+
+    private AuditElements.Result result;
+
+    @Parameter(name = JAXRSService.PARAM_ENTITY_KEY, description = "audit entity key to match", schema =
+            @Schema(implementation = String.class, example = "50592942-73ec-44c4-a377-e859524245e4"))
+    public String getEntityKey() {
+        return entityKey;
+    }
+
+    @NotNull
+    @QueryParam(JAXRSService.PARAM_ENTITY_KEY)
+    public void setEntityKey(final String entityKey) {
+        this.entityKey = entityKey;
+    }
+
+    @Parameter(name = "type", description = "audit type to match", schema =
+            @Schema(implementation = AuditElements.EventCategoryType.class))
+    public AuditElements.EventCategoryType getType() {
+        return type;
+    }
+
+    @QueryParam("type")
+    public void setType(final AuditElements.EventCategoryType type) {
+        this.type = type;
+    }
+
+    @Parameter(name = "category", description = "audit category to match", schema =
+            @Schema(implementation = String.class))
+    public String getCategory() {
+        return category;
+    }
+
+    @QueryParam("category")
+    public void setCategory(final String category) {
+        this.category = category;
+    }
+
+    @Parameter(name = "subcategory", description = "audit subcategory to match", schema =
+            @Schema(implementation = String.class))
+    public String getSubcategory() {
+        return subcategory;
+    }
+
+    @QueryParam("subcategory")
+    public void setSubcategory(final String subcategory) {
+        this.subcategory = subcategory;
+    }
+
+    @Parameter(name = "result", description = "audit result to match", schema =
+            @Schema(implementation = AuditElements.Result.class))
+    public AuditElements.Result getResult() {
+        return result;
+    }
+
+    @QueryParam("result")
+    public void setResult(final AuditElements.Result result) {
+        this.result = result;
+    }
+
+    @Parameter(name = "events", description = "audit events(s) to match", array =
+            @ArraySchema(uniqueItems = true, schema =
+                    @Schema(implementation = String.class)))
+    public List<String> getEvents() {
+        return events;
+    }
+
+    @QueryParam("events")
+    public void setEvents(final List<String> events) {
+        if (events != null) {
+            this.events.addAll(events);
         }
     }
 }
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
index c2d44a1..9955e5d 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
@@ -131,8 +131,6 @@ public class TaskQuery extends AbstractQuery {
         return entityKey;
     }
 
-    @Parameter(name = JAXRSService.PARAM_RESOURCE, description = " key", schema =
-            @Schema(implementation = String.class, example = "resource-ldap"))
     @QueryParam(JAXRSService.PARAM_ENTITY_KEY)
     public void setEntityKey(final String entityKey) {
         this.entityKey = entityKey;
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuditService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuditService.java
index 897131e..5035494 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuditService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuditService.java
@@ -38,7 +38,7 @@ import javax.ws.rs.core.MediaType;
 @Tag(name = "Audits")
 @SecurityRequirements({
     @SecurityRequirement(name = "BasicAuthentication"),
-    @SecurityRequirement(name = "Bearer")})
+    @SecurityRequirement(name = "Bearer") })
 @Path("audits")
 public interface AuditService {
 
@@ -49,6 +49,6 @@ public interface AuditService {
      * @return paged list of objects matching the given query
      */
     @GET
-    @Produces({MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML})
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     PagedResult<AuditEntryTO> search(@BeanParam AuditQuery auditQuery);
 }
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
index 2b532f0..b43c3b1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AuditLogic.java
@@ -46,17 +46,21 @@ public class AuditLogic extends AbstractTransactionalLogic<AuditEntryTO> {
     @PreAuthorize("hasRole('" + StandardEntitlement.AUDIT_SEARCH + "')")
     @Transactional(readOnly = true)
     public Pair<Integer, List<AuditEntryTO>> search(
-            final String key,
+            final String entityKey,
             final int page,
             final int size,
-            final List<AuditElements.Result> results,
+            final AuditElements.EventCategoryType type,
+            final String category,
+            final String subcategory,
             final List<String> events,
+            final AuditElements.Result result,
             final List<OrderByClause> orderByClauses) {
 
-        Integer count = auditDAO.count(key);
-        List<AuditEntry> matching = auditDAO.findByEntityKey(key, page, size, results, events, orderByClauses);
+        Integer count = auditDAO.count(entityKey);
+        List<AuditEntry> matching = auditDAO.findByEntityKey(
+                entityKey, page, size, type, category, subcategory, events, result, orderByClauses);
         List<AuditEntryTO> searchResults = matching.stream().
-                map(binder::getAuditTO).
+                map(auditEntry -> binder.getAuditTO(entityKey, auditEntry)).
                 collect(Collectors.toList());
         return Pair.of(count, searchResults);
     }
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
index 0f864b5..4a8a66b 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/LoggerLoader.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.logic.init;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.sql.Timestamp;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -31,7 +32,6 @@ import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.db.ColumnMapping;
 import org.apache.logging.log4j.core.appender.db.jdbc.AbstractConnectionSource;
-import org.apache.logging.log4j.core.appender.db.jdbc.ColumnConfig;
 import org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender;
 import org.apache.logging.log4j.core.appender.rewrite.RewriteAppender;
 import org.apache.logging.log4j.core.config.LoggerConfig;
@@ -80,19 +80,18 @@ public class LoggerLoader implements SyncopeLoader {
                 });
 
         // Audit table and DataSource for each configured domain
-        ColumnConfig[] columnConfigs = {
-            ColumnConfig.newBuilder().
-            setConfiguration(ctx.getConfiguration()).setName("EVENT_DATE").setEventTimestamp(true).build(),
-            ColumnConfig.newBuilder().setUnicode(false).
+        ColumnMapping[] columnMappings = {
+            ColumnMapping.newBuilder().
+            setConfiguration(ctx.getConfiguration()).setName("EVENT_DATE").setType(Timestamp.class).build(),
+            ColumnMapping.newBuilder().
             setConfiguration(ctx.getConfiguration()).setName("LOGGER_LEVEL").setPattern("%level").build(),
-            ColumnConfig.newBuilder().setUnicode(false).
+            ColumnMapping.newBuilder().
             setConfiguration(ctx.getConfiguration()).setName("LOGGER").setPattern("%logger").build(),
-            ColumnConfig.newBuilder().setUnicode(false).
-            setConfiguration(ctx.getConfiguration()).setName("MESSAGE").setPattern("%message").build(),
-            ColumnConfig.newBuilder().setUnicode(false).
+            ColumnMapping.newBuilder().
+            setConfiguration(ctx.getConfiguration()).setName(AuditDAO.MESSAGE_COLUMN).setPattern("%message").build(),
+            ColumnMapping.newBuilder().
             setConfiguration(ctx.getConfiguration()).setName("THROWABLE").setPattern("%ex{full}").build()
         };
-        ColumnMapping[] columnMappings = new ColumnMapping[0];
 
         domainsHolder.getDomains().forEach((key, value) -> {
             Appender appender = ctx.getConfiguration().getAppender("audit_for_" + key);
@@ -102,8 +101,7 @@ public class LoggerLoader implements SyncopeLoader {
                         setIgnoreExceptions(false).
                         setConnectionSource(new DataSourceConnectionSource(key, value)).
                         setBufferSize(0).
-                        setTableName(AuditDAO.TABLE_NAME).
-                        setColumnConfigs(columnConfigs).
+                        setTableName(AuditDAO.TABLE).
                         setColumnMappings(columnMappings).
                         build();
                 appender.start();
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
index 3f1994c..5a78787 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AuditDAO.java
@@ -26,12 +26,20 @@ import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
 public interface AuditDAO {
 
-    String TABLE_NAME = "SYNCOPEAUDIT";
+    String TABLE = "SYNCOPEAUDIT";
 
-    List<AuditEntry> findByEntityKey(String key, int page, int size,
-                                     List<AuditElements.Result> results,
-                                     List<String> events,
-                                     List<OrderByClause> orderByClauses);
+    String MESSAGE_COLUMN = "MESSAGE";
 
-    Integer count(String key);
+    List<AuditEntry> findByEntityKey(
+            String entityKey,
+            int page,
+            int size,
+            AuditElements.EventCategoryType type,
+            String category,
+            String subcategory,
+            List<String> events,
+            AuditElements.Result result,
+            List<OrderByClause> orderByClauses);
+
+    int count(String key);
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AuditEntry.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AuditEntry.java
index 7bcb134..2b10e43 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AuditEntry.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AuditEntry.java
@@ -18,10 +18,9 @@
  */
 package org.apache.syncope.core.persistence.api.entity;
 
-import org.apache.syncope.common.lib.types.AuditLoggerName;
-
 import java.io.Serializable;
 import java.util.Date;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
 
 public interface AuditEntry extends Serializable {
 
@@ -38,6 +37,4 @@ public interface AuditEntry extends Serializable {
     String getThrowable();
 
     Date getDate();
-
-    String getKey();
 }
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAuditDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAuditDAO.java
new file mode 100644
index 0000000..a921db1
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractJPAJSONAuditDAO.java
@@ -0,0 +1,125 @@
+/*
+ * 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.syncope.core.persistence.jpa.dao;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.springframework.util.CollectionUtils;
+
+public abstract class AbstractJPAJSONAuditDAO extends JPAAuditDAO {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    protected abstract static class JSONMessageCriteriaBuilder extends MessageCriteriaBuilder {
+
+        protected String entityKey;
+
+        private AuditElements.EventCategoryType type;
+
+        private String category;
+
+        private String subcategory;
+
+        private List<String> events;
+
+        private AuditElements.Result result;
+
+        @Override
+        protected MessageCriteriaBuilder entityKey(final String entityKey) {
+            this.entityKey = entityKey;
+            return this;
+        }
+
+        @Override
+        public MessageCriteriaBuilder type(final AuditElements.EventCategoryType type) {
+            this.type = type;
+            return this;
+        }
+
+        @Override
+        public MessageCriteriaBuilder category(final String category) {
+            this.category = category;
+            return this;
+        }
+
+        @Override
+        public MessageCriteriaBuilder subcategory(final String subcategory) {
+            this.subcategory = subcategory;
+            return this;
+        }
+
+        @Override
+        public MessageCriteriaBuilder events(final List<String> events) {
+            this.events = events;
+            return this;
+        }
+
+        @Override
+        public MessageCriteriaBuilder result(final AuditElements.Result result) {
+            this.result = result;
+            return this;
+        }
+
+        private Optional<ObjectNode> buildContainer() {
+            ObjectNode logger = MAPPER.createObjectNode();
+            if (type != null) {
+                logger.put("type", type.name());
+            }
+            if (StringUtils.isNotBlank(category)) {
+                logger.put("category", category);
+            }
+            if (StringUtils.isNotBlank(subcategory)) {
+                logger.put("subcategory", subcategory);
+            }
+            if (result != null) {
+                logger.put("result", result.name());
+            }
+
+            if (!logger.isEmpty()) {
+                ObjectNode container = MAPPER.createObjectNode();
+                container.set("logger", logger);
+                return Optional.of(container);
+            }
+
+            return Optional.empty();
+        }
+
+        protected abstract String doBuild(List<ObjectNode> containers);
+
+        @Override
+        public String build() {
+            List<ObjectNode> containers = new ArrayList<>();
+            if (CollectionUtils.isEmpty(events)) {
+                buildContainer().ifPresent(containers::add);
+            } else {
+                events.forEach(event -> buildContainer().ifPresent(container -> {
+                    ((ObjectNode) container.get("logger")).put("event", event);
+                    containers.add(container);
+                }));
+            }
+
+            return doBuild(containers);
+        }
+    }
+}
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditDAO.java
new file mode 100644
index 0000000..020069b
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/MyJPAJSONAuditDAO.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.syncope.core.persistence.jpa.dao;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class MyJPAJSONAuditDAO extends AbstractJPAJSONAuditDAO {
+
+    private static class MyMessageCriteriaBuilder extends JSONMessageCriteriaBuilder {
+
+        @Override
+        protected String doBuild(final List<ObjectNode> containers) {
+            query.append('(').append(MESSAGE_COLUMN).append(" -> '$.before' LIKE '%").append(entityKey).
+                    append("%' OR ").append(MESSAGE_COLUMN).append(" -> '$.input' LIKE '%").append(entityKey).
+                    append("%' OR ").append(MESSAGE_COLUMN).append(" -> '$.output' LIKE '%").append(entityKey).
+                    append("%')");
+
+            if (!containers.isEmpty()) {
+                query.append(" AND (").
+                        append(containers.stream().map(container -> "JSON_CONTAINS(" + MESSAGE_COLUMN + ", '"
+                        + POJOHelper.serialize(container).replace("'", "''")
+                        + "')").collect(Collectors.joining(" OR "))).
+                        append(')');
+            }
+
+            return query.toString();
+        }
+    }
+
+    @Override
+    protected MessageCriteriaBuilder messageCriteriaBuilder(final String entityKey) {
+        return new MyMessageCriteriaBuilder().entityKey(entityKey);
+    }
+}
diff --git a/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditDAO.java b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditDAO.java
new file mode 100644
index 0000000..54ea828
--- /dev/null
+++ b/core/persistence-jpa-json/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAJSONAuditDAO.java
@@ -0,0 +1,59 @@
+/*
+ * 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.syncope.core.persistence.jpa.dao;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.syncope.core.persistence.jpa.dao.AbstractJPAJSONAuditDAO.JSONMessageCriteriaBuilder;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAJSONAuditDAO extends AbstractJPAJSONAuditDAO {
+
+    private static class PGMessageCriteriaBuilder extends JSONMessageCriteriaBuilder {
+
+        @Override
+        protected String doBuild(final List<ObjectNode> containers) {
+            query.append('(').append(MESSAGE_COLUMN).append(" ->> 'before' LIKE '%").append(entityKey).
+                    append("%' OR ").append(MESSAGE_COLUMN).append(" ->> 'input' LIKE '%").append(entityKey).
+                    append("%' OR ").append(MESSAGE_COLUMN).append(" ->> 'output' LIKE '%").append(entityKey).
+                    append("%')");
+
+            if (!containers.isEmpty()) {
+                query.append(" AND (").
+                        append(containers.stream().map(container -> MESSAGE_COLUMN + " @> '"
+                        + POJOHelper.serialize(container).replace("'", "''")
+                        + "'::jsonb").collect(Collectors.joining(" OR "))).
+                        append(')');
+            }
+
+            return query.toString();
+        }
+    }
+
+    @Override
+    protected String select() {
+        return MESSAGE_COLUMN + "::text";
+    }
+
+    @Override
+    protected MessageCriteriaBuilder messageCriteriaBuilder(final String entityKey) {
+        return new PGMessageCriteriaBuilder().entityKey(entityKey);
+    }
+}
diff --git a/core/persistence-jpa/src/main/resources/audit/audit.sql b/core/persistence-jpa-json/src/main/resources/audit/audit_myjson.sql
similarity index 95%
copy from core/persistence-jpa/src/main/resources/audit/audit.sql
copy to core/persistence-jpa-json/src/main/resources/audit/audit_myjson.sql
index 44ffb17..af5d37b 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit.sql
+++ b/core/persistence-jpa-json/src/main/resources/audit/audit_myjson.sql
@@ -19,8 +19,6 @@ CREATE TABLE IF NOT EXISTS SYNCOPEAUDIT (
   EVENT_DATE TIMESTAMP,
   LOGGER_LEVEL VARCHAR(255) NOT NULL,
   LOGGER VARCHAR(255) NOT NULL,
-  MESSAGE TEXT NOT NULL,
+  MESSAGE JSON NOT NULL,
   THROWABLE TEXT
-);
-
-COMMIT;
+) ENGINE=InnoDB;
diff --git a/core/persistence-jpa/src/main/resources/audit/audit.sql b/core/persistence-jpa-json/src/main/resources/audit/audit_pgjsonb.sql
similarity index 89%
copy from core/persistence-jpa/src/main/resources/audit/audit.sql
copy to core/persistence-jpa-json/src/main/resources/audit/audit_pgjsonb.sql
index 44ffb17..0edbdf8 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit.sql
+++ b/core/persistence-jpa-json/src/main/resources/audit/audit_pgjsonb.sql
@@ -19,8 +19,7 @@ CREATE TABLE IF NOT EXISTS SYNCOPEAUDIT (
   EVENT_DATE TIMESTAMP,
   LOGGER_LEVEL VARCHAR(255) NOT NULL,
   LOGGER VARCHAR(255) NOT NULL,
-  MESSAGE TEXT NOT NULL,
+  MESSAGE JSONB NOT NULL,
   THROWABLE TEXT
 );
-
-COMMIT;
+CREATE INDEX SYNCOPEAUDIT_idx ON SYNCOPEAUDIT USING gin ((MESSAGE) jsonb_path_ops)
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
index 2197c87..6dfdf26 100644
--- a/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
+++ b/core/persistence-jpa-json/src/main/resources/myjson/domains/Master.properties
@@ -25,4 +25,4 @@ Master.orm=META-INF/spring-orm-myjson.xml
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit_mysql_innodb.sql
+Master.audit.sql=audit_myjson.sql
diff --git a/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
index 31a2dd8..cac21af 100644
--- a/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
+++ b/core/persistence-jpa-json/src/main/resources/myjson/persistence.properties
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa-json/src/main/resources/pgjsonb/domains/Master.properties b/core/persistence-jpa-json/src/main/resources/pgjsonb/domains/Master.properties
index d9a648f..4ab67b0 100644
--- a/core/persistence-jpa-json/src/main/resources/pgjsonb/domains/Master.properties
+++ b/core/persistence-jpa-json/src/main/resources/pgjsonb/domains/Master.properties
@@ -25,4 +25,4 @@ Master.orm=META-INF/spring-orm-pgjsonb.xml
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_pgjsonb.sql
diff --git a/core/persistence-jpa-json/src/main/resources/pgjsonb/persistence.properties b/core/persistence-jpa-json/src/main/resources/pgjsonb/persistence.properties
index 50d568e..c9141cf 100644
--- a/core/persistence-jpa-json/src/main/resources/pgjsonb/persistence.properties
+++ b/core/persistence-jpa-json/src/main/resources/pgjsonb/persistence.properties
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
index f76e9e8..be47a81 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAuditDAO.java
@@ -18,128 +18,146 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.sql.Clob;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import javax.persistence.Query;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.AuditElements;
-import org.apache.syncope.core.persistence.api.DomainsHolder;
 import org.apache.syncope.core.persistence.api.dao.AuditDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity;
 import org.apache.syncope.core.provisioning.api.AuditEntryImpl;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import javax.sql.DataSource;
-
-import java.sql.Timestamp;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-@Transactional(rollbackFor = Throwable.class)
-@Repository
 public class JPAAuditDAO extends AbstractDAO<AbstractEntity> implements AuditDAO {
 
-    @Autowired
-    private DomainsHolder domainsHolder;
+    protected static class MessageCriteriaBuilder {
 
-    private static String buildWhereClauseForEntityKey(final String key) {
-        return " WHERE MESSAGE LIKE '%" + key + "%' ";
-    }
+        protected final StringBuilder query = new StringBuilder();
 
-    @Override
-    public List<AuditEntry> findByEntityKey(
-        final String key,
-        final int page,
-        final int itemsPerPage,
-        final List<AuditElements.Result> results,
-        final List<String> events,
-        final List<OrderByClause> orderByClauses) {
-        try {
-            String query = new MessageCriteriaBuilder()
-                .results(results)
-                .events(events)
-                .key(key)
-                .build();
-            String queryString = "SELECT * FROM " + TABLE_NAME + " WHERE " + query;
-            if (!orderByClauses.isEmpty()) {
-                queryString += " ORDER BY " + orderByClauses.stream().
-                    map(orderBy -> orderBy.getField() + ' ' + orderBy.getDirection().name()).
-                    collect(Collectors.joining(","));
-            }
-            JdbcTemplate template = getJdbcTemplate();
-            template.setMaxRows(itemsPerPage);
-            template.setFetchSize(itemsPerPage * (page <= 0 ? 0 : page - 1));
-            return template.query(queryString, (resultSet, i) -> {
-                AuditEntryImpl entry = POJOHelper.deserialize(resultSet.getString("MESSAGE"), AuditEntryImpl.class);
-                String throwable = resultSet.getString("THROWABLE");
-                entry.setThrowable(throwable);
-                Timestamp date = resultSet.getTimestamp("EVENT_DATE");
-                entry.setDate(new Date(date.getTime()));
-                entry.setKey(key);
-                return entry;
-            });
-        } catch (Exception e) {
-            LOG.error("Unable to execute search query to find entity " + key, e);
-        }
-        return Collections.emptyList();
-    }
-
-    @Override
-    public Integer count(final String key) {
-        try {
-            String queryString = "SELECT COUNT(0) FROM " + AuditDAO.TABLE_NAME + buildWhereClauseForEntityKey(key);
-            return Objects.requireNonNull(getJdbcTemplate().queryForObject(queryString, Integer.class));
-        } catch (Exception e) {
-            LOG.error("Unable to execute count query for entity " + key, e);
+        protected MessageCriteriaBuilder entityKey(final String entityKey) {
+            query.append(' ').append(MESSAGE_COLUMN).append(" LIKE '%\"key\":\"").append(entityKey).append("\"%'");
+            return this;
         }
-        return 0;
-    }
 
-    private JdbcTemplate getJdbcTemplate() {
-        String domain = AuthContextUtils.getDomain();
-        DataSource datasource = domainsHolder.getDomains().get(domain);
-        if (datasource == null) {
-            throw new IllegalArgumentException("Could not get to DataSource for domain " + domain);
+        public MessageCriteriaBuilder type(final AuditElements.EventCategoryType type) {
+            if (type != null) {
+                query.append(" AND " + MESSAGE_COLUMN + " LIKE '%\"type\":\"").append(type.name()).append("\"%'");
+            }
+            return this;
         }
-        return new JdbcTemplate(datasource);
-    }
-
-    private static class MessageCriteriaBuilder {
-        private final StringBuilder query = new StringBuilder(" 1=1 ");
 
-        public MessageCriteriaBuilder key(final String key) {
-            query.append(" AND MESSAGE LIKE '%\"key\":\"").append(key).append("\"%' ");
+        public MessageCriteriaBuilder category(final String category) {
+            if (StringUtils.isNotBlank(category)) {
+                query.append(" AND " + MESSAGE_COLUMN + " LIKE '%\"category\":\"").append(category).append("\"%'");
+            }
             return this;
         }
 
-        public MessageCriteriaBuilder results(final List<AuditElements.Result> results) {
-            buildCriteriaFor(results.stream().map(Enum::name).collect(Collectors.toList()), "result");
+        public MessageCriteriaBuilder subcategory(final String subcategory) {
+            if (StringUtils.isNotBlank(subcategory)) {
+                query.append(" AND " + MESSAGE_COLUMN + " LIKE '%\"subcategory\":\"").
+                        append(subcategory).append("\"%'");
+            }
             return this;
         }
 
-        private void buildCriteriaFor(final List<String> items, final String field) {
-            if (!items.isEmpty()) {
-                query.append(" AND ( ");
-                query.append(items.stream().map(res -> "MESSAGE LIKE '%\"" + field + "\":\"" + res + "\"%'")
-                    .collect(Collectors.joining(" OR ")));
-                query.append(" )");
+        public MessageCriteriaBuilder events(final List<String> events) {
+            if (!events.isEmpty()) {
+                query.append(" AND ( ").
+                        append(events.stream().
+                                map(event -> MESSAGE_COLUMN + " LIKE '%\"event\":\"" + event + "\"%'").
+                                collect(Collectors.joining(" OR "))).
+                        append(" )");
             }
+            return this;
         }
 
-        public MessageCriteriaBuilder events(final List<String> events) {
-            buildCriteriaFor(events, "event");
+        public MessageCriteriaBuilder result(final AuditElements.Result result) {
+            if (result != null) {
+                query.append(" AND ").
+                        append(MESSAGE_COLUMN).append(" LIKE '%\"result\":\"").append(result.name()).append("\"%' ");
+            }
             return this;
         }
 
         public String build() {
-            query.trimToSize();
             return query.toString();
         }
     }
+
+    protected MessageCriteriaBuilder messageCriteriaBuilder(final String entityKey) {
+        return new MessageCriteriaBuilder().entityKey(entityKey);
+    }
+
+    protected String select() {
+        return MESSAGE_COLUMN;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<AuditEntry> findByEntityKey(
+            final String entityKey,
+            final int page,
+            final int itemsPerPage,
+            final AuditElements.EventCategoryType type,
+            final String category,
+            final String subcategory,
+            final List<String> events,
+            final AuditElements.Result result,
+            final List<OrderByClause> orderByClauses) {
+
+        String queryString = "SELECT " + select()
+                + " FROM " + TABLE
+                + " WHERE " + messageCriteriaBuilder(entityKey).
+                        type(type).
+                        category(category).
+                        subcategory(subcategory).
+                        result(result).
+                        events(events).
+                        build();
+        if (!orderByClauses.isEmpty()) {
+            queryString += " ORDER BY " + orderByClauses.stream().
+                    map(orderBy -> orderBy.getField() + ' ' + orderBy.getDirection().name()).
+                    collect(Collectors.joining(","));
+        }
+
+        Query query = entityManager().createNativeQuery(queryString);
+        query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
+        if (itemsPerPage >= 0) {
+            query.setMaxResults(itemsPerPage);
+        }
+
+        @SuppressWarnings("unchecked")
+        List<Object> entries = query.getResultList();
+        return entries.stream().map(row -> {
+            String value;
+            if (row instanceof Clob) {
+                Clob clob = (Clob) row;
+                try {
+                    value = clob.getSubString(1, (int) clob.length());
+                } catch (SQLException e) {
+                    LOG.error("Unexpected error reading Audit Entry for entity key {}", entityKey, e);
+                    return null;
+                }
+            } else {
+                value = row.toString();
+            }
+            return POJOHelper.deserialize(value, AuditEntryImpl.class);
+        }).filter(Objects::nonNull).collect(Collectors.toList());
+    }
+
+    @Override
+    public int count(final String key) {
+        String queryString = "SELECT COUNT(0) FROM " + TABLE
+                + " WHERE " + messageCriteriaBuilder(key).build();
+        Query countQuery = entityManager().createNativeQuery(queryString);
+
+        return ((Number) countQuery.getSingleResult()).intValue();
+    }
 }
diff --git a/core/persistence-jpa/src/main/resources/audit/audit.sql b/core/persistence-jpa/src/main/resources/audit/audit.sql
index 44ffb17..1526b50 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit.sql
+++ b/core/persistence-jpa/src/main/resources/audit/audit.sql
@@ -22,5 +22,3 @@ CREATE TABLE IF NOT EXISTS SYNCOPEAUDIT (
   MESSAGE TEXT NOT NULL,
   THROWABLE TEXT
 );
-
-COMMIT;
diff --git a/core/persistence-jpa/src/main/resources/audit/audit_sqlserver.sql b/core/persistence-jpa/src/main/resources/audit/audit_sqlserver.sql
index 191428a..4615af6 100644
--- a/core/persistence-jpa/src/main/resources/audit/audit_sqlserver.sql
+++ b/core/persistence-jpa/src/main/resources/audit/audit_sqlserver.sql
@@ -15,14 +15,13 @@
 -- specific language governing permissions and limitations
 -- under the License.
 
-IF NOT EXISTS
-(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[SYNCOPEAUDIT]') AND type in (N'U'))
-BEGIN
+IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[SYNCOPEAUDIT]') AND OBJECTPROPERTY(id, N'ISUSERTABLE') = 1)
+DROP TABLE [dbo].[SYNCOPEAUDIT];
+
 CREATE TABLE SYNCOPEAUDIT (
   EVENT_DATE DATETIME,
   LOGGER_LEVEL VARCHAR(255) NOT NULL,
   LOGGER VARCHAR(255) NOT NULL,
   MESSAGE TEXT NOT NULL,
   THROWABLE TEXT
-)
-END
+)  ON [PRIMARY];
diff --git a/core/persistence-jpa/src/main/resources/persistence.properties b/core/persistence-jpa/src/main/resources/persistence.properties
index 1ce4a2b..3d10e26 100644
--- a/core/persistence-jpa/src/main/resources/persistence.properties
+++ b/core/persistence-jpa/src/main/resources/persistence.properties
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa/src/main/resources/persistenceContext.xml b/core/persistence-jpa/src/main/resources/persistenceContext.xml
index 577ab78..b37beae 100644
--- a/core/persistence-jpa/src/main/resources/persistenceContext.xml
+++ b/core/persistence-jpa/src/main/resources/persistenceContext.xml
@@ -39,6 +39,7 @@ under the License.
   <bean class="${group.dao}"/>
   <bean class="${anyObject.dao}"/>
   <bean class="${conf.dao}"/>
+  <bean class="${audit.dao}"/>
 
   <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
 
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
index a6fde1b..60541bd 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AuditEntryImpl.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.provisioning.api;
 
+import java.util.Date;
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.commons.lang3.ArrayUtils;
@@ -27,8 +28,6 @@ import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AuditLoggerName;
 import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
-import java.util.Date;
-
 public class AuditEntryImpl implements AuditEntry {
 
     private static final long serialVersionUID = -2299082316063743582L;
@@ -49,15 +48,13 @@ public class AuditEntryImpl implements AuditEntry {
 
     private Date date;
 
-    private String key;
-    
     @JsonCreator
     public AuditEntryImpl(
-        @JsonProperty("who") final String who,
-        @JsonProperty("logger") final AuditLoggerName logger,
-        @JsonProperty("before") final Object before,
-        @JsonProperty("output") final Object output,
-        @JsonProperty("input") final Object[] input) {
+            @JsonProperty("who") final String who,
+            @JsonProperty("logger") final AuditLoggerName logger,
+            @JsonProperty("before") final Object before,
+            @JsonProperty("output") final Object output,
+            @JsonProperty("input") final Object[] input) {
 
         super();
 
@@ -137,20 +134,12 @@ public class AuditEntryImpl implements AuditEntry {
         this.date = date;
     }
 
-    @Override
-    public String getKey() {
-        return key;
-    }
-
-    public void setKey(final String key) {
-        this.key = key;
-    }
-
     public static Builder builder() {
         return new Builder();
     }
 
     public static final class Builder {
+
         private String who;
 
         private AuditLoggerName logger;
@@ -214,7 +203,6 @@ public class AuditEntryImpl implements AuditEntry {
             AuditEntryImpl entry = new AuditEntryImpl(who, logger, before, output, input);
             entry.setDate(date);
             entry.setThrowable(throwable);
-            entry.setKey(key);
             return entry;
         }
     }
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
index 2f79388..082f71f 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/AuditDataBinder.java
@@ -23,5 +23,5 @@ import org.apache.syncope.core.persistence.api.entity.AuditEntry;
 
 public interface AuditDataBinder {
 
-    AuditEntryTO getAuditTO(AuditEntry auditEntry);
+    AuditEntryTO getAuditTO(String key, AuditEntry auditEntry);
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
index 8d74e11..de49702 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AuditDataBinderImpl.java
@@ -31,36 +31,36 @@ import org.springframework.stereotype.Component;
 public class AuditDataBinderImpl implements AuditDataBinder {
 
     @Override
-    public AuditEntryTO getAuditTO(final AuditEntry auditEntry) {
-        AuditEntryTO auditTO = new AuditEntryTO();
-        auditTO.setKey(auditEntry.getKey());
-        auditTO.setWho(auditEntry.getWho());
-        auditTO.setDate(auditEntry.getDate());
-        auditTO.setThrowable(auditEntry.getThrowable());
-        auditTO.setLoggerName(auditEntry.getLogger().toLoggerName());
+    public AuditEntryTO getAuditTO(final String key, final AuditEntry auditEntry) {
+        AuditEntryTO auditEntryTO = new AuditEntryTO();
+        auditEntryTO.setKey(key);
+        auditEntryTO.setWho(auditEntry.getWho());
+        auditEntryTO.setDate(auditEntry.getDate());
+        auditEntryTO.setThrowable(auditEntry.getThrowable());
+        auditEntryTO.setLoggerName(auditEntry.getLogger().toLoggerName());
 
-        auditTO.setSubCategory(auditEntry.getLogger().getSubcategory());
-        auditTO.setEvent(auditEntry.getLogger().getEvent());
+        auditEntryTO.setSubCategory(auditEntry.getLogger().getSubcategory());
+        auditEntryTO.setEvent(auditEntry.getLogger().getEvent());
 
         if (auditEntry.getLogger().getResult() != null) {
-            auditTO.setResult(auditEntry.getLogger().getResult().name());
+            auditEntryTO.setResult(auditEntry.getLogger().getResult().name());
         }
 
         if (auditEntry.getBefore() != null) {
-            auditTO.setBefore(POJOHelper.serialize(auditEntry.getBefore()));
+            auditEntryTO.setBefore(POJOHelper.serialize(auditEntry.getBefore()));
         }
 
         if (auditEntry.getInput() != null) {
-            auditTO.getInputs().addAll(Arrays.stream(auditEntry.getInput()).
+            auditEntryTO.getInputs().addAll(Arrays.stream(auditEntry.getInput()).
                     filter(Objects::nonNull).
                     map(POJOHelper::serialize).
                     collect(Collectors.toList()));
         }
 
         if (auditEntry.getOutput() != null) {
-            auditTO.setOutput(POJOHelper.serialize(auditEntry.getOutput()));
+            auditEntryTO.setOutput(POJOHelper.serialize(auditEntry.getOutput()));
         }
 
-        return auditTO;
+        return auditEntryTO;
     }
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
index 82017c2..d613ffc 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AuditReportlet.java
@@ -49,12 +49,12 @@ public class AuditReportlet extends AbstractReportlet {
     private DataSource datasource;
 
     private void doExtractConf(final ContentHandler handler, final AtomicReference<String> status) throws SAXException {
-        status.set("Fetching " + conf.getSize() + " rows from the " + AuditDAO.TABLE_NAME + " table");
+        status.set("Fetching " + conf.getSize() + " rows from the " + AuditDAO.TABLE + " table");
 
         JdbcTemplate jdbcTemplate = new JdbcTemplate(datasource);
         jdbcTemplate.setMaxRows(conf.getSize());
         List<Map<String, Object>> rows = jdbcTemplate.
-                queryForList("SELECT * FROM " + AuditDAO.TABLE_NAME + " ORDER BY EVENT_DATE DESC");
+                queryForList("SELECT * FROM " + AuditDAO.TABLE + " ORDER BY EVENT_DATE DESC");
 
         handler.startElement("", "", "events", null);
         AttributesImpl atts = new AttributesImpl();
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
index 67126f7..b646f91 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuditServiceImpl.java
@@ -38,11 +38,14 @@ public class AuditServiceImpl extends AbstractServiceImpl implements AuditServic
     @Override
     public PagedResult<AuditEntryTO> search(final AuditQuery auditQuery) {
         Pair<Integer, List<AuditEntryTO>> result = logic.search(
-                auditQuery.getKey(),
+                auditQuery.getEntityKey(),
                 auditQuery.getPage(),
                 auditQuery.getSize(),
-                auditQuery.getResults(),
+                auditQuery.getType(),
+                auditQuery.getCategory(),
+                auditQuery.getSubcategory(),
                 auditQuery.getEvents(),
+                auditQuery.getResult(),
                 getOrderByClauses(auditQuery.getOrderBy()));
         return buildPagedResult(result.getRight(), auditQuery.getPage(), auditQuery.getSize(), result.getLeft());
     }
diff --git a/docker/core/src/main/resources/persistence.properties.all b/docker/core/src/main/resources/persistence.properties.all
index b4e2c81..629e0fd 100644
--- a/docker/core/src/main/resources/persistence.properties.all
+++ b/docker/core/src/main/resources/persistence.properties.all
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAuditDAO
 openjpa.RemoteCommitProvider=${OPENJPA_REMOTE_COMMIT}
diff --git a/docker/core/src/main/resources/persistence.properties.myjson b/docker/core/src/main/resources/persistence.properties.myjson
index 31a2dd8..cac21af 100644
--- a/docker/core/src/main/resources/persistence.properties.myjson
+++ b/docker/core/src/main/resources/persistence.properties.myjson
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/docker/core/src/main/resources/persistence.properties.pgjsonb b/docker/core/src/main/resources/persistence.properties.pgjsonb
index 6da6788..1ec7dcb 100644
--- a/docker/core/src/main/resources/persistence.properties.pgjsonb
+++ b/docker/core/src/main/resources/persistence.properties.pgjsonb
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAuditDAO
 openjpa.RemoteCommitProvider=${OPENJPA_REMOTE_COMMIT}
diff --git a/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties b/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
index dd4b730..2b3db1b 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
+++ b/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/fit/core-reference/pom.xml b/fit/core-reference/pom.xml
index 1249f21..79bfa42 100644
--- a/fit/core-reference/pom.xml
+++ b/fit/core-reference/pom.xml
@@ -1262,13 +1262,14 @@ under the License.
                   </build>
                   <run>
                     <env>
-                      <ORACLE_DISABLE_ASYNCH_IO>true</ORACLE_DISABLE_ASYNCH_IO>
+                      <ORACLE_ALLOW_REMOTE>true</ORACLE_ALLOW_REMOTE>
+                      <ORACLE_ENABLE_XDB>true</ORACLE_ENABLE_XDB>
                     </env>
                     <ports>
                       <port>1521:1521</port>
                     </ports>
                     <wait>
-                      <log>Disconnected from Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production</log>
+                      <log>Disconnected from Oracle Database 11g Express Edition</log>
                       <time>30000</time>
                     </wait>                
                   </run>
diff --git a/fit/core-reference/src/main/resources/elasticsearch/persistence.properties b/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
index dd4b730..2b3db1b 100644
--- a/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
+++ b/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
@@ -24,4 +24,5 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAuditDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/fit/core-reference/src/main/resources/myjson/domains/Master.properties b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
index 2197c87..6dfdf26 100644
--- a/fit/core-reference/src/main/resources/myjson/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/myjson/domains/Master.properties
@@ -25,4 +25,4 @@ Master.orm=META-INF/spring-orm-myjson.xml
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit_mysql_innodb.sql
+Master.audit.sql=audit_myjson.sql
diff --git a/fit/core-reference/src/main/resources/oracle/Dockerfile b/fit/core-reference/src/main/resources/oracle/Dockerfile
index b69d613..11acbec 100644
--- a/fit/core-reference/src/main/resources/oracle/Dockerfile
+++ b/fit/core-reference/src/main/resources/oracle/Dockerfile
@@ -15,6 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-FROM wnameless/oracle-xe-11g
+FROM oracleinanutshell/oracle-xe-11g
 
 ADD init.sql /docker-entrypoint-initdb.d/
diff --git a/fit/core-reference/src/main/resources/pgjsonb/domains/Master.properties b/fit/core-reference/src/main/resources/pgjsonb/domains/Master.properties
index d9a648f..4ab67b0 100644
--- a/fit/core-reference/src/main/resources/pgjsonb/domains/Master.properties
+++ b/fit/core-reference/src/main/resources/pgjsonb/domains/Master.properties
@@ -25,4 +25,4 @@ Master.orm=META-INF/spring-orm-pgjsonb.xml
 Master.pool.maxActive=10
 Master.pool.minIdle=2
 
-Master.audit.sql=audit.sql
+Master.audit.sql=audit_pgjsonb.sql
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
index b7eaeec..3b8b995 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuditITCase.java
@@ -48,7 +48,7 @@ public class AuditITCase extends AbstractITCase {
             i++;
         } while (results.isEmpty() && i < maxWaitSeconds);
         if (results.isEmpty()) {
-            fail("Timeout when executing query for key " + query.getKey());
+            fail("Timeout when executing query for key " + query.getEntityKey());
         }
 
         return results.get(0);
@@ -59,8 +59,7 @@ public class AuditITCase extends AbstractITCase {
         UserTO userTO = createUser(UserITCase.getUniqueSampleTO("audit@syncope.org")).getEntity();
         assertNotNull(userTO.getKey());
 
-        AuditQuery query = new AuditQuery.Builder().
-                key(userTO.getKey()).orderBy("event_date desc").
+        AuditQuery query = new AuditQuery.Builder(userTO.getKey()).orderBy("event_date desc").
                 page(1).size(1).build();
         AuditEntryTO entry = query(query, 50);
         assertEquals(userTO.getKey(), entry.getKey());
@@ -68,15 +67,16 @@ public class AuditITCase extends AbstractITCase {
     }
 
     @Test
-    public void findByUserAndByEventAndByResults() {
+    public void findByUserAndOther() {
         UserTO userTO = createUser(UserITCase.getUniqueSampleTO("audit-2@syncope.org")).getEntity();
         assertNotNull(userTO.getKey());
 
-        AuditQuery query = new AuditQuery.Builder().
-                key(userTO.getKey()).
+        AuditQuery query = new AuditQuery.Builder(userTO.getKey()).
                 orderBy("event_date desc").
                 page(1).
                 size(1).
+                type(AuditElements.EventCategoryType.LOGIC).
+                category("UserLogic").
                 event("create").
                 result(AuditElements.Result.SUCCESS).
                 build();
@@ -90,9 +90,8 @@ public class AuditITCase extends AbstractITCase {
         GroupTO groupTO = createGroup(GroupITCase.getBasicSampleTO("AuditGroup")).getEntity();
         assertNotNull(groupTO.getKey());
 
-        AuditQuery query = new AuditQuery.Builder()
-                .key(groupTO.getKey()).orderBy("event_date desc")
-                .page(1).size(1).build();
+        AuditQuery query = new AuditQuery.Builder(groupTO.getKey()).orderBy("event_date desc").
+                page(1).size(1).build();
         AuditEntryTO entry = query(query, 50);
         assertEquals(groupTO.getKey(), entry.getKey());
         groupService.delete(groupTO.getKey());
diff --git a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/dbms.adoc b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/dbms.adoc
index b0c71f6..814101e 100644
--- a/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/dbms.adoc
+++ b/src/main/asciidoc/reference-guide/workingwithapachesyncope/systemadministration/dbms.adoc
@@ -91,6 +91,7 @@ user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
 group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
 anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
 conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAJSONAuditDAO
 ....
 
 In `provisioning.properties`, replace as follows:
@@ -110,6 +111,7 @@ Master.username=syncope
 Master.password=syncope
 Master.databasePlatform=org.apache.openjpa.jdbc.sql.PostgresDictionary
 Master.orm=META-INF/spring-orm-pgjsonb.xml
+Master.audit.sql=audit_pgjsonb.sql
 ....
 
 [WARNING]
@@ -210,6 +212,21 @@ Add the following dependency to `core/pom.xml`:
 </dependency>
 ----
 
+In `persistence.properties`, replace as follows:
+
+....
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.MyJPAJSONEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONPlainAttrValueDAO
+any.search.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONAnyObjectDAO
+conf.dao=org.apache.syncope.core.persistence.jpa.dao.JPAJSONConfDAO
+audit.dao=org.apache.syncope.core.persistence.jpa.dao.MyJPAJSONAuditDAO
+....
+
 In `provisioning.properties`, replace as follows:
 
 ....
@@ -218,8 +235,7 @@ quartz.sql=tables_mysql_innodb.sql
 ....
 
 [WARNING]
-This assumes that the InnoDB engine is enabled in your MySQL instance - if this is not the case, then change the value
-for `quartz.sql` to `tables_mysql.sql`.
+This assumes that the InnoDB engine is enabled in your MySQL instance.
 
 In `domains/Master.properties` (for the `Master` domain), replace as follows:
 
@@ -231,17 +247,13 @@ Master.username=syncope
 Master.password=syncope
 Master.databasePlatform=org.apache.openjpa.jdbc.sql.MySQLDictionary(blobTypeName=LONGBLOB,dateFractionDigits=3)
 Master.orm=META-INF/spring-orm-myjson.xml
-Master.audit.sql=audit_mysql_innodb.sql
+Master.audit.sql=audit_myjson.sql
 ....
 
 [CAUTION]
 It is important to set the collation to `utf8_general_ci` after creation of `syncope` database.
 
 [WARNING]
-This assumes that the InnoDB engine is enabled in your MySQL instance - if this is not the case, then change the value
-for `Master.audit` to `audit.sql`.
-
-[WARNING]
 This assumes that you have a MySQL instance running on localhost, listening on its default port 3306 with a database
 `syncope` fully accessible by user `syncope` with password `syncope`.