mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
No effective change - change newline char
This commit is contained in:
@@ -1,79 +1,79 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Daemon based ScheduleThreadPool.
|
||||
* <p>
|
||||
* Uses Daemon threads and hooks into shutdown event.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private int shutdownWaitSeconds;
|
||||
|
||||
/**
|
||||
* Construct the DaemonScheduleThreadPool.
|
||||
*/
|
||||
public DaemonScheduleThreadPool(int coreSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
|
||||
super(coreSize, new DaemonThreadFactory(namePrefix));
|
||||
this.namePrefix = namePrefix;
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM Runtime.
|
||||
*/
|
||||
public void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonScheduleThreadPool {} shutting down...", namePrefix);
|
||||
super.shutdown();
|
||||
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonScheduleThreadPool shut down timeout exceeded. Terminating running threads.");
|
||||
super.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of " + namePrefix, e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime shutdown.
|
||||
*/
|
||||
private class ShutdownHook extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Daemon based ScheduleThreadPool.
|
||||
* <p>
|
||||
* Uses Daemon threads and hooks into shutdown event.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private int shutdownWaitSeconds;
|
||||
|
||||
/**
|
||||
* Construct the DaemonScheduleThreadPool.
|
||||
*/
|
||||
public DaemonScheduleThreadPool(int coreSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
|
||||
super(coreSize, new DaemonThreadFactory(namePrefix));
|
||||
this.namePrefix = namePrefix;
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM Runtime.
|
||||
*/
|
||||
public void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonScheduleThreadPool {} shutting down...", namePrefix);
|
||||
super.shutdown();
|
||||
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonScheduleThreadPool shut down timeout exceeded. Terminating running threads.");
|
||||
super.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of " + namePrefix, e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime shutdown.
|
||||
*/
|
||||
private class ShutdownHook extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* ThreadFactory for Daemon threads.
|
||||
* <p>
|
||||
* Daemon threads do not stop a JVM stopping. If an application only has Daemon
|
||||
* threads left it will shutdown.
|
||||
* </p>
|
||||
* <p>
|
||||
* In using Daemon threads you need to either not care about being interrupted
|
||||
* on shutdown or register with the JVM shutdown hook to perform a nice shutdown
|
||||
* of the daemon threads etc.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger poolNumber = new AtomicInteger(1);
|
||||
|
||||
private final ThreadGroup group;
|
||||
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
public DaemonThreadFactory(String namePrefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
|
||||
this.namePrefix = namePrefix != null ? namePrefix : "pool-" + poolNumber.getAndIncrement() + "-thread-";
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
|
||||
t.setDaemon(true);
|
||||
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* ThreadFactory for Daemon threads.
|
||||
* <p>
|
||||
* Daemon threads do not stop a JVM stopping. If an application only has Daemon
|
||||
* threads left it will shutdown.
|
||||
* </p>
|
||||
* <p>
|
||||
* In using Daemon threads you need to either not care about being interrupted
|
||||
* on shutdown or register with the JVM shutdown hook to perform a nice shutdown
|
||||
* of the daemon threads etc.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger poolNumber = new AtomicInteger(1);
|
||||
|
||||
private final ThreadGroup group;
|
||||
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
public DaemonThreadFactory(String namePrefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
|
||||
this.namePrefix = namePrefix != null ? namePrefix : "pool-" + poolNumber.getAndIncrement() + "-thread-";
|
||||
}
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
|
||||
t.setDaemon(true);
|
||||
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +1,86 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Thread Pool based on Daemon threads.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class DaemonThreadPool extends ThreadPoolExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonThreadPool.class);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private final int shutdownWaitSeconds;
|
||||
|
||||
/**
|
||||
* Construct the DaemonThreadPool.
|
||||
*
|
||||
* @param coreSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely. After
|
||||
* this the pool is forced to shutdown.
|
||||
*/
|
||||
public DaemonThreadPool(int coreSize, int maximumPoolSize, long keepAliveSecs, int shutdownWaitSeconds, String namePrefix) {
|
||||
|
||||
super(coreSize, maximumPoolSize, keepAliveSecs, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory(namePrefix));
|
||||
allowCoreThreadTimeOut(true);
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM Runtime.
|
||||
*/
|
||||
public void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonThreadPool[" + namePrefix + "] already shut down");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonThreadPool[" + namePrefix + "] shutting down...");
|
||||
super.shutdown();
|
||||
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonThreadPool[" + namePrefix+ "] shut down timeout exceeded. Terminating running threads.");
|
||||
super.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime shutdown.
|
||||
*/
|
||||
private class ShutdownHook extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Thread Pool based on Daemon threads.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public final class DaemonThreadPool extends ThreadPoolExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonThreadPool.class);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private final int shutdownWaitSeconds;
|
||||
|
||||
/**
|
||||
* Construct the DaemonThreadPool.
|
||||
*
|
||||
* @param coreSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely. After
|
||||
* this the pool is forced to shutdown.
|
||||
*/
|
||||
public DaemonThreadPool(int coreSize, int maximumPoolSize, long keepAliveSecs, int shutdownWaitSeconds, String namePrefix) {
|
||||
|
||||
super(coreSize, maximumPoolSize, keepAliveSecs, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory(namePrefix));
|
||||
allowCoreThreadTimeOut(true);
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a shutdown hook with the JVM Runtime.
|
||||
*/
|
||||
public void registerShutdownHook() {
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonThreadPool[" + namePrefix + "] already shut down");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonThreadPool[" + namePrefix + "] shutting down...");
|
||||
super.shutdown();
|
||||
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonThreadPool[" + namePrefix+ "] shut down timeout exceeded. Terminating running threads.");
|
||||
super.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime shutdown.
|
||||
*/
|
||||
private class ShutdownHook extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the ShutdownHook that gets added to Runtime.
|
||||
* It will try to shutdown the system cleanly when the JVM exits.
|
||||
* It is best to add your own shutdown hooks to StartStop.
|
||||
*/
|
||||
class ShutdownHook extends Thread {
|
||||
|
||||
ShutdownHook() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime on shutdown.
|
||||
*/
|
||||
public void run() {
|
||||
ShutdownManager.shutdown();
|
||||
}
|
||||
|
||||
};
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the ShutdownHook that gets added to Runtime.
|
||||
* It will try to shutdown the system cleanly when the JVM exits.
|
||||
* It is best to add your own shutdown hooks to StartStop.
|
||||
*/
|
||||
class ShutdownHook extends Thread {
|
||||
|
||||
ShutdownHook() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired by the JVM Runtime on shutdown.
|
||||
*/
|
||||
public void run() {
|
||||
ShutdownManager.shutdown();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,187 +1,187 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import com.avaje.ebean.common.SpiContainer;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages the shutdown of the JVM Runtime.
|
||||
* <p>
|
||||
* Makes sure all the resources are shutdown properly and in order.
|
||||
* </p>
|
||||
*/
|
||||
public final class ShutdownManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
|
||||
|
||||
static final List<SpiEbeanServer> servers = new ArrayList<SpiEbeanServer>();
|
||||
|
||||
static final ShutdownHook shutdownHook = new ShutdownHook();
|
||||
|
||||
static boolean stopping;
|
||||
|
||||
static SpiContainer container;
|
||||
|
||||
static {
|
||||
// Register the Shutdown hook
|
||||
registerShutdownHook();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallow construction.
|
||||
*/
|
||||
private ShutdownManager() {
|
||||
}
|
||||
|
||||
public static void registerContainer(SpiContainer ebeanContainer){
|
||||
container = ebeanContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the ShutdownManager is activated.
|
||||
*/
|
||||
public static void touch() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the system is in the process of stopping.
|
||||
*/
|
||||
public static boolean isStopping() {
|
||||
synchronized (servers) {
|
||||
return stopping;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister the Shutdown hook.
|
||||
* <p>
|
||||
* For running in a Servlet Container a redeploy will cause a shutdown, and
|
||||
* for that case we need to make sure the shutdown hook is deregistered.
|
||||
* </p>
|
||||
*/
|
||||
protected static void deregisterShutdownHook() {
|
||||
synchronized (servers) {
|
||||
try {
|
||||
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the shutdown hook with the Runtime.
|
||||
*/
|
||||
protected static void registerShutdownHook() {
|
||||
synchronized (servers) {
|
||||
try {
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown gracefully cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook.
|
||||
* </p>
|
||||
*/
|
||||
public static void shutdown() {
|
||||
synchronized (servers) {
|
||||
if (stopping) {
|
||||
// Already run shutdown...
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down");
|
||||
}
|
||||
|
||||
stopping = true;
|
||||
|
||||
deregisterShutdownHook();
|
||||
|
||||
String shutdownRunner = System.getProperty("ebean.shutdown.runnable");
|
||||
if (shutdownRunner != null) {
|
||||
try {
|
||||
// A custom runnable executed at the start of shutdown
|
||||
Runnable r = (Runnable) ClassUtil.newInstance(shutdownRunner);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error running custom shutdown runnable", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (container != null) {
|
||||
// shutdown cluster networking if active
|
||||
container.shutdown();
|
||||
}
|
||||
|
||||
// shutdown any registered servers that have not
|
||||
// already been shutdown manually
|
||||
for (SpiEbeanServer server : servers) {
|
||||
try {
|
||||
server.shutdownManaged();
|
||||
} catch (Exception ex) {
|
||||
logger.error("Error executing shutdown runnable", ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
|
||||
deregisterAllJdbcDrivers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void deregisterAllJdbcDrivers() {
|
||||
// This manually deregisters all JDBC drivers
|
||||
Enumeration<Driver> drivers = DriverManager.getDrivers();
|
||||
while (drivers.hasMoreElements()) {
|
||||
Driver driver = drivers.nextElement();
|
||||
try {
|
||||
logger.info("Deregistering jdbc driver: "+driver);
|
||||
DriverManager.deregisterDriver(driver);
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error deregistering driver "+driver, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an ebeanServer to be shutdown when the JVM is shutdown.
|
||||
*/
|
||||
public static void registerEbeanServer(SpiEbeanServer server) {
|
||||
synchronized (servers) {
|
||||
servers.add(server);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister an ebeanServer.
|
||||
* <p>
|
||||
* This is done when the ebeanServer is shutdown manually.
|
||||
* </p>
|
||||
*/
|
||||
public static void unregisterEbeanServer(SpiEbeanServer server) {
|
||||
synchronized (servers) {
|
||||
servers.remove(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import com.avaje.ebean.common.SpiContainer;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages the shutdown of the JVM Runtime.
|
||||
* <p>
|
||||
* Makes sure all the resources are shutdown properly and in order.
|
||||
* </p>
|
||||
*/
|
||||
public final class ShutdownManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
|
||||
|
||||
static final List<SpiEbeanServer> servers = new ArrayList<SpiEbeanServer>();
|
||||
|
||||
static final ShutdownHook shutdownHook = new ShutdownHook();
|
||||
|
||||
static boolean stopping;
|
||||
|
||||
static SpiContainer container;
|
||||
|
||||
static {
|
||||
// Register the Shutdown hook
|
||||
registerShutdownHook();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disallow construction.
|
||||
*/
|
||||
private ShutdownManager() {
|
||||
}
|
||||
|
||||
public static void registerContainer(SpiContainer ebeanContainer){
|
||||
container = ebeanContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the ShutdownManager is activated.
|
||||
*/
|
||||
public static void touch() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the system is in the process of stopping.
|
||||
*/
|
||||
public static boolean isStopping() {
|
||||
synchronized (servers) {
|
||||
return stopping;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister the Shutdown hook.
|
||||
* <p>
|
||||
* For running in a Servlet Container a redeploy will cause a shutdown, and
|
||||
* for that case we need to make sure the shutdown hook is deregistered.
|
||||
* </p>
|
||||
*/
|
||||
protected static void deregisterShutdownHook() {
|
||||
synchronized (servers) {
|
||||
try {
|
||||
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the shutdown hook with the Runtime.
|
||||
*/
|
||||
protected static void registerShutdownHook() {
|
||||
synchronized (servers) {
|
||||
try {
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown gracefully cleaning up any resources as required.
|
||||
* <p>
|
||||
* This is typically invoked via JVM shutdown hook.
|
||||
* </p>
|
||||
*/
|
||||
public static void shutdown() {
|
||||
synchronized (servers) {
|
||||
if (stopping) {
|
||||
// Already run shutdown...
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down");
|
||||
}
|
||||
|
||||
stopping = true;
|
||||
|
||||
deregisterShutdownHook();
|
||||
|
||||
String shutdownRunner = System.getProperty("ebean.shutdown.runnable");
|
||||
if (shutdownRunner != null) {
|
||||
try {
|
||||
// A custom runnable executed at the start of shutdown
|
||||
Runnable r = (Runnable) ClassUtil.newInstance(shutdownRunner);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error running custom shutdown runnable", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (container != null) {
|
||||
// shutdown cluster networking if active
|
||||
container.shutdown();
|
||||
}
|
||||
|
||||
// shutdown any registered servers that have not
|
||||
// already been shutdown manually
|
||||
for (SpiEbeanServer server : servers) {
|
||||
try {
|
||||
server.shutdownManaged();
|
||||
} catch (Exception ex) {
|
||||
logger.error("Error executing shutdown runnable", ex);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
|
||||
deregisterAllJdbcDrivers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void deregisterAllJdbcDrivers() {
|
||||
// This manually deregisters all JDBC drivers
|
||||
Enumeration<Driver> drivers = DriverManager.getDrivers();
|
||||
while (drivers.hasMoreElements()) {
|
||||
Driver driver = drivers.nextElement();
|
||||
try {
|
||||
logger.info("Deregistering jdbc driver: "+driver);
|
||||
DriverManager.deregisterDriver(driver);
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error deregistering driver "+driver, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an ebeanServer to be shutdown when the JVM is shutdown.
|
||||
*/
|
||||
public static void registerEbeanServer(SpiEbeanServer server) {
|
||||
synchronized (servers) {
|
||||
servers.add(server);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deregister an ebeanServer.
|
||||
* <p>
|
||||
* This is done when the ebeanServer is shutdown manually.
|
||||
* </p>
|
||||
*/
|
||||
public static void unregisterEbeanServer(SpiEbeanServer server) {
|
||||
synchronized (servers) {
|
||||
servers.remove(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +1,108 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Helper object used to find directories typically from the current working
|
||||
* directory.
|
||||
*/
|
||||
public class DirectoryFinder {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DirectoryFinder.class);
|
||||
|
||||
/**
|
||||
* Find a directory by search through subdirectories.
|
||||
* <p>
|
||||
* For example, used to find the WEB-INF directory starting from the current
|
||||
* working directory.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // search to a depth of 3 from the current working directory
|
||||
* // looking for a directory WEB-INF that contains the subdirectory
|
||||
* // data
|
||||
*
|
||||
* File dir = DirectoryFinder.find(null, "WEB-INF/data", 3);
|
||||
* if (dir != null) {
|
||||
* //found the directory
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static File find(File startDir, String match, int maxDepth) {
|
||||
|
||||
String matchSub = null;
|
||||
int slashPos = match.indexOf('/');
|
||||
if (slashPos > -1) {
|
||||
// match has sub directories
|
||||
matchSub = match.substring(slashPos + 1);
|
||||
match = match.substring(0, slashPos);
|
||||
}
|
||||
|
||||
// search for the directory
|
||||
File found = find(startDir, match, matchSub, 0, maxDepth);
|
||||
|
||||
if (found != null && matchSub != null) {
|
||||
// match has sub directories
|
||||
return new File(found, matchSub);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private static File find(File dir, String match, String matchSub, int depth, int maxDepth) {
|
||||
|
||||
if (dir == null) {
|
||||
String curDir = System.getProperty("user.dir");
|
||||
dir = new File(curDir);
|
||||
}
|
||||
|
||||
if (dir.exists()) {
|
||||
File[] list = dir.listFiles();
|
||||
if (list != null){
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (isMatch(list[i], match, matchSub)) {
|
||||
return list[i];
|
||||
}
|
||||
}
|
||||
|
||||
// go through the directories again
|
||||
// Aka *NOT* a depth first search
|
||||
if (depth < maxDepth) {
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i].isDirectory()) {
|
||||
File found = find(list[i], match, matchSub, depth + 1, maxDepth);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isMatch(File f, String match, String matchSub) {
|
||||
if (f == null) {
|
||||
return false;
|
||||
}
|
||||
if (!f.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
if (!f.getName().equalsIgnoreCase(match)) {
|
||||
return false;
|
||||
}
|
||||
if (matchSub == null) {
|
||||
return true;
|
||||
}
|
||||
File sub = new File(f, matchSub);
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.trace("search; " + f.getPath());
|
||||
}
|
||||
return sub.exists();
|
||||
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Helper object used to find directories typically from the current working
|
||||
* directory.
|
||||
*/
|
||||
public class DirectoryFinder {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DirectoryFinder.class);
|
||||
|
||||
/**
|
||||
* Find a directory by search through subdirectories.
|
||||
* <p>
|
||||
* For example, used to find the WEB-INF directory starting from the current
|
||||
* working directory.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* // search to a depth of 3 from the current working directory
|
||||
* // looking for a directory WEB-INF that contains the subdirectory
|
||||
* // data
|
||||
*
|
||||
* File dir = DirectoryFinder.find(null, "WEB-INF/data", 3);
|
||||
* if (dir != null) {
|
||||
* //found the directory
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static File find(File startDir, String match, int maxDepth) {
|
||||
|
||||
String matchSub = null;
|
||||
int slashPos = match.indexOf('/');
|
||||
if (slashPos > -1) {
|
||||
// match has sub directories
|
||||
matchSub = match.substring(slashPos + 1);
|
||||
match = match.substring(0, slashPos);
|
||||
}
|
||||
|
||||
// search for the directory
|
||||
File found = find(startDir, match, matchSub, 0, maxDepth);
|
||||
|
||||
if (found != null && matchSub != null) {
|
||||
// match has sub directories
|
||||
return new File(found, matchSub);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private static File find(File dir, String match, String matchSub, int depth, int maxDepth) {
|
||||
|
||||
if (dir == null) {
|
||||
String curDir = System.getProperty("user.dir");
|
||||
dir = new File(curDir);
|
||||
}
|
||||
|
||||
if (dir.exists()) {
|
||||
File[] list = dir.listFiles();
|
||||
if (list != null){
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (isMatch(list[i], match, matchSub)) {
|
||||
return list[i];
|
||||
}
|
||||
}
|
||||
|
||||
// go through the directories again
|
||||
// Aka *NOT* a depth first search
|
||||
if (depth < maxDepth) {
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i].isDirectory()) {
|
||||
File found = find(list[i], match, matchSub, depth + 1, maxDepth);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isMatch(File f, String match, String matchSub) {
|
||||
if (f == null) {
|
||||
return false;
|
||||
}
|
||||
if (!f.isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
if (!f.getName().equalsIgnoreCase(match)) {
|
||||
return false;
|
||||
}
|
||||
if (matchSub == null) {
|
||||
return true;
|
||||
}
|
||||
File sub = new File(f, matchSub);
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.trace("search; " + f.getPath());
|
||||
}
|
||||
return sub.exists();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+71
-71
@@ -1,71 +1,71 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Content from a file system file.
|
||||
*/
|
||||
public class FileResourceContent implements ResourceContent {
|
||||
|
||||
/**
|
||||
* The underlying file.
|
||||
*/
|
||||
File file;
|
||||
|
||||
String entryName;
|
||||
|
||||
/**
|
||||
* Create with a File and the entryName.
|
||||
*/
|
||||
public FileResourceContent(File file, String entryName) {
|
||||
this.file = file;
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("[").append(getName());
|
||||
sb.append("] size[").append(size());
|
||||
sb.append("] lastModified[").append(new Date(lastModified()));
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry name which contains the path from the base directory.
|
||||
* <p>
|
||||
* This does not return the full path of the file, but the path relative to
|
||||
* the FileIoSource directory.
|
||||
* </p>
|
||||
*/
|
||||
public String getName() {
|
||||
return entryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the file was last modified.
|
||||
*/
|
||||
public long lastModified() {
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the file.
|
||||
*/
|
||||
public long size() {
|
||||
return file.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream for this file.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Content from a file system file.
|
||||
*/
|
||||
public class FileResourceContent implements ResourceContent {
|
||||
|
||||
/**
|
||||
* The underlying file.
|
||||
*/
|
||||
File file;
|
||||
|
||||
String entryName;
|
||||
|
||||
/**
|
||||
* Create with a File and the entryName.
|
||||
*/
|
||||
public FileResourceContent(File file, String entryName) {
|
||||
this.file = file;
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("[").append(getName());
|
||||
sb.append("] size[").append(size());
|
||||
sb.append("] lastModified[").append(new Date(lastModified()));
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry name which contains the path from the base directory.
|
||||
* <p>
|
||||
* This does not return the full path of the file, but the path relative to
|
||||
* the FileIoSource directory.
|
||||
* </p>
|
||||
*/
|
||||
public String getName() {
|
||||
return entryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the file was last modified.
|
||||
*/
|
||||
public long lastModified() {
|
||||
return file.lastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the file.
|
||||
*/
|
||||
public long size() {
|
||||
return file.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream for this file.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
|
||||
FileInputStream is = new FileInputStream(file);
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A file system directory represented as a FileSource.
|
||||
*/
|
||||
public class FileResourceSource extends AbstractResourceSource implements ResourceSource {
|
||||
|
||||
/**
|
||||
* The directory name.
|
||||
*/
|
||||
String directory;
|
||||
|
||||
String baseDir;
|
||||
|
||||
/**
|
||||
* Create the source based on a directory name.
|
||||
*/
|
||||
public FileResourceSource(String directory){
|
||||
this.directory = directory;
|
||||
this.baseDir = directory+File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the source based on a directory file.
|
||||
*/
|
||||
public FileResourceSource(File dir){
|
||||
this(dir.getPath());
|
||||
}
|
||||
|
||||
|
||||
public String getRealPath() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the given file and return as IoContent.
|
||||
*/
|
||||
public ResourceContent getContent(String entry) {
|
||||
|
||||
String fullPath = baseDir+entry;
|
||||
|
||||
File f = new File(fullPath);
|
||||
if (f.exists()){
|
||||
FileResourceContent content = new FileResourceContent(f, entry);
|
||||
return content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A file system directory represented as a FileSource.
|
||||
*/
|
||||
public class FileResourceSource extends AbstractResourceSource implements ResourceSource {
|
||||
|
||||
/**
|
||||
* The directory name.
|
||||
*/
|
||||
String directory;
|
||||
|
||||
String baseDir;
|
||||
|
||||
/**
|
||||
* Create the source based on a directory name.
|
||||
*/
|
||||
public FileResourceSource(String directory){
|
||||
this.directory = directory;
|
||||
this.baseDir = directory+File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the source based on a directory file.
|
||||
*/
|
||||
public FileResourceSource(File dir){
|
||||
this(dir.getPath());
|
||||
}
|
||||
|
||||
|
||||
public String getRealPath() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the given file and return as IoContent.
|
||||
*/
|
||||
public ResourceContent getContent(String entry) {
|
||||
|
||||
String fullPath = baseDir+entry;
|
||||
|
||||
File f = new File(fullPath);
|
||||
if (f.exists()){
|
||||
FileResourceContent content = new FileResourceContent(f, entry);
|
||||
return content;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Represents content that can be read via the ResourceManager.
|
||||
* <p>
|
||||
* Typically either content from a File or a URL.
|
||||
* </p>
|
||||
*/
|
||||
public interface ResourceContent {
|
||||
|
||||
/**
|
||||
* The name of the content.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* The size of the content in bytes.
|
||||
*/
|
||||
public long size();
|
||||
|
||||
/**
|
||||
* The last modified timestamp of the content.
|
||||
*/
|
||||
public long lastModified();
|
||||
|
||||
/**
|
||||
* The content itself.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException;
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Represents content that can be read via the ResourceManager.
|
||||
* <p>
|
||||
* Typically either content from a File or a URL.
|
||||
* </p>
|
||||
*/
|
||||
public interface ResourceContent {
|
||||
|
||||
/**
|
||||
* The name of the content.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* The size of the content in bytes.
|
||||
*/
|
||||
public long size();
|
||||
|
||||
/**
|
||||
* The last modified timestamp of the content.
|
||||
*/
|
||||
public long lastModified();
|
||||
|
||||
/**
|
||||
* The content itself.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Source for ResourceManager.
|
||||
* <p>
|
||||
* Typically a File System Directory based source or a ServletContext URL
|
||||
* resource based source (for Servlet WAR files).
|
||||
* </p>
|
||||
*/
|
||||
public interface ResourceSource {
|
||||
|
||||
/**
|
||||
* Return the File System path of the root of the ResourceSource.
|
||||
* <p>
|
||||
* This will return null IF the ResourceSource is an unpacked WAR file.
|
||||
* </p>
|
||||
*/
|
||||
public String getRealPath();
|
||||
|
||||
/**
|
||||
* Find the content with a given entry name. This will return null if no
|
||||
* matching content was found.
|
||||
*/
|
||||
public ResourceContent getContent(String entry);
|
||||
|
||||
/**
|
||||
* Return the content as a String.
|
||||
*/
|
||||
public String readString(ResourceContent content, int bufSize) throws IOException;
|
||||
|
||||
/**
|
||||
* Return the content as a byte[].
|
||||
*/
|
||||
public byte[] readBytes(ResourceContent content, int bufSize) throws IOException;
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A Source for ResourceManager.
|
||||
* <p>
|
||||
* Typically a File System Directory based source or a ServletContext URL
|
||||
* resource based source (for Servlet WAR files).
|
||||
* </p>
|
||||
*/
|
||||
public interface ResourceSource {
|
||||
|
||||
/**
|
||||
* Return the File System path of the root of the ResourceSource.
|
||||
* <p>
|
||||
* This will return null IF the ResourceSource is an unpacked WAR file.
|
||||
* </p>
|
||||
*/
|
||||
public String getRealPath();
|
||||
|
||||
/**
|
||||
* Find the content with a given entry name. This will return null if no
|
||||
* matching content was found.
|
||||
*/
|
||||
public ResourceContent getContent(String entry);
|
||||
|
||||
/**
|
||||
* Return the content as a String.
|
||||
*/
|
||||
public String readString(ResourceContent content, int bufSize) throws IOException;
|
||||
|
||||
/**
|
||||
* Return the content as a byte[].
|
||||
*/
|
||||
public byte[] readBytes(ResourceContent content, int bufSize) throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,77 +1,77 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Content from a URL Resource.
|
||||
*/
|
||||
public class UrlResourceContent implements ResourceContent {
|
||||
|
||||
/**
|
||||
* The underlying resource.
|
||||
*/
|
||||
//URL url;
|
||||
|
||||
String entryName;
|
||||
|
||||
URLConnection con;
|
||||
|
||||
/**
|
||||
* Create with a File and the entryName.
|
||||
*/
|
||||
public UrlResourceContent(URL url, String entryName) {
|
||||
//this.url = url;
|
||||
this.entryName = entryName;
|
||||
try {
|
||||
con = url.openConnection();
|
||||
} catch (IOException ex){
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("[").append(getName());
|
||||
sb.append("] size[").append(size());
|
||||
sb.append("] lastModified[").append(new Date(lastModified()));
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry name which contains the path from the base directory.
|
||||
* <p>
|
||||
* This does not return the full path of the file, but the path relative to
|
||||
* the FileIoSource directory.
|
||||
* </p>
|
||||
*/
|
||||
public String getName() {
|
||||
return entryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the file was last modified.
|
||||
*/
|
||||
public long lastModified() {
|
||||
return con.getLastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the file.
|
||||
*/
|
||||
public long size() {
|
||||
return con.getContentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream for this file.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
|
||||
return con.getInputStream();
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Content from a URL Resource.
|
||||
*/
|
||||
public class UrlResourceContent implements ResourceContent {
|
||||
|
||||
/**
|
||||
* The underlying resource.
|
||||
*/
|
||||
//URL url;
|
||||
|
||||
String entryName;
|
||||
|
||||
URLConnection con;
|
||||
|
||||
/**
|
||||
* Create with a File and the entryName.
|
||||
*/
|
||||
public UrlResourceContent(URL url, String entryName) {
|
||||
//this.url = url;
|
||||
this.entryName = entryName;
|
||||
try {
|
||||
con = url.openConnection();
|
||||
} catch (IOException ex){
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("[").append(getName());
|
||||
sb.append("] size[").append(size());
|
||||
sb.append("] lastModified[").append(new Date(lastModified()));
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry name which contains the path from the base directory.
|
||||
* <p>
|
||||
* This does not return the full path of the file, but the path relative to
|
||||
* the FileIoSource directory.
|
||||
* </p>
|
||||
*/
|
||||
public String getName() {
|
||||
return entryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the file was last modified.
|
||||
*/
|
||||
public long lastModified() {
|
||||
return con.getLastModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of the file.
|
||||
*/
|
||||
public long size() {
|
||||
return con.getContentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the input stream for this file.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
|
||||
return con.getInputStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.GeneralException;
|
||||
|
||||
/**
|
||||
* A file system directory represented as a FileSource.
|
||||
*/
|
||||
public class UrlResourceSource extends AbstractResourceSource implements ResourceSource {
|
||||
|
||||
|
||||
ServletContext sc;
|
||||
|
||||
String basePath;
|
||||
|
||||
String realPath;
|
||||
|
||||
/**
|
||||
* Create the source based on a directory name.
|
||||
*/
|
||||
public UrlResourceSource(ServletContext sc, String basePath){
|
||||
this.sc = sc;
|
||||
if (basePath == null){
|
||||
this.basePath = "/";
|
||||
} else {
|
||||
this.basePath = "/"+basePath+"/";
|
||||
}
|
||||
this.realPath = sc.getRealPath(basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "real path" from the ServletContext root.
|
||||
* <p>
|
||||
* This can be null for unpacked WAR deployment.
|
||||
* </p>
|
||||
*/
|
||||
public String getRealPath() {
|
||||
return realPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the given URL resource and return as ResourceContent.
|
||||
* <p>
|
||||
* Returns null if the resource is not found.
|
||||
* </p>
|
||||
*/
|
||||
public ResourceContent getContent(String entry) {
|
||||
|
||||
try {
|
||||
URL url = sc.getResource(basePath+entry);
|
||||
if (url != null){
|
||||
return new UrlResourceContent(url, entry);
|
||||
}
|
||||
return null;
|
||||
|
||||
} catch (MalformedURLException ex){
|
||||
throw new GeneralException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.resource;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.GeneralException;
|
||||
|
||||
/**
|
||||
* A file system directory represented as a FileSource.
|
||||
*/
|
||||
public class UrlResourceSource extends AbstractResourceSource implements ResourceSource {
|
||||
|
||||
|
||||
ServletContext sc;
|
||||
|
||||
String basePath;
|
||||
|
||||
String realPath;
|
||||
|
||||
/**
|
||||
* Create the source based on a directory name.
|
||||
*/
|
||||
public UrlResourceSource(ServletContext sc, String basePath){
|
||||
this.sc = sc;
|
||||
if (basePath == null){
|
||||
this.basePath = "/";
|
||||
} else {
|
||||
this.basePath = "/"+basePath+"/";
|
||||
}
|
||||
this.realPath = sc.getRealPath(basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "real path" from the ServletContext root.
|
||||
* <p>
|
||||
* This can be null for unpacked WAR deployment.
|
||||
* </p>
|
||||
*/
|
||||
public String getRealPath() {
|
||||
return realPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for the given URL resource and return as ResourceContent.
|
||||
* <p>
|
||||
* Returns null if the resource is not found.
|
||||
* </p>
|
||||
*/
|
||||
public ResourceContent getContent(String entry) {
|
||||
|
||||
try {
|
||||
URL url = sc.getResource(basePath+entry);
|
||||
if (url != null){
|
||||
return new UrlResourceContent(url, entry);
|
||||
}
|
||||
return null;
|
||||
|
||||
} catch (MalformedURLException ex){
|
||||
throw new GeneralException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,202 +1,202 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues;
|
||||
|
||||
/**
|
||||
* A buffer especially designed for Busy PooledConnections.
|
||||
* <p>
|
||||
* All thread safety controlled externally (by PooledConnectionQueue).
|
||||
* </p>
|
||||
* <p>
|
||||
* It has a set of 'slots' and PooledConnections know which slot they went into
|
||||
* and this allows for fast addition and removal (by slotId without looping).
|
||||
* The capacity will increase on demand by the 'growBy' amount.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
class BusyConnectionBuffer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class);
|
||||
|
||||
private PooledConnection[] slots;
|
||||
|
||||
private int growBy;
|
||||
|
||||
private int size;
|
||||
|
||||
private int pos = -1;
|
||||
|
||||
/**
|
||||
* Create the buffer with an initial capacity and fixed growBy.
|
||||
* We generally do not want the buffer to grow very often.
|
||||
*
|
||||
* @param capacity
|
||||
* the initial capacity
|
||||
* @param growBy
|
||||
* the fixed amount to grow the buffer by.
|
||||
*/
|
||||
protected BusyConnectionBuffer(int capacity, int growBy) {
|
||||
this.slots = new PooledConnection[capacity];
|
||||
this.growBy = growBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* We can only grow (not shrink) the capacity.
|
||||
*/
|
||||
protected void setCapacity(int newCapacity) {
|
||||
if (newCapacity > slots.length){
|
||||
PooledConnection[] current = this.slots;
|
||||
this.slots = new PooledConnection[newCapacity];
|
||||
System.arraycopy(current, 0, this.slots, 0, current.length);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Arrays.toString(slots);
|
||||
}
|
||||
|
||||
protected int getCapacity() {
|
||||
return slots.length;
|
||||
}
|
||||
|
||||
protected int size(){
|
||||
return size;
|
||||
}
|
||||
|
||||
protected boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
protected int add(PooledConnection pc){
|
||||
if (size == slots.length){
|
||||
// grow the capacity
|
||||
setCapacity(slots.length + growBy);
|
||||
}
|
||||
int slot = nextEmptySlot();
|
||||
pc.setSlotId(slot);
|
||||
slots[slot] = pc;
|
||||
return ++size;
|
||||
}
|
||||
|
||||
protected boolean remove(PooledConnection pc) {
|
||||
|
||||
int slotId = pc.getSlotId();
|
||||
if (slots[slotId] != pc){
|
||||
PooledConnection heldBy = slots[slotId];
|
||||
logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy);
|
||||
return false;
|
||||
}
|
||||
slots[slotId] = null;
|
||||
--size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the load statistics from all the busy connections.
|
||||
* @param reset
|
||||
*/
|
||||
protected void collectStatistics(LoadValues values, boolean reset) {
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
values.plus(slots[i].getStatistics().getValues(reset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close connections that should be considered leaked.
|
||||
*/
|
||||
protected void closeBusyConnections(long leakTimeMinutes) {
|
||||
|
||||
long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes*60000);
|
||||
|
||||
logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes);
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
//tmp.add(slots[i]);
|
||||
PooledConnection pc = slots[i];
|
||||
if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) {
|
||||
// PooledConnection has been used recently or
|
||||
// expected to be longRunning so not closing...
|
||||
} else {
|
||||
slots[i] = null;
|
||||
--size;
|
||||
closeBusyConnection(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeBusyConnection(PooledConnection pc) {
|
||||
try {
|
||||
|
||||
logger.warn("DataSourcePool closing busy connection? "+pc.getFullDescription());
|
||||
System.out.println("CLOSING busy connection: "+pc.getFullDescription());
|
||||
|
||||
pc.closeConnectionFully(false);
|
||||
|
||||
} catch (Exception ex) {
|
||||
// this should never actually happen
|
||||
logger.error("Error when closing potentially leaked connection "+pc.getDescription(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information describing connections that are currently being used.
|
||||
*/
|
||||
protected String getBusyConnectionInformation(boolean toLogger) {
|
||||
|
||||
if (toLogger) {
|
||||
logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size());
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
PooledConnection pc = slots[i];
|
||||
if (toLogger) {
|
||||
logger.info("Busy Connection - {}", pc.getFullDescription());
|
||||
} else {
|
||||
sb.append(pc.getFullDescription()).append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the position of the next empty slot.
|
||||
*/
|
||||
private int nextEmptySlot() {
|
||||
|
||||
// search forward
|
||||
while(++pos < slots.length) {
|
||||
if (slots[pos] == null){
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
// search from beginning
|
||||
pos = -1;
|
||||
while(++pos < slots.length) {
|
||||
if (slots[pos] == null){
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
// not expecting this
|
||||
throw new RuntimeException("No Empty Slot Found?");
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues;
|
||||
|
||||
/**
|
||||
* A buffer especially designed for Busy PooledConnections.
|
||||
* <p>
|
||||
* All thread safety controlled externally (by PooledConnectionQueue).
|
||||
* </p>
|
||||
* <p>
|
||||
* It has a set of 'slots' and PooledConnections know which slot they went into
|
||||
* and this allows for fast addition and removal (by slotId without looping).
|
||||
* The capacity will increase on demand by the 'growBy' amount.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
class BusyConnectionBuffer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BusyConnectionBuffer.class);
|
||||
|
||||
private PooledConnection[] slots;
|
||||
|
||||
private int growBy;
|
||||
|
||||
private int size;
|
||||
|
||||
private int pos = -1;
|
||||
|
||||
/**
|
||||
* Create the buffer with an initial capacity and fixed growBy.
|
||||
* We generally do not want the buffer to grow very often.
|
||||
*
|
||||
* @param capacity
|
||||
* the initial capacity
|
||||
* @param growBy
|
||||
* the fixed amount to grow the buffer by.
|
||||
*/
|
||||
protected BusyConnectionBuffer(int capacity, int growBy) {
|
||||
this.slots = new PooledConnection[capacity];
|
||||
this.growBy = growBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* We can only grow (not shrink) the capacity.
|
||||
*/
|
||||
protected void setCapacity(int newCapacity) {
|
||||
if (newCapacity > slots.length){
|
||||
PooledConnection[] current = this.slots;
|
||||
this.slots = new PooledConnection[newCapacity];
|
||||
System.arraycopy(current, 0, this.slots, 0, current.length);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Arrays.toString(slots);
|
||||
}
|
||||
|
||||
protected int getCapacity() {
|
||||
return slots.length;
|
||||
}
|
||||
|
||||
protected int size(){
|
||||
return size;
|
||||
}
|
||||
|
||||
protected boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
protected int add(PooledConnection pc){
|
||||
if (size == slots.length){
|
||||
// grow the capacity
|
||||
setCapacity(slots.length + growBy);
|
||||
}
|
||||
int slot = nextEmptySlot();
|
||||
pc.setSlotId(slot);
|
||||
slots[slot] = pc;
|
||||
return ++size;
|
||||
}
|
||||
|
||||
protected boolean remove(PooledConnection pc) {
|
||||
|
||||
int slotId = pc.getSlotId();
|
||||
if (slots[slotId] != pc){
|
||||
PooledConnection heldBy = slots[slotId];
|
||||
logger.warn("Failed to remove from slot[{}] PooledConnection[{}] - HeldBy[{}]", pc.getSlotId(), pc, heldBy);
|
||||
return false;
|
||||
}
|
||||
slots[slotId] = null;
|
||||
--size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the load statistics from all the busy connections.
|
||||
* @param reset
|
||||
*/
|
||||
protected void collectStatistics(LoadValues values, boolean reset) {
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
values.plus(slots[i].getStatistics().getValues(reset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close connections that should be considered leaked.
|
||||
*/
|
||||
protected void closeBusyConnections(long leakTimeMinutes) {
|
||||
|
||||
long olderThanTime = System.currentTimeMillis() - (leakTimeMinutes*60000);
|
||||
|
||||
logger.debug("Closing busy connections using leakTimeMinutes {}", leakTimeMinutes);
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
//tmp.add(slots[i]);
|
||||
PooledConnection pc = slots[i];
|
||||
if (pc.isLongRunning() || pc.getLastUsedTime() > olderThanTime) {
|
||||
// PooledConnection has been used recently or
|
||||
// expected to be longRunning so not closing...
|
||||
} else {
|
||||
slots[i] = null;
|
||||
--size;
|
||||
closeBusyConnection(pc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeBusyConnection(PooledConnection pc) {
|
||||
try {
|
||||
|
||||
logger.warn("DataSourcePool closing busy connection? "+pc.getFullDescription());
|
||||
System.out.println("CLOSING busy connection: "+pc.getFullDescription());
|
||||
|
||||
pc.closeConnectionFully(false);
|
||||
|
||||
} catch (Exception ex) {
|
||||
// this should never actually happen
|
||||
logger.error("Error when closing potentially leaked connection "+pc.getDescription(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information describing connections that are currently being used.
|
||||
*/
|
||||
protected String getBusyConnectionInformation(boolean toLogger) {
|
||||
|
||||
if (toLogger) {
|
||||
logger.info("Dumping [{}] busy connections: (Use datasource.xxx.capturestacktrace=true ... to get stackTraces)", size());
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < slots.length; i++) {
|
||||
if (slots[i] != null){
|
||||
PooledConnection pc = slots[i];
|
||||
if (toLogger) {
|
||||
logger.info("Busy Connection - {}", pc.getFullDescription());
|
||||
} else {
|
||||
sb.append(pc.getFullDescription()).append("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the position of the next empty slot.
|
||||
*/
|
||||
private int nextEmptySlot() {
|
||||
|
||||
// search forward
|
||||
while(++pos < slots.length) {
|
||||
if (slots[pos] == null){
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
// search from beginning
|
||||
pos = -1;
|
||||
while(++pos < slots.length) {
|
||||
if (slots[pos] == null){
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
// not expecting this
|
||||
throw new RuntimeException("No Empty Slot Found?");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A general DataSource exception.
|
||||
*/
|
||||
public class DataSourceException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539844L;
|
||||
|
||||
public DataSourceException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DataSourceException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public DataSourceException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A general DataSource exception.
|
||||
*/
|
||||
public class DataSourceException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539844L;
|
||||
|
||||
public DataSourceException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public DataSourceException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public DataSourceException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+389
-389
@@ -1,389 +1,389 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Date;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Extended PreparedStatement that supports caching.
|
||||
* <p>
|
||||
* Designed so that it can be cached by the PooledConnection. It additionally
|
||||
* notes any Exceptions that occur and this is used to ensure bad connections
|
||||
* are removed from the connection pool.
|
||||
* </p>
|
||||
*/
|
||||
public class ExtendedPreparedStatement extends ExtendedStatement implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* The SQL used to create the underlying PreparedStatement.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* The key used to cache this in the connection.
|
||||
*/
|
||||
private final String cacheKey;
|
||||
|
||||
/**
|
||||
* Create a wrapped PreparedStatement that can be cached.
|
||||
*/
|
||||
public ExtendedPreparedStatement(PooledConnection pooledConnection, PreparedStatement pstmt, String sql, String cacheKey) {
|
||||
super(pooledConnection, pstmt);
|
||||
this.sql = sql;
|
||||
this.cacheKey = cacheKey;
|
||||
}
|
||||
|
||||
public PreparedStatement getDelegate() {
|
||||
return pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key used to cache this on the Connection.
|
||||
*/
|
||||
public String getCacheKey() {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL used to create this PreparedStatement.
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully close the underlying PreparedStatement. After this we can no longer
|
||||
* reuse the PreparedStatement.
|
||||
*/
|
||||
public void closeDestroy() throws SQLException {
|
||||
pstmt.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PreparedStatement back into the cache. This doesn't fully
|
||||
* close the underlying PreparedStatement.
|
||||
*/
|
||||
public void close() throws SQLException {
|
||||
// return the connection back into the cache.
|
||||
pooledConnection.returnPreparedStatement(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the last binding for batch execution.
|
||||
*/
|
||||
public void addBatch() throws SQLException {
|
||||
try {
|
||||
pstmt.addBatch();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check this
|
||||
// connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear parameters.
|
||||
*/
|
||||
public void clearParameters() throws SQLException {
|
||||
try {
|
||||
pstmt.clearParameters();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* execute the statement.
|
||||
*/
|
||||
public boolean execute() throws SQLException {
|
||||
try {
|
||||
return pstmt.execute();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute teh query.
|
||||
*/
|
||||
public ResultSet executeQuery() throws SQLException {
|
||||
try {
|
||||
return pstmt.executeQuery();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the dml statement.
|
||||
*/
|
||||
public int executeUpdate() throws SQLException {
|
||||
try {
|
||||
return pstmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MetaData for the query.
|
||||
*/
|
||||
public ResultSetMetaData getMetaData() throws SQLException {
|
||||
try {
|
||||
return pstmt.getMetaData();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public ParameterMetaData getParameterMetaData() throws SQLException {
|
||||
return pstmt.getParameterMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setArray(int i, Array x) throws SQLException {
|
||||
pstmt.setArray(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setAsciiStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
|
||||
pstmt.setBigDecimal(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setBinaryStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBlob(int i, Blob x) throws SQLException {
|
||||
pstmt.setBlob(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
|
||||
pstmt.setBoolean(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setByte(int parameterIndex, byte x) throws SQLException {
|
||||
pstmt.setByte(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
|
||||
pstmt.setBytes(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length)
|
||||
throws SQLException {
|
||||
pstmt.setCharacterStream(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setClob(int i, Clob x) throws SQLException {
|
||||
pstmt.setClob(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDate(int parameterIndex, Date x) throws SQLException {
|
||||
pstmt.setDate(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
|
||||
pstmt.setDate(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDouble(int parameterIndex, double x) throws SQLException {
|
||||
pstmt.setDouble(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setFloat(int parameterIndex, float x) throws SQLException {
|
||||
pstmt.setFloat(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setInt(int parameterIndex, int x) throws SQLException {
|
||||
pstmt.setInt(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setLong(int parameterIndex, long x) throws SQLException {
|
||||
pstmt.setLong(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setNull(int parameterIndex, int sqlType) throws SQLException {
|
||||
pstmt.setNull(parameterIndex, sqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException {
|
||||
pstmt.setNull(paramIndex, sqlType, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x) throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x, targetSqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scale)
|
||||
throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x, targetSqlType, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setRef(int i, Ref x) throws SQLException {
|
||||
pstmt.setRef(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setShort(int parameterIndex, short x) throws SQLException {
|
||||
pstmt.setShort(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setString(int parameterIndex, String x) throws SQLException {
|
||||
pstmt.setString(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTime(int parameterIndex, Time x) throws SQLException {
|
||||
pstmt.setTime(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
||||
pstmt.setTime(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
|
||||
pstmt.setTimestamp(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
|
||||
pstmt.setTimestamp(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
* @deprecated
|
||||
*/
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setUnicodeStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setURL(int parameterIndex, URL x) throws SQLException {
|
||||
pstmt.setURL(parameterIndex, x);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Date;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Extended PreparedStatement that supports caching.
|
||||
* <p>
|
||||
* Designed so that it can be cached by the PooledConnection. It additionally
|
||||
* notes any Exceptions that occur and this is used to ensure bad connections
|
||||
* are removed from the connection pool.
|
||||
* </p>
|
||||
*/
|
||||
public class ExtendedPreparedStatement extends ExtendedStatement implements PreparedStatement {
|
||||
|
||||
/**
|
||||
* The SQL used to create the underlying PreparedStatement.
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* The key used to cache this in the connection.
|
||||
*/
|
||||
private final String cacheKey;
|
||||
|
||||
/**
|
||||
* Create a wrapped PreparedStatement that can be cached.
|
||||
*/
|
||||
public ExtendedPreparedStatement(PooledConnection pooledConnection, PreparedStatement pstmt, String sql, String cacheKey) {
|
||||
super(pooledConnection, pstmt);
|
||||
this.sql = sql;
|
||||
this.cacheKey = cacheKey;
|
||||
}
|
||||
|
||||
public PreparedStatement getDelegate() {
|
||||
return pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key used to cache this on the Connection.
|
||||
*/
|
||||
public String getCacheKey() {
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL used to create this PreparedStatement.
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully close the underlying PreparedStatement. After this we can no longer
|
||||
* reuse the PreparedStatement.
|
||||
*/
|
||||
public void closeDestroy() throws SQLException {
|
||||
pstmt.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PreparedStatement back into the cache. This doesn't fully
|
||||
* close the underlying PreparedStatement.
|
||||
*/
|
||||
public void close() throws SQLException {
|
||||
// return the connection back into the cache.
|
||||
pooledConnection.returnPreparedStatement(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the last binding for batch execution.
|
||||
*/
|
||||
public void addBatch() throws SQLException {
|
||||
try {
|
||||
pstmt.addBatch();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check this
|
||||
// connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear parameters.
|
||||
*/
|
||||
public void clearParameters() throws SQLException {
|
||||
try {
|
||||
pstmt.clearParameters();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* execute the statement.
|
||||
*/
|
||||
public boolean execute() throws SQLException {
|
||||
try {
|
||||
return pstmt.execute();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute teh query.
|
||||
*/
|
||||
public ResultSet executeQuery() throws SQLException {
|
||||
try {
|
||||
return pstmt.executeQuery();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the dml statement.
|
||||
*/
|
||||
public int executeUpdate() throws SQLException {
|
||||
try {
|
||||
return pstmt.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MetaData for the query.
|
||||
*/
|
||||
public ResultSetMetaData getMetaData() throws SQLException {
|
||||
try {
|
||||
return pstmt.getMetaData();
|
||||
} catch (SQLException e) {
|
||||
// we got an error... need to check
|
||||
// this connection before returning it
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public ParameterMetaData getParameterMetaData() throws SQLException {
|
||||
return pstmt.getParameterMetaData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setArray(int i, Array x) throws SQLException {
|
||||
pstmt.setArray(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setAsciiStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {
|
||||
pstmt.setBigDecimal(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setBinaryStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBlob(int i, Blob x) throws SQLException {
|
||||
pstmt.setBlob(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBoolean(int parameterIndex, boolean x) throws SQLException {
|
||||
pstmt.setBoolean(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setByte(int parameterIndex, byte x) throws SQLException {
|
||||
pstmt.setByte(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setBytes(int parameterIndex, byte[] x) throws SQLException {
|
||||
pstmt.setBytes(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setCharacterStream(int parameterIndex, Reader reader, int length)
|
||||
throws SQLException {
|
||||
pstmt.setCharacterStream(parameterIndex, reader, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setClob(int i, Clob x) throws SQLException {
|
||||
pstmt.setClob(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDate(int parameterIndex, Date x) throws SQLException {
|
||||
pstmt.setDate(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
|
||||
pstmt.setDate(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setDouble(int parameterIndex, double x) throws SQLException {
|
||||
pstmt.setDouble(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setFloat(int parameterIndex, float x) throws SQLException {
|
||||
pstmt.setFloat(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setInt(int parameterIndex, int x) throws SQLException {
|
||||
pstmt.setInt(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setLong(int parameterIndex, long x) throws SQLException {
|
||||
pstmt.setLong(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setNull(int parameterIndex, int sqlType) throws SQLException {
|
||||
pstmt.setNull(parameterIndex, sqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setNull(int paramIndex, int sqlType, String typeName) throws SQLException {
|
||||
pstmt.setNull(paramIndex, sqlType, typeName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x) throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x, targetSqlType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scale)
|
||||
throws SQLException {
|
||||
pstmt.setObject(parameterIndex, x, targetSqlType, scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setRef(int i, Ref x) throws SQLException {
|
||||
pstmt.setRef(i, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setShort(int parameterIndex, short x) throws SQLException {
|
||||
pstmt.setShort(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setString(int parameterIndex, String x) throws SQLException {
|
||||
pstmt.setString(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTime(int parameterIndex, Time x) throws SQLException {
|
||||
pstmt.setTime(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
|
||||
pstmt.setTime(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {
|
||||
pstmt.setTimestamp(parameterIndex, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {
|
||||
pstmt.setTimestamp(parameterIndex, x, cal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
* @deprecated
|
||||
*/
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {
|
||||
pstmt.setUnicodeStream(parameterIndex, x, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard PreparedStatement method execution.
|
||||
*/
|
||||
public void setURL(int parameterIndex, URL x) throws SQLException {
|
||||
pstmt.setURL(parameterIndex, x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,328 +1,328 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
|
||||
import com.avaje.ebeaninternal.jdbc.PreparedStatementDelegator;
|
||||
|
||||
/**
|
||||
* Implements the Statement methods for ExtendedPreparedStatement.
|
||||
* <p>
|
||||
* PreparedStatements should always be used and the intention is that there
|
||||
* should be no use of Statement at all. The implementation here is generally
|
||||
* for the case where someone uses the Statement api on an ExtendedPreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class ExtendedStatement extends PreparedStatementDelegator
|
||||
{
|
||||
|
||||
/**
|
||||
* The pooled connection this Statement belongs to.
|
||||
*/
|
||||
protected final PooledConnection pooledConnection;
|
||||
|
||||
/**
|
||||
* The underlying Statement that this object wraps.
|
||||
*/
|
||||
protected final PreparedStatement pstmt;
|
||||
|
||||
/**
|
||||
* Create the ExtendedStatement for a given pooledConnection.
|
||||
*/
|
||||
public ExtendedStatement(PooledConnection pooledConnection, PreparedStatement pstmt) {
|
||||
super(pstmt);
|
||||
|
||||
this.pooledConnection = pooledConnection;
|
||||
this.pstmt = pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the statement back into the statement cache.
|
||||
*/
|
||||
public abstract void close() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the underlying connection.
|
||||
*/
|
||||
public Connection getConnection() throws SQLException {
|
||||
try {
|
||||
return pstmt.getConnection();
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the sql for batch execution.
|
||||
*/
|
||||
public void addBatch(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
pstmt.addBatch(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the sql.
|
||||
*/
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.execute(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query.
|
||||
*/
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.executeQuery(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the dml sql.
|
||||
*/
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int[] executeBatch() throws SQLException {
|
||||
return pstmt.executeBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void cancel() throws SQLException {
|
||||
pstmt.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void clearBatch() throws SQLException {
|
||||
pstmt.clearBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void clearWarnings() throws SQLException {
|
||||
pstmt.clearWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getFetchDirection() throws SQLException {
|
||||
return pstmt.getFetchDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getFetchSize() throws SQLException {
|
||||
return pstmt.getFetchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getMaxFieldSize() throws SQLException {
|
||||
return pstmt.getMaxFieldSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getMaxRows() throws SQLException {
|
||||
return pstmt.getMaxRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean getMoreResults() throws SQLException {
|
||||
return pstmt.getMoreResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getQueryTimeout() throws SQLException {
|
||||
return pstmt.getQueryTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public ResultSet getResultSet() throws SQLException {
|
||||
return pstmt.getResultSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetConcurrency() throws SQLException {
|
||||
return pstmt.getResultSetConcurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetType() throws SQLException {
|
||||
return pstmt.getResultSetType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getUpdateCount() throws SQLException {
|
||||
return pstmt.getUpdateCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public SQLWarning getWarnings() throws SQLException {
|
||||
return pstmt.getWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setCursorName(String name) throws SQLException {
|
||||
pstmt.setCursorName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setEscapeProcessing(boolean enable) throws SQLException {
|
||||
pstmt.setEscapeProcessing(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setFetchDirection(int direction) throws SQLException {
|
||||
pstmt.setFetchDirection(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setFetchSize(int rows) throws SQLException {
|
||||
pstmt.setFetchSize(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setMaxFieldSize(int max) throws SQLException {
|
||||
pstmt.setMaxFieldSize(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setMaxRows(int max) throws SQLException {
|
||||
pstmt.setMaxRows(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setQueryTimeout(int seconds) throws SQLException {
|
||||
pstmt.setQueryTimeout(seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean getMoreResults(int i) throws SQLException {
|
||||
return pstmt.getMoreResults(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public ResultSet getGeneratedKeys() throws SQLException {
|
||||
return pstmt.getGeneratedKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, int i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, int[] i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, String[] i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, int i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, int[] i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, String[] i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetHoldability() throws SQLException {
|
||||
return pstmt.getResultSetHoldability();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLWarning;
|
||||
|
||||
import com.avaje.ebeaninternal.jdbc.PreparedStatementDelegator;
|
||||
|
||||
/**
|
||||
* Implements the Statement methods for ExtendedPreparedStatement.
|
||||
* <p>
|
||||
* PreparedStatements should always be used and the intention is that there
|
||||
* should be no use of Statement at all. The implementation here is generally
|
||||
* for the case where someone uses the Statement api on an ExtendedPreparedStatement.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class ExtendedStatement extends PreparedStatementDelegator
|
||||
{
|
||||
|
||||
/**
|
||||
* The pooled connection this Statement belongs to.
|
||||
*/
|
||||
protected final PooledConnection pooledConnection;
|
||||
|
||||
/**
|
||||
* The underlying Statement that this object wraps.
|
||||
*/
|
||||
protected final PreparedStatement pstmt;
|
||||
|
||||
/**
|
||||
* Create the ExtendedStatement for a given pooledConnection.
|
||||
*/
|
||||
public ExtendedStatement(PooledConnection pooledConnection, PreparedStatement pstmt) {
|
||||
super(pstmt);
|
||||
|
||||
this.pooledConnection = pooledConnection;
|
||||
this.pstmt = pstmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the statement back into the statement cache.
|
||||
*/
|
||||
public abstract void close() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the underlying connection.
|
||||
*/
|
||||
public Connection getConnection() throws SQLException {
|
||||
try {
|
||||
return pstmt.getConnection();
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the sql for batch execution.
|
||||
*/
|
||||
public void addBatch(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
pstmt.addBatch(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the sql.
|
||||
*/
|
||||
public boolean execute(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.execute(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query.
|
||||
*/
|
||||
public ResultSet executeQuery(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.executeQuery(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the dml sql.
|
||||
*/
|
||||
public int executeUpdate(String sql) throws SQLException {
|
||||
try {
|
||||
pooledConnection.setLastStatement(sql);
|
||||
return pstmt.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
pooledConnection.addError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int[] executeBatch() throws SQLException {
|
||||
return pstmt.executeBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void cancel() throws SQLException {
|
||||
pstmt.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void clearBatch() throws SQLException {
|
||||
pstmt.clearBatch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void clearWarnings() throws SQLException {
|
||||
pstmt.clearWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getFetchDirection() throws SQLException {
|
||||
return pstmt.getFetchDirection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getFetchSize() throws SQLException {
|
||||
return pstmt.getFetchSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getMaxFieldSize() throws SQLException {
|
||||
return pstmt.getMaxFieldSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getMaxRows() throws SQLException {
|
||||
return pstmt.getMaxRows();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean getMoreResults() throws SQLException {
|
||||
return pstmt.getMoreResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getQueryTimeout() throws SQLException {
|
||||
return pstmt.getQueryTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public ResultSet getResultSet() throws SQLException {
|
||||
return pstmt.getResultSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetConcurrency() throws SQLException {
|
||||
return pstmt.getResultSetConcurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetType() throws SQLException {
|
||||
return pstmt.getResultSetType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getUpdateCount() throws SQLException {
|
||||
return pstmt.getUpdateCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public SQLWarning getWarnings() throws SQLException {
|
||||
return pstmt.getWarnings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setCursorName(String name) throws SQLException {
|
||||
pstmt.setCursorName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setEscapeProcessing(boolean enable) throws SQLException {
|
||||
pstmt.setEscapeProcessing(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setFetchDirection(int direction) throws SQLException {
|
||||
pstmt.setFetchDirection(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setFetchSize(int rows) throws SQLException {
|
||||
pstmt.setFetchSize(rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setMaxFieldSize(int max) throws SQLException {
|
||||
pstmt.setMaxFieldSize(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setMaxRows(int max) throws SQLException {
|
||||
pstmt.setMaxRows(max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public void setQueryTimeout(int seconds) throws SQLException {
|
||||
pstmt.setQueryTimeout(seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean getMoreResults(int i) throws SQLException {
|
||||
return pstmt.getMoreResults(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public ResultSet getGeneratedKeys() throws SQLException {
|
||||
return pstmt.getGeneratedKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, int i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, int[] i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int executeUpdate(String s, String[] i) throws SQLException {
|
||||
return pstmt.executeUpdate(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, int i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, int[] i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public boolean execute(String s, String[] i) throws SQLException {
|
||||
return pstmt.execute(s, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Statement method call.
|
||||
*/
|
||||
public int getResultSetHoldability() throws SQLException {
|
||||
return pstmt.getResultSetHoldability();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,106 +1,106 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues;
|
||||
|
||||
/**
|
||||
* A buffer designed especially to hold free pooled connections.
|
||||
* <p>
|
||||
* All thread safety controlled externally (by PooledConnectionQueue).
|
||||
* </p>
|
||||
*/
|
||||
class FreeConnectionBuffer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FreeConnectionBuffer.class);
|
||||
|
||||
/**
|
||||
* Buffer oriented for add and remove.
|
||||
*/
|
||||
private final LinkedList<PooledConnection> freeBuffer = new LinkedList<PooledConnection>();
|
||||
|
||||
protected FreeConnectionBuffer() {
|
||||
}
|
||||
|
||||
protected int size() {
|
||||
return freeBuffer.size();
|
||||
}
|
||||
|
||||
protected boolean isEmpty() {
|
||||
return freeBuffer.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add connection to the free list.
|
||||
*/
|
||||
protected void add(PooledConnection pc) {
|
||||
freeBuffer.addLast(pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a connection from the free list.
|
||||
*/
|
||||
protected PooledConnection remove() {
|
||||
return freeBuffer.removeFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all connections in this buffer.
|
||||
*/
|
||||
protected void closeAll(boolean logErrors) {
|
||||
|
||||
// create a temporary list
|
||||
List<PooledConnection> tempList = new ArrayList<PooledConnection>(freeBuffer.size());
|
||||
|
||||
// add all the connections into it
|
||||
for (PooledConnection c : freeBuffer) {
|
||||
tempList.add(c);
|
||||
}
|
||||
|
||||
// clear the buffer (in case it takes some time to close these connections).
|
||||
freeBuffer.clear();
|
||||
|
||||
logger.debug("... closing all {} connections from the free list with logErrors: {}", tempList.size(), logErrors);
|
||||
for (int i = 0; i < tempList.size(); i++) {
|
||||
PooledConnection pooledConnection = tempList.get(i);
|
||||
logger.debug("... closing {} of {} connections from the free list", i, tempList.size());
|
||||
pooledConnection.closeConnectionFully(logErrors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim any inactive connections that have not been used since usedSince.
|
||||
*/
|
||||
protected int trim(long usedSince, long createdSince) {
|
||||
|
||||
int trimCount = 0;
|
||||
|
||||
Iterator<PooledConnection> iterator = freeBuffer.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PooledConnection pooledConnection = iterator.next();
|
||||
if (pooledConnection.shouldTrim(usedSince, createdSince)) {
|
||||
iterator.remove();
|
||||
pooledConnection.closeConnectionFully(true);
|
||||
trimCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return trimCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the load statistics from all the free connections.
|
||||
*/
|
||||
protected void collectStatistics(LoadValues values, boolean reset) {
|
||||
|
||||
for (PooledConnection c : freeBuffer) {
|
||||
values.plus(c.getStatistics().getValues(reset));
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.sql.PooledConnectionStatistics.LoadValues;
|
||||
|
||||
/**
|
||||
* A buffer designed especially to hold free pooled connections.
|
||||
* <p>
|
||||
* All thread safety controlled externally (by PooledConnectionQueue).
|
||||
* </p>
|
||||
*/
|
||||
class FreeConnectionBuffer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FreeConnectionBuffer.class);
|
||||
|
||||
/**
|
||||
* Buffer oriented for add and remove.
|
||||
*/
|
||||
private final LinkedList<PooledConnection> freeBuffer = new LinkedList<PooledConnection>();
|
||||
|
||||
protected FreeConnectionBuffer() {
|
||||
}
|
||||
|
||||
protected int size() {
|
||||
return freeBuffer.size();
|
||||
}
|
||||
|
||||
protected boolean isEmpty() {
|
||||
return freeBuffer.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add connection to the free list.
|
||||
*/
|
||||
protected void add(PooledConnection pc) {
|
||||
freeBuffer.addLast(pc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a connection from the free list.
|
||||
*/
|
||||
protected PooledConnection remove() {
|
||||
return freeBuffer.removeFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all connections in this buffer.
|
||||
*/
|
||||
protected void closeAll(boolean logErrors) {
|
||||
|
||||
// create a temporary list
|
||||
List<PooledConnection> tempList = new ArrayList<PooledConnection>(freeBuffer.size());
|
||||
|
||||
// add all the connections into it
|
||||
for (PooledConnection c : freeBuffer) {
|
||||
tempList.add(c);
|
||||
}
|
||||
|
||||
// clear the buffer (in case it takes some time to close these connections).
|
||||
freeBuffer.clear();
|
||||
|
||||
logger.debug("... closing all {} connections from the free list with logErrors: {}", tempList.size(), logErrors);
|
||||
for (int i = 0; i < tempList.size(); i++) {
|
||||
PooledConnection pooledConnection = tempList.get(i);
|
||||
logger.debug("... closing {} of {} connections from the free list", i, tempList.size());
|
||||
pooledConnection.closeConnectionFully(logErrors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim any inactive connections that have not been used since usedSince.
|
||||
*/
|
||||
protected int trim(long usedSince, long createdSince) {
|
||||
|
||||
int trimCount = 0;
|
||||
|
||||
Iterator<PooledConnection> iterator = freeBuffer.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
PooledConnection pooledConnection = iterator.next();
|
||||
if (pooledConnection.shouldTrim(usedSince, createdSince)) {
|
||||
iterator.remove();
|
||||
pooledConnection.closeConnectionFully(true);
|
||||
trimCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return trimCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the load statistics from all the free connections.
|
||||
*/
|
||||
protected void collectStatistics(LoadValues values, boolean reset) {
|
||||
|
||||
for (PooledConnection c : freeBuffer) {
|
||||
values.plus(c.getStatistics().getValues(reset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,100 +1,100 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Security mechanisim.
|
||||
*/
|
||||
public class Prefix {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Prefix.class);
|
||||
|
||||
private static final int[] oa = { 50, 12, 4, 6, 8, 10, 7, 23, 45, 23, 6, 9, 12, 2, 8, 34 };
|
||||
|
||||
public static String getProp(String prop) {
|
||||
String v = dec(prop);
|
||||
int p = v.indexOf(":");
|
||||
String r = v.substring(1, p);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String m = e(args[0]);
|
||||
logger.info("[" + m + "]");
|
||||
String o = getProp(m);
|
||||
logger.info("[" + o + "]");
|
||||
}
|
||||
|
||||
public static String e(String msg) {
|
||||
msg = elen(msg, 40);
|
||||
return enc(msg);
|
||||
}
|
||||
|
||||
public static byte az(byte c, int offset) {
|
||||
|
||||
int z = c + offset;
|
||||
if (z > 122) {
|
||||
// dp("z> "+z);
|
||||
z = z - 122 + 48 - 1;
|
||||
}
|
||||
// dp("z="+z+" c:"+(int)c);
|
||||
return (byte) z;
|
||||
}
|
||||
|
||||
public static byte bz(byte c, int offset) {
|
||||
int z = c - offset;
|
||||
if (z < (48)) {
|
||||
// dp("z< "+z);
|
||||
z = z + 122 - 48 + 1;
|
||||
}
|
||||
return (byte) z;
|
||||
}
|
||||
|
||||
public static String enc(String msg) {
|
||||
byte[] msgbytes = msg.getBytes();
|
||||
byte[] encbytes = new byte[msgbytes.length + 1];
|
||||
Random r = new Random();
|
||||
int key = r.nextInt(70);
|
||||
|
||||
char k = (char) (key + 48);
|
||||
|
||||
encbytes[0] = az((byte) k, oa[0]);
|
||||
// dp("key:"+key+" encbytes[0]:"+(byte)encbytes[0]);
|
||||
int ios = key;
|
||||
for (int i = 1; i < (msgbytes.length + 1); i++) {
|
||||
encbytes[i] = az(msgbytes[i - 1], (oa[(i + ios) % oa.length]));
|
||||
}
|
||||
return new String(encbytes);
|
||||
}
|
||||
|
||||
public static String dec(String msg) {
|
||||
byte[] msgbytes = msg.getBytes();
|
||||
byte[] encbytes = new byte[msgbytes.length];
|
||||
|
||||
encbytes[0] = bz(msgbytes[0], oa[0]);
|
||||
byte key = encbytes[0];
|
||||
int ios = (key - 48);
|
||||
for (int i = 1; i < msgbytes.length; i++) {
|
||||
encbytes[i] = bz(msgbytes[i], oa[(i + ios) % oa.length]);
|
||||
}
|
||||
return new String(encbytes);
|
||||
}
|
||||
|
||||
public static String elen(String msg, int len) {
|
||||
Random r = new Random();
|
||||
if (msg.length() < len) {
|
||||
int max = len - msg.length();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(msg).append(":");
|
||||
for (int i = 1; i < max; i++) {
|
||||
int bc = r.nextInt(122 - 48);
|
||||
sb.append(Character.toString((char) (bc + 48)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Security mechanisim.
|
||||
*/
|
||||
public class Prefix {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Prefix.class);
|
||||
|
||||
private static final int[] oa = { 50, 12, 4, 6, 8, 10, 7, 23, 45, 23, 6, 9, 12, 2, 8, 34 };
|
||||
|
||||
public static String getProp(String prop) {
|
||||
String v = dec(prop);
|
||||
int p = v.indexOf(":");
|
||||
String r = v.substring(1, p);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String m = e(args[0]);
|
||||
logger.info("[" + m + "]");
|
||||
String o = getProp(m);
|
||||
logger.info("[" + o + "]");
|
||||
}
|
||||
|
||||
public static String e(String msg) {
|
||||
msg = elen(msg, 40);
|
||||
return enc(msg);
|
||||
}
|
||||
|
||||
public static byte az(byte c, int offset) {
|
||||
|
||||
int z = c + offset;
|
||||
if (z > 122) {
|
||||
// dp("z> "+z);
|
||||
z = z - 122 + 48 - 1;
|
||||
}
|
||||
// dp("z="+z+" c:"+(int)c);
|
||||
return (byte) z;
|
||||
}
|
||||
|
||||
public static byte bz(byte c, int offset) {
|
||||
int z = c - offset;
|
||||
if (z < (48)) {
|
||||
// dp("z< "+z);
|
||||
z = z + 122 - 48 + 1;
|
||||
}
|
||||
return (byte) z;
|
||||
}
|
||||
|
||||
public static String enc(String msg) {
|
||||
byte[] msgbytes = msg.getBytes();
|
||||
byte[] encbytes = new byte[msgbytes.length + 1];
|
||||
Random r = new Random();
|
||||
int key = r.nextInt(70);
|
||||
|
||||
char k = (char) (key + 48);
|
||||
|
||||
encbytes[0] = az((byte) k, oa[0]);
|
||||
// dp("key:"+key+" encbytes[0]:"+(byte)encbytes[0]);
|
||||
int ios = key;
|
||||
for (int i = 1; i < (msgbytes.length + 1); i++) {
|
||||
encbytes[i] = az(msgbytes[i - 1], (oa[(i + ios) % oa.length]));
|
||||
}
|
||||
return new String(encbytes);
|
||||
}
|
||||
|
||||
public static String dec(String msg) {
|
||||
byte[] msgbytes = msg.getBytes();
|
||||
byte[] encbytes = new byte[msgbytes.length];
|
||||
|
||||
encbytes[0] = bz(msgbytes[0], oa[0]);
|
||||
byte key = encbytes[0];
|
||||
int ios = (key - 48);
|
||||
for (int i = 1; i < msgbytes.length; i++) {
|
||||
encbytes[i] = bz(msgbytes[i], oa[(i + ios) % oa.length]);
|
||||
}
|
||||
return new String(encbytes);
|
||||
}
|
||||
|
||||
public static String elen(String msg, int len) {
|
||||
Random r = new Random();
|
||||
if (msg.length() < len) {
|
||||
int max = len - msg.length();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(msg).append(":");
|
||||
for (int i = 1; i < max; i++) {
|
||||
int bc = r.nextInt(122 - 48);
|
||||
sb.append(Character.toString((char) (bc + 48)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +1,183 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A LRU based cache for PreparedStatements.
|
||||
*/
|
||||
public class PstmtCache extends LinkedHashMap<String, ExtendedPreparedStatement> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PstmtCache.class);
|
||||
|
||||
static final long serialVersionUID = -3096406924865550697L;
|
||||
|
||||
/**
|
||||
* The name of the cache, for tracing purposes.
|
||||
*/
|
||||
protected final String cacheName;
|
||||
|
||||
/**
|
||||
* The maximum size of the cache. When this is exceeded the oldest entry is removed.
|
||||
*/
|
||||
private final int maxSize;
|
||||
|
||||
/**
|
||||
* The total number of entries removed from this cache.
|
||||
*/
|
||||
private int removeCounter;
|
||||
|
||||
/**
|
||||
* The number of get hits.
|
||||
*/
|
||||
private int hitCounter;
|
||||
|
||||
/**
|
||||
* The number of get() misses.
|
||||
*/
|
||||
private int missCounter;
|
||||
|
||||
/**
|
||||
* The number of puts into this cache.
|
||||
*/
|
||||
private int putCounter;
|
||||
|
||||
public PstmtCache(String cacheName, int maxCacheSize) {
|
||||
|
||||
// note = access ordered list. This is what gives it the LRU order
|
||||
super(maxCacheSize*3, 0.75f, true);
|
||||
this.cacheName = cacheName;
|
||||
this.maxSize = maxCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this cache.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return "size["+size()+"] max["+maxSize+"] hits["+hitCounter+"] miss["+missCounter+"] hitRatio["+getHitRatio()+"] removes["+removeCounter+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current maximum size of the cache.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hit ratio. A number between 0 and 100 indicating the number of
|
||||
* hits to misses. A number approaching 100 is desirable.
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
if (hitCounter == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return hitCounter*100/(hitCounter+missCounter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of hits against this cache.
|
||||
*/
|
||||
public int getHitCounter() {
|
||||
return hitCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of misses against this cache.
|
||||
*/
|
||||
public int getMissCounter() {
|
||||
return missCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of puts against this cache.
|
||||
*/
|
||||
public int getPutCounter() {
|
||||
return putCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to add the returning statement to the cache. If there is already a
|
||||
* matching ExtendedPreparedStatement in the cache return false else add
|
||||
* the statement to the cache and return true.
|
||||
*/
|
||||
public boolean returnStatement(ExtendedPreparedStatement pstmt) {
|
||||
|
||||
ExtendedPreparedStatement alreadyInCache = super.get(pstmt.getCacheKey());
|
||||
if (alreadyInCache != null) {
|
||||
return false;
|
||||
}
|
||||
// add the returning prepared statement to the cache.
|
||||
// Note that the LRUCache will automatically close fully old unused
|
||||
// PStmts when the cache has hit its maximum size.
|
||||
put(pstmt.getCacheKey(), pstmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains hit and miss statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement get(Object key) {
|
||||
|
||||
ExtendedPreparedStatement o = super.get(key);
|
||||
if (o == null) {
|
||||
missCounter++;
|
||||
} else {
|
||||
hitCounter++;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains hit and miss statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement remove(Object key) {
|
||||
|
||||
ExtendedPreparedStatement o = super.remove(key);
|
||||
if (o == null) {
|
||||
missCounter++;
|
||||
} else {
|
||||
hitCounter++;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains put counter statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement put(String key, ExtendedPreparedStatement value) {
|
||||
|
||||
putCounter++;
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* will check to see if we need to remove entries and
|
||||
* if so call the cacheCleanup.cleanupEldestLRUCacheEntry() if
|
||||
* one has been set.
|
||||
*/
|
||||
protected boolean removeEldestEntry(Map.Entry<String,ExtendedPreparedStatement> eldest) {
|
||||
|
||||
if (size() < maxSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeCounter++;
|
||||
|
||||
try {
|
||||
ExtendedPreparedStatement pstmt = eldest.getValue();
|
||||
pstmt.closeDestroy();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing ExtendedPreparedStatement", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A LRU based cache for PreparedStatements.
|
||||
*/
|
||||
public class PstmtCache extends LinkedHashMap<String, ExtendedPreparedStatement> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PstmtCache.class);
|
||||
|
||||
static final long serialVersionUID = -3096406924865550697L;
|
||||
|
||||
/**
|
||||
* The name of the cache, for tracing purposes.
|
||||
*/
|
||||
protected final String cacheName;
|
||||
|
||||
/**
|
||||
* The maximum size of the cache. When this is exceeded the oldest entry is removed.
|
||||
*/
|
||||
private final int maxSize;
|
||||
|
||||
/**
|
||||
* The total number of entries removed from this cache.
|
||||
*/
|
||||
private int removeCounter;
|
||||
|
||||
/**
|
||||
* The number of get hits.
|
||||
*/
|
||||
private int hitCounter;
|
||||
|
||||
/**
|
||||
* The number of get() misses.
|
||||
*/
|
||||
private int missCounter;
|
||||
|
||||
/**
|
||||
* The number of puts into this cache.
|
||||
*/
|
||||
private int putCounter;
|
||||
|
||||
public PstmtCache(String cacheName, int maxCacheSize) {
|
||||
|
||||
// note = access ordered list. This is what gives it the LRU order
|
||||
super(maxCacheSize*3, 0.75f, true);
|
||||
this.cacheName = cacheName;
|
||||
this.maxSize = maxCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a summary description of this cache.
|
||||
*/
|
||||
public String getDescription() {
|
||||
return "size["+size()+"] max["+maxSize+"] hits["+hitCounter+"] miss["+missCounter+"] hitRatio["+getHitRatio()+"] removes["+removeCounter+"]";
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the current maximum size of the cache.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hit ratio. A number between 0 and 100 indicating the number of
|
||||
* hits to misses. A number approaching 100 is desirable.
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
if (hitCounter == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return hitCounter*100/(hitCounter+missCounter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of hits against this cache.
|
||||
*/
|
||||
public int getHitCounter() {
|
||||
return hitCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of misses against this cache.
|
||||
*/
|
||||
public int getMissCounter() {
|
||||
return missCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of puts against this cache.
|
||||
*/
|
||||
public int getPutCounter() {
|
||||
return putCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to add the returning statement to the cache. If there is already a
|
||||
* matching ExtendedPreparedStatement in the cache return false else add
|
||||
* the statement to the cache and return true.
|
||||
*/
|
||||
public boolean returnStatement(ExtendedPreparedStatement pstmt) {
|
||||
|
||||
ExtendedPreparedStatement alreadyInCache = super.get(pstmt.getCacheKey());
|
||||
if (alreadyInCache != null) {
|
||||
return false;
|
||||
}
|
||||
// add the returning prepared statement to the cache.
|
||||
// Note that the LRUCache will automatically close fully old unused
|
||||
// PStmts when the cache has hit its maximum size.
|
||||
put(pstmt.getCacheKey(), pstmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains hit and miss statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement get(Object key) {
|
||||
|
||||
ExtendedPreparedStatement o = super.get(key);
|
||||
if (o == null) {
|
||||
missCounter++;
|
||||
} else {
|
||||
hitCounter++;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains hit and miss statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement remove(Object key) {
|
||||
|
||||
ExtendedPreparedStatement o = super.remove(key);
|
||||
if (o == null) {
|
||||
missCounter++;
|
||||
} else {
|
||||
hitCounter++;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* additionally maintains put counter statistics.
|
||||
*/
|
||||
public ExtendedPreparedStatement put(String key, ExtendedPreparedStatement value) {
|
||||
|
||||
putCounter++;
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* will check to see if we need to remove entries and
|
||||
* if so call the cacheCleanup.cleanupEldestLRUCacheEntry() if
|
||||
* one has been set.
|
||||
*/
|
||||
protected boolean removeEldestEntry(Map.Entry<String,ExtendedPreparedStatement> eldest) {
|
||||
|
||||
if (size() < maxSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
removeCounter++;
|
||||
|
||||
try {
|
||||
ExtendedPreparedStatement pstmt = eldest.getValue();
|
||||
pstmt.closeDestroy();
|
||||
} catch (SQLException e) {
|
||||
logger.error("Error closing ExtendedPreparedStatement", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,106 +1,106 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailEvent;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailListener;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailMessage;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailSender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple smtp email alert that sends a email message on dataSourceDown and
|
||||
* dataSourceUp etc.
|
||||
* <ul>
|
||||
* <li>alert.fromuser = the from user name
|
||||
* <li>alert.fromemail = the from email account
|
||||
* <li>alert.toemail = comma delimited list of email accounts to email
|
||||
* <li>alert.mailserver = the smpt server name
|
||||
* </ul>
|
||||
*/
|
||||
public class SimpleDataSourceAlert implements DataSourceAlert, MailListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleDataSourceAlert.class);
|
||||
|
||||
private static String alertMailServerName = System.getProperty("ebean.datasource.alert.mailserver");
|
||||
|
||||
private static String fromUser = System.getProperty("ebean.datasource.alert.fromUser");
|
||||
private static String fromEmail = System.getProperty("ebean.datasource.alert.fromEmail");
|
||||
private static String toEmail = System.getProperty("ebean.datasource.alert.toEmail");
|
||||
|
||||
/**
|
||||
* Create a SimpleAlerter.
|
||||
*/
|
||||
public SimpleDataSourceAlert() {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the email failed then log the error.
|
||||
*/
|
||||
public void handleEvent(MailEvent event) {
|
||||
Throwable e = event.getError();
|
||||
if (e != null) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the dataSource down alert.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceDown(String dataSourceName) {
|
||||
String msg = getSubject(true, dataSourceName);
|
||||
sendMessage(msg, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the dataSource up alert.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceUp(String dataSourceName) {
|
||||
String msg = getSubject(false, dataSourceName);
|
||||
sendMessage(msg, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the warning message.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceWarning(String subject, String msg) {
|
||||
sendMessage(subject, msg);
|
||||
}
|
||||
|
||||
private String getSubject(boolean isDown, String dsName) {
|
||||
String msg = "The DataSource " + dsName;
|
||||
if (isDown) {
|
||||
msg += " is DOWN!!";
|
||||
} else {
|
||||
msg += " is UP.";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void sendMessage(String subject, String msg) {
|
||||
|
||||
if (alertMailServerName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MailMessage data = new MailMessage();
|
||||
data.setSender(fromUser, fromEmail);
|
||||
data.addBodyLine(msg);
|
||||
data.setSubject(subject);
|
||||
|
||||
String[] toList = toEmail.split(",");
|
||||
if (toList.length == 0) {
|
||||
logger.error("alert.toemail has not been set?");
|
||||
} else {
|
||||
for (int i = 0; i < toList.length; i++) {
|
||||
data.addRecipient(null, toList[i].trim());
|
||||
}
|
||||
MailSender sender = new MailSender(alertMailServerName);
|
||||
sender.setMailListener(this);
|
||||
sender.sendInBackground(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailEvent;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailListener;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailMessage;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailSender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple smtp email alert that sends a email message on dataSourceDown and
|
||||
* dataSourceUp etc.
|
||||
* <ul>
|
||||
* <li>alert.fromuser = the from user name
|
||||
* <li>alert.fromemail = the from email account
|
||||
* <li>alert.toemail = comma delimited list of email accounts to email
|
||||
* <li>alert.mailserver = the smpt server name
|
||||
* </ul>
|
||||
*/
|
||||
public class SimpleDataSourceAlert implements DataSourceAlert, MailListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleDataSourceAlert.class);
|
||||
|
||||
private static String alertMailServerName = System.getProperty("ebean.datasource.alert.mailserver");
|
||||
|
||||
private static String fromUser = System.getProperty("ebean.datasource.alert.fromUser");
|
||||
private static String fromEmail = System.getProperty("ebean.datasource.alert.fromEmail");
|
||||
private static String toEmail = System.getProperty("ebean.datasource.alert.toEmail");
|
||||
|
||||
/**
|
||||
* Create a SimpleAlerter.
|
||||
*/
|
||||
public SimpleDataSourceAlert() {
|
||||
}
|
||||
|
||||
/**
|
||||
* If the email failed then log the error.
|
||||
*/
|
||||
public void handleEvent(MailEvent event) {
|
||||
Throwable e = event.getError();
|
||||
if (e != null) {
|
||||
logger.error(null, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the dataSource down alert.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceDown(String dataSourceName) {
|
||||
String msg = getSubject(true, dataSourceName);
|
||||
sendMessage(msg, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the dataSource up alert.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceUp(String dataSourceName) {
|
||||
String msg = getSubject(false, dataSourceName);
|
||||
sendMessage(msg, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the warning message.
|
||||
*/
|
||||
@Override
|
||||
public void dataSourceWarning(String subject, String msg) {
|
||||
sendMessage(subject, msg);
|
||||
}
|
||||
|
||||
private String getSubject(boolean isDown, String dsName) {
|
||||
String msg = "The DataSource " + dsName;
|
||||
if (isDown) {
|
||||
msg += " is DOWN!!";
|
||||
} else {
|
||||
msg += " is UP.";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void sendMessage(String subject, String msg) {
|
||||
|
||||
if (alertMailServerName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MailMessage data = new MailMessage();
|
||||
data.setSender(fromUser, fromEmail);
|
||||
data.addBodyLine(msg);
|
||||
data.setSubject(subject);
|
||||
|
||||
String[] toList = toEmail.split(",");
|
||||
if (toList.length == 0) {
|
||||
logger.error("alert.toemail has not been set?");
|
||||
} else {
|
||||
for (int i = 0; i < toList.length; i++) {
|
||||
data.addRecipient(null, toList[i].trim());
|
||||
}
|
||||
MailSender sender = new MailSender(alertMailServerName);
|
||||
sender.setMailListener(this);
|
||||
sender.sendInBackground(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* Helper object that can convert between transaction isolation descriptions and values.
|
||||
*
|
||||
*/
|
||||
public class TransactionIsolation {
|
||||
|
||||
|
||||
/**
|
||||
* return the isolation level for a given string description.
|
||||
*/
|
||||
public static int getLevel(String level) {
|
||||
level = level.toUpperCase();
|
||||
if (level.startsWith("TRANSACTION")){
|
||||
level = level.substring("TRANSACTION".length());
|
||||
}
|
||||
level = level.replace("_", "");
|
||||
if ("NONE".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_NONE;
|
||||
}
|
||||
if ("READCOMMITTED".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_READ_COMMITTED;
|
||||
}
|
||||
if ("READUNCOMMITTED".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
}
|
||||
if ("REPEATABLEREAD".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_REPEATABLE_READ;
|
||||
}
|
||||
if ("SERIALIZABLE".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_SERIALIZABLE;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string description of the transaction isolation level specified.
|
||||
* <p>Returned value is one of NONE, READ_COMMITTED,READ_UNCOMMITTED,
|
||||
* REPEATABLE_READ or SERIALIZABLE.</p>
|
||||
*
|
||||
* @param level the transaction isolation level as per java.sql.Connection
|
||||
* @return the level description as a string.
|
||||
*/
|
||||
public static String getLevelDescription(int level) {
|
||||
switch (level) {
|
||||
case Connection.TRANSACTION_NONE :
|
||||
return "NONE";
|
||||
case Connection.TRANSACTION_READ_COMMITTED :
|
||||
return "READ_COMMITTED";
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED :
|
||||
return "READ_UNCOMMITTED";
|
||||
case Connection.TRANSACTION_REPEATABLE_READ :
|
||||
return "REPEATABLE_READ";
|
||||
case Connection.TRANSACTION_SERIALIZABLE :
|
||||
return "SERIALIZABLE";
|
||||
case -1 :
|
||||
return "NotSet";
|
||||
default :
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not defined.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* Helper object that can convert between transaction isolation descriptions and values.
|
||||
*
|
||||
*/
|
||||
public class TransactionIsolation {
|
||||
|
||||
|
||||
/**
|
||||
* return the isolation level for a given string description.
|
||||
*/
|
||||
public static int getLevel(String level) {
|
||||
level = level.toUpperCase();
|
||||
if (level.startsWith("TRANSACTION")){
|
||||
level = level.substring("TRANSACTION".length());
|
||||
}
|
||||
level = level.replace("_", "");
|
||||
if ("NONE".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_NONE;
|
||||
}
|
||||
if ("READCOMMITTED".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_READ_COMMITTED;
|
||||
}
|
||||
if ("READUNCOMMITTED".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
}
|
||||
if ("REPEATABLEREAD".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_REPEATABLE_READ;
|
||||
}
|
||||
if ("SERIALIZABLE".equalsIgnoreCase(level)){
|
||||
return Connection.TRANSACTION_SERIALIZABLE;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string description of the transaction isolation level specified.
|
||||
* <p>Returned value is one of NONE, READ_COMMITTED,READ_UNCOMMITTED,
|
||||
* REPEATABLE_READ or SERIALIZABLE.</p>
|
||||
*
|
||||
* @param level the transaction isolation level as per java.sql.Connection
|
||||
* @return the level description as a string.
|
||||
*/
|
||||
public static String getLevelDescription(int level) {
|
||||
switch (level) {
|
||||
case Connection.TRANSACTION_NONE :
|
||||
return "NONE";
|
||||
case Connection.TRANSACTION_READ_COMMITTED :
|
||||
return "READ_COMMITTED";
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED :
|
||||
return "READ_UNCOMMITTED";
|
||||
case Connection.TRANSACTION_REPEATABLE_READ :
|
||||
return "REPEATABLE_READ";
|
||||
case Connection.TRANSACTION_SERIALIZABLE :
|
||||
return "SERIALIZABLE";
|
||||
case -1 :
|
||||
return "NotSet";
|
||||
default :
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not defined.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception when creating an Object.
|
||||
*/
|
||||
public class CreateObjectException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539736L;
|
||||
|
||||
public CreateObjectException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public CreateObjectException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public CreateObjectException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception when creating an Object.
|
||||
*/
|
||||
public class CreateObjectException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539736L;
|
||||
|
||||
public CreateObjectException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public CreateObjectException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public CreateObjectException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,324 +1,324 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A lightweight tree structure for simple XML handling.
|
||||
* <p>
|
||||
* It removes support for nodes being mixed with content. That is, a node can
|
||||
* only contain content or a list of one or more child nodes. It does not
|
||||
* support mixing bits of content between the child nodes.
|
||||
* </p>
|
||||
* <p>
|
||||
* Although designed to simplify XML in supported cases it can be used as a
|
||||
* general tree structure with attributes of java Objects.
|
||||
* </p>
|
||||
*/
|
||||
public class Dnode {
|
||||
|
||||
int level;
|
||||
|
||||
String nodeName;
|
||||
|
||||
String nodeContent;
|
||||
|
||||
ArrayList<Dnode> children;
|
||||
|
||||
LinkedHashMap<String, String> attrList = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Create a node.
|
||||
*/
|
||||
public Dnode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw XML string.
|
||||
*/
|
||||
public static Dnode parse(String s){
|
||||
DnodeReader r = new DnodeReader();
|
||||
return r.parseXml(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node as XML.
|
||||
*/
|
||||
public String toXml() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
generate(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate this node as xml to the buffer.
|
||||
*/
|
||||
public StringBuilder generate(StringBuilder sb) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
sb.append("<").append(nodeName);
|
||||
for (String attr : attrList.keySet()) {
|
||||
Object attrValue = getAttribute(attr);
|
||||
sb.append(" ").append(attr).append("=\"");
|
||||
if (attrValue != null) {
|
||||
sb.append(attrValue);
|
||||
}
|
||||
sb.append("\"");
|
||||
}
|
||||
|
||||
if (nodeContent == null && !hasChildren()) {
|
||||
sb.append(" />");
|
||||
|
||||
} else {
|
||||
sb.append(">");
|
||||
if (children != null && children.size() > 0) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.generate(sb);
|
||||
}
|
||||
}
|
||||
if (nodeContent != null) {
|
||||
sb.append(nodeContent);
|
||||
}
|
||||
sb.append("</").append(nodeName).append(">");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node name.
|
||||
*/
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node name.
|
||||
*/
|
||||
public void setNodeName(String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node content.
|
||||
*/
|
||||
public String getNodeContent() {
|
||||
return nodeContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node content.
|
||||
*/
|
||||
public void setNodeContent(String nodeContent) {
|
||||
this.nodeContent = nodeContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this node has children.
|
||||
*/
|
||||
public boolean hasChildren() {
|
||||
return getChildrenCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of children this node has.
|
||||
*/
|
||||
public int getChildrenCount() {
|
||||
if (children == null) {
|
||||
return 0;
|
||||
}
|
||||
return children.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a ancestor node.
|
||||
*/
|
||||
public boolean remove(Dnode node) {
|
||||
if (children == null) {
|
||||
return false;
|
||||
}
|
||||
if (children.remove(node)) {
|
||||
return true;
|
||||
}
|
||||
for (Dnode child : children) {
|
||||
if (child.remove(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of children nodes.
|
||||
*/
|
||||
public List<Dnode> children() {
|
||||
if (children == null) {
|
||||
return null;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child.
|
||||
*/
|
||||
public void addChild(Dnode child) {
|
||||
if (children == null) {
|
||||
children = new ArrayList<Dnode>();
|
||||
}
|
||||
children.add(child);
|
||||
child.setLevel(level + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level or depth of the node from the root.
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the level or depth of this node from the root.
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.setLevel(level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first matching node using nodeName. This is a depth first tree
|
||||
* search.
|
||||
*/
|
||||
public Dnode find(String nodeName) {
|
||||
return find(nodeName, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first node matching nodeName and attribute value. This is a
|
||||
* depth first tree search.
|
||||
*/
|
||||
public Dnode find(String nodeName, String attrName, Object value) {
|
||||
|
||||
return find(nodeName, attrName, value, -1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a single node with control over maxLevel. Find the first node
|
||||
* matching nodeName and attribute value. If attrName and value are null
|
||||
* then this will just search using the nodeName. This is a depth first tree
|
||||
* search. Once a matching node is found the search will stop.
|
||||
*/
|
||||
public Dnode find(String nodeName, String attrName, Object value, int maxLevel) {
|
||||
|
||||
ArrayList<Dnode> list = new ArrayList<Dnode>();
|
||||
findByNode(list, nodeName, true, attrName, value, maxLevel);
|
||||
if (list.size() >= 1) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the nodes that match the nodeName.
|
||||
*
|
||||
*/
|
||||
public List<Dnode> findAll(String nodeName, int maxLevel) {
|
||||
int level = -1;
|
||||
if (maxLevel > 0) {
|
||||
level = this.level + maxLevel;
|
||||
}
|
||||
return findAll(nodeName, null, null, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the nodes that match the nodeName and attribute value.
|
||||
*/
|
||||
public List<Dnode> findAll(String nodeName, String attrName, Object value, int maxLevel) {
|
||||
|
||||
if (nodeName == null && attrName == null) {
|
||||
throw new RuntimeException("You can not have both nodeName and attrName null");
|
||||
}
|
||||
ArrayList<Dnode> list = new ArrayList<Dnode>();
|
||||
findByNode(list, nodeName, false, attrName, value, maxLevel);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for recursive calling.
|
||||
*/
|
||||
private void findByNode(List<Dnode> list, String node, boolean findOne,String attrName, Object value, int maxLevel) {
|
||||
|
||||
if (findOne && list.size() == 1) {
|
||||
return;
|
||||
}
|
||||
if (node == null || node.equals(nodeName)) {
|
||||
if (attrName == null || value.equals(getAttribute(attrName))) {
|
||||
list.add(this);
|
||||
if (findOne) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxLevel > 0 && level >= maxLevel) {
|
||||
// hit max level
|
||||
|
||||
} else if (children != null) {
|
||||
// recursively search the children
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.findByNode(list, node, findOne, attrName, value,maxLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute names as strings.
|
||||
*/
|
||||
public Collection<String> attributeNames() {
|
||||
return attrList.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute for a given name.
|
||||
*/
|
||||
public String getAttribute(String name) {
|
||||
return attrList.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Attribute as a String.
|
||||
* <p>
|
||||
* Will throw a ClassCastException if the attribute is not a String.
|
||||
* </p>
|
||||
*/
|
||||
public String getStringAttr(String name, String defaultValue) {
|
||||
Object o = attrList.get(name);
|
||||
if (o == null){
|
||||
return defaultValue;
|
||||
} else {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an attribute.
|
||||
*/
|
||||
public void setAttribute(String name, String value) {
|
||||
attrList.put(name, value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[").append(getNodeName()).append(" ").append(attrList).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A lightweight tree structure for simple XML handling.
|
||||
* <p>
|
||||
* It removes support for nodes being mixed with content. That is, a node can
|
||||
* only contain content or a list of one or more child nodes. It does not
|
||||
* support mixing bits of content between the child nodes.
|
||||
* </p>
|
||||
* <p>
|
||||
* Although designed to simplify XML in supported cases it can be used as a
|
||||
* general tree structure with attributes of java Objects.
|
||||
* </p>
|
||||
*/
|
||||
public class Dnode {
|
||||
|
||||
int level;
|
||||
|
||||
String nodeName;
|
||||
|
||||
String nodeContent;
|
||||
|
||||
ArrayList<Dnode> children;
|
||||
|
||||
LinkedHashMap<String, String> attrList = new LinkedHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Create a node.
|
||||
*/
|
||||
public Dnode() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the raw XML string.
|
||||
*/
|
||||
public static Dnode parse(String s){
|
||||
DnodeReader r = new DnodeReader();
|
||||
return r.parseXml(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node as XML.
|
||||
*/
|
||||
public String toXml() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
generate(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate this node as xml to the buffer.
|
||||
*/
|
||||
public StringBuilder generate(StringBuilder sb) {
|
||||
if (sb == null) {
|
||||
sb = new StringBuilder();
|
||||
}
|
||||
sb.append("<").append(nodeName);
|
||||
for (String attr : attrList.keySet()) {
|
||||
Object attrValue = getAttribute(attr);
|
||||
sb.append(" ").append(attr).append("=\"");
|
||||
if (attrValue != null) {
|
||||
sb.append(attrValue);
|
||||
}
|
||||
sb.append("\"");
|
||||
}
|
||||
|
||||
if (nodeContent == null && !hasChildren()) {
|
||||
sb.append(" />");
|
||||
|
||||
} else {
|
||||
sb.append(">");
|
||||
if (children != null && children.size() > 0) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.generate(sb);
|
||||
}
|
||||
}
|
||||
if (nodeContent != null) {
|
||||
sb.append(nodeContent);
|
||||
}
|
||||
sb.append("</").append(nodeName).append(">");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node name.
|
||||
*/
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node name.
|
||||
*/
|
||||
public void setNodeName(String nodeName) {
|
||||
this.nodeName = nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the node content.
|
||||
*/
|
||||
public String getNodeContent() {
|
||||
return nodeContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node content.
|
||||
*/
|
||||
public void setNodeContent(String nodeContent) {
|
||||
this.nodeContent = nodeContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this node has children.
|
||||
*/
|
||||
public boolean hasChildren() {
|
||||
return getChildrenCount() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of children this node has.
|
||||
*/
|
||||
public int getChildrenCount() {
|
||||
if (children == null) {
|
||||
return 0;
|
||||
}
|
||||
return children.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a ancestor node.
|
||||
*/
|
||||
public boolean remove(Dnode node) {
|
||||
if (children == null) {
|
||||
return false;
|
||||
}
|
||||
if (children.remove(node)) {
|
||||
return true;
|
||||
}
|
||||
for (Dnode child : children) {
|
||||
if (child.remove(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of children nodes.
|
||||
*/
|
||||
public List<Dnode> children() {
|
||||
if (children == null) {
|
||||
return null;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a child.
|
||||
*/
|
||||
public void addChild(Dnode child) {
|
||||
if (children == null) {
|
||||
children = new ArrayList<Dnode>();
|
||||
}
|
||||
children.add(child);
|
||||
child.setLevel(level + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level or depth of the node from the root.
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the level or depth of this node from the root.
|
||||
*/
|
||||
public void setLevel(int level) {
|
||||
this.level = level;
|
||||
if (children != null) {
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.setLevel(level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first matching node using nodeName. This is a depth first tree
|
||||
* search.
|
||||
*/
|
||||
public Dnode find(String nodeName) {
|
||||
return find(nodeName, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first node matching nodeName and attribute value. This is a
|
||||
* depth first tree search.
|
||||
*/
|
||||
public Dnode find(String nodeName, String attrName, Object value) {
|
||||
|
||||
return find(nodeName, attrName, value, -1);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a single node with control over maxLevel. Find the first node
|
||||
* matching nodeName and attribute value. If attrName and value are null
|
||||
* then this will just search using the nodeName. This is a depth first tree
|
||||
* search. Once a matching node is found the search will stop.
|
||||
*/
|
||||
public Dnode find(String nodeName, String attrName, Object value, int maxLevel) {
|
||||
|
||||
ArrayList<Dnode> list = new ArrayList<Dnode>();
|
||||
findByNode(list, nodeName, true, attrName, value, maxLevel);
|
||||
if (list.size() >= 1) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the nodes that match the nodeName.
|
||||
*
|
||||
*/
|
||||
public List<Dnode> findAll(String nodeName, int maxLevel) {
|
||||
int level = -1;
|
||||
if (maxLevel > 0) {
|
||||
level = this.level + maxLevel;
|
||||
}
|
||||
return findAll(nodeName, null, null, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the nodes that match the nodeName and attribute value.
|
||||
*/
|
||||
public List<Dnode> findAll(String nodeName, String attrName, Object value, int maxLevel) {
|
||||
|
||||
if (nodeName == null && attrName == null) {
|
||||
throw new RuntimeException("You can not have both nodeName and attrName null");
|
||||
}
|
||||
ArrayList<Dnode> list = new ArrayList<Dnode>();
|
||||
findByNode(list, nodeName, false, attrName, value, maxLevel);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for recursive calling.
|
||||
*/
|
||||
private void findByNode(List<Dnode> list, String node, boolean findOne,String attrName, Object value, int maxLevel) {
|
||||
|
||||
if (findOne && list.size() == 1) {
|
||||
return;
|
||||
}
|
||||
if (node == null || node.equals(nodeName)) {
|
||||
if (attrName == null || value.equals(getAttribute(attrName))) {
|
||||
list.add(this);
|
||||
if (findOne) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (maxLevel > 0 && level >= maxLevel) {
|
||||
// hit max level
|
||||
|
||||
} else if (children != null) {
|
||||
// recursively search the children
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
Dnode child = children.get(i);
|
||||
child.findByNode(list, node, findOne, attrName, value,maxLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute names as strings.
|
||||
*/
|
||||
public Collection<String> attributeNames() {
|
||||
return attrList.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the attribute for a given name.
|
||||
*/
|
||||
public String getAttribute(String name) {
|
||||
return attrList.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Attribute as a String.
|
||||
* <p>
|
||||
* Will throw a ClassCastException if the attribute is not a String.
|
||||
* </p>
|
||||
*/
|
||||
public String getStringAttr(String name, String defaultValue) {
|
||||
Object o = attrList.get(name);
|
||||
if (o == null){
|
||||
return defaultValue;
|
||||
} else {
|
||||
return o.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an attribute.
|
||||
*/
|
||||
public void setAttribute(String name, String value) {
|
||||
attrList.put(name, value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[").append(getNodeName()).append(" ").append(attrList).append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,200 +1,200 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Parse an xml document into a Dnode tree.
|
||||
*/
|
||||
public class DnodeParser extends DefaultHandler {
|
||||
|
||||
/**
|
||||
* The root of the DContent tree.
|
||||
*/
|
||||
Dnode root;
|
||||
|
||||
/**
|
||||
* The current node being parsed.
|
||||
*/
|
||||
Dnode currentNode;
|
||||
|
||||
/**
|
||||
* The nodeContent buffer.
|
||||
*/
|
||||
StringBuilder buffer;
|
||||
|
||||
/**
|
||||
* Used to stack the nodes.
|
||||
*/
|
||||
Stack<Dnode> stack = new Stack<Dnode>();
|
||||
|
||||
/**
|
||||
* The class used to construct new nodes. Should be Dnode or a subtype of
|
||||
* Dnode.
|
||||
*/
|
||||
Class<?> nodeClass = Dnode.class;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
/**
|
||||
* Trim whitespace from the content.
|
||||
*/
|
||||
boolean trimWhitespace = true;
|
||||
|
||||
/**
|
||||
* The name of the tag that contains html content
|
||||
*/
|
||||
String contentName;
|
||||
|
||||
/**
|
||||
* The depth of the tag that contains the html content
|
||||
*/
|
||||
int contentDepth;
|
||||
|
||||
|
||||
/**
|
||||
* If true then trim the whitespace from the content.
|
||||
*/
|
||||
public boolean isTrimWhitespace() {
|
||||
return trimWhitespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to trim whitespace from the content.
|
||||
*/
|
||||
public void setTrimWhitespace(boolean trimWhitespace) {
|
||||
this.trimWhitespace = trimWhitespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root node of the DContent tree.
|
||||
*/
|
||||
public Dnode getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type class of node to be created.
|
||||
*/
|
||||
public void setNodeClass(Class<?> nodeClass) {
|
||||
this.nodeClass = nodeClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Dnode using the nodeClass.
|
||||
*/
|
||||
private Dnode createNewNode() {
|
||||
try {
|
||||
return (Dnode) nodeClass.newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* process a startElement.
|
||||
*/
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||
throws SAXException {
|
||||
|
||||
super.startElement(uri, localName, qName, attributes);
|
||||
depth++;
|
||||
|
||||
boolean isContent = (contentName != null);
|
||||
|
||||
if (isContent){
|
||||
// must be html content... add the begin tag as content
|
||||
buffer.append("<").append(localName);
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String key = attributes.getLocalName(i);
|
||||
String val = attributes.getValue(i);
|
||||
buffer.append(" ").append(key).append("='").append(val).append("'");
|
||||
}
|
||||
buffer.append(">");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
buffer = new StringBuilder();
|
||||
Dnode node = createNewNode();
|
||||
node.setNodeName(localName);
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String key = attributes.getLocalName(i);
|
||||
String val = attributes.getValue(i);
|
||||
node.setAttribute(key, val);
|
||||
if ("type".equalsIgnoreCase(key) && "content".equalsIgnoreCase(val)) {
|
||||
// this tag contains html content
|
||||
// no more nodes until end tag is found
|
||||
contentName = localName;
|
||||
contentDepth = depth-1;
|
||||
}
|
||||
|
||||
}
|
||||
if (root == null) {
|
||||
root = node;
|
||||
}
|
||||
if (currentNode != null) {
|
||||
currentNode.addChild(node);
|
||||
}
|
||||
stack.push(node);
|
||||
currentNode = node;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* append the node content.
|
||||
*/
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
super.characters(ch, start, length);
|
||||
String s = new String(ch, start, length);
|
||||
int p = s.indexOf('\r');
|
||||
int p2 = s.indexOf('\n');
|
||||
if (p == -1 && p2 > -1) {
|
||||
// This is probably not an issue but tidys up content
|
||||
// in my text editor
|
||||
s = StringHelper.replaceString(s, "\n", "\r\n");
|
||||
}
|
||||
buffer.append(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* process the endElement.
|
||||
*/
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
super.endElement(uri, localName, qName);
|
||||
depth--;
|
||||
|
||||
if (contentName != null){
|
||||
// is this the end of the content?
|
||||
if (contentName.equals(localName) && contentDepth == depth){
|
||||
contentName = null;
|
||||
|
||||
} else {
|
||||
// the html content end tag
|
||||
buffer.append("</").append(localName).append(">");
|
||||
}
|
||||
return;
|
||||
}
|
||||
String content = buffer.toString();
|
||||
buffer.setLength(0);
|
||||
if (content.length() > 0) {
|
||||
if (trimWhitespace) {
|
||||
content = content.trim();
|
||||
}
|
||||
if (content.length() > 0) {
|
||||
currentNode.setNodeContent(content);
|
||||
}
|
||||
}
|
||||
stack.pop();
|
||||
if (!stack.isEmpty()) {
|
||||
// get the new currentNode
|
||||
currentNode = (Dnode) stack.pop();
|
||||
stack.push(currentNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
/**
|
||||
* Parse an xml document into a Dnode tree.
|
||||
*/
|
||||
public class DnodeParser extends DefaultHandler {
|
||||
|
||||
/**
|
||||
* The root of the DContent tree.
|
||||
*/
|
||||
Dnode root;
|
||||
|
||||
/**
|
||||
* The current node being parsed.
|
||||
*/
|
||||
Dnode currentNode;
|
||||
|
||||
/**
|
||||
* The nodeContent buffer.
|
||||
*/
|
||||
StringBuilder buffer;
|
||||
|
||||
/**
|
||||
* Used to stack the nodes.
|
||||
*/
|
||||
Stack<Dnode> stack = new Stack<Dnode>();
|
||||
|
||||
/**
|
||||
* The class used to construct new nodes. Should be Dnode or a subtype of
|
||||
* Dnode.
|
||||
*/
|
||||
Class<?> nodeClass = Dnode.class;
|
||||
|
||||
int depth = 0;
|
||||
|
||||
/**
|
||||
* Trim whitespace from the content.
|
||||
*/
|
||||
boolean trimWhitespace = true;
|
||||
|
||||
/**
|
||||
* The name of the tag that contains html content
|
||||
*/
|
||||
String contentName;
|
||||
|
||||
/**
|
||||
* The depth of the tag that contains the html content
|
||||
*/
|
||||
int contentDepth;
|
||||
|
||||
|
||||
/**
|
||||
* If true then trim the whitespace from the content.
|
||||
*/
|
||||
public boolean isTrimWhitespace() {
|
||||
return trimWhitespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to trim whitespace from the content.
|
||||
*/
|
||||
public void setTrimWhitespace(boolean trimWhitespace) {
|
||||
this.trimWhitespace = trimWhitespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root node of the DContent tree.
|
||||
*/
|
||||
public Dnode getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type class of node to be created.
|
||||
*/
|
||||
public void setNodeClass(Class<?> nodeClass) {
|
||||
this.nodeClass = nodeClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Dnode using the nodeClass.
|
||||
*/
|
||||
private Dnode createNewNode() {
|
||||
try {
|
||||
return (Dnode) nodeClass.newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* process a startElement.
|
||||
*/
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||
throws SAXException {
|
||||
|
||||
super.startElement(uri, localName, qName, attributes);
|
||||
depth++;
|
||||
|
||||
boolean isContent = (contentName != null);
|
||||
|
||||
if (isContent){
|
||||
// must be html content... add the begin tag as content
|
||||
buffer.append("<").append(localName);
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String key = attributes.getLocalName(i);
|
||||
String val = attributes.getValue(i);
|
||||
buffer.append(" ").append(key).append("='").append(val).append("'");
|
||||
}
|
||||
buffer.append(">");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
buffer = new StringBuilder();
|
||||
Dnode node = createNewNode();
|
||||
node.setNodeName(localName);
|
||||
for (int i = 0; i < attributes.getLength(); i++) {
|
||||
String key = attributes.getLocalName(i);
|
||||
String val = attributes.getValue(i);
|
||||
node.setAttribute(key, val);
|
||||
if ("type".equalsIgnoreCase(key) && "content".equalsIgnoreCase(val)) {
|
||||
// this tag contains html content
|
||||
// no more nodes until end tag is found
|
||||
contentName = localName;
|
||||
contentDepth = depth-1;
|
||||
}
|
||||
|
||||
}
|
||||
if (root == null) {
|
||||
root = node;
|
||||
}
|
||||
if (currentNode != null) {
|
||||
currentNode.addChild(node);
|
||||
}
|
||||
stack.push(node);
|
||||
currentNode = node;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* append the node content.
|
||||
*/
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
super.characters(ch, start, length);
|
||||
String s = new String(ch, start, length);
|
||||
int p = s.indexOf('\r');
|
||||
int p2 = s.indexOf('\n');
|
||||
if (p == -1 && p2 > -1) {
|
||||
// This is probably not an issue but tidys up content
|
||||
// in my text editor
|
||||
s = StringHelper.replaceString(s, "\n", "\r\n");
|
||||
}
|
||||
buffer.append(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* process the endElement.
|
||||
*/
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
super.endElement(uri, localName, qName);
|
||||
depth--;
|
||||
|
||||
if (contentName != null){
|
||||
// is this the end of the content?
|
||||
if (contentName.equals(localName) && contentDepth == depth){
|
||||
contentName = null;
|
||||
|
||||
} else {
|
||||
// the html content end tag
|
||||
buffer.append("</").append(localName).append(">");
|
||||
}
|
||||
return;
|
||||
}
|
||||
String content = buffer.toString();
|
||||
buffer.setLength(0);
|
||||
if (content.length() > 0) {
|
||||
if (trimWhitespace) {
|
||||
content = content.trim();
|
||||
}
|
||||
if (content.length() > 0) {
|
||||
currentNode.setNodeContent(content);
|
||||
}
|
||||
}
|
||||
stack.pop();
|
||||
if (!stack.isEmpty()) {
|
||||
// get the new currentNode
|
||||
currentNode = (Dnode) stack.pop();
|
||||
stack.push(currentNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
/**
|
||||
* Parses an XML inputstream returning a Dnode tree.
|
||||
*/
|
||||
public class DnodeReader {
|
||||
|
||||
public Dnode parseXml(String str) {
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream(str.length());
|
||||
OutputStreamWriter osw = new OutputStreamWriter(bao);
|
||||
|
||||
StringReader sr = new StringReader(str);
|
||||
|
||||
int charBufferSize = 1024;
|
||||
char[] buf = new char[charBufferSize];
|
||||
int len;
|
||||
while ((len = sr.read(buf, 0, buf.length)) != -1) {
|
||||
osw.write(buf, 0, len);
|
||||
}
|
||||
sr.close();
|
||||
osw.flush();
|
||||
osw.close();
|
||||
|
||||
bao.flush();
|
||||
bao.close();
|
||||
|
||||
InputStream is = new ByteArrayInputStream(bao.toByteArray());
|
||||
return parseXml(is);
|
||||
|
||||
} catch (IOException ex){
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the XML inputstream returning the Dnode tree.
|
||||
*/
|
||||
public Dnode parseXml(InputStream in) {
|
||||
|
||||
try {
|
||||
InputSource inSource = new InputSource(in);
|
||||
|
||||
DnodeParser parser = new DnodeParser();
|
||||
|
||||
XMLReader myReader = XMLReaderFactory.createXMLReader();
|
||||
myReader.setContentHandler(parser);
|
||||
|
||||
myReader.parse(inSource);
|
||||
|
||||
return parser.getRoot();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
/**
|
||||
* Parses an XML inputstream returning a Dnode tree.
|
||||
*/
|
||||
public class DnodeReader {
|
||||
|
||||
public Dnode parseXml(String str) {
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream(str.length());
|
||||
OutputStreamWriter osw = new OutputStreamWriter(bao);
|
||||
|
||||
StringReader sr = new StringReader(str);
|
||||
|
||||
int charBufferSize = 1024;
|
||||
char[] buf = new char[charBufferSize];
|
||||
int len;
|
||||
while ((len = sr.read(buf, 0, buf.length)) != -1) {
|
||||
osw.write(buf, 0, len);
|
||||
}
|
||||
sr.close();
|
||||
osw.flush();
|
||||
osw.close();
|
||||
|
||||
bao.flush();
|
||||
bao.close();
|
||||
|
||||
InputStream is = new ByteArrayInputStream(bao.toByteArray());
|
||||
return parseXml(is);
|
||||
|
||||
} catch (IOException ex){
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the XML inputstream returning the Dnode tree.
|
||||
*/
|
||||
public Dnode parseXml(InputStream in) {
|
||||
|
||||
try {
|
||||
InputSource inSource = new InputSource(in);
|
||||
|
||||
DnodeParser parser = new DnodeParser();
|
||||
|
||||
XMLReader myReader = XMLReaderFactory.createXMLReader();
|
||||
myReader.setContentHandler(parser);
|
||||
|
||||
myReader.parse(inSource);
|
||||
|
||||
return parser.getRoot();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* A general exception that can be used for multiple purposes.
|
||||
*/
|
||||
public class GeneralException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 5783084420007103280L;
|
||||
|
||||
public GeneralException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public GeneralException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public GeneralException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* A general exception that can be used for multiple purposes.
|
||||
*/
|
||||
public class GeneralException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 5783084420007103280L;
|
||||
|
||||
public GeneralException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public GeneralException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public GeneralException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception for invalid data.
|
||||
*/
|
||||
public class InvalidDataException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539846L;
|
||||
|
||||
public InvalidDataException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InvalidDataException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public InvalidDataException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception for invalid data.
|
||||
*/
|
||||
public class InvalidDataException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539846L;
|
||||
|
||||
public InvalidDataException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InvalidDataException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public InvalidDataException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* An Email address with an associated alias.
|
||||
*/
|
||||
public class MailAddress {
|
||||
|
||||
|
||||
String alias;
|
||||
|
||||
String emailAddress;
|
||||
|
||||
/**
|
||||
* Create an address with an optional alias.
|
||||
*/
|
||||
public MailAddress(String alias, String emailAddress){
|
||||
this.alias = alias;
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the alias.
|
||||
* If the alias is null this returns an empty string.
|
||||
*/
|
||||
public String getAlias() {
|
||||
if (alias == null){
|
||||
return "";
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the email address.
|
||||
*/
|
||||
public String getEmailAddress(){
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getAlias()).append(" ").append("<").append(getEmailAddress()).append(">");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* An Email address with an associated alias.
|
||||
*/
|
||||
public class MailAddress {
|
||||
|
||||
|
||||
String alias;
|
||||
|
||||
String emailAddress;
|
||||
|
||||
/**
|
||||
* Create an address with an optional alias.
|
||||
*/
|
||||
public MailAddress(String alias, String emailAddress){
|
||||
this.alias = alias;
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the alias.
|
||||
* If the alias is null this returns an empty string.
|
||||
*/
|
||||
public String getAlias() {
|
||||
if (alias == null){
|
||||
return "";
|
||||
}
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the email address.
|
||||
*/
|
||||
public String getEmailAddress(){
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getAlias()).append(" ").append("<").append(getEmailAddress()).append(">");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Represents the success or failure of a mail send.
|
||||
*/
|
||||
public class MailEvent {
|
||||
|
||||
|
||||
/**
|
||||
* The error indicating a send failure.
|
||||
*/
|
||||
Throwable error;
|
||||
|
||||
/**
|
||||
* The message that was sent.
|
||||
*/
|
||||
MailMessage message;
|
||||
|
||||
|
||||
/**
|
||||
* The message send failed with an error.
|
||||
*/
|
||||
public MailEvent(MailMessage message, Throwable error){
|
||||
this.message = message;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* The message that we attempted to send.
|
||||
*/
|
||||
public MailMessage getMailMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the message was sent successfully.
|
||||
*/
|
||||
public boolean wasSuccessful() {
|
||||
return (error == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error indicating the send failed.
|
||||
*/
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Represents the success or failure of a mail send.
|
||||
*/
|
||||
public class MailEvent {
|
||||
|
||||
|
||||
/**
|
||||
* The error indicating a send failure.
|
||||
*/
|
||||
Throwable error;
|
||||
|
||||
/**
|
||||
* The message that was sent.
|
||||
*/
|
||||
MailMessage message;
|
||||
|
||||
|
||||
/**
|
||||
* The message send failed with an error.
|
||||
*/
|
||||
public MailEvent(MailMessage message, Throwable error){
|
||||
this.message = message;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* The message that we attempted to send.
|
||||
*/
|
||||
public MailMessage getMailMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the message was sent successfully.
|
||||
*/
|
||||
public boolean wasSuccessful() {
|
||||
return (error == null);
|
||||
}
|
||||
|
||||
/**
|
||||
* The error indicating the send failed.
|
||||
*/
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Listens to see if the message was successfully sent.
|
||||
*/
|
||||
public interface MailListener {
|
||||
|
||||
/**
|
||||
* Handle the message event.
|
||||
*/
|
||||
public void handleEvent(MailEvent event);
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Listens to see if the message was successfully sent.
|
||||
*/
|
||||
public interface MailListener {
|
||||
|
||||
/**
|
||||
* Handle the message event.
|
||||
*/
|
||||
public void handleEvent(MailEvent event);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,157 +1,157 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple test message that can be sent via smtp.
|
||||
*/
|
||||
public class MailMessage {
|
||||
|
||||
// /**
|
||||
// * The subject text.
|
||||
// */
|
||||
// String subject;
|
||||
|
||||
/**
|
||||
* The body content.
|
||||
*/
|
||||
ArrayList<String> bodylines;
|
||||
|
||||
/**
|
||||
* The sender email address.
|
||||
*/
|
||||
MailAddress senderAddress;
|
||||
|
||||
/**
|
||||
* The headers.
|
||||
*/
|
||||
HashMap<String,String> header = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* the recipient of the email.
|
||||
*/
|
||||
MailAddress currentRecipient;
|
||||
|
||||
/**
|
||||
* The list of recipients.
|
||||
*/
|
||||
ArrayList<MailAddress> recipientList = new ArrayList<MailAddress>();
|
||||
|
||||
/**
|
||||
* Create the message.
|
||||
*/
|
||||
public MailMessage() {
|
||||
bodylines = new ArrayList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current recipient.
|
||||
*/
|
||||
public void setCurrentRecipient(MailAddress currentRecipient){
|
||||
this.currentRecipient = currentRecipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current recipient.
|
||||
*/
|
||||
public MailAddress getCurrentRecipient() {
|
||||
return currentRecipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a recipient.
|
||||
*/
|
||||
public void addRecipient(String alias, String emailAddress){
|
||||
recipientList.add(new MailAddress(alias, emailAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sender details.
|
||||
*/
|
||||
public void setSender(String alias, String senderEmail){
|
||||
this.senderAddress = new MailAddress(alias, senderEmail);
|
||||
}
|
||||
/**
|
||||
* Return the sender address.
|
||||
*/
|
||||
public MailAddress getSender() {
|
||||
return senderAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the recipient list.
|
||||
*/
|
||||
public List<MailAddress> getRecipientList() {
|
||||
return recipientList;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a header to the message.
|
||||
*/
|
||||
public void addHeader(String key, String val) {
|
||||
header.put(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subject text.
|
||||
*/
|
||||
public void setSubject(String subject){
|
||||
addHeader("Subject", subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subject text.
|
||||
*/
|
||||
public String getSubject() {
|
||||
return getHeader("Subject");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text to the body.
|
||||
*/
|
||||
public void addBodyLine(String line) {
|
||||
bodylines.add(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the body text.
|
||||
*/
|
||||
public List<String> getBodyLines() {
|
||||
return bodylines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the headers.
|
||||
*/
|
||||
public Collection<String> getHeaderFields() {
|
||||
return header.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a given header.
|
||||
*/
|
||||
public String getHeader(String key) {
|
||||
return header.get(key);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
sb.append("Sender: " + senderAddress + "\tRecipient: " + recipientList + "\n");
|
||||
for (String key : header.keySet()) {
|
||||
String hline = key + ": " + header.get(key) + "\n";
|
||||
sb.append(hline);
|
||||
}
|
||||
sb.append("\n");
|
||||
for (String line : bodylines) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple test message that can be sent via smtp.
|
||||
*/
|
||||
public class MailMessage {
|
||||
|
||||
// /**
|
||||
// * The subject text.
|
||||
// */
|
||||
// String subject;
|
||||
|
||||
/**
|
||||
* The body content.
|
||||
*/
|
||||
ArrayList<String> bodylines;
|
||||
|
||||
/**
|
||||
* The sender email address.
|
||||
*/
|
||||
MailAddress senderAddress;
|
||||
|
||||
/**
|
||||
* The headers.
|
||||
*/
|
||||
HashMap<String,String> header = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* the recipient of the email.
|
||||
*/
|
||||
MailAddress currentRecipient;
|
||||
|
||||
/**
|
||||
* The list of recipients.
|
||||
*/
|
||||
ArrayList<MailAddress> recipientList = new ArrayList<MailAddress>();
|
||||
|
||||
/**
|
||||
* Create the message.
|
||||
*/
|
||||
public MailMessage() {
|
||||
bodylines = new ArrayList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current recipient.
|
||||
*/
|
||||
public void setCurrentRecipient(MailAddress currentRecipient){
|
||||
this.currentRecipient = currentRecipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current recipient.
|
||||
*/
|
||||
public MailAddress getCurrentRecipient() {
|
||||
return currentRecipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a recipient.
|
||||
*/
|
||||
public void addRecipient(String alias, String emailAddress){
|
||||
recipientList.add(new MailAddress(alias, emailAddress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sender details.
|
||||
*/
|
||||
public void setSender(String alias, String senderEmail){
|
||||
this.senderAddress = new MailAddress(alias, senderEmail);
|
||||
}
|
||||
/**
|
||||
* Return the sender address.
|
||||
*/
|
||||
public MailAddress getSender() {
|
||||
return senderAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the recipient list.
|
||||
*/
|
||||
public List<MailAddress> getRecipientList() {
|
||||
return recipientList;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a header to the message.
|
||||
*/
|
||||
public void addHeader(String key, String val) {
|
||||
header.put(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subject text.
|
||||
*/
|
||||
public void setSubject(String subject){
|
||||
addHeader("Subject", subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subject text.
|
||||
*/
|
||||
public String getSubject() {
|
||||
return getHeader("Subject");
|
||||
}
|
||||
|
||||
/**
|
||||
* Add text to the body.
|
||||
*/
|
||||
public void addBodyLine(String line) {
|
||||
bodylines.add(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the body text.
|
||||
*/
|
||||
public List<String> getBodyLines() {
|
||||
return bodylines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the headers.
|
||||
*/
|
||||
public Collection<String> getHeaderFields() {
|
||||
return header.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a given header.
|
||||
*/
|
||||
public String getHeader(String key) {
|
||||
return header.get(key);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
sb.append("Sender: " + senderAddress + "\tRecipient: " + recipientList + "\n");
|
||||
for (String key : header.keySet()) {
|
||||
String hline = key + ": " + header.get(key) + "\n";
|
||||
sb.append(hline);
|
||||
}
|
||||
sb.append("\n");
|
||||
for (String line : bodylines) {
|
||||
sb.append(line).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,206 +1,206 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Sends simple MailMessages via smtp.
|
||||
*/
|
||||
public class MailSender implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MailSender.class);
|
||||
|
||||
int traceLevel = 0;
|
||||
|
||||
Socket sserver;
|
||||
String server;
|
||||
|
||||
BufferedReader in;
|
||||
|
||||
OutputStreamWriter out;
|
||||
|
||||
MailMessage message;
|
||||
|
||||
MailListener listener = null;
|
||||
|
||||
private static final int SMTP_PORT = 25;
|
||||
|
||||
/**
|
||||
* Create for a given mail server.
|
||||
*/
|
||||
public MailSender(String server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener to handle MessageEvents.
|
||||
*/
|
||||
public void setMailListener(MailListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message.
|
||||
*/
|
||||
public void run() {
|
||||
send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message in a background thread.
|
||||
*/
|
||||
public void sendInBackground(MailMessage message) {
|
||||
this.message = message;
|
||||
Thread thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message in the current thread.
|
||||
*/
|
||||
public void send(MailMessage message) {
|
||||
try {
|
||||
for (MailAddress recipientAddress : message.getRecipientList()) {
|
||||
sserver = new Socket(server, SMTP_PORT);
|
||||
send(message, sserver, recipientAddress);
|
||||
sserver.close();
|
||||
|
||||
if (listener != null) {
|
||||
MailEvent event = new MailEvent(message, null);
|
||||
listener.handleEvent(event);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (listener != null) {
|
||||
MailEvent event = new MailEvent(message, ex);
|
||||
listener.handleEvent(event);
|
||||
} else {
|
||||
logger.error(null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void send(MailMessage message, Socket sserver, MailAddress recipientAddress) throws IOException {
|
||||
|
||||
// A bit convoluted, but doesn't depend on DNS in any way...
|
||||
InetAddress localhost = sserver.getLocalAddress();
|
||||
String localaddress = localhost.getHostAddress();
|
||||
MailAddress sender = message.getSender();
|
||||
message.setCurrentRecipient(recipientAddress);
|
||||
|
||||
// Mandatory header fields, Date and From
|
||||
if (message.getHeader("Date") == null) {
|
||||
message.addHeader("Date", new java.util.Date().toString());
|
||||
}
|
||||
if (message.getHeader("From") == null) {
|
||||
message.addHeader("From", sender.getAlias() + " <" + sender.getEmailAddress() + ">");
|
||||
}
|
||||
|
||||
// if (message.getHeader("From") == null){
|
||||
message.addHeader("To", recipientAddress.getAlias() + " <" + recipientAddress.getEmailAddress() + ">");
|
||||
// }
|
||||
|
||||
out = new OutputStreamWriter(sserver.getOutputStream());
|
||||
in = new BufferedReader(new InputStreamReader(sserver.getInputStream()));
|
||||
String sintro = readln();
|
||||
if (!sintro.startsWith("220")) { // 220
|
||||
logger.debug("SmtpSender: intro==" + sintro);
|
||||
return;
|
||||
}
|
||||
|
||||
writeln("EHLO " + localaddress);
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeln("MAIL FROM:<" + sender.getEmailAddress() + ">");
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
writeln("RCPT TO:<" + recipientAddress.getEmailAddress() + ">");
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
writeln("DATA");
|
||||
while (true) { // may be multiple 250 replies pending from server
|
||||
String line = readln();
|
||||
if (line.startsWith("3"))
|
||||
break; // ready to send
|
||||
if (!line.startsWith("2")) {
|
||||
logger.debug("SmtpSender.send reponse to DATA: " + line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (String key : message.getHeaderFields()) {
|
||||
writeln(key + ": " + message.getHeader(key));
|
||||
}
|
||||
writeln(""); // end of header;
|
||||
for (String bline : message.getBodyLines()) {
|
||||
if (bline.startsWith(".")) {
|
||||
bline = "." + bline;
|
||||
}
|
||||
writeln(bline);
|
||||
}
|
||||
writeln(".");
|
||||
expect250();
|
||||
writeln("QUIT");
|
||||
|
||||
}
|
||||
|
||||
private boolean expect250() throws IOException {
|
||||
String line = readln();
|
||||
if (!line.startsWith("2")) {
|
||||
logger.info("SmtpSender.expect250: " + line);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void writeln(String s) throws IOException {
|
||||
if (traceLevel > 2) {
|
||||
logger.debug("From client: " + s);
|
||||
}
|
||||
out.write(s + "\r\n");
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private String readln() throws IOException {
|
||||
String line = in.readLine();
|
||||
if (traceLevel > 1) {
|
||||
logger.debug("From server: " + line);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trace level.
|
||||
*/
|
||||
public void setTraceLevel(int traceLevel) {
|
||||
this.traceLevel = traceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hostname of the local machine.
|
||||
*/
|
||||
public String getLocalHostName() {
|
||||
try {
|
||||
InetAddress ipaddress = InetAddress.getLocalHost();
|
||||
String localHost = ipaddress.getHostName();
|
||||
if (localHost == null) {
|
||||
return "localhost";
|
||||
} else {
|
||||
return localHost;
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
return "localhost";
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Sends simple MailMessages via smtp.
|
||||
*/
|
||||
public class MailSender implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MailSender.class);
|
||||
|
||||
int traceLevel = 0;
|
||||
|
||||
Socket sserver;
|
||||
String server;
|
||||
|
||||
BufferedReader in;
|
||||
|
||||
OutputStreamWriter out;
|
||||
|
||||
MailMessage message;
|
||||
|
||||
MailListener listener = null;
|
||||
|
||||
private static final int SMTP_PORT = 25;
|
||||
|
||||
/**
|
||||
* Create for a given mail server.
|
||||
*/
|
||||
public MailSender(String server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener to handle MessageEvents.
|
||||
*/
|
||||
public void setMailListener(MailListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message.
|
||||
*/
|
||||
public void run() {
|
||||
send(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message in a background thread.
|
||||
*/
|
||||
public void sendInBackground(MailMessage message) {
|
||||
this.message = message;
|
||||
Thread thread = new Thread(this);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message in the current thread.
|
||||
*/
|
||||
public void send(MailMessage message) {
|
||||
try {
|
||||
for (MailAddress recipientAddress : message.getRecipientList()) {
|
||||
sserver = new Socket(server, SMTP_PORT);
|
||||
send(message, sserver, recipientAddress);
|
||||
sserver.close();
|
||||
|
||||
if (listener != null) {
|
||||
MailEvent event = new MailEvent(message, null);
|
||||
listener.handleEvent(event);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (listener != null) {
|
||||
MailEvent event = new MailEvent(message, ex);
|
||||
listener.handleEvent(event);
|
||||
} else {
|
||||
logger.error(null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void send(MailMessage message, Socket sserver, MailAddress recipientAddress) throws IOException {
|
||||
|
||||
// A bit convoluted, but doesn't depend on DNS in any way...
|
||||
InetAddress localhost = sserver.getLocalAddress();
|
||||
String localaddress = localhost.getHostAddress();
|
||||
MailAddress sender = message.getSender();
|
||||
message.setCurrentRecipient(recipientAddress);
|
||||
|
||||
// Mandatory header fields, Date and From
|
||||
if (message.getHeader("Date") == null) {
|
||||
message.addHeader("Date", new java.util.Date().toString());
|
||||
}
|
||||
if (message.getHeader("From") == null) {
|
||||
message.addHeader("From", sender.getAlias() + " <" + sender.getEmailAddress() + ">");
|
||||
}
|
||||
|
||||
// if (message.getHeader("From") == null){
|
||||
message.addHeader("To", recipientAddress.getAlias() + " <" + recipientAddress.getEmailAddress() + ">");
|
||||
// }
|
||||
|
||||
out = new OutputStreamWriter(sserver.getOutputStream());
|
||||
in = new BufferedReader(new InputStreamReader(sserver.getInputStream()));
|
||||
String sintro = readln();
|
||||
if (!sintro.startsWith("220")) { // 220
|
||||
logger.debug("SmtpSender: intro==" + sintro);
|
||||
return;
|
||||
}
|
||||
|
||||
writeln("EHLO " + localaddress);
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeln("MAIL FROM:<" + sender.getEmailAddress() + ">");
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
writeln("RCPT TO:<" + recipientAddress.getEmailAddress() + ">");
|
||||
if (!expect250()) {
|
||||
return;
|
||||
}
|
||||
writeln("DATA");
|
||||
while (true) { // may be multiple 250 replies pending from server
|
||||
String line = readln();
|
||||
if (line.startsWith("3"))
|
||||
break; // ready to send
|
||||
if (!line.startsWith("2")) {
|
||||
logger.debug("SmtpSender.send reponse to DATA: " + line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (String key : message.getHeaderFields()) {
|
||||
writeln(key + ": " + message.getHeader(key));
|
||||
}
|
||||
writeln(""); // end of header;
|
||||
for (String bline : message.getBodyLines()) {
|
||||
if (bline.startsWith(".")) {
|
||||
bline = "." + bline;
|
||||
}
|
||||
writeln(bline);
|
||||
}
|
||||
writeln(".");
|
||||
expect250();
|
||||
writeln("QUIT");
|
||||
|
||||
}
|
||||
|
||||
private boolean expect250() throws IOException {
|
||||
String line = readln();
|
||||
if (!line.startsWith("2")) {
|
||||
logger.info("SmtpSender.expect250: " + line);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void writeln(String s) throws IOException {
|
||||
if (traceLevel > 2) {
|
||||
logger.debug("From client: " + s);
|
||||
}
|
||||
out.write(s + "\r\n");
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private String readln() throws IOException {
|
||||
String line = in.readLine();
|
||||
if (traceLevel > 1) {
|
||||
logger.debug("From server: " + line);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trace level.
|
||||
*/
|
||||
public void setTraceLevel(int traceLevel) {
|
||||
this.traceLevel = traceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the hostname of the local machine.
|
||||
*/
|
||||
public String getLocalHostName() {
|
||||
try {
|
||||
InetAddress ipaddress = InetAddress.getLocalHost();
|
||||
String localHost = ipaddress.getHostName();
|
||||
if (localHost == null) {
|
||||
return "localhost";
|
||||
} else {
|
||||
return localHost;
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
return "localhost";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Utility String class that supports String manipulation functions.
|
||||
*/
|
||||
public class MapFromString {
|
||||
|
||||
LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
|
||||
|
||||
String mapToString;
|
||||
|
||||
int stringLength;
|
||||
int keyStart = 0;
|
||||
int eqPos = 0;
|
||||
int valEnd = 0;
|
||||
|
||||
public static LinkedHashMap<String,String> parse(String mapToString) {
|
||||
MapFromString c = new MapFromString(mapToString);
|
||||
return c.parse();
|
||||
}
|
||||
|
||||
private MapFromString(String mapToString) {
|
||||
if (mapToString.charAt(0) == '{'){
|
||||
mapToString = mapToString.substring(1);
|
||||
}
|
||||
if (mapToString.charAt(mapToString.length()-1) == '}'){
|
||||
mapToString = mapToString.substring(0, mapToString.length()-1);
|
||||
}
|
||||
|
||||
this.mapToString = mapToString;
|
||||
this.stringLength = mapToString.length();
|
||||
}
|
||||
|
||||
private LinkedHashMap<String,String> parse() {
|
||||
while(findNext()){
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private boolean findNext() {
|
||||
if (keyStart > stringLength){
|
||||
return false;
|
||||
}
|
||||
eqPos = mapToString.indexOf("=",keyStart);
|
||||
if (eqPos == -1){
|
||||
throw new RuntimeException("No = after "+keyStart);
|
||||
}
|
||||
valEnd = mapToString.indexOf(", ",eqPos);
|
||||
if (valEnd == -1){
|
||||
valEnd = mapToString.length();
|
||||
}
|
||||
// check that the next valEnd occurs after the next eqPos
|
||||
|
||||
String keyValue = mapToString.substring(keyStart,eqPos);
|
||||
String valValue = mapToString.substring(eqPos+1,valEnd);
|
||||
map.put(keyValue, valValue);
|
||||
keyStart = valEnd + 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Utility String class that supports String manipulation functions.
|
||||
*/
|
||||
public class MapFromString {
|
||||
|
||||
LinkedHashMap<String,String> map = new LinkedHashMap<String,String>();
|
||||
|
||||
String mapToString;
|
||||
|
||||
int stringLength;
|
||||
int keyStart = 0;
|
||||
int eqPos = 0;
|
||||
int valEnd = 0;
|
||||
|
||||
public static LinkedHashMap<String,String> parse(String mapToString) {
|
||||
MapFromString c = new MapFromString(mapToString);
|
||||
return c.parse();
|
||||
}
|
||||
|
||||
private MapFromString(String mapToString) {
|
||||
if (mapToString.charAt(0) == '{'){
|
||||
mapToString = mapToString.substring(1);
|
||||
}
|
||||
if (mapToString.charAt(mapToString.length()-1) == '}'){
|
||||
mapToString = mapToString.substring(0, mapToString.length()-1);
|
||||
}
|
||||
|
||||
this.mapToString = mapToString;
|
||||
this.stringLength = mapToString.length();
|
||||
}
|
||||
|
||||
private LinkedHashMap<String,String> parse() {
|
||||
while(findNext()){
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private boolean findNext() {
|
||||
if (keyStart > stringLength){
|
||||
return false;
|
||||
}
|
||||
eqPos = mapToString.indexOf("=",keyStart);
|
||||
if (eqPos == -1){
|
||||
throw new RuntimeException("No = after "+keyStart);
|
||||
}
|
||||
valEnd = mapToString.indexOf(", ",eqPos);
|
||||
if (valEnd == -1){
|
||||
valEnd = mapToString.length();
|
||||
}
|
||||
// check that the next valEnd occurs after the next eqPos
|
||||
|
||||
String keyValue = mapToString.substring(keyStart,eqPos);
|
||||
String valValue = mapToString.substring(eqPos+1,valEnd);
|
||||
map.put(keyValue, valValue);
|
||||
keyStart = valEnd + 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Helper methods to determine the mime type based on a file name.
|
||||
*/
|
||||
public class MimeTypeHelper {
|
||||
|
||||
/**
|
||||
* Return the mimeType for a given file path.
|
||||
* This will extract the file extension, and then use that
|
||||
* to look up an appropriate mime type (from the mimetypes.props file).
|
||||
*
|
||||
* To add a new mime type, add it to the mimetype.props file.
|
||||
*/
|
||||
public static String getMimeType(String filePath) {
|
||||
|
||||
int lastPeriod = filePath.lastIndexOf(".");
|
||||
if (lastPeriod > -1) {
|
||||
filePath = filePath.substring(lastPeriod+1);
|
||||
}
|
||||
|
||||
try {
|
||||
return resources.getString(filePath.toLowerCase());
|
||||
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
//String m = "Unable to locate mimetype for ["+filePath.toLowerCase()+"] in mimetypes.properties";
|
||||
//throw new NotFoundException(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static ResourceBundle resources = ResourceBundle.getBundle("com.avaje.lib.util.mimetypes");
|
||||
|
||||
|
||||
};
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Helper methods to determine the mime type based on a file name.
|
||||
*/
|
||||
public class MimeTypeHelper {
|
||||
|
||||
/**
|
||||
* Return the mimeType for a given file path.
|
||||
* This will extract the file extension, and then use that
|
||||
* to look up an appropriate mime type (from the mimetypes.props file).
|
||||
*
|
||||
* To add a new mime type, add it to the mimetype.props file.
|
||||
*/
|
||||
public static String getMimeType(String filePath) {
|
||||
|
||||
int lastPeriod = filePath.lastIndexOf(".");
|
||||
if (lastPeriod > -1) {
|
||||
filePath = filePath.substring(lastPeriod+1);
|
||||
}
|
||||
|
||||
try {
|
||||
return resources.getString(filePath.toLowerCase());
|
||||
|
||||
} catch (MissingResourceException e) {
|
||||
return null;
|
||||
//String m = "Unable to locate mimetype for ["+filePath.toLowerCase()+"] in mimetypes.properties";
|
||||
//throw new NotFoundException(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static ResourceBundle resources = ResourceBundle.getBundle("com.avaje.lib.util.mimetypes");
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception where data is not found.
|
||||
*/
|
||||
public class NotFoundException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539845L;
|
||||
|
||||
public NotFoundException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NotFoundException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public NotFoundException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general exception where data is not found.
|
||||
*/
|
||||
public class NotFoundException extends RuntimeException
|
||||
{
|
||||
static final long serialVersionUID = 7061559938704539845L;
|
||||
|
||||
public NotFoundException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NotFoundException(String s, Exception cause) {
|
||||
super(s, cause);
|
||||
}
|
||||
|
||||
public NotFoundException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general string parsing exception.
|
||||
*/
|
||||
public class StringParsingException extends RuntimeException {
|
||||
|
||||
static final long serialVersionUID = -3070423471260426402L;
|
||||
|
||||
public StringParsingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
};
|
||||
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
|
||||
/**
|
||||
* A general string parsing exception.
|
||||
*/
|
||||
public class StringParsingException extends RuntimeException {
|
||||
|
||||
static final long serialVersionUID = -3070423471260426402L;
|
||||
|
||||
public StringParsingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Builds a string from a stack trace.
|
||||
* <p>
|
||||
* Generally used to flatten a stack trace into a single string
|
||||
* removing \r\n and limiting the size of any given stack.
|
||||
* </p>
|
||||
*/
|
||||
public class ThrowablePrinter {
|
||||
|
||||
private static final String atString = " at ";
|
||||
|
||||
private String newLineChar = "\\r\\n";
|
||||
|
||||
private int maxStackTraceLines = 3;
|
||||
|
||||
/**
|
||||
* Set the maximum number of lines in any one part of
|
||||
* the stack trace. This is not the total maximum.
|
||||
*/
|
||||
public void setMaxStackTraceLines(int maxStackTraceLines) {
|
||||
this.maxStackTraceLines = maxStackTraceLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new line character used to replace \r\n with.
|
||||
* This is useful so that the stack is placed on a single line
|
||||
* in a log file.
|
||||
*/
|
||||
public void setNewLineChar(String newLineChar) {
|
||||
this.newLineChar = newLineChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the error into a string representation.
|
||||
* <p>
|
||||
* Replaces the \r\n and limits the stack lines.
|
||||
* </p>
|
||||
*/
|
||||
public String print(Throwable e) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
printThrowable(sb, e, false);
|
||||
|
||||
String line = sb.toString();
|
||||
line = StringHelper.replaceString(line, "\r", "\\r");
|
||||
line = StringHelper.replaceString(line, "\n", "\\n");
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively output the Throwable stack trace to the log.
|
||||
*
|
||||
* @param sb the buffer to write the stack trace to
|
||||
* @param e the source throwable
|
||||
* @param isCause flag to indicate if this is the top level throwable or a
|
||||
* cause
|
||||
*/
|
||||
protected void printThrowable(StringBuffer sb, Throwable e, boolean isCause) {
|
||||
if (e != null) {
|
||||
if (isCause) {
|
||||
sb.append("Caused by: ");
|
||||
}
|
||||
sb.append(e.getClass().getName());
|
||||
sb.append(":");
|
||||
sb.append(e.getMessage()).append(newLineChar);
|
||||
|
||||
StackTraceElement[] ste = e.getStackTrace();
|
||||
int outputStackLines = ste.length;
|
||||
int notShownCount = 0;
|
||||
if (ste.length > maxStackTraceLines) {
|
||||
outputStackLines = maxStackTraceLines;
|
||||
notShownCount = ste.length - outputStackLines;
|
||||
}
|
||||
for (int i = 0; i < outputStackLines; i++) {
|
||||
sb.append(atString);
|
||||
sb.append(ste[i].toString()).append(newLineChar);
|
||||
}
|
||||
if (notShownCount > 0) {
|
||||
sb.append(" ... ");
|
||||
sb.append(notShownCount);
|
||||
sb.append(" more").append(newLineChar);
|
||||
}
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null) {
|
||||
printThrowable(sb, cause, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.avaje.ebeaninternal.server.lib.util;
|
||||
|
||||
/**
|
||||
* Builds a string from a stack trace.
|
||||
* <p>
|
||||
* Generally used to flatten a stack trace into a single string
|
||||
* removing \r\n and limiting the size of any given stack.
|
||||
* </p>
|
||||
*/
|
||||
public class ThrowablePrinter {
|
||||
|
||||
private static final String atString = " at ";
|
||||
|
||||
private String newLineChar = "\\r\\n";
|
||||
|
||||
private int maxStackTraceLines = 3;
|
||||
|
||||
/**
|
||||
* Set the maximum number of lines in any one part of
|
||||
* the stack trace. This is not the total maximum.
|
||||
*/
|
||||
public void setMaxStackTraceLines(int maxStackTraceLines) {
|
||||
this.maxStackTraceLines = maxStackTraceLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new line character used to replace \r\n with.
|
||||
* This is useful so that the stack is placed on a single line
|
||||
* in a log file.
|
||||
*/
|
||||
public void setNewLineChar(String newLineChar) {
|
||||
this.newLineChar = newLineChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the error into a string representation.
|
||||
* <p>
|
||||
* Replaces the \r\n and limits the stack lines.
|
||||
* </p>
|
||||
*/
|
||||
public String print(Throwable e) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
printThrowable(sb, e, false);
|
||||
|
||||
String line = sb.toString();
|
||||
line = StringHelper.replaceString(line, "\r", "\\r");
|
||||
line = StringHelper.replaceString(line, "\n", "\\n");
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively output the Throwable stack trace to the log.
|
||||
*
|
||||
* @param sb the buffer to write the stack trace to
|
||||
* @param e the source throwable
|
||||
* @param isCause flag to indicate if this is the top level throwable or a
|
||||
* cause
|
||||
*/
|
||||
protected void printThrowable(StringBuffer sb, Throwable e, boolean isCause) {
|
||||
if (e != null) {
|
||||
if (isCause) {
|
||||
sb.append("Caused by: ");
|
||||
}
|
||||
sb.append(e.getClass().getName());
|
||||
sb.append(":");
|
||||
sb.append(e.getMessage()).append(newLineChar);
|
||||
|
||||
StackTraceElement[] ste = e.getStackTrace();
|
||||
int outputStackLines = ste.length;
|
||||
int notShownCount = 0;
|
||||
if (ste.length > maxStackTraceLines) {
|
||||
outputStackLines = maxStackTraceLines;
|
||||
notShownCount = ste.length - outputStackLines;
|
||||
}
|
||||
for (int i = 0; i < outputStackLines; i++) {
|
||||
sb.append(atString);
|
||||
sb.append(ste[i].toString()).append(newLineChar);
|
||||
}
|
||||
if (notShownCount > 0) {
|
||||
sb.append(" ... ");
|
||||
sb.append(notShownCount);
|
||||
sb.append(" more").append(newLineChar);
|
||||
}
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null) {
|
||||
printThrowable(sb, cause, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user