1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender.db.jpa;
18
19 import java.lang.reflect.Constructor;
20
21 import javax.persistence.EntityManager;
22 import javax.persistence.EntityManagerFactory;
23 import javax.persistence.EntityTransaction;
24 import javax.persistence.Persistence;
25
26 import org.apache.logging.log4j.core.LogEvent;
27 import org.apache.logging.log4j.core.appender.AppenderLoggingException;
28 import org.apache.logging.log4j.core.appender.ManagerFactory;
29 import org.apache.logging.log4j.core.appender.db.AbstractDatabaseManager;
30
31
32
33
34 public final class JpaDatabaseManager extends AbstractDatabaseManager {
35 private static final JPADatabaseManagerFactory FACTORY = new JPADatabaseManagerFactory();
36
37 private final String entityClassName;
38 private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
39 private final String persistenceUnitName;
40
41 private EntityManagerFactory entityManagerFactory;
42
43 private EntityManager entityManager;
44 private EntityTransaction transaction;
45
46 private JpaDatabaseManager(final String name, final int bufferSize,
47 final Class<? extends AbstractLogEventWrapperEntity> entityClass,
48 final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
49 final String persistenceUnitName) {
50 super(name, bufferSize);
51 this.entityClassName = entityClass.getName();
52 this.entityConstructor = entityConstructor;
53 this.persistenceUnitName = persistenceUnitName;
54 }
55
56 @Override
57 protected void startupInternal() {
58 this.entityManagerFactory = Persistence.createEntityManagerFactory(this.persistenceUnitName);
59 }
60
61 @Override
62 protected void shutdownInternal() {
63 if (this.entityManager != null || this.transaction != null) {
64 this.commitAndClose();
65 }
66 if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
67 this.entityManagerFactory.close();
68 }
69 }
70
71 @Override
72 protected void connectAndStart() {
73 try {
74 this.entityManager = this.entityManagerFactory.createEntityManager();
75 this.transaction = this.entityManager.getTransaction();
76 this.transaction.begin();
77 } catch (final Exception e) {
78 throw new AppenderLoggingException(
79 "Cannot write logging event or flush buffer; manager cannot create EntityManager or transaction.", e
80 );
81 }
82 }
83
84 @Override
85 protected void writeInternal(final LogEvent event) {
86 if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null
87 || this.transaction == null) {
88 throw new AppenderLoggingException(
89 "Cannot write logging event; JPA manager not connected to the database.");
90 }
91
92 AbstractLogEventWrapperEntity entity;
93 try {
94 entity = this.entityConstructor.newInstance(event);
95 } catch (final Exception e) {
96 throw new AppenderLoggingException("Failed to instantiate entity class [" + this.entityClassName + "].", e);
97 }
98
99 try {
100 this.entityManager.persist(entity);
101 } catch (final Exception e) {
102 if (this.transaction != null && this.transaction.isActive()) {
103 this.transaction.rollback();
104 this.transaction = null;
105 }
106 throw new AppenderLoggingException("Failed to insert record for log event in JPA manager: " +
107 e.getMessage(), e);
108 }
109 }
110
111 @Override
112 protected void commitAndClose() {
113 try {
114 if (this.transaction != null && this.transaction.isActive()) {
115 this.transaction.commit();
116 }
117 } catch (final Exception e) {
118 if (this.transaction != null && this.transaction.isActive()) {
119 this.transaction.rollback();
120 }
121 } finally {
122 this.transaction = null;
123 try {
124 if (this.entityManager != null && this.entityManager.isOpen()) {
125 this.entityManager.close();
126 }
127 } catch (final Exception e) {
128 LOGGER.warn("Failed to close entity manager while logging event or flushing buffer.", e);
129 } finally {
130 this.entityManager = null;
131 }
132 }
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146 public static JpaDatabaseManager getJPADatabaseManager(final String name, final int bufferSize,
147 final Class<? extends AbstractLogEventWrapperEntity>
148 entityClass,
149 final Constructor<? extends AbstractLogEventWrapperEntity>
150 entityConstructor,
151 final String persistenceUnitName) {
152
153 return AbstractDatabaseManager.getManager(
154 name, new FactoryData(bufferSize, entityClass, entityConstructor, persistenceUnitName), FACTORY
155 );
156 }
157
158
159
160
161 private static final class FactoryData extends AbstractDatabaseManager.AbstractFactoryData {
162 private final Class<? extends AbstractLogEventWrapperEntity> entityClass;
163 private final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor;
164 private final String persistenceUnitName;
165
166 protected FactoryData(final int bufferSize, final Class<? extends AbstractLogEventWrapperEntity> entityClass,
167 final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
168 final String persistenceUnitName) {
169 super(bufferSize);
170
171 this.entityClass = entityClass;
172 this.entityConstructor = entityConstructor;
173 this.persistenceUnitName = persistenceUnitName;
174 }
175 }
176
177
178
179
180 private static final class JPADatabaseManagerFactory implements ManagerFactory<JpaDatabaseManager, FactoryData> {
181 @Override
182 public JpaDatabaseManager createManager(final String name, final FactoryData data) {
183 return new JpaDatabaseManager(
184 name, data.getBufferSize(), data.entityClass, data.entityConstructor, data.persistenceUnitName
185 );
186 }
187 }
188 }