1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.mongodb2;
18
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Method;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import org.apache.logging.log4j.Logger;
25 import org.apache.logging.log4j.core.Core;
26 import org.apache.logging.log4j.core.appender.nosql.NoSqlProvider;
27 import org.apache.logging.log4j.core.config.plugins.Plugin;
28 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
29 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
30 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
31 import org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
32 import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
33 import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
34 import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
35 import org.apache.logging.log4j.core.filter.AbstractFilterable;
36 import org.apache.logging.log4j.core.util.NameUtil;
37 import org.apache.logging.log4j.status.StatusLogger;
38 import org.apache.logging.log4j.util.LoaderUtil;
39 import org.apache.logging.log4j.util.Strings;
40
41 import com.mongodb.DB;
42 import com.mongodb.MongoClient;
43 import com.mongodb.MongoCredential;
44 import com.mongodb.ServerAddress;
45 import com.mongodb.WriteConcern;
46
47
48
49
50 @Plugin(name = "MongoDb2", category = Core.CATEGORY_NAME, printObject = true)
51 @PluginAliases("MongoDb")
52 public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
53
54 public static class Builder<B extends Builder<B>> extends AbstractFilterable.Builder<B>
55 implements org.apache.logging.log4j.core.util.Builder<MongoDbProvider> {
56
57 private static WriteConcern toWriteConcern(final String writeConcernConstant,
58 final String writeConcernConstantClassName) {
59 WriteConcern writeConcern;
60 if (Strings.isNotEmpty(writeConcernConstant)) {
61 if (Strings.isNotEmpty(writeConcernConstantClassName)) {
62 try {
63 final Class<?> writeConcernConstantClass = LoaderUtil.loadClass(writeConcernConstantClassName);
64 final Field field = writeConcernConstantClass.getField(writeConcernConstant);
65 writeConcern = (WriteConcern) field.get(null);
66 } catch (final Exception e) {
67 LOGGER.error("Write concern constant [{}.{}] not found, using default.",
68 writeConcernConstantClassName, writeConcernConstant);
69 writeConcern = DEFAULT_WRITE_CONCERN;
70 }
71 } else {
72 writeConcern = WriteConcern.valueOf(writeConcernConstant);
73 if (writeConcern == null) {
74 LOGGER.warn("Write concern constant [{}] not found, using default.", writeConcernConstant);
75 writeConcern = DEFAULT_WRITE_CONCERN;
76 }
77 }
78 } else {
79 writeConcern = DEFAULT_WRITE_CONCERN;
80 }
81 return writeConcern;
82 }
83
84 @PluginBuilderAttribute
85 @ValidHost
86 private String server = "localhost";
87
88 @PluginBuilderAttribute
89 @ValidPort
90 private String port = "" + DEFAULT_PORT;
91
92 @PluginBuilderAttribute
93 @Required(message = "No database name provided")
94 private String databaseName;
95
96 @PluginBuilderAttribute
97 @Required(message = "No collection name provided")
98 private String collectionName;
99
100 @PluginBuilderAttribute
101 private String userName;
102
103 @PluginBuilderAttribute(sensitive = true)
104 private String password;
105
106 @PluginBuilderAttribute("capped")
107 private boolean isCapped = false;
108
109 @PluginBuilderAttribute
110 private int collectionSize = DEFAULT_COLLECTION_SIZE;
111
112 @PluginBuilderAttribute
113 private String factoryClassName;
114
115 @PluginBuilderAttribute
116 private String factoryMethodName;
117
118 @PluginBuilderAttribute
119 private String writeConcernConstantClassName;
120
121 @PluginBuilderAttribute
122 private String writeConcernConstant;
123
124 @Override
125 public MongoDbProvider build() {
126 DB database;
127 String description;
128 if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
129 try {
130 final Class<?> factoryClass = LoaderUtil.loadClass(factoryClassName);
131 final Method method = factoryClass.getMethod(factoryMethodName);
132 final Object object = method.invoke(null);
133
134 if (object instanceof DB) {
135 database = (DB) object;
136 } else if (object instanceof MongoClient) {
137 if (Strings.isNotEmpty(databaseName)) {
138 database = ((MongoClient) object).getDB(databaseName);
139 } else {
140 LOGGER.error("The factory method [{}.{}()] returned a MongoClient so the database name is "
141 + "required.", factoryClassName, factoryMethodName);
142 return null;
143 }
144 } else if (object == null) {
145 LOGGER.error("The factory method [{}.{}()] returned null.", factoryClassName, factoryMethodName);
146 return null;
147 } else {
148 LOGGER.error("The factory method [{}.{}()] returned an unsupported type [{}].", factoryClassName,
149 factoryMethodName, object.getClass().getName());
150 return null;
151 }
152
153 description = "database=" + database.getName();
154 final List<ServerAddress> addresses = database.getMongo().getAllAddress();
155 if (addresses.size() == 1) {
156 description += ", server=" + addresses.get(0).getHost() + ", port=" + addresses.get(0).getPort();
157 } else {
158 description += ", servers=[";
159 for (final ServerAddress address : addresses) {
160 description += " { " + address.getHost() + ", " + address.getPort() + " } ";
161 }
162 description += "]";
163 }
164 } catch (final ClassNotFoundException e) {
165 LOGGER.error("The factory class [{}] could not be loaded.", factoryClassName, e);
166 return null;
167 } catch (final NoSuchMethodException e) {
168 LOGGER.error("The factory class [{}] does not have a no-arg method named [{}].", factoryClassName,
169 factoryMethodName, e);
170 return null;
171 } catch (final Exception e) {
172 LOGGER.error("The factory method [{}.{}()] could not be invoked.", factoryClassName, factoryMethodName,
173 e);
174 return null;
175 }
176 } else if (Strings.isNotEmpty(databaseName)) {
177 final List<MongoCredential> credentials = new ArrayList<>();
178 description = "database=" + databaseName;
179 if (Strings.isNotEmpty(userName) && Strings.isNotEmpty(password)) {
180 description += ", username=" + userName + ", passwordHash="
181 + NameUtil.md5(password + MongoDbProvider.class.getName());
182 credentials.add(MongoCredential.createCredential(userName, databaseName, password.toCharArray()));
183 }
184 try {
185 final int portInt = TypeConverters.convert(port, int.class, DEFAULT_PORT);
186 description += ", server=" + server + ", port=" + portInt;
187 database = new MongoClient(new ServerAddress(server, portInt), credentials).getDB(databaseName);
188 } catch (final Exception e) {
189 LOGGER.error(
190 "Failed to obtain a database instance from the MongoClient at server [{}] and " + "port [{}].",
191 server, port);
192 return null;
193 }
194 } else {
195 LOGGER.error("No factory method was provided so the database name is required.");
196 return null;
197 }
198
199 try {
200 database.getCollectionNames();
201 } catch (final Exception e) {
202 LOGGER.error(
203 "The database is not up, or you are not authenticated, try supplying a username and password to the MongoDB provider.",
204 e);
205 return null;
206 }
207
208 final WriteConcern writeConcern = toWriteConcern(writeConcernConstant, writeConcernConstantClassName);
209
210 return new MongoDbProvider(database, writeConcern, collectionName, isCapped, collectionSize, description);
211 }
212
213 public B setCapped(final boolean isCapped) {
214 this.isCapped = isCapped;
215 return asBuilder();
216 }
217
218 public B setCollectionName(final String collectionName) {
219 this.collectionName = collectionName;
220 return asBuilder();
221 }
222
223 public B setCollectionSize(final int collectionSize) {
224 this.collectionSize = collectionSize;
225 return asBuilder();
226 }
227
228 public B setDatabaseName(final String databaseName) {
229 this.databaseName = databaseName;
230 return asBuilder();
231 }
232
233 public B setFactoryClassName(final String factoryClassName) {
234 this.factoryClassName = factoryClassName;
235 return asBuilder();
236 }
237
238 public B setFactoryMethodName(final String factoryMethodName) {
239 this.factoryMethodName = factoryMethodName;
240 return asBuilder();
241 }
242
243 public B setPassword(final String password) {
244 this.password = password;
245 return asBuilder();
246 }
247
248 public B setPort(final String port) {
249 this.port = port;
250 return asBuilder();
251 }
252
253 public B setServer(final String server) {
254 this.server = server;
255 return asBuilder();
256 }
257
258 public B setUserName(final String userName) {
259 this.userName = userName;
260 return asBuilder();
261 }
262
263 public B setWriteConcernConstant(final String writeConcernConstant) {
264 this.writeConcernConstant = writeConcernConstant;
265 return asBuilder();
266 }
267
268 public B setWriteConcernConstantClassName(final String writeConcernConstantClassName) {
269 this.writeConcernConstantClassName = writeConcernConstantClassName;
270 return asBuilder();
271 }
272 }
273 private static final WriteConcern DEFAULT_WRITE_CONCERN = WriteConcern.ACKNOWLEDGED;
274 private static final Logger LOGGER = StatusLogger.getLogger();
275 private static final int DEFAULT_PORT = 27017;
276
277 private static final int DEFAULT_COLLECTION_SIZE = 536870912;
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 @Deprecated
302 public static MongoDbProvider createNoSqlProvider(
303 final String collectionName,
304 final String writeConcernConstant,
305 final String writeConcernConstantClassName,
306 final String databaseName,
307 final String server,
308 final String port,
309 final String userName,
310 final String password,
311 final String factoryClassName,
312 final String factoryMethodName) {
313 LOGGER.info("createNoSqlProvider");
314 return newBuilder().setCollectionName(collectionName).setWriteConcernConstant(writeConcernConstantClassName)
315 .setWriteConcernConstant(writeConcernConstant).setDatabaseName(databaseName).setServer(server)
316 .setPort(port).setUserName(userName).setPassword(password).setFactoryClassName(factoryClassName)
317 .setFactoryMethodName(factoryMethodName).build();
318 }
319 @PluginBuilderFactory
320 public static <B extends Builder<B>> B newBuilder() {
321 return new Builder<B>().asBuilder();
322 }
323 private final String collectionName;
324 private final DB database;
325 private final String description;
326
327 private final WriteConcern writeConcern;
328
329 private final boolean isCapped;
330
331 private final Integer collectionSize;
332
333 private MongoDbProvider(final DB database, final WriteConcern writeConcern, final String collectionName,
334 final boolean isCapped, final Integer collectionSize, final String description) {
335 this.database = database;
336 this.writeConcern = writeConcern;
337 this.collectionName = collectionName;
338 this.isCapped = isCapped;
339 this.collectionSize = collectionSize;
340 this.description = "mongoDb{ " + description + " }";
341 }
342
343 @Override
344 public MongoDbConnection getConnection() {
345 return new MongoDbConnection(this.database, this.writeConcern, this.collectionName, this.isCapped, this.collectionSize);
346 }
347
348 @Override
349 public String toString() {
350 return this.description;
351 }
352 }