1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.nosql.appender.mongodb;
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.appender.AbstractAppender;
26 import org.apache.logging.log4j.core.config.plugins.Plugin;
27 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
28 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
29 import org.apache.logging.log4j.core.util.Loader;
30 import org.apache.logging.log4j.core.util.NameUtil;
31 import org.apache.logging.log4j.nosql.appender.NoSqlProvider;
32 import org.apache.logging.log4j.status.StatusLogger;
33 import org.apache.logging.log4j.util.Strings;
34
35 import com.mongodb.DB;
36 import com.mongodb.MongoClient;
37 import com.mongodb.MongoCredential;
38 import com.mongodb.ServerAddress;
39 import com.mongodb.WriteConcern;
40
41
42
43
44 @Plugin(name = "MongoDb", category = "Core", printObject = true)
45 public final class MongoDbProvider implements NoSqlProvider<MongoDbConnection> {
46
47 private static final WriteConcern DEFAULT_WRITE_CONCERN = WriteConcern.ACKNOWLEDGED;
48 private static final Logger LOGGER = StatusLogger.getLogger();
49
50 private final String collectionName;
51 private final DB database;
52 private final String description;
53 private final WriteConcern writeConcern;
54
55 private MongoDbProvider(final DB database, final WriteConcern writeConcern, final String collectionName,
56 final String description) {
57 this.database = database;
58 this.writeConcern = writeConcern;
59 this.collectionName = collectionName;
60 this.description = "mongoDb{ " + description + " }";
61 }
62
63 @Override
64 public MongoDbConnection getConnection() {
65 return new MongoDbConnection(this.database, this.writeConcern, this.collectionName);
66 }
67
68 @Override
69 public String toString() {
70 return this.description;
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 @PluginFactory
96 public static MongoDbProvider createNoSqlProvider(
97 @PluginAttribute("collectionName") final String collectionName,
98 @PluginAttribute("writeConcernConstant") final String writeConcernConstant,
99 @PluginAttribute("writeConcernConstantClass") final String writeConcernConstantClassName,
100 @PluginAttribute("databaseName") final String databaseName,
101 @PluginAttribute("server") final String server,
102 @PluginAttribute("port") final String port,
103 @PluginAttribute("userName") final String userName,
104 @PluginAttribute(value = "password", sensitive = true) final String password,
105 @PluginAttribute("factoryClassName") final String factoryClassName,
106 @PluginAttribute("factoryMethodName") final String factoryMethodName) {
107 DB database;
108 String description;
109 if (Strings.isNotEmpty(factoryClassName) && Strings.isNotEmpty(factoryMethodName)) {
110 try {
111 final Class<?> factoryClass = Loader.loadClass(factoryClassName);
112 final Method method = factoryClass.getMethod(factoryMethodName);
113 final Object object = method.invoke(null);
114
115 if (object instanceof DB) {
116 database = (DB) object;
117 } else if (object instanceof MongoClient) {
118 if (Strings.isNotEmpty(databaseName)) {
119 database = ((MongoClient) object).getDB(databaseName);
120 } else {
121 LOGGER.error("The factory method [{}.{}()] returned a MongoClient so the database name is "
122 + "required.", factoryClassName, factoryMethodName);
123 return null;
124 }
125 } else if (object == null) {
126 LOGGER.error("The factory method [{}.{}()] returned null.", factoryClassName, factoryMethodName);
127 return null;
128 } else {
129 LOGGER.error("The factory method [{}.{}()] returned an unsupported type [{}].", factoryClassName,
130 factoryMethodName, object.getClass().getName());
131 return null;
132 }
133
134 description = "database=" + database.getName();
135 final List<ServerAddress> addresses = database.getMongo().getAllAddress();
136 if (addresses.size() == 1) {
137 description += ", server=" + addresses.get(0).getHost() + ", port=" + addresses.get(0).getPort();
138 } else {
139 description += ", servers=[";
140 for (final ServerAddress address : addresses) {
141 description += " { " + address.getHost() + ", " + address.getPort() + " } ";
142 }
143 description += "]";
144 }
145 } catch (final ClassNotFoundException e) {
146 LOGGER.error("The factory class [{}] could not be loaded.", factoryClassName, e);
147 return null;
148 } catch (final NoSuchMethodException e) {
149 LOGGER.error("The factory class [{}] does not have a no-arg method named [{}].", factoryClassName,
150 factoryMethodName, e);
151 return null;
152 } catch (final Exception e) {
153 LOGGER.error("The factory method [{}.{}()] could not be invoked.", factoryClassName, factoryMethodName,
154 e);
155 return null;
156 }
157 } else if (Strings.isNotEmpty(databaseName)) {
158 final List<MongoCredential> credentials = new ArrayList<>();
159 description = "database=" + databaseName;
160 if (Strings.isNotEmpty(userName) && Strings.isNotEmpty(password)) {
161 description += ", username=" + userName + ", passwordHash="
162 + NameUtil.md5(password + MongoDbProvider.class.getName());
163 credentials.add(MongoCredential.createCredential(userName, databaseName, password.toCharArray()));
164 }
165 try {
166 if (Strings.isNotEmpty(server)) {
167 final int portInt = AbstractAppender.parseInt(port, 0);
168 description += ", server=" + server;
169 if (portInt > 0) {
170 description += ", port=" + portInt;
171 database = new MongoClient(new ServerAddress(server, portInt), credentials).getDB(databaseName);
172 } else {
173 database = new MongoClient(new ServerAddress(server), credentials).getDB(databaseName);
174 }
175 } else {
176 database = new MongoClient(new ServerAddress(), credentials).getDB(databaseName);
177 }
178 } catch (final Exception e) {
179 LOGGER.error(
180 "Failed to obtain a database instance from the MongoClient at server [{}] and " + "port [{}].",
181 server, port);
182 return null;
183 }
184 } else {
185 LOGGER.error("No factory method was provided so the database name is required.");
186 return null;
187 }
188
189 try {
190 database.getCollectionNames();
191 } catch (final Exception e) {
192 LOGGER.error(
193 "The database is not up, or you are not authenticated, try supplying a username and password to the MongoDB provider.",
194 e);
195 return null;
196 }
197
198 final WriteConcern writeConcern = toWriteConcern(writeConcernConstant, writeConcernConstantClassName);
199
200 return new MongoDbProvider(database, writeConcern, collectionName, description);
201 }
202
203 private static WriteConcern toWriteConcern(final String writeConcernConstant,
204 final String writeConcernConstantClassName) {
205 WriteConcern writeConcern;
206 if (Strings.isNotEmpty(writeConcernConstant)) {
207 if (Strings.isNotEmpty(writeConcernConstantClassName)) {
208 try {
209 final Class<?> writeConcernConstantClass = Loader.loadClass(writeConcernConstantClassName);
210 final Field field = writeConcernConstantClass.getField(writeConcernConstant);
211 writeConcern = (WriteConcern) field.get(null);
212 } catch (final Exception e) {
213 LOGGER.error("Write concern constant [{}.{}] not found, using default.",
214 writeConcernConstantClassName, writeConcernConstant);
215 writeConcern = DEFAULT_WRITE_CONCERN;
216 }
217 } else {
218 writeConcern = WriteConcern.valueOf(writeConcernConstant);
219 if (writeConcern == null) {
220 LOGGER.warn("Write concern constant [{}] not found, using default.", writeConcernConstant);
221 writeConcern = DEFAULT_WRITE_CONCERN;
222 }
223 }
224 } else {
225 writeConcern = DEFAULT_WRITE_CONCERN;
226 }
227 return writeConcern;
228 }
229 }