All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.enioka.jqm.tools.Helpers Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
/**
 * Copyright © 2013 enioka. All rights reserved
 * Authors: Marc-Antoine GOUILLART ([email protected])
 *          Pierre COPPEE ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.enioka.jqm.tools;

import java.io.IOException;
import java.io.InputStream;
import java.security.SecureRandom;
import java.sql.SQLTransientException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

import javax.mail.MessagingException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.NamingManager;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Persistence;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Appender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.RollingFileAppender;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha512Hash;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.util.StringUtils;
import org.hibernate.LazyInitializationException;
import org.hibernate.exception.JDBCConnectionException;

import com.enioka.jqm.jpamodel.Deliverable;
import com.enioka.jqm.jpamodel.DeploymentParameter;
import com.enioka.jqm.jpamodel.GlobalParameter;
import com.enioka.jqm.jpamodel.History;
import com.enioka.jqm.jpamodel.JndiObjectResource;
import com.enioka.jqm.jpamodel.JndiObjectResourceParameter;
import com.enioka.jqm.jpamodel.JobDef;
import com.enioka.jqm.jpamodel.JobInstance;
import com.enioka.jqm.jpamodel.Message;
import com.enioka.jqm.jpamodel.Node;
import com.enioka.jqm.jpamodel.Queue;
import com.enioka.jqm.jpamodel.RPermission;
import com.enioka.jqm.jpamodel.RRole;
import com.enioka.jqm.jpamodel.RUser;
import com.enioka.jqm.jpamodel.State;

/**
 * This is a helper class for internal use only.
 * 
 */
final class Helpers
{
    private static final String PERSISTENCE_UNIT = "jobqueue-api-pu";
    private static Logger jqmlogger = Logger.getLogger(Helpers.class);

    // The one and only EMF in the engine.
    private static Properties props = new Properties();
    private static EntityManagerFactory emf;

    // Resource file contains at least the jqm jdbc connection definition. Static because JNDI root context is common to the whole JVM.
    static String resourceFile = "resources.xml";

    private Helpers()
    {

    }

    /**
     * Get a fresh EM on the jobqueue-api-pu persistence Unit
     * 
     * @return an EntityManager
     */
    static EntityManager getNewEm()
    {
        getEmf();
        return emf.createEntityManager();
    }

    static void setEmf(EntityManagerFactory newEmf)
    {
        emf = newEmf;
    }

    static EntityManagerFactory getEmf()
    {
        if (emf == null)
        {
            emf = createFactory();
        }
        return emf;
    }

    private static EntityManagerFactory createFactory()
    {
        InputStream fis = null;
        try
        {
            Properties p = new Properties();
            fis = Helpers.class.getClassLoader().getResourceAsStream("jqm.properties");
            if (fis != null)
            {
                jqmlogger.trace("A jqm.properties file was found");
                p.load(fis);
                IOUtils.closeQuietly(fis);
                props.putAll(p);
            }
            return Persistence.createEntityManagerFactory(PERSISTENCE_UNIT, props);
        }
        catch (IOException e)
        {
            jqmlogger.fatal("conf/jqm.properties file is invalid", e);
            IOUtils.closeQuietly(fis);
            throw new JqmInitError("Invalid JQM configuration file", e);
        }
        catch (Exception e)
        {
            jqmlogger.fatal("Unable to connect with the database. Maybe your configuration file is wrong. "
                    + "Please check the password or the url in the $JQM_DIR/conf/resources.xml", e);
            throw new JqmInitError("Database connection issue", e);
        }
        finally
        {
            IOUtils.closeQuietly(fis);
        }
    }

    static void closeQuietly(EntityManager em)
    {
        try
        {
            if (em != null)
            {
                if (em.getTransaction().isActive())
                {
                    em.getTransaction().rollback();
                }
                em.close();
            }
        }
        catch (Exception e)
        {
            // fail silently
        }
    }

    static void allowCreateSchema()
    {
        props.put("hibernate.hbm2ddl.auto", "update");
    }

    static void registerJndiIfNeeded()
    {
        try
        {
            JndiContext.createJndiContext();
        }
        catch (NamingException e)
        {
            throw new JqmInitError("Could not register the JNDI provider", e);
        }
    }

    /**
     * For internal test use only 
* WARNING This will invalidate all open EntityManagers! */ static void resetEmf() { if (emf != null) { emf.close(); emf = null; } } static void setLogFileName(String name) { Appender a = Logger.getRootLogger().getAppender("rollingfile"); if (a == null) { return; } RollingFileAppender r = (RollingFileAppender) a; r.setFile("./logs/jqm-" + name + ".log"); r.activateOptions(); } static void setLogLevel(String level) { try { Logger.getRootLogger().setLevel(Level.toLevel(level)); Logger.getLogger("com.enioka").setLevel(Level.toLevel(level)); jqmlogger.info("Setting general log level at " + level + " which translates as log4j level " + Level.toLevel(level)); } catch (Exception e) { jqmlogger.warn("Log level could not be set", e); } } /** * Create a text message that will be stored in the database. Must be called inside a JPA transaction. * * @return the JPA message created */ static Message createMessage(String textMessage, JobInstance jobInstance, EntityManager em) { Message m = new Message(); m.setTextMessage(textMessage); m.setJi(jobInstance.getId()); em.persist(m); return m; } /** * Create a Deliverable inside the database that will track a file created by a JobInstance Must be called from inside a JPA transaction * * @param path * FilePath (relative to a root directory - cf. Node) * @param originalFileName * FileName * @param fileFamily * File family (may be null). E.g.: "daily report" * @param jobId * Job Instance ID * @param em * the EM to use. */ static Deliverable createDeliverable(String path, String originalFileName, String fileFamily, Integer jobId, EntityManager em) { Deliverable j = new Deliverable(); j.setFilePath(path); j.setRandomId(UUID.randomUUID().toString()); j.setFileFamily(fileFamily); j.setJobId(jobId); j.setOriginalFileName(originalFileName); em.persist(j); return j; } /** * Retrieve the value of a single-valued parameter. * * @param key * @param defaultValue * @param em */ static String getParameter(String key, String defaultValue, EntityManager em) { try { GlobalParameter gp = em.createQuery("SELECT n from GlobalParameter n WHERE n.key = :key", GlobalParameter.class) .setParameter("key", key).getSingleResult(); return gp.getValue(); } catch (NoResultException e) { return defaultValue; } } /** * Checks if a parameter exists. If it exists, it is left untouched. If it doesn't, it is created. Only works for parameters which key * is unique. Must be called from within an open JPA transaction. */ static void initSingleParam(String key, String initValue, EntityManager em) { try { em.createQuery("SELECT n from GlobalParameter n WHERE n.key = :key", GlobalParameter.class).setParameter("key", key) .getSingleResult(); return; } catch (NoResultException e) { GlobalParameter gp = new GlobalParameter(); gp.setKey(key); gp.setValue(initValue); em.persist(gp); } catch (NonUniqueResultException e) { // It exists! Nothing to do... } } /** * Checks if a parameter exists. If it exists, it is updated. If it doesn't, it is created. Only works for parameters which key is * unique. Will create a transaction on the given entity manager. */ static void setSingleParam(String key, String value, EntityManager em) { try { em.getTransaction().begin(); GlobalParameter prm = em.createQuery("SELECT n from GlobalParameter n WHERE n.key = :key", GlobalParameter.class) .setParameter("key", key).getSingleResult(); prm.setValue(value); em.getTransaction().commit(); } catch (NoResultException e) { GlobalParameter gp = new GlobalParameter(); gp.setKey(key); gp.setValue(value); em.persist(gp); em.getTransaction().commit(); } } static void checkConfiguration(String nodeName, EntityManager em) { // Node long n = em.createQuery("SELECT COUNT(n) FROM Node n WHERE n.name = :l", Long.class).setParameter("l", nodeName).getSingleResult(); if (n == 0L) { throw new JqmInitError("The node does not exist. It must be referenced (CLI option createnode) before it can be used"); } Node nn = em.createQuery("SELECT n FROM Node n WHERE n.name = :l", Node.class).setParameter("l", nodeName).getSingleResult(); if (!StringUtils.hasText(nn.getDlRepo()) || !StringUtils.hasText(nn.getRepo()) || !StringUtils.hasText(nn.getTmpDirectory())) { throw new JqmInitError( "The node does not have all its paths specified. Check node configuration (or recreate it with the CLI)."); } // Default queue long i = (Long) em.createQuery("SELECT COUNT(qu) FROM Queue qu where qu.defaultQueue = true").getSingleResult(); if (i == 0L) { throw new JqmInitError("There is no default queue. Correct this (for example with CLI option -u, or with the web admin)"); } if (i > 1L) { throw new JqmInitError( "There is more than one default queue. Correct this (for example with CLI option -u, or with the web admin)"); } // Deployment parameters i = (Long) em.createQuery("SELECT COUNT(dp) FROM DeploymentParameter dp WHERE dp.node.name = :localnode", Long.class) .setParameter("localnode", nodeName).getSingleResult(); if (i == 0L) { jqmlogger .warn("This node is not bound to any queue. Either use the GUI to bind it or use CLI option -u to bind it to the default queue"); } // Roles i = em.createQuery("SELECT count(rr) from RRole rr WHERE rr.name = :rr", Long.class).setParameter("rr", "administrator") .getSingleResult(); if (i == 0L) { throw new JqmInitError("The 'administrator' role does not exist. It is needed for the APIs. Run CLI option -u to create it."); } // Mail session i = (Long) em.createQuery("SELECT COUNT(r) FROM JndiObjectResource r WHERE r.name = :nn").setParameter("nn", "mail/default") .getSingleResult(); if (i == 0L) { throw new JqmInitError("Mail session named mail/default does not exist but is required for the engine to run" + ". Use CLI option -u to create an empty one or use the admin web GUI to create it."); } } /** * Creates or updates a node.
* This method makes the assumption metadata is valid. e.g. there MUST be a single default queue.
* Call {@link #updateConfiguration(EntityManager)} before to be sure if necessary. * * @param nodeName * name of the node that should be created or updated (if incompletely defined only) * @param em * an EntityManager on which a transaction will be opened. */ static void updateNodeConfiguration(String nodeName, EntityManager em) { // Node Node n = null; try { n = em.createQuery("SELECT n FROM Node n WHERE n.name = :l", Node.class).setParameter("l", nodeName).getSingleResult(); } catch (NoResultException e) { jqmlogger.info("Node " + nodeName + " does not exist in the configuration and will be created with default values"); em.getTransaction().begin(); n = new Node(); n.setDlRepo(System.getProperty("user.dir") + "/outputfiles/"); n.setName(nodeName); n.setPort(0); n.setRepo(System.getProperty("user.dir") + "/jobs/"); n.setTmpDirectory(System.getProperty("user.dir") + "/tmp/"); n.setRootLogLevel("INFO"); em.persist(n); em.getTransaction().commit(); } // Deployment parameters DeploymentParameter dp = null; long i = (Long) em.createQuery("SELECT COUNT(dp) FROM DeploymentParameter dp WHERE dp.node = :localnode") .setParameter("localnode", n).getSingleResult(); if (i == 0) { jqmlogger.info("As this node is not bound to any queue, it will be set to poll from the default queue with default parameters"); Queue q = em.createQuery("SELECT q FROM Queue q WHERE q.defaultQueue = true", Queue.class).getSingleResult(); em.getTransaction().begin(); dp = new DeploymentParameter(); dp.setNbThread(5); dp.setNode(n); dp.setPollingInterval(1000); dp.setQueue(q); em.persist(dp); em.getTransaction().commit(); } } /** * Creates or updates metadata common to all nodes: default queue, global parameters, roles...
* It is idempotent. It also has the effect of making broken metadata viable again. */ static void updateConfiguration(EntityManager em) { em.getTransaction().begin(); // Default queue Queue q = null; long i = (Long) em.createQuery("SELECT COUNT(qu) FROM Queue qu").getSingleResult(); if (i == 0L) { q = new Queue(); q.setDefaultQueue(true); q.setDescription("default queue"); q.setTimeToLive(1024); q.setName("DEFAULT"); em.persist(q); jqmlogger.info("A default queue was created in the configuration"); } else { try { q = em.createQuery("SELECT q FROM Queue q WHERE q.defaultQueue = true", Queue.class).getSingleResult(); jqmlogger.info("Default queue is named " + q.getName()); } catch (NonUniqueResultException e) { // Faulty configuration, but why not q = em.createQuery("SELECT q FROM Queue q", Queue.class).getResultList().get(0); q.setDefaultQueue(true); jqmlogger.info("Queue " + q.getName() + " was modified to become the default queue as there were mutliple default queue"); } catch (NoResultException e) { // Faulty configuration, but why not q = em.createQuery("SELECT q FROM Queue q", Queue.class).getResultList().get(0); q.setDefaultQueue(true); jqmlogger.warn("Queue " + q.getName() + " was modified to become the default queue as there was no default queue"); } } // Global parameters initSingleParam("mavenRepo", "http://repo1.maven.org/maven2/", em); initSingleParam(Constants.GP_DEFAULT_CONNECTION_KEY, Constants.GP_JQM_CONNECTION_ALIAS, em); initSingleParam("logFilePerLaunch", "true", em); initSingleParam("internalPollingPeriodMs", "60000", em); initSingleParam("disableWsApi", "false", em); initSingleParam("enableWsApiSsl", "false", em); initSingleParam("enableWsApiAuth", "true", em); initSingleParam("enableInternalPki", "true", em); // Roles RRole adminr = createRoleIfMissing(em, "administrator", "all permissions without exception", "*:*"); createRoleIfMissing(em, "config admin", "can read and write all configuration, except security configuration", "node:*", "queue:*", "qmapping:*", "jndi:*", "prm:*", "jd:*"); createRoleIfMissing(em, "config viewer", "can read all configuration except for security configuration", "node:read", "queue:read", "qmapping:read", "jndi:read", "prm:read", "jd:read"); createRoleIfMissing(em, "client", "can use the full client API except reading logs, files and altering position", "node:read", "queue:read", "job_instance:*", "jd:read"); createRoleIfMissing(em, "client power user", "can use the full client API", "node:read", "queue:read", "job_instance:*", "jd:read", "logs:read", "queue_position:create", "files:read"); createRoleIfMissing(em, "client read only", "can query job instances and get their files", "queue:read", "job_instance:read", "logs:read", "files:read"); // Users createUserIfMissing(em, "root", "all powerfull user", adminr); // Mail session i = (Long) em.createQuery("SELECT COUNT(r) FROM JndiObjectResource r WHERE r.name = :nn").setParameter("nn", "mail/default") .getSingleResult(); if (i == 0) { HashMap prms = new HashMap(); prms.put("smtpServerHost", "smtp.gmail.com"); JndiObjectResource res = new JndiObjectResource(); res.setAuth(null); res.setDescription("default parameters used to send e-mails"); res.setFactory("com.enioka.jqm.providers.MailSessionFactory"); res.setName("mail/default"); res.setType("javax.mail.Session"); res.setSingleton(true); em.persist(res); JndiObjectResourceParameter prm = new JndiObjectResourceParameter(); prm.setKey("smtpServerHost"); prm.setValue("smtp.gmail.com"); em.persist(prm); res.getParameters().add(prm); prm.setResource(res); } // Done em.getTransaction().commit(); } static RRole createRoleIfMissing(EntityManager em, String roleName, String description, String... permissions) { try { return em.createQuery("SELECT rr from RRole rr WHERE rr.name = :r", RRole.class).setParameter("r", roleName).getSingleResult(); } catch (NoResultException e) { RRole r = new RRole(); r.setName(roleName); r.setDescription(description); em.persist(r); for (String s : permissions) { RPermission p = new RPermission(); p.setName(s); p.setRole(r); em.persist(p); r.getPermissions().add(p); } return r; } } static RUser createUserIfMissing(EntityManager em, String login, String description, RRole... roles) { RUser res = null; try { res = em.createQuery("SELECT r from RUser r WHERE r.login = :l", RUser.class).setParameter("l", login).getSingleResult(); } catch (NoResultException e) { res = new RUser(); res.setFreeText(description); res.setLogin(login); res.setPassword(String.valueOf((new SecureRandom()).nextInt())); encodePassword(res); em.persist(res); } res.setLocked(false); for (RRole r : res.getRoles()) { r.getUsers().remove(res); } res.getRoles().clear(); for (RRole r : roles) { res.getRoles().add(r); r.getUsers().add(res); } return res; } static void encodePassword(RUser user) { ByteSource salt = new SecureRandomNumberGenerator().nextBytes(); user.setPassword(new Sha512Hash(user.getPassword(), salt, 100000).toHex()); user.setHashSalt(salt.toHex()); } /** * Transaction is not opened nor committed here but needed. * */ static History createHistory(JobInstance job, EntityManager em, State finalState, Calendar endDate) { History h = new History(); h.setId(job.getId()); h.setJd(job.getJd()); h.setApplicationName(job.getJd().getApplicationName()); h.setSessionId(job.getSessionID()); h.setQueue(job.getQueue()); h.setQueueName(job.getQueue().getName()); h.setEnqueueDate(job.getCreationDate()); h.setEndDate(endDate); h.setAttributionDate(job.getAttributionDate()); h.setExecutionDate(job.getExecutionDate()); h.setUserName(job.getUserName()); h.setEmail(job.getEmail()); h.setParentJobId(job.getParentId()); h.setApplication(job.getJd().getApplication()); h.setModule(job.getJd().getModule()); h.setKeyword1(job.getJd().getKeyword1()); h.setKeyword2(job.getJd().getKeyword2()); h.setKeyword3(job.getJd().getKeyword3()); h.setInstanceApplication(job.getApplication()); h.setInstanceKeyword1(job.getKeyword1()); h.setInstanceKeyword2(job.getKeyword2()); h.setInstanceKeyword3(job.getKeyword3()); h.setInstanceModule(job.getModule()); h.setProgress(job.getProgress()); h.setStatus(finalState); h.setNode(job.getNode()); h.setNodeName(job.getNode().getName()); em.persist(h); return h; } static String getMavenVersion() { String res = System.getProperty("mavenVersion"); if (res != null) { return res; } InputStream is = Main.class.getResourceAsStream("/META-INF/maven/com.enioka.jqm/jqm-engine/pom.properties"); Properties p = new Properties(); try { p.load(is); res = p.getProperty("version"); } catch (Exception e) { res = "maven version not found"; jqmlogger.warn("maven version not found", e); } return res; } static JobDef findJobDef(String applicationName, EntityManager em) { try { return em.createQuery("SELECT j FROM JobDef j WHERE j.applicationName = :n", JobDef.class).setParameter("n", applicationName) .getSingleResult(); } catch (NoResultException ex) { return null; } } static Queue findQueue(String qName, EntityManager em) { try { return em.createQuery("SELECT q FROM Queue q WHERE q.name = :name", Queue.class).setParameter("name", qName).getSingleResult(); } catch (NoResultException ex) { return null; } } static void dumpParameters(EntityManager em, Node n) { String terse = getParameter("disableVerboseStartup", "false", em); if ("false".equals(terse)) { jqmlogger.info("Global cluster parameters are as follow:"); List prms = em.createQuery("SELECT gp FROM GlobalParameter gp", GlobalParameter.class).getResultList(); for (GlobalParameter prm : prms) { jqmlogger.info(String.format("\t%1$s = %2$s", prm.getKey(), prm.getValue())); } jqmlogger.info("Node parameters are as follow:"); jqmlogger.info("\tfile produced storage directory: " + n.getDlRepo()); jqmlogger.info("\tHTTP listening interface: " + n.getDns()); jqmlogger.info("\tlooks for payloads inside: " + n.getRepo()); jqmlogger.info("\tlog level: " + n.getRootLogLevel()); jqmlogger.info("\ttemp files will be created inside: " + n.getTmpDirectory()); jqmlogger.info("\tJMX registry port: " + n.getJmxRegistryPort()); jqmlogger.info("\tJMX server port: " + n.getJmxServerPort()); jqmlogger.info("\tHTTP listening port: " + n.getPort()); jqmlogger.info("\tAPI admin enabled: " + n.getLoadApiAdmin()); jqmlogger.info("\tAPI client enabled: " + n.getLoadApiClient()); jqmlogger.info("\tAPI simple enabled: " + n.getLoapApiSimple()); jqmlogger.info("Node polling parameters are as follow:"); List dps = em .createQuery("SELECT dp FROM DeploymentParameter dp WHERE dp.node.id = :n", DeploymentParameter.class) .setParameter("n", n.getId()).getResultList(); // Pollers for (DeploymentParameter dp : dps) { jqmlogger.info("\t" + dp.getQueue().getName() + " - every " + dp.getPollingInterval() + "ms - maximum " + dp.getNbThread() + " concurrent threads"); } } } /** * Send a mail message using a JNDI resource.
* As JNDI resource providers are inside the EXT class loader, this uses reflection. This method is basically a bonus on top of the * MailSessionFactory offered to payloads, making it accessible also to the engine. * * @param to * @param subject * @param body * @param mailSessionJndiAlias * @throws MessagingException */ @SuppressWarnings({ "unchecked", "rawtypes" }) static void sendMessage(String to, String subject, String body, String mailSessionJndiAlias) throws MessagingException { jqmlogger.debug("sending mail to " + to + " - subject is " + subject); ClassLoader extLoader = getExtClassLoader(); ClassLoader old = Thread.currentThread().getContextClassLoader(); Object mailSession = null; try { mailSession = InitialContext.doLookup(mailSessionJndiAlias); } catch (NamingException e) { throw new MessagingException("could not find mail session description", e); } try { Thread.currentThread().setContextClassLoader(extLoader); Class transportZ = extLoader.loadClass("javax.mail.Transport"); Class sessionZ = extLoader.loadClass("javax.mail.Session"); Class mimeMessageZ = extLoader.loadClass("javax.mail.internet.MimeMessage"); Class messageZ = extLoader.loadClass("javax.mail.Message"); Class recipientTypeZ = extLoader.loadClass("javax.mail.Message$RecipientType"); Object msg = mimeMessageZ.getConstructor(sessionZ).newInstance(mailSession); mimeMessageZ.getMethod("setRecipients", recipientTypeZ, String.class).invoke(msg, recipientTypeZ.getField("TO").get(null), to); mimeMessageZ.getMethod("setSubject", String.class).invoke(msg, subject); mimeMessageZ.getMethod("setText", String.class).invoke(msg, body); transportZ.getMethod("send", messageZ).invoke(null, msg); jqmlogger.trace("Mail was sent"); } catch (Exception e) { throw new MessagingException("an exception occurred during mail sending", e); } finally { Thread.currentThread().setContextClassLoader(old); } } static void sendEndMessage(JobInstance ji) { try { String message = "The Job number " + ji.getId() + " finished correctly\n\n" + "Job description:\n" + "- Job definition: " + ji.getJd().getApplicationName() + "\n" + "- Parent: " + ji.getParentId() + "\n" + "- User name: " + ji.getUserName() + "\n" + "- Session ID: " + ji.getSessionID() + "\n" + "- Queue: " + ji.getQueue().getName() + "\n" + "- Node: " + ji.getNode().getName() + "\n" + "Best regards,\n"; sendMessage(ji.getEmail(), "[JQM] Job: " + ji.getId() + " ENDED", message, "mail/default"); } catch (Exception e) { jqmlogger.warn("Could not send email. Job has nevertheless run correctly", e); } } static ClassLoader getExtClassLoader() { try { return ((JndiContext) NamingManager.getInitialContext(null)).getExtCl(); } catch (NamingException e) { // Don't do anything - this actually cannot happen. Death to checked exceptions. return null; } } static boolean testDbFailure(Exception e) { return (e instanceof LazyInitializationException) || (e instanceof JDBCConnectionException) || (e.getCause() instanceof JDBCConnectionException) || (e.getCause() != null && e.getCause().getCause() instanceof JDBCConnectionException) || (e.getCause() instanceof SQLTransientException) || (e.getCause() != null && e.getCause().getCause() instanceof SQLTransientException) || (e.getCause() != null && e.getCause().getCause() != null && e.getCause().getCause().getCause() instanceof SQLTransientException) || (e.getCause() != null && e.getCause().getCause() != null && e.getCause().getCause().getCause() != null && e.getCause() .getCause().getCause().getCause() instanceof SQLTransientException); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy