1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.about.app;
35
36 import static info.magnolia.about.app.AboutView.*;
37
38 import info.magnolia.cms.beans.config.ServerConfiguration;
39 import info.magnolia.cms.pddescriptor.ProductDescriptorExtractor;
40 import info.magnolia.context.MgnlContext;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.init.MagnoliaConfigurationProperties;
43 import info.magnolia.objectfactory.Components;
44
45 import java.io.File;
46 import java.sql.Connection;
47 import java.sql.DatabaseMetaData;
48 import java.sql.DriverManager;
49 import java.sql.PreparedStatement;
50 import java.sql.ResultSet;
51 import java.sql.SQLException;
52
53 import javax.inject.Inject;
54 import javax.jcr.Repository;
55 import javax.jcr.RepositoryException;
56 import javax.naming.Context;
57 import javax.naming.InitialContext;
58 import javax.naming.NamingException;
59 import javax.sql.DataSource;
60 import javax.xml.parsers.SAXParserFactory;
61
62 import org.apache.commons.lang3.StringUtils;
63 import org.apache.jackrabbit.commons.JcrUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66 import org.xml.sax.Attributes;
67 import org.xml.sax.SAXException;
68 import org.xml.sax.helpers.DefaultHandler;
69
70 import com.vaadin.data.Item;
71 import com.vaadin.data.util.ObjectProperty;
72 import com.vaadin.data.util.PropertysetItem;
73
74
75
76
77 public class AboutPresenter {
78
79 private static final Logger log = LoggerFactory.getLogger(AboutPresenter.class);
80
81 static final String COMMUNITY_EDITION_I18N_KEY = "about.app.main.communityEdition";
82 static final String INSTANCE_AUTHOR_I18N_KEY = "about.app.main.instance.author";
83 static final String INSTANCE_PUBLIC_I18N_KEY = "about.app.main.instance.public";
84 static final String UNKNOWN_PROPERTY_I18N_KEY = "about.app.main.unknown";
85
86 private final AboutView view;
87 private final ServerConfiguration serverConfiguration;
88 private final MagnoliaConfigurationProperties magnoliaProperties;
89
90 protected final SimpleTranslator i18n;
91 private final ProductDescriptorExtractor productDescriptorExtractor;
92
93
94 protected Item viewData = new PropertysetItem();
95
96 @Inject
97 public AboutPresenter(AboutView view, ServerConfiguration serverConfiguration, MagnoliaConfigurationProperties magnoliaProperties, SimpleTranslator i18n, ProductDescriptorExtractor productDescriptorExtractor) {
98 this.view = view;
99 this.serverConfiguration = serverConfiguration;
100 this.magnoliaProperties = magnoliaProperties;
101 this.i18n = i18n;
102 this.productDescriptorExtractor = productDescriptorExtractor;
103 }
104
105
106
107
108 @Deprecated
109 public AboutPresenter(AboutView view, ServerConfiguration serverConfiguration, MagnoliaConfigurationProperties magnoliaProperties, SimpleTranslator i18n) {
110 this(view, serverConfiguration, magnoliaProperties, i18n, Components.getComponent(ProductDescriptorExtractor.class));
111 }
112
113 public AboutView start() {
114
115
116 String mgnlEdition = getEditionName();
117 String mgnlVersion = productDescriptorExtractor.get(ProductDescriptorExtractor.VERSION_NUMBER);
118 String authorInstance = serverConfiguration.isAdmin() ?
119 i18n.translate(INSTANCE_AUTHOR_I18N_KEY) :
120 i18n.translate(INSTANCE_PUBLIC_I18N_KEY);
121
122
123 String osInfo = String.format("%s %s (%s)",
124 magnoliaProperties.getProperty("os.name"),
125 magnoliaProperties.getProperty("os.version"),
126 magnoliaProperties.getProperty("os.arch"));
127 String javaInfo = String.format("%s (build %s)",
128 magnoliaProperties.getProperty("java.version"),
129 magnoliaProperties.getProperty("java.runtime.version"));
130 String serverInfo = MgnlContext.getWebContext().getServletContext().getServerInfo();
131
132 String dbInfo = null;
133 String dbDriverInfo = null;
134 Connection connection = null;
135 try {
136 String connectionString[] = getConnectionString();
137
138 String repoHome = magnoliaProperties.getProperty("magnolia.repositories.home");
139 String repoName = getRepoName();
140 connectionString[0] = StringUtils.replace(connectionString[0], "${wsp.home}", repoHome + "/" + repoName + "/workspaces/default");
141 if (connectionString[0].startsWith("jdbc:")) {
142
143 connection = DriverManager.getConnection(connectionString[0], connectionString[1], connectionString[2]);
144 } else if (connectionString[0].startsWith("java:")) {
145
146 Context initialContext = new InitialContext();
147 DataSource datasource = (DataSource) initialContext.lookup(connectionString[0]);
148 if (datasource != null) {
149 connection = datasource.getConnection();
150 } else {
151 log.debug("Failed to lookup datasource.");
152 }
153 }
154 if (connection != null) {
155 DatabaseMetaData meta = connection.getMetaData();
156 dbInfo = meta.getDatabaseProductName() + " " + meta.getDatabaseProductVersion();
157 if (dbInfo.toLowerCase().contains("mysql")) {
158 String engine = getMySQLEngineInfo(connection, connectionString);
159 if (engine != null) {
160 dbInfo += engine;
161 }
162 }
163 dbDriverInfo = meta.getDriverName() + " " + meta.getDriverVersion();
164 } else {
165 dbInfo = i18n.translate(UNKNOWN_PROPERTY_I18N_KEY);
166 }
167 } catch (NamingException e) {
168 log.debug("Failed obtain DB connection through JNDI with {}", e.getMessage(), e);
169 } catch (SQLException e) {
170 log.debug("Failed to read DB and driver info from connection with {}", e.getMessage(), e);
171 } catch (IllegalArgumentException e) {
172 log.debug("Failed to understand DB connection URL with {}", e.getMessage(), e);
173 } finally {
174 if (connection != null) {
175 try {
176 connection.close();
177 } catch (SQLException e) {
178
179 }
180 }
181 }
182
183 String jcrInfo;
184 try {
185 Repository repo = JcrUtils.getRepository();
186 jcrInfo = String.format("%s %s",
187 repo.getDescriptor("jcr.repository.name"),
188 repo.getDescriptor("jcr.repository.version"));
189 } catch (RepositoryException e) {
190 log.debug("JCR repository information is not available", e);
191 jcrInfo = "-";
192 }
193
194
195 addViewProperty(MAGNOLIA_EDITION_KEY, mgnlEdition);
196 addViewProperty(MAGNOLIA_VERSION_KEY, mgnlVersion);
197 addViewProperty(MAGNOLIA_INSTANCE_KEY, authorInstance);
198 addViewProperty(OS_INFO_KEY, osInfo);
199 addViewProperty(JAVA_INFO_KEY, javaInfo);
200 addViewProperty(SERVER_INFO_KEY, serverInfo);
201 addViewProperty(JCR_INFO_KEY, jcrInfo);
202 addViewProperty(DB_INFO_KEY, dbInfo);
203 addViewProperty(DB_DRIVER_INFO_KEY, dbDriverInfo);
204 view.setDataSource(viewData);
205
206 return view;
207 }
208
209
210
211
212 protected void addViewProperty(String key, String value) {
213 String unknownProperty = i18n.translate(UNKNOWN_PROPERTY_I18N_KEY);
214 viewData.addItemProperty(key, new ObjectProperty<>(StringUtils.defaultIfBlank(value, unknownProperty)));
215 }
216
217
218
219
220 protected String getEditionName() {
221
222 return i18n.translate(COMMUNITY_EDITION_I18N_KEY);
223 }
224
225 private String getMySQLEngineInfo(Connection connection, String[] connectionString) {
226 PreparedStatement statement = null;
227 ResultSet resultSet = null;
228 try {
229 statement = connection.prepareStatement("SHOW TABLE STATUS FROM `" + StringUtils.substringAfterLast(connectionString[0], "/") + "`;");
230 resultSet = statement.executeQuery();
231 if (resultSet.next()) {
232 String engine = resultSet.getString("Engine");
233 return " (" + engine + ")";
234 }
235 } catch (SQLException e) {
236
237 } finally {
238 try {
239 if (resultSet != null) {
240 resultSet.close();
241 }
242 if (statement != null) {
243 statement.close();
244 }
245 } catch (SQLException ignored) {
246 }
247 }
248 return null;
249 }
250
251 String[] getConnectionString() {
252 File config = null;
253
254
255 String configuredPath = magnoliaProperties.getProperty("magnolia.repositories.jackrabbit.config");
256 if (configuredPath != null) {
257 if (configuredPath.startsWith("WEB-INF")) {
258 config = new File(magnoliaProperties.getProperty("magnolia.app.rootdir") + "/" + configuredPath);
259 } else {
260 config = new File(configuredPath);
261 }
262 }
263
264
265
266 final String[] connectionString = new String[] { "", "", "" };
267 try {
268 SAXParserFactory.newInstance().newSAXParser().parse(config, new DefaultHandler() {
269 private boolean inPM;
270
271 @Override
272 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
273 super.startElement(uri, localName, qName, attributes);
274 if ("PersistenceManager".equals(qName) || "DataSource".equals(qName)) {
275 inPM = true;
276 }
277 if (inPM && "param".equals(qName)) {
278 if ("url".equals(attributes.getValue("name"))) {
279 connectionString[0] = attributes.getValue("value");
280 }
281 if ("user".equals(attributes.getValue("name"))) {
282 connectionString[1] = attributes.getValue("value");
283 }
284 if ("password".equals(attributes.getValue("name"))) {
285 connectionString[2] = attributes.getValue("value");
286 }
287 }
288 }
289
290 @Override
291 public void endElement(String uri, String localName, String qName) throws SAXException {
292 super.endElement(uri, localName, qName);
293 if ("PersistenceManager".equals(localName) || "DataSource".equals(qName)) {
294 inPM = false;
295 }
296 }
297 });
298 return connectionString;
299 } catch (Exception e) {
300 log.debug("Failed to obtain DB connection info with {}", e.getMessage(), e);
301 }
302 return connectionString;
303 }
304
305 String getRepoName() {
306 String repoConfigPath = magnoliaProperties.getProperty("magnolia.repositories.config");
307 File config = new File(magnoliaProperties.getProperty("magnolia.app.rootdir") + "/" + repoConfigPath);
308 final String[] repoName = new String[1];
309 try {
310 SAXParserFactory.newInstance().newSAXParser().parse(config, new DefaultHandler() {
311 private boolean inRepo;
312
313 @Override
314 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
315 super.startElement(uri, localName, qName, attributes);
316 if ("RepositoryMapping".equals(qName)) {
317 inRepo = true;
318 }
319 if (inRepo && "Map".equals(qName)) {
320 if ("config".equals(attributes.getValue("name"))) {
321 repoName[0] = attributes.getValue("repositoryName");
322 }
323 }
324 }
325
326 @Override
327 public void endElement(String uri, String localName, String qName) throws SAXException {
328 super.endElement(uri, localName, qName);
329 if ("RepositoryMapping".equals(localName)) {
330 inRepo = false;
331 }
332 }
333 });
334 return repoName[0];
335 } catch (Exception e) {
336 log.debug("Failed to obtain repository configuration info with {}", e.getMessage(), e);
337 }
338 return null;
339 }
340 }