package fi.otavanopisto.pyramus; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Resource; import javax.inject.Inject; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.transaction.UserTransaction; import fi.internetix.smvc.controllers.RequestController; import fi.internetix.smvc.controllers.RequestControllerMapper; import fi.internetix.smvc.logging.Logging; import fi.otavanopisto.pyramus.dao.DAOFactory; import fi.otavanopisto.pyramus.dao.SystemDAO; import fi.otavanopisto.pyramus.dao.base.MagicKeyDAO; import fi.otavanopisto.pyramus.dao.plugins.PluginDAO; import fi.otavanopisto.pyramus.dao.plugins.PluginRepositoryDAO; import fi.otavanopisto.pyramus.dao.system.SettingDAO; import fi.otavanopisto.pyramus.dao.system.SettingKeyDAO; import fi.otavanopisto.pyramus.dao.webhooks.WebhookDAO; import fi.otavanopisto.pyramus.domainmodel.base.MagicKey; import fi.otavanopisto.pyramus.domainmodel.base.MagicKeyScope; import fi.otavanopisto.pyramus.domainmodel.plugins.Plugin; import fi.otavanopisto.pyramus.domainmodel.plugins.PluginRepository; import fi.otavanopisto.pyramus.domainmodel.system.Setting; import fi.otavanopisto.pyramus.domainmodel.system.SettingKey; import fi.otavanopisto.pyramus.domainmodel.webhooks.Webhook; import fi.otavanopisto.pyramus.plugin.PluginDescriptor; import fi.otavanopisto.pyramus.plugin.PluginManager; import fi.otavanopisto.pyramus.plugin.auth.AuthenticationProviderVault; import fi.otavanopisto.pyramus.plugin.auth.internal.InternalAuthenticationStrategy; import fi.otavanopisto.pyramus.webhooks.Webhooks; /** * The application context listener responsible of initialization and finalization of the * application. */ public class PyramusServletContextListener implements ServletContextListener { @Inject private Webhooks webhooks; @Inject private WebhookDAO webhookDAO; /** * Called when the application shuts down. * * @param ctx The servlet context event */ public void contextDestroyed(ServletContextEvent ctx) { try { userTransaction.begin(); MagicKeyDAO magicKeyDAO = DAOFactory.getInstance().getMagicKeyDAO(); MagicKey magicKey = magicKeyDAO.findByApplicationScope(); if (magicKey != null) { magicKeyDAO.delete(magicKey); } userTransaction.commit(); } catch (Exception e) { try { userTransaction.rollback(); } catch (Exception e1) { e1.printStackTrace(); } } } /** * Called when the application starts. Sets up both Hibernate and the page and JSON mappers needed * to serve the client requests. * * @param servletContextEvent The servlet context event */ public void contextInitialized(ServletContextEvent servletContextEvent) { try { userTransaction.begin(); MagicKeyDAO magicKeyDAO = DAOFactory.getInstance().getMagicKeyDAO(); String applicationMagicKey = UUID.randomUUID().toString(); MagicKey magicKey = magicKeyDAO.findByApplicationScope(); if (magicKey != null) { magicKeyDAO.updateName(magicKey, applicationMagicKey); } else { magicKeyDAO.create(applicationMagicKey, MagicKeyScope.APPLICATION); } Properties pageControllers = new Properties(); Properties jsonControllers = new Properties(); Properties binaryControllers = new Properties(); ServletContext ctx = servletContextEvent.getServletContext(); String webappPath = ctx.getRealPath("/"); // Load the system settings into the system properties loadSystemSettings(System.getProperties()); // Load default page mappings from properties file loadPropertiesFile(pageControllers, "pagemapping.properties"); // Load default JSON mappings from properties file loadPropertiesFile(jsonControllers, "jsonmapping.properties"); // Load default binary mappings from properties file loadPropertiesFile(binaryControllers, "binarymapping.properties"); // Initialize the page mapper in order to serve page requests RequestControllerMapper.mapControllers(pageControllers, ".page"); // Initialize the JSON mapper in order to serve JSON requests RequestControllerMapper.mapControllers(jsonControllers, ".json"); // Initialize the binary mapper in order to serve binary requests RequestControllerMapper.mapControllers(binaryControllers, ".binary"); // Load plugins here so that plugins can override existing controllers loadPlugins(); // Sets the application directory of the application, used primarily for initial data creation System.getProperties().setProperty("appdirectory", webappPath); // Register internal authentication provider AuthenticationProviderVault.registerAuthenticationProviderClass("internal", InternalAuthenticationStrategy.class); // Initializes all configured authentication strategies AuthenticationProviderVault.getInstance().initializeStrategies(); if ("development".equals(System.getProperties().getProperty("system.environment"))) { trustSelfSignedCerts(); } if ("it".equals(System.getProperties().getProperty("system.environment"))) { reindexHibernateEntities(); } userTransaction.commit(); } catch (Exception e) { try { userTransaction.rollback(); } catch (Exception e1) { e1.printStackTrace(); } e.printStackTrace(); throw new ExceptionInInitializerError(e); } } private void reindexHibernateEntities() { SystemDAO systemDAO = DAOFactory.getInstance().getSystemDAO(); List<Class<?>> indexedEntities = systemDAO.getIndexedEntities(); for (Class<?> indexedEntity : indexedEntities) { try { systemDAO.reindexHibernateSearchObjects(indexedEntity, 200); } catch (InterruptedException e) { Logger.getGlobal().log(Level.SEVERE, "Hibernate entity indexing failed", e); } } } private void loadPropertiesFile(Properties properties, String filename) throws FileNotFoundException, IOException { InputStream resourceStream = getClass().getClassLoader().getResourceAsStream(filename); if (resourceStream == null) { throw new FileNotFoundException("Could not find properties file: " + filename); } properties.load(resourceStream); } private void loadSystemSettings(Properties properties) { SettingDAO settingDAO = DAOFactory.getInstance().getSettingDAO(); SettingKeyDAO settingKeyDAO = DAOFactory.getInstance().getSettingKeyDAO(); List<SettingKey> settingKeys = settingKeyDAO.listAll(); for (SettingKey settingKey : settingKeys) { Setting setting = settingDAO.findByKey(settingKey); if (setting != null) properties.put(settingKey.getName(), setting.getValue()); } } @SuppressWarnings("unchecked") private void loadPlugins() { try { PluginRepositoryDAO pluginRepositoryDAO = DAOFactory.getInstance().getPluginRepositoryDAO(); List<PluginRepository> pluginRepositories = pluginRepositoryDAO.listAll(); PluginManager pluginManager = PluginManager.initialize(getClass().getClassLoader(), pluginRepositories); PluginDAO pluginDAO = DAOFactory.getInstance().getPluginDAO(); List<Plugin> enabledPlugins = pluginDAO.listByEnabled(Boolean.TRUE); for (Plugin plugin : enabledPlugins) { try { pluginManager.loadPlugin(plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion()); } catch (Exception e) { Logging.logException("Failed to load plugin: " + plugin.getGroupId() + "." + plugin.getArtifactId() + ":" + plugin.getVersion(), e); } } pluginManager.registerPlugins(); // Load additional request mappings from plugins List<PluginDescriptor> plugins = pluginManager.getPlugins(); for (PluginDescriptor plugin : plugins) { Map<String, Class<?>> pageRequestControllers = plugin.getPageRequestControllers(); if (pageRequestControllers != null) { for (Map.Entry<String, Class<?>> entry : pageRequestControllers.entrySet()) { String className = entry.getValue().getName(); Class<? extends RequestController> pageController = (Class<? extends RequestController>) Class.forName(className, false, pluginManager.getPluginsClassLoader()); RequestController oldController = RequestControllerMapper.getRequestController(entry.getKey() + ".page"); if (oldController != null) { // Save masked controllers for extending existing functionality by calling // the masked controller's .process() RequestControllerMapper.mapController(entry.getKey(), ".page.masked", oldController); } RequestControllerMapper.mapController(entry.getKey(), ".page", pageController.newInstance()); } } Map<String, Class<?>> jsonRequestControllers = plugin.getJSONRequestControllers(); if (jsonRequestControllers != null) { for (Map.Entry<String, Class<?>> entry : jsonRequestControllers.entrySet()) { String className = entry.getValue().getName(); Class<? extends RequestController> pageController = (Class<? extends RequestController>) Class.forName(className, false, pluginManager.getPluginsClassLoader()); RequestController oldController = RequestControllerMapper.getRequestController(entry.getKey() + ".json"); if (oldController != null) { // Save masked controllers for extending existing functionality by calling // the masked controller's .process() RequestControllerMapper.mapController(entry.getKey(), ".json.masked", oldController); } RequestControllerMapper.mapController(entry.getKey(), ".json", pageController.newInstance()); } } Map<String, Class<?>> binaryRequestControllers = plugin.getBinaryRequestControllers(); if (binaryRequestControllers != null) { for (Map.Entry<String, Class<?>> entry : binaryRequestControllers.entrySet()) { String className = entry.getValue().getName(); Class<? extends RequestController> pageController = (Class<? extends RequestController>) Class.forName(className, false, pluginManager.getPluginsClassLoader()); RequestController oldController = RequestControllerMapper.getRequestController(entry.getKey() + ".binary"); if (oldController != null) { // Save masked controllers for extending existing functionality by calling // the masked controller's .process() RequestControllerMapper.mapController(entry.getKey(), ".binary.masked", oldController); } RequestControllerMapper.mapController(entry.getKey(), ".binary", pageController.newInstance()); } } } } catch (Exception e) { Logging.logException("Plugins loading failed", e); } for (Webhook webhook : webhookDAO.listAll()) { webhooks.addWebhook(webhook.getUrl(), webhook.getSecret()); }; } private static void trustSelfSignedCerts() { try { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) { } } }; SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { } } @Resource private UserTransaction userTransaction; }