View Javadoc

1   /**
2    * This file Copyright (c) 2013-2014 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.about.app;
35  
36  import info.magnolia.cms.beans.config.ServerConfiguration;
37  import info.magnolia.cms.license.LicenseFileExtractor;
38  import info.magnolia.context.MgnlContext;
39  import info.magnolia.i18nsystem.SimpleTranslator;
40  import info.magnolia.init.MagnoliaConfigurationProperties;
41  
42  import java.io.File;
43  import java.sql.Connection;
44  import java.sql.DatabaseMetaData;
45  import java.sql.DriverManager;
46  import java.sql.PreparedStatement;
47  import java.sql.ResultSet;
48  import java.sql.SQLException;
49  
50  import javax.inject.Inject;
51  import javax.jcr.Repository;
52  import javax.jcr.RepositoryException;
53  import javax.xml.parsers.SAXParserFactory;
54  
55  import org.apache.commons.lang.StringUtils;
56  import org.apache.jackrabbit.commons.JcrUtils;
57  import org.slf4j.Logger;
58  import org.slf4j.LoggerFactory;
59  import org.xml.sax.Attributes;
60  import org.xml.sax.SAXException;
61  import org.xml.sax.helpers.DefaultHandler;
62  
63  import com.vaadin.data.Item;
64  import com.vaadin.data.util.ObjectProperty;
65  import com.vaadin.data.util.PropertysetItem;
66  
67  /**
68   * The AboutPresenter.
69   */
70  public class AboutPresenter {
71  
72      private static final Logger log = LoggerFactory.getLogger(AboutPresenter.class);
73  
74      private final AboutView view;
75  
76      private final ServerConfiguration serverConfiguration;
77      private final MagnoliaConfigurationProperties magnoliaProperties;
78  
79      protected final SimpleTranslator i18n;
80  
81      // Object to transport data prepared in the presenter to the view
82      protected Item viewData = new PropertysetItem();
83  
84      @Inject
85      public AboutPresenter(AboutView view, ServerConfiguration serverConfiguration, MagnoliaConfigurationProperties magnoliaProperties, SimpleTranslator i18n) {
86          this.view = view;
87          this.serverConfiguration = serverConfiguration;
88          this.magnoliaProperties = magnoliaProperties;
89          this.i18n = i18n;
90      }
91  
92      public AboutView start() {
93  
94          // magnolia information
95          LicenseFileExtractor licenseProperties = LicenseFileExtractor.getInstance();
96          String mgnlEdition = getEditionName();
97          String mgnlVersion = licenseProperties.get(LicenseFileExtractor.VERSION_NUMBER);
98          String authorInstance = serverConfiguration.isAdmin() ?
99                  i18n.translate("about.app.main.instance.author") :
100                 i18n.translate("about.app.main.instance.public");
101 
102         // system information
103         String osInfo = String.format("%s %s (%s)",
104                 magnoliaProperties.getProperty("os.name"),
105                 magnoliaProperties.getProperty("os.version"),
106                 magnoliaProperties.getProperty("os.arch"));
107         String javaInfo = String.format("%s (build %s)",
108                 magnoliaProperties.getProperty("java.version"),
109                 magnoliaProperties.getProperty("java.runtime.version"));
110         String serverInfo = MgnlContext.getWebContext().getServletContext().getServerInfo();
111 
112         String dbInfo;
113         String dbDriverInfo;
114         Connection connection = null;
115         try {
116 
117             String connectionString[] = getConnectionString();
118 
119             String repoHome = magnoliaProperties.getProperty("magnolia.repositories.home");
120             String repoName = getRepoName();
121             connectionString[0] = StringUtils.replace(connectionString[0], "${wsp.home}", repoHome + "/" + repoName + "/workspaces/default");
122             connection = DriverManager.getConnection(connectionString[0], connectionString[1], connectionString[2]);
123             DatabaseMetaData meta = connection.getMetaData();
124             dbInfo = meta.getDatabaseProductName() + " " + meta.getDatabaseProductVersion();
125             if (dbInfo.toLowerCase().indexOf("mysql") != -1) {
126                 String engine = getMySQLEngineInfo(connection, connectionString);
127                 if (engine != null) {
128                     dbInfo += engine;
129                 }
130             }
131             dbDriverInfo = meta.getDriverName() + " " + meta.getDriverVersion();
132 
133         } catch (SQLException e) {
134             log.debug("Failed to read DB and driver info from connection with {}", e.getMessage(), e);
135             dbInfo = i18n.translate("about.app.main.unknown");
136             dbDriverInfo = dbInfo;
137         } finally {
138             if (connection != null) {
139                 try {
140                     connection.close();
141                 } catch (SQLException e) {
142                     // ignore, nothing we can do
143                 }
144             }
145         }
146 
147         String jcrInfo;
148         try {
149             Repository repo = JcrUtils.getRepository();
150             jcrInfo = String.format("%s %s",
151                     repo.getDescriptor("jcr.repository.name"),
152                     repo.getDescriptor("jcr.repository.version"));
153         } catch (RepositoryException e) {
154             log.debug("JCR repository information is not available", e);
155             jcrInfo = "-";
156         }
157 
158         // Prepare information for the view
159         viewData.addItemProperty(AboutView.MAGNOLIA_EDITION_KEY, new ObjectProperty<String>(mgnlEdition));
160         viewData.addItemProperty(AboutView.MAGNOLIA_VERSION_KEY, new ObjectProperty<String>(mgnlVersion));
161         viewData.addItemProperty(AboutView.MAGNOLIA_INSTANCE_KEY, new ObjectProperty<String>(authorInstance));
162         viewData.addItemProperty(AboutView.OS_INFO_KEY, new ObjectProperty<String>(osInfo));
163         viewData.addItemProperty(AboutView.JAVA_INFO_KEY, new ObjectProperty<String>(javaInfo));
164         viewData.addItemProperty(AboutView.SERVER_INFO_KEY, new ObjectProperty<String>(serverInfo));
165         viewData.addItemProperty(AboutView.JCR_INFO_KEY, new ObjectProperty<String>(jcrInfo));
166         viewData.addItemProperty(AboutView.DB_INFO_KEY, new ObjectProperty<String>(dbInfo));
167         viewData.addItemProperty(AboutView.DB_DRIVER_INFO_KEY, new ObjectProperty<String>(dbDriverInfo));
168         view.setDataSource(viewData);
169 
170         return view;
171     }
172 
173     /**
174      * Returns the name of the edition.
175      */
176     protected String getEditionName() {
177         // Hard code this in CE edition - value will be correctly populated for EE in EnterpriseAboutPresenter
178         return i18n.translate("about.app.main.communityEdition");
179     }
180 
181     private String getMySQLEngineInfo(Connection connection, String[] connectionString) {
182         PreparedStatement statement = null;
183         ResultSet resultSet = null;
184         try {
185             statement = connection.prepareStatement("SHOW TABLE STATUS FROM `" + StringUtils.substringAfterLast(connectionString[0], "/") + "`;");
186             resultSet = statement.executeQuery();
187             if (resultSet.next()) {
188                 String engine = resultSet.getString("Engine");
189                 return " (" + engine + ")";
190             }
191         } catch (SQLException e) {
192             // can't get extra info, oh well
193         } finally {
194             try {
195                 if (resultSet != null) {
196                     resultSet.close();
197                 }
198                 if (statement != null) {
199                     statement.close();
200                 }
201             } catch (SQLException e) {
202             }
203         }
204         return null;
205     }
206 
207     String[] getConnectionString() {
208         File config = null;
209         // Assuming, the path to the repository-config.-file is configured relative, starting with WEB-INF.
210         // Otherwise, assuming it's an absolute path for this config. (See JIRA MGNLUI-3163)
211         String configuredPath = magnoliaProperties.getProperty("magnolia.repositories.jackrabbit.config");
212         if(configuredPath!=null){
213             if(configuredPath.startsWith("WEB-INF")){
214                 config = new File(magnoliaProperties.getProperty("magnolia.app.rootdir") + "/" +configuredPath);
215             }else {
216                 config = new File(configuredPath);
217             }
218         }
219         // No special handling here if the config (file) is null or not existing.
220         // If the path is wrong or not set, Magnolia won't start up properly and it won't be possible to launch the About-app.
221 
222        final String[] connectionString = new String[3];
223         try {
224             SAXParserFactory.newInstance().newSAXParser().parse(config, new DefaultHandler() {
225                 private boolean inPM;
226 
227                 @Override
228                 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
229                     super.startElement(uri, localName, qName, attributes);
230                     if ("PersistenceManager".equals(qName) || "DataSource".equals(qName)) {
231                         inPM = true;
232                     }
233                     if (inPM && "param".equals(qName)) {
234                         if ("url".equals(attributes.getValue("name"))) {
235                             connectionString[0] = attributes.getValue("value");
236                         }
237                         if ("user".equals(attributes.getValue("name"))) {
238                             connectionString[1] = attributes.getValue("value");
239                         }
240                         if ("password".equals(attributes.getValue("name"))) {
241                             connectionString[2] = attributes.getValue("value");
242                         }
243                     }
244                 }
245 
246                 @Override
247                 public void endElement(String uri, String localName, String qName) throws SAXException {
248                     super.endElement(uri, localName, qName);
249                     if ("PersistenceManager".equals(localName) || "DataSource".equals(qName)) {
250                         inPM = false;
251                     }
252                 }
253             });
254             return connectionString;
255         } catch (Exception e) {
256             log.debug("Failed to obtain DB connection info with {}", e.getMessage(), e);
257         }
258         return null;
259     }
260 
261     String getRepoName() {
262         String repoConfigPath = magnoliaProperties.getProperty("magnolia.repositories.config");
263         File config = new File(magnoliaProperties.getProperty("magnolia.app.rootdir") + "/" + repoConfigPath);
264         final String[] repoName = new String[1];
265         try {
266             SAXParserFactory.newInstance().newSAXParser().parse(config, new DefaultHandler() {
267                 private boolean inRepo;
268 
269                 @Override
270                 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
271                     super.startElement(uri, localName, qName, attributes);
272                     if ("RepositoryMapping".equals(qName)) {
273                         inRepo = true;
274                     }
275                     if (inRepo && "Map".equals(qName)) {
276                         if ("config".equals(attributes.getValue("name"))) {
277                             repoName[0] = attributes.getValue("repositoryName");
278                         }
279                     }
280                 }
281 
282                 @Override
283                 public void endElement(String uri, String localName, String qName) throws SAXException {
284                     super.endElement(uri, localName, qName);
285                     if ("RepositoryMapping".equals(localName)) {
286                         inRepo = false;
287                     }
288                 }
289             });
290             return repoName[0];
291         } catch (Exception e) {
292             log.debug("Failed to obtain repository configuration info with {}", e.getMessage(), e);
293         }
294         return null;
295     }
296 }