From 12fcbf7baebf1f1146b744611557e18db41d8f14 Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 19 Jun 2013 09:27:46 +0800 Subject: [PATCH 01/17] adjuest for taobao --- api/pom.xml | 2 +- .../main/java/org/adbcj/ConnectionPool.java | 24 +- jdbc/pom.xml | 2 +- .../org/adbcj/jdbc/JdbcConnectionManager.java | 2 - .../jdbc/JdbcConnectionManagerFactory.java | 1 - mysql/codec/pom.xml | 2 +- mysql/mina/pom.xml | 2 +- .../mina/MysqlConnectionManagerFactory.java | 1 - .../adbcj/mysql/mina/MysqlMessageEncoder.java | 1 - mysql/netty/pom.xml | 2 +- .../mysql/netty/MessageQueuingHandler.java | 2 +- .../netty/MySqlConnectionManagerFactory.java | 4 +- .../mysql/netty/MysqlConnectionManager.java | 21 +- .../mysql/netty/WrappedMysqlConnection.java | 33 + .../pool2/BaseKeyedPoolableObjectFactory.java | 100 + .../apache/commons/pool2/BaseObjectPool.java | 141 ++ .../pool2/BasePoolableObjectFactory.java | 82 + .../apache/commons/pool2/KeyedObjectPool.java | 220 ++ .../pool2/KeyedPoolableObjectFactory.java | 140 ++ .../org/apache/commons/pool2/ObjectPool.java | 169 ++ .../org/apache/commons/pool2/PoolUtils.java | 1807 +++++++++++++++++ .../commons/pool2/PoolableObjectFactory.java | 135 ++ .../commons/pool2/impl/AbandonedConfig.java | 194 ++ .../pool2/impl/BaseGenericObjectPool.java | 1077 ++++++++++ .../pool2/impl/BaseObjectPoolConfig.java | 420 ++++ .../pool2/impl/DefaultEvictionPolicy.java | 53 + .../commons/pool2/impl/EvictionConfig.java | 63 + .../commons/pool2/impl/EvictionPolicy.java | 45 + .../commons/pool2/impl/EvictionTimer.java | 130 ++ .../pool2/impl/GenericKeyedObjectPool.java | 1380 +++++++++++++ .../impl/GenericKeyedObjectPoolConfig.java | 104 + .../impl/GenericKeyedObjectPoolMBean.java | 160 ++ .../commons/pool2/impl/GenericObjectPool.java | 960 +++++++++ .../pool2/impl/GenericObjectPoolConfig.java | 91 + .../pool2/impl/GenericObjectPoolMBean.java | 163 ++ .../impl/InterruptibleReentrantLock.java | 45 + .../pool2/impl/LinkedBlockingDeque.java | 1213 +++++++++++ .../commons/pool2/impl/PooledObject.java | 305 +++ .../commons/pool2/impl/PooledObjectState.java | 90 + .../pool2/impl/SoftReferenceObjectPool.java | 339 ++++ .../apache/commons/pool2/impl/TrackedUse.java | 34 + mysql/pom.xml | 2 +- pom.xml | 8 +- postgresql/codec/pom.xml | 2 +- postgresql/mina/pom.xml | 2 +- .../mina/MinaConnectionManager.java | 12 +- .../mina/MinaConnectionManagerFactory.java | 1 - postgresql/netty/pom.xml | 2 +- .../netty/NettyConnectionManager.java | 30 +- .../netty/NettyConnectionManagerFactory.java | 1 - postgresql/pom.xml | 2 +- tck/pom.xml | 2 +- 52 files changed, 9755 insertions(+), 68 deletions(-) create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java diff --git a/api/pom.xml b/api/pom.xml index 90870e79..ac559461 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT adbcj-api diff --git a/api/src/main/java/org/adbcj/ConnectionPool.java b/api/src/main/java/org/adbcj/ConnectionPool.java index 7a0f710e..86e9a3b0 100644 --- a/api/src/main/java/org/adbcj/ConnectionPool.java +++ b/api/src/main/java/org/adbcj/ConnectionPool.java @@ -39,7 +39,7 @@ public void setPoolSize(int size) { } } - @Override + public DbFuture connect() { final DbSession session = sessions.poll(); if (session == null) { @@ -48,58 +48,58 @@ public DbFuture connect() { DefaultDbFuture future = new DefaultDbFuture(); future.setResult(new DbSession() { - @Override + public void beginTransaction() { session.beginTransaction(); } - @Override + public DbSessionFuture commit() { return session.commit(); } - @Override + public DbSessionFuture rollback() { return session.rollback(); } - @Override + public boolean isInTransaction() { return session.isInTransaction(); } - @Override + public DbSessionFuture executeQuery(String sql) { return session.executeQuery(sql); } - @Override + public DbSessionFuture executeQuery(String sql, ResultEventHandler eventHandler, T accumulator) { return session.executeQuery(sql, eventHandler, accumulator); } - @Override + public DbSessionFuture executeUpdate(String sql) { return session.executeUpdate(sql); } - @Override + public DbSessionFuture prepareStatement(String sql) { return session.prepareStatement(sql); } - @Override + public DbSessionFuture prepareStatement(Object key, String sql) { return session.prepareStatement(key, sql); } - @Override + public DbSessionFuture close(boolean immediate) throws DbException { sessions.add(session); return DefaultDbSessionFuture.createCompletedFuture(this, null); } - @Override + public boolean isClosed() throws DbException { return false; } diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 882c7de6..53a2f04e 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT adbcj-jdbc diff --git a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java index 6c5dbce4..2a98a57b 100644 --- a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java +++ b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java @@ -105,7 +105,6 @@ public DbFuture close(boolean immediate) throws DbException { if (closeFuture == null) { closeFuture = new DefaultDbFuture(); closeFuture.addListener(new DbListener() { - @Override public void onCompletion(DbFuture future) throws Exception { executorService.shutdown(); } @@ -118,7 +117,6 @@ public void onCompletion(DbFuture future) throws Exception { final AtomicBoolean allClosed = new AtomicBoolean(false); DbListener listener = new DbListener() { - @Override public void onCompletion(DbFuture future) { try { int count = countDown.decrementAndGet(); diff --git a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java index 12e2c992..08332f72 100644 --- a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java +++ b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java @@ -44,7 +44,6 @@ public ConnectionManager createConnectionManager(String url, String username, St } } - @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/mysql/codec/pom.xml b/mysql/codec/pom.xml index 482a2339..c1ff35eb 100644 --- a/mysql/codec/pom.xml +++ b/mysql/codec/pom.xml @@ -8,7 +8,7 @@ org.adbcj mysql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT mysql-codec diff --git a/mysql/mina/pom.xml b/mysql/mina/pom.xml index 0987a6f2..4aaf0144 100644 --- a/mysql/mina/pom.xml +++ b/mysql/mina/pom.xml @@ -8,7 +8,7 @@ org.adbcj mysql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT mysql-mina diff --git a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlConnectionManagerFactory.java b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlConnectionManagerFactory.java index 7a5522f5..d86f1ac9 100644 --- a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlConnectionManagerFactory.java +++ b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlConnectionManagerFactory.java @@ -50,7 +50,6 @@ public ConnectionManager createConnectionManager(String url, String username, St } } - @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol) | PROTOCOL_MINA.equals(protocol); } diff --git a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java index 8621aae7..040fab80 100644 --- a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java +++ b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java @@ -35,7 +35,6 @@ public void dispose(IoSession session) throws Exception { // Nothing to dispose } - @Override public void encode(IoSession session, Object message, ProtocolEncoderOutput encoderOut) throws Exception { IoBuffer buffer = IoBuffer.allocate(1024); OutputStream out = buffer.asOutputStream(); diff --git a/mysql/netty/pom.xml b/mysql/netty/pom.xml index 6934f3dd..1029acc5 100644 --- a/mysql/netty/pom.xml +++ b/mysql/netty/pom.xml @@ -8,7 +8,7 @@ org.adbcj mysql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT mysql-netty diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java index 6d6c339d..108d3d65 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java @@ -19,7 +19,7 @@ class MessageQueuingHandler implements ChannelUpstreamHandler { // Access must be synchronized on this private boolean flushed = false; - @Override + public synchronized void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (!flushed) { diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java index 0841c4d3..a650bd77 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java @@ -13,7 +13,7 @@ public class MySqlConnectionManagerFactory implements ConnectionManagerFactory { public static final String PROTOCOL = "mysqlnetty"; public static final int DEFAULT_PORT = 3306; - @Override + public ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) throws DbException { try { /* @@ -40,7 +40,7 @@ public ConnectionManager createConnectionManager(String url, String username, St } } - @Override + public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java index c2dad332..b1f66e28 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java @@ -7,11 +7,13 @@ import java.util.concurrent.Executors; import org.adbcj.Connection; +import org.adbcj.DbFuture; import org.adbcj.mysql.codec.AbstractMySqlConnectionManager; import org.adbcj.mysql.codec.ClientRequest; import org.adbcj.mysql.codec.MySqlClientDecoder; import org.adbcj.mysql.codec.MySqlClientEncoder; import org.adbcj.mysql.codec.ProtocolHandler; +import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPool; import org.adbcj.support.DefaultDbFuture; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; @@ -39,7 +41,6 @@ import org.slf4j.LoggerFactory; public class MysqlConnectionManager extends AbstractMySqlConnectionManager { - private static final Logger logger = LoggerFactory.getLogger(MysqlConnectionManager.class); private static final String QUEUE_HANDLER = MysqlConnectionManager.class.getName() + ".queueHandler"; @@ -67,7 +68,7 @@ public MysqlConnectionManager(String host, int port, String username, String pas private void init(String host, int port) { bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - @Override + public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); @@ -84,14 +85,14 @@ public ChannelPipeline getPipeline() throws Exception { bootstrap.setOption("remoteAddress", new InetSocketAddress(host, port)); } - @Override + protected void dispose() { if (executorService != null) { executorService.shutdownNow(); } } - @Override + protected DefaultDbFuture createConnectionFuture() { final ChannelFuture channelFuture = bootstrap.connect(); return new MysqlConnectFuture(channelFuture); @@ -103,7 +104,7 @@ class MysqlConnectFuture extends DefaultDbFuture { public MysqlConnectFuture(ChannelFuture channelFuture) { this.channelFuture = channelFuture; channelFuture.addListener(new ChannelFutureListener() { - @Override + public void operationComplete(ChannelFuture future) throws Exception { logger.debug("Connect completed"); @@ -120,7 +121,7 @@ public void operationComplete(ChannelFuture future) throws Exception { }); } - @Override + protected boolean doCancel(boolean mayInterruptIfRunning) { return channelFuture.cancel(); } @@ -132,7 +133,7 @@ class Decoder extends FrameDecoder { private final MySqlClientDecoder decoder = new MySqlClientDecoder(); - @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { InputStream in = new ChannelBufferInputStream(buffer); try { @@ -178,12 +179,12 @@ public Handler(MysqlConnection connection) { this.connection = connection; } - @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { handler.messageReceived(connection, e.getMessage()); } - @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable t = handler.handleException(connection, e.getCause()); if (t != null) { @@ -192,7 +193,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } } - @Override + public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { handler.connectionClosed(connection); } diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java new file mode 100644 index 00000000..cf30b504 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java @@ -0,0 +1,33 @@ +package org.adbcj.mysql.netty; + +import org.adbcj.Connection; +import org.adbcj.DbFuture; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; + +public class WrappedMysqlConnection implements PoolableObjectFactory { + private MysqlConnectionManager connectionManager = null; + public Connection makeObject() throws Exception { + DbFuture conn = connectionManager.connect(); + return conn.get(); + } + + public void destroyObject(Connection conn) throws Exception { + conn.close(true); + } + + public boolean validateObject(Connection obj) { + Connection conn = (Connection)obj; + return !conn.isClosed(); + } + + public void activateObject(Connection obj) throws Exception { + + } + + public void passivateObject(Connection obj) throws Exception { + + } + + + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java new file mode 100644 index 00000000..a1954dc2 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +/** + * A base implementation of KeyedPoolableObjectFactory. + *

+ * All operations defined here are essentially no-op's. + *

+ * This class is immutable, and therefore thread-safe. + * + * @see KeyedPoolableObjectFactory + * + * @param The type of keys managed by this factory. + * @param Type of element managed by this factory. + * + * @version $Revision: 1333925 $ + * + * @since 2.0 + */ +public abstract class BaseKeyedPoolableObjectFactory + implements KeyedPoolableObjectFactory { + + /** + * Create an instance that can be served by the pool. + * + * @param key the key used when constructing the object + * @return an instance that can be served by the pool + */ + + public abstract V makeObject(K key) + throws Exception; + + /** + * Destroy an instance no longer needed by the pool. + *

+ * The default implementation is a no-op. + * + * @param key the key used when selecting the instance + * @param obj the instance to be destroyed + */ + + public void destroyObject(K key, V obj) + throws Exception { + } + + /** + * Ensures that the instance is safe to be returned by the pool. + *

+ * The default implementation always returns true. + * + * @param key the key used when selecting the object + * @param obj the instance to be validated + * @return always true in the default implementation + */ + + public boolean validateObject(K key, V obj) { + return true; + } + + /** + * Reinitialize an instance to be returned by the pool. + *

+ * The default implementation is a no-op. + * + * @param key the key used when selecting the object + * @param obj the instance to be activated + */ + + public void activateObject(K key, V obj) + throws Exception { + } + + /** + * Uninitialize an instance to be returned to the idle object pool. + *

+ * The default implementation is a no-op. + * + * @param key the key used when selecting the object + * @param obj the instance to be passivated + */ + + public void passivateObject(K key, V obj) + throws Exception { + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java new file mode 100644 index 00000000..5646b047 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +/** + * A simple base implementation of {@link ObjectPool}. + * Optional operations are implemented to either do nothing, return a value + * indicating it is unsupported or throw {@link UnsupportedOperationException}. + *

+ * This class is intended to be thread-safe. + * + * @param Type of element pooled in this pool. + * + * @version $Revision: 1333925 $ + * + * @since 2.0 + */ +public abstract class BaseObjectPool implements ObjectPool { + /** + * Obtains an instance from the pool. + * + * @return an instance from the pool + * + * @throws Exception if an instance cannot be obtained from the pool + */ + + public abstract T borrowObject() throws Exception; + + /** + * Returns an instance to the pool. + * + * @param obj instance to return to the pool + */ + + public abstract void returnObject(T obj) throws Exception; + + /** + * Invalidates an object from the pool. + *

+ * By contract, obj must have been obtained + * using {@link #borrowObject borrowObject}. + *

+ * This method should be used when an object that has been borrowed is + * determined (due to an exception or other problem) to be invalid. + * + * @param obj a {@link #borrowObject borrowed} instance to be disposed. + * @throws Exception + */ + + public abstract void invalidateObject(T obj) throws Exception; + + /** + * Not supported in this base implementation. + * + * @return a negative value. + */ + + public int getNumIdle() { + return -1; + } + + /** + * Not supported in this base implementation. + * + * @return a negative value. + */ + + public int getNumActive() { + return -1; + } + + /** + * Not supported in this base implementation. + * + * @throws UnsupportedOperationException + */ + + public void clear() throws Exception, UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /** + * Not supported in this base implementation.Always throws an + * {@link UnsupportedOperationException}, subclasses should override this + * behavior. + * + * @throws UnsupportedOperationException + */ + + public void addObject() throws Exception, UnsupportedOperationException { + throw new UnsupportedOperationException(); + } + + /** + * Close this pool. This affects the behavior of isClosed and + * assertOpen. + */ + + public void close() { + closed = true; + } + + /** + * Has this pool instance been closed. + * + * @return true when this pool has been closed. + */ + public final boolean isClosed() { + return closed; + } + + /** + * Throws an IllegalStateException when this pool has been + * closed. + * + * @throws IllegalStateException when this pool has been closed. + * + * @see #isClosed() + */ + protected final void assertOpen() throws IllegalStateException { + if (isClosed()) { + throw new IllegalStateException("Pool not open"); + } + } + + private volatile boolean closed = false; +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java new file mode 100644 index 00000000..b5aa0bd5 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +/** + * A base implementation of PoolableObjectFactory. + *

+ * All operations defined here are essentially no-op's. + *

+ * This class is immutable, and therefore thread-safe + * + * @param Type of element managed in this factory. + * + * @see PoolableObjectFactory + * @see BaseKeyedPoolableObjectFactory + * + * @version $Revision: 1333925 $ + * + * @since 2.0 + */ +public abstract class BasePoolableObjectFactory implements PoolableObjectFactory { + /** + * {@inheritDoc} + */ + + public abstract T makeObject() throws Exception; + + /** + * No-op. + * + * @param obj ignored + */ + + public void destroyObject(T obj) + throws Exception { + } + + /** + * This implementation always returns true. + * + * @param obj ignored + * + * @return true + */ + + public boolean validateObject(T obj) { + return true; + } + + /** + * No-op. + * + * @param obj ignored + */ + + public void activateObject(T obj) throws Exception { + } + + /** + * No-op. + * + * @param obj ignored + */ + + public void passivateObject(T obj) + throws Exception { + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java new file mode 100644 index 00000000..4a3aa318 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +import java.util.NoSuchElementException; + +/** + * A "keyed" pooling interface. + *

+ * A keyed pool pools instances of multiple types. Each type may be accessed + * using an arbitrary key. + *

+ * Example of use: + *

 Object obj = null;
+ * Object key = "Key";
+ *
+ * try {
+ *     obj = pool.borrowObject(key);
+ *     //...use the object...
+ * } catch(Exception e) {
+ *     // invalidate the object
+ *     pool.invalidateObject(key, obj);
+ *     // do not return the object to the pool twice
+ *     obj = null;
+ * } finally {
+ *     // make sure the object is returned to the pool
+ *     if(null != obj) {
+ *         pool.returnObject(key, obj);
+ *     }
+ * }
+ *

+ * {@link KeyedObjectPool} implementations may choose to store at most + * one instance per key value, or may choose to maintain a pool of instances + * for each key (essentially creating a {@link java.util.Map Map} of + * {@link ObjectPool pools}). + *

+ * See {@link org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericKeyedObjectPool + * GenericKeyedObjectPool} for an implementation. + * + * @param The type of keys maintained by this pool. + * @param Type of element pooled in this pool. + * + * @see KeyedPoolableObjectFactory + * @see ObjectPool + * @see org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool + * + * @version $Revision: 1334193 $ + * + * @since 2.0 + */ +public interface KeyedObjectPool { + /** + * Obtains an instance from this pool for the specified key. + *

+ * Instances returned from this method will have been either newly created + * with {@link KeyedPoolableObjectFactory#makeObject makeObject} or will be + * a previously idle object and have been activated with + * {@link KeyedPoolableObjectFactory#activateObject activateObject} and then + * validated with + * {@link KeyedPoolableObjectFactory#validateObject validateObject}. + *

+ * By contract, clients must return the borrowed object + * using {@link #returnObject returnObject}, + * {@link #invalidateObject invalidateObject}, or a related method as + * defined in an implementation or sub-interface, using a key + * that is {@link Object#equals equivalent} to the one used to borrow the + * instance in the first place. + *

+ * The behaviour of this method when the pool has been exhausted is not + * strictly specified (although it may be specified by implementations). + * + * @param key the key used to obtain the object + * + * @return an instance from this pool. + * + * @throws IllegalStateException + * after {@link #close close} has been called on this pool + * @throws Exception + * when {@link KeyedPoolableObjectFactory#makeObject + * makeObject} throws an exception + * @throws NoSuchElementException + * when the pool is exhausted and cannot or will not return + * another instance + */ + V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException; + + /** + * Return an instance to the pool. By contract, obj + * must have been obtained using + * {@link #borrowObject borrowObject} or a related method as defined in an + * implementation or sub-interface using a key that is + * equivalent to the one used to borrow the instance in the first place. + * + * @param key the key used to obtain the object + * @param obj a {@link #borrowObject borrowed} instance to be returned. + * + * @throws Exception + */ + void returnObject(K key, V obj) throws Exception; + + /** + * Invalidates an object from the pool. + *

+ * By contract, obj must have been obtained + * using {@link #borrowObject borrowObject} or a related method as defined + * in an implementation or sub-interface using a key that is + * equivalent to the one used to borrow the Object in the first + * place. + *

+ * This method should be used when an object that has been borrowed is + * determined (due to an exception or other problem) to be invalid. + * + * @param key the key used to obtain the object + * @param obj a {@link #borrowObject borrowed} instance to be returned. + * + * @throws Exception + */ + void invalidateObject(K key, V obj) throws Exception; + + /** + * Create an object using the {@link KeyedPoolableObjectFactory factory} or + * other implementation dependent mechanism, passivate it, and then place it + * in the idle object pool. addObject is useful for + * "pre-loading" a pool with idle objects (Optional operation). + * + * @param key the key a new instance should be added to + * + * @throws Exception + * when {@link KeyedPoolableObjectFactory#makeObject} fails. + * @throws IllegalStateException + * after {@link #close} has been called on this pool. + * @throws UnsupportedOperationException + * when this pool cannot add new idle objects. + */ + void addObject(K key) throws Exception, IllegalStateException, + UnsupportedOperationException; + + /** + * Returns the number of instances corresponding to the given + * key currently idle in this pool. Returns a negative value if + * this information is not available. + * + * @param key the key to query + * @return the number of instances corresponding to the given + * key currently idle in this pool. + */ + int getNumIdle(K key); + + /** + * Returns the number of instances currently borrowed from but not yet + * returned to the pool corresponding to the given key. + * Returns a negative value if this information is not available. + * + * @param key the key to query + * @return the number of instances currently borrowed from but not yet + * returned to the pool corresponding to the given key. += */ + int getNumActive(K key); + + /** + * Returns the total number of instances currently idle in this pool. + * Returns a negative value if this information is not available. + * @return the total number of instances currently idle in this pool. + = */ + int getNumIdle(); + + /** + * Returns the total number of instances current borrowed from this pool but + * not yet returned. Returns a negative value if this information is not + * available. + * @return the total number of instances current borrowed from this pool but + * not yet returned. + */ + int getNumActive(); + + /** + * Clears the pool, removing all pooled instances (optional operation). + * + * @throws UnsupportedOperationException when this implementation doesn't + * support the operation + */ + void clear() throws Exception, UnsupportedOperationException; + + /** + * Clears the specified pool, removing all pooled instances corresponding to + * the given key (optional operation). + * + * @param key the key to clear + * + * @throws UnsupportedOperationException when this implementation doesn't + * support the operation + */ + void clear(K key) throws Exception, UnsupportedOperationException; + + /** + * Close this pool, and free any resources associated with it. + *

+ * Calling {@link #addObject addObject} or + * {@link #borrowObject borrowObject} after invoking this method on a pool + * will cause them to throw an {@link IllegalStateException}. + *

+ * Implementations should silently fail if not all resources can be freed. + */ + void close(); +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java new file mode 100644 index 00000000..2c2b3447 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +/** + * An interface defining life-cycle methods for + * instances to be served by a {@link KeyedObjectPool}. + *

+ * By contract, when an {@link KeyedObjectPool} + * delegates to a {@link KeyedPoolableObjectFactory}, + *

    + *
  1. + * {@link #makeObject} is called whenever a new instance is needed. + *
  2. + *
  3. + * {@link #activateObject} is invoked on every instance that has been + * {@link #passivateObject passivated} before it is + * {@link KeyedObjectPool#borrowObject borrowed} from the pool. + *
  4. + *
  5. + * {@link #validateObject} is invoked on {@link #activateObject activated} + * instances to make sure they can be + * {@link KeyedObjectPool#borrowObject borrowed} from the pool. + * validateObject may also be used to test an + * instance being {@link KeyedObjectPool#returnObject returned} to the pool + * before it is {@link #passivateObject passivated}. It will only be invoked + * on an activated instance. + *
  6. + *
  7. + * {@link #passivateObject passivateObject} + * is invoked on every instance when it is returned to the pool. + *
  8. + *
  9. + * {@link #destroyObject destroyObject} + * is invoked on every instance when it is being "dropped" from the + * pool (whether due to the response from validateObject, + * or for reasons specific to the pool implementation.) There is no + * guarantee that the instance being destroyed will + * be considered active, passive or in a generally consistent state. + *
  10. + *
+ * {@link KeyedPoolableObjectFactory} must be thread-safe. The only promise + * an {@link KeyedObjectPool} makes is that the same instance of an object will + * not be passed to more than one method of a + * KeyedPoolableObjectFactory at a time. + * + * @see KeyedObjectPool + * + * @param The type of keys managed by this factory. + * @param Type of element managed by this factory. + * + * @version $Revision: 1333925 $ + * + * @since 2.0 + */ +public interface KeyedPoolableObjectFactory { + /** + * Create an instance that can be served by the pool. + * + * @param key the key used when constructing the object + * + * @return an instance that can be served by the pool. + * + * @throws Exception if there is a problem creating a new instance, + * this will be propagated to the code requesting an object. + */ + V makeObject(K key) throws Exception; + + /** + * Destroy an instance no longer needed by the pool. + *

+ * It is important for implementations of this method to be aware that there + * is no guarantee about what state obj will be in and the + * implementation should be prepared to handle unexpected errors. + *

+ * Also, an implementation must take in to consideration that instances lost + * to the garbage collector may never be destroyed. + * + * @param key the key used when selecting the instance + * @param obj the instance to be destroyed + * + * @throws Exception should be avoided as it may be swallowed by + * the pool implementation. + * + * @see #validateObject + * @see KeyedObjectPool#invalidateObject + */ + void destroyObject(K key, V obj) throws Exception; + + /** + * Ensures that the instance is safe to be returned by the pool. + * + * @param key the key used when selecting the object + * @param obj the instance to be validated + * + * @return false if obj is not valid and should + * be dropped from the pool, true otherwise. + */ + boolean validateObject(K key, V obj); + + /** + * Reinitialize an instance to be returned by the pool. + * + * @param key the key used when selecting the object + * @param obj the instance to be activated + * + * @throws Exception if there is a problem activating obj, + * this exception may be swallowed by the pool. + * + * @see #destroyObject + */ + void activateObject(K key, V obj) throws Exception; + + /** + * Uninitialize an instance to be returned to the idle object pool. + * + * @param key the key used when selecting the object + * @param obj the instance to be passivated + * + * @throws Exception if there is a problem passivating obj, + * this exception may be swallowed by the pool. + * + * @see #destroyObject + */ + void passivateObject(K key, V obj) throws Exception; +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java new file mode 100644 index 00000000..b65fe716 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +import java.util.NoSuchElementException; + +/** + * A pooling simple interface. + *

+ * Example of use: + *

 Object obj = null;
+ *
+ * try {
+ *     obj = pool.borrowObject();
+ *     try {
+ *         //...use the object...
+ *     } catch(Exception e) {
+ *         // invalidate the object
+ *         pool.invalidateObject(obj);
+ *         // do not return the object to the pool twice
+ *         obj = null;
+ *     } finally {
+ *         // make sure the object is returned to the pool
+ *         if(null != obj) {
+ *             pool.returnObject(obj);
+ *        }
+ *     }
+ * } catch(Exception e) {
+ *       // failed to borrow an object
+ * }
+ *

+ * See {@link BaseObjectPool} for a simple base implementation. + * + * @param Type of element pooled in this pool. + * + * @see PoolableObjectFactory + * @see KeyedObjectPool + * @see BaseObjectPool + * + * @version $Revision: 1334194 $ + * + * @since 2.0 + */ +public interface ObjectPool { + /** + * Obtains an instance from this pool. + *

+ * Instances returned from this method will have been either newly created + * with {@link PoolableObjectFactory#makeObject} or will be a previously + * idle object and have been activated with + * {@link PoolableObjectFactory#activateObject} and then validated with + * {@link PoolableObjectFactory#validateObject}. + *

+ * By contract, clients must return the borrowed instance + * using {@link #returnObject}, {@link #invalidateObject}, or a related + * method as defined in an implementation or sub-interface. + *

+ * The behaviour of this method when the pool has been exhausted + * is not strictly specified (although it may be specified by + * implementations). + * + * @return an instance from this pool. + * + * @throws IllegalStateException + * after {@link #close close} has been called on this pool. + * @throws Exception + * when {@link PoolableObjectFactory#makeObject} throws an + * exception. + * @throws NoSuchElementException + * when the pool is exhausted and cannot or will not return + * another instance. + */ + T borrowObject() throws Exception, NoSuchElementException, + IllegalStateException; + + /** + * Return an instance to the pool. By contract, obj + * must have been obtained using {@link #borrowObject()} or + * a related method as defined in an implementation or sub-interface. + * + * @param obj a {@link #borrowObject borrowed} instance to be returned. + * + * @throws Exception + */ + void returnObject(T obj) throws Exception; + + /** + * Invalidates an object from the pool. + *

+ * By contract, obj must have been obtained + * using {@link #borrowObject} or a related method as defined in an + * implementation or sub-interface. + *

+ * This method should be used when an object that has been borrowed is + * determined (due to an exception or other problem) to be invalid. + * + * @param obj a {@link #borrowObject borrowed} instance to be disposed. + * + * @throws Exception + */ + void invalidateObject(T obj) throws Exception; + + /** + * Create an object using the {@link PoolableObjectFactory factory} or other + * implementation dependent mechanism, passivate it, and then place it in + * the idle object pool. addObject is useful for "pre-loading" + * a pool with idle objects. (Optional operation). + * + * @throws Exception + * when {@link PoolableObjectFactory#makeObject} fails. + * @throws IllegalStateException + * after {@link #close} has been called on this pool. + * @throws UnsupportedOperationException + * when this pool cannot add new idle objects. + */ + void addObject() throws Exception, IllegalStateException, + UnsupportedOperationException; + + /** + * Return the number of instances currently idle in this pool. This may be + * considered an approximation of the number of objects that can be + * {@link #borrowObject borrowed} without creating any new instances. + * Returns a negative value if this information is not available. + * @return the number of instances currently idle in this pool. + */ + int getNumIdle(); + + /** + * Return the number of instances currently borrowed from this pool. Returns + * a negative value if this information is not available. + * @return the number of instances currently borrowed from this pool. += */ + int getNumActive(); + + /** + * Clears any objects sitting idle in the pool, releasing any associated + * resources (optional operation). Idle objects cleared must be + * {@link PoolableObjectFactory#destroyObject(Object)}. + * + * @throws UnsupportedOperationException + * if this implementation does not support the operation + */ + void clear() throws Exception, UnsupportedOperationException; + + /** + * Close this pool, and free any resources associated with it. + *

+ * Calling {@link #addObject} or {@link #borrowObject} after invoking this + * method on a pool will cause them to throw an {@link IllegalStateException}. + *

+ * Implementations should silently fail if not all resources can be freed. + */ + void close(); +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java new file mode 100644 index 00000000..5213c010 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java @@ -0,0 +1,1807 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Timer; +import java.util.TimerTask; +import java.util.Collections; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +/** + * This class consists exclusively of static methods that operate on or return + * ObjectPool or KeyedObjectPool related interfaces. + * + * @version $Revision: 1351161 $ + * + * @since 2.0 + */ +public final class PoolUtils { + + /** + * Timer used to periodically check pools idle object count. Because a + * {@link Timer} creates a {@link Thread}, an IODH is used. + */ + static class TimerHolder { + static final Timer MIN_IDLE_TIMER = new Timer(true); + } + + /** + * PoolUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);. + * This constructor is public to permit tools that require a JavaBean + * instance to operate. + */ + public PoolUtils() { + } + + /** + * Should the supplied Throwable be re-thrown (eg if it is an instance of + * one of the Throwables that should never be swallowed). Used by the pool + * error handling for operations that throw exceptions that normally need to + * be ignored. + * + * @param t + * The Throwable to check + * @throws ThreadDeath + * if that is passed in + * @throws VirtualMachineError + * if that is passed in + */ + public static void checkRethrow(Throwable t) { + if (t instanceof ThreadDeath) { + throw (ThreadDeath) t; + } + if (t instanceof VirtualMachineError) { + throw (VirtualMachineError) t; + } + // All other instances of Throwable will be silently swallowed + } + + /** + * Periodically check the idle object count for the pool. At most one idle + * object will be added per period. If there is an exception when calling + * {@link ObjectPool#addObject()} then no more checks will be performed. + * + * @param pool + * the pool to check periodically. + * @param minIdle + * if the {@link ObjectPool#getNumIdle()} is less than this then + * add an idle object. + * @param period + * the frequency to check the number of idle objects in a pool, + * see {@link Timer#schedule(TimerTask, long, long)}. + * @param the type of objects in the pool + * @return the {@link TimerTask} that will periodically check the pools idle + * object count. + * @throws IllegalArgumentException + * when pool is null or when + * minIdle is negative or when period + * isn't valid for {@link Timer#schedule(TimerTask, long, long)} + */ + public static TimerTask checkMinIdle(final ObjectPool pool, + final int minIdle, final long period) + throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (minIdle < 0) { + throw new IllegalArgumentException("minIdle must be non-negative."); + } + final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle); + getMinIdleTimer().schedule(task, 0L, period); + return task; + } + + /** + * Periodically check the idle object count for the key in the keyedPool. At + * most one idle object will be added per period. If there is an exception + * when calling {@link KeyedObjectPool#addObject(Object)} then no more + * checks for that key will be performed. + * + * @param keyedPool + * the keyedPool to check periodically. + * @param key + * the key to check the idle count of. + * @param minIdle + * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than + * this then add an idle object. + * @param period + * the frequency to check the number of idle objects in a + * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. + * @param the type of the pool key + * @param the type of pool entries + * @return the {@link TimerTask} that will periodically check the pools idle + * object count. + * @throws IllegalArgumentException + * when keyedPool, key is + * null or when minIdle is negative or + * when period isn't valid for + * {@link Timer#schedule(TimerTask, long, long)}. + */ + public static TimerTask checkMinIdle( + final KeyedObjectPool keyedPool, final K key, + final int minIdle, final long period) + throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + if (minIdle < 0) { + throw new IllegalArgumentException("minIdle must be non-negative."); + } + final TimerTask task = new KeyedObjectPoolMinIdleTimerTask( + keyedPool, key, minIdle); + getMinIdleTimer().schedule(task, 0L, period); + return task; + } + + /** + * Periodically check the idle object count for each key in the + * Collection keys in the keyedPool. At most one + * idle object will be added per period. + * + * @param keyedPool + * the keyedPool to check periodically. + * @param keys + * a collection of keys to check the idle object count. + * @param minIdle + * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than + * this then add an idle object. + * @param period + * the frequency to check the number of idle objects in a + * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. + * @param the type of the pool key + * @param the type of pool entries + * @return a {@link Map} of key and {@link TimerTask} pairs that will + * periodically check the pools idle object count. + * @throws IllegalArgumentException + * when keyedPool, keys, or any of the + * values in the collection is null or when + * minIdle is negative or when period + * isn't valid for {@link Timer#schedule(TimerTask, long, long)} + * . + * @see #checkMinIdle(KeyedObjectPool, Object, int, long) + */ + public static Map checkMinIdle( + final KeyedObjectPool keyedPool, final Collection keys, + final int minIdle, final long period) + throws IllegalArgumentException { + if (keys == null) { + throw new IllegalArgumentException("keys must not be null."); + } + final Map tasks = new HashMap(keys.size()); + final Iterator iter = keys.iterator(); + while (iter.hasNext()) { + final K key = iter.next(); + final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period); + tasks.put(key, task); + } + return tasks; + } + + /** + * Call addObject() on pool count + * number of times. + * + * @param pool + * the pool to prefill. + * @param count + * the number of idle objects to add. + * @param the type of objects in the pool + * @throws Exception + * when {@link ObjectPool#addObject()} fails. + * @throws IllegalArgumentException + * when pool is null. + */ + public static void prefill(final ObjectPool pool, final int count) + throws Exception, IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + for (int i = 0; i < count; i++) { + pool.addObject(); + } + } + + /** + * Call addObject(Object) on keyedPool with + * key count number of times. + * + * @param keyedPool + * the keyedPool to prefill. + * @param key + * the key to add objects for. + * @param count + * the number of idle objects to add for key. + * @param the type of the pool key + * @param the type of pool entries + * @throws Exception + * when {@link KeyedObjectPool#addObject(Object)} fails. + * @throws IllegalArgumentException + * when keyedPool or key is + * null. + */ + public static void prefill(final KeyedObjectPool keyedPool, + final K key, final int count) throws Exception, + IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + for (int i = 0; i < count; i++) { + keyedPool.addObject(key); + } + } + + /** + * Call addObject(Object) on keyedPool with each + * key in keys for count number of times. This has + * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)} + * for each key in the keys collection. + * + * @param keyedPool + * the keyedPool to prefill. + * @param keys + * {@link Collection} of keys to add objects for. + * @param count + * the number of idle objects to add for each key. + * @param the type of the pool key + * @param the type of pool entries + * @throws Exception + * when {@link KeyedObjectPool#addObject(Object)} fails. + * @throws IllegalArgumentException + * when keyedPool, keys, or any value + * in keys is null. + * @see #prefill(KeyedObjectPool, Object, int) + */ + public static void prefill(final KeyedObjectPool keyedPool, + final Collection keys, final int count) throws Exception, + IllegalArgumentException { + if (keys == null) { + throw new IllegalArgumentException("keys must not be null."); + } + final Iterator iter = keys.iterator(); + while (iter.hasNext()) { + prefill(keyedPool, iter.next(), count); + } + } + + /** + * Returns a synchronized (thread-safe) ObjectPool backed by the specified + * ObjectPool. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. Wrapping a pool that {@link #wait() waits} for poolable + * objects to be returned before allowing another one to be borrowed with + * another layer of synchronization will cause liveliness issues or a + * deadlock. + *

+ * + * @param pool + * the ObjectPool to be "wrapped" in a synchronized ObjectPool. + * @param the type of objects in the pool + * @return a synchronized view of the specified ObjectPool. + */ + public static ObjectPool synchronizedPool(final ObjectPool pool) { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + /* + * assert !(pool instanceof GenericObjectPool) : + * "GenericObjectPool is already thread-safe"; assert !(pool instanceof + * SoftReferenceObjectPool) : + * "SoftReferenceObjectPool is already thread-safe"; assert !(pool + * instanceof StackObjectPool) : + * "StackObjectPool is already thread-safe"; assert + * !"org.apache.commons.pool.composite.CompositeObjectPool" + * .equals(pool.getClass().getName()) : + * "CompositeObjectPools are already thread-safe"; + */ + return new SynchronizedObjectPool(pool); + } + + /** + * Returns a synchronized (thread-safe) KeyedObjectPool backed by the + * specified KeyedObjectPool. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. Wrapping a pool that {@link #wait() waits} for poolable + * objects to be returned before allowing another one to be borrowed with + * another layer of synchronization will cause liveliness issues or a + * deadlock. + *

+ * + * @param keyedPool + * the KeyedObjectPool to be "wrapped" in a synchronized + * KeyedObjectPool. + * @param the type of the pool key + * @param the type of pool entries + * @return a synchronized view of the specified KeyedObjectPool. + */ + public static KeyedObjectPool synchronizedPool( + final KeyedObjectPool keyedPool) { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + /* + * assert !(keyedPool instanceof GenericKeyedObjectPool) : + * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool + * instanceof StackKeyedObjectPool) : + * "StackKeyedObjectPool is already thread-safe"; assert + * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool" + * .equals(keyedPool.getClass().getName()) : + * "CompositeKeyedObjectPools are already thread-safe"; + */ + return new SynchronizedKeyedObjectPool(keyedPool); + } + + /** + * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the + * specified PoolableObjectFactory. + * + * @param factory + * the PoolableObjectFactory to be "wrapped" in a synchronized + * PoolableObjectFactory. + * @param the type of objects in the pool + * @return a synchronized view of the specified PoolableObjectFactory. + */ + public static PoolableObjectFactory synchronizedPoolableFactory( + final PoolableObjectFactory factory) { + return new SynchronizedPoolableObjectFactory(factory); + } + + /** + * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by + * the specified KeyedPoolableObjectFactory. + * + * @param keyedFactory + * the KeyedPoolableObjectFactory to be "wrapped" in a + * synchronized KeyedPoolableObjectFactory. + * @param the type of the pool key + * @param the type of pool entries + * @return a synchronized view of the specified KeyedPoolableObjectFactory. + */ + public static KeyedPoolableObjectFactory synchronizedPoolableFactory( + final KeyedPoolableObjectFactory keyedFactory) { + return new SynchronizedKeyedPoolableObjectFactory(keyedFactory); + } + + /** + * Returns a pool that adaptively decreases it's size when idle objects are + * no longer needed. This is intended as an always thread-safe alternative + * to using an idle object evictor provided by many pool implementations. + * This is also an effective way to shrink FIFO ordered pools that + * experience load spikes. + * + * @param pool + * the ObjectPool to be decorated so it shrinks it's idle count + * when possible. + * @param the type of objects in the pool + * @return a pool that adaptively decreases it's size when idle objects are + * no longer needed. + * @see #erodingPool(ObjectPool, float) + */ + public static ObjectPool erodingPool(final ObjectPool pool) { + return erodingPool(pool, 1f); + } + + /** + * Returns a pool that adaptively decreases it's size when idle objects are + * no longer needed. This is intended as an always thread-safe alternative + * to using an idle object evictor provided by many pool implementations. + * This is also an effective way to shrink FIFO ordered pools that + * experience load spikes. + *

+ * The factor parameter provides a mechanism to tweak the rate at which the + * pool tries to shrink it's size. Values between 0 and 1 cause the pool to + * try to shrink it's size more often. Values greater than 1 cause the pool + * to less frequently try to shrink it's size. + *

+ * + * @param pool + * the ObjectPool to be decorated so it shrinks it's idle count + * when possible. + * @param factor + * a positive value to scale the rate at which the pool tries to + * reduce it's size. If 0 < factor < 1 then the pool + * shrinks more aggressively. If 1 < factor then the pool + * shrinks less aggressively. + * @param the type of objects in the pool + * @return a pool that adaptively decreases it's size when idle objects are + * no longer needed. + * @see #erodingPool(ObjectPool) + */ + public static ObjectPool erodingPool(final ObjectPool pool, + final float factor) { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + if (factor <= 0f) { + throw new IllegalArgumentException("factor must be positive."); + } + return new ErodingObjectPool(pool, factor); + } + + /** + * Returns a pool that adaptively decreases it's size when idle objects are + * no longer needed. This is intended as an always thread-safe alternative + * to using an idle object evictor provided by many pool implementations. + * This is also an effective way to shrink FIFO ordered pools that + * experience load spikes. + * + * @param keyedPool + * the KeyedObjectPool to be decorated so it shrinks it's idle + * count when possible. + * @param the type of the pool key + * @param the type of pool entries + * @return a pool that adaptively decreases it's size when idle objects are + * no longer needed. + * @see #erodingPool(KeyedObjectPool, float) + * @see #erodingPool(KeyedObjectPool, float, boolean) + */ + public static KeyedObjectPool erodingPool( + final KeyedObjectPool keyedPool) { + return erodingPool(keyedPool, 1f); + } + + /** + * Returns a pool that adaptively decreases it's size when idle objects are + * no longer needed. This is intended as an always thread-safe alternative + * to using an idle object evictor provided by many pool implementations. + * This is also an effective way to shrink FIFO ordered pools that + * experience load spikes. + *

+ * The factor parameter provides a mechanism to tweak the rate at which the + * pool tries to shrink it's size. Values between 0 and 1 cause the pool to + * try to shrink it's size more often. Values greater than 1 cause the pool + * to less frequently try to shrink it's size. + *

+ * + * @param keyedPool + * the KeyedObjectPool to be decorated so it shrinks it's idle + * count when possible. + * @param factor + * a positive value to scale the rate at which the pool tries to + * reduce it's size. If 0 < factor < 1 then the pool + * shrinks more aggressively. If 1 < factor then the pool + * shrinks less aggressively. + * @param the type of the pool key + * @param the type of pool entries + * @return a pool that adaptively decreases it's size when idle objects are + * no longer needed. + * @see #erodingPool(KeyedObjectPool, float, boolean) + */ + public static KeyedObjectPool erodingPool( + final KeyedObjectPool keyedPool, final float factor) { + return erodingPool(keyedPool, factor, false); + } + + /** + * Returns a pool that adaptively decreases it's size when idle objects are + * no longer needed. This is intended as an always thread-safe alternative + * to using an idle object evictor provided by many pool implementations. + * This is also an effective way to shrink FIFO ordered pools that + * experience load spikes. + *

+ * The factor parameter provides a mechanism to tweak the rate at which the + * pool tries to shrink it's size. Values between 0 and 1 cause the pool to + * try to shrink it's size more often. Values greater than 1 cause the pool + * to less frequently try to shrink it's size. + *

+ *

+ * The perKey parameter determines if the pool shrinks on a whole pool basis + * or a per key basis. When perKey is false, the keys do not have an effect + * on the rate at which the pool tries to shrink it's size. When perKey is + * true, each key is shrunk independently. + *

+ * + * @param keyedPool + * the KeyedObjectPool to be decorated so it shrinks it's idle + * count when possible. + * @param factor + * a positive value to scale the rate at which the pool tries to + * reduce it's size. If 0 < factor < 1 then the pool + * shrinks more aggressively. If 1 < factor then the pool + * shrinks less aggressively. + * @param perKey + * when true, each key is treated independently. + * @param the type of the pool key + * @param the type of pool entries + * @return a pool that adaptively decreases it's size when idle objects are + * no longer needed. + * @see #erodingPool(KeyedObjectPool) + * @see #erodingPool(KeyedObjectPool, float) + */ + public static KeyedObjectPool erodingPool( + final KeyedObjectPool keyedPool, final float factor, + final boolean perKey) { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (factor <= 0f) { + throw new IllegalArgumentException("factor must be positive."); + } + if (perKey) { + return new ErodingPerKeyKeyedObjectPool(keyedPool, factor); + } + return new ErodingKeyedObjectPool(keyedPool, factor); + } + + /** + * Get the Timer for checking keyedPool's idle count. + * + * @return the {@link Timer} for checking keyedPool's idle count. + */ + private static Timer getMinIdleTimer() { + return TimerHolder.MIN_IDLE_TIMER; + } + + /** + * Timer task that adds objects to the pool until the number of idle + * instances reaches the configured minIdle. Note that this is not the same + * as the pool's minIdle setting. + */ + private static class ObjectPoolMinIdleTimerTask extends TimerTask { + + /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ + private final int minIdle; + + /** Object pool */ + private final ObjectPool pool; + + /** + * Create a new ObjectPoolMinIdleTimerTask for the given pool with the + * given minIdle setting. + * + * @param pool + * object pool + * @param minIdle + * number of idle instances to maintain + * @throws IllegalArgumentException + * if the pool is null + */ + ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) + throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + this.pool = pool; + this.minIdle = minIdle; + } + + /** + * {@inheritDoc} + */ + + public void run() { + boolean success = false; + try { + if (pool.getNumIdle() < minIdle) { + pool.addObject(); + } + success = true; + + } catch (Exception e) { + cancel(); + + } finally { + // detect other types of Throwable and cancel this Timer + if (!success) { + cancel(); + } + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("ObjectPoolMinIdleTimerTask"); + sb.append("{minIdle=").append(minIdle); + sb.append(", pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + /** + * Timer task that adds objects to the pool until the number of idle + * instances for the given key reaches the configured minIdle. Note that + * this is not the same as the pool's minIdle setting. + */ + private static class KeyedObjectPoolMinIdleTimerTask extends + TimerTask { + /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ + private final int minIdle; + + /** Key to ensure minIdle for */ + private final K key; + + /** Keyed object pool */ + private final KeyedObjectPool keyedPool; + + /** + * Create a new KeyedObjecPoolMinIdleTimerTask. + * + * @param keyedPool + * keyed object pool + * @param key + * key to ensure minimum number of idle instances + * @param minIdle + * minimum number of idle instances + * @throws IllegalArgumentException + * if the key is null + */ + KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, + final K key, final int minIdle) throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException( + "keyedPool must not be null."); + } + this.keyedPool = keyedPool; + this.key = key; + this.minIdle = minIdle; + } + + /** + * {@inheritDoc} + */ + + public void run() { + boolean success = false; + try { + if (keyedPool.getNumIdle(key) < minIdle) { + keyedPool.addObject(key); + } + success = true; + + } catch (Exception e) { + cancel(); + + } finally { + // detect other types of Throwable and cancel this Timer + if (!success) { + cancel(); + } + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("KeyedObjectPoolMinIdleTimerTask"); + sb.append("{minIdle=").append(minIdle); + sb.append(", key=").append(key); + sb.append(", keyedPool=").append(keyedPool); + sb.append('}'); + return sb.toString(); + } + } + + /** + * A synchronized (thread-safe) ObjectPool backed by the specified + * ObjectPool. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. Wrapping a pool that {@link #wait() waits} for poolable + * objects to be returned before allowing another one to be borrowed with + * another layer of synchronization will cause liveliness issues or a + * deadlock. + *

+ */ + private static class SynchronizedObjectPool implements ObjectPool { + + /** + * Object whose monitor is used to synchronize methods on the wrapped + * pool. + */ + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + /** the underlying object pool */ + private final ObjectPool pool; + + /** + * Create a new SynchronizedObjectPool wrapping the given pool. + * + * @param pool + * the ObjectPool to be "wrapped" in a synchronized + * ObjectPool. + * @throws IllegalArgumentException + * if the pool is null + */ + SynchronizedObjectPool(final ObjectPool pool) + throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + this.pool = pool; + } + + /** + * {@inheritDoc} + */ + + public T borrowObject() throws Exception, NoSuchElementException, + IllegalStateException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + return pool.borrowObject(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void returnObject(final T obj) { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + pool.returnObject(obj); + } catch (Exception e) { + // swallowed as of Pool 2 + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void invalidateObject(final T obj) { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + pool.invalidateObject(obj); + } catch (Exception e) { + // swallowed as of Pool 2 + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void addObject() throws Exception, IllegalStateException, + UnsupportedOperationException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + pool.addObject(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle() { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return pool.getNumIdle(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumActive() { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return pool.getNumActive(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void clear() throws Exception, UnsupportedOperationException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + pool.clear(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void close() { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + pool.close(); + } catch (Exception e) { + // swallowed as of Pool 2 + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("SynchronizedObjectPool"); + sb.append("{pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + /** + * A synchronized (thread-safe) KeyedObjectPool backed by the specified + * KeyedObjectPool. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. Wrapping a pool that {@link #wait() waits} for poolable + * objects to be returned before allowing another one to be borrowed with + * another layer of synchronization will cause liveliness issues or a + * deadlock. + *

+ */ + private static class SynchronizedKeyedObjectPool implements + KeyedObjectPool { + + /** + * Object whose monitor is used to synchronize methods on the wrapped + * pool. + */ + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + /** Underlying object pool */ + private final KeyedObjectPool keyedPool; + + /** + * Create a new SynchronizedKeyedObjectPool wrapping the given pool + * + * @param keyedPool + * KeyedObjectPool to wrap + * @throws IllegalArgumentException + * if keyedPool is null + */ + SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) + throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException( + "keyedPool must not be null."); + } + this.keyedPool = keyedPool; + } + + /** + * {@inheritDoc} + */ + + public V borrowObject(final K key) throws Exception, + NoSuchElementException, IllegalStateException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + return keyedPool.borrowObject(key); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void returnObject(final K key, final V obj) { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.returnObject(key, obj); + } catch (Exception e) { + // swallowed + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void invalidateObject(final K key, final V obj) { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.invalidateObject(key, obj); + } catch (Exception e) { + // swallowed as of Pool 2 + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void addObject(final K key) throws Exception, + IllegalStateException, UnsupportedOperationException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.addObject(key); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle(final K key) { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return keyedPool.getNumIdle(key); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumActive(final K key) { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return keyedPool.getNumActive(key); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle() { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return keyedPool.getNumIdle(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public int getNumActive() { + ReadLock readLock = readWriteLock.readLock(); + readLock.lock(); + try { + return keyedPool.getNumActive(); + } finally { + readLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void clear() throws Exception, UnsupportedOperationException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.clear(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void clear(final K key) throws Exception, + UnsupportedOperationException { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.clear(key); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void close() { + WriteLock writeLock = readWriteLock.writeLock(); + writeLock.lock(); + try { + keyedPool.close(); + } catch (Exception e) { + // swallowed as of Pool 2 + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("SynchronizedKeyedObjectPool"); + sb.append("{keyedPool=").append(keyedPool); + sb.append('}'); + return sb.toString(); + } + } + + /** + * A fully synchronized PoolableObjectFactory that wraps a + * PoolableObjectFactory and synchronizes access to the wrapped factory + * methods. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. + *

+ */ + private static class SynchronizedPoolableObjectFactory implements + PoolableObjectFactory { + /** Synchronization lock */ + private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); + + /** Wrapped factory */ + private final PoolableObjectFactory factory; + + /** + * Create a SynchronizedPoolableObjectFactory wrapping the given + * factory. + * + * @param factory + * underlying factory to wrap + * @throws IllegalArgumentException + * if the factory is null + */ + SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) + throws IllegalArgumentException { + if (factory == null) { + throw new IllegalArgumentException("factory must not be null."); + } + this.factory = factory; + } + + /** + * {@inheritDoc} + */ + + public T makeObject() throws Exception { + writeLock.lock(); + try { + return factory.makeObject(); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void destroyObject(final T obj) throws Exception { + writeLock.lock(); + try { + factory.destroyObject(obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public boolean validateObject(final T obj) { + writeLock.lock(); + try { + return factory.validateObject(obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void activateObject(final T obj) throws Exception { + writeLock.lock(); + try { + factory.activateObject(obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void passivateObject(final T obj) throws Exception { + writeLock.lock(); + try { + factory.passivateObject(obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("SynchronizedPoolableObjectFactory"); + sb.append("{factory=").append(factory); + sb.append('}'); + return sb.toString(); + } + } + + /** + * A fully synchronized KeyedPoolableObjectFactory that wraps a + * KeyedPoolableObjectFactory and synchronizes access to the wrapped factory + * methods. + *

+ * Note: This should not be used on pool implementations that already + * provide proper synchronization such as the pools provided in the Commons + * Pool library. + *

+ */ + private static class SynchronizedKeyedPoolableObjectFactory + implements KeyedPoolableObjectFactory { + /** Synchronization lock */ + private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); + + /** Wrapped factory */ + private final KeyedPoolableObjectFactory keyedFactory; + + /** + * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given + * factory. + * + * @param keyedFactory + * underlying factory to wrap + * @throws IllegalArgumentException + * if the factory is null + */ + SynchronizedKeyedPoolableObjectFactory( + final KeyedPoolableObjectFactory keyedFactory) + throws IllegalArgumentException { + if (keyedFactory == null) { + throw new IllegalArgumentException( + "keyedFactory must not be null."); + } + this.keyedFactory = keyedFactory; + } + + /** + * {@inheritDoc} + */ + + public V makeObject(final K key) throws Exception { + writeLock.lock(); + try { + return keyedFactory.makeObject(key); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void destroyObject(final K key, final V obj) throws Exception { + writeLock.lock(); + try { + keyedFactory.destroyObject(key, obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public boolean validateObject(final K key, final V obj) { + writeLock.lock(); + try { + return keyedFactory.validateObject(key, obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void activateObject(final K key, final V obj) throws Exception { + writeLock.lock(); + try { + keyedFactory.activateObject(key, obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public void passivateObject(final K key, final V obj) throws Exception { + writeLock.lock(); + try { + keyedFactory.passivateObject(key, obj); + } finally { + writeLock.unlock(); + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("SynchronizedKeyedPoolableObjectFactory"); + sb.append("{keyedFactory=").append(keyedFactory); + sb.append('}'); + return sb.toString(); + } + } + + /** + * Encapsulate the logic for when the next poolable object should be + * discarded. Each time update is called, the next time to shrink is + * recomputed, based on the float factor, number of idle instances in the + * pool and high water mark. Float factor is assumed to be between 0 and 1. + * Values closer to 1 cause less frequent erosion events. Erosion event + * timing also depends on numIdle. When this value is relatively high (close + * to previously established high water mark), erosion occurs more + * frequently. + */ + private static class ErodingFactor { + /** Determines frequency of "erosion" events */ + private final float factor; + + /** Time of next shrink event */ + private transient volatile long nextShrink; + + /** High water mark - largest numIdle encountered */ + private transient volatile int idleHighWaterMark; + + /** + * Create a new ErodingFactor with the given erosion factor. + * + * @param factor + * erosion factor + */ + public ErodingFactor(final float factor) { + this.factor = factor; + nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now + // + + // 15 + // min + // * + // factor + idleHighWaterMark = 1; + } + + /** + * Updates internal state using the supplied time and numIdle. + * + * @param now + * current time + * @param numIdle + * number of idle elements in the pool + */ + public void update(final long now, final int numIdle) { + final int idle = Math.max(0, numIdle); + idleHighWaterMark = Math.max(idle, idleHighWaterMark); + final float maxInterval = 15f; + final float minutes = maxInterval + + ((1f - maxInterval) / idleHighWaterMark) * idle; + nextShrink = now + (long) (minutes * 60000f * factor); + } + + /** + * Returns the time of the next erosion event. + * + * @return next shrink time + */ + public long getNextShrink() { + return nextShrink; + } + + /** + * {@inheritDoc} + */ + + public String toString() { + return "ErodingFactor{" + "factor=" + factor + + ", idleHighWaterMark=" + idleHighWaterMark + '}'; + } + } + + /** + * Decorates an object pool, adding "eroding" behavior. Based on the + * configured {@link #factor erosion factor}, objects returning to the pool + * may be invalidated instead of being added to idle capacity. + */ + private static class ErodingObjectPool implements ObjectPool { + /** Underlying object pool */ + private final ObjectPool pool; + + /** Erosion factor */ + private final ErodingFactor factor; + + /** + * Create an ErodingObjectPool wrapping the given pool using the + * specified erosion factor. + * + * @param pool + * underlying pool + * @param factor + * erosion factor - determines the frequency of erosion + * events + * @see #factor + */ + public ErodingObjectPool(final ObjectPool pool, final float factor) { + this.pool = pool; + this.factor = new ErodingFactor(factor); + } + + /** + * {@inheritDoc} + */ + + public T borrowObject() throws Exception, NoSuchElementException, + IllegalStateException { + return pool.borrowObject(); + } + + /** + * Returns obj to the pool, unless erosion is triggered, in which case + * obj is invalidated. Erosion is triggered when there are idle + * instances in the pool and more than the {@link #factor erosion + * factor}-determined time has elapsed since the last returnObject + * activation. + * + * @param obj + * object to return or invalidate + * @see #factor + */ + + public void returnObject(final T obj) { + boolean discard = false; + final long now = System.currentTimeMillis(); + synchronized (pool) { + if (factor.getNextShrink() < now) { // XXX: Pool 3: move test + // out of sync block + final int numIdle = pool.getNumIdle(); + if (numIdle > 0) { + discard = true; + } + + factor.update(now, numIdle); + } + } + try { + if (discard) { + pool.invalidateObject(obj); + } else { + pool.returnObject(obj); + } + } catch (Exception e) { + // swallowed + } + } + + /** + * {@inheritDoc} + */ + + public void invalidateObject(final T obj) { + try { + pool.invalidateObject(obj); + } catch (Exception e) { + // swallowed + } + } + + /** + * {@inheritDoc} + */ + + public void addObject() throws Exception, IllegalStateException, + UnsupportedOperationException { + pool.addObject(); + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle() { + return pool.getNumIdle(); + } + + /** + * {@inheritDoc} + */ + + public int getNumActive() { + return pool.getNumActive(); + } + + /** + * {@inheritDoc} + */ + + public void clear() throws Exception, UnsupportedOperationException { + pool.clear(); + } + + /** + * {@inheritDoc} + */ + + public void close() { + try { + pool.close(); + } catch (Exception e) { + // swallowed + } + } + + /** + * {@inheritDoc} + */ + + public String toString() { + return "ErodingObjectPool{" + "factor=" + factor + ", pool=" + + pool + '}'; + } + } + + /** + * Decorates a keyed object pool, adding "eroding" behavior. Based on the + * configured {@link #factor erosion factor}, objects returning to the pool + * may be invalidated instead of being added to idle capacity. + */ + private static class ErodingKeyedObjectPool implements + KeyedObjectPool { + /** Underlying pool */ + private final KeyedObjectPool keyedPool; + + /** Erosion factor */ + private final ErodingFactor erodingFactor; + + /** + * Create an ErodingObjectPool wrapping the given pool using the + * specified erosion factor. + * + * @param keyedPool + * underlying pool + * @param factor + * erosion factor - determines the frequency of erosion + * events + * @see #erodingFactor + */ + public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, + final float factor) { + this(keyedPool, new ErodingFactor(factor)); + } + + /** + * Create an ErodingObjectPool wrapping the given pool using the + * specified erosion factor. + * + * @param keyedPool + * underlying pool - must not be null + * @param erodingFactor + * erosion factor - determines the frequency of erosion + * events + * @see #factor + */ + protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, + final ErodingFactor erodingFactor) { + if (keyedPool == null) { + throw new IllegalArgumentException( + "keyedPool must not be null."); + } + this.keyedPool = keyedPool; + this.erodingFactor = erodingFactor; + } + + /** + * {@inheritDoc} + */ + + public V borrowObject(final K key) throws Exception, + NoSuchElementException, IllegalStateException { + return keyedPool.borrowObject(key); + } + + /** + * Returns obj to the pool, unless erosion is triggered, in which case + * obj is invalidated. Erosion is triggered when there are idle + * instances in the pool associated with the given key and more than the + * configured {@link #erodingFactor erosion factor} time has elapsed + * since the last returnObject activation. + * + * @param obj + * object to return or invalidate + * @param key + * key + * @see #erodingFactor + */ + + public void returnObject(final K key, final V obj) throws Exception { + boolean discard = false; + final long now = System.currentTimeMillis(); + final ErodingFactor factor = getErodingFactor(key); + synchronized (keyedPool) { + if (factor.getNextShrink() < now) { + final int numIdle = getNumIdle(key); + if (numIdle > 0) { + discard = true; + } + + factor.update(now, numIdle); + } + } + try { + if (discard) { + keyedPool.invalidateObject(key, obj); + } else { + keyedPool.returnObject(key, obj); + } + } catch (Exception e) { + // swallowed + } + } + + /** + * Returns the eroding factor for the given key + * + * @param key + * key + * @return eroding factor for the given keyed pool + */ + protected ErodingFactor getErodingFactor(final K key) { + return erodingFactor; + } + + /** + * {@inheritDoc} + */ + + public void invalidateObject(final K key, final V obj) { + try { + keyedPool.invalidateObject(key, obj); + } catch (Exception e) { + // swallowed + } + } + + /** + * {@inheritDoc} + */ + + public void addObject(final K key) throws Exception, + IllegalStateException, UnsupportedOperationException { + keyedPool.addObject(key); + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle() { + return keyedPool.getNumIdle(); + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle(final K key) { + return keyedPool.getNumIdle(key); + } + + /** + * {@inheritDoc} + */ + + public int getNumActive() { + return keyedPool.getNumActive(); + } + + /** + * {@inheritDoc} + */ + + public int getNumActive(final K key) { + return keyedPool.getNumActive(key); + } + + /** + * {@inheritDoc} + */ + + public void clear() throws Exception, UnsupportedOperationException { + keyedPool.clear(); + } + + /** + * {@inheritDoc} + */ + + public void clear(final K key) throws Exception, + UnsupportedOperationException { + keyedPool.clear(key); + } + + /** + * {@inheritDoc} + */ + + public void close() { + try { + keyedPool.close(); + } catch (Exception e) { + // swallowed + } + } + + /** + * Returns the underlying pool + * + * @return the keyed pool that this ErodingKeyedObjectPool wraps + */ + protected KeyedObjectPool getKeyedPool() { + return keyedPool; + } + + /** + * {@inheritDoc} + */ + + public String toString() { + return "ErodingKeyedObjectPool{" + "erodingFactor=" + + erodingFactor + ", keyedPool=" + keyedPool + '}'; + } + } + + /** + * Extends ErodingKeyedObjectPool to allow erosion to take place on a + * per-key basis. Timing of erosion events is tracked separately for + * separate keyed pools. + */ + private static class ErodingPerKeyKeyedObjectPool extends + ErodingKeyedObjectPool { + /** Erosion factor - same for all pools */ + private final float factor; + + /** Map of ErodingFactor instances keyed on pool keys */ + private final Map factors = Collections.synchronizedMap(new HashMap()); + + /** + * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed + * pool with the specified erosion factor. + * + * @param keyedPool + * underlying keyed pool + * @param factor + * erosion factor + */ + public ErodingPerKeyKeyedObjectPool( + final KeyedObjectPool keyedPool, final float factor) { + super(keyedPool, null); + this.factor = factor; + } + + /** + * {@inheritDoc} + */ + + protected ErodingFactor getErodingFactor(final K key) { + ErodingFactor factor = factors.get(key); + // this may result in two ErodingFactors being created for a key + // since they are small and cheap this is okay. + if (factor == null) { + factor = new ErodingFactor(this.factor); + factors.put(key, factor); + } + return factor; + } + + /** + * {@inheritDoc} + */ + + public String toString() { + return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor + + ", keyedPool=" + getKeyedPool() + '}'; + } + } +} \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java new file mode 100644 index 00000000..1a32787a --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2; + +/** + * An interface defining life-cycle methods for instances to be served by an + * {@link ObjectPool}. + *

+ * By contract, when an {@link ObjectPool} delegates to a + * {@link PoolableObjectFactory}, + *

    + *
  1. + * {@link #makeObject} is called whenever a new instance is needed. + *
  2. + *
  3. + * {@link #activateObject} is invoked on every instance that has been + * {@link #passivateObject passivated} before it is + * {@link ObjectPool#borrowObject borrowed} from the pool. + *
  4. + *
  5. + * {@link #validateObject} is invoked on {@link #activateObject activated} + * instances to make sure they can be {@link ObjectPool#borrowObject borrowed} + * from the pool. {@link #validateObject} may also be used to + * test an instance being {@link ObjectPool#returnObject returned} to the pool + * before it is {@link #passivateObject passivated}. It will only be invoked + * on an activated instance. + *
  6. + *
  7. + * {@link #passivateObject} is invoked on every instance when it is returned + * to the pool. + *
  8. + *
  9. + * {@link #destroyObject} is invoked on every instance when it is being + * "dropped" from the pool (whether due to the response from + * {@link #validateObject}, or for reasons specific to the pool + * implementation.) There is no guarantee that the instance being destroyed + * will be considered active, passive or in a generally consistent state. + *
  10. + *
+ * {@link PoolableObjectFactory} must be thread-safe. The only promise + * an {@link ObjectPool} makes is that the same instance of an object will not + * be passed to more than one method of a PoolableObjectFactory + * at a time. + * + * @param Type of element managed in this factory. + * + * @see ObjectPool + * + * @version $Revision: 1333925 $ + * + * @since 2.0 + */ +public interface PoolableObjectFactory { + /** + * Creates an instance that can be served by the pool. Instances returned from + * this method should be in the same state as if they had been + * {@link #activateObject activated}. They will not be activated before being + * served by the pool. + * + * @return an instance that can be served by the pool. + * + * @throws Exception if there is a problem creating a new instance, + * this will be propagated to the code requesting an object. + */ + T makeObject() throws Exception; + + /** + * Destroys an instance no longer needed by the pool. + *

+ * It is important for implementations of this method to be aware that there + * is no guarantee about what state obj will be in and the + * implementation should be prepared to handle unexpected errors. + *

+ * Also, an implementation must take in to consideration that instances lost + * to the garbage collector may never be destroyed. + *

+ * + * @param obj the instance to be destroyed + * + * @throws Exception should be avoided as it may be swallowed by + * the pool implementation. + * + * @see #validateObject + * @see ObjectPool#invalidateObject + */ + void destroyObject(T obj) throws Exception; + + /** + * Ensures that the instance is safe to be returned by the pool. + * + * @param obj the instance to be validated + * + * @return false if obj is not valid and should + * be dropped from the pool, true otherwise. + */ + boolean validateObject(T obj); + + /** + * Reinitialize an instance to be returned by the pool. + * + * @param obj the instance to be activated + * + * @throws Exception if there is a problem activating obj, + * this exception may be swallowed by the pool. + * + * @see #destroyObject + */ + void activateObject(T obj) throws Exception; + + /** + * Uninitialize an instance to be returned to the idle object pool. + * + * @param obj the instance to be passivated + * + * @throws Exception if there is a problem passivating obj, + * this exception may be swallowed by the pool. + * + * @see #destroyObject + */ + void passivateObject(T obj) throws Exception; +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java new file mode 100644 index 00000000..3bfb41ae --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.io.PrintWriter; + +/** + * Configuration settings for abandoned object removal. + * + * @version $Revision:$ + */ +public class AbandonedConfig { + + /** + * Whether or not borrowObject performs abandoned object removal. + */ + private boolean removeAbandonedOnBorrow = false; + + /** + * Whether or not pool maintenance (evictor) performs abandoned object + * removal. + */ + private boolean removeAbandonedOnMaintenance = false; + + /** + *

Flag to remove abandoned objects if they exceed the + * removeAbandonedTimeout when borrowObject is invoked.

+ * + *

The default value is false.

+ * + *

If set to true, abandoned objects are removed by borrowObject if + * there are fewer than 2 idle objects available in the pool and + * getNumActive() > getMaxTotal() - 3

+ * + * @return true if abandoned objects are to be removed by borrowObject + */ + public boolean getRemoveAbandonedOnBorrow() { + return (this.removeAbandonedOnBorrow); + } + + /** + *

Flag to remove abandoned objects if they exceed the + * removeAbandonedTimeout when borrowObject is invoked.

+ * + * @param removeAbandonedOnBorrow true means abandoned objects will be + * removed by borrowObject + * @see #getRemoveAbandonedOnBorrow() + */ + public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) { + this.removeAbandonedOnBorrow = removeAbandonedOnBorrow; + } + + /** + *

Flag to remove abandoned objects if they exceed the + * removeAbandonedTimeout when pool maintenance (the "evictor") + * runs.

+ * + *

The default value is false.

+ * + *

If set to true, abandoned objects are removed by the pool + * maintenance thread when it runs. This setting has no effect + * unless maintenance is enabled by setting + *{@link GenericObjectPool#getTimeBetweenEvictionRunsMillis() timeBetweenEvictionRunsMillis} + * to a positive number.

+ * + * @return true if abandoned objects are to be removed by the evictor + */ + public boolean getRemoveAbandonedOnMaintenance() { + return (this.removeAbandonedOnMaintenance); + } + + /** + *

Flag to remove abandoned objects if they exceed the + * removeAbandonedTimeout when pool maintenance runs.

+ * + * @param removeAbandonedOnMaintenance true means abandoned objects will be + * removed by pool maintenance + * @see #getRemoveAbandonedOnMaintenance + */ + public void setRemoveAbandonedOnMaintenance(boolean removeAbandonedOnMaintenance) { + this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance; + } + + /** + * Timeout in seconds before an abandoned object can be removed. + */ + private int removeAbandonedTimeout = 300; + + /** + *

Timeout in seconds before an abandoned object can be removed.

+ * + *

The time of most recent use of an object is the maximum (latest) of + * {@link TrackedUse#getLastUsed()} (if this class of the object implements + * TrackedUse) and the time when the object was borrowed from the pool.

+ * + *

The default value is 300 seconds.

+ * + * @return the abandoned object timeout in seconds + */ + public int getRemoveAbandonedTimeout() { + return (this.removeAbandonedTimeout); + } + + /** + *

Sets the timeout in seconds before an abandoned object can be + * removed

+ * + *

Setting this property has no effect if + * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and + * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance} + * are both false.

+ * + * @param removeAbandonedTimeout new abandoned timeout in seconds + * @see #getRemoveAbandonedTimeout() + */ + public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { + this.removeAbandonedTimeout = removeAbandonedTimeout; + } + + /** + * Determines whether or not to log stack traces for application code + * which abandoned an object. + */ + private boolean logAbandoned = false; + + /** + * Flag to log stack traces for application code which abandoned + * an object. + * + * Defaults to false. + * Logging of abandoned objects adds overhead for every object created + * because a stack trace has to be generated. + * + * @return boolean true if stack trace logging is turned on for abandoned + * objects + * + */ + public boolean getLogAbandoned() { + return (this.logAbandoned); + } + + /** + * Sets the flag to log stack traces for application code which abandoned + * an object. + * + * @param logAbandoned true turns on abandoned stack trace logging + * @see #getLogAbandoned() + * + */ + public void setLogAbandoned(boolean logAbandoned) { + this.logAbandoned = logAbandoned; + } + + /** + * PrintWriter to use to log information on abandoned objects. + */ + private PrintWriter logWriter = new PrintWriter(System.out); + + /** + * Returns the log writer being used by this configuration to log + * information on abandoned objects. If not set, a PrintWriter based on + * System.out is used. + * + * @return log writer in use + */ + public PrintWriter getLogWriter() { + return logWriter; + } + + /** + * Sets the log writer to be used by this configuration to log + * information on abandoned objects. + * + * @param logWriter The new log writer + */ + public void setLogWriter(PrintWriter logWriter) { + this.logWriter = logWriter; + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java new file mode 100644 index 00000000..44abfb86 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java @@ -0,0 +1,1077 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +/** + * Base class that provides common functionality for {@link GenericObjectPool} + * and {@link GenericKeyedObjectPool}. The primary reason this class exists is + * reduce code duplication between the two pool implementations. + * + * @param Type of element pooled in this pool. + * + * This class is intended to be thread-safe. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public abstract class BaseGenericObjectPool implements NotificationEmitter { + + // Constants + /** + * Name of the JMX notification broadcast when the pool implementation + * swallows an {@link Exception}. + */ + public static final String NOTIFICATION_SWALLOWED_EXCEPTION = + "SWALLOWED_EXCEPTION"; + /** + * The size of the caches used to store historical data for some attributes + * so that rolling means may be calculated. + */ + public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100; + private static final int SWALLOWED_EXCEPTION_QUEUE_SIZE = 10; + + // Configuration attributes + private volatile int maxTotal = + GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; + private volatile boolean blockWhenExhausted = + GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; + private volatile long maxWaitMillis = + GenericKeyedObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS; + private volatile boolean lifo = GenericObjectPoolConfig.DEFAULT_LIFO; + private volatile boolean testOnBorrow = + GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW; + private volatile boolean testOnReturn = + GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN; + private volatile boolean testWhileIdle = + GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE; + private volatile long timeBetweenEvictionRunsMillis = + GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + private volatile int numTestsPerEvictionRun = + GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; + private volatile long minEvictableIdleTimeMillis = + GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + private volatile long softMinEvictableIdleTimeMillis = + GenericObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + private volatile EvictionPolicy evictionPolicy; + + + // Internal (primarily state) attributes + final Object closeLock = new Object(); + volatile boolean closed = false; + final Object evictionLock = new Object(); + private Evictor evictor = null; // @GuardedBy("evictionLock") + Iterator> evictionIterator = null; // @GuardedBy("evictionLock") + /* + * Class loader for evictor thread to use since in a J2EE or similar + * environment the context class loader for the evictor thread may have + * visibility of the correct factory. See POOL-161. + */ + private final ClassLoader factoryClassLoader; + + + // Monitoring (primarily JMX) attributes + private final ObjectName oname; + private final NotificationBroadcasterSupport jmxNotificationSupport; + private final String creationStackTrace; + private final Deque swallowedExceptions = new LinkedList(); + private final AtomicInteger swallowedExcpetionCount = new AtomicInteger(0); + private final AtomicLong borrowedCount = new AtomicLong(0); + private final AtomicLong returnedCount = new AtomicLong(0); + final AtomicLong createdCount = new AtomicLong(0); + final AtomicLong destroyedCount = new AtomicLong(0); + final AtomicLong destroyedByEvictorCount = new AtomicLong(0); + final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0); + private final LinkedList activeTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() + private final LinkedList idleTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() + private final LinkedList waitTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() + private final Object maxBorrowWaitTimeMillisLock = new Object(); + private volatile long maxBorrowWaitTimeMillis = 0; // @GuardedBy("maxBorrowWaitTimeMillisLock") + + + /** + * Handles JMX registration (if required) and the initialization required for + * monitoring. + * + * @param config Pool configuration + * @param jmxNameBase Base JMX name for the new pool + * @param jmxNamePrefix Prefix tobe used for JMX name for the new pool + */ + public BaseGenericObjectPool(BaseObjectPoolConfig config, + String jmxNameBase, String jmxNamePrefix) { + if (config.getJmxEnabled()) { + this.jmxNotificationSupport = new NotificationBroadcasterSupport(); + this.oname = jmxRegister(jmxNameBase, jmxNamePrefix); + } else { + this.jmxNotificationSupport = null; + this.oname = null; + } + + // Populate the swallowed exceptions queue + for (int i = 0; i < SWALLOWED_EXCEPTION_QUEUE_SIZE; i++) { + swallowedExceptions.add(null); + } + + // Populate the creation stack trace + this.creationStackTrace = getStackTrace(new Exception()); + + // save the current CCL to be used later by the evictor Thread + factoryClassLoader = Thread.currentThread().getContextClassLoader(); + + // Initialise the attributes used to record rolling averages + initStats(); + } + + + /** + * Returns the maximum number of objects that can be allocated by the pool + * (checked out to clients, or idle awaiting checkout) at a given time. When + * non-positive, there is no limit to the number of objects that can be + * managed by the pool at one time. + * + * @return the cap on the total number of object instances managed by the + * pool. + * + * @see #setMaxTotal + */ + public final int getMaxTotal() { + return maxTotal; + } + + /** + * Sets the cap on the number of objects that can be allocated by the pool + * (checked out to clients, or idle awaiting checkout) at a given time. Use + * a negative value for no limit. + * + * @param maxTotal The cap on the total number of object instances managed + * by the pool. Negative values mean that there is no limit + * to the number of objects allocated by the pool. + * + * @see #getMaxTotal + */ + public final void setMaxTotal(int maxTotal) { + this.maxTotal = maxTotal; + } + + /** + * Returns whether to block when the borrowObject() method is + * invoked when the pool is exhausted (the maximum number of "active" + * objects has been reached). + * + * @return true if borrowObject() should block + * when the pool is exhausted + * + * @see #setBlockWhenExhausted + */ + public final boolean getBlockWhenExhausted() { + return blockWhenExhausted; + } + + /** + * Sets whether to block when the borrowObject() method is + * invoked when the pool is exhausted (the maximum number of "active" + * objects has been reached). + * + * @param blockWhenExhausted true if + * borrowObject() should block + * when the pool is exhausted + * + * @see #getBlockWhenExhausted + */ + public final void setBlockWhenExhausted(boolean blockWhenExhausted) { + this.blockWhenExhausted = blockWhenExhausted; + } + + /** + * Returns the maximum amount of time (in milliseconds) the + * borrowObject() method should block before throwing an + * exception when the pool is exhausted and + * {@link #getBlockWhenExhausted} is true. When less than 0, the + * borrowObject() method may block indefinitely. + * + * @return the maximum number of milliseconds borrowObject() + * will block. + * + * @see #setMaxWaitMillis + * @see #setBlockWhenExhausted + */ + public final long getMaxWaitMillis() { + return maxWaitMillis; + } + + /** + * Sets the maximum amount of time (in milliseconds) the + * borrowObject() method should block before throwing an + * exception when the pool is exhausted and + * {@link #getBlockWhenExhausted} is true. When less than 0, the + * borrowObject() method may block indefinitely. + * + * @param maxWaitMillis the maximum number of milliseconds + * borrowObject() will block or negative + * for indefinitely. + * + * @see #getMaxWaitMillis + * @see #setBlockWhenExhausted + */ + public final void setMaxWaitMillis(long maxWaitMillis) { + this.maxWaitMillis = maxWaitMillis; + } + + /** + * Returns whether the pool has LIFO (last in, first out) behaviour with + * respect to idle objects - always returning the most recently used object + * from the pool, or as a FIFO (first in, first out) queue, where the pool + * always returns the oldest object in the idle object pool. + * + * @return true if the pool is configured with LIFO behaviour + * or false if the pool is configured with FIFO + * behaviour + * + * @see #setLifo + */ + public final boolean getLifo() { + return lifo; + } + + /** + * Sets whether the pool has LIFO (last in, first out) behaviour with + * respect to idle objects - always returning the most recently used object + * from the pool, or as a FIFO (first in, first out) queue, where the pool + * always returns the oldest object in the idle object pool. + * + * @param lifo true if the pool is to be configured with LIFO + * behaviour or false if the pool is to be + * configured with FIFO behaviour + * + * @see #getLifo() + */ + public final void setLifo(boolean lifo) { + this.lifo = lifo; + } + + /** + * Returns whether objects borrowed from the pool will be validated before + * being returned from the borrowObject() method. Validation is + * performed by the validateObject() method of the factory + * associated with the pool. If the object fails to validate, it will be + * removed from the pool and destroyed, and a new attempt will be made to + * borrow an object from the pool. + * + * @return true if objects are validated before being returned + * from the borrowObject() method + * + * @see #setTestOnBorrow + */ + public final boolean getTestOnBorrow() { + return testOnBorrow; + } + + /** + * Sets whether objects borrowed from the pool will be validated before + * being returned from the borrowObject() method. Validation is + * performed by the validateObject() method of the factory + * associated with the pool. If the object fails to validate, it will be + * removed from the pool and destroyed, and a new attempt will be made to + * borrow an object from the pool. + * + * @param testOnBorrow true if objects should be validated + * before being returned from the + * borrowObject() method + * + * @see #getTestOnBorrow + */ + public final void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + /** + * Returns whether objects borrowed from the pool will be validated when + * they are returned to the pool via the returnObject() method. + * Validation is performed by the validateObject() method of + * the factory associated with the pool. If the object fails to it will be + * destroyed rather then returned the pool. + * + * @return true if objects are validated on being returned to + * the pool via the returnObject() method + * + * @see #setTestOnReturn + */ + public final boolean getTestOnReturn() { + return testOnReturn; + } + + /** + * Sets whether objects borrowed from the pool will be validated when + * they are returned to the pool via the returnObject() method. + * Validation is performed by the validateObject() method of + * the factory associated with the pool. If the object fails to it will be + * destroyed rather then returned the pool. + * + * @param testOnReturn true if objects are validated on being + * returned to the pool via the + * returnObject() method + * + * @see #getTestOnReturn + */ + public final void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + /** + * Returns whether objects sitting idle in the pool will be validated by the + * idle object evictor (if any - see + * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed + * by the validateObject() method of the factory associated + * with the pool. If the object fails to validate, it will be removed from + * the pool and destroyed. + * + * @return true if objects will be validated by the evictor + * + * @see #setTestWhileIdle + * @see #setTimeBetweenEvictionRunsMillis + */ + public final boolean getTestWhileIdle() { + return testWhileIdle; + } + + /** + * Returns whether objects sitting idle in the pool will be validated by the + * idle object evictor (if any - see + * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed + * by the validateObject() method of the factory associated + * with the pool. If the object fails to validate, it will be removed from + * the pool and destroyed. + * + * @param testWhileIdle + * true so objects will be validated by the evictor + * + * @see #getTestWhileIdle + * @see #setTimeBetweenEvictionRunsMillis + */ + public final void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + /** + * Returns the number of milliseconds to sleep between runs of the idle + * object evictor thread. When non-positive, no idle object evictor thread + * will be run. + * + * @return number of milliseconds to sleep between evictor runs + * + * @see #setTimeBetweenEvictionRunsMillis + */ + public final long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + /** + * Sets the number of milliseconds to sleep between runs of the idle + * object evictor thread. When non-positive, no idle object evictor thread + * will be run. + * + * @param timeBetweenEvictionRunsMillis + * number of milliseconds to sleep between evictor runs + * + * @see #getTimeBetweenEvictionRunsMillis + */ + public final void setTimeBetweenEvictionRunsMillis( + long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + startEvictor(timeBetweenEvictionRunsMillis); + } + + /** + * Returns the maximum number of objects to examine during each run (if any) + * of the idle object evictor thread. When positive, the number of tests + * performed for a run will be the minimum of the configured value and the + * number of idle instances in the pool. When negative, the number of tests + * performed will be ceil({@link #getNumIdle}/ + * abs({@link #getNumTestsPerEvictionRun})) whch means that when the value + * is -n roughly one nth of the idle objects will be tested per + * run. + * + * @return max number of objects to examine during each evictor run + * + * @see #setNumTestsPerEvictionRun + * @see #setTimeBetweenEvictionRunsMillis + */ + public final int getNumTestsPerEvictionRun() { + return numTestsPerEvictionRun; + } + + /** + * Sets the maximum number of objects to examine during each run (if any) + * of the idle object evictor thread. When positive, the number of tests + * performed for a run will be the minimum of the configured value and the + * number of idle instances in the pool. When negative, the number of tests + * performed will be ceil({@link #getNumIdle}/ + * abs({@link #getNumTestsPerEvictionRun})) whch means that when the value + * is -n roughly one nth of the idle objects will be tested per + * run. + * + * @param numTestsPerEvictionRun + * max number of objects to examine during each evictor run + * + * @see #getNumTestsPerEvictionRun + * @see #setTimeBetweenEvictionRunsMillis + */ + public final void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.numTestsPerEvictionRun = numTestsPerEvictionRun; + } + + /** + * Returns the minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction by the idle object evictor (if any - + * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, + * no objects will be evicted from the pool due to idle time alone. + * + * @return minimum amount of time an object may sit idle in the pool before + * it is eligible for eviction + * + * @see #setMinEvictableIdleTimeMillis + * @see #setTimeBetweenEvictionRunsMillis + */ + public final long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + /** + * Sets the minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction by the idle object evictor (if any - + * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, + * no objects will be evicted from the pool due to idle time alone. + * + * @param minEvictableIdleTimeMillis + * minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction + * + * @see #getMinEvictableIdleTimeMillis + * @see #setTimeBetweenEvictionRunsMillis + */ + public final void setMinEvictableIdleTimeMillis( + long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + /** + * Returns the minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction by the idle object evictor (if any - + * see {@link #setTimeBetweenEvictionRunsMillis(long)}), + * with the extra condition that at least minIdle object + * instances remain in the pool. This setting is overridden by + * {@link #getMinEvictableIdleTimeMillis} (that is, if + * {@link #getMinEvictableIdleTimeMillis} is positive, then + * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). + * + * @return minimum amount of time an object may sit idle in the pool before + * it is eligible for eviction if minIdle instances are available + * + * @see #setSoftMinEvictableIdleTimeMillis + */ + public final long getSoftMinEvictableIdleTimeMillis() { + return softMinEvictableIdleTimeMillis; + } + + /** + * Sets the minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction by the idle object evictor (if any - + * see {@link #setTimeBetweenEvictionRunsMillis(long)}), + * with the extra condition that at least minIdle object + * instances remain in the pool. This setting is overridden by + * {@link #getMinEvictableIdleTimeMillis} (that is, if + * {@link #getMinEvictableIdleTimeMillis} is positive, then + * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). + * + * @param softMinEvictableIdleTimeMillis + * minimum amount of time an object may sit idle in the pool + * before it is eligible for eviction if minIdle instances are + * available + * + * @see #getSoftMinEvictableIdleTimeMillis + */ + public final void setSoftMinEvictableIdleTimeMillis( + long softMinEvictableIdleTimeMillis) { + this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; + } + + /** + * Returns the name of the {@link EvictionPolicy} implementation that is + * used by this pool. + * + * @return The fully qualified class name of the {@link EvictionPolicy} + * + * @see #setEvictionPolicyClassName(String) + */ + public final String getEvictionPolicyClassName() { + return evictionPolicy.getClass().getName(); + } + + /** + * Sets the name of the {@link EvictionPolicy} implementation that is + * used by this pool. + * + * @param evictionPolicyClassName the fully qualified class name of the + * new eviction policy + * + * @see #getEvictionPolicyClassName() + */ + @SuppressWarnings("unchecked") + public final void setEvictionPolicyClassName( + String evictionPolicyClassName) { + try { + Class clazz = Class.forName(evictionPolicyClassName); + Object policy = clazz.newInstance(); + if (policy instanceof EvictionPolicy) { + this.evictionPolicy = (EvictionPolicy) policy; + } + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException( + "Unable to create EvictionPolicy instance of type " + + evictionPolicyClassName, e); + } catch (InstantiationException e) { + throw new IllegalArgumentException( + "Unable to create EvictionPolicy instance of type " + + evictionPolicyClassName, e); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException( + "Unable to create EvictionPolicy instance of type " + + evictionPolicyClassName, e); + } + } + + + /** + * Closes the pool, destroys the remaining idle objects and, if registered + * in JMX, deregisters it. + */ + public abstract void close(); + + /** + * Has this pool instance been closed. + * @return true when this pool has been closed. + */ + public final boolean isClosed() { + return closed; + } + + /** + *

Perform numTests idle object eviction tests, evicting + * examined objects that meet the criteria for eviction. If + * testWhileIdle is true, examined objects are validated + * when visited (and removed if invalid); otherwise only objects that + * have been idle for more than minEvicableIdleTimeMillis + * are removed.

+ * + * @throws Exception when there is a problem evicting idle objects. + */ + public abstract void evict() throws Exception; + + /** + * Returns the {@link EvictionPolicy} defined for this pool. + * @return the eviction policy + */ + final EvictionPolicy getEvictionPolicy() { + return evictionPolicy; + } + + /** + * Verifies that the pool is open. + * @throws IllegalStateException if the pool is closed. + */ + final void assertOpen() throws IllegalStateException { + if (isClosed()) { + throw new IllegalStateException("Pool not open"); + } + } + + /** + *

Starts the evictor with the given delay. If there is an evictor + * running when this method is called, it is stopped and replaced with a + * new evictor with the specified delay.

+ * + *

This method needs to be final, since it is called from a constructor. + * See POOL-195.

+ * + * @param delay time in milliseconds before start and between eviction runs + */ + final void startEvictor(long delay) { + synchronized (evictionLock) { + if (null != evictor) { + EvictionTimer.cancel(evictor); + evictor = null; + evictionIterator = null; + } + if (delay > 0) { + evictor = new Evictor(); + EvictionTimer.schedule(evictor, delay, delay); + } + } + } + + /** + * Tries to ensure that the configured minimum number of idle instances are + * available in the pool. + * @throws Exception if an error occurs creating idle instances + */ + abstract void ensureMinIdle() throws Exception; + + + // Monitoring (primarily JMX) related methods + + /** + * Provides the name under which the pool has been registered with the + * platform MBean server or null if the pool has not been + * registered. + * @return the JMX name + */ + public final ObjectName getJmxName() { + return oname; + } + + /** + * Provides the stack trace for the call that created this pool. JMX + * registration may trigger a memory leak so it is important that pools are + * deregistered when no longer used by calling the {@link #close()} method. + * This method is provided to assist with identifying code that creates but + * does not close it thereby creating a memory leak. + * @return pool creation stack trace + */ + public final String getCreationStackTrace() { + return creationStackTrace; + } + + /** + * Lists the most recent exceptions that have been swallowed by the pool + * implementation. Exceptions are typically swallowed when a problem occurs + * while destroying an object. + * @return array containing stack traces of recently swallowed exceptions + */ + public final String[] getSwallowedExceptions() { + List temp = + new ArrayList(SWALLOWED_EXCEPTION_QUEUE_SIZE); + synchronized (swallowedExceptions) { + temp.addAll(swallowedExceptions); + } + return temp.toArray(new String[SWALLOWED_EXCEPTION_QUEUE_SIZE]); + } + + /** + * The total number of objects successfully borrowed from this pool over the + * lifetime of the pool. + * @return the borrowed object count + */ + public final long getBorrowedCount() { + return borrowedCount.get(); + } + + /** + * The total number of objects returned to this pool over the lifetime of + * the pool. This excludes attempts to return the same object multiple + * times. + * @return the returned object count + */ + public final long getReturnedCount() { + return returnedCount.get(); + } + + /** + * The total number of objects created for this pool over the lifetime of + * the pool. + * @return the created object count + */ + public final long getCreatedCount() { + return createdCount.get(); + } + + /** + * The total number of objects destroyed by this pool over the lifetime of + * the pool. + * @return the destroyed object count + */ + public final long getDestroyedCount() { + return destroyedCount.get(); + } + + /** + * The total number of objects destroyed by the evictor associated with this + * pool over the lifetime of the pool. + * @return the evictor destroyed object count + */ + public final long getDestroyedByEvictorCount() { + return destroyedByEvictorCount.get(); + } + + /** + * The total number of objects destroyed by this pool as a result of failing + * validation during borrowObject() over the lifetime of the + * pool. + * @return validation destroyed object count + */ + public final long getDestroyedByBorrowValidationCount() { + return destroyedByBorrowValidationCount.get(); + } + + /** + * The mean time objects are active for based on the last {@link + * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool. + * @return mean time an object has been checked out from the pool among + * recently returned objects + */ + public final long getMeanActiveTimeMillis() { + return getMeanFromStatsCache(activeTimes); + } + + /** + * The mean time objects are idle for based on the last {@link + * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. + * @return mean time an object has been idle in the pool among recently + * borrowed objects + */ + public final long getMeanIdleTimeMillis() { + return getMeanFromStatsCache(idleTimes); + } + + /** + * The mean time threads wait to borrow an object based on the last {@link + * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. + * @return mean time in milliseconds that a recently served thread has had + * to wait to borrow an object from the pool + */ + public final long getMeanBorrowWaitTimeMillis() { + return getMeanFromStatsCache(waitTimes); + } + + /** + * The maximum time a thread has waited to borrow objects from the pool. + * @return maximum wait time in milliseconds since the pool was created + */ + public final long getMaxBorrowWaitTimeMillis() { + return maxBorrowWaitTimeMillis; + } + + /** + * The number of instances currently idle in this pool. + * @return count of instances available for checkout from the pool + */ + public abstract int getNumIdle(); + + /** + * Returns the {@link NotificationBroadcasterSupport} for the pool + * @return JMX notification broadcaster + */ + final NotificationBroadcasterSupport getJmxNotificationSupport() { + return jmxNotificationSupport; + } + + /** + * Swallows an exception, sends a JMX notification, and adds the swallowed exception + * to the swallowed exceptions queue. + * @param e exception to be swallowed + */ + final void swallowException(Exception e) { + String msg = getStackTrace(e); + + ObjectName oname = getJmxName(); + if (oname != null && !isClosed()) { + Notification n = new Notification(NOTIFICATION_SWALLOWED_EXCEPTION, + oname, swallowedExcpetionCount.incrementAndGet(), msg); + getJmxNotificationSupport().sendNotification(n); + } + + // Add the exception the queue, removing the oldest + synchronized (swallowedExceptions) { + swallowedExceptions.addLast(msg); + swallowedExceptions.pollFirst(); + } + } + + /** + * Updates statistics after an object is borrowed from the pool. + * @param p object borrowed from the pool + * @param waitTime time (in milliseconds) that the borrowing thread had to wait + */ + final void updateStatsBorrow(PooledObject p, long waitTime) { + borrowedCount.incrementAndGet(); + synchronized (idleTimes) { + idleTimes.add(Long.valueOf(p.getIdleTimeMillis())); + idleTimes.poll(); + } + synchronized (waitTimes) { + waitTimes.add(Long.valueOf(waitTime)); + waitTimes.poll(); + } + synchronized (maxBorrowWaitTimeMillisLock) { + if (waitTime > maxBorrowWaitTimeMillis) { + maxBorrowWaitTimeMillis = waitTime; + } + } + } + + /** + * Updates statistics after an object is returned to the pool. + * @param activeTime the amount of time (in milliseconds) that the returning + * object was checked out + */ + final void updateStatsReturn(long activeTime) { + returnedCount.incrementAndGet(); + synchronized (activeTimes) { + activeTimes.add(Long.valueOf(activeTime)); + activeTimes.poll(); + } + } + + /** + * Unregisters this pool's MBean. + */ + final void jmxUnregister() { + if (oname != null) { + try { + ManagementFactory.getPlatformMBeanServer().unregisterMBean( + oname); + } catch (MBeanRegistrationException e) { + swallowException(e); + } catch (InstanceNotFoundException e) { + swallowException(e); + } + } + } + + /** + * Registers the pool with the platform MBean server. + * The registered name will be + * jmxNameBase + jmxNamePrefix + i where i is the least + * integer greater than or equal to 1 such that the name is not already + * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException + * returning null. + * + * @param jmxNameBase base JMX name for this pool + * @param jmxNamePrefix name prefix + * @return registered ObjectName, null if registration fails + */ + private ObjectName jmxRegister(String jmxNameBase, String jmxNamePrefix) { + ObjectName objectName = null; + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + int i = 1; + boolean registered = false; + while (!registered) { + try { + ObjectName oname = + new ObjectName(jmxNameBase + jmxNamePrefix + i); + mbs.registerMBean(this, oname); + objectName = oname; + registered = true; + } catch (MalformedObjectNameException e) { + if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals( + jmxNamePrefix)) { + // Shouldn't happen. Skip registration if it does. + registered = true; + } else { + // Must be an invalid name prefix. Use the default + // instead. + jmxNamePrefix = + BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX; + } + } catch (InstanceAlreadyExistsException e) { + // Increment the index and try again + i++; + } catch (MBeanRegistrationException e) { + // Shouldn't happen. Skip registration if it does. + registered = true; + } catch (NotCompliantMBeanException e) { + // Shouldn't happen. Skip registration if it does. + registered = true; + } + } + return objectName; + } + + /** + * Gets the stack trace of an exception as a string. + * @param e exception to trace + * @return exception stack trace as a string + */ + private String getStackTrace(Exception e) { + // Need the exception in string form to prevent the retention of + // references to classes in the stack trace that could trigger a memory + // leak in a container environment. + Writer w = new StringWriter(); + PrintWriter pw = new PrintWriter(w); + e.printStackTrace(pw); + return w.toString(); + } + + /** + * Returns the greatest integer less than ore equal to the arithmetic mean + * of the entries in cache, acquiring and holding the argument's + * monitor while making a local copy. + * @param cache list containing entries to analyze + * @return truncated arithmetic mean + */ + private long getMeanFromStatsCache(LinkedList cache) { + List times = new ArrayList(MEAN_TIMING_STATS_CACHE_SIZE); + synchronized (cache) { + times.addAll(cache); + } + double result = 0; + int counter = 0; + Iterator iter = times.iterator(); + while (iter.hasNext()) { + Long time = iter.next(); + if (time != null) { + counter++; + result = result * ((counter - 1) / (double) counter) + + time.longValue()/(double) counter; + } + } + return (long) result; + } + + /** + * Initializes pool statistics. + */ + private void initStats() { + for (int i = 0; i < MEAN_TIMING_STATS_CACHE_SIZE; i++) { + activeTimes.add(null); + idleTimes.add(null); + waitTimes.add(null); + } + } + + + // Implement NotificationEmitter interface + + + public final void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws IllegalArgumentException { + + if (jmxNotificationSupport == null) { + throw new UnsupportedOperationException("JMX is not enabled"); + } + jmxNotificationSupport.addNotificationListener( + listener, filter, handback); + } + + + public final void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + + if (jmxNotificationSupport == null) { + throw new UnsupportedOperationException("JMX is not enabled"); + } + jmxNotificationSupport.removeNotificationListener(listener); + } + + + public final MBeanNotificationInfo[] getNotificationInfo() { + + if (jmxNotificationSupport == null) { + throw new UnsupportedOperationException("JMX is not enabled"); + } + return jmxNotificationSupport.getNotificationInfo(); + } + + + public final void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object handback) + throws ListenerNotFoundException { + + if (jmxNotificationSupport == null) { + throw new UnsupportedOperationException("JMX is not enabled"); + } + jmxNotificationSupport.removeNotificationListener( + listener, filter, handback); + } + + + // Inner classes + + /** + * The idle object evictor {@link TimerTask}. + * + * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis + */ + class Evictor extends TimerTask { + /** + * Run pool maintenance. Evict objects qualifying for eviction and then + * ensure that the minimum number of idle instances are available. + * Since the Timer that invokes Evictors is shared for all Pools but + * pools may exist in different class loaders, the Evictor ensures that + * any actions taken are under the class loader of the factory + * associated with the pool. + */ + + public void run() { + ClassLoader savedClassLoader = + Thread.currentThread().getContextClassLoader(); + try { + // Set the class loader for the factory + Thread.currentThread().setContextClassLoader( + factoryClassLoader); + + // Evict from the pool + try { + evict(); + } catch(Exception e) { + swallowException(e); + } catch(OutOfMemoryError oome) { + // Log problem but give evictor thread a chance to continue + // in case error is recoverable + oome.printStackTrace(System.err); + } + // Re-create idle instances. + try { + ensureMinIdle(); + } catch (Exception e) { + swallowException(e); + } + } finally { + // Restore the previous CCL + Thread.currentThread().setContextClassLoader(savedClassLoader); + } + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java new file mode 100644 index 00000000..1f8a309d --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java @@ -0,0 +1,420 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * Provides the implementation for the common attributes shared by the + * sub-classes. New instances of this class will be created using the defaults + * defined by the public constants. + *

+ * This class is not thread-safe. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public abstract class BaseObjectPoolConfig implements Cloneable { + + /** + * The default value for the {@code lifo} configuration attribute. + * @see GenericObjectPool#getLifo() + * @see GenericKeyedObjectPool#getLifo() + */ + public static final boolean DEFAULT_LIFO = true; + + /** + * The default value for the {@code maxWait} configuration attribute. + * @see GenericObjectPool#getMaxWaitMillis() + * @see GenericKeyedObjectPool#getMaxWaitMillis() + */ + public static final long DEFAULT_MAX_WAIT_MILLIS = -1L; + + /** + * The default value for the {@code minEvictableIdleTimeMillis} + * configuration attribute. + * @see GenericObjectPool#getMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() + */ + public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = + 1000L * 60L * 30L; + + /** + * The default value for the {@code softMinEvictableIdleTimeMillis} + * configuration attribute. + * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() + */ + public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1; + + /** + * The default value for the {@code numTestsPerEvictionRun} configuration + * attribute. + * @see GenericObjectPool#getNumTestsPerEvictionRun() + * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() + */ + public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; + + /** + * The default value for the {@code testOnBorrow} configuration attribute. + * @see GenericObjectPool#getTestOnBorrow() + * @see GenericKeyedObjectPool#getTestOnBorrow() + */ + public static final boolean DEFAULT_TEST_ON_BORROW = false; + + /** + * The default value for the {@code testOnReturn} configuration attribute. + * @see GenericObjectPool#getTestOnReturn() + * @see GenericKeyedObjectPool#getTestOnReturn() + */ + public static final boolean DEFAULT_TEST_ON_RETURN = false; + + /** + * The default value for the {@code testWhileIdle} configuration attribute. + * @see GenericObjectPool#getTestWhileIdle() + * @see GenericKeyedObjectPool#getTestWhileIdle() + */ + public static final boolean DEFAULT_TEST_WHILE_IDLE = false; + + /** + * The default value for the {@code timeBetweenEvictionRunsMillis} + * configuration attribute. + * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() + * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() + */ + public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; + + /** + * The default value for the {@code blockWhenExhausted} configuration + * attribute. + * @see GenericObjectPool#getBlockWhenExhausted() + * @see GenericKeyedObjectPool#getBlockWhenExhausted() + */ + public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true; + + /** + * The default value for enabling JMX for pools created with a configuration + * instance. + */ + public static final boolean DEFAULT_JMX_ENABLE = true; + + /** + * The default value for the prefix used to name JMX enabled pools created + * with a configuration instance. + * @see GenericObjectPool#getJmxName() + * @see GenericKeyedObjectPool#getJmxName() + */ + public static final String DEFAULT_JMX_NAME_PREFIX = "pool"; + + /** + * The default value for the {@code evictionPolicyClassName} configuration + * attribute. + * @see GenericObjectPool#getEvictionPolicyClassName() + * @see GenericKeyedObjectPool#getEvictionPolicyClassName() + */ + public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = + "org.apache.commons.pool2.impl.DefaultEvictionPolicy"; + + + private boolean lifo = DEFAULT_LIFO; + + private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS; + + private long minEvictableIdleTimeMillis = + DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + + private long softMinEvictableIdleTimeMillis = + DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + + private int numTestsPerEvictionRun = + DEFAULT_NUM_TESTS_PER_EVICTION_RUN; + + private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME; + + private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; + + private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; + + private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE; + + private long timeBetweenEvictionRunsMillis = + DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + + private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED; + + private boolean jmxEnabled = DEFAULT_JMX_ENABLE; + + private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX; + + + /** + * Get the value for the {@code lifo} configuration attribute for pools + * created with this configuration instance. + * @see GenericObjectPool#getLifo() + * @see GenericKeyedObjectPool#getLifo() + */ + public boolean getLifo() { + return lifo; + } + + /** + * Set the value for the {@code lifo} configuration attribute for pools + * created with this configuration instance. + * @see GenericObjectPool#getLifo() + * @see GenericKeyedObjectPool#getLifo() + */ + public void setLifo(boolean lifo) { + this.lifo = lifo; + } + + /** + * Get the value for the {@code maxWait} configuration attribute for pools + * created with this configuration instance. + * @see GenericObjectPool#getMaxWaitMillis() + * @see GenericKeyedObjectPool#getMaxWaitMillis() + */ + public long getMaxWaitMillis() { + return maxWaitMillis; + } + + /** + * Set the value for the {@code maxWait} configuration attribute for pools + * created with this configuration instance. + * @see GenericObjectPool#getMaxWaitMillis() + * @see GenericKeyedObjectPool#getMaxWaitMillis() + */ + public void setMaxWaitMillis(long maxWaitMillis) { + this.maxWaitMillis = maxWaitMillis; + } + + /** + * Get the value for the {@code minEvictableIdleTimeMillis} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() + */ + public long getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + /** + * Set the value for the {@code minEvictableIdleTimeMillis} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() + */ + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + /** + * Get the value for the {@code softMinEvictableIdleTimeMillis} + * configuration attribute for pools created with this configuration + * instance. + * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() + */ + public long getSoftMinEvictableIdleTimeMillis() { + return softMinEvictableIdleTimeMillis; + } + + /** + * Set the value for the {@code softMinEvictableIdleTimeMillis} + * configuration attribute for pools created with this configuration + * instance. + * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() + * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() + */ + public void setSoftMinEvictableIdleTimeMillis( + long softMinEvictableIdleTimeMillis) { + this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; + } + + /** + * Get the value for the {@code numTestsPerEvictionRun} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getNumTestsPerEvictionRun() + * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() + */ + public int getNumTestsPerEvictionRun() { + return numTestsPerEvictionRun; + } + + /** + * Set the value for the {@code numTestsPerEvictionRun} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getNumTestsPerEvictionRun() + * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() + */ + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.numTestsPerEvictionRun = numTestsPerEvictionRun; + } + + /** + * Get the value for the {@code testOnBorrow} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestOnBorrow() + * @see GenericKeyedObjectPool#getTestOnBorrow() + */ + public boolean getTestOnBorrow() { + return testOnBorrow; + } + + /** + * Set the value for the {@code testOnBorrow} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestOnBorrow() + * @see GenericKeyedObjectPool#getTestOnBorrow() + */ + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + /** + * Get the value for the {@code testOnReturn} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestOnReturn() + * @see GenericKeyedObjectPool#getTestOnReturn() + */ + public boolean getTestOnReturn() { + return testOnReturn; + } + + /** + * Set the value for the {@code testOnReturn} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestOnReturn() + * @see GenericKeyedObjectPool#getTestOnReturn() + */ + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + /** + * Get the value for the {@code testWhileIdle} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestWhileIdle() + * @see GenericKeyedObjectPool#getTestWhileIdle() + */ + public boolean getTestWhileIdle() { + return testWhileIdle; + } + + /** + * Set the value for the {@code testWhileIdle} configuration attribute for + * pools created with this configuration instance. + * @see GenericObjectPool#getTestWhileIdle() + * @see GenericKeyedObjectPool#getTestWhileIdle() + */ + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + /** + * Get the value for the {@code timeBetweenEvictionRunsMillis} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() + * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() + */ + public long getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + /** + * Set the value for the {@code timeBetweenEvictionRunsMillis} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() + * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() + */ + public void setTimeBetweenEvictionRunsMillis( + long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + /** + * Get the value for the {@code evictionPolicyClassName} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getEvictionPolicyClassName() + * @see GenericKeyedObjectPool#getEvictionPolicyClassName() + */ + public String getEvictionPolicyClassName() { + return evictionPolicyClassName; + } + + /** + * Set the value for the {@code evictionPolicyClassName} configuration + * attribute for pools created with this configuration instance. + * @see GenericObjectPool#getEvictionPolicyClassName() + * @see GenericKeyedObjectPool#getEvictionPolicyClassName() + */ + public void setEvictionPolicyClassName(String evictionPolicyClassName) { + this.evictionPolicyClassName = evictionPolicyClassName; + } + + /** + * Get the value for the {@code blockWhenExhausted} configuration attribute + * for pools created with this configuration instance. + * @see GenericObjectPool#getBlockWhenExhausted() + * @see GenericKeyedObjectPool#getBlockWhenExhausted() + */ + public boolean getBlockWhenExhausted() { + return blockWhenExhausted; + } + + /** + * Set the value for the {@code blockWhenExhausted} configuration attribute + * for pools created with this configuration instance. + * @see GenericObjectPool#getBlockWhenExhausted() + * @see GenericKeyedObjectPool#getBlockWhenExhausted() + */ + public void setBlockWhenExhausted(boolean blockWhenExhausted) { + this.blockWhenExhausted = blockWhenExhausted; + } + + /** + * Gets the value of the flag that determines if JMX will be enabled for + * pools created with this configuration instance. + */ + public boolean getJmxEnabled() { + return jmxEnabled; + } + + /** + * Sets the value of the flag that determines if JMX will be enabled for + * pools created with this configuration instance. + */ + public void setJmxEnabled(boolean jmxEnabled) { + this.jmxEnabled = jmxEnabled; + } + + /** + * Gets the value of the JMX name prefix that will be used as part of the + * name assigned to JMX enabled pools created with this configuration + * instance. + */ + public String getJmxNamePrefix() { + return jmxNamePrefix; + } + + /** + * Sets the value of the JMX name prefix that will be used as part of the + * name assigned to JMX enabled pools created with this configuration + * instance. + */ + public void setJmxNamePrefix(String jmxNamePrefix) { + this.jmxNamePrefix = jmxNamePrefix; + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java new file mode 100644 index 00000000..1b3be595 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * Provides the default implementation of {@link EvictionPolicy} used by the + * pools. Objects will be evicted if the following conditions are met: + *

    + *
  • the object has been idle longer than + * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} / + * {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()}
  • + *
  • there are more than {@link GenericObjectPool#getMinIdle()} / + * {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} idle objects in + * the pool and the object has been idle for longer than + * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} / + * {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()} + *
+ * This class is immutable and thread-safe. + * + * @param the type of objects in the pool + * + * @version $Revision: $ + * + * @since 2.0 + */ +public class DefaultEvictionPolicy implements EvictionPolicy { + + + public boolean evict(EvictionConfig config, PooledObject underTest, + int idleCount) { + + if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && + config.getMinIdle() < idleCount) || + config.getIdleEvictTime() < underTest.getIdleTimeMillis()) { + return true; + } + return false; + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java new file mode 100644 index 00000000..d238848a --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * This class is used by pool implementations to pass configuration information + * to {@link EvictionPolicy} instances. The {@link EvictionPolicy} may also have + * its own specific configuration attributes. + *

+ * This class is immutable and thread-safe. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public class EvictionConfig { + + private final long idleEvictTime; + private final long idleSoftEvictTime; + private final int minIdle; + + + public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, + int minIdle) { + if (poolIdleEvictTime > 0) { + idleEvictTime = poolIdleEvictTime; + } else { + idleEvictTime = Long.MAX_VALUE; + } + if (poolIdleSoftEvictTime > 0) { + idleSoftEvictTime = poolIdleSoftEvictTime; + } else { + idleSoftEvictTime = Long.MAX_VALUE; + } + this.minIdle = minIdle; + } + + public long getIdleEvictTime() { + return idleEvictTime; + } + + public long getIdleSoftEvictTime() { + return idleSoftEvictTime; + } + + public int getMinIdle() { + return minIdle; + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java new file mode 100644 index 00000000..f932a786 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * To provide a custom eviction policy (i.e. something other than {@link + * DefaultEvictionPolicy} for a pool, users must provide an implementation of + * this interface that provides the required eviction policy. + * + * @param the type of objects in the pool + * + * @version $Revision: $ + * + * @since 2.0 + */ +public interface EvictionPolicy { + + /** + * This method is called to test if an idle object in the pool should be + * evicted or not. + * + * @param config The pool configuration settings related to eviction + * @param underTest The pooled object being tested for eviction + * @param idleCount The current number of idle objects in the pool including + * the object under test + * @return true if the object should be evicted, otherwise + * false + */ + boolean evict(EvictionConfig config, PooledObject underTest, + int idleCount); +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java new file mode 100644 index 00000000..802a2980 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Provides a shared idle object eviction timer for all pools. This class wraps + * the standard {@link Timer} and keeps track of how many pools are using it. + * If no pools are using the timer, it is cancelled. This prevents a thread + * being left running which, in application server environments, can lead to + * memory leads and/or prevent applications from shutting down or reloading + * cleanly. + *

+ * This class has package scope to prevent its inclusion in the pool public API. + * The class declaration below should *not* be changed to public. + *

+ * This class is intended to be thread-safe. + */ +class EvictionTimer { + + /** Timer instance */ + private static Timer _timer; //@GuardedBy("this") + + /** Static usage count tracker */ + private static int _usageCount; //@GuardedBy("this") + + /** Prevent instantiation */ + private EvictionTimer() { + // Hide the default constuctor + } + + /** + * Add the specified eviction task to the timer. Tasks that are added with a + * call to this method *must* call {@link #cancel(TimerTask)} to cancel the + * task to prevent memory and/or thread leaks in application server + * environments. + * @param task Task to be scheduled + * @param delay Delay in milliseconds before task is executed + * @param period Time in milliseconds between executions + */ + static synchronized void schedule(TimerTask task, long delay, long period) { + if (null == _timer) { + // Force the new Timer thread to be created with a context class + // loader set to the class loader that loaded this library + ClassLoader ccl = AccessController.doPrivileged( + new PrivilegedGetTccl()); + try { + AccessController.doPrivileged(new PrivilegedSetTccl( + EvictionTimer.class.getClassLoader())); + _timer = new Timer("commons-pool-EvictionTimer", true); + } finally { + AccessController.doPrivileged(new PrivilegedSetTccl(ccl)); + } + } + _usageCount++; + _timer.schedule(task, delay, period); + } + + /** + * Remove the specified eviction task from the timer. + * @param task Task to be scheduled + */ + static synchronized void cancel(TimerTask task) { + task.cancel(); + _usageCount--; + if (_usageCount == 0) { + _timer.cancel(); + _timer = null; + } + } + + /** + * {@link PrivilegedAction} used to get the ContextClassLoader + */ + private static class PrivilegedGetTccl implements PrivilegedAction { + + /** + * {@inheritDoc} + */ + + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + } + + /** + * {@link PrivilegedAction} used to set the ContextClassLoader + */ + private static class PrivilegedSetTccl implements PrivilegedAction { + + /** ClassLoader */ + private final ClassLoader cl; + + /** + * Create a new PrivilegedSetTccl using the given classloader + * @param cl ClassLoader to use + */ + PrivilegedSetTccl(ClassLoader cl) { + this.cl = cl; + } + + /** + * {@inheritDoc} + */ + + public Void run() { + Thread.currentThread().setContextClassLoader(cl); + return null; + } + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java new file mode 100644 index 00000000..3d3fc309 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java @@ -0,0 +1,1380 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.NoSuchElementException; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import org.adbcj.mysql.netty.org.apache.commons.pool2.KeyedObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.KeyedPoolableObjectFactory; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; + +/** + * A configurable KeyedObjectPool implementation. + *

+ * When coupled with the appropriate {@link KeyedPoolableObjectFactory}, + * GenericKeyedObjectPool provides robust pooling functionality for + * keyed objects. A GenericKeyedObjectPool can be viewed as a map + * of sub-pools, keyed on the (unique) key values provided to the + * {@link #preparePool preparePool}, {@link #addObject addObject} or + * {@link #borrowObject borrowObject} methods. Each time a new key value is + * provided to one of these methods, a sub-new pool is created under the given + * key to be managed by the containing GenericKeyedObjectPool. + *

+ * Optionally, one may configure the pool to examine and possibly evict objects + * as they sit idle in the pool and to ensure that a minimum number of idle + * objects is maintained for each key. This is performed by an "idle object + * eviction" thread, which runs asynchronously. Caution should be used when + * configuring this optional feature. Eviction runs contend with client threads + * for access to objects in the pool, so if they run too frequently performance + * issues may result. + *

+ * Implementation note: To prevent possible deadlocks, care has been taken to + * ensure that no call to a factory method will occur within a synchronization + * block. See POOL-125 and DBCP-44 for more information. + *

+ * This class is intended to be thread-safe. + * + * @see GenericObjectPool + * + * @param The type of keys maintained by this pool. + * @param Type of element pooled in this pool. + * + * @version $Revision: 1431456 $ + * + * @since 2.0 + */ +public class GenericKeyedObjectPool extends BaseGenericObjectPool + implements KeyedObjectPool, GenericKeyedObjectPoolMBean { + + /** + * Create a new GenericKeyedObjectPool using defaults from + * {@link GenericKeyedObjectPoolConfig}. + * @param factory the factory to be used to create entries + */ + public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) { + this(factory, new GenericKeyedObjectPoolConfig()); + } + + /** + * Create a new GenericKeyedObjectPool using a specific + * configuration. + * + * @param factory the factory to be used to create entries + * @param config The configuration to use for this pool instance. The + * configuration is used by value. Subsequent changes to + * the configuration object will not be reflected in the + * pool. + */ + public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, + GenericKeyedObjectPoolConfig config) { + + super(config, ONAME_BASE, config.getJmxNamePrefix()); + + if (factory == null) { + jmxUnregister(); // tidy up + throw new IllegalArgumentException("factory may not be null"); + } + this.factory = factory; + + setConfig(config); + + startEvictor(getMinEvictableIdleTimeMillis()); + } + + /** + * Returns the limit on the number of object instances allocated by the pool + * (checked out or idle), per key. When the limit is reached, the sub-pool + * is said to be exhausted. A negative value indicates no limit. + * + * @return the limit on the number of active instances per key + * + * @see #setMaxTotalPerKey + */ + + public int getMaxTotalPerKey() { + return maxTotalPerKey; + } + + /** + * Sets the limit on the number of object instances allocated by the pool + * (checked out or idle), per key. When the limit is reached, the sub-pool + * is said to be exhausted. A negative value indicates no limit. + * + * @param maxTotalPerKey the limit on the number of active instances per key + * + * @see #getMaxTotalPerKey + */ + public void setMaxTotalPerKey(int maxTotalPerKey) { + this.maxTotalPerKey = maxTotalPerKey; + } + + + /** + * Returns the cap on the number of "idle" instances per key in the pool. + * If maxIdlePerKey is set too low on heavily loaded systems it is possible + * you will see objects being destroyed and almost immediately new objects + * being created. This is a result of the active threads momentarily + * returning objects faster than they are requesting them them, causing the + * number of idle objects to rise above maxIdlePerKey. The best value for + * maxIdlePerKey for heavily loaded system will vary but the default is a + * good starting point. + * + * @return the maximum number of "idle" instances that can be held in a + * given keyed sub-pool or a negative value if there is no limit + * + * @see #setMaxIdlePerKey + */ + + public int getMaxIdlePerKey() { + return maxIdlePerKey; + } + + /** + * Sets the cap on the number of "idle" instances per key in the pool. + * If maxIdlePerKey is set too low on heavily loaded systems it is possible + * you will see objects being destroyed and almost immediately new objects + * being created. This is a result of the active threads momentarily + * returning objects faster than they are requesting them them, causing the + * number of idle objects to rise above maxIdlePerKey. The best value for + * maxIdlePerKey for heavily loaded system will vary but the default is a + * good starting point. + * + * @param maxIdlePerKey the maximum number of "idle" instances that can be + * held in a given keyed sub-pool. Use a negative value + * for no limit + * + * @see #getMaxIdlePerKey + */ + public void setMaxIdlePerKey(int maxIdlePerKey) { + this.maxIdlePerKey = maxIdlePerKey; + } + + /** + * Sets the target for the minimum number of idle objects to maintain in + * each of the keyed sub-pools. This setting only has an effect if it is + * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than + * zero. If this is the case, an attempt is made to ensure that each + * sub-pool has the required minimum number of instances during idle object + * eviction runs. + *

+ * If the configured value of minIdlePerKey is greater than the configured + * value for maxIdlePerKey then the value of maxIdlePerKey will be used + * instead. + * + * @param minIdlePerKey The minimum size of the each keyed pool + * + * @see #getMinIdlePerKey + * @see #getMaxIdlePerKey() + * @see #setTimeBetweenEvictionRunsMillis + */ + public void setMinIdlePerKey(int minIdlePerKey) { + this.minIdlePerKey = minIdlePerKey; + } + + /** + * Returns the target for the minimum number of idle objects to maintain in + * each of the keyed sub-pools. This setting only has an effect if it is + * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than + * zero. If this is the case, an attempt is made to ensure that each + * sub-pool has the required minimum number of instances during idle object + * eviction runs. + *

+ * If the configured value of minIdlePerKey is greater than the configured + * value for maxIdlePerKey then the value of maxIdlePerKey will be used + * instead. + * + * @return minimum size of the each keyed pool + * + * @see #setTimeBetweenEvictionRunsMillis + */ + + public int getMinIdlePerKey() { + int maxIdlePerKey = getMaxIdlePerKey(); + if (this.minIdlePerKey > maxIdlePerKey) { + return maxIdlePerKey; + } else { + return minIdlePerKey; + } + } + + /** + * Sets the configuration. + * + * @param conf the new configuration to use. This is used by value. + * + * @see GenericKeyedObjectPoolConfig + */ + public void setConfig(GenericKeyedObjectPoolConfig conf) { + setLifo(conf.getLifo()); + setMaxIdlePerKey(conf.getMaxIdlePerKey()); + setMaxTotalPerKey(conf.getMaxTotalPerKey()); + setMaxTotal(conf.getMaxTotal()); + setMinIdlePerKey(conf.getMinIdlePerKey()); + setMaxWaitMillis(conf.getMaxWaitMillis()); + setBlockWhenExhausted(conf.getBlockWhenExhausted()); + setTestOnBorrow(conf.getTestOnBorrow()); + setTestOnReturn(conf.getTestOnReturn()); + setTestWhileIdle(conf.getTestWhileIdle()); + setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun()); + setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis()); + setSoftMinEvictableIdleTimeMillis( + conf.getSoftMinEvictableIdleTimeMillis()); + setTimeBetweenEvictionRunsMillis( + conf.getTimeBetweenEvictionRunsMillis()); + setEvictionPolicyClassName(conf.getEvictionPolicyClassName()); + } + + /** + * Obtain a reference to the factory used to create, destroy and validate + * the objects used by this pool. + * + * @return the factory + */ + public KeyedPoolableObjectFactory getFactory() { + return factory; + } + + /** + * Equivalent to {@link #borrowObject(Object, long) borrowObject}(key, + * {@link #getMaxWaitMillis()}). + *

+ * {@inheritDoc} + */ + + public T borrowObject(K key) throws Exception { + return borrowObject(key, getMaxWaitMillis()); + } + + /** + * Borrows an object from the sub-pool associated with the given key using + * the specified waiting time which only applies if + * {@link #getBlockWhenExhausted()} is true. + *

+ * If there is one or more idle instances available in the sub-pool + * associated with the given key, then an idle instance will be selected + * based on the value of {@link #getLifo()}, activated and returned. If + * activation fails, or {@link #getTestOnBorrow() testOnBorrow} is set to + * true and validation fails, the instance is destroyed and the + * next available instance is examined. This continues until either a valid + * instance is returned or there are no more idle instances available. + *

+ * If there are no idle instances available in the sub-pool associated with + * the given key, behavior depends on the {@link #getMaxTotalPerKey() + * maxTotalPerKey}, {@link #getMaxTotal() maxTotal}, and (if applicable) + * {@link #getBlockWhenExhausted()} and the value passed in to the + * borrowMaxWait parameter. If the number of instances checked + * out from the sub-pool under the given key is less than + * maxTotalPerKey and the total number of instances in + * circulation (under all keys) is less than maxTotal, a new + * instance is created, activated and (if applicable) validated and returned + * to the caller. + *

+ * If the associated sub-pool is exhausted (no available idle instances and + * no capacity to create new ones), this method will either block + * ({@link #getBlockWhenExhausted()} is true) or throw a + * NoSuchElementException + * ({@link #getBlockWhenExhausted()} is false). + * The length of time that this method will block when + * {@link #getBlockWhenExhausted()} is true is determined by the value + * passed in to the borrowMaxWait parameter. + *

+ * When maxTotal is set to a positive value and this method is + * invoked when at the limit with no idle instances available, an attempt is + * made to create room by clearing the oldest 15% of the elements from the + * keyed sub-pools. + *

+ * When the pool is exhausted, multiple calling threads may be + * simultaneously blocked waiting for instances to become available. A + * "fairness" algorithm has been implemented to ensure that threads receive + * available instances in request arrival order. + * + * @param key pool key + * @param borrowMaxWaitMillis The time to wait in milliseconds for an object + * to become available + * + * @return object instance from the keyed pool + * + * @throws NoSuchElementException if a keyed object instance cannot be + * returned. + */ + public T borrowObject(K key, long borrowMaxWaitMillis) throws Exception { + assertOpen(); + + PooledObject p = null; + + // Get local copy of current config so it is consistent for entire + // method execution + boolean blockWhenExhausted = getBlockWhenExhausted(); + + boolean create; + long waitTime = 0; + ObjectDeque objectDeque = register(key); + + try { + while (p == null) { + create = false; + if (blockWhenExhausted) { + p = objectDeque.getIdleObjects().pollFirst(); + if (p == null) { + create = true; + p = create(key); + } + if (p == null) { + if (borrowMaxWaitMillis < 0) { + p = objectDeque.getIdleObjects().takeFirst(); + } else { + waitTime = System.currentTimeMillis(); + p = objectDeque.getIdleObjects().pollFirst( + borrowMaxWaitMillis, TimeUnit.MILLISECONDS); + waitTime = System.currentTimeMillis() - waitTime; + } + } + if (p == null) { + throw new NoSuchElementException( + "Timeout waiting for idle object"); + } + if (!p.allocate()) { + p = null; + } + } else { + p = objectDeque.getIdleObjects().pollFirst(); + if (p == null) { + create = true; + p = create(key); + } + if (p == null) { + throw new NoSuchElementException("Pool exhausted"); + } + if (!p.allocate()) { + p = null; + } + } + + if (p != null) { + try { + factory.activateObject(key, p.getObject()); + } catch (Exception e) { + try { + destroy(key, p, true); + } catch (Exception e1) { + // Ignore - activation failure is more important + } + p = null; + if (create) { + NoSuchElementException nsee = new NoSuchElementException( + "Unable to activate object"); + nsee.initCause(e); + throw nsee; + } + } + if (p != null && getTestOnBorrow()) { + boolean validate = false; + Throwable validationThrowable = null; + try { + validate = factory.validateObject(key, p.getObject()); + } catch (Throwable t) { + PoolUtils.checkRethrow(t); + validationThrowable = t; + } + if (!validate) { + try { + destroy(key, p, true); + destroyedByBorrowValidationCount.incrementAndGet(); + } catch (Exception e) { + // Ignore - validation failure is more important + } + p = null; + if (create) { + NoSuchElementException nsee = new NoSuchElementException( + "Unable to validate object"); + nsee.initCause(validationThrowable); + throw nsee; + } + } + } + } + } + } finally { + deregister(key); + } + + updateStatsBorrow(p, waitTime); + + return p.getObject(); + } + + + /** + * Returns an object to a keyed sub-pool. + *

+ * If {@link #getMaxIdlePerKey() maxIdle} is set to a positive value and the + * number of idle instances under the given key has reached this value, the + * returning instance is destroyed. + *

+ * If {@link #getTestOnReturn() testOnReturn} == true, the returning + * instance is validated before being returned to the idle instance sub-pool + * under the given key. In this case, if validation fails, the instance is + * destroyed. + *

+ * Exceptions encountered destroying objects for any reason are swallowed + * but remain accessible via {@link #getSwallowedExceptions()}. + * + * @param key pool key + * @param obj instance to return to the keyed pool + * + * @throws IllegalStateException if an object is returned to the pool that + * was not borrowed from it or if an object is + * returned to the pool multiple times + */ + + public void returnObject(K key, T obj) { + + ObjectDeque objectDeque = poolMap.get(key); + + PooledObject p = objectDeque.getAllObjects().get(obj); + + if (p == null) { + throw new IllegalStateException( + "Returned object not currently part of this pool"); + } + + long activeTime = p.getActiveTimeMillis(); + + if (getTestOnReturn()) { + if (!factory.validateObject(key, obj)) { + try { + destroy(key, p, true); + } catch (Exception e) { + swallowException(e); + } + updateStatsReturn(activeTime); + return; + } + } + + try { + factory.passivateObject(key, obj); + } catch (Exception e1) { + swallowException(e1); + try { + destroy(key, p, true); + } catch (Exception e) { + swallowException(e); + } + updateStatsReturn(activeTime); + return; + } + + if (!p.deallocate()) { + throw new IllegalStateException( + "Object has already been retured to this pool"); + } + + int maxIdle = getMaxIdlePerKey(); + LinkedBlockingDeque> idleObjects = + objectDeque.getIdleObjects(); + + if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { + try { + destroy(key, p, true); + } catch (Exception e) { + swallowException(e); + } + } else { + if (getLifo()) { + idleObjects.addFirst(p); + } else { + idleObjects.addLast(p); + } + } + + if (hasBorrowWaiters()) { + reuseCapacity(); + } + + updateStatsReturn(activeTime); + } + + + /** + * {@inheritDoc} + *

+ * Activation of this method decrements the active count associated with + * the given keyed pool and attempts to destroy obj. + * + * @param key pool key + * @param obj instance to invalidate + * + * @throws Exception if an exception occurs destroying the + * object + * @throws IllegalStateException if obj does not belong to the pool + * under the given key + */ + + public void invalidateObject(K key, T obj) throws Exception { + + ObjectDeque objectDeque = poolMap.get(key); + + PooledObject p = objectDeque.getAllObjects().get(obj); + if (p == null) { + throw new IllegalStateException( + "Object not currently part of this pool"); + } + synchronized (p) { + if (p.getState() != PooledObjectState.INVALID) { + destroy(key, p, true); + } + } + } + + + /** + * Clears any objects sitting idle in the pool by removing them from the + * idle instance sub-pools and then invoking the configured + * PoolableObjectFactory's + * {@link KeyedPoolableObjectFactory#destroyObject(Object, Object)} method + * on each idle instance. + *

+ * Implementation notes: + *

    + *
  • This method does not destroy or effect in any way instances that are + * checked out when it is invoked.
  • + *
  • Invoking this method does not prevent objects being returned to the + * idle instance pool, even during its execution. Additional instances may + * be returned while removed items are being destroyed.
  • + *
  • Exceptions encountered destroying idle instances are swallowed but + * remain accessible via {@link #getSwallowedExceptions()}.
  • + *
+ */ + + public void clear() { + Iterator iter = poolMap.keySet().iterator(); + + while (iter.hasNext()) { + clear(iter.next()); + } + } + + + /** + * Clears the specified sub-pool, removing all pooled instances + * corresponding to the given key. Exceptions encountered + * destroying idle instances are swallowed but remain accessible via + * {@link #getSwallowedExceptions()}. + * + * @param key the key to clear + */ + + public void clear(K key) { + + ObjectDeque objectDeque = register(key); + + try { + LinkedBlockingDeque> idleObjects = + objectDeque.getIdleObjects(); + + PooledObject p = idleObjects.poll(); + + while (p != null) { + try { + destroy(key, p, true); + } catch (Exception e) { + swallowException(e); + } + p = idleObjects.poll(); + } + } finally { + deregister(key); + } + } + + + /** + * {@inheritDoc} + */ + + public int getNumActive() { + return numTotal.get() - getNumIdle(); + } + + /** + * {@inheritDoc} + */ + + public int getNumIdle() { + Iterator> iter = poolMap.values().iterator(); + int result = 0; + + while (iter.hasNext()) { + result += iter.next().getIdleObjects().size(); + } + + return result; + } + + /** + * Returns the number of instances currently borrowed from but not yet + * returned to the sub-pool corresponding to the given key. + * + * @param key the key to query + */ + + public int getNumActive(K key) { + final ObjectDeque objectDeque = poolMap.get(key); + if (objectDeque != null) { + return objectDeque.getAllObjects().size() - + objectDeque.getIdleObjects().size(); + } else { + return 0; + } + } + + /** + * Returns the number of idle instances in the sub-pool corresponding to the + * given key. + * + * @param key the key to query + */ + + public int getNumIdle(K key) { + final ObjectDeque objectDeque = poolMap.get(key); + return objectDeque != null ? objectDeque.getIdleObjects().size() : 0; + } + + + /** + * Closes the keyed object pool. Once the pool is closed, + * {@link #borrowObject(Object)} will fail with IllegalStateException, but + * {@link #returnObject(Object, Object)} and + * {@link #invalidateObject(Object, Object)} will continue to work, with + * returned objects destroyed on return. + *

+ * Destroys idle instances in the pool by invoking {@link #clear()}. + */ + + public void close() { + if (isClosed()) { + return; + } + + synchronized (closeLock) { + if (isClosed()) { + return; + } + + // Stop the evictor before the pool is closed since evict() calls + // assertOpen() + startEvictor(-1L); + + closed = true; + // This clear removes any idle objects + clear(); + + jmxUnregister(); + + // Release any threads that were waiting for an object + Iterator> iter = poolMap.values().iterator(); + while (iter.hasNext()) { + iter.next().getIdleObjects().interuptTakeWaiters(); + } + // This clear cleans up the keys now any waiting threads have been + // interrupted + clear(); + } + } + + + /** + * Clears oldest 15% of objects in pool. The method sorts the objects into + * a TreeMap and then iterates the first 15% for removal. + */ + public void clearOldest() { + + // build sorted map of idle objects + final Map, K> map = new TreeMap, K>(); + + for (K k : poolMap.keySet()) { + ObjectDeque queue = poolMap.get(k); + // Protect against possible NPE if key has been removed in another + // thread. Not worth locking the keys while this loop completes. + if (queue != null) { + final LinkedBlockingDeque> idleObjects = + queue.getIdleObjects(); + for (PooledObject p : idleObjects) { + // each item into the map using the PooledObject object as the + // key. It then gets sorted based on the idle time + map.put(p, k); + } + } + } + + // Now iterate created map and kill the first 15% plus one to account + // for zero + int itemsToRemove = ((int) (map.size() * 0.15)) + 1; + Iterator, K>> iter = + map.entrySet().iterator(); + + while (iter.hasNext() && itemsToRemove > 0) { + Map.Entry, K> entry = iter.next(); + // kind of backwards on naming. In the map, each key is the + // PooledObject because it has the ordering with the timestamp + // value. Each value that the key references is the key of the + // list it belongs to. + K key = entry.getValue(); + PooledObject p = entry.getKey(); + // Assume the destruction succeeds + boolean destroyed = true; + try { + destroyed = destroy(key, p, false); + } catch (Exception e) { + swallowException(e); + } + if (destroyed) { + itemsToRemove--; + } + } + } + + /** + * Attempt to create one new instance to serve from the most heavily + * loaded pool that can add a new instance. + * + * This method exists to ensure liveness in the pool when threads are + * parked waiting and capacity to create instances under the requested keys + * subsequently becomes available. + * + * This method is not guaranteed to create an instance and its selection + * of the most loaded pool that can create an instance may not always be + * correct, since it does not lock the pool and instances may be created, + * borrowed, returned or destroyed by other threads while it is executing. + */ + private void reuseCapacity() { + final int maxTotalPerKey = getMaxTotalPerKey(); + + // Find the most loaded pool that could take a new instance + int maxQueueLength = 0; + LinkedBlockingDeque> mostLoaded = null; + K loadedKey = null; + for (K k : poolMap.keySet()) { + final ObjectDeque deque = poolMap.get(k); + if (deque != null) { + final LinkedBlockingDeque> pool = deque.getIdleObjects(); + final int queueLength = pool.getTakeQueueLength(); + if (getNumActive(k) < maxTotalPerKey && queueLength > maxQueueLength) { + maxQueueLength = queueLength; + mostLoaded = pool; + loadedKey = k; + } + } + } + + // Attempt to add an instance to the most loaded pool + if (mostLoaded != null) { + register(loadedKey); + try { + PooledObject p = create(loadedKey); + if (p != null) { + addIdleObject(loadedKey, p); + } + } catch (Exception e) { + swallowException(e); + } finally { + deregister(loadedKey); + } + } + } + + private boolean hasBorrowWaiters() { + for (K k : poolMap.keySet()) { + final ObjectDeque deque = poolMap.get(k); + if (deque != null) { + final LinkedBlockingDeque> pool = + deque.getIdleObjects(); + if(pool.hasTakeWaiters()) { + return true; + } + } + } + return false; + } + + + /** + * {@inheritDoc} + *

+ * Successive activations of this method examine objects in keyed sub-pools + * in sequence, cycling through the keys and examining objects in + * oldest-to-youngest order within the keyed sub-pools. + */ + + public void evict() throws Exception { + assertOpen(); + + if (getNumIdle() == 0) { + return; + } + + PooledObject underTest = null; + EvictionPolicy evictionPolicy = getEvictionPolicy(); + + synchronized (evictionLock) { + EvictionConfig evictionConfig = new EvictionConfig( + getMinEvictableIdleTimeMillis(), + getSoftMinEvictableIdleTimeMillis(), + getMinIdlePerKey()); + + boolean testWhileIdle = getTestWhileIdle(); + + LinkedBlockingDeque> idleObjects = null; + + for (int i = 0, m = getNumTests(); i < m; i++) { + if(evictionIterator == null || !evictionIterator.hasNext()) { + if (evictionKeyIterator == null || + !evictionKeyIterator.hasNext()) { + List keyCopy = new ArrayList(); + Lock readLock = keyLock.readLock(); + readLock.lock(); + try { + keyCopy.addAll(poolKeyList); + } finally { + readLock.unlock(); + } + evictionKeyIterator = keyCopy.iterator(); + } + while (evictionKeyIterator.hasNext()) { + evictionKey = evictionKeyIterator.next(); + ObjectDeque objectDeque = poolMap.get(evictionKey); + if (objectDeque == null) { + continue; + } + idleObjects = objectDeque.getIdleObjects(); + + if (getLifo()) { + evictionIterator = idleObjects.descendingIterator(); + } else { + evictionIterator = idleObjects.iterator(); + } + if (evictionIterator.hasNext()) { + break; + } + evictionIterator = null; + } + } + if (evictionIterator == null) { + // Pools exhausted + return; + } + try { + underTest = evictionIterator.next(); + } catch (NoSuchElementException nsee) { + // Object was borrowed in another thread + // Don't count this as an eviction test so reduce i; + i--; + evictionIterator = null; + continue; + } + + if (!underTest.startEvictionTest()) { + // Object was borrowed in another thread + // Don't count this as an eviction test so reduce i; + i--; + continue; + } + + if (evictionPolicy.evict(evictionConfig, underTest, + poolMap.get(evictionKey).getIdleObjects().size())) { + destroy(evictionKey, underTest, true); + destroyedByEvictorCount.incrementAndGet(); + } else { + if (testWhileIdle) { + boolean active = false; + try { + factory.activateObject(evictionKey, + underTest.getObject()); + active = true; + } catch (Exception e) { + destroy(evictionKey, underTest, true); + destroyedByEvictorCount.incrementAndGet(); + } + if (active) { + if (!factory.validateObject(evictionKey, + underTest.getObject())) { + destroy(evictionKey, underTest, true); + destroyedByEvictorCount.incrementAndGet(); + } else { + try { + factory.passivateObject(evictionKey, + underTest.getObject()); + } catch (Exception e) { + destroy(evictionKey, underTest, true); + destroyedByEvictorCount.incrementAndGet(); + } + } + } + } + if (!underTest.endEvictionTest(idleObjects)) { + // TODO - May need to add code here once additional + // states are used + } + } + } + } + } + + private PooledObject create(K key) throws Exception { + int maxTotalPerKey = getMaxTotalPerKey(); // Per key + int maxTotal = getMaxTotal(); // All keys + + // Check against the overall limit + boolean loop = true; + + while (loop) { + int newNumTotal = numTotal.incrementAndGet(); + if (maxTotal > -1 && newNumTotal > maxTotal) { + numTotal.decrementAndGet(); + if (getNumIdle() == 0) { + return null; + } else { + clearOldest(); + } + } else { + loop = false; + } + } + + ObjectDeque objectDeque = poolMap.get(key); + long newCreateCount = objectDeque.getCreateCount().incrementAndGet(); + + // Check against the per key limit + if (maxTotalPerKey > -1 && newCreateCount > maxTotalPerKey || + newCreateCount > Integer.MAX_VALUE) { + numTotal.decrementAndGet(); + objectDeque.getCreateCount().decrementAndGet(); + return null; + } + + + T t = null; + try { + t = factory.makeObject(key); + } catch (Exception e) { + numTotal.decrementAndGet(); + throw e; + } + + PooledObject p = new PooledObject(t); + createdCount.incrementAndGet(); + objectDeque.getAllObjects().put(t, p); + return p; + } + + private boolean destroy(K key, PooledObject toDestroy, boolean always) + throws Exception { + + ObjectDeque objectDeque = register(key); + + try { + boolean isIdle = objectDeque.getIdleObjects().remove(toDestroy); + + if (isIdle || always) { + objectDeque.getAllObjects().remove(toDestroy.getObject()); + toDestroy.invalidate(); + + try { + factory.destroyObject(key, toDestroy.getObject()); + } finally { + objectDeque.getCreateCount().decrementAndGet(); + destroyedCount.incrementAndGet(); + numTotal.decrementAndGet(); + } + return true; + } else { + return false; + } + } finally { + deregister(key); + } + } + + + /* + * register() and deregister() must always be used as a pair. + * + * If this method returns without throwing an exception then it will never + * return null. + */ + private ObjectDeque register(K k) { + Lock lock = keyLock.readLock(); + ObjectDeque objectDeque = null; + try { + lock.lock(); + objectDeque = poolMap.get(k); + if (objectDeque == null) { + // Upgrade to write lock + lock.unlock(); + lock = keyLock.writeLock(); + lock.lock(); + objectDeque = poolMap.get(k); + if (objectDeque == null) { + objectDeque = new ObjectDeque(); + objectDeque.getNumInterested().incrementAndGet(); + // NOTE: Keys must always be added to both poolMap and + // poolKeyList at the same time while protected by + // keyLock.writeLock() + poolMap.put(k, objectDeque); + poolKeyList.add(k); + } else { + objectDeque.getNumInterested().incrementAndGet(); + } + } else { + objectDeque.getNumInterested().incrementAndGet(); + } + } finally { + lock.unlock(); + } + return objectDeque; + } + + /* + * register() and deregister() must always be used as a pair. + */ + private void deregister(K k) { + ObjectDeque objectDeque; + + objectDeque = poolMap.get(k); + long numInterested = objectDeque.getNumInterested().decrementAndGet(); + if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) { + // Potential to remove key + Lock writeLock = keyLock.writeLock(); + writeLock.lock(); + try { + if (objectDeque.getCreateCount().get() == 0 && + objectDeque.getNumInterested().get() == 0) { + // NOTE: Keys must always be removed from both poolMap and + // poolKeyList at the same time while protected by + // keyLock.writeLock() + poolMap.remove(k); + poolKeyList.remove(k); + } + } finally { + writeLock.unlock(); + } + } + } + + + void ensureMinIdle() throws Exception { + int minIdlePerKey = getMinIdlePerKey(); + if (minIdlePerKey < 1) { + return; + } + + for (K k : poolMap.keySet()) { + ensureMinIdle(k); + } + } + + private void ensureMinIdle(K key) throws Exception { + // Calculate current pool objects + ObjectDeque objectDeque = poolMap.get(key); + + // objectDeque == null is OK here. It is handled correctly by both + // methods called below. + + // this method isn't synchronized so the + // calculateDeficit is done at the beginning + // as a loop limit and a second time inside the loop + // to stop when another thread already returned the + // needed objects + int deficit = calculateDeficit(objectDeque); + + for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) { + addObject(key); + } + } + + /** + * Create an object using the {@link KeyedPoolableObjectFactory#makeObject + * factory}, passivate it, and then place it in the idle object pool. + * addObject is useful for "pre-loading" a pool with idle + * objects. + * + * @param key the key a new instance should be added to + * + * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} + * fails. + */ + + public void addObject(K key) throws Exception { + assertOpen(); + register(key); + try { + PooledObject p = create(key); + addIdleObject(key, p); + } finally { + deregister(key); + } + } + + private void addIdleObject(K key, PooledObject p) throws Exception { + + if (p != null) { + factory.passivateObject(key, p.getObject()); + LinkedBlockingDeque> idleObjects = + poolMap.get(key).getIdleObjects(); + if (getLifo()) { + idleObjects.addFirst(p); + } else { + idleObjects.addLast(p); + } + } + } + + /** + * Registers a key for pool control and ensures that + * {@link #getMinIdlePerKey()} idle instances are created. + * + * @param key - The key to register for pool control. + */ + public void preparePool(K key) throws Exception { + int minIdlePerKey = getMinIdlePerKey(); + if (minIdlePerKey < 1) { + return; + } + ensureMinIdle(key); + } + + private int getNumTests() { + int totalIdle = getNumIdle(); + int numTests = getNumTestsPerEvictionRun(); + if (numTests >= 0) { + return Math.min(numTests, totalIdle); + } + return(int)(Math.ceil(totalIdle/Math.abs((double)numTests))); + } + + private int calculateDeficit(ObjectDeque objectDeque) { + + if (objectDeque == null) { + return getMinIdlePerKey(); + } + + // Used more than once so keep a local copy so the value is consistent + int maxTotal = getMaxTotal(); + int maxTotalPerKey = getMaxTotalPerKey(); + + int objectDefecit = 0; + + // Calculate no of objects needed to be created, in order to have + // the number of pooled objects < maxTotalPerKey(); + objectDefecit = getMinIdlePerKey() - objectDeque.getIdleObjects().size(); + if (maxTotalPerKey > 0) { + int growLimit = Math.max(0, + maxTotalPerKey - objectDeque.getIdleObjects().size()); + objectDefecit = Math.min(objectDefecit, growLimit); + } + + // Take the maxTotal limit into account + if (maxTotal > 0) { + int growLimit = Math.max(0, maxTotal - getNumActive() - getNumIdle()); + objectDefecit = Math.min(objectDefecit, growLimit); + } + + return objectDefecit; + } + + + //--- JMX support ---------------------------------------------------------- + + + public Map getNumActivePerKey() { + HashMap result = new HashMap(); + + Iterator>> iter = poolMap.entrySet().iterator(); + while (iter.hasNext()) { + Entry> entry = iter.next(); + if (entry != null) { + K key = entry.getKey(); + ObjectDeque objectDequeue = entry.getValue(); + if (key != null && objectDequeue != null) { + result.put(key.toString(), Integer.valueOf( + objectDequeue.getAllObjects().size() - + objectDequeue.getIdleObjects().size())); + } + } + } + return result; + } + + /** + * Return an estimate of the number of threads currently blocked waiting for + * an object from the pool. This is intended for monitoring only, not for + * synchronization control. + */ + + public int getNumWaiters() { + int result = 0; + + if (getBlockWhenExhausted()) { + Iterator> iter = poolMap.values().iterator(); + + while (iter.hasNext()) { + // Assume no overflow + result += iter.next().getIdleObjects().getTakeQueueLength(); + } + } + + return result; + } + + /** + * Return an estimate of the number of threads currently blocked waiting for + * an object from the pool for the given key. This is intended for + * monitoring only, not for synchronization control. + */ + + public int getNumWaiters(K key) { + if (getBlockWhenExhausted()) { + final ObjectDeque objectDeque = poolMap.get(key); + if (objectDeque == null) { + return 0; + } else { + return objectDeque.getIdleObjects().getTakeQueueLength(); + } + } else { + return 0; + } + } + + + public List getKeys() { + List keyCopy = new ArrayList(); + Lock readLock = keyLock.readLock(); + readLock.lock(); + try { + keyCopy.addAll(poolKeyList); + } finally { + readLock.unlock(); + } + return keyCopy; + } + + + //--- inner classes ---------------------------------------------- + + /* + * Maintains information on the per key queue for a given key. + */ + private class ObjectDeque { + + private final LinkedBlockingDeque> idleObjects = + new LinkedBlockingDeque>(); + + /* + * Number of instances created - number destroyed. + * Invariant: createCount <= maxTotalPerKey + */ + private final AtomicInteger createCount = new AtomicInteger(0); + + /* + * The map is keyed on pooled instances. Note: pooled instances + * must be distinguishable by equals for this structure to + * work properly. + */ + private final Map> allObjects = + new ConcurrentHashMap>(); + + /* + * Number of threads with registered interest in this key. + * register(K) increments this counter and deRegister(K) decrements it. + * Invariant: empty keyed pool will not be dropped unless numInterested + * is 0. + */ + private final AtomicLong numInterested = new AtomicLong(0); + + public LinkedBlockingDeque> getIdleObjects() { + return idleObjects; + } + + public AtomicInteger getCreateCount() { + return createCount; + } + + public AtomicLong getNumInterested() { + return numInterested; + } + + public Map> getAllObjects() { + return allObjects; + } + } + + //--- configuration attributes --------------------------------------------- + private volatile int maxIdlePerKey = + GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; + private volatile int minIdlePerKey = + GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; + private volatile int maxTotalPerKey = + GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; + private final KeyedPoolableObjectFactory factory; + + + //--- internal attributes -------------------------------------------------- + + /* + * My hash of sub-pools (ObjectQueue). The list of keys must be kept + * in step with {@link #poolKeyList} using {@link #keyLock} to ensure any + * changes to the list of current keys is made in a thread-safe manner. + */ + private final Map> poolMap = + new ConcurrentHashMap>(); // @GuardedBy("keyLock") for write access (and some read access) + /* + * List of pool keys - used to control eviction order. The list of keys + * must be kept in step with {@link #poolMap} using {@link #keyLock} + * to ensure any changes to the list of current keys is made in a + * thread-safe manner. + */ + private final List poolKeyList = new ArrayList(); // @GuardedBy("keyLock") + private final ReadWriteLock keyLock = new ReentrantReadWriteLock(true); + /* + * The combined count of the currently active objects for all keys and those + * in the process of being created. Under load, it may exceed + * {@link #maxTotal} but there will never be more than {@link #maxTotal} + * created at any one time. + */ + private final AtomicInteger numTotal = new AtomicInteger(0); + private Iterator evictionKeyIterator = null; // @GuardedBy("evictionLock") + private K evictionKey = null; // @GuardedBy("evictionLock") + + // JMX specific attributes + private static final String ONAME_BASE = + "org.apache.commoms.pool2:type=GenericKeyedObjectPool,name="; +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java new file mode 100644 index 00000000..dbba0f0c --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * A simple "struct" encapsulating the configuration for a + * {@link GenericKeyedObjectPool}. + * + *

+ * This class is not thread-safe; it is only intended to be used to provide + * attributes used when creating a pool. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public class GenericKeyedObjectPoolConfig extends BaseObjectPoolConfig { + + public static final int DEFAULT_MAX_TOTAL_PER_KEY = 8; + + /** + * The default maximum number of instances under management + * (idle or checked out) across all keyed pools. + */ + public static final int DEFAULT_MAX_TOTAL = -1; + + /** + * The default minimum number of idle instances that the maintenance + * thread (if enabled) will try to maintain per key. + */ + public static final int DEFAULT_MIN_IDLE_PER_KEY = 0; + + /** + * The default maximum number of idle instances per key. + */ + public static final int DEFAULT_MAX_IDLE_PER_KEY = 8; + + + private int minIdlePerKey = DEFAULT_MIN_IDLE_PER_KEY; + + private int maxIdlePerKey = DEFAULT_MAX_IDLE_PER_KEY; + + private int maxTotalPerKey = DEFAULT_MAX_TOTAL_PER_KEY; + + private int maxTotal = DEFAULT_MAX_TOTAL; + + public GenericKeyedObjectPoolConfig() { + } + + public int getMaxTotal() { + return maxTotal; + } + + public void setMaxTotal(int maxTotal) { + this.maxTotal = maxTotal; + } + + public int getMaxTotalPerKey() { + return maxTotalPerKey; + } + + public void setMaxTotalPerKey(int maxTotalPerKey) { + this.maxTotalPerKey = maxTotalPerKey; + } + + public int getMinIdlePerKey() { + return minIdlePerKey; + } + + public void setMinIdlePerKey(int minIdlePerKey) { + this.minIdlePerKey = minIdlePerKey; + } + + public int getMaxIdlePerKey() { + return maxIdlePerKey; + } + + public void setMaxIdlePerKey(int maxIdlePerKey) { + this.maxIdlePerKey = maxIdlePerKey; + } + + + public GenericKeyedObjectPoolConfig clone() { + try { + return (GenericKeyedObjectPoolConfig) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // Can't happen + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java new file mode 100644 index 00000000..d27b73d7 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.util.List; +import java.util.Map; + +/** + * Defines the methods that will be made available via JMX. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public interface GenericKeyedObjectPoolMBean { + // Expose getters for configuration settings + /** + * See {@link GenericKeyedObjectPool#getBlockWhenExhausted()} + */ + boolean getBlockWhenExhausted(); + /** + * See {@link GenericKeyedObjectPool#getLifo()} + */ + boolean getLifo(); + /** + * See {@link GenericKeyedObjectPool#getMaxIdlePerKey()} + */ + int getMaxIdlePerKey(); + /** + * See {@link GenericKeyedObjectPool#getMaxTotal()} + */ + int getMaxTotal(); + /** + * See {@link GenericKeyedObjectPool#getMaxTotalPerKey()} + */ + int getMaxTotalPerKey(); + /** + * See {@link GenericKeyedObjectPool#getMaxWaitMillis()} + */ + long getMaxWaitMillis(); + /** + * See {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()} + */ + long getMinEvictableIdleTimeMillis(); + /** + * See {@link GenericKeyedObjectPool#getMinIdlePerKey()} + */ + int getMinIdlePerKey(); + /** + * See {@link GenericKeyedObjectPool#getNumActive()} + */ + int getNumActive(); + /** + * See {@link GenericKeyedObjectPool#getNumIdle()} + */ + int getNumIdle(); + /** + * See {@link GenericKeyedObjectPool#getNumTestsPerEvictionRun()} + */ + int getNumTestsPerEvictionRun(); + /** + * See {@link GenericKeyedObjectPool#getTestOnBorrow()} + */ + boolean getTestOnBorrow(); + /** + * See {@link GenericKeyedObjectPool#getTestOnReturn()} + */ + boolean getTestOnReturn(); + /** + * See {@link GenericKeyedObjectPool#getTestWhileIdle()} + */ + boolean getTestWhileIdle(); + /** + * See {@link GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()} + */ + long getTimeBetweenEvictionRunsMillis(); + /** + * See {@link GenericKeyedObjectPool#isClosed()} + */ + boolean isClosed(); + // Expose getters for monitoring attributes + /** + * See {@link GenericKeyedObjectPool#getNumActivePerKey()} + */ + Map getNumActivePerKey(); + /** + * See {@link GenericKeyedObjectPool#getBorrowedCount()} + */ + long getBorrowedCount(); + /** + * See {@link GenericKeyedObjectPool#getReturnedCount()} + */ + long getReturnedCount(); + /** + * See {@link GenericKeyedObjectPool#getCreatedCount()} + */ + long getCreatedCount(); + /** + * See {@link GenericKeyedObjectPool#getDestroyedCount()} + */ + long getDestroyedCount(); + /** + * See {@link GenericKeyedObjectPool#getDestroyedByEvictorCount()} + */ + long getDestroyedByEvictorCount(); + /** + * See {@link GenericKeyedObjectPool#getDestroyedByBorrowValidationCount()} + */ + long getDestroyedByBorrowValidationCount(); + /** + * See {@link GenericKeyedObjectPool#getMeanActiveTimeMillis()} + */ + long getMeanActiveTimeMillis(); + /** + * See {@link GenericKeyedObjectPool#getMeanIdleTimeMillis()} + */ + long getMeanIdleTimeMillis(); + /** + * See {@link GenericKeyedObjectPool#getMaxBorrowWaitTimeMillis()} + */ + long getMeanBorrowWaitTimeMillis(); + /** + * See {@link GenericKeyedObjectPool#getMaxBorrowWaitTimeMillis()} + */ + long getMaxBorrowWaitTimeMillis(); + /** + * See {@link GenericKeyedObjectPool#getSwallowedExceptions()} + */ + String[] getSwallowedExceptions(); + /** + * See {@link GenericKeyedObjectPool#getCreationStackTrace()} + */ + String getCreationStackTrace(); + /** + * See {@link GenericKeyedObjectPool#getNumWaiters()} + */ + int getNumWaiters(); + /** + * See {@link GenericKeyedObjectPool#getNumWaiters(Object)} + */ + int getNumWaiters(K key); + /** + * See {@link GenericKeyedObjectPool#getKeys()} + */ + List getKeys(); +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java new file mode 100644 index 00000000..25c86496 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java @@ -0,0 +1,960 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; + +/** + * A configurable {@link ObjectPool} implementation. + *

+ * When coupled with the appropriate {@link PoolableObjectFactory}, + * GenericObjectPool provides robust pooling functionality for + * arbitrary objects.

+ *

+ * Optionally, one may configure the pool to examine and possibly evict objects + * as they sit idle in the pool and to ensure that a minimum number of idle + * objects are available. This is performed by an "idle object eviction" thread, + * which runs asynchronously. Caution should be used when configuring this + * optional feature. Eviction runs contend with client threads for access to + * objects in the pool, so if they run too frequently performance issues may + * result.

+ *

+ * The pool can also be configured to detect and remove "abandoned" objects, + * i.e. objects that have been checked out of the pool but neither used nor + * returned before the configured + * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}. + * Abandoned object removal can be configured to happen when + * borrowObject is invoked and the pool is close to starvation, or + * it can be executed by the idle object evictor, or both. If pooled objects + * implement the {@link TrackedUse} interface, their last use will be queried + * using the getLastUsed method on that interface; otherwise + * abandonment is determined by how long an object has been checked out from + * the pool.

+ *

+ * Implementation note: To prevent possible deadlocks, care has been taken to + * ensure that no call to a factory method will occur within a synchronization + * block. See POOL-125 and DBCP-44 for more information.

+ *

+ * This class is intended to be thread-safe.

+ * + * @see GenericKeyedObjectPool + * + * @param Type of element pooled in this pool. + * + * @version $Revision: 1431458 $ + * + * @since 2.0 + */ +public class GenericObjectPool extends BaseGenericObjectPool + implements ObjectPool, GenericObjectPoolMBean { + + /** + * Create a new GenericObjectPool using defaults from + * {@link GenericObjectPoolConfig}. + */ + public GenericObjectPool(PoolableObjectFactory factory) { + this(factory, new GenericObjectPoolConfig()); + } + + /** + * Create a new GenericObjectPool using a specific + * configuration. + * + * @param config The configuration to use for this pool instance. The + * configuration is used by value. Subsequent changes to + * the configuration object will not be reflected in the + * pool. + */ + public GenericObjectPool(PoolableObjectFactory factory, + GenericObjectPoolConfig config) { + + super(config, ONAME_BASE, config.getJmxNamePrefix()); + + if (factory == null) { + jmxUnregister(); // tidy up + throw new IllegalArgumentException("factory may not be null"); + } + this.factory = factory; + + setConfig(config); + + startEvictor(getTimeBetweenEvictionRunsMillis()); + } + + /** + * Create a new GenericObjectPool that tracks and destroys + * objects that are checked out, but never returned to the pool. + * + * @param config The base pool configuration to use for this pool instance. + * The configuration is used by value. Subsequent changes to + * the configuration object will not be reflected in the + * pool. + * @param abandonedConfig Configuration for abandoned object identification + * and removal. The configuration is used by value. + */ + public GenericObjectPool(PoolableObjectFactory factory, + GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) { + this(factory, config); + setAbandonedConfig(abandonedConfig); + } + + /** + * Returns the cap on the number of "idle" instances in the pool. If maxIdle + * is set too low on heavily loaded systems it is possible you will see + * objects being destroyed and almost immediately new objects being created. + * This is a result of the active threads momentarily returning objects + * faster than they are requesting them them, causing the number of idle + * objects to rise above maxIdle. The best value for maxIdle for heavily + * loaded system will vary but the default is a good starting point. + * + * @return the maximum number of "idle" instances that can be held in the + * pool or a negative value if there is no limit + * + * @see #setMaxIdle + */ + + public int getMaxIdle() { + return maxIdle; + } + + /** + * Returns the cap on the number of "idle" instances in the pool. If maxIdle + * is set too low on heavily loaded systems it is possible you will see + * objects being destroyed and almost immediately new objects being created. + * This is a result of the active threads momentarily returning objects + * faster than they are requesting them them, causing the number of idle + * objects to rise above maxIdle. The best value for maxIdle for heavily + * loaded system will vary but the default is a good starting point. + * + * @param maxIdle + * The cap on the number of "idle" instances in the pool. Use a + * negative value to indicate an unlimited number of idle + * instances + * + * @see #getMaxIdle + */ + public void setMaxIdle(int maxIdle) { + this.maxIdle = maxIdle; + } + + /** + * Sets the target for the minimum number of idle objects to maintain in + * the pool. This setting only has an effect if it is positive and + * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this + * is the case, an attempt is made to ensure that the pool has the required + * minimum number of instances during idle object eviction runs. + *

+ * If the configured value of minIdle is greater than the configured value + * for maxIdle then the value of maxIdle will be used instead. + * + * @param minIdle + * The minimum number of objects. + * + * @see #getMinIdle() + * @see #getMaxIdle() + * @see #getTimeBetweenEvictionRunsMillis() + */ + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + /** + * Returns the target for the minimum number of idle objects to maintain in + * the pool. This setting only has an effect if it is positive and + * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this + * is the case, an attempt is made to ensure that the pool has the required + * minimum number of instances during idle object eviction runs. + *

+ * If the configured value of minIdle is greater than the configured value + * for maxIdle then the value of maxIdle will be used instead. + * + * @return The minimum number of objects. + * + * @see #setMinIdle(int) + * @see #setMaxIdle(int) + * @see #setTimeBetweenEvictionRunsMillis(long) + */ + + public int getMinIdle() { + int maxIdle = getMaxIdle(); + if (this.minIdle > maxIdle) { + return maxIdle; + } else { + return minIdle; + } + } + + /** + * Whether or not abandoned object removal is configured for this pool. + * + * @return true if this pool is configured to detect and remove + * abandoned objects + */ + + public boolean isAbandonedConfig() { + return abandonedConfig != null; + } + + /** + * Returns true if abandoned object removal is configured for this pool + * and removal events are to be logged. + * + * See {@link AbandonedConfig#getLogAbandoned()} + */ + + public boolean getLogAbandoned() { + return isAbandonedConfig() && abandonedConfig.getLogAbandoned(); + } + + /** + * Returns true if abandoned object removal is configured to be + * activated by borrowObject. + * + * See {@link AbandonedConfig#getRemoveAbandonedOnBorrow()} + */ + + public boolean getRemoveAbandonedOnBorrow() { + return isAbandonedConfig() && + abandonedConfig.getRemoveAbandonedOnBorrow(); + } + + /** + * Returns true if abandoned object removal is configured to be + * activated when the evictor runs. + * + * See {@link AbandonedConfig#getRemoveAbandonedOnMaintenance()} + */ + + public boolean getRemoveAbandonedOnMaintenance() { + return isAbandonedConfig() && + abandonedConfig.getRemoveAbandonedOnMaintenance(); + } + + /** + * Returns the abandoned object timeout if abandoned object removal + * is configured for this pool; Integer.MAX_VALUE otherwise. + * + * See {@link AbandonedConfig#getRemoveAbandonedTimeout()} + */ + + public int getRemoveAbandonedTimeout() { + return isAbandonedConfig() ? + abandonedConfig.getRemoveAbandonedTimeout() : + Integer.MAX_VALUE; + } + + + /** + * Sets the base pool configuration. + * + * @param conf the new configuration to use. This is used by value. + * + * @see GenericObjectPoolConfig + */ + public void setConfig(GenericObjectPoolConfig conf) { + setLifo(conf.getLifo()); + setMaxIdle(conf.getMaxIdle()); + setMinIdle(conf.getMinIdle()); + setMaxTotal(conf.getMaxTotal()); + setMaxWaitMillis(conf.getMaxWaitMillis()); + setBlockWhenExhausted(conf.getBlockWhenExhausted()); + setTestOnBorrow(conf.getTestOnBorrow()); + setTestOnReturn(conf.getTestOnReturn()); + setTestWhileIdle(conf.getTestWhileIdle()); + setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun()); + setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis()); + setTimeBetweenEvictionRunsMillis( + conf.getTimeBetweenEvictionRunsMillis()); + setSoftMinEvictableIdleTimeMillis( + conf.getSoftMinEvictableIdleTimeMillis()); + setEvictionPolicyClassName(conf.getEvictionPolicyClassName()); + } + + /** + * Sets the abandoned object removal configuration. + * + * @param abandonedConfig the new configuration to use. This is used by value. + * + * @see AbandonedConfig + */ + public void setAbandonedConfig(AbandonedConfig abandonedConfig) throws IllegalArgumentException { + this.abandonedConfig = new AbandonedConfig(); + this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned()); + this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter()); + this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow()); + this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance()); + this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout()); + } + + /** + * Obtain a reference to the factory used to create, destroy and validate + * the objects used by this pool. + * + * @return the factory + */ + public PoolableObjectFactory getFactory() { + return factory; + } + + /** + * Equivalent to {@link #borrowObject(long) + * borrowObject}({@link #getMaxWaitMillis()}). + */ + + public T borrowObject() throws Exception { + return borrowObject(getMaxWaitMillis()); + } + + /** + * Borrow an object from the pool using the specific waiting time which only + * applies if {@link #getBlockWhenExhausted()} is true. + *

+ * If there is one or more idle instance available in the pool, then an + * idle instance will be selected based on the value of {@link #getLifo()}, + * activated and returned. If activation fails, or {@link #getTestOnBorrow() + * testOnBorrow} is set to true and validation fails, the + * instance is destroyed and the next available instance is examined. This + * continues until either a valid instance is returned or there are no more + * idle instances available. + *

+ * If there are no idle instances available in the pool, behavior depends on + * the {@link #getMaxTotal() maxTotal}, (if applicable) + * {@link #getBlockWhenExhausted()} and the value passed in to the + * borrowMaxWaitMillis parameter. If the number of instances + * checked out from the pool is less than maxActive, a new + * instance is created, activated and (if applicable) validated and returned + * to the caller. + *

+ * If the pool is exhausted (no available idle instances and no capacity to + * create new ones), this method will either block (if + * {@link #getBlockWhenExhausted()} is true) or throw a + * NoSuchElementException (if + * {@link #getBlockWhenExhausted()} is false). The length of time that this + * method will block when {@link #getBlockWhenExhausted()} is true is + * determined by the value passed in to the borrowMaxWait + * parameter. + *

+ * When the pool is exhausted, multiple calling threads may be + * simultaneously blocked waiting for instances to become available. A + * "fairness" algorithm has been implemented to ensure that threads receive + * available instances in request arrival order. + * + * @param borrowMaxWaitMillis The time to wait in milliseconds for an object + * to become available + * + * @return object instance from the pool + * + * @throws NoSuchElementException if an instance cannot be returned + */ + public T borrowObject(long borrowMaxWaitMillis) throws Exception { + assertOpen(); + + if (isAbandonedConfig() && + abandonedConfig.getRemoveAbandonedOnBorrow() && + (getNumIdle() < 2) && + (getNumActive() > getMaxTotal() - 3) ) { + removeAbandoned(); + } + + PooledObject p = null; + + // Get local copy of current config so it is consistent for entire + // method execution + boolean blockWhenExhausted = getBlockWhenExhausted(); + + boolean create; + long waitTime = 0; + + while (p == null) { + create = false; + if (blockWhenExhausted) { + p = idleObjects.pollFirst(); + if (p == null) { + create = true; + p = create(); + } + if (p == null) { + if (borrowMaxWaitMillis < 0) { + p = idleObjects.takeFirst(); + } else { + waitTime = System.currentTimeMillis(); + p = idleObjects.pollFirst(borrowMaxWaitMillis, + TimeUnit.MILLISECONDS); + waitTime = System.currentTimeMillis() - waitTime; + } + } + if (p == null) { + throw new NoSuchElementException( + "Timeout waiting for idle object"); + } + if (!p.allocate()) { + p = null; + } + } else { + p = idleObjects.pollFirst(); + if (p == null) { + create = true; + p = create(); + } + if (p == null) { + throw new NoSuchElementException("Pool exhausted"); + } + if (!p.allocate()) { + p = null; + } + } + + if (p != null) { + try { + factory.activateObject(p.getObject()); + } catch (Exception e) { + try { + destroy(p); + } catch (Exception e1) { + // Ignore - activation failure is more important + } + p = null; + if (create) { + NoSuchElementException nsee = new NoSuchElementException( + "Unable to activate object"); + nsee.initCause(e); + throw nsee; + } + } + if (p != null && getTestOnBorrow()) { + boolean validate = false; + Throwable validationThrowable = null; + try { + validate = factory.validateObject(p.getObject()); + } catch (Throwable t) { + PoolUtils.checkRethrow(t); + validationThrowable = t; + } + if (!validate) { + try { + destroy(p); + destroyedByBorrowValidationCount.incrementAndGet(); + } catch (Exception e) { + // Ignore - validation failure is more important + } + p = null; + if (create) { + NoSuchElementException nsee = new NoSuchElementException( + "Unable to validate object"); + nsee.initCause(validationThrowable); + throw nsee; + } + } + } + } + } + + updateStatsBorrow(p, waitTime); + + return p.getObject(); + } + + /** + * Returns an object instance to the pool. + *

+ * If {@link #getMaxIdle() maxIdle} is set to a positive value and the + * number of idle instances has reached this value, the returning instance + * is destroyed. + *

+ * If {@link #getTestOnReturn() testOnReturn} == true, the returning + * instance is validated before being returned to the idle instance pool. In + * this case, if validation fails, the instance is destroyed. + *

+ * Exceptions encountered destroying objects for any reason are swallowed + * but remain accessible via {@link #getSwallowedExceptions()}. + * + * @param obj instance to return to the pool + */ + + public void returnObject(T obj) { + PooledObject p = allObjects.get(obj); + + if (!isAbandonedConfig()) { + if (p == null) { + throw new IllegalStateException( + "Returned object not currently part of this pool"); + } + } else { + if (p == null) { + return; // Object was abandoned and removed + } else { + // Make sure object is not being reclaimed + synchronized(p) { + final PooledObjectState state = p.getState(); + if (state == PooledObjectState.ABANDONED || + state == PooledObjectState.INVALID) { + return; + } else { + p.markReturning(); // Keep from being marked abandoned + } + } + } + } + + long activeTime = p.getActiveTimeMillis(); + + if (getTestOnReturn()) { + if (!factory.validateObject(obj)) { + try { + destroy(p); + } catch (Exception e) { + swallowException(e); + } + updateStatsReturn(activeTime); + return; + } + } + + try { + factory.passivateObject(obj); + } catch (Exception e1) { + swallowException(e1); + try { + destroy(p); + } catch (Exception e) { + swallowException(e); + } + updateStatsReturn(activeTime); + return; + } + + if (!p.deallocate()) { + throw new IllegalStateException( + "Object has already been retured to this pool or is invalid"); + } + + int maxIdle = getMaxIdle(); + if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { + try { + destroy(p); + } catch (Exception e) { + swallowException(e); + } + } else { + if (getLifo()) { + idleObjects.addFirst(p); + } else { + idleObjects.addLast(p); + } + } + updateStatsReturn(activeTime); + } + + /** + * {@inheritDoc} + *

+ * Activation of this method decrements the active count and attempts to + * destroy the instance. + * + * @throws Exception if an exception occurs destroying the + * object + * @throws IllegalStateException if obj does not belong to this pool + */ + + public void invalidateObject(T obj) throws Exception { + PooledObject p = allObjects.get(obj); + if (p == null) { + if (isAbandonedConfig()) { + return; + } else { + throw new IllegalStateException( + "Invalidated object not currently part of this pool"); + } + } + synchronized (p) { + if (p.getState() != PooledObjectState.INVALID) { + destroy(p); + } + } + } + + /** + * Clears any objects sitting idle in the pool by removing them from the + * idle instance pool and then invoking the configured + * {@link PoolableObjectFactory#destroyObject(Object)} method on each idle + * instance. + *

+ * Implementation notes: + *

    + *
  • This method does not destroy or effect in any way instances that are + * checked out of the pool when it is invoked.
  • + *
  • Invoking this method does not prevent objects being returned to the + * idle instance pool, even during its execution. Additional instances may + * be returned while removed items are being destroyed.
  • + *
  • Exceptions encountered destroying idle instances are swallowed but + * remain accessible via {@link #getSwallowedExceptions()}.
  • + *
+ */ + + public void clear() { + PooledObject p = idleObjects.poll(); + + while (p != null) { + try { + destroy(p); + } catch (Exception e) { + swallowException(e); + } + p = idleObjects.poll(); + } + } + + /** + * Returns the total number of instances currently borrowed from this pool + * but not yet returned. + */ + + public int getNumActive() { + return allObjects.size() - idleObjects.size(); + } + + + public int getNumIdle() { + return idleObjects.size(); + } + + /** + * Closes the pool. Once the pool is closed, {@link #borrowObject()} will + * fail with IllegalStateException, but {@link #returnObject(Object)} and + * {@link #invalidateObject(Object)} will continue to work, with returned + * objects destroyed on return. + *

+ * Destroys idle instances in the pool by invoking {@link #clear()}. + */ + + public void close() { + if (isClosed()) { + return; + } + + synchronized (closeLock) { + if (isClosed()) { + return; + } + + // Stop the evictor before the pool is closed since evict() calls + // assertOpen() + startEvictor(-1L); + + closed = true; + // This clear removes any idle objects + clear(); + + jmxUnregister(); + + // Release any threads that were waiting for an object + idleObjects.interuptTakeWaiters(); + } + } + + /** + * {@inheritDoc} + *

+ * Successive activations of this method examine objects in sequence, + * cycling through objects in oldest-to-youngest order. + */ + + public void evict() throws Exception { + assertOpen(); + + if (idleObjects.size() > 0) { + + PooledObject underTest = null; + EvictionPolicy evictionPolicy = getEvictionPolicy(); + + synchronized (evictionLock) { + EvictionConfig evictionConfig = new EvictionConfig( + getMinEvictableIdleTimeMillis(), + getSoftMinEvictableIdleTimeMillis(), + getMinIdle()); + + boolean testWhileIdle = getTestWhileIdle(); + + for (int i = 0, m = getNumTests(); i < m; i++) { + if (evictionIterator == null || !evictionIterator.hasNext()) { + if (getLifo()) { + evictionIterator = idleObjects.descendingIterator(); + } else { + evictionIterator = idleObjects.iterator(); + } + } + if (!evictionIterator.hasNext()) { + // Pool exhausted, nothing to do here + return; + } + + try { + underTest = evictionIterator.next(); + } catch (NoSuchElementException nsee) { + // Object was borrowed in another thread + // Don't count this as an eviction test so reduce i; + i--; + evictionIterator = null; + continue; + } + + if (!underTest.startEvictionTest()) { + // Object was borrowed in another thread + // Don't count this as an eviction test so reduce i; + i--; + continue; + } + + if (evictionPolicy.evict(evictionConfig, underTest, + idleObjects.size())) { + destroy(underTest); + destroyedByEvictorCount.incrementAndGet(); + } else { + if (testWhileIdle) { + boolean active = false; + try { + factory.activateObject(underTest.getObject()); + active = true; + } catch (Exception e) { + destroy(underTest); + destroyedByEvictorCount.incrementAndGet(); + } + if (active) { + if (!factory.validateObject(underTest.getObject())) { + destroy(underTest); + destroyedByEvictorCount.incrementAndGet(); + } else { + try { + factory.passivateObject(underTest.getObject()); + } catch (Exception e) { + destroy(underTest); + destroyedByEvictorCount.incrementAndGet(); + } + } + } + } + if (!underTest.endEvictionTest(idleObjects)) { + // TODO - May need to add code here once additional + // states are used + } + } + } + } + } + if (isAbandonedConfig() && abandonedConfig.getRemoveAbandonedOnMaintenance()) { + removeAbandoned(); + } + } + + private PooledObject create() throws Exception { + int localMaxTotal = getMaxTotal(); + long newCreateCount = createCount.incrementAndGet(); + if (localMaxTotal > -1 && newCreateCount > localMaxTotal || + newCreateCount > Integer.MAX_VALUE) { + createCount.decrementAndGet(); + return null; + } + + T t = null; + try { + t = factory.makeObject(); + } catch (Exception e) { + createCount.decrementAndGet(); + throw e; + } + + final PooledObject p; + if (isAbandonedConfig() && abandonedConfig.getLogAbandoned()) { + p = new PooledObject(t, abandonedConfig.getLogWriter()); + } else { + p = new PooledObject(t); + } + createdCount.incrementAndGet(); + allObjects.put(t, p); + return p; + } + + private void destroy(PooledObject toDestory) throws Exception { + toDestory.invalidate(); + idleObjects.remove(toDestory); + allObjects.remove(toDestory.getObject()); + try { + factory.destroyObject(toDestory.getObject()); + } finally { + destroyedCount.incrementAndGet(); + createCount.decrementAndGet(); + } + } + + + void ensureMinIdle() throws Exception { + int minIdle = getMinIdle(); + if (minIdle < 1) { + return; + } + + while (idleObjects.size() < minIdle) { + PooledObject p = create(); + if (p == null) { + // Can't create objects, no reason to think another call to + // create will work. Give up. + break; + } + if (getLifo()) { + idleObjects.addFirst(p); + } else { + idleObjects.addLast(p); + } + } + } + + /** + * Create an object, and place it into the pool. addObject() is useful for + * "pre-loading" a pool with idle objects. + */ + + public void addObject() throws Exception { + assertOpen(); + if (factory == null) { + throw new IllegalStateException( + "Cannot add objects without a factory."); + } + PooledObject p = create(); + addIdleObject(p); + } + + private void addIdleObject(PooledObject p) throws Exception { + if (p != null) { + factory.passivateObject(p.getObject()); + if (getLifo()) { + idleObjects.addFirst(p); + } else { + idleObjects.addLast(p); + } + } + } + + private int getNumTests() { + int numTestsPerEvictionRun = getNumTestsPerEvictionRun(); + if (numTestsPerEvictionRun >= 0) { + return Math.min(numTestsPerEvictionRun, idleObjects.size()); + } else { + return (int) (Math.ceil(idleObjects.size() / + Math.abs((double) numTestsPerEvictionRun))); + } + } + + /** + * Recover abandoned objects which have been checked out but + * not used since longer than the removeAbandonedTimeout. + */ + private void removeAbandoned() { + // Generate a list of abandoned objects to remove + final long now = System.currentTimeMillis(); + final long timeout = + now - (abandonedConfig.getRemoveAbandonedTimeout() * 1000L); + ArrayList> remove = new ArrayList>(); + Iterator> it = allObjects.values().iterator(); + while (it.hasNext()) { + PooledObject pooledObject = it.next(); + synchronized (pooledObject) { + if (pooledObject.getState() == PooledObjectState.ALLOCATED && + pooledObject.getLastUsed() <= timeout) { + pooledObject.markAbandoned(); + remove.add(pooledObject); + } + } + } + + // Now remove the abandoned objects + Iterator> itr = remove.iterator(); + while (itr.hasNext()) { + PooledObject pooledObject = itr.next(); + if (abandonedConfig.getLogAbandoned()) { + pooledObject.printStackTrace(); + } + try { + invalidateObject(pooledObject.getObject()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + //--- JMX support ---------------------------------------------------------- + + /** + * Return an estimate of the number of threads currently blocked waiting for + * an object from the pool. This is intended for monitoring only, not for + * synchronization control. + */ + + public int getNumWaiters() { + if (getBlockWhenExhausted()) { + return idleObjects.getTakeQueueLength(); + } else { + return 0; + } + } + + + // --- configuration attributes -------------------------------------------- + + private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; + private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; + private final PoolableObjectFactory factory; + + + // --- internal attributes ------------------------------------------------- + + /* + * All of the objects currently associated with this pool in any state. It + * excludes objects that have been destroyed. The size of + * {@link #allObjects} will always be less than or equal to {@link + * #_maxActive}. Map keys are pooled objects, values are the PooledObject + * wrappers used internally by the pool. + */ + private final Map> allObjects = + new ConcurrentHashMap>(); + /* + * The combined count of the currently created objects and those in the + * process of being created. Under load, it may exceed {@link #_maxActive} + * if multiple threads try and create a new object at the same time but + * {@link #create(boolean)} will ensure that there are never more than + * {@link #_maxActive} objects created at any one time. + */ + private final AtomicLong createCount = new AtomicLong(0); + private final LinkedBlockingDeque> idleObjects = + new LinkedBlockingDeque>(); + + // JMX specific attributes + private static final String ONAME_BASE = + "org.apache.commoms.pool2:type=GenericObjectPool,name="; + + // Additional configuration properties for abandoned object tracking + private volatile AbandonedConfig abandonedConfig = null; +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java new file mode 100644 index 00000000..58aad26d --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * A simple "struct" encapsulating the configuration for a + * {@link GenericObjectPool}. + * + *

+ * This class is not thread-safe; it is only intended to be used to provide + * attributes used when creating a pool. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public class GenericObjectPoolConfig extends BaseObjectPoolConfig { + + /** + * The default maximum number of instances under management + * (idle or checked out). + */ + public static final int DEFAULT_MAX_TOTAL = 8; + + /** + * The default cap on the number of "sleeping" instances in the pool. + */ + public static final int DEFAULT_MAX_IDLE = 8; + + /** + * The default minimum number of "sleeping" instances in the pool before + * before the evictor thread (if active) spawns new objects. + */ + public static final int DEFAULT_MIN_IDLE = 0; + + + private int maxTotal = DEFAULT_MAX_TOTAL; + + private int maxIdle = DEFAULT_MAX_IDLE; + + private int minIdle = DEFAULT_MIN_IDLE; + + public int getMaxTotal() { + return maxTotal; + } + + public void setMaxTotal(int maxTotal) { + this.maxTotal = maxTotal; + } + + + public int getMaxIdle() { + return maxIdle; + } + + public void setMaxIdle(int maxIdle) { + this.maxIdle = maxIdle; + } + + + public int getMinIdle() { + return minIdle; + } + + public void setMinIdle(int minIdle) { + this.minIdle = minIdle; + } + + + public GenericObjectPoolConfig clone() { + try { + return (GenericObjectPoolConfig) super.clone(); + } catch (CloneNotSupportedException e) { + throw new AssertionError(); // Can't happen + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java new file mode 100644 index 00000000..8607b491 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * Defines the methods that will be made available via JMX. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public interface GenericObjectPoolMBean { + // Getters for basic configuration settings + /** + * See {@link GenericObjectPool#getBlockWhenExhausted()} + */ + boolean getBlockWhenExhausted(); + /** + * See {@link GenericObjectPool#getLifo()} + */ + boolean getLifo(); + /** + * See {@link GenericObjectPool#getMaxIdle()} + */ + int getMaxIdle(); + /** + * See {@link GenericObjectPool#getMaxTotal()} + */ + int getMaxTotal(); + /** + * See {@link GenericObjectPool#getMaxWaitMillis()} + */ + long getMaxWaitMillis(); + /** + * See {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} + */ + long getMinEvictableIdleTimeMillis(); + /** + * See {@link GenericObjectPool#getMinIdle()} + */ + int getMinIdle(); + /** + * See {@link GenericObjectPool#getNumActive()} + */ + int getNumActive(); + /** + * See {@link GenericObjectPool#getNumIdle()} + */ + int getNumIdle(); + /** + * See {@link GenericObjectPool#getNumTestsPerEvictionRun()} + */ + int getNumTestsPerEvictionRun(); + /** + * See {@link GenericObjectPool#getTestOnBorrow()} + */ + boolean getTestOnBorrow(); + /** + * See {@link GenericObjectPool#getTestOnReturn()} + */ + boolean getTestOnReturn(); + /** + * See {@link GenericObjectPool#getTestWhileIdle()} + */ + boolean getTestWhileIdle(); + /** + * See {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} + */ + long getTimeBetweenEvictionRunsMillis(); + /** + * See {@link GenericObjectPool#isClosed()} + */ + boolean isClosed(); + // Getters for monitoring attributes + /** + * See {@link GenericObjectPool#getBorrowedCount()} + */ + long getBorrowedCount(); + /** + * See {@link GenericObjectPool#getReturnedCount()} + */ + long getReturnedCount(); + /** + * See {@link GenericObjectPool#getCreatedCount()} + */ + long getCreatedCount(); + /** + * See {@link GenericObjectPool#getDestroyedCount()} + */ + long getDestroyedCount(); + /** + * See {@link GenericObjectPool#getDestroyedByEvictorCount()} + */ + long getDestroyedByEvictorCount(); + /** + * See {@link GenericObjectPool#getDestroyedByBorrowValidationCount()} + */ + long getDestroyedByBorrowValidationCount(); + /** + * See {@link GenericObjectPool#getMeanActiveTimeMillis()} + */ + long getMeanActiveTimeMillis(); + /** + * See {@link GenericObjectPool#getMeanIdleTimeMillis()} + */ + long getMeanIdleTimeMillis(); + /** + * See {@link GenericObjectPool#getMeanBorrowWaitTimeMillis()} + */ + long getMeanBorrowWaitTimeMillis(); + /** + * See {@link GenericObjectPool#getMaxBorrowWaitTimeMillis()} + */ + long getMaxBorrowWaitTimeMillis(); + /** + * See {@link GenericObjectPool#getSwallowedExceptions()} + */ + String[] getSwallowedExceptions(); + /** + * See {@link GenericObjectPool#getCreationStackTrace()} + */ + String getCreationStackTrace(); + /** + * See {@link GenericObjectPool#getNumWaiters()} + */ + int getNumWaiters(); + + // Getters for abandoned object removal configuration + /** + * See {@link GenericObjectPool#isAbandonedConfig()} + */ + boolean isAbandonedConfig(); + /** + * See {@link GenericObjectPool#getLogAbandoned()} + */ + boolean getLogAbandoned(); + /** + * See {@link GenericObjectPool#getRemoveAbandonedOnBorrow()} + */ + boolean getRemoveAbandonedOnBorrow(); + /** + * See {@link GenericObjectPool#getRemoveAbandonedOnMaintenance()} + */ + boolean getRemoveAbandonedOnMaintenance(); + /** + * See {@link GenericObjectPool#getRemoveAbandonedTimeout()} + */ + int getRemoveAbandonedTimeout(); +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java new file mode 100644 index 00000000..0b752f1d --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.util.Collection; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * This sub-class was created to expose the waiting threads so that they can be + * interrupted when the pool using the queue that uses this lock is closed. The + * class is intended for internal use only. + *

+ * This class is intended to be thread-safe. + */ +class InterruptibleReentrantLock extends ReentrantLock { + + private static final long serialVersionUID = 1L; + + /** + * Interrupt the threads that are waiting on a specific condition + * + * @param condition the condition on which the threads are waiting. + */ + public void interruptWaiters(Condition condition) { + Collection threads = getWaitingThreads(condition); + for (Thread thread : threads) { + thread.interrupt(); + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java new file mode 100644 index 00000000..eb2827df --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java @@ -0,0 +1,1213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.util.AbstractQueue; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * An optionally-bounded {@linkplain java.util.concurrent.BlockingDeque blocking deque} based on + * linked nodes. + * + *

The optional capacity bound constructor argument serves as a + * way to prevent excessive expansion. The capacity, if unspecified, + * is equal to {@link Integer#MAX_VALUE}. Linked nodes are + * dynamically created upon each insertion unless this would bring the + * deque above capacity. + * + *

Most operations run in constant time (ignoring time spent + * blocking). Exceptions include {@link #remove(Object) remove}, + * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link + * #removeLastOccurrence removeLastOccurrence}, {@link #contains + * contains}, {@link #iterator iterator.remove()}, and the bulk + * operations, all of which run in linear time. + * + *

This class and its iterator implement all of the + * optional methods of the {@link Collection} and {@link + * Iterator} interfaces. + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @param the type of elements held in this collection + * + * Note: This was copied from Apache Harmony and modified to suit the needs of + * Commons Pool. + */ +class LinkedBlockingDeque extends AbstractQueue + implements java.io.Serializable { + + /* + * Implemented as a simple doubly-linked list protected by a + * single lock and using conditions to manage blocking. + * + * To implement weakly consistent iterators, it appears we need to + * keep all Nodes GC-reachable from a predecessor dequeued Node. + * That would cause two problems: + * - allow a rogue Iterator to cause unbounded memory retention + * - cause cross-generational linking of old Nodes to new Nodes if + * a Node was tenured while live, which generational GCs have a + * hard time dealing with, causing repeated major collections. + * However, only non-deleted Nodes need to be reachable from + * dequeued Nodes, and reachability does not necessarily have to + * be of the kind understood by the GC. We use the trick of + * linking a Node that has just been dequeued to itself. Such a + * self-link implicitly means to jump to "first" (for next links) + * or "last" (for prev links). + */ + + /* + * We have "diamond" multiple interface/abstract class inheritance + * here, and that introduces ambiguities. Often we want the + * BlockingDeque javadoc combined with the AbstractQueue + * implementation, so a lot of method specs are duplicated here. + */ + + private static final long serialVersionUID = -387911632671998426L; + + /** Doubly-linked list node class */ + private static final class Node { + /** + * The item, or null if this node has been removed. + */ + E item; + + /** + * One of: + * - the real predecessor Node + * - this Node, meaning the predecessor is tail + * - null, meaning there is no predecessor + */ + Node prev; + + /** + * One of: + * - the real successor Node + * - this Node, meaning the successor is head + * - null, meaning there is no successor + */ + Node next; + + Node(E x, Node p, Node n) { + item = x; + prev = p; + next = n; + } + } + + /** + * Pointer to first node. + * Invariant: (first == null && last == null) || + * (first.prev == null && first.item != null) + */ + private transient Node first; + + /** + * Pointer to last node. + * Invariant: (first == null && last == null) || + * (last.next == null && last.item != null) + */ + private transient Node last; + + /** Number of items in the deque */ + private transient int count; + + /** Maximum number of items in the deque */ + private final int capacity; + + /** Main lock guarding all access */ + private final InterruptibleReentrantLock lock = + new InterruptibleReentrantLock(); + + /** Condition for waiting takes */ + private final Condition notEmpty = lock.newCondition(); + + /** Condition for waiting puts */ + private final Condition notFull = lock.newCondition(); + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}. + */ + public LinkedBlockingDeque() { + this(Integer.MAX_VALUE); + } + + /** + * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity. + * + * @param capacity the capacity of this deque + * @throws IllegalArgumentException if {@code capacity} is less than 1 + */ + public LinkedBlockingDeque(int capacity) { + if (capacity <= 0) throw new IllegalArgumentException(); + this.capacity = capacity; + } + + /** + * Creates a {@code LinkedBlockingDeque} with a capacity of + * {@link Integer#MAX_VALUE}, initially containing the elements of + * the given collection, added in traversal order of the + * collection's iterator. + * + * @param c the collection of elements to initially contain + * @throws NullPointerException if the specified collection or any + * of its elements are null + */ + public LinkedBlockingDeque(Collection c) { + this(Integer.MAX_VALUE); + final ReentrantLock lock = this.lock; + lock.lock(); // Never contended, but necessary for visibility + try { + for (E e : c) { + if (e == null) + throw new NullPointerException(); + if (!linkLast(e)) + throw new IllegalStateException("Deque full"); + } + } finally { + lock.unlock(); + } + } + + + // Basic linking and unlinking operations, called only while holding lock + + /** + * Links e as first element, or returns false if full. + */ + private boolean linkFirst(E e) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node f = first; + Node x = new Node(e, null, f); + first = x; + if (last == null) + last = x; + else + f.prev = x; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Links e as last element, or returns false if full. + */ + private boolean linkLast(E e) { + // assert lock.isHeldByCurrentThread(); + if (count >= capacity) + return false; + Node l = last; + Node x = new Node(e, l, null); + last = x; + if (first == null) + first = x; + else + l.next = x; + ++count; + notEmpty.signal(); + return true; + } + + /** + * Removes and returns first element, or null if empty. + */ + private E unlinkFirst() { + // assert lock.isHeldByCurrentThread(); + Node f = first; + if (f == null) + return null; + Node n = f.next; + E item = f.item; + f.item = null; + f.next = f; // help GC + first = n; + if (n == null) + last = null; + else + n.prev = null; + --count; + notFull.signal(); + return item; + } + + /** + * Removes and returns last element, or null if empty. + */ + private E unlinkLast() { + // assert lock.isHeldByCurrentThread(); + Node l = last; + if (l == null) + return null; + Node p = l.prev; + E item = l.item; + l.item = null; + l.prev = l; // help GC + last = p; + if (p == null) + first = null; + else + p.next = null; + --count; + notFull.signal(); + return item; + } + + /** + * Unlinks x. + */ + private void unlink(Node x) { + // assert lock.isHeldByCurrentThread(); + Node p = x.prev; + Node n = x.next; + if (p == null) { + unlinkFirst(); + } else if (n == null) { + unlinkLast(); + } else { + p.next = n; + n.prev = p; + x.item = null; + // Don't mess with x's links. They may still be in use by + // an iterator. + --count; + notFull.signal(); + } + } + + // BlockingDeque methods + + /** + * @throws IllegalStateException + * @throws NullPointerException + */ + public void addFirst(E e) { + if (!offerFirst(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws IllegalStateException + * @throws NullPointerException + */ + public void addLast(E e) { + if (!offerLast(e)) + throw new IllegalStateException("Deque full"); + } + + /** + * @throws NullPointerException + */ + public boolean offerFirst(E e) { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkFirst(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException + */ + public boolean offerLast(E e) { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return linkLast(e); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public void putFirst(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkFirst(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public void putLast(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + while (!linkLast(e)) + notFull.await(); + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public boolean offerFirst(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkFirst(e)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public boolean offerLast(E e, long timeout, TimeUnit unit) + throws InterruptedException { + if (e == null) throw new NullPointerException(); + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + while (!linkLast(e)) { + if (nanos <= 0) + return false; + nanos = notFull.awaitNanos(nanos); + } + return true; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException + */ + public E removeFirst() { + E x = pollFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException + */ + public E removeLast() { + E x = pollLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E pollFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkFirst(); + } finally { + lock.unlock(); + } + } + + public E pollLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return unlinkLast(); + } finally { + lock.unlock(); + } + } + + public E takeFirst() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkFirst()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E takeLast() throws InterruptedException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + E x; + while ( (x = unlinkLast()) == null) + notEmpty.await(); + return x; + } finally { + lock.unlock(); + } + } + + public E pollFirst(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkFirst()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + public E pollLast(long timeout, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(timeout); + final ReentrantLock lock = this.lock; + lock.lockInterruptibly(); + try { + E x; + while ( (x = unlinkLast()) == null) { + if (nanos <= 0) + return null; + nanos = notEmpty.awaitNanos(nanos); + } + return x; + } finally { + lock.unlock(); + } + } + + /** + * @throws NoSuchElementException + */ + public E getFirst() { + E x = peekFirst(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + /** + * @throws NoSuchElementException + */ + public E getLast() { + E x = peekLast(); + if (x == null) throw new NoSuchElementException(); + return x; + } + + public E peekFirst() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (first == null) ? null : first.item; + } finally { + lock.unlock(); + } + } + + public E peekLast() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return (last == null) ? null : last.item; + } finally { + lock.unlock(); + } + } + + public boolean removeFirstOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = first; p != null; p = p.next) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + public boolean removeLastOccurrence(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = last; p != null; p = p.prev) { + if (o.equals(p.item)) { + unlink(p); + return true; + } + } + return false; + } finally { + lock.unlock(); + } + } + + // BlockingQueue methods + + /** + * Inserts the specified element at the end of this deque unless it would + * violate capacity restrictions. When using a capacity-restricted deque, + * it is generally preferable to use method {@link #offer(Object) offer}. + * + *

This method is equivalent to {@link #addLast}. + * + * @throws IllegalStateException if the element cannot be added at this + * time due to capacity restrictions + * @throws NullPointerException if the specified element is null + */ + + public boolean add(E e) { + addLast(e); + return true; + } + + /** + * @throws NullPointerException if the specified element is null + */ + + public boolean offer(E e) { + return offerLast(e); + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public void put(E e) throws InterruptedException { + putLast(e); + } + + /** + * @throws NullPointerException + * @throws InterruptedException + */ + public boolean offer(E e, long timeout, TimeUnit unit) + throws InterruptedException { + return offerLast(e, timeout, unit); + } + + /** + * Retrieves and removes the head of the queue represented by this deque. + * This method differs from {@link #poll poll} only in that it throws an + * exception if this deque is empty. + * + *

This method is equivalent to {@link #removeFirst() removeFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + + public E remove() { + return removeFirst(); + } + + + public E poll() { + return pollFirst(); + } + + public E take() throws InterruptedException { + return takeFirst(); + } + + public E poll(long timeout, TimeUnit unit) throws InterruptedException { + return pollFirst(timeout, unit); + } + + /** + * Retrieves, but does not remove, the head of the queue represented by + * this deque. This method differs from {@link #peek peek} only in that + * it throws an exception if this deque is empty. + * + *

This method is equivalent to {@link #getFirst() getFirst}. + * + * @return the head of the queue represented by this deque + * @throws NoSuchElementException if this deque is empty + */ + + public E element() { + return getFirst(); + } + + + public E peek() { + return peekFirst(); + } + + /** + * Returns the number of additional elements that this deque can ideally + * (in the absence of memory or resource constraints) accept without + * blocking. This is always equal to the initial capacity of this deque + * less the current {@code size} of this deque. + * + *

Note that you cannot always tell if an attempt to insert + * an element will succeed by inspecting {@code remainingCapacity} + * because it may be the case that another thread is about to + * insert or remove an element. + */ + public int remainingCapacity() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return capacity - count; + } finally { + lock.unlock(); + } + } + + /** + * @throws UnsupportedOperationException + * @throws ClassCastException + * @throws NullPointerException + * @throws IllegalArgumentException + */ + public int drainTo(Collection c) { + return drainTo(c, Integer.MAX_VALUE); + } + + /** + * @throws UnsupportedOperationException + * @throws ClassCastException + * @throws NullPointerException + * @throws IllegalArgumentException + */ + public int drainTo(Collection c, int maxElements) { + if (c == null) + throw new NullPointerException(); + if (c == this) + throw new IllegalArgumentException(); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + int n = Math.min(maxElements, count); + for (int i = 0; i < n; i++) { + c.add(first.item); // In this order, in case add() throws. + unlinkFirst(); + } + return n; + } finally { + lock.unlock(); + } + } + + // Stack methods + + /** + * @throws IllegalStateException + * @throws NullPointerException + */ + public void push(E e) { + addFirst(e); + } + + /** + * @throws NoSuchElementException + */ + public E pop() { + return removeFirst(); + } + + // Collection methods + + /** + * Removes the first occurrence of the specified element from this deque. + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element {@code e} such that + * {@code o.equals(e)} (if such an element exists). + * Returns {@code true} if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + *

This method is equivalent to + * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. + * + * @param o element to be removed from this deque, if present + * @return {@code true} if this deque changed as a result of the call + */ + + public boolean remove(Object o) { + return removeFirstOccurrence(o); + } + + /** + * Returns the number of elements in this deque. + * + * @return the number of elements in this deque + */ + + public int size() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return count; + } finally { + lock.unlock(); + } + } + + /** + * Returns {@code true} if this deque contains the specified element. + * More formally, returns {@code true} if and only if this deque contains + * at least one element {@code e} such that {@code o.equals(e)}. + * + * @param o object to be checked for containment in this deque + * @return {@code true} if this deque contains the specified element + */ + + public boolean contains(Object o) { + if (o == null) return false; + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node p = first; p != null; p = p.next) + if (o.equals(p.item)) + return true; + return false; + } finally { + lock.unlock(); + } + } + + /* + * TODO: Add support for more efficient bulk operations. + * + * We don't want to acquire the lock for every iteration, but we + * also want other threads a chance to interact with the + * collection, especially when count is close to capacity. + */ + +// /** +// * Adds all of the elements in the specified collection to this +// * queue. Attempts to addAll of a queue to itself result in +// * {@code IllegalArgumentException}. Further, the behavior of +// * this operation is undefined if the specified collection is +// * modified while the operation is in progress. +// * +// * @param c collection containing elements to be added to this queue +// * @return {@code true} if this queue changed as a result of the call +// * @throws ClassCastException +// * @throws NullPointerException +// * @throws IllegalArgumentException +// * @throws IllegalStateException +// * @see #add(Object) +// */ +// public boolean addAll(Collection c) { +// if (c == null) +// throw new NullPointerException(); +// if (c == this) +// throw new IllegalArgumentException(); +// final ReentrantLock lock = this.lock; +// lock.lock(); +// try { +// boolean modified = false; +// for (E e : c) +// if (linkLast(e)) +// modified = true; +// return modified; +// } finally { +// lock.unlock(); +// } +// } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence (from first to last element). + * + *

The returned array will be "safe" in that no references to it are + * maintained by this deque. (In other words, this method must allocate + * a new array). The caller is thus free to modify the returned array. + * + *

This method acts as bridge between array-based and collection-based + * APIs. + * + * @return an array containing all of the elements in this deque + */ + + public Object[] toArray() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + Object[] a = new Object[count]; + int k = 0; + for (Node p = first; p != null; p = p.next) + a[k++] = p.item; + return a; + } finally { + lock.unlock(); + } + } + + /** + * Returns an array containing all of the elements in this deque, in + * proper sequence; the runtime type of the returned array is that of + * the specified array. If the deque fits in the specified array, it + * is returned therein. Otherwise, a new array is allocated with the + * runtime type of the specified array and the size of this deque. + * + *

If this deque fits in the specified array with room to spare + * (i.e., the array has more elements than this deque), the element in + * the array immediately following the end of the deque is set to + * {@code null}. + * + *

Like the {@link #toArray()} method, this method acts as bridge between + * array-based and collection-based APIs. Further, this method allows + * precise control over the runtime type of the output array, and may, + * under certain circumstances, be used to save allocation costs. + * + *

Suppose {@code x} is a deque known to contain only strings. + * The following code can be used to dump the deque into a newly + * allocated array of {@code String}: + * + *

+     *     String[] y = x.toArray(new String[0]);
+ * + * Note that {@code toArray(new Object[0])} is identical in function to + * {@code toArray()}. + * + * @param a the array into which the elements of the deque are to + * be stored, if it is big enough; otherwise, a new array of the + * same runtime type is allocated for this purpose + * @return an array containing all of the elements in this deque + * @throws ArrayStoreException if the runtime type of the specified array + * is not a supertype of the runtime type of every element in + * this deque + * @throws NullPointerException if the specified array is null + */ + + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (a.length < count) + a = (T[])java.lang.reflect.Array.newInstance + (a.getClass().getComponentType(), count); + + int k = 0; + for (Node p = first; p != null; p = p.next) + a[k++] = (T)p.item; + if (a.length > k) + a[k] = null; + return a; + } finally { + lock.unlock(); + } + } + + + public String toString() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return super.toString(); + } finally { + lock.unlock(); + } + } + + /** + * Atomically removes all of the elements from this deque. + * The deque will be empty after this call returns. + */ + + public void clear() { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + for (Node f = first; f != null; ) { + f.item = null; + Node n = f.next; + f.prev = null; + f.next = null; + f = n; + } + first = last = null; + count = 0; + notFull.signalAll(); + } finally { + lock.unlock(); + } + } + + /** + * Returns an iterator over the elements in this deque in proper sequence. + * The elements will be returned in order from first (head) to last (tail). + * The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + * + * @return an iterator over the elements in this deque in proper sequence + */ + + public Iterator iterator() { + return new Itr(); + } + + /** + * Returns an iterator over the elements in this deque in reverse + * sequential order. The elements will be returned in order from + * last (tail) to first (head). + * The returned {@code Iterator} is a "weakly consistent" iterator that + * will never throw {@link java.util.ConcurrentModificationException + * ConcurrentModificationException}, + * and guarantees to traverse elements as they existed upon + * construction of the iterator, and may (but is not guaranteed to) + * reflect any modifications subsequent to construction. + */ + public Iterator descendingIterator() { + return new DescendingItr(); + } + + /** + * Base class for Iterators for LinkedBlockingDeque + */ + private abstract class AbstractItr implements Iterator { + /** + * The next node to return in next() + */ + Node next; + + /** + * nextItem holds on to item fields because once we claim that + * an element exists in hasNext(), we must return item read + * under lock (in advance()) even if it was in the process of + * being removed when hasNext() was called. + */ + E nextItem; + + /** + * Node returned by most recent call to next. Needed by remove. + * Reset to null if this element is deleted by a call to remove. + */ + private Node lastRet; + + abstract Node firstNode(); + abstract Node nextNode(Node n); + + AbstractItr() { + // set to initial position + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + next = firstNode(); + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + /** + * Advances next. + */ + void advance() { + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + // assert next != null; + Node s = nextNode(next); + if (s == next) { + next = firstNode(); + } else { + // Skip over removed nodes. + // May be necessary if multiple interior Nodes are removed. + while (s != null && s.item == null) + s = nextNode(s); + next = s; + } + nextItem = (next == null) ? null : next.item; + } finally { + lock.unlock(); + } + } + + + public boolean hasNext() { + return next != null; + } + + + public E next() { + if (next == null) + throw new NoSuchElementException(); + lastRet = next; + E x = nextItem; + advance(); + return x; + } + + + public void remove() { + Node n = lastRet; + if (n == null) + throw new IllegalStateException(); + lastRet = null; + final ReentrantLock lock = LinkedBlockingDeque.this.lock; + lock.lock(); + try { + if (n.item != null) + unlink(n); + } finally { + lock.unlock(); + } + } + } + + /** Forward iterator */ + private class Itr extends AbstractItr { + + Node firstNode() { return first; } + + Node nextNode(Node n) { return n.next; } + } + + /** Descending iterator */ + private class DescendingItr extends AbstractItr { + + Node firstNode() { return last; } + + Node nextNode(Node n) { return n.prev; } + } + + /** + * Save the state of this deque to a stream (that is, serialize it). + * + * @serialData The capacity (int), followed by elements (each an + * {@code Object}) in the proper order, followed by a null + * @param s the stream + */ + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + // Write out capacity and any hidden stuff + s.defaultWriteObject(); + // Write out all elements in the proper order. + for (Node p = first; p != null; p = p.next) + s.writeObject(p.item); + // Use trailing null as sentinel + s.writeObject(null); + } finally { + lock.unlock(); + } + } + + /** + * Reconstitute this deque from a stream (that is, + * deserialize it). + * @param s the stream + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + count = 0; + first = null; + last = null; + // Read in all elements and place in queue + for (;;) { + E item = (E)s.readObject(); + if (item == null) + break; + add(item); + } + } + + // Monitoring methods + + /** + * Returns true if there are threads waiting to take instances from this deque. + * See disclaimer on accuracy in {@link ReentrantLock#hasWaiters(Condition)}. + * + * @return true if there is at least one thread waiting on this deque's notEmpty condition. + */ + public boolean hasTakeWaiters() { + lock.lock(); + try { + return lock.hasWaiters(notEmpty); + } finally { + lock.unlock(); + } + } + + /** + * Returns the length of the queue of threads waiting to take instances from this deque. + * See disclaimer on accuracy in {@link ReentrantLock#getWaitQueueLength(Condition)}. + * + * @return number of threads waiting on this deque's notEmpty condition. + */ + public int getTakeQueueLength() { + lock.lock(); + try { + return lock.getWaitQueueLength(notEmpty); + } finally { + lock.unlock(); + } + } + + /** + * Interrupts the threads currently waiting to take an object from the pool. + * See disclaimer on accuracy in + * {@link ReentrantLock#getWaitingThreads(Condition)}. + */ + public void interuptTakeWaiters() { + lock.lock(); + try { + lock.interruptWaiters(notEmpty); + } finally { + lock.unlock(); + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java new file mode 100644 index 00000000..51bce9fb --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * This wrapper is used to track the additional information, such as state, for + * the pooled objects. + *

+ * This class is intended to be thread-safe. + * + * @param the type of object in the pool + * + * @version $Revision: $ + * + * @since 2.0 + */ +public class PooledObject implements Comparable> { + + private final T object; + private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid + private final long createTime = System.currentTimeMillis(); + private volatile long lastBorrowTime = createTime; + private volatile long lastReturnTime = createTime; + private final Exception createdBy; + private final PrintWriter logWriter; + + public PooledObject(T object) { + this.object = object; + createdBy = null; + logWriter = null; + } + + public PooledObject(T object, PrintWriter logWriter) { + this.object = object; + this.logWriter = logWriter; + createdBy = new AbandonedObjectException(); + } + + /** + * Obtain the underlying object that is wrapped by this instance of + * {@link PooledObject}. + */ + public T getObject() { + return object; + } + + /** + * Obtain the time (using the same basis as + * {@link System#currentTimeMillis()}) that this object was created. + */ + public long getCreateTime() { + return createTime; + } + + /** + * Obtain the time in milliseconds that this object last spent in the the + * active state (it may still be active in which case subsequent calls will + * return an increased value). + */ + public long getActiveTimeMillis() { + // Take copies to avoid threading issues + long rTime = lastReturnTime; + long bTime = lastBorrowTime; + + if (rTime > bTime) { + return rTime - bTime; + } else { + return System.currentTimeMillis() - bTime; + } + } + + /** + * Obtain the time in milliseconds that this object last spend in the the + * idle state (it may still be idle in which case subsequent calls will + * return an increased value). + */ + public long getIdleTimeMillis() { + return System.currentTimeMillis() - lastReturnTime; + } + + public long getLastBorrowTime() { + return lastBorrowTime; + } + + public long getLastReturnTime() { + return lastReturnTime; + } + + /** + * Return an estimate of the last time this object was used. If the class + * of the pooled object implements {@link TrackedUse}, what is returned is + * the maximum of {@link TrackedUse#getLastUsed()} and + * {@link #getLastBorrowTime()}; otherwise this method gives the same + * value as {@link #getLastBorrowTime()}. + * + * @return the last time this object was used + */ + public long getLastUsed() { + if (object instanceof TrackedUse) { + return Math.max(((TrackedUse) object).getLastUsed(), lastBorrowTime); + } else { + return lastBorrowTime; + } + } + + /** + * Orders instances based on idle time - i.e. the length of time since the + * instance was returned to the pool. Used by the GKOP idle object evictor. + *

+ * Note: This class has a natural ordering that is inconsistent with + * equals if distinct objects have the same identity hash code. + */ + + public int compareTo(PooledObject other) { + final long lastActiveDiff = + this.getLastReturnTime() - other.getLastReturnTime(); + if (lastActiveDiff == 0) { + // Make sure the natural ordering is broadly consistent with equals + // although this will break down if distinct objects have the same + // identity hash code. + // see java.lang.Comparable Javadocs + return System.identityHashCode(this) - System.identityHashCode(other); + } + // handle int overflow + return (int)Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE); + } + + + + public boolean equals(Object obj) { + // Overridden purely to stop FindBugs complaining because compareTo() + // has been defined. + return super.equals(obj); + } + + + public int hashCode() { + // Overridden because equals() had to be overridden (see above) + return super.hashCode(); + } + + /** + * Provides a String form of the wrapper for debug purposes. The format is + * not fixed and may change at any time. + */ + + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("Object: "); + result.append(object.toString()); + result.append(", State: "); + synchronized (this) { + result.append(state.toString()); + } + return result.toString(); + // TODO add other attributes + } + + public synchronized boolean startEvictionTest() { + if (state == PooledObjectState.IDLE) { + state = PooledObjectState.MAINTAIN_EVICTION; + return true; + } + + return false; + } + + public synchronized boolean endEvictionTest( + LinkedBlockingDeque> idleQueue) { + if (state == PooledObjectState.MAINTAIN_EVICTION) { + state = PooledObjectState.IDLE; + return true; + } else if (state == PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD) { + state = PooledObjectState.IDLE; + if (!idleQueue.offerFirst(this)) { + // TODO - Should never happen + } + } + + return false; + } + + /** + * Allocates the object. + * + * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} + */ + public synchronized boolean allocate() { + if (state == PooledObjectState.IDLE) { + state = PooledObjectState.ALLOCATED; + lastBorrowTime = System.currentTimeMillis(); + return true; + } else if (state == PooledObjectState.MAINTAIN_EVICTION) { + // TODO Allocate anyway and ignore eviction test + state = PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD; + return false; + } + // TODO if validating and testOnBorrow == true then pre-allocate for + // performance + return false; + } + + /** + * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE} + * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}. + * + * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED} + */ + public synchronized boolean deallocate() { + if (state == PooledObjectState.ALLOCATED || + state == PooledObjectState.RETURNING) { + state = PooledObjectState.IDLE; + lastReturnTime = System.currentTimeMillis(); + return true; + } + + return false; + } + + /** + * Sets the state to {@link PooledObjectState#INVALID INVALID} + */ + public synchronized void invalidate() { + state = PooledObjectState.INVALID; + } + + /** + * Prints the stack trace of the code that created this pooled object to + * the configured log writer. Does nothing of no PrintWriter was supplied + * to the constructor. + */ + public void printStackTrace() { + if (createdBy != null && logWriter != null) { + createdBy.printStackTrace(logWriter); + } + } + + /** + * Returns the state of this object. + * @return state + */ + public synchronized PooledObjectState getState() { + return state; + } + + /** + * Marks the pooled object as abandoned. + */ + public synchronized void markAbandoned() { + state = PooledObjectState.ABANDONED; + } + + /** + * Marks the object as returning to the pool. + */ + public synchronized void markReturning() { + state = PooledObjectState.RETURNING; + } + + static class AbandonedObjectException extends Exception { + + private static final long serialVersionUID = 7398692158058772916L; + + /** Date format */ + //@GuardedBy("this") + private static final SimpleDateFormat format = new SimpleDateFormat + ("'Pooled object created' yyyy-MM-dd HH:mm:ss " + + "'by the following code was never returned to the pool:'"); + + private final long _createdTime; + + public AbandonedObjectException() { + _createdTime = System.currentTimeMillis(); + } + + // Override getMessage to avoid creating objects and formatting + // dates unless the log message will actually be used. + + public String getMessage() { + String msg; + synchronized(format) { + msg = format.format(new Date(_createdTime)); + } + return msg; + } + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java new file mode 100644 index 00000000..656303b3 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * Provides the possible states that a {@link PooledObject} may be in. + * + * TODO: Find shorter names for these states without loss of meaning. + * + * @version $Revision: $ + * + * @since 2.0 + */ +public enum PooledObjectState { + /** + * In the queue, not in use. + */ + IDLE, + + /** + * In use. + */ + ALLOCATED, + + /** + * In the queue, currently being tested for possible eviction. + */ + MAINTAIN_EVICTION, + + /** + * Not in the queue, currently being tested for possible eviction. An + * attempt to borrow the object was made while being tested which removed it + * from the queue. It should be returned to the head of the queue once + * eviction testing completes. + * TODO: Consider allocating object and ignoring the result of the eviction + * test. + */ + MAINTAIN_EVICTION_RETURN_TO_HEAD, + + /** + * In the queue, currently being validated. + */ + MAINTAIN_VALIDATION, + + /** + * Not in queue, currently being validated. The object was borrowed while + * being validated and since testOnBorrow was configured, it was removed + * from the queue and pre-allocated. It should be allocated once validation + * completes. + */ + MAINTAIN_VALIDATION_PREALLOCATED, + + /** + * Not in queue, currently being validated. An attempt to borrow the object + * was made while previously being tested for eviction which removed it from + * the queue. It should be returned to the head of the queue once validation + * completes. + */ + MAINTAIN_VALIDATION_RETURN_TO_HEAD, + + /** + * Failed maintenance (e.g. eviction test or validation) and will be / has + * been destroyed + */ + INVALID, + + /** + * Deemed abandoned, to be invalidated. + */ + ABANDONED, + + /** + * Returning to the pool. + */ + RETURNING +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java new file mode 100644 index 00000000..92811d78 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.adbcj.mysql.netty.org.apache.commons.pool2.BaseObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; + +/** + * A {@link java.lang.ref.SoftReference SoftReference} based {@link ObjectPool}. + *

+ * This class is intended to be thread-safe. + * + * @param + * Type of element pooled in this pool. + * + * @version $Revision: 1361742 $ + * + * @since 2.0 + */ +public class SoftReferenceObjectPool extends BaseObjectPool { + /** + * Create a SoftReferenceObjectPool with the specified factory. + * + * @param factory + * object factory to use. + */ + public SoftReferenceObjectPool(PoolableObjectFactory factory) { + _pool = new ArrayList>(); + _factory = factory; + } + + /** + * Borrow an object from the pool. If there are no idle instances available + * in the pool, the configured factory's + * {@link PoolableObjectFactory#makeObject()} method is invoked to create a + * new instance. + *

+ * All instances are {@link PoolableObjectFactory#activateObject(Object) + * activated} and {@link PoolableObjectFactory#validateObject(Object) + * validated} before being returned by this method. If validation fails or + * an exception occurs activating or validating an idle instance, the + * failing instance is {@link PoolableObjectFactory#destroyObject(Object) + * destroyed} and another instance is retrieved from the pool, validated and + * activated. This process continues until either the pool is empty or an + * instance passes validation. If the pool is empty on activation or it does + * not contain any valid instances, the factory's makeObject + * method is used to create a new instance. If the created instance either + * raises an exception on activation or fails validation, + * NoSuchElementException is thrown. Exceptions thrown by + * MakeObject are propagated to the caller; but other than + * ThreadDeath or VirtualMachineError, exceptions + * generated by activation, validation or destroy methods are swallowed + * silently. + * + * @throws NoSuchElementException + * if a valid object cannot be provided + * @throws IllegalStateException + * if invoked on a {@link #close() closed} pool + * @throws Exception + * if an exception occurs creating a new instance + * @return a valid, activated object instance + */ + + public synchronized T borrowObject() throws Exception { + assertOpen(); + T obj = null; + boolean newlyCreated = false; + while (null == obj) { + if (_pool.isEmpty()) { + if (null == _factory) { + throw new NoSuchElementException(); + } else { + newlyCreated = true; + obj = _factory.makeObject(); + } + } else { + SoftReference ref = _pool.remove(_pool.size() - 1); + obj = ref.get(); + ref.clear(); // prevent this ref from being enqueued with + // refQueue. + } + if (null != _factory && null != obj) { + try { + _factory.activateObject(obj); + if (!_factory.validateObject(obj)) { + throw new Exception("ValidateObject failed"); + } + } catch (Throwable t) { + PoolUtils.checkRethrow(t); + try { + _factory.destroyObject(obj); + } catch (Throwable t2) { + PoolUtils.checkRethrow(t2); + // Swallowed + } finally { + obj = null; + } + if (newlyCreated) { + throw new NoSuchElementException( + "Could not create a validated object, cause: " + + t.getMessage()); + } + } + } + } + _numActive++; + return obj; + } + + /** + * Returns an instance to the pool after successful validation and + * passivation. The returning instance is destroyed if any of the following + * are true: + *

    + *
  • the pool is closed
  • + *
  • {@link PoolableObjectFactory#validateObject(Object) validation} fails + *
  • + *
  • {@link PoolableObjectFactory#passivateObject(Object) passivation} + * throws an exception
  • + *
+ * Exceptions passivating or destroying instances are silently swallowed. + * Exceptions validating instances are propagated to the client. + * + * @param obj + * instance to return to the pool + */ + + public synchronized void returnObject(T obj) throws Exception { + boolean success = !isClosed(); + if (_factory != null) { + if (!_factory.validateObject(obj)) { + success = false; + } else { + try { + _factory.passivateObject(obj); + } catch (Exception e) { + success = false; + } + } + } + + boolean shouldDestroy = !success; + _numActive--; + if (success) { + _pool.add(new SoftReference(obj, refQueue)); + } + notifyAll(); // _numActive has changed + + if (shouldDestroy && _factory != null) { + try { + _factory.destroyObject(obj); + } catch (Exception e) { + // ignored + } + } + } + + /** + * {@inheritDoc} + */ + + public synchronized void invalidateObject(T obj) throws Exception { + _numActive--; + if (_factory != null) { + _factory.destroyObject(obj); + } + notifyAll(); // _numActive has changed + } + + /** + * Create an object, and place it into the pool. addObject() is useful for + * "pre-loading" a pool with idle objects. + *

+ * Before being added to the pool, the newly created instance is + * {@link PoolableObjectFactory#validateObject(Object) validated} and + * {@link PoolableObjectFactory#passivateObject(Object) passivated}. If + * validation fails, the new instance is + * {@link PoolableObjectFactory#destroyObject(Object) destroyed}. Exceptions + * generated by the factory makeObject or + * passivate are propagated to the caller. Exceptions + * destroying instances are silently swallowed. + * + * @throws IllegalStateException + * if invoked on a {@link #close() closed} pool + * @throws Exception + * when the {@link #getFactory() factory} has a problem creating + * or passivating an object. + */ + + public synchronized void addObject() throws Exception { + assertOpen(); + if (_factory == null) { + throw new IllegalStateException( + "Cannot add objects without a factory."); + } + T obj = _factory.makeObject(); + + boolean success = true; + if (!_factory.validateObject(obj)) { + success = false; + } else { + _factory.passivateObject(obj); + } + + boolean shouldDestroy = !success; + if (success) { + _pool.add(new SoftReference(obj, refQueue)); + notifyAll(); // _numActive has changed + } + + if (shouldDestroy) { + try { + _factory.destroyObject(obj); + } catch (Exception e) { + // ignored + } + } + } + + /** + * Returns an approximation not less than the of the number of idle + * instances in the pool. + * + * @return estimated number of idle instances in the pool + */ + + public synchronized int getNumIdle() { + pruneClearedReferences(); + return _pool.size(); + } + + /** + * Return the number of instances currently borrowed from this pool. + * + * @return the number of instances currently borrowed from this pool + */ + + public synchronized int getNumActive() { + return _numActive; + } + + /** + * Clears any objects sitting idle in the pool. + */ + + public synchronized void clear() { + if (null != _factory) { + Iterator> iter = _pool.iterator(); + while (iter.hasNext()) { + try { + T obj = iter.next().get(); + if (null != obj) { + _factory.destroyObject(obj); + } + } catch (Exception e) { + // ignore error, keep destroying the rest + } + } + } + _pool.clear(); + pruneClearedReferences(); + } + + /** + * Close this pool, and free any resources associated with it. Invokes + * {@link #clear()} to destroy and remove instances in the pool. + *

+ * Calling {@link #addObject} or {@link #borrowObject} after invoking this + * method on a pool will cause them to throw an + * {@link IllegalStateException}. + */ + + public void close() { + super.close(); + clear(); + } + + /** + * If any idle objects were garbage collected, remove their + * {@link Reference} wrappers from the idle object pool. + */ + private void pruneClearedReferences() { + Reference ref; + while ((ref = refQueue.poll()) != null) { + try { + _pool.remove(ref); + } catch (UnsupportedOperationException uoe) { + // ignored + } + } + } + + /** + * Returns the {@link PoolableObjectFactory} used by this pool to create and + * manage object instances. + * + * @return the factory + */ + public synchronized PoolableObjectFactory getFactory() { + return _factory; + } + + private final List> _pool; + + private final PoolableObjectFactory _factory; + + /** + * Queue of broken references that might be able to be removed from + * _pool. This is used to help {@link #getNumIdle()} be more + * accurate with minimal performance overhead. + */ + private final ReferenceQueue refQueue = new ReferenceQueue(); + + private int _numActive = 0; // @GuardedBy("this") +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java new file mode 100644 index 00000000..5713a47b --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; + +/** + * Methods to support usage tracking for instances managed by pools configured + * to remove abandoned objects. + * + * @version $Revision:$ + */ +public interface TrackedUse { + + /** + * Get the last time this object was used in ms. + * + * @return long time in ms + */ + long getLastUsed(); +} diff --git a/mysql/pom.xml b/mysql/pom.xml index 11a1db5b..67c14fc1 100644 --- a/mysql/pom.xml +++ b/mysql/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT mysql-build diff --git a/pom.xml b/pom.xml index b790fd03..f18f8b1a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT pom ADBCJ @@ -72,14 +72,14 @@ - + org.apache.maven.plugins maven-surefire-plugin diff --git a/postgresql/codec/pom.xml b/postgresql/codec/pom.xml index 37686222..12254373 100644 --- a/postgresql/codec/pom.xml +++ b/postgresql/codec/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT postgresql-codec diff --git a/postgresql/mina/pom.xml b/postgresql/mina/pom.xml index a0374811..0bc72c5f 100644 --- a/postgresql/mina/pom.xml +++ b/postgresql/mina/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT postgresql-mina diff --git a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java index 676f9487..fbd20581 100644 --- a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java +++ b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java @@ -54,7 +54,7 @@ public ProtocolDecoder getDecoder(IoSession session) throws Exception { private final BackendMessageDecoder decoder = new BackendMessageDecoder(connection.getConnectionState()); - @Override + protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { DecoderInputStream inputStream = new DecoderInputStream(in.asInputStream()); while (true) { @@ -75,12 +75,12 @@ public ProtocolEncoder getEncoder(IoSession session) throws Exception { private final FrontendMessageEncoder encoder = new FrontendMessageEncoder(connection.getConnectionState()); - @Override + public void dispose(IoSession ioSession) throws Exception { // Do nothing. } - @Override + public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception { IoBuffer buffer = IoBuffer.allocate(4096); OutputStream out = buffer.asOutputStream(); @@ -136,7 +136,7 @@ class PgConnectFuture extends DefaultDbFuture implements IoSessionIn private boolean cancelled = false; private boolean started = false; - @Override + public synchronized void initializeSession(IoSession session, ConnectFuture future) { if (cancelled) { session.close(true); @@ -148,7 +148,7 @@ public synchronized void initializeSession(IoSession session, ConnectFuture futu IoSessionUtil.setConnection(session, connection); } - @Override + protected synchronized boolean doCancel(boolean mayInterruptIfRunning) { if (started) { logger.debug("Can't cancel, connection already started"); @@ -195,7 +195,7 @@ public void setPipeliningEnabled(boolean pipeliningEnabled) { // // ================================================================================================================ - @Override + public String toString() { return String.format("Postgresql (MINA) Connection Manager (Db: '%s', User: '%s')", getDatabase(), getUsername()); } diff --git a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManagerFactory.java b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManagerFactory.java index b9078481..5796733b 100644 --- a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManagerFactory.java +++ b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManagerFactory.java @@ -51,7 +51,6 @@ public ConnectionManager createConnectionManager(String url, String username, St } } - @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/postgresql/netty/pom.xml b/postgresql/netty/pom.xml index 22b77dc9..21144c90 100644 --- a/postgresql/netty/pom.xml +++ b/postgresql/netty/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT postgresql-netty diff --git a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java index 8126aad3..f83d3ff4 100644 --- a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java +++ b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java @@ -86,7 +86,7 @@ private ClientBootstrap initBootstrap(ChannelFactory channelFactory, String host } - @Override + public DbFuture connect() { if (isClosed()) { throw new DbException("Connection manager is closed"); @@ -95,7 +95,7 @@ public DbFuture connect() { return new PostgresqlConnectFuture(channelFuture); } - @Override + public DbFuture close(boolean immediate) throws DbException { if (isClosed()) { return closeFuture; @@ -117,19 +117,19 @@ public DbFuture close(boolean immediate) throws DbException { } } - @Override + public boolean isClosed() { synchronized (this) { return closeFuture != null; } } - @Override + public boolean isPipeliningEnabled() { return pipeliningEnabled; } - @Override + public void setPipeliningEnabled(boolean pipeliningEnabled) { this.pipeliningEnabled = pipeliningEnabled; } @@ -141,7 +141,7 @@ private class PostgresqlConnectFuture extends DefaultDbFuture getConnectFuture() { return connectFuture; } - @Override + protected boolean isConnectionClosing() { return !channel.isOpen(); } - @Override + protected void write(AbstractFrontendMessage message) { channel.write(message); } - @Override + protected void write(AbstractFrontendMessage[] messages) { channel.write(messages); } @@ -209,17 +209,17 @@ class Handler extends SimpleChannelHandler { this.protocolHandler = protocolHandler; } - @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { protocolHandler.handleMessage(connection, (AbstractBackendMessage) e.getMessage()); } - @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { protocolHandler.handleException(connection, e.getCause()); } - @Override + public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { protocolHandler.closeConnection(connection); } @@ -236,7 +236,7 @@ class Decoder extends FrameDecoder { this.decoder = new BackendMessageDecoder(state); } - @Override + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { InputStream in = new ChannelBufferInputStream(buffer); DecoderInputStream dis = new DecoderInputStream(in); diff --git a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManagerFactory.java b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManagerFactory.java index c66420e2..58f43300 100644 --- a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManagerFactory.java +++ b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManagerFactory.java @@ -38,7 +38,6 @@ public ConnectionManager createConnectionManager(String url, String username, St } } - @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/postgresql/pom.xml b/postgresql/pom.xml index df058fd4..db9afb35 100644 --- a/postgresql/pom.xml +++ b/postgresql/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT postgresql-build diff --git a/tck/pom.xml b/tck/pom.xml index f06f548f..1bac79ff 100644 --- a/tck/pom.xml +++ b/tck/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 0.2-SNAPSHOT + 1.0-tb-SNAPSHOT adbcj-tck From e6c4bfdf012e2002371820c682e2771ddb95bae7 Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 26 Jun 2013 18:05:09 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=94=AF=E6=8C=81,=E5=A2=9E=E5=8A=A0taobao=20style=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/src/main/java/org/adbcj/Row.java | 4 +- api/src/main/java/org/adbcj/Value.java | 188 +++-- .../java/org/adbcj/support/DefaultValue.java | 216 ++--- .../adbcj/mysql/codec/MySqlClientDecoder.java | 754 ++++++++++-------- .../tdhs/config/AtomAlreadyInitException.java | 22 + .../taobao/tdhs/config/AtomDbStatusEnum.java | 64 ++ .../taobao/tdhs/config/AtomDbTypeEnum.java | 53 ++ .../tdhs/config/AtomIllegalException.java | 26 + .../tdhs/config/AtomInitialException.java | 26 + .../taobao/tdhs/config/ConfigDataHandler.java | 55 ++ .../tdhs/config/ConfigDataHandlerFactory.java | 109 +++ .../tdhs/config/ConfigDataListener.java | 19 + .../com/taobao/tdhs/config/DbConfManager.java | 40 + .../taobao/tdhs/config/DbPasswdManager.java | 21 + .../DefaultConfigDataHandlerFactory.java | 251 ++++++ .../com/taobao/tdhs/config/DiamondConfig.java | 80 ++ .../tdhs/config/DiamondConfigDataHandler.java | 122 +++ .../tdhs/config/DiamondDbConfManager.java | 94 +++ .../tdhs/config/DiamondDbPasswdManager.java | 62 ++ .../config/SecureIdentityLoginModule.java | 113 +++ .../taobao/tdhs/config/TAtomConfParser.java | 189 +++++ .../taobao/tdhs/config/TAtomConstants.java | 125 +++ .../com/taobao/tdhs/config/TAtomDsConfDO.java | 294 +++++++ .../taobao/tdhs/config/TAtomDsConfHandle.java | 318 ++++++++ .../com/taobao/tdhs/config/TDDLConstant.java | 13 + .../tdhs/config/group/ConfigManager.java | 152 ++++ .../tdhs/config/group/GroupExtraConfig.java | 131 +++ .../com/taobao/tdhs/config/group/Weight.java | 155 ++++ .../tdhs/config/group/WeightSelector.java | 120 +++ .../netty/AtomMysqlConnectionManager.java | 88 ++ .../netty/GroupMysqlConnectionManager.java | 108 +++ .../netty/MySqlConnectionManagerFactory.java | 15 +- .../mysql/netty/MysqlConnectionManager.java | 266 +++--- .../org/adbcj/mysql/netty/TAtomConstants.java | 125 +++ .../mysql/netty/WrappedMysqlConnection.java | 105 ++- .../netty/WrappedMysqlConnectionManager.java | 96 +++ .../WrappedMysqlConnectionManagerFactory.java | 54 ++ ...WrappedMysqlConnectionPoolableFactory.java | 39 + .../WrappedMysqlConnectionPoolableObject.java | 38 + .../pool2/impl/BaseObjectPoolConfig.java | 103 ++- mysql/netty/src/test/java/Test.java | 2 +- 41 files changed, 4121 insertions(+), 734 deletions(-) create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java create mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java diff --git a/api/src/main/java/org/adbcj/Row.java b/api/src/main/java/org/adbcj/Row.java index 94c28346..e6ed46c3 100644 --- a/api/src/main/java/org/adbcj/Row.java +++ b/api/src/main/java/org/adbcj/Row.java @@ -21,5 +21,7 @@ public interface Row extends Map { ResultSet getResultSet(); - + + Value[] getValues(); + } diff --git a/api/src/main/java/org/adbcj/Value.java b/api/src/main/java/org/adbcj/Value.java index 24c8cdc0..8643ba6c 100644 --- a/api/src/main/java/org/adbcj/Value.java +++ b/api/src/main/java/org/adbcj/Value.java @@ -20,95 +20,125 @@ import java.util.Date; /** - * Holds a field value. The {@code Value} methods attempt to convert the field value to Java types. - * + * Holds a field value. The {@code Value} methods attempt to convert the field + * value to Java types. + * * @author Mike Heath */ public interface Value { - /** - * Return the field type for this value. - * - * @return the field type for this value. - */ - Field getField(); + /** + * Return the field type for this value. + * + * @return the field type for this value. + */ + Field getField(); + + /** + * The value as a {@code BigDecimal} with full precision . If the value is + * {@code null}, returns {@code null}. + * + * @return the value as a {@link BigDecimal} or {@code null} if the value is + * {@code null}. + * @throws NumberFormatException if the value is not a valid representation + * of a {@code BigDecimal}. + */ + BigDecimal getBigDecimal(); + + /** + * Returns the value as a {@code boolean}. If the value is {@code null}, + * returns false. If the value is a numeric type, return {@code true} if the + * the value is not 0. Otherwise, returns {@true} if the value as a + * {@code String} is {@code "true"}. + * + * @return the value as a boolean. + */ + boolean getBoolean(); + + /** + * Returns the value as a {@link Date}. If the value is {@code null}, + * returns {@code null}. + * + * @return the value as a {@link Date} or {@code null} if the value is + * {@code null}. + * @throws DbException if the value is not a date type + */ + Date getDate(); + + /** + * Returns the value as a {@code double}. If the value is {@code null}, + * returns 0. + * + * @return the value as a {@code double} or 0 if the value is {@code null}. + * @throws NumberFormatException if the value is not a valid representation + * of a {@code double}. + */ + double getDouble(); - /** - * The value as a {@code BigDecimal} with full precision . If the value is {@code null}, returns {@code null}. - * - * @return the value as a {@link BigDecimal} or {@code null} if the value is {@code null}. - * @throws NumberFormatException if the value is not a valid representation of a {@code BigDecimal}. - */ - BigDecimal getBigDecimal(); + /** + * Returns the value as a {@code float}. If the value is {@code null}, + * returns 0. + * + * @return the value as a {@code float} or 0 if the value is {@code null}. + * @throws NumberFormatException if the value is not a valid representation + * of a {@code float}. + */ + float getFloat(); - /** - * Returns the value as a {@code boolean}. If the value is {@code null}, returns false. If the value is a numeric - * type, return {@code true} if the the value is not 0. Otherwise, returns {@true} if the value as a - * {@code String} is {@code "true"}. - * - * @return the value as a boolean. - */ - boolean getBoolean(); + /** + * Returns the value as a {@code int}. If the value is {@code null}, returns + * 0. + * + * @return the value as a {@code double} or 0 if the value is {@code null}. + * @throws NumberFormatException if the value is not a valid representation + * of a {@code double}. + */ + int getInt(); - /** - * Returns the value as a {@link Date}. If the value is {@code null}, returns {@code null}. - * - * @return the value as a {@link Date} or {@code null} if the value is {@code null}. - * @throws DbException if the value is not a date type - */ - Date getDate(); + /** + * Returns the value as a {@code long}. If the value is {@code null}, + * returns 0. + * + * @return the value as a {@code long} or 0 if the value is {@code null}. + * @throws NumberFormatException if the value is not a valid representation + * of a {@code long}. + */ + long getLong(); - /** - * Returns the value as a {@code double}. If the value is {@code null}, returns 0. - * - * @return the value as a {@code double} or 0 if the value is {@code null}. - * @throws NumberFormatException if the value is not a valid representation of a {@code double}. - */ - double getDouble(); - - /** - * Returns the value as a {@code float}. If the value is {@code null}, returns 0. - * - * @return the value as a {@code float} or 0 if the value is {@code null}. - * @throws NumberFormatException if the value is not a valid representation of a {@code float}. - */ - float getFloat(); + /** + * Returns the value as a {@link String}. If the value is {@code null}, + * returns {@code null}. + * + * @return the value as a {@link String} or {@code null} if the value is + * {@code null}. + */ + String getString(); - /** - * Returns the value as a {@code int}. If the value is {@code null}, returns 0. - * - * @return the value as a {@code double} or 0 if the value is {@code null}. - * @throws NumberFormatException if the value is not a valid representation of a {@code double}. - */ - int getInt(); - - /** - * Returns the value as a {@code long}. If the value is {@code null}, returns 0. - * - * @return the value as a {@code long} or 0 if the value is {@code null}. - * @throws NumberFormatException if the value is not a valid representation of a {@code long}. - */ - long getLong(); + /** + * Returns the value in its native type. If the value is {@code null}, + * return {@code null}. + * + * @return the avleu in its native or {@code null} if the value is + * {@code null}. + */ + Object getValue(); - /** - * Returns the value as a {@link String}. If the value is {@code null}, returns {@code null}. - * - * @return the value as a {@link String} or {@code null} if the value is {@code null}. - */ - String getString(); + /** + * Returns the value in its native type. If the value is {@code null}, + * return {@code null}. + * + * @return the avleu in its native or {@code null} if the value is + * {@code null}. + */ + short getShort(); - /** - * Returns the value in its native type. If the value is {@code null}, return {@code null}. - * - * @return the avleu in its native or {@code null} if the value is {@code null}. - */ - Object getValue(); + /** + * Returns {@code true} if the value is {@code null}, {@code false} + * otherwise. + * + * @return {@code true} if the value is {@code null}, {@code false} + * otherwise. + */ + boolean isNull(); - /** - * Returns {@code true} if the value is {@code null}, {@code false} otherwise. - * - * @return {@code true} if the value is {@code null}, {@code false} otherwise. - */ - boolean isNull(); - } diff --git a/api/src/main/java/org/adbcj/support/DefaultValue.java b/api/src/main/java/org/adbcj/support/DefaultValue.java index 07aac75d..8b95551f 100644 --- a/api/src/main/java/org/adbcj/support/DefaultValue.java +++ b/api/src/main/java/org/adbcj/support/DefaultValue.java @@ -25,108 +25,118 @@ public class DefaultValue implements Value { - private final Field field; - private final Object value; - - public DefaultValue(Field field, Object value) { - this.field = field; - this.value = value; - } - - public Field getField() { - return field; - } - - public BigDecimal getBigDecimal() { - if (value == null) { - return null; - } - if (value instanceof BigDecimal) { - return (BigDecimal)value; - } - return new BigDecimal(value.toString()); - } - - public boolean getBoolean() { - if (value == null) { - return false; - } - if (value instanceof Boolean) { - return ((Boolean)value).booleanValue(); - } - if (value instanceof Number) { - return getInt() != 0; - } - return Boolean.valueOf(value.toString()); - } - - public Date getDate() { - if (value == null) { - return null; - } - if (value instanceof Date) { - return (Date)value; - } - throw new DbException(String.format("%s is not a date", value.toString())); - } - - public double getDouble() { - if (value == null) { - return 0d; - } - if (value instanceof Number) { - return ((Number)value).doubleValue(); - } - return Double.valueOf(value.toString()); - } - - public float getFloat() { - if (value == null) { - return 0f; - } - if (value instanceof Number) { - return ((Number)value).floatValue(); - } - return Float.valueOf(value.toString()); - } - - public int getInt() { - if (value == null) { - return 0; - } - if (value instanceof Number) { - return ((Number)value).intValue(); - } - return Integer.valueOf(value.toString()); - } - - public long getLong() { - if (value == null) { - return 0L; - } - if (value instanceof Number) { - return ((Number)value).longValue(); - } - return Long.valueOf(value.toString()); - } - - public String getString() { - return value == null ? null : value.toString(); - } - - public Object getValue() { - return value; - } - - public boolean isNull() { - return value == null; - } - - @Override - public String toString() { - // TODO Add padding if a display width is specified in the Field - String s = getString(); - return s == null ? "null" : s; - } + private final Field field; + private final Object value; + + public DefaultValue(Field field, Object value){ + this.field = field; + this.value = value; + } + + public Field getField() { + return field; + } + + public BigDecimal getBigDecimal() { + if (value == null) { + return null; + } + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + return new BigDecimal(value.toString()); + } + + public boolean getBoolean() { + if (value == null) { + return false; + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue(); + } + if (value instanceof Number) { + return getInt() != 0; + } + return Boolean.valueOf(value.toString()); + } + + public Date getDate() { + if (value == null) { + return null; + } + if (value instanceof Date) { + return (Date) value; + } + throw new DbException(String.format("%s is not a date", value.toString())); + } + + public double getDouble() { + if (value == null) { + return 0d; + } + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + return Double.valueOf(value.toString()); + } + + public float getFloat() { + if (value == null) { + return 0f; + } + if (value instanceof Number) { + return ((Number) value).floatValue(); + } + return Float.valueOf(value.toString()); + } + + public int getInt() { + if (value == null) { + return 0; + } + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return Integer.valueOf(value.toString()); + } + + public short getShort() { + if (value == null) { + return 0; + } + if (value instanceof Number) { + return ((Number) value).shortValue(); + } + return Short.valueOf(value.toString()); + } + + public long getLong() { + if (value == null) { + return 0L; + } + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return Long.valueOf(value.toString()); + } + + public String getString() { + return value == null ? null : value.toString(); + } + + public Object getValue() { + return value; + } + + public boolean isNull() { + return value == null; + } + + @Override + public String toString() { + // TODO Add padding if a display width is specified in the Field + String s = getString(); + return s == null ? "null" : s; + } } diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java index 468dee54..fb41579e 100644 --- a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java @@ -17,8 +17,12 @@ Copyright 2008 Mike Heath */ package org.adbcj.mysql.codec; + import java.io.IOException; import java.io.InputStream; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; import java.util.Set; import org.adbcj.Value; @@ -27,354 +31,410 @@ import org.slf4j.LoggerFactory; /** - * Client stateful decoder. Being stateful, each client connection must have its own decoder instance to function - * properly. - * + * Client stateful decoder. Being stateful, each client connection must have its + * own decoder instance to function properly. + * * @author Mike Heath - * */ public class MySqlClientDecoder { - private static final Logger logger = LoggerFactory.getLogger(MySqlClientDecoder.class); - - /** - * The salt size in a server greeting - */ - public static final int SALT_SIZE = 8; - - /** - * The size of the second salt in a server greeting - */ - public static final int SALT2_SIZE = 12; - - /** - * Number of unused bytes in server greeting - */ - public static final int GREETING_UNUSED_SIZE = 13; - - public static final int SQL_STATE_LENGTH = 5; - - public static final int RESPONSE_OK = 0x00; - public static final int RESPONSE_EOF = 0xfe; - public static final int RESPONSE_ERROR = 0xff; - /** - * The state of the decoder. - */ - enum State { - /** - * The client is connecting - */ - CONNECTING, - RESPONSE, - FIELD, - FIELD_EOF, - ROW - } - - private State state = State.CONNECTING; - - private String charset = "ISO8859_1"; - - /** - * Holds the remaining number of field packets expected to build the result set - */ - private int expectedFieldPackets = 0; - - private int fieldIndex = 0; - - /** - * The field definitions for the current result set - */ - private MysqlField[] fields; - - /** - * Decodes a message from a MySql server. - * - * @param input the {@code InputStream} from which to decode the message - * @param block true if the decoder can block, false otherwise - * @return the decode message, null if the {@code block} is {@code} false and there is not enough data available - * to decode the message without blocking - * @throws IOException thrown if an error occurs reading data from the inputstream - */ - public ServerPacket decode(InputStream input, boolean block) throws IOException { - // If mark is not support and we can't block, throw an exception - if (!input.markSupported() && !block) { - throw new IllegalArgumentException("Non-blocking decoding requires an InputStream that supports marking"); - } - // TODO This should be the max packet size - make this configurable - input.mark(Integer.MAX_VALUE); - ServerPacket message = null; - try { - message = doDecode(input, block); - } finally { - if (message == null) { - input.reset(); - } - } - return message; - } - - protected ServerPacket doDecode(InputStream input, boolean block) throws IOException { - // If we can't block, make sure there's enough data available to read - if (!block) { - if (input.available() < 3) { - return null; - } - } - // Read the packet length - final int length = IoUtils.readUnsignedMediumInt(input); - - // If we can't block, make sure the stream has enough data - if (!block) { - // Make sure we have enough data for the packet length and the packet number - if (input.available() < length + 1) { - return null; - } - } - final int packetNumber = IoUtils.safeRead(input); - BoundedInputStream in = new BoundedInputStream(input, length); - boolean threwException = false; - try { - - logger.trace("Decoding in state {}", state); - switch (state) { - case CONNECTING: - ServerGreeting serverGreeting = decodeServerGreeting(in, length, packetNumber); - state = State.RESPONSE; - return serverGreeting; - case RESPONSE: - int fieldCount = in.read(); - if (fieldCount == RESPONSE_OK) { - // Create Ok response - return decodeOkResponse(in, length, packetNumber); - } - if (fieldCount == RESPONSE_ERROR) { - // Create error response - ErrorResponse response = decodeErrorResponse(in, length, packetNumber); - return response; - } - if (fieldCount == RESPONSE_EOF) { - throw new IllegalStateException("Did not expect an EOF response from the server"); - } - // Must be receiving result set header - - // Get the number of fields. The largest this can be is a 24-bit - // integer so cast to int is ok - expectedFieldPackets = (int)IoUtils.readBinaryLengthEncoding(in, fieldCount); - fields = new MysqlField[expectedFieldPackets]; - logger.trace("Field count {}", expectedFieldPackets); - - Long extra = null; - if (in.getRemaining() > 0) { - extra = IoUtils.readBinaryLengthEncoding(in); - } - - state = State.FIELD; - - return new ResultSetResponse(length, packetNumber, expectedFieldPackets, extra); - case FIELD: - ResultSetFieldResponse resultSetFieldResponse = decodeFieldResponse(in, length, packetNumber); - - expectedFieldPackets--; - logger.trace("fieldPacketCount: {}", expectedFieldPackets); - if (expectedFieldPackets == 0) { - state = State.FIELD_EOF; - } - return resultSetFieldResponse; - case FIELD_EOF: - fieldCount = in.read(); - - if (fieldCount != RESPONSE_EOF) { - throw new IllegalStateException("Expected an EOF response from the server"); - } - EofResponse fieldEof = decodeEofResponse(in, length, packetNumber, EofResponse.Type.FIELD); - state = State.ROW; - fieldIndex = 0; - return fieldEof; - case ROW: - fieldCount = in.read(); // This is only for checking for EOF - if (fieldCount == RESPONSE_EOF) { - EofResponse rowEof = decodeEofResponse(in, length, packetNumber, EofResponse.Type.ROW); - - state = State.RESPONSE; - - return rowEof; - } - - Value[] values = new Value[fields.length]; - for (int i = 0; i < fields.length; ) { - MysqlField field = fields[i++]; - Object value = null; - if (fieldCount != IoUtils.NULL_VALUE) { - // We will have to move this as some datatypes will not be sent across the wire as strings - String strVal = IoUtils.readLengthCodedString(in, fieldCount, charset); - - // TODO add decoding for all column types - switch (field.getColumnType()) { - case TINYINT: - value = Byte.valueOf(strVal); - break; - case INTEGER: - case BIGINT: - value = Long.valueOf(strVal); - break; - case VARCHAR: - value = strVal; - break; - default: - throw new IllegalStateException("Don't know how to handle column type of " - + field.getColumnType()); - } - } - values[field.getIndex()] = new DefaultValue(field, value); - if (i < fields.length) { - fieldCount = in.read(); - } - - } - return new ResultSetRowResponse(length, packetNumber, values); - default: - throw new IllegalStateException("Unkown decoder state " + state); - } - } catch (IOException e) { - threwException = true; - throw e; - } catch (RuntimeException e) { - threwException = true; - throw e; - } finally { - if (!threwException && in.getRemaining() > 0) { - throw new IllegalStateException("Buffer underrun occured; remaining bytes: " + in.getRemaining()); - } - } - } - - protected ServerGreeting decodeServerGreeting(InputStream in, int length, int packetNumber) throws IOException { - int protocol = IoUtils.safeRead(in); - String version = IoUtils.readString(in, "ASCII"); - int threadId = IoUtils.readInt(in); - - byte[] salt = new byte[SALT_SIZE + SALT2_SIZE]; - in.read(salt, 0, SALT_SIZE); - in.read(); // Throw away 0 byte - - Set serverCapabilities = IoUtils.readEnumSetShort(in, ClientCapabilities.class); - MysqlCharacterSet charSet = MysqlCharacterSet.findById(in.read()); - Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); - in.skip(GREETING_UNUSED_SIZE); - - in.read(salt, SALT_SIZE, SALT2_SIZE); - in.read(); // Throw away 0 byte - - return new ServerGreeting(length, packetNumber, protocol, version, threadId, salt, serverCapabilities, charSet, - serverStatus); - } - - protected OkResponse decodeOkResponse(BoundedInputStream in, int length, int packetNumber) throws IOException { - long affectedRows = IoUtils.readBinaryLengthEncoding(in); - long insertId = IoUtils.readBinaryLengthEncoding(in); - Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); - int warningCount = IoUtils.readUnsignedShort(in); - String message = IoUtils.readFixedLengthString(in, in.getRemaining(), charset); - - return new OkResponse(length, packetNumber, affectedRows, insertId, serverStatus, - warningCount, message); - } - - protected ErrorResponse decodeErrorResponse(InputStream in, int length, int packetNumber) throws IOException { - int errorNumber = IoUtils.readUnsignedShort(in); - in.read(); // Throw away sqlstate marker - String sqlState = IoUtils.readString(in, "ASCII"); - String message = IoUtils.readString(in, charset); - return new ErrorResponse(length, packetNumber, errorNumber, sqlState, message); - } - - protected EofResponse decodeEofResponse(InputStream in, int length, int packetNumber, EofResponse.Type type) throws IOException { - int warnings = IoUtils.readUnsignedShort(in); - Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); - - return new EofResponse(length, packetNumber, warnings, serverStatus, type); - } - - protected ResultSetFieldResponse decodeFieldResponse(InputStream in, - int packetLength, int packetNumber) throws IOException { - String catalogName = IoUtils.readLengthCodedString(in, charset); - String schemaName = IoUtils.readLengthCodedString(in, charset); - String tableLabel = IoUtils.readLengthCodedString(in, charset); - String tableName = IoUtils.readLengthCodedString(in, charset); - String columnLabel = IoUtils.readLengthCodedString(in, charset); - String columnName = IoUtils.readLengthCodedString(in, charset); - in.read(); // Skip filler - int characterSetNumber = IoUtils.readUnsignedShort(in); - MysqlCharacterSet charSet = MysqlCharacterSet.findById(characterSetNumber); - long length = IoUtils.readUnsignedInt(in); - int fieldTypeId = in.read(); - MysqlType fieldType = MysqlType.findById(fieldTypeId); - Set flags = IoUtils.readEnumSet(in, FieldFlag.class); - int decimals = in.read(); - in.skip(2); // Skip filler - long fieldDefault = IoUtils.readBinaryLengthEncoding(in); - MysqlField field = new MysqlField(fieldIndex, catalogName, schemaName, tableLabel, tableName, fieldType, columnLabel, - columnName, 0, // Figure out precision - decimals, charSet, length, flags, fieldDefault); - fields[fieldIndex++] = field; - return new ResultSetFieldResponse(packetLength, packetNumber, field); - } - - // TODO: This stream implementation doesn't even work b ecause it doesn't delegate all InputStream methods - private static class BoundedInputStream extends InputStream { - - private final InputStream in; - private int remaining; - - public BoundedInputStream(InputStream in, int length) { - this.in = in; - this.remaining = length; - } - - @Override - public int read() throws IOException { - int i = in.read(); - if (i >= 0) { - remaining --; - } - if (remaining < 0) { - throw new IllegalStateException("Buffer overrun"); - } - return i; - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - int i = in.read(b, off, len); - remaining -= i; - if (remaining < 0) { - throw new IllegalStateException("Read too many bytes"); - } - return i; - } - - @Override - public long skip(long n) throws IOException { - long i = in.skip(n); - remaining -= i; - if (remaining < 0) { - throw new IllegalStateException("Read too many bytes"); - } - return i; - } - - public int getRemaining() { - return remaining; - } - - } - - /** - * Sets the state, used for testing. - * - * @param state - */ - void setState(State state) { - this.state = state; - } + + private static final Logger logger = LoggerFactory.getLogger(MySqlClientDecoder.class); + + /** + * The salt size in a server greeting + */ + public static final int SALT_SIZE = 8; + + /** + * The size of the second salt in a server greeting + */ + public static final int SALT2_SIZE = 12; + + /** + * Number of unused bytes in server greeting + */ + public static final int GREETING_UNUSED_SIZE = 13; + + public static final int SQL_STATE_LENGTH = 5; + + public static final int RESPONSE_OK = 0x00; + public static final int RESPONSE_EOF = 0xfe; + public static final int RESPONSE_ERROR = 0xff; + + /** + * The state of the decoder. + */ + enum State { + /** + * The client is connecting + */ + CONNECTING, RESPONSE, FIELD, FIELD_EOF, ROW + } + + private State state = State.CONNECTING; + + private String charset = "ISO8859_1"; + + /** + * Holds the remaining number of field packets expected to build the result + * set + */ + private int expectedFieldPackets = 0; + + private int fieldIndex = 0; + + /** + * The field definitions for the current result set + */ + private MysqlField[] fields; + + /** + * Decodes a message from a MySql server. + * + * @param input the {@code InputStream} from which to decode the message + * @param block true if the decoder can block, false otherwise + * @return the decode message, null if the {@code block} is {@code} false + * and there is not enough data available to decode the message without + * blocking + * @throws IOException thrown if an error occurs reading data from the + * inputstream + */ + public ServerPacket decode(InputStream input, boolean block) throws IOException { + // If mark is not support and we can't block, throw an exception + if (!input.markSupported() && !block) { + throw new IllegalArgumentException("Non-blocking decoding requires an InputStream that supports marking"); + } + // TODO This should be the max packet size - make this configurable + input.mark(Integer.MAX_VALUE); + ServerPacket message = null; + try { + message = doDecode(input, block); + } finally { + if (message == null) { + input.reset(); + } + } + return message; + } + + protected ServerPacket doDecode(InputStream input, boolean block) throws IOException { + // If we can't block, make sure there's enough data available to read + if (!block) { + if (input.available() < 3) { + return null; + } + } + // Read the packet length + final int length = IoUtils.readUnsignedMediumInt(input); + + // If we can't block, make sure the stream has enough data + if (!block) { + // Make sure we have enough data for the packet length and the + // packet number + if (input.available() < length + 1) { + return null; + } + } + final int packetNumber = IoUtils.safeRead(input); + BoundedInputStream in = new BoundedInputStream(input, length); + boolean threwException = false; + try { + + logger.trace("Decoding in state {}", state); + switch (state) { + case CONNECTING: + ServerGreeting serverGreeting = decodeServerGreeting(in, length, packetNumber); + state = State.RESPONSE; + return serverGreeting; + case RESPONSE: + int fieldCount = in.read(); + if (fieldCount == RESPONSE_OK) { + // Create Ok response + return decodeOkResponse(in, length, packetNumber); + } + if (fieldCount == RESPONSE_ERROR) { + // Create error response + ErrorResponse response = decodeErrorResponse(in, length, packetNumber); + return response; + } + if (fieldCount == RESPONSE_EOF) { + throw new IllegalStateException("Did not expect an EOF response from the server"); + } + // Must be receiving result set header + + // Get the number of fields. The largest this can be is a + // 24-bit + // integer so cast to int is ok + expectedFieldPackets = (int) IoUtils.readBinaryLengthEncoding(in, fieldCount); + fields = new MysqlField[expectedFieldPackets]; + logger.trace("Field count {}", expectedFieldPackets); + + Long extra = null; + if (in.getRemaining() > 0) { + extra = IoUtils.readBinaryLengthEncoding(in); + } + + state = State.FIELD; + + return new ResultSetResponse(length, packetNumber, expectedFieldPackets, extra); + case FIELD: + ResultSetFieldResponse resultSetFieldResponse = decodeFieldResponse(in, length, packetNumber); + + expectedFieldPackets--; + logger.trace("fieldPacketCount: {}", expectedFieldPackets); + if (expectedFieldPackets == 0) { + state = State.FIELD_EOF; + } + return resultSetFieldResponse; + case FIELD_EOF: + fieldCount = in.read(); + + if (fieldCount != RESPONSE_EOF) { + throw new IllegalStateException("Expected an EOF response from the server"); + } + EofResponse fieldEof = decodeEofResponse(in, length, packetNumber, EofResponse.Type.FIELD); + state = State.ROW; + fieldIndex = 0; + return fieldEof; + case ROW: + fieldCount = in.read(); // This is only for checking for EOF + if (fieldCount == RESPONSE_EOF) { + EofResponse rowEof = decodeEofResponse(in, length, packetNumber, EofResponse.Type.ROW); + + state = State.RESPONSE; + + return rowEof; + } + + Value[] values = new Value[fields.length]; + for (int i = 0; i < fields.length;) { + MysqlField field = fields[i++]; + Object value = null; + if (fieldCount != IoUtils.NULL_VALUE) { + // We will have to move this as some datatypes will + // not be sent across the wire as strings + String strVal = IoUtils.readLengthCodedString(in, fieldCount, charset); + + // TODO add decoding for all column types + switch (field.getColumnType()) { + case TINYINT: + value = Byte.valueOf(strVal); + break; + case INTEGER: + value = Integer.valueOf(strVal); + break; + case BIGINT: + value = Long.valueOf(strVal); + break; + case VARCHAR: + value = strVal; + break; + case DATE: + value = Date.valueOf(strVal); + break; + case TIMESTAMP: + value = Timestamp.valueOf(strVal); + break; + case FLOAT: + value = Float.valueOf(strVal); + break; + case TIME: + value = Time.valueOf(strVal); + break; + case BOOLEAN: + value = Boolean.valueOf(strVal); + break; + case CHAR: + value = strVal; + break; + case DOUBLE: + value = Double.valueOf(strVal); + break; + case SMALLINT: + value = Integer.valueOf(strVal); + break; + case LONGVARCHAR: + value = String.valueOf(strVal); + break; + case BINARY: + // UTF-8?GBK? + value = strVal.getBytes(); + break; + + default: + throw new IllegalStateException("Don't know how to handle column type of " + + field.getColumnType()); + } + } + values[field.getIndex()] = new DefaultValue(field, value); + if (i < fields.length) { + fieldCount = in.read(); + } + + } + return new ResultSetRowResponse(length, packetNumber, values); + default: + throw new IllegalStateException("Unkown decoder state " + state); + } + } catch (IOException e) { + threwException = true; + throw e; + } catch (RuntimeException e) { + threwException = true; + throw e; + } finally { + if (!threwException && in.getRemaining() > 0) { + throw new IllegalStateException("Buffer underrun occured; remaining bytes: " + in.getRemaining()); + } + } + } + + protected ServerGreeting decodeServerGreeting(InputStream in, int length, int packetNumber) throws IOException { + int protocol = IoUtils.safeRead(in); + String version = IoUtils.readString(in, "ASCII"); + int threadId = IoUtils.readInt(in); + + byte[] salt = new byte[SALT_SIZE + SALT2_SIZE]; + in.read(salt, 0, SALT_SIZE); + in.read(); // Throw away 0 byte + + Set serverCapabilities = IoUtils.readEnumSetShort(in, ClientCapabilities.class); + MysqlCharacterSet charSet = MysqlCharacterSet.findById(in.read()); + Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); + in.skip(GREETING_UNUSED_SIZE); + + in.read(salt, SALT_SIZE, SALT2_SIZE); + in.read(); // Throw away 0 byte + + return new ServerGreeting(length, + packetNumber, + protocol, + version, + threadId, + salt, + serverCapabilities, + charSet, + serverStatus); + } + + protected OkResponse decodeOkResponse(BoundedInputStream in, int length, int packetNumber) throws IOException { + long affectedRows = IoUtils.readBinaryLengthEncoding(in); + long insertId = IoUtils.readBinaryLengthEncoding(in); + Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); + int warningCount = IoUtils.readUnsignedShort(in); + String message = IoUtils.readFixedLengthString(in, in.getRemaining(), charset); + + return new OkResponse(length, packetNumber, affectedRows, insertId, serverStatus, warningCount, message); + } + + protected ErrorResponse decodeErrorResponse(InputStream in, int length, int packetNumber) throws IOException { + int errorNumber = IoUtils.readUnsignedShort(in); + in.read(); // Throw away sqlstate marker + String sqlState = IoUtils.readString(in, "ASCII"); + String message = IoUtils.readString(in, charset); + return new ErrorResponse(length, packetNumber, errorNumber, sqlState, message); + } + + protected EofResponse decodeEofResponse(InputStream in, int length, int packetNumber, EofResponse.Type type) + throws IOException { + int warnings = IoUtils.readUnsignedShort(in); + Set serverStatus = IoUtils.readEnumSetShort(in, ServerStatus.class); + + return new EofResponse(length, packetNumber, warnings, serverStatus, type); + } + + protected ResultSetFieldResponse decodeFieldResponse(InputStream in, int packetLength, int packetNumber) + throws IOException { + String catalogName = IoUtils.readLengthCodedString(in, charset); + String schemaName = IoUtils.readLengthCodedString(in, charset); + String tableLabel = IoUtils.readLengthCodedString(in, charset); + String tableName = IoUtils.readLengthCodedString(in, charset); + String columnLabel = IoUtils.readLengthCodedString(in, charset); + String columnName = IoUtils.readLengthCodedString(in, charset); + in.read(); // Skip filler + int characterSetNumber = IoUtils.readUnsignedShort(in); + MysqlCharacterSet charSet = MysqlCharacterSet.findById(characterSetNumber); + long length = IoUtils.readUnsignedInt(in); + int fieldTypeId = in.read(); + MysqlType fieldType = MysqlType.findById(fieldTypeId); + Set flags = IoUtils.readEnumSet(in, FieldFlag.class); + int decimals = in.read(); + in.skip(2); // Skip filler + long fieldDefault = IoUtils.readBinaryLengthEncoding(in); + MysqlField field = new MysqlField(fieldIndex, + catalogName, + schemaName, + tableLabel, + tableName, + fieldType, + columnLabel, + columnName, + 0, // Figure out precision + decimals, + charSet, + length, + flags, + fieldDefault); + fields[fieldIndex++] = field; + return new ResultSetFieldResponse(packetLength, packetNumber, field); + } + + // TODO: This stream implementation doesn't even work b ecause it doesn't + // delegate all InputStream methods + private static class BoundedInputStream extends InputStream { + + private final InputStream in; + private int remaining; + + public BoundedInputStream(InputStream in, int length){ + this.in = in; + this.remaining = length; + } + + @Override + public int read() throws IOException { + int i = in.read(); + if (i >= 0) { + remaining--; + } + if (remaining < 0) { + throw new IllegalStateException("Buffer overrun"); + } + return i; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int i = in.read(b, off, len); + remaining -= i; + if (remaining < 0) { + throw new IllegalStateException("Read too many bytes"); + } + return i; + } + + @Override + public long skip(long n) throws IOException { + long i = in.skip(n); + remaining -= i; + if (remaining < 0) { + throw new IllegalStateException("Read too many bytes"); + } + return i; + } + + public int getRemaining() { + return remaining; + } + + } + + /** + * Sets the state, used for testing. + * + * @param state + */ + void setState(State state) { + this.state = state; + } } diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java new file mode 100644 index 00000000..5d81f287 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java @@ -0,0 +1,22 @@ +package com.taobao.tdhs.config; + +public class AtomAlreadyInitException extends Exception { + + private static final long serialVersionUID = -3907211238952987907L; + + public AtomAlreadyInitException() { + super(); + } + + public AtomAlreadyInitException(String msg) { + super(msg); + } + + public AtomAlreadyInitException(Throwable cause) { + super(cause); + } + + public AtomAlreadyInitException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java new file mode 100644 index 00000000..8f4a7dd4 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java @@ -0,0 +1,64 @@ + +package com.taobao.tdhs.config; + +import com.alibaba.common.lang.StringUtil; + +/** + * æ•°æ®åº“çŠ¶æ€æžšä¸¾ç±»åž‹ + * @author qihao + * + */ +public enum AtomDbStatusEnum { + + R_STAUTS(TAtomConstants.DB_STATUS_R), W_STATUS(TAtomConstants.DB_STATUS_W), RW_STATUS(TAtomConstants.DB_STATUS_RW), NA_STATUS( + TAtomConstants.DB_STATUS_NA); + + private String status; + + AtomDbStatusEnum(String status) { + this.status = status; + } + + public String getStatus() { + return status; + } + + public static AtomDbStatusEnum getAtomDbStatusEnumByType(String type) { + AtomDbStatusEnum statusEnum = null; + if (StringUtil.isNotBlank(type)) { + String typeStr = type.toUpperCase().trim(); + if (typeStr.length() > 1) { + if (AtomDbStatusEnum.NA_STATUS.getStatus().equals(typeStr)) { + statusEnum = AtomDbStatusEnum.NA_STATUS; + } else if (!StringUtil.contains(typeStr, AtomDbStatusEnum.NA_STATUS.getStatus()) + &&StringUtil.contains(typeStr, AtomDbStatusEnum.R_STAUTS.getStatus()) + && StringUtil.contains(typeStr, AtomDbStatusEnum.W_STATUS.getStatus())) { + statusEnum = AtomDbStatusEnum.RW_STATUS; + } + } else { + if (AtomDbStatusEnum.R_STAUTS.getStatus().equals(typeStr)) { + statusEnum = AtomDbStatusEnum.R_STAUTS; + } else if (AtomDbStatusEnum.W_STATUS.getStatus().equals(typeStr)) { + statusEnum = AtomDbStatusEnum.W_STATUS; + } + } + } + return statusEnum; + } + + public boolean isNaStatus() { + return this == AtomDbStatusEnum.NA_STATUS; + } + + public boolean isRstatus() { + return this == AtomDbStatusEnum.R_STAUTS || this == AtomDbStatusEnum.RW_STATUS; + } + + public boolean isWstatus() { + return this == AtomDbStatusEnum.W_STATUS || this == AtomDbStatusEnum.RW_STATUS; + } + + public boolean isRWstatus() { + return this == AtomDbStatusEnum.RW_STATUS; + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java new file mode 100644 index 00000000..62c6ab08 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java @@ -0,0 +1,53 @@ +package com.taobao.tdhs.config; + + +/** + * æ•°æ®åº“类型枚举类型 + * + * @author qihao + * + */ +public enum AtomDbTypeEnum { + + ORACLE(TAtomConstants.DEFAULT_ORACLE_DRIVER_CLASS, TAtomConstants.DEFAULT_ORACLE_SORTER_CLASS), + + MYSQL(TAtomConstants.DEFAULT_MYSQL_DRIVER_CLASS, TAtomConstants.DEFAULT_MYSQL_SORTER_CLASS); + + private String driverClass; + private String sorterClass; + + AtomDbTypeEnum(String driverClass, String sorterClass) { + this.driverClass = driverClass; + this.sorterClass = sorterClass; + } + + public static AtomDbTypeEnum getAtomDbTypeEnumByType(String type) { + /* + if (StringUtil.isNotBlank(type)) { + for (AtomDbTypeEnum typeEnum : AtomDbTypeEnum.values()) { + if (typeEnum.getType().equals(type.toUpperCase().trim())) { + return typeEnum; + } + } + } + return null; + */ + try { + return AtomDbTypeEnum.valueOf(type.trim().toUpperCase()); + } catch (Exception e) { + return null; + } + } + + public String getDriverClass() { + return driverClass; + } + + public String getSorterClass() { + return sorterClass; + } + + /*public String getType() { + return type; + }*/ +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java new file mode 100644 index 00000000..2444807a --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java @@ -0,0 +1,26 @@ +package com.taobao.tdhs.config; + +/** + * @author qihao + * + */ +public class AtomIllegalException extends Exception { + + private static final long serialVersionUID = -5341803227125385166L; + + public AtomIllegalException() { + super(); + } + + public AtomIllegalException(String msg) { + super(msg); + } + + public AtomIllegalException(Throwable cause) { + super(cause); + } + + public AtomIllegalException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java new file mode 100644 index 00000000..f0c6e2ee --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java @@ -0,0 +1,26 @@ +package com.taobao.tdhs.config; + +/** + * @author qihao + * + */ +public class AtomInitialException extends Exception { + + private static final long serialVersionUID = -2933446568649742125L; + + public AtomInitialException() { + super(); + } + + public AtomInitialException(String msg) { + super(msg); + } + + public AtomInitialException(Throwable cause) { + super(cause); + } + + public AtomInitialException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java new file mode 100644 index 00000000..f85d70e8 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java @@ -0,0 +1,55 @@ +//Copyrigh(c) Taobao.com +package com.taobao.tdhs.config; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-11上åˆ11:22:29 + * @desc 获å–é…置的处ç†å™¨ + */ +public interface ConfigDataHandler { + public static final String FIRST_SERVER_STRATEGY = "firstServer"; + public static final String FIRST_CACHE_THEN_SERVER_STRATEGY="firstCache"; + + /** + * DefaultConfigDataHandler会在 实例化具体的Handler之åŽè°ƒç”¨æ­¤æ–¹æ³• 给予Handlerç›¸å…³ä¿¡æ¯ + * @param dataId æ•°æ®åœ¨é…置平å°ä¸Šæ³¨å†Œçš„id + * @param listenerList æ•°æ®ç›‘å¬å™¨åˆ—表 + * @param prop 全局é…置和è¿è¡Œæ—¶ + */ + void init(String dataId, List listenerList, + Map prop); + + /** + * 从é…ç½®ä¸­å¿ƒæ‹‰å–æ•°æ® + * @param timeout 获å–é…置信æ¯è¶…æ—¶æ—¶é—´ + * @param strategy 获å–é…置策略 + * @return + */ + String getData(long timeout, String strategy); + + /** + * 为推é€è¿‡æ¥çš„æ•°æ®æ³¨å†Œå¤„ç†çš„监å¬å™¨ + * @param configDataListener 监å¬å™¨ + * @param executor 执行的executor + */ + void addListener(ConfigDataListener configDataListener, Executor executor); + + /** + * 为推é€è¿‡æ¥çš„æ•°æ®æ³¨å†Œå¤šä¸ªå¤„ç†ç›‘å¬å™¨ + * @param configDataListenerList 监å¬å™¨åˆ—表 + * @param executor 执行的executor + */ + void addListeners(List configDataListenerList, + Executor executor); + + /** + * åœæ­¢åº•层é…置管ç†å™¨ + */ + void closeUnderManager(); +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java new file mode 100644 index 00000000..d6f1eb66 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java @@ -0,0 +1,109 @@ +package com.taobao.tdhs.config; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * @author whisper + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-11上åˆ11:22:29 + * @desc 得到具体的é…置处ç†å™¨å®žä¾‹ + */ +public interface ConfigDataHandlerFactory { + /** + * 对æŸä¸€ä¸ªdataIdè¿›è¡Œç›‘å¬ + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandler(String dataId); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ + * @param dataId æ•°æ®åœ¨p诶值中心注册的id + * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandler(String dataId, + ConfigDataListener configDataListener); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,处ç†å™¨æ”¶åˆ°é…ç½®ä¿¡æ¯æ—¶ + * ,é€ä¸ªè°ƒç”¨ç›‘å¬å™¨çš„回调方法 + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerWithListenerList(String dataId, + List configDataListenerList); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œå¹¶ä¸”æä¾›å†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ + * @param config TDDL内部对handleræä¾›çš„一些é…ç½® + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerC(String dataId, + ConfigDataListener configDataListener, + Map config); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬,使用者æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,并且æä¾›å†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 + * @param config TDDL内部对handleræä¾›çš„一些é…ç½® + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerWithListenerListC(String dataId, + List configDataListenerList, + Map config); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œå¹¶ä¸”æä¾›æ‰§è¡Œçº¿ç¨‹æ±  + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ + * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerE(String dataId, + ConfigDataListener configDataListener, Executor executor); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,并且æä¾›æ‰§è¡Œçº¿ç¨‹æ±  + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 + * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerWithListenerListE(String dataId, + List configDataListenerList, Executor executor); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œ + * 并且æä¾›æ‰§è¡Œçº¿ç¨‹æ± å’Œå†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ + * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  + * @param config TDDL内部对handleræä¾›çš„一些é…ç½® + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerCE(String dataId, + ConfigDataListener configDataListener, Executor executor, + Map config); + + /** + * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表, + * 并且æä¾›æ‰§è¡Œçº¿ç¨‹æ± å’Œå†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 + * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  + * @param config TDDL内部对handleræä¾›çš„一些é…ç½® + * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ + */ + ConfigDataHandler getConfigDataHandlerWithListenerListCE(String dataId, + List configDataListenerList, Executor executor, + Map config); +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java new file mode 100644 index 00000000..2c3986d9 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java @@ -0,0 +1,19 @@ +package com.taobao.tdhs.config; + +/** + * @author shenxun + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-11上åˆ11:22:29 + * @desc 接收信æ¯çš„å›žè°ƒæŽ¥å£ + */ +public interface ConfigDataListener { + /** + * é…ç½®ä¸­å¿ƒå®¢æˆ·ç«¯æ”¶åˆ°æ•°æ®æ—¶è°ƒç”¨æ³¨å†Œçš„监å¬å™¨æ–¹æ³•, + * 并把收到的数æ®ä¼ é€’到此方法中 + * @param dataId æ•°æ®åœ¨é…置中心注册的id + * @param data å­—ç¬¦ä¸²æ•°æ® + */ + void onDataRecieved(String dataId,String data); +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java new file mode 100644 index 00000000..8a5f5db3 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java @@ -0,0 +1,40 @@ +package com.taobao.tdhs.config; + + +/** + * TAtomæ•°æ®æºå…¨å±€å’Œåº”用的é…ç½®ç®¡ç†æŽ¥å£å®šä¹‰ + * + * @author qihao + * + */ +public interface DbConfManager { + /**获å–全局é…ç½® + * + * @return + */ + public String getGlobalDbConf(); + + /**获å–应用é…ç½® + * + * @return + */ + public String getAppDbDbConf(); + + /** + * 注册全局é…ç½®ç›‘å¬ + * + * @param Listener + */ + public void registerGlobaDbConfListener(ConfigDataListener Listener); + + /**注册应用é…ç½®ç›‘å¬ + * + * @param Listener + */ + public void registerAppDbConfListener(ConfigDataListener Listener); + + /** + * åœæ­¢DbConfManager + */ + public void stopDbConfManager(); +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java new file mode 100644 index 00000000..b3a23659 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java @@ -0,0 +1,21 @@ +package com.taobao.tdhs.config; + + +public interface DbPasswdManager { + + /**��ȡ��ݿ����� + * @return + */ + public String getPasswd(); + + /**ע��Ӧ�����ü��� + * + * @param Listener + */ + public void registerPasswdConfListener(ConfigDataListener Listener); + + /** + * Í£Ö¹DbPasswdManager + */ + public void stopDbPasswdManager(); +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java new file mode 100644 index 00000000..f798551c --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java @@ -0,0 +1,251 @@ +//Copyright(c) Taobao.com +package com.taobao.tdhs.config; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @description + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-11下åˆ01:17:21 + */ +@SuppressWarnings("rawtypes") +public class DefaultConfigDataHandlerFactory implements + ConfigDataHandlerFactory { + private static final Log log = LogFactory + .getLog(DefaultConfigDataHandlerFactory.class); + private static final String HANDLER_CLASS = "config.handler.constructor.name"; + private static final String DEFAULT_HANDLER_CLASS = "com.taobao.tdhs.config.DiamondConfigDataHandler"; + + private static String propertyFile = "remote-config.properties"; + private static String handlerClassName; + private static Class handlerClassObj; + private static Constructor handlerConstructor; + private static Properties prop; + + static { + findSpecifiedConfigHandlerClass(); + createConstuctFromClassName(); + } + + private static void findSpecifiedConfigHandlerClass() { + ClassLoader currentCL = getBaseClassLoader(); + InputStream resource; + for (;;) { + if (currentCL != null) { + resource = currentCL.getResourceAsStream(propertyFile); + } else { + resource = ClassLoader.getSystemResourceAsStream(propertyFile); + break; + } + + if (null != resource) { + break; + } else { + currentCL = currentCL.getParent(); + } + } + + if (null != resource) { + prop = new Properties(); + try { + prop.load(resource); + handlerClassName = prop.getProperty(HANDLER_CLASS); + if (null == handlerClassName || "".equals(handlerClassName)) { + handlerClassName = DEFAULT_HANDLER_CLASS; + } + } catch (IOException e) { + log.error("properties can not load " + propertyFile); + } + } else { + handlerClassName = DEFAULT_HANDLER_CLASS; + } + } + + @SuppressWarnings("unchecked") + private static void createConstuctFromClassName() { + ClassLoader currentCL = getBaseClassLoader(); + handlerClassObj = loadClass(handlerClassName, currentCL); + if (null == handlerClassObj) { + throw new IllegalArgumentException("can not get handler class:" + + handlerClassName); + } + + try { + handlerConstructor = handlerClassObj.getConstructor(); + } catch (SecurityException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + + private static Class loadClass(String className, ClassLoader currentCL) { + log.info("Trying to load '" + className); + try { + Class clazz = currentCL.loadClass(handlerClassName); + if (clazz != null) { + return clazz; + } + } catch (ClassNotFoundException e) { + log.error("can not load the class "); + } + + return null; + + } + + private static boolean useTCCL = true; + + private static ClassLoader getBaseClassLoader() { + ClassLoader thisClassLoader = DefaultConfigDataHandlerFactory.class + .getClassLoader(); + if (useTCCL == false) { + return thisClassLoader; + } + ClassLoader contextClassLoader = Thread.currentThread() + .getContextClassLoader(); + ClassLoader baseClassLoader = getLowestClassLoader(contextClassLoader, + thisClassLoader); + return baseClassLoader; + } + + private static ClassLoader getLowestClassLoader(ClassLoader c1, + ClassLoader c2) { + if (c1 == null) + return c2; + + if (c2 == null) + return c1; + + ClassLoader current; + + current = c1; + while (current != null) { + if (current == c2) + return c1; + current = current.getParent(); + } + + current = c2; + while (current != null) { + if (current == c1) + return c2; + current = current.getParent(); + } + + return null; + } + + public static String objectId(Object o) { + if (o == null) { + return "null"; + } else { + // 这里这个System.identityHashCodeåªä¼šåœ¨åˆå§‹åŒ–时调用一次,所以 + // å…¶å¯èƒ½å­˜åœ¨çš„问题影å“å¹¶ä¸å¤§ã€‚ + return o.getClass().getName() + "@" + System.identityHashCode(o); + } + } + + + public ConfigDataHandler getConfigDataHandler(String dataId) { + return this.getConfigDataHandler(dataId, null); + } + + + public ConfigDataHandler getConfigDataHandler(String dataId, + ConfigDataListener configDataListener) { + return this.getConfigDataHandlerC(dataId, configDataListener, + new HashMap()); + } + + + public ConfigDataHandler getConfigDataHandlerWithListenerList( + String dataId, List configDataListenerList) { + return this.getConfigDataHandlerWithListenerListC(dataId, + configDataListenerList, new HashMap()); + } + + + public ConfigDataHandler getConfigDataHandlerC(String dataId, + ConfigDataListener configDataListener, Map config) { + return this.getConfigDataHandlerCE(dataId, configDataListener, null, + config); + } + + + public ConfigDataHandler getConfigDataHandlerWithListenerListC( + String dataId, List configDataListenerList, + Map config) { + return this.getConfigDataHandlerWithListenerListCE(dataId, + configDataListenerList, null, config); + } + + + public ConfigDataHandler getConfigDataHandlerE(String dataId, + ConfigDataListener configDataListener, Executor executor) { + return this.getConfigDataHandlerCE(dataId, configDataListener, + executor, new HashMap()); + } + + + public ConfigDataHandler getConfigDataHandlerWithListenerListE( + String dataId, List configDataListenerList, + Executor executor) { + return this + .getConfigDataHandlerWithListenerListCE(dataId, + configDataListenerList, executor, + new HashMap()); + } + + + public ConfigDataHandler getConfigDataHandlerCE(String dataId, + ConfigDataListener configDataListener, Executor executor, + Map config) { + List configDataListenerList = new ArrayList(); + configDataListenerList.add(configDataListener); + return this.getConfigDataHandlerWithListenerListCE(dataId, + configDataListenerList, executor, config); + } + + public ConfigDataHandler getConfigDataHandlerWithListenerListCE( + String dataId, List configDataListenerList, + Executor executor, Map config) { + try { + ConfigDataHandler instance = (ConfigDataHandler) handlerConstructor + .newInstance(); + Map configMap = new HashMap(); + if (config != null) { + configMap.putAll(config); + } + + if (prop != null) { + configMap.putAll((Map) prop); + } + instance.init(dataId, configDataListenerList, configMap); + return instance; + } catch (IllegalArgumentException e) { + log.error("illegal arguments!", e); + } catch (InstantiationException e) { + log.error("handler init error!", e); + } catch (IllegalAccessException e) { + log.error("securty limit,handler can not be init!", e); + } catch (InvocationTargetException e) { + log.error("constructor invode error!", e); + } + return null; + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java new file mode 100644 index 00000000..de587f48 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java @@ -0,0 +1,80 @@ +//Copyright(c) Taobao.com +package com.taobao.tdhs.config; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import com.taobao.diamond.client.DiamondConfigure; +import com.taobao.diamond.client.impl.DiamondClientFactory; + +/** + * @description + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-17����07:21:41 + */ +public class DiamondConfig { + private volatile static DiamondConfigure configure = DiamondClientFactory + .getSingletonDiamondSubscriber().getDiamondConfigure(); + + protected static void handleConfig(Map prop) { + if(null==prop){ + return; + } + + Object interval = prop.get("pollingIntervalTime"); + if (interval != null) { + configure.setPollingIntervalTime((Integer) interval); + } + + Object connectTimeOut = prop.get("connectTimeOut"); + if (connectTimeOut != null) { + configure.setConnectionTimeout((Integer) connectTimeOut); + } + + Object onceTimeout = prop.get("onceTimeout"); + if (onceTimeout != null) { + configure.setOnceTimeout((Integer) onceTimeout); + } + + Object receiveWaitTime = prop.get("receiveWaitTime"); + if (receiveWaitTime != null) { + configure.setReceiveWaitTime((Integer) receiveWaitTime); + } + + Object domainNames = prop.get("domainNames"); + if (domainNames != null) { + String[] domains = String.valueOf(domainNames).split(","); + List domainNameList = Arrays.asList(domains); + configure.setDomainNameList(domainNameList); + } + + Object maxHostConns = prop.get("maxHostConns"); + if (maxHostConns != null) { + configure.setMaxHostConnections((Integer) maxHostConns); + } + + Object connStateCheckEnable = prop.get("connStateCheckEnable"); + if (connStateCheckEnable != null) { + configure.setConnectionStaleCheckingEnabled(Boolean.valueOf(String + .valueOf(connStateCheckEnable))); + } + + Object maxTotalConns=prop.get("maxTotalConns"); + if (maxTotalConns != null) { + configure.setMaxTotalConnections((Integer)maxTotalConns); + } + + Object filePath=prop.get("filePath"); + if (filePath != null) { + configure.setFilePath((String)filePath); + } + + Object port=prop.get("port"); + if (port != null) { + configure.setFilePath((String)port); + } + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java new file mode 100644 index 00000000..3f6d8d2d --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java @@ -0,0 +1,122 @@ +package com.taobao.tdhs.config; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.taobao.diamond.manager.DiamondManager; +import com.taobao.diamond.manager.ManagerListener; +import com.taobao.diamond.manager.impl.DefaultDiamondManager; + +/** + * @author shenxun + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-1-11����11:22:29 + * @desc �־���������diamondʵ�� + */ +public class DiamondConfigDataHandler implements ConfigDataHandler { + private static final Log logger = LogFactory + .getLog(DiamondConfigDataHandler.class); + private DiamondManager diamondManager; + private String dataId; + private String mbeanId; + + public void init(final String dataId, + final List configDataListenerList, + final Map config) { + mbeanId = dataId + System.currentTimeMillis(); + DiamondConfig.handleConfig(config); + DefaultDiamondManager.Builder builder = new DefaultDiamondManager.Builder( + dataId, new ManagerListener() { + public void receiveConfigInfo(String data) { + if (configDataListenerList != null) { + for (ConfigDataListener configDataListener : configDataListenerList) { + configDataListener.onDataRecieved(dataId, data); + } + } + } + + public Executor getExecutor() { + return (Executor) config.get("executor"); + } + }); + String group = (String) config.get("group"); + if (null != group) { + builder.setGroup(group); + } + this.diamondManager = builder.build(); + this.dataId = dataId; + + } + + public String getData(long timeout, String strategy) { + String data = null; + if (strategy != null + && strategy + .equals(ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY)) { + data = diamondManager.getAvailableConfigureInfomation(timeout); + } else if (strategy != null + && strategy.equals(ConfigDataHandler.FIRST_SERVER_STRATEGY)) { + data = diamondManager.getConfigureInfomation(timeout); + } + + + return data; + } + + public void addListener(final ConfigDataListener configDataListener, + final Executor executor) { + if (configDataListener != null) { + diamondManager.setManagerListener(new ManagerListener() { + public void receiveConfigInfo(String data) { + configDataListener.onDataRecieved(dataId, data); + } + + public Executor getExecutor() { + return executor; + } + }); + } + } + + public void addListeners( + final List configDataListenerList, + final Executor executor) { + if (configDataListenerList != null) { + diamondManager.setManagerListener(new ManagerListener() { + public void receiveConfigInfo(String data) { + for (ConfigDataListener configDataListener : configDataListenerList) { + try { + configDataListener.onDataRecieved(dataId, data); + } catch (Exception e) { + logger.error("one of listener failed", e); + continue; + } + } + + } + + public Executor getExecutor() { + return executor; + } + }); + } + } + + public void closeUnderManager() { + diamondManager.close(); + } + + public String getDataId() { + return dataId; + } + + public void setDataId(String dataId) { + this.dataId = dataId; + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java new file mode 100644 index 00000000..9363605b --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java @@ -0,0 +1,94 @@ +package com.taobao.tdhs.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * ȫ�ֺ�Ӧ�õ����ù���Diamondʵ�� + * + * @author qihao + * + */ +public class DiamondDbConfManager implements DbConfManager { + private static Log logger = LogFactory.getLog(DiamondDbConfManager.class); + private String globalConfigDataId; + private String appConfigDataId; + private ConfigDataHandlerFactory configFactory; + private ConfigDataHandler globalHandler; + private ConfigDataHandler appDBHandler; + private volatile List globalDbConfListener = new ArrayList(); + private volatile List appDbConfListener = new ArrayList(); + + public void init() { + configFactory = new DefaultConfigDataHandlerFactory(); + Map config = new HashMap(); + config.put("group", TAtomConstants.DEFAULT_DIAMOND_GROUP); + globalHandler = configFactory.getConfigDataHandlerWithListenerListCE( + globalConfigDataId, globalDbConfListener, + Executors.newSingleThreadScheduledExecutor(), config); + appDBHandler = configFactory.getConfigDataHandlerWithListenerListCE( + appConfigDataId, appDbConfListener, + Executors.newSingleThreadScheduledExecutor(), config); + } + + public String getAppDbConfDataId() { + return appConfigDataId; + } + + public String getAppDbDbConf() { + if (null != appDBHandler) { + return appDBHandler.getData(TDDLConstant.DIAMOND_GET_DATA_TIMEOUT,ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); + } + logger.error("[getDataError] appDBConfig not init !"); + return null; + } + + public String getGlobalDbConf() { + if (null != globalHandler) { + return globalHandler.getData(TDDLConstant.DIAMOND_GET_DATA_TIMEOUT,ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); + } + logger.error("[getDataError] globalConfig not init !"); + return null; + } + + public void setGlobalConfigDataId(String globalConfigDataId) { + this.globalConfigDataId = globalConfigDataId; + } + + public String getAppConfigDataId() { + return appConfigDataId; + } + + public void setAppConfigDataId(String appConfigDataId) { + this.appConfigDataId = appConfigDataId; + } + + /** + * @param Listener + */ + public void registerGlobaDbConfListener(ConfigDataListener listener) { + globalDbConfListener.add(listener); + } + + /** + * @param Listener + */ + public void registerAppDbConfListener(ConfigDataListener listener) { + appDbConfListener.add(listener); + } + + public void stopDbConfManager() { + if (null != this.globalHandler) { + this.globalHandler.closeUnderManager(); + } + if (null != this.appDBHandler) { + this.appDBHandler.closeUnderManager(); + } + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java new file mode 100644 index 00000000..c3edb7d6 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java @@ -0,0 +1,62 @@ +package com.taobao.tdhs.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * ���������Diamondʵ�� + * + * @author qihao + * + */ +public class DiamondDbPasswdManager implements DbPasswdManager { + private static Log logger = LogFactory.getLog(DiamondDbPasswdManager.class); + private String passwdConfDataId; + private ConfigDataHandlerFactory configFactory; + private ConfigDataHandler passwdHandler; + private volatile List passwdConfListener = new ArrayList(); + + public void init() { + configFactory = new DefaultConfigDataHandlerFactory(); + Map config = new HashMap(); + config.put("group", TAtomConstants.DEFAULT_DIAMOND_GROUP); + passwdHandler = configFactory.getConfigDataHandlerWithListenerListCE( + passwdConfDataId, passwdConfListener, + Executors.newSingleThreadScheduledExecutor(), config); + } + + public String getPasswd() { + if (null != passwdHandler) { + String passwdStr = passwdHandler.getData( + TDDLConstant.DIAMOND_GET_DATA_TIMEOUT, + ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); + if (passwdStr == null) { + logger.error("[getDataError] remote password string is empty !"); + return null; + } + return TAtomConfParser.parserPasswd(passwdStr); + } + logger.error("[getDataError] passwdConfig not init !"); + return null; + } + + public void registerPasswdConfListener(ConfigDataListener Listener) { + passwdConfListener.add(Listener); + } + + public void setPasswdConfDataId(String passwdConfDataId) { + this.passwdConfDataId = passwdConfDataId; + } + + public void stopDbPasswdManager() { + if (null != this.passwdHandler) { + this.passwdHandler.closeUnderManager(); + } + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java new file mode 100644 index 00000000..31dcf12c --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java @@ -0,0 +1,113 @@ +package com.taobao.tdhs.config; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.lang.StringUtils; + +public class SecureIdentityLoginModule { + + private static byte[] ENC_KEY_BYTES = "jaas is the way".getBytes(); + + private String userName; + + private String password; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getDecodedPassword() throws Exception { + return new String(decode(password)); + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((password == null) ? 0 : password.hashCode()); + result = prime * result + ((userName == null) ? 0 : userName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + SecureIdentityLoginModule other = (SecureIdentityLoginModule) obj; + if (password == null) { + if (other.password != null) return false; + } else if (!password.equals(other.password)) return false; + if (userName == null) { + if (other.userName != null) return false; + } else if (!userName.equals(other.userName)) return false; + return true; + } + + public static String encode(String encKey, String secret) throws NoSuchAlgorithmException, NoSuchPaddingException, + InvalidKeyException, IllegalBlockSizeException, + BadPaddingException { + byte[] kbytes = SecureIdentityLoginModule.ENC_KEY_BYTES; + if (StringUtils.isNotBlank(encKey)) { + kbytes = encKey.getBytes(); + } + SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish"); + Cipher cipher = Cipher.getInstance("Blowfish"); + cipher.init(Cipher.ENCRYPT_MODE, key); + byte[] encoding = cipher.doFinal(secret.getBytes()); + BigInteger n = new BigInteger(encoding); + return n.toString(16); + } + + public static String encode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + return SecureIdentityLoginModule.encode(null, secret); + } + + public static String decode(String encKey, String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, BadPaddingException, + IllegalBlockSizeException { + byte[] kbytes = SecureIdentityLoginModule.ENC_KEY_BYTES; + if (StringUtils.isNotBlank(encKey)) { + kbytes = encKey.getBytes(); + } + SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish"); + BigInteger n = new BigInteger(secret, 16); + byte[] encoding = n.toByteArray(); + Cipher cipher = Cipher.getInstance("Blowfish"); + cipher.init(Cipher.DECRYPT_MODE, key); + byte[] decode = cipher.doFinal(encoding); + return new String(decode); + } + + public static char[] decode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + return SecureIdentityLoginModule.decode(null, secret).toCharArray(); + } + + public static void main(String[] args) throws Exception { + System.out.println("Encoded password: " + new String(SecureIdentityLoginModule.encode("Config_RsA+"))); + System.out.println("decoded password: " + + new String(SecureIdentityLoginModule.decode("-5ba6f4c59342aa2ce70e0b8bdc250194e9eba007b67f1e12"))); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java new file mode 100644 index 00000000..2b95164d --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java @@ -0,0 +1,189 @@ +package com.taobao.tdhs.config; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.alibaba.common.lang.StringUtil; +import com.alibaba.common.lang.io.ByteArrayInputStream; + +/** + * TAtomæ•°æ®æºçš„æŽ¨é€é…置解æžç±» + * + * @author qihao + */ +public class TAtomConfParser { + + private static Log logger = LogFactory.getLog(TAtomConfParser.class); + + public static final String GLOBA_IP_KEY = "ip"; + public static final String GLOBA_PORT_KEY = "port"; + public static final String GLOBA_DB_NAME_KEY = "dbName"; + public static final String GLOBA_DB_TYPE_KEY = "dbType"; + public static final String GLOBA_DB_STATUS_KEY = "dbStatus"; + public static final String APP_USER_NAME_KEY = "userName"; + public static final String APP_MIN_POOL_SIZE_KEY = "minPoolSize"; + public static final String APP_MAX_POOL_SIZE_KEY = "maxPoolSize"; + public static final String APP_IDLE_TIMEOUT_KEY = "idleTimeout"; + public static final String APP_BLOCKING_TIMEOUT_KEY = "blockingTimeout"; + public static final String APP_PREPARED_STATEMENT_CACHE_SIZE_KEY = "preparedStatementCacheSize"; + public static final String APP_ORACLE_CON_TYPE_KEY = "oracleConType"; + public static final String APP_CON_PROP_KEY = "connectionProperties"; + public static final String PASSWD_ENC_PASSWD_KEY = "encPasswd"; + public static final String PASSWD_ENC_KEY_KEY = "encKey"; + /** + * 写,次数é™åˆ¶ + */ + public static final String APP_WRITE_RESTRICT_TIMES = "writeRestrictTimes"; + /** + * 读,次数é™åˆ¶ + */ + public static final String APP_READ_RESTRICT_TIMES = "readRestrictTimes"; + /** + * thread count 次数é™åˆ¶ + */ + public static final String APP_THREAD_COUNT_RESTRICT = "threadCountRestrict"; + + public static final String APP_TIME_SLICE_IN_MILLS = "timeSliceInMillis"; + + public static TAtomDsConfDO parserTAtomDsConfDO(String globaConfStr, String appConfStr) { + TAtomDsConfDO pasObj = new TAtomDsConfDO(); + if (StringUtil.isNotBlank(globaConfStr)) { + Properties globaProp = TAtomConfParser.parserConfStr2Properties(globaConfStr); + if (!globaProp.isEmpty()) { + String ip = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_IP_KEY)); + if (StringUtil.isNotBlank(ip)) { + pasObj.setIp(ip); + } + String port = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_PORT_KEY)); + if (StringUtil.isNotBlank(port)) { + pasObj.setPort(port); + } + String dbName = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_NAME_KEY)); + if (StringUtil.isNotBlank(dbName)) { + pasObj.setDbName(dbName); + } + String dbType = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_TYPE_KEY)); + if (StringUtil.isNotBlank(dbType)) { + pasObj.setDbType(dbType); + } + String dbStatus = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_STATUS_KEY)); + if (StringUtil.isNotBlank(dbStatus)) { + pasObj.setDbStatus(dbStatus); + } + } + } + if (StringUtil.isNotBlank(appConfStr)) { + Properties appProp = TAtomConfParser.parserConfStr2Properties(appConfStr); + if (!appProp.isEmpty()) { + String userName = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_USER_NAME_KEY)); + if (StringUtil.isNotBlank(userName)) { + pasObj.setUserName(userName); + } + String oracleConType = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_ORACLE_CON_TYPE_KEY)); + if (StringUtil.isNotBlank(oracleConType)) { + pasObj.setOracleConType(oracleConType); + } + String minPoolSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_MIN_POOL_SIZE_KEY)); + if (StringUtil.isNotBlank(minPoolSize) && StringUtil.isNumeric(minPoolSize)) { + pasObj.setMinPoolSize(Integer.valueOf(minPoolSize)); + } + String maxPoolSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_MAX_POOL_SIZE_KEY)); + if (StringUtil.isNotBlank(maxPoolSize) && StringUtil.isNumeric(maxPoolSize)) { + pasObj.setMaxPoolSize(Integer.valueOf(maxPoolSize)); + } + String idleTimeout = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_IDLE_TIMEOUT_KEY)); + if (StringUtil.isNotBlank(idleTimeout) && StringUtil.isNumeric(idleTimeout)) { + pasObj.setIdleTimeout(Long.valueOf(idleTimeout)); + } + String blockingTimeout = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_BLOCKING_TIMEOUT_KEY)); + if (StringUtil.isNotBlank(blockingTimeout) && StringUtil.isNumeric(blockingTimeout)) { + pasObj.setBlockingTimeout(Integer.valueOf(blockingTimeout)); + } + String preparedStatementCacheSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_PREPARED_STATEMENT_CACHE_SIZE_KEY)); + if (StringUtil.isNotBlank(preparedStatementCacheSize) + && StringUtil.isNumeric(preparedStatementCacheSize)) { + pasObj.setPreparedStatementCacheSize(Integer.valueOf(preparedStatementCacheSize)); + } + + String writeRestrictTimes = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_WRITE_RESTRICT_TIMES)); + if (StringUtil.isNotBlank(writeRestrictTimes) && StringUtil.isNumeric(writeRestrictTimes)) { + pasObj.setWriteRestrictTimes(Integer.valueOf(writeRestrictTimes)); + } + + String readRestrictTimes = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_READ_RESTRICT_TIMES)); + if (StringUtil.isNotBlank(readRestrictTimes) && StringUtil.isNumeric(readRestrictTimes)) { + pasObj.setReadRestrictTimes(Integer.valueOf(readRestrictTimes)); + } + String threadCountRestrict = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_THREAD_COUNT_RESTRICT)); + if (StringUtil.isNotBlank(threadCountRestrict) && StringUtil.isNumeric(threadCountRestrict)) { + pasObj.setThreadCountRestrict(Integer.valueOf(threadCountRestrict)); + } + String timeSliceInMillis = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_TIME_SLICE_IN_MILLS)); + if (StringUtil.isNotBlank(timeSliceInMillis) && StringUtil.isNumeric(timeSliceInMillis)) { + pasObj.setTimeSliceInMillis(Integer.valueOf(timeSliceInMillis)); + } + + String conPropStr = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_CON_PROP_KEY)); + Map connectionProperties = parserConPropStr2Map(conPropStr); + if (null != connectionProperties && !connectionProperties.isEmpty()) { + pasObj.setConnectionProperties(connectionProperties); + } + } + } + return pasObj; + } + + public static Map parserConPropStr2Map(String conPropStr) { + Map connectionProperties = null; + if (StringUtil.isNotBlank(conPropStr)) { + String[] keyValues = StringUtil.split(conPropStr, ";"); + if (null != keyValues && keyValues.length > 0) { + connectionProperties = new HashMap(keyValues.length); + for (String keyValue : keyValues) { + String key = StringUtil.substringBefore(keyValue, "="); + String value = StringUtil.substringAfter(keyValue, "="); + if (StringUtil.isNotBlank(key) && StringUtil.isNotBlank(value)) { + connectionProperties.put(key, value); + } + } + } + } + return connectionProperties; + } + + public static String parserPasswd(String passwdStr) { + String passwd = null; + Properties passwdProp = TAtomConfParser.parserConfStr2Properties(passwdStr); + String encPasswd = passwdProp.getProperty(TAtomConfParser.PASSWD_ENC_PASSWD_KEY); + if (StringUtil.isNotBlank(encPasswd)) { + String encKey = passwdProp.getProperty(TAtomConfParser.PASSWD_ENC_KEY_KEY); + try { + passwd = SecureIdentityLoginModule.decode(encKey, encPasswd); + } catch (Exception e) { + logger.error("[parserPasswd Error] decode dbPasswdError!may jdk version error!", e); + } + } + return passwd; + } + + private static Properties parserConfStr2Properties(String data) { + Properties prop = new Properties(); + if (StringUtil.isNotBlank(data)) { + ByteArrayInputStream byteArrayInputStream = null; + try { + byteArrayInputStream = new ByteArrayInputStream((data).getBytes()); + prop.load(byteArrayInputStream); + } catch (IOException e) { + logger.error("parserConfStr2Properties Error", e); + } finally { + byteArrayInputStream.close(); + } + } + return prop; + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java new file mode 100644 index 00000000..3d6e5af1 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java @@ -0,0 +1,125 @@ +package com.taobao.tdhs.config; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * TAtomæ•°æ®æºçš„常é‡è®¾ç½®ç±» + * + * @author qihao + * + */ +public class TAtomConstants { + + public final static String DEFAULT_DIAMOND_GROUP = null; + + public final static String DEFAULT_MYSQL_CHAR_SET = "gbk"; + + //public final static String ORACLE_DBTYPE_STR = "ORACLE"; + + //public final static String MYSQL_DBTYPE_STR = "MYSQL"; + + public final static String DEFAULT_ORACLE_CON_TYPE = "oci"; + + public final static String DB_STATUS_R = "R"; + + public final static String DB_STATUS_W = "W"; + + public final static String DB_STATUS_RW = "RW"; + + public final static String DB_STATUS_NA = "NA"; + + public static Map DEFAULT_ORACLE_CONNECTION_PROPERTIES = new HashMap( + 2); + static { + TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( + "SetBigStringTryClob", "true"); + TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( + "defaultRowPrefetch", "50"); + } + + public static Map DEFAULT_MYSQL_CONNECTION_PROPERTIES = new HashMap( + 1); + static { + TAtomConstants.DEFAULT_MYSQL_CONNECTION_PROPERTIES.put( + "characterEncoding", "gbk"); + } + + public final static String DEFAULT_ORACLE_DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver"; + + public final static String DEFAULT_MYSQL_DRIVER_CLASS = "com.mysql.jdbc.Driver"; + + public final static String DEFAULT_ORACLE_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.OracleExceptionSorter"; + + public final static String DEFAULT_MYSQL_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.MySQLExceptionSorter"; + + + public final static String MYSQL_INTEGRATION_SORTER_CLASS = "com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter"; + + public final static String DEFAULT_MYSQL_VALID_CONNECTION_CHECKERCLASS = "com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker"; + + /** + * 全局é…ç½®dataIdæ¨¡æ¿ + */ + private static MessageFormat GLOBAL_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.global.{0}"); + + /** + * 应用é…ç½®dataIdæ¨¡æ¿ + */ + private static MessageFormat APP_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.app.{0}.{1}"); + + private static MessageFormat PASSWD_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.passwd.{0}.{1}.{2}"); + + /** + * dbNameæ¨¡æ¿ + */ + private static MessageFormat DB_NAME_FORMAT = new MessageFormat( + "atom.dbkey.{0}^{1}"); + + /** + * æ ¹æ®dbKey获å–全局é…ç½®dataId + * + * @param dbKey + * æ•°æ®åº“åKEY + * @return + */ + public static String getGlobalDataId(String dbKey) { + return GLOBAL_FORMAT.format(new Object[] { dbKey }); + } + + /** + * æ ¹æ®åº”用åå’ŒdbKeyèŽ·å–æŒ‡å®šçš„应用é…ç½®dataId + * + * @param appName + * @param dbKey + * @return + */ + public static String getAppDataId(String appName, String dbKey) { + return APP_FORMAT.format(new Object[] { appName, dbKey }); + } + + /** + * æ ¹æ®dbKeyå’ŒuserName获得对应的passwdçš„dataId + * + * @param dbKey + * @param userName + * @return + */ + public static String getPasswdDataId(String dbName, String dbType, + String userName) { + return PASSWD_FORMAT.format(new Object[] { dbName, dbType, userName }); + } + + /** + * @param appName + * @param dbkey + * @return + */ + public static String getDbNameStr(String appName, String dbkey) { + return DB_NAME_FORMAT.format(new Object[] { appName, dbkey }); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java new file mode 100644 index 00000000..12764693 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java @@ -0,0 +1,294 @@ +package com.taobao.tdhs.config; + +import java.util.HashMap; +import java.util.Map; + +import com.alibaba.common.lang.StringUtil; + +/** + * TAtomæ•°æ®æºå…¨å±€å’Œåº”用é…置的DO + * + * @author qihao + * @author shenxun + * + */ +public class TAtomDsConfDO implements Cloneable { + + private String ip; + + private String port; + + private String dbName; + + private String userName; + + private String passwd; + + private String driverClass; + + private String sorterClass; + + private int preparedStatementCacheSize; + + private int minPoolSize; + + private int maxPoolSize; + + private int blockingTimeout; + + private long idleTimeout; + + //private String dbType; + + private String oracleConType = TAtomConstants.DEFAULT_ORACLE_CON_TYPE; + + private AtomDbTypeEnum dbTypeEnum; + + private AtomDbStatusEnum dbStautsEnum; + + private String dbStatus; + + private Map connectionProperties = new HashMap(); + + /** + * 写 次数é™åˆ¶ + */ + private int writeRestrictTimes; + + /** + * 读 次数é™åˆ¶ + */ + private int readRestrictTimes; + + /** + * 统计时间片 + */ + private int timeSliceInMillis; + + /** + * 线程技术counté™åˆ¶ + */ + private int threadCountRestrict; + + /** + * å…许并å‘读的最大个数,0为ä¸é™åˆ¶ + */ + private int maxConcurrentReadRestrict; + + /** + * å…许并å‘写的最大个数,0为ä¸é™åˆ¶ + */ + private int maxConcurrentWriteRestrict; + + private volatile boolean isSingleInGroup; + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getDbName() { + return dbName; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPasswd() { + return passwd; + } + + public void setPasswd(String passwd) { + this.passwd = passwd; + } + + public String getDriverClass() { + if (StringUtil.isBlank(driverClass) && null != this.dbTypeEnum) { + return this.dbTypeEnum.getDriverClass(); + } + return driverClass; + } + + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + public String getSorterClass() { + if (StringUtil.isBlank(sorterClass) && null != this.dbTypeEnum) { + return this.dbTypeEnum.getSorterClass(); + } + return sorterClass; + } + + public void setSorterClass(String sorterClass) { + this.sorterClass = sorterClass; + } + + public int getPreparedStatementCacheSize() { + return preparedStatementCacheSize; + } + + public void setPreparedStatementCacheSize(int preparedStatementCacheSize) { + this.preparedStatementCacheSize = preparedStatementCacheSize; + } + + public int getMinPoolSize() { + return minPoolSize; + } + + public void setMinPoolSize(int minPoolSize) { + this.minPoolSize = minPoolSize; + } + + public int getMaxPoolSize() { + return maxPoolSize; + } + + public void setMaxPoolSize(int maxPoolSize) { + this.maxPoolSize = maxPoolSize; + } + + public int getBlockingTimeout() { + return blockingTimeout; + } + + public void setBlockingTimeout(int blockingTimeout) { + this.blockingTimeout = blockingTimeout; + } + + public long getIdleTimeout() { + return idleTimeout; + } + + public void setIdleTimeout(long idleTimeout) { + this.idleTimeout = idleTimeout; + } + + public Map getConnectionProperties() { + return connectionProperties; + } + + public String getDbType() { + return dbTypeEnum.name().toLowerCase(); + } + + public void setDbType(String dbType) { + this.dbTypeEnum = AtomDbTypeEnum.getAtomDbTypeEnumByType(dbType); + } + + public String getDbStatus() { + return dbStatus; + } + + public void setDbStatus(String dbStatus) { + this.dbStatus = dbStatus; + if (StringUtil.isNotBlank(dbStatus)) { + this.dbStautsEnum = AtomDbStatusEnum.getAtomDbStatusEnumByType(dbStatus); + } + } + + public AtomDbStatusEnum getDbStautsEnum() { + return dbStautsEnum; + } + + public AtomDbTypeEnum getDbTypeEnum() { + return dbTypeEnum; + } + + public void setConnectionProperties(Map connectionProperties) { + this.connectionProperties = connectionProperties; + } + + public String getOracleConType() { + return oracleConType; + } + + public void setOracleConType(String oracleConType) { + this.oracleConType = oracleConType; + } + + public int getWriteRestrictTimes() { + return writeRestrictTimes; + } + + public void setWriteRestrictTimes(int writeRestrictTimes) { + this.writeRestrictTimes = writeRestrictTimes; + } + + public int getReadRestrictTimes() { + return readRestrictTimes; + } + + public void setReadRestrictTimes(int readRestrictTimes) { + this.readRestrictTimes = readRestrictTimes; + } + + public int getThreadCountRestrict() { + return threadCountRestrict; + } + + public void setThreadCountRestrict(int threadCountRestrict) { + this.threadCountRestrict = threadCountRestrict; + } + + public int getTimeSliceInMillis() { + return timeSliceInMillis; + } + + public void setTimeSliceInMillis(int timeSliceInMillis) { + this.timeSliceInMillis = timeSliceInMillis; + } + + public int getMaxConcurrentReadRestrict() { + return maxConcurrentReadRestrict; + } + + public void setMaxConcurrentReadRestrict(int maxConcurrentReadRestrict) { + this.maxConcurrentReadRestrict = maxConcurrentReadRestrict; + } + + public int getMaxConcurrentWriteRestrict() { + return maxConcurrentWriteRestrict; + } + + public void setMaxConcurrentWriteRestrict(int maxConcurrentWriteRestrict) { + this.maxConcurrentWriteRestrict = maxConcurrentWriteRestrict; + } + + public TAtomDsConfDO clone() { + TAtomDsConfDO tAtomDsConfDO = null; + try { + tAtomDsConfDO = (TAtomDsConfDO) super.clone(); + } catch (CloneNotSupportedException e) { + } + return tAtomDsConfDO; + } + + public boolean isSingleInGroup() { + return isSingleInGroup; + } + + public void setSingleInGroup(boolean isSingleInGroup) { + this.isSingleInGroup = isSingleInGroup; + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java new file mode 100644 index 00000000..50cce6bc --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java @@ -0,0 +1,318 @@ +package com.taobao.tdhs.config; + +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import org.adbcj.ConnectionManager; +import org.adbcj.mysql.netty.WrappedMysqlConnectionManager; +import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.alibaba.common.lang.StringUtil; + +/** + * æ•°æ®åº“动æ€åˆ‡æ¢çš„Handle类,所有数æ®åº“的动æ€åˆ‡æ¢ éƒ½æ˜¯ç”±è¿™ä¸ªç±»å®Œæˆ + * + * @author qihao + */ +public class TAtomDsConfHandle { + + private static Log logger = LogFactory.getLog(TAtomDsConfHandle.class); + private String appName; + + private String dbKey; + + private ConnectionManager connectionManager; + /** + * è¿è¡Œæ—¶é…ç½® + */ + private volatile TAtomDsConfDO runTimeConf = new TAtomDsConfDO(); + + /** + * 本地é…置,优先于推é€çš„动æ€é…ç½® + */ + private TAtomDsConfDO localConf = new TAtomDsConfDO(); + + /** + * 全局é…置,应用é…ç½®è®¢é˜…ç®¡ç† + */ + private DbConfManager dbConfManager; + + /** + * 密ç é…ç½®è®¢é˜…ç®¡ç† + */ + private DbPasswdManager dbPasswdManager; + + /** + * åˆå§‹åŒ–标记为一但åˆå§‹åŒ–过,所有本地的é…ç½®ç¦æ­¢æ”¹åЍ + */ + private volatile boolean initFalg; + + /** + * æ•°æ®æºæ“作é”,当需è¦å¯¹æ•°æ®æºè¿›è¡Œé‡å»ºæˆ–者刷新时需è¦å…ˆèŽ·å¾—è¯¥é” + */ + private final ReentrantLock lock = new ReentrantLock(); + + /** + * åˆå§‹åŒ–æ–¹æ³•ï¼Œåˆ›å»ºå¯¹åº”çš„æ•°æ®æºï¼Œåªèƒ½è¢«è°ƒç”¨ä¸€æ¬¡ + * + * @throws Exception + */ + public void init() throws Exception { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] double call Init !"); + } + // 1.åˆå§‹åŒ–傿•°æ£€æŸ¥ + if (StringUtil.isBlank(this.appName) || StringUtil.isBlank(this.dbKey)) { + String errorMsg = "[attributeError] TAtomDatasource of appName Or dbKey is Empty !"; + logger.error(errorMsg); + throw new AtomIllegalException(errorMsg); + } + // 2.é…ç½®dbConfManager + DiamondDbConfManager defaultDbConfManager = new DiamondDbConfManager(); + defaultDbConfManager.setGlobalConfigDataId(TAtomConstants.getGlobalDataId(this.dbKey)); + defaultDbConfManager.setAppConfigDataId(TAtomConstants.getAppDataId(this.appName, this.dbKey)); + // åˆå§‹åŒ–dbConfManager + defaultDbConfManager.init(); + dbConfManager = defaultDbConfManager; + // 3.获å–全局é…ç½® + String globaConfStr = dbConfManager.getGlobalDbConf(); + // 注册全局é…ç½®ç›‘å¬ + registerGlobaDbConfListener(defaultDbConfManager); + if (StringUtil.isBlank(globaConfStr)) { + String errorMsg = "[ConfError] read globalConfig is Empty !"; + logger.error(errorMsg); + throw new AtomInitialException(errorMsg); + } + // 4.获å–应用é…ç½® + String appConfStr = dbConfManager.getAppDbDbConf(); + // 注册应用é…ç½®ç›‘å¬ + registerAppDbConfListener(defaultDbConfManager); + if (StringUtil.isBlank(appConfStr)) { + String errorMsg = "[ConfError] read appConfig is Empty !"; + logger.error(errorMsg); + throw new AtomInitialException(errorMsg); + } + lock.lock(); + try { + // 5.è§£æžé…ç½®stringæˆTAtomDsConfDO + runTimeConf = TAtomConfParser.parserTAtomDsConfDO(globaConfStr, appConfStr); + // 6.å¤„ç†æœ¬åœ°ä¼˜å…ˆé…ç½® + overConfByLocal(localConf, runTimeConf); + // 7.如果没有设置本地密ç ï¼Œåˆ™ç”¨è®¢çš„密ç ï¼Œåˆå§‹åŒ–passwdManager + if (StringUtil.isBlank(this.runTimeConf.getPasswd())) { + // 检查dbKey和对应的userName是å¦ä¸ºç©º + if (StringUtil.isBlank(runTimeConf.getUserName())) { + String errorMsg = "[attributeError] TAtomDatasource of UserName is Empty !"; + logger.error(errorMsg); + throw new AtomIllegalException(errorMsg); + } + DiamondDbPasswdManager diamondDbPasswdManager = new DiamondDbPasswdManager(); + diamondDbPasswdManager.setPasswdConfDataId(TAtomConstants.getPasswdDataId(runTimeConf.getDbName(), + runTimeConf.getDbType(), + runTimeConf.getUserName())); + diamondDbPasswdManager.init(); + dbPasswdManager = diamondDbPasswdManager; + // 获å–å¯†ç  + String passwd = dbPasswdManager.getPasswd(); + if (StringUtil.isBlank(passwd)) { + String errorMsg = "[PasswdError] read passwd is Empty !"; + logger.error(errorMsg); + throw new AtomInitialException(errorMsg); + } + runTimeConf.setPasswd(passwd); + } + String ip = runTimeConf.getIp(); + + String port = runTimeConf.getPort(); + // 因为是epoll模型,所以连接数å‡å°‘一些 + + GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + int blockingTimeout = runTimeConf.getBlockingTimeout(); + if (blockingTimeout > -1) { + config.setBlockWhenExhausted(true); + config.setMaxWaitMillis(blockingTimeout); + } else { + config.setBlockWhenExhausted(false); + } + + int maxPoolSize = runTimeConf.getMaxPoolSize(); + if (maxPoolSize > 0) { + config.setMaxTotal(maxPoolSize); + } + int minPoolSize = runTimeConf.getMinPoolSize(); + if (minPoolSize > 0) { + config.setMinIdle(minPoolSize); + } + config.setLifo(false); + connectionManager = new WrappedMysqlConnectionManager(ip, + Integer.valueOf(port), + runTimeConf.getUserName(), + runTimeConf.getPasswd(), + runTimeConf.getDbName(), + null, + config); + initFalg = true; + } finally { + lock.unlock(); + } + } + + /** + * 全局é…置监å¬,全局é…ç½®å‘生å˜åŒ–, 需è¦é‡æ–°FLUSHæ•°æ®æº + * + * @param defaultDbConfManager + */ + private void registerGlobaDbConfListener(DbConfManager dbConfManager) { + dbConfManager.registerGlobaDbConfListener(new ConfigDataListener() { + + public void onDataRecieved(String dataId, String data) { + logger.error("[GlobaConf HandleData] dataId : " + dataId + " data: " + data); + if (null == data || StringUtil.isBlank(data)) { + return; + } + lock.lock(); + try { + } finally { + lock.unlock(); + } + } + + }); + } + + /** + * 应用é…置监å¬ï¼Œå½“应用é…ç½®å‘生å˜åŒ–时,区分å‘生 å˜åŒ–çš„é…置,æ¥å†³å®šå…·ä½“是flush还是reCreate + * + * @param defaultDbConfManager + */ + private void registerAppDbConfListener(DbConfManager dbConfManager) { + dbConfManager.registerAppDbConfListener(new ConfigDataListener() { + + public void onDataRecieved(String dataId, String data) { + logger.error("[AppConf HandleData] dataId : " + dataId + " data: " + data); + if (null == data || StringUtil.isBlank(data)) { + return; + } + lock.lock(); + try { + String appConfStr = data; + TAtomDsConfDO tmpConf = TAtomConfParser.parserTAtomDsConfDO(null, appConfStr); + TAtomDsConfDO newConf = TAtomDsConfHandle.this.runTimeConf.clone(); + // 有些既有é…ç½®ä¸èƒ½å˜æ›´ï¼Œæ‰€ä»¥å…‹éš†è€çš„é…置,然åŽå°†æ–°çš„set进去 + newConf.setUserName(tmpConf.getUserName()); + newConf.setMinPoolSize(tmpConf.getMinPoolSize()); + newConf.setMaxPoolSize(tmpConf.getMaxPoolSize()); + newConf.setIdleTimeout(tmpConf.getIdleTimeout()); + newConf.setBlockingTimeout(tmpConf.getBlockingTimeout()); + newConf.setPreparedStatementCacheSize(tmpConf.getPreparedStatementCacheSize()); + newConf.setConnectionProperties(tmpConf.getConnectionProperties()); + newConf.setOracleConType(tmpConf.getOracleConType()); + // 增加3个具体的实现 + newConf.setWriteRestrictTimes(tmpConf.getWriteRestrictTimes()); + newConf.setReadRestrictTimes(tmpConf.getReadRestrictTimes()); + newConf.setThreadCountRestrict(tmpConf.getThreadCountRestrict()); + newConf.setTimeSliceInMillis(tmpConf.getTimeSliceInMillis()); + // å¤„ç†æœ¬åœ°ä¼˜å…ˆé…ç½® + overConfByLocal(TAtomDsConfHandle.this.localConf, newConf); + // 转æ¢tAtomDsConfDO + // 检查转æ¢åŽç»“æžœæ˜¯å¦æ­£ç¡® + } finally { + lock.unlock(); + } + } + + }); + } + + /** + * 是用本地é…置覆盖传入的TAtomDsConfDO的属性 + * + * @param tAtomDsConfDO + */ + private void overConfByLocal(TAtomDsConfDO localDsConfDO, TAtomDsConfDO newDsConfDO) { + if (null == newDsConfDO || null == localDsConfDO) { + return; + } + if (StringUtil.isNotBlank(localDsConfDO.getDriverClass())) { + newDsConfDO.setDriverClass(localDsConfDO.getDriverClass()); + } + if (StringUtil.isNotBlank(localDsConfDO.getSorterClass())) { + newDsConfDO.setSorterClass(localDsConfDO.getSorterClass()); + } + if (StringUtil.isNotBlank(localDsConfDO.getPasswd())) { + newDsConfDO.setPasswd(localDsConfDO.getPasswd()); + } + if (null != localDsConfDO.getConnectionProperties() && !localDsConfDO.getConnectionProperties().isEmpty()) { + newDsConfDO.setConnectionProperties(localDsConfDO.getConnectionProperties()); + } + } + + void setSingleInGroup(boolean isSingleInGroup) { + this.runTimeConf.setSingleInGroup(isSingleInGroup); + } + + public void setAppName(String appName) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset appName !"); + } + this.appName = appName; + } + + public void setDbKey(String dbKey) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset dbKey !"); + } + this.dbKey = dbKey; + } + + public void setLocalPasswd(String passwd) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset passwd !"); + } + this.localConf.setPasswd(passwd); + } + + public void setLocalConnectionProperties(Map map) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset connectionProperties !"); + } + this.localConf.setConnectionProperties(map); + } + + public void setLocalDriverClass(String driverClass) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset driverClass !"); + } + this.localConf.setDriverClass(driverClass); + } + + public void setLocalSorterClass(String sorterClass) throws AtomAlreadyInitException { + if (initFalg) { + throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset sorterClass !"); + } + this.localConf.setSorterClass(sorterClass); + } + + public String getAppName() { + return appName; + } + + public String getDbKey() { + return dbKey; + } + + public AtomDbStatusEnum getStatus() { + return this.runTimeConf.getDbStautsEnum(); + } + + public AtomDbTypeEnum getDbType() { + return this.runTimeConf.getDbTypeEnum(); + } + + public ConnectionManager getConnectionManager() { + return connectionManager; + } + +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java new file mode 100644 index 00000000..d3a7f14a --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java @@ -0,0 +1,13 @@ +//Copyright(c) Taobao.com +package com.taobao.tdhs.config; +/** + * @description TDDL整个工程的常é‡ç±» + * @author junyu + * @version 1.0 + * @since 1.6 + * @date 2011-5-23上åˆ09:54:49 + */ +public class TDDLConstant { + //åˆæ¬¡èŽ·å–diamondé…置超时时间 + public static final long DIAMOND_GET_DATA_TIMEOUT=10*1000; +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java new file mode 100644 index 00000000..f646e539 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java @@ -0,0 +1,152 @@ +package com.taobao.tdhs.config.group; + +import java.util.ArrayList; +import java.util.List; + +import org.adbcj.ConnectionManager; +import org.adbcj.mysql.netty.AtomMysqlConnectionManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.taobao.tdhs.config.ConfigDataHandler; +import com.taobao.tdhs.config.ConfigDataHandlerFactory; +import com.taobao.tdhs.config.ConfigDataListener; +import com.taobao.tdhs.config.DefaultConfigDataHandlerFactory; + +/** + * 一个ConfigManager对应一个TGroupDataSource, + * 主è¦ç”¨äºŽå°†æ ¹æ®Groupçš„dataIDå–得的对应é…置字符串信(比如db0:rwp1q1i0, db1:rwp0q0i1), + * 转化为真正的Group层的é…置体系结构:一个Group层挂ç€ä¸¤ä¸ªAtom db0 与 db1 , 则我们使用一个 Map æ¥è¡¨ç¤º 其中的String 为æ¯ä¸ªAtom DS çš„dbKey ,DataSourceWrapper + * 为ç»è¿‡å°è£…çš„TAtomDataSource + * ---这里需è¦è§£é‡Šä¸€ä¸‹ï¼Œä¸ºä»€ä¹ˆä¸ç›´æŽ¥ä½¿ç”¨AtomDataSource?因为æ¯ä¸ªAtomDataSource还有相应的æƒé‡å’Œä¼˜å…ˆçº§ä¿¡æ¯ 因此,需è¦***方法 + * 其中,é…置的æ¯ä¸€ä¸ªAtom DataSourceä¹Ÿåªæ˜¯ç”¨Atom + * çš„dbKeyè¡¨ç¤ºï¼Œå› æ­¤ï¼Œæˆ‘ä»¬è¿˜éœ€è¦æ ¹æ®æ­¤dbKeyå–å¾—Atomçš„é…置信æ¯ï¼Œå¹¶ä¸”将它å°è£…æˆä¸€ä¸ªAtomDataSource对象。 因此需è¦***方法 + * 有了这个map能根æ®dbKey迅速的找到对应的Datasource也是ä¸å¤Ÿçš„,我们的Groupå±‚åº”è¯¥æ˜¯å¯¹åº”ç”¨é€æ˜Žçš„, + * å› æ­¤ï¼Œå½“æˆ‘ä»¬çš„è¯»å†™è¯·æ±‚è¿›æ¥æ—¶ï¼ŒGroup层应该能够根æ®é…置的æƒé‡å’Œä¼˜å…ˆçº§ï¼Œè‡ªåŠ¨çš„é€‰æ‹©ä¸€ä¸ªåˆé€‚çš„DB上进行读写, + * 所以,我们还需è¦å°†é…置信æ¯ç”Ÿæˆä¸€ä¸ªDBSelectoræ¥è‡ªåŠ¨çš„å®Œæˆæ ¹æ®æƒé‡ã€ä¼˜å…ˆçº§é€‰æ‹©åˆé€‚的目标库 因此,需è¦***方法 + * + * @author yangzhu + * @author linxuan refactor + */ +public class ConfigManager { + + private static final Log logger = LogFactory.getLog(ConfigManager.class); + + private final ConfigDataListener configReceiver; // //åŠ¨æ€æŽ¥æ”¶Diamond推é€è¿‡æ¥çš„ä¿¡æ¯ + private ConfigDataHandlerFactory configFactory; + private ConfigDataHandler globalHandler; + + // add by junyu + + private String fullGroupKey; + private String appName = null; + + private int configReceiveTimeout = 20000; + private List atomTdhsClient = new ArrayList(); + private WeightSelector writeSelector = new WeightSelector(); + private WeightSelector readSelector = new WeightSelector(); + + public ConfigManager(){ + configReceiver = new ConfigReceiver(); + } + + /** + * 从Diamondé…置中心æå–ä¿¡æ¯ï¼Œæž„造TAtomDataSourceã€æž„造有优先级信æ¯çš„读写DBSelector ---add by + * mazhidan.pt + */ + public void init() { + // 警告: ä¸è¦åœ¨æž„造DefaultDiamondManager时就注册ManagerListener(比如:configReceiver) + // 也就是说,ä¸è¦è¿™æ ·ç”¨: new DefaultDiamondManager(dbGroupKey, configReceiver), + // 而是è¦è®¾æˆnull,等第一次å–å¾—ä¿¡æ¯å¹¶è§£æžå®ŒæˆåŽå†æ³¨å†Œï¼Œè¿™æ ·å¯ä»¥ä¸ç”¨åŒæ­¥ï¼Œé¿å…任何与并å‘相关的问题, + // 因为有å¯èƒ½åœ¨ç¬¬ä¸€æ¬¡åˆšå–回信æ¯åŽï¼ŒDiamondé…置中心那边马上修改了记录,导致ManagerListener这个线程立刻收到信æ¯ï¼Œ + // 造æˆåˆå§‹åŒ–线程和ManagerListenerçº¿ç¨‹åŒæ—¶è§£æžä¿¡æ¯ã€‚ + configFactory = new DefaultConfigDataHandlerFactory(); + globalHandler = configFactory.getConfigDataHandler(fullGroupKey, null); + + String dsWeightCommaStr = globalHandler.getData(configReceiveTimeout, + ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); + String[] dbArray = dsWeightCommaStr.split(","); // 逗å·åˆ†éš”:db0:rwp1q1i0, + for (String db : dbArray) { + String[] dbNameAndWeight = db.split(":"); + if (dbNameAndWeight.length != 2) { + throw new IllegalArgumentException("weight can't find " + db); + } + String dbKey = dbNameAndWeight[0]; + String weightStr = dbNameAndWeight[1]; + Weight weight = new Weight(weightStr); + int w = weight.w; + AtomMysqlConnectionManager one = new AtomMysqlConnectionManager(); + try { + one.setAppName(appName); + one.setDbKey(dbKey); + one.init(); + } catch (Exception e) { + throw new RuntimeException(e); + } + int index = atomTdhsClient.size(); + atomTdhsClient.add(one); + for (int i = 0; i < w; i++) { + writeSelector.add(index); + } + + int r = weight.r; + for (int i = 0; i < r; i++) { + readSelector.add(index); + } + } + + } + + public String getFullGroupKey() { + return fullGroupKey; + } + + public void setFullGroupKey(String fullGroupKey) { + this.fullGroupKey = fullGroupKey; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public List getAtomTdhsClient() { + return atomTdhsClient; + } + + public void setAtomTdhsClient(List atomTdhsClient) { + this.atomTdhsClient = atomTdhsClient; + } + + public WeightSelector getWriteSelector() { + return writeSelector; + } + + public void setWriteSelector(WeightSelector writeSelector) { + this.writeSelector = writeSelector; + } + + public WeightSelector getReadSelector() { + return readSelector; + } + + public void setReadSelector(WeightSelector readSelector) { + this.readSelector = readSelector; + } + + private class ConfigReceiver implements ConfigDataListener { + + public void onDataRecieved(String dataId, String data) { + try { + logger.warn("group ds data received !dataId:" + dataId + " data:" + data); + logger.warn("not allow"); + } catch (Throwable t) { + logger.error("动æ€è§£æžé…ç½®ä¿¡æ¯æ—¶å‡ºçŽ°é”™è¯¯:" + data, t); + } + } + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java new file mode 100644 index 00000000..e9c77e4c --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java @@ -0,0 +1,131 @@ +package com.taobao.tdhs.config.group; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author jiechen.qzm + */ +public class GroupExtraConfig { + /** + * when set this parameter is true,table not in tableDsIndexMap or sql not + * in sqlDsIndexMap, this sql will be forced go to main db, priority is + * low(compare to local seted dataSourceIndex, + * tableDsIndexMap,sqlDsIndexMap),higher than weight select. + * + * add by junyu,2011-11-01 + */ + private boolean defaultMain = false; + + /** + * this map define the actual_table and dataSourceIndex relation + * + * add by junyu,2011-11-01 + */ + private Map tableDsIndexMap = new HashMap(); + + /** + * this map define the sql and dataSourceIndex relation + * + * add by junyu,2011-11-01 + */ + private Map sqlDsIndexMap = new HashMap(); + + /** + * this list contain the sqls whitch are forbidden + * add by jiechen,2011-12-29 + */ + private Set sqlForbidSet = new HashSet(); + + public boolean isDefaultMain() { + return defaultMain; + } + + public void setDefaultMain(boolean defaultMain) { + this.defaultMain = defaultMain; + } + + public Map getTableDsIndexMap() { + return tableDsIndexMap; + } + + public void setTableDsIndexMap(Map tableDsIndexMap) { + this.tableDsIndexMap = tableDsIndexMap; + } + + public Map getSqlDsIndexMap() { + return sqlDsIndexMap; + } + + public void setSqlDsIndexMap(Map sqlDsIndexMap) { + this.sqlDsIndexMap = sqlDsIndexMap; + } + + public Set getSqlForbidSet() { + return sqlForbidSet; + } + + public void setSqlForbidSet(Set sqlForbidSet) { + this.sqlForbidSet = sqlForbidSet; + } + + /*public Boolean getDefaultMain() { + return defaultMain; + } + + public void setDefaultMain(Boolean defaultMain) { + this.defaultMain = defaultMain; + } + + public void clearDefaultMain() { + this.defaultMain = false; + } + + public Map getTableDsIndexMap() { + return tableDsIndexMap; + } + + public void setTableDsIndexMap(Map tableDsIndexMap) { + this.clearTableDsIndexMap(); + this.tableDsIndexMap.putAll(tableDsIndexMap); + } + + public void clearTableDsIndexMap() { + this.tableDsIndexMap.clear(); + } + + public Map getSqlDsIndexMap() { + return sqlDsIndexMap; + } + + public void setSqlDsIndexMap(Map sqlDsIndexMap) { + this.clearSqlDsIndexMap(); + this.sqlDsIndexMap.putAll(sqlDsIndexMap); + } + + public void clearSqlDsIndexMap() { + this.sqlDsIndexMap.clear(); + } + + public Set getSqlForbidSet() { + return sqlForbidSet; + } + + public void setSqlForbidSet(Set sqlForbidSet) { + this.clearSqlForbinSet(); + this.sqlForbidSet.addAll(sqlForbidSet); + } + + public void clearSqlForbinSet() { + this.sqlForbidSet.clear(); + } + + public void clearAll() { + this.clearDefaultMain(); + this.clearTableDsIndexMap(); + this.clearSqlDsIndexMap(); + this.clearSqlForbinSet(); + }*/ +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java new file mode 100644 index 00000000..e2ae4827 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java @@ -0,0 +1,155 @@ +package com.taobao.tdhs.config.group; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + *

æ•°æ®åº“æƒé‡é…置,æƒé‡è¶Šå¤§ï¼Œè¢«é€‰ä¸­çš„æœºçŽ‡è¶Šå¤§. + * + *

æƒé‡é…置模å¼: + *

[r|R](\\d*) [w|W](\\d*) [p|P](\\d*) [q|Q](\\d*) [i|I](\\d*) + * + *

å­—æ¯r或R表示å¯ä»¥å¯¹æ•°æ®åº“进行读æ“作, åŽé¢è·Ÿä¸€ä¸ªæ•°å­—表示读æ“作的æƒé‡ï¼Œå¦‚果字æ¯r或RåŽé¢æ²¡æœ‰æ•°å­—,则默认是10; + * + *

å­—æ¯w或W表示å¯ä»¥å¯¹æ•°æ®åº“进行写æ“作, åŽé¢è·Ÿä¸€ä¸ªæ•°å­—表示写æ“作的æƒé‡ï¼Œå¦‚果字æ¯w或WåŽé¢æ²¡æœ‰æ•°å­—,则默认是10;< + * + *

å­—æ¯p或P表示读æ“作的优先级, 数字越大优先级越高,读æ“作优先从优先级最高的数æ®åº“中读数æ®ï¼Œ + * 如果字æ¯p或PåŽé¢æ²¡æœ‰æ•°å­—,则默认优先级是0; + * + *

å­—æ¯q或Q表示写æ“作的优先级, 数字越大优先级越高,写æ“作优先从优先级最高的数æ®åº“中写数æ®ï¼Œ + * 如果字æ¯q或QåŽé¢æ²¡æœ‰æ•°å­—,则默认优先级是0. + * + *

å­—æ¯i或I表示动æ€DBIndex, 和用户通过threadLocal指定的dbIndex结åˆï¼Œå®žçްrwä¹‹ä¸Šæ›´çµæ´»çš„路由 + * 一个dbå¯ä»¥åŒæ—¶é…置多个iï¼›ä¸åŒçš„dbå¯ä»¥é…置相åŒçš„i,例如 db0:i0i2,db1:i1,db2:i1,db3:i2则 + * 用户指定dbIndex=0,路由到db0ï¼›ï¼ˆåªæœ‰db0有i0) + * 用户指定dbIndex=1ï¼Œéšæœºè·¯ç”±åˆ°db1å’Œdb2;(db1å’Œdb2都有i1) + * 用户指定dbIndex=2ï¼Œéšæœºè·¯ç”±åˆ°db0å’Œdb3;(db0å’Œdb3都有i2) + * + *

如:db1: r10w10p2, db2: r20p2, db3: rp3,则对应如下三个Weight: + * db1: Weight(r10w10p2) + * db2: Weight(r20p2) + * db3: Weight(rp3) + * + *

在这个例å­ä¸­ï¼Œå¯¹db1, db2,db3这三个数æ®åº“的读æ“作分æˆäº†ä¸¤ä¸ªä¼˜å…ˆçº§: + * p3->[db3] + * p2->[db1, db2] + * + * 当进行读æ“作时,因为db3的优先级最高,所以优先从db3读, + * 如果db3无法进行读æ“作,å†ä»Ždb1, db2ä¸­éšæœºé€‰ä¸€ä¸ªï¼Œå› ä¸ºdb2的读æƒé‡æ˜¯20,而db1是10,所以db2被选中的机率比db1更大。 + * + *

如果在数æ®åº“ååŽé¢æ²¡æœ‰è®¾ç½®æƒé‡å­—符串,就认为æƒé‡å­—符串是null, + * 如: db1: r10w10, db2, db3,则对应如下三个Weight: + * db1: Weight(r10w10) + * db2: Weight(null) + * db3: Weight(null) + * + *

为了兼容2.4之å‰çš„è€ç‰ˆæœ¬ï¼Œå½“æƒé‡å­—符串是null时,相当于"r10w10p0q0", + * 对于上é¢çš„例å­ï¼Œå®žé™…的数æ®åº“æƒé‡é…置是:db1: r10w10p0q0, db2: r10w10p0q0, db3: r10w10p0q0。 + * + * @author yangzhu + * @author linxuan add indexes i/I at 2011/01/21 + * + */ +public class Weight { + private static final Pattern weightPattern_r = Pattern.compile("[R](\\d*)"); + private static final Pattern weightPattern_w = Pattern.compile("[W](\\d*)"); + private static final Pattern weightPattern_p = Pattern.compile("[P](\\d*)"); + private static final Pattern weightPattern_q = Pattern.compile("[Q](\\d*)"); + private static final Pattern weightPattern_i = Pattern.compile("[I](\\d*)"); + + /** + * 读æƒé‡ï¼Œé»˜è®¤æ˜¯10 + */ + public final int r; + + /** + * 写æƒé‡ï¼Œé»˜è®¤æ˜¯10 + */ + public final int w; + + /** + * 读优先级,默认是0 + */ + public final int p; + + /** + * 写优先级,默认是0 + */ + public final int q; + + public final Set indexes; + + public Weight(String weightStr) { + //兼容2.4之å‰çš„è€ç‰ˆæœ¬ï¼Œå½“æƒé‡å­—符串是null时,相当于"r10w10p0q0", + if (weightStr == null) { + r = 10; + w = 10; + p = 0; + q = 0; + indexes = null; + } else { + weightStr = weightStr.trim().toUpperCase(); + + //如果字æ¯'R'在weightStr中找ä¸åˆ°ï¼Œåˆ™è¯»æƒé‡æ˜¯0, + //如果字æ¯'R'在weightStr中已找到了,但是在字æ¯'R'åŽé¢æ²¡æœ‰æ•°å­—,是读æƒé‡æ˜¯10 + r = getUnitWeight(weightStr, 'R', weightPattern_r, 0, 10); + + w = getUnitWeight(weightStr, 'W', weightPattern_w, 0, 10); + + p = getUnitWeight(weightStr, 'P', weightPattern_p, 0, 0); + + q = getUnitWeight(weightStr, 'Q', weightPattern_q, 0, 0); + + indexes = getUnitWeights(weightStr, 'I', weightPattern_i); + + } + } + + public String toString() { + return "Weight[r=" + r + ", w=" + w + ", p=" + p + ", q=" + q + ", indexes=" + indexes + "]"; + } + + //如果字符c在weightStr中找ä¸åˆ°ï¼Œåˆ™è¿”回defaultValue1, + //如果字符c在weightSträ¸­å·²ç»æ‰¾åˆ°äº†ï¼Œä½†æ˜¯åœ¨å­—æ¯cåŽé¢æ²¡æœ‰æ•°å­—,则返回defaultValue2, + //å¦åˆ™è¿”回字æ¯cåŽé¢ 的数字. + private static int getUnitWeight(String weightStr, char c, Pattern p, int defaultValue1, int defaultValue2) { + if (weightStr.indexOf(c) == -1) { + return defaultValue1; + } else { + Matcher m = p.matcher(weightStr); + m.find(); + + if (m.group(1).length() == 0) { + return defaultValue2; + } else { + return Integer.parseInt(m.group(1)); + } + } + } + + private static Set getUnitWeights(String weightStr, char c, Pattern p) { + if (weightStr.indexOf(c) == -1) { + return null; + } + Set is = new HashSet(); + int start = 0; + Matcher m = p.matcher(weightStr); + while (m.find(start)) { + if (m.group(1).length() != 0) { + is.add(Integer.valueOf(m.group(1))); + } + start = m.end(); + } + return is; + } + + public static void main(String[] args) { + System.out.println(new Weight("wr0i1")); + System.out.println(new Weight("wr0i0I1")); + System.out.println(new Weight("i0w10I1r20")); + System.out.println(new Weight("i0w10I1r20i3")); + } +} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java new file mode 100644 index 00000000..54002ea1 --- /dev/null +++ b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java @@ -0,0 +1,120 @@ +package com.taobao.tdhs.config.group; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Random; + + +public class WeightSelector { + Random ran = new Random(); + + List index = new ArrayList(); + + public Integer getIndex() + { + return index.get(ran.nextInt(index.size())); + } + public void add(int arg0, Integer arg1) { + index.add(arg0, arg1); + } + + public boolean add(Integer arg0) { + return index.add(arg0); + } + + public boolean addAll(Collection arg0) { + return index.addAll(arg0); + } + + public boolean addAll(int arg0, Collection arg1) { + return index.addAll(arg0, arg1); + } + + public void clear() { + index.clear(); + } + + public boolean contains(Object arg0) { + return index.contains(arg0); + } + + public boolean containsAll(Collection arg0) { + return index.containsAll(arg0); + } + + public boolean equals(Object arg0) { + return index.equals(arg0); + } + + public Integer get(int arg0) { + return index.get(arg0); + } + + public int hashCode() { + return index.hashCode(); + } + + public int indexOf(Object arg0) { + return index.indexOf(arg0); + } + + public boolean isEmpty() { + return index.isEmpty(); + } + + public Iterator iterator() { + return index.iterator(); + } + + public int lastIndexOf(Object arg0) { + return index.lastIndexOf(arg0); + } + + public ListIterator listIterator() { + return index.listIterator(); + } + + public ListIterator listIterator(int arg0) { + return index.listIterator(arg0); + } + + public Integer remove(int arg0) { + return index.remove(arg0); + } + + public boolean remove(Object arg0) { + return index.remove(arg0); + } + + public boolean removeAll(Collection arg0) { + return index.removeAll(arg0); + } + + public boolean retainAll(Collection arg0) { + return index.retainAll(arg0); + } + + public Integer set(int arg0, Integer arg1) { + return index.set(arg0, arg1); + } + + public int size() { + return index.size(); + } + + public List subList(int arg0, int arg1) { + return index.subList(arg0, arg1); + } + + public Object[] toArray() { + return index.toArray(); + } + + public T[] toArray(T[] arg0) { + return index.toArray(arg0); + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java new file mode 100644 index 00000000..01f9cec9 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java @@ -0,0 +1,88 @@ +package org.adbcj.mysql.netty; + +import java.util.HashMap; +import java.util.Map; + +import org.adbcj.Connection; +import org.adbcj.ConnectionManager; +import org.adbcj.DbException; +import org.adbcj.DbFuture; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.taobao.tdhs.config.AtomAlreadyInitException; +import com.taobao.tdhs.config.TAtomDsConfHandle; + +public class AtomMysqlConnectionManager implements ConnectionManager { + + private static Map cacheConfHandleMap = new HashMap(); + + private final static Log logger = LogFactory.getLog(AtomMysqlConnectionManager.class); + TAtomDsConfHandle atomTdhs = new TAtomDsConfHandle(); + protected volatile boolean inited = false; + + public void setAppName(String appName) throws AtomAlreadyInitException { + atomTdhs.setAppName(appName); + } + + public void setDbKey(String dbKey) throws AtomAlreadyInitException { + atomTdhs.setDbKey(dbKey); + } + + public String getAppName() { + return atomTdhs.getAppName(); + } + + public String getDbKey() { + return atomTdhs.getDbKey(); + } + + public void init() { + if (inited) { + return; + } + inited = true; + try { + String dbName = TAtomConstants.getDbNameStr(this.getAppName(), this.getDbKey()); + synchronized (cacheConfHandleMap) { + TAtomDsConfHandle cacheConfHandle = cacheConfHandleMap.get(dbName); + if (null == cacheConfHandle) { + // åˆå§‹åŒ–config的管ç†å™¨ + this.atomTdhs.init(); + cacheConfHandleMap.put(dbName, atomTdhs); + logger.info("create new TAtomDsConfHandle dbName : " + dbName); + } else { + atomTdhs = cacheConfHandle; + logger.info("use the cache TAtomDsConfHandle dbName : " + dbName); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public DbFuture connect() { + init(); + return atomTdhs.getConnectionManager().connect(); + } + + public DbFuture close(boolean immediate) throws DbException { + init(); + return atomTdhs.getConnectionManager().close(immediate); + } + + public boolean isClosed() { + init(); + return atomTdhs.getConnectionManager().isClosed(); + } + + public boolean isPipeliningEnabled() { + init(); + return atomTdhs.getConnectionManager().isPipeliningEnabled(); + } + + public void setPipeliningEnabled(boolean pipeliningEnabled) { + init(); + atomTdhs.getConnectionManager().setPipeliningEnabled(pipeliningEnabled); + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java new file mode 100644 index 00000000..83ee6fbd --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java @@ -0,0 +1,108 @@ +package org.adbcj.mysql.netty; + +import org.adbcj.Connection; +import org.adbcj.ConnectionManager; +import org.adbcj.DbException; +import org.adbcj.DbFuture; + +import com.taobao.tdhs.config.group.ConfigManager; +import com.taobao.tdhs.config.group.WeightSelector; + +/** + * TODO !! ç›®å‰åªå…许写主机。。 简略一点为了先能跑通 + * http://gitlab.alibaba-inc.com/shenxun/adbjc-tb/issues/2785 + * + * @author Whisper 2013-6-21 下åˆ3:12:42 + * @since 3.0.1 + */ +public class GroupMysqlConnectionManager implements ConnectionManager { + + private static String VERSION = "2.4.1"; + private static String PREFIX = "com.taobao.tddl.jdbc.group_V" + VERSION + "_"; + private String dbGroupKey; + private String fullDbGroupKey = null; + private String appName; + private ConfigManager configManager = new ConfigManager(); + protected volatile boolean inited = false; + + public void init() { + if (inited) { + return; + } + inited = true; + configManager.setAppName(appName); + configManager.setFullGroupKey(getFullDbGroupKey()); + configManager.init(); + // db1:rwp0q0i1 + } + + public GroupMysqlConnectionManager(String dbGroupKey, String appName){ + super(); + this.dbGroupKey = dbGroupKey; + this.appName = appName; + } + + public ConnectionManager getClient(boolean isWrite) { + int index = 0; + if (isWrite) { + WeightSelector ws = configManager.getWriteSelector(); + index = ws.getIndex(); + + } else { + WeightSelector ws = configManager.getReadSelector(); + index = ws.getIndex(); + } + return configManager.getAtomTdhsClient().get(index); + } + + public static String getFullDbGroupKey(String dbGroupKey) { + return PREFIX + dbGroupKey; + } + + public String getFullDbGroupKey() { + if (fullDbGroupKey == null) fullDbGroupKey = PREFIX + getDbGroupKey(); + return fullDbGroupKey; + } + + public String getDbGroupKey() { + return dbGroupKey; + } + + public void setDbGroupKey(String dbGroupKey) { + this.dbGroupKey = dbGroupKey; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public DbFuture connect() { + init(); + return getClient(true).connect(); + } + + public DbFuture close(boolean immediate) throws DbException { + init(); + return getClient(true).close(immediate); + } + + public boolean isClosed() { + init(); + return getClient(true).isClosed(); + } + + public boolean isPipeliningEnabled() { + init(); + return getClient(true).isPipeliningEnabled(); + } + + public void setPipeliningEnabled(boolean pipeliningEnabled) { + init(); + getClient(true).setPipeliningEnabled(pipeliningEnabled); + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java index a650bd77..9d49f30e 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java @@ -15,6 +15,10 @@ public class MySqlConnectionManagerFactory implements ConnectionManagerFactory { public ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) throws DbException { + String host = null; + int port = 0; + String schema = null; + try { /* * Parse URL @@ -23,8 +27,8 @@ public ConnectionManager createConnectionManager(String url, String username, St // Throw away the 'adbcj' protocol part of the URL uri = new URI(uri.getSchemeSpecificPart()); - String host = uri.getHost(); - int port = uri.getPort(); + host = uri.getHost(); + port = uri.getPort(); if (port < 0) { port = DEFAULT_PORT; } @@ -32,12 +36,13 @@ public ConnectionManager createConnectionManager(String url, String username, St if (path.length() == 0 || "/".equals(path)) { throw new DbException("You must specific a database in the URL path"); } - String schema = path.substring(1); + schema = path.substring(1); - return new MysqlConnectionManager(host, port, username, password, schema, properties); - } catch (URISyntaxException e) { + } catch (URISyntaxException e) { throw new DbException(e); } + return new MysqlConnectionManager(host, port, username, password, schema, properties); + } diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java index b1f66e28..1b3676d0 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java @@ -5,15 +5,14 @@ import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import org.adbcj.Connection; -import org.adbcj.DbFuture; import org.adbcj.mysql.codec.AbstractMySqlConnectionManager; import org.adbcj.mysql.codec.ClientRequest; import org.adbcj.mysql.codec.MySqlClientDecoder; import org.adbcj.mysql.codec.MySqlClientEncoder; import org.adbcj.mysql.codec.ProtocolHandler; -import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPool; import org.adbcj.support.DefaultDbFuture; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; @@ -41,116 +40,126 @@ import org.slf4j.LoggerFactory; public class MysqlConnectionManager extends AbstractMySqlConnectionManager { - private static final Logger logger = LoggerFactory.getLogger(MysqlConnectionManager.class); - - private static final String QUEUE_HANDLER = MysqlConnectionManager.class.getName() + ".queueHandler"; - private static final String ENCODER = MysqlConnectionManager.class.getName() + ".encoder"; - private static final String DECODER = MysqlConnectionManager.class.getName() + ".decoder"; - - private final ExecutorService executorService; - private final ClientBootstrap bootstrap; - - public MysqlConnectionManager(String host, int port, String username, String password, String schema, Properties properties) { - super(username, password, schema, properties); - executorService = Executors.newCachedThreadPool(); - - ChannelFactory factory = new NioClientSocketChannelFactory(executorService, executorService); - bootstrap = new ClientBootstrap(factory); - init(host, port); - } - - public MysqlConnectionManager(String host, int port, String username, String password, String schema, Properties properties, ChannelFactory factory) { - super(username, password, schema, properties); - executorService = null; - bootstrap = new ClientBootstrap(factory); - init(host, port); - } - - private void init(String host, int port) { - bootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = Channels.pipeline(); - - pipeline.addFirst(QUEUE_HANDLER, new MessageQueuingHandler()); - - pipeline.addLast(DECODER, new Decoder()); - pipeline.addLast(ENCODER, new Encoder()); - - return pipeline; - } - }); - bootstrap.setOption("tcpNoDelay", true); - bootstrap.setOption("keepAlive", true); - bootstrap.setOption("remoteAddress", new InetSocketAddress(host, port)); - } - - - protected void dispose() { - if (executorService != null) { - executorService.shutdownNow(); - } - } - - - protected DefaultDbFuture createConnectionFuture() { - final ChannelFuture channelFuture = bootstrap.connect(); - return new MysqlConnectFuture(channelFuture); - } - - class MysqlConnectFuture extends DefaultDbFuture { - private final ChannelFuture channelFuture; - - public MysqlConnectFuture(ChannelFuture channelFuture) { - this.channelFuture = channelFuture; - channelFuture.addListener(new ChannelFutureListener() { - - public void operationComplete(ChannelFuture future) throws Exception { - logger.debug("Connect completed"); - - Channel channel = future.getChannel(); - MysqlConnection connection = new MysqlConnection(MysqlConnectionManager.this, getCredentials(), channel, MysqlConnectFuture.this); - channel.getPipeline().addLast("handler", new Handler(connection)); - MessageQueuingHandler queuingHandler = channel.getPipeline().get(MessageQueuingHandler.class); - synchronized (queuingHandler) { - queuingHandler.flush(); - channel.getPipeline().remove(queuingHandler); - } - - } - }); - } - - - protected boolean doCancel(boolean mayInterruptIfRunning) { - return channelFuture.cancel(); - } - } + + private static final Logger logger = LoggerFactory.getLogger(MysqlConnectionManager.class); + + private static final String QUEUE_HANDLER = MysqlConnectionManager.class.getName() + ".queueHandler"; + private static final String ENCODER = MysqlConnectionManager.class.getName() + ".encoder"; + private static final String DECODER = MysqlConnectionManager.class.getName() + ".decoder"; + + private final ExecutorService executorService; + private final ClientBootstrap bootstrap; + + public MysqlConnectionManager(String host, int port, String username, String password, String schema, + Properties properties){ + super(username, password, schema, properties); + ThreadFactory threadFactory = new ThreadFactory() { + + public Thread newThread(Runnable r) { + Thread thd = new Thread(r); + thd.setDaemon(true); + return thd; + } + }; + executorService = Executors.newCachedThreadPool(threadFactory); + + ChannelFactory factory = new NioClientSocketChannelFactory(executorService, executorService); + bootstrap = new ClientBootstrap(factory); + init(host, port); + } + + public MysqlConnectionManager(String host, int port, String username, String password, String schema, + Properties properties, ChannelFactory factory){ + super(username, password, schema, properties); + executorService = null; + bootstrap = new ClientBootstrap(factory); + init(host, port); + } + + private void init(String host, int port) { + bootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = Channels.pipeline(); + + pipeline.addFirst(QUEUE_HANDLER, new MessageQueuingHandler()); + + pipeline.addLast(DECODER, new Decoder()); + pipeline.addLast(ENCODER, new Encoder()); + + return pipeline; + } + }); + bootstrap.setOption("tcpNoDelay", true); + bootstrap.setOption("keepAlive", true); + bootstrap.setOption("remoteAddress", new InetSocketAddress(host, port)); + } + + protected void dispose() { + if (executorService != null) { + executorService.shutdownNow(); + } + } + + protected DefaultDbFuture createConnectionFuture() { + final ChannelFuture channelFuture = bootstrap.connect(); + return new MysqlConnectFuture(channelFuture); + } + + class MysqlConnectFuture extends DefaultDbFuture { + + private final ChannelFuture channelFuture; + + public MysqlConnectFuture(ChannelFuture channelFuture){ + this.channelFuture = channelFuture; + channelFuture.addListener(new ChannelFutureListener() { + + public void operationComplete(ChannelFuture future) throws Exception { + logger.debug("Connect completed"); + + Channel channel = future.getChannel(); + MysqlConnection connection = new MysqlConnection(MysqlConnectionManager.this, + getCredentials(), + channel, + MysqlConnectFuture.this); + channel.getPipeline().addLast("handler", new Handler(connection)); + MessageQueuingHandler queuingHandler = channel.getPipeline().get(MessageQueuingHandler.class); + synchronized (queuingHandler) { + queuingHandler.flush(); + channel.getPipeline().remove(queuingHandler); + } + + } + }); + } + + protected boolean doCancel(boolean mayInterruptIfRunning) { + return channelFuture.cancel(); + } + } } @ChannelPipelineCoverage("one") class Decoder extends FrameDecoder { - private final MySqlClientDecoder decoder = new MySqlClientDecoder(); + private final MySqlClientDecoder decoder = new MySqlClientDecoder(); - - protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { - InputStream in = new ChannelBufferInputStream(buffer); - try { - return decoder.decode(in, false); - } finally { - in.close(); - } - } + protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { + InputStream in = new ChannelBufferInputStream(buffer); + try { + return decoder.decode(in, false); + } finally { + in.close(); + } + } } -@ChannelPipelineCoverage("all") class Encoder implements ChannelDownstreamHandler { - private final MySqlClientEncoder encoder = new MySqlClientEncoder(); + private final MySqlClientEncoder encoder = new MySqlClientEncoder(); - public void handleDownstream(ChannelHandlerContext context, ChannelEvent event) throws Exception { + public void handleDownstream(ChannelHandlerContext context, ChannelEvent event) throws Exception { if (!(event instanceof MessageEvent)) { context.sendDownstream(event); return; @@ -164,38 +173,35 @@ public void handleDownstream(ChannelHandlerContext context, ChannelEvent event) ChannelBuffer buffer = ChannelBuffers.buffer(1024); ChannelBufferOutputStream out = new ChannelBufferOutputStream(buffer); - encoder.encode((ClientRequest) e.getMessage(), out); - Channels.write(context, e.getFuture(), buffer); - } + encoder.encode((ClientRequest) e.getMessage(), out); + Channels.write(context, e.getFuture(), buffer); + } } @ChannelPipelineCoverage("one") class Handler extends SimpleChannelHandler { - private final MysqlConnection connection; - private final ProtocolHandler handler = new ProtocolHandler(); - - public Handler(MysqlConnection connection) { - this.connection = connection; - } - - - public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - handler.messageReceived(connection, e.getMessage()); - } - - - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - Throwable t = handler.handleException(connection, e.getCause()); - if (t != null) { - // TODO: Pass exception on to connectionManager - t.printStackTrace(); - } - } - - - public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - handler.connectionClosed(connection); - } - -} \ No newline at end of file + private final MysqlConnection connection; + private final ProtocolHandler handler = new ProtocolHandler(); + + public Handler(MysqlConnection connection){ + this.connection = connection; + } + + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + handler.messageReceived(connection, e.getMessage()); + } + + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + Throwable t = handler.handleException(connection, e.getCause()); + if (t != null) { + // TODO: Pass exception on to connectionManager + t.printStackTrace(); + } + } + + public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + handler.connectionClosed(connection); + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java new file mode 100644 index 00000000..ec9400b2 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java @@ -0,0 +1,125 @@ +package org.adbcj.mysql.netty; + +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; + +/** + * TAtomæ•°æ®æºçš„常é‡è®¾ç½®ç±» + * + * @author qihao + * + */ +public class TAtomConstants { + + public final static String DEFAULT_DIAMOND_GROUP = null; + + public final static String DEFAULT_MYSQL_CHAR_SET = "gbk"; + + //public final static String ORACLE_DBTYPE_STR = "ORACLE"; + + //public final static String MYSQL_DBTYPE_STR = "MYSQL"; + + public final static String DEFAULT_ORACLE_CON_TYPE = "oci"; + + public final static String DB_STATUS_R = "R"; + + public final static String DB_STATUS_W = "W"; + + public final static String DB_STATUS_RW = "RW"; + + public final static String DB_STATUS_NA = "NA"; + + public static Map DEFAULT_ORACLE_CONNECTION_PROPERTIES = new HashMap( + 2); + static { + TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( + "SetBigStringTryClob", "true"); + TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( + "defaultRowPrefetch", "50"); + } + + public static Map DEFAULT_MYSQL_CONNECTION_PROPERTIES = new HashMap( + 1); + static { + TAtomConstants.DEFAULT_MYSQL_CONNECTION_PROPERTIES.put( + "characterEncoding", "gbk"); + } + + public final static String DEFAULT_ORACLE_DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver"; + + public final static String DEFAULT_MYSQL_DRIVER_CLASS = "com.mysql.jdbc.Driver"; + + public final static String DEFAULT_ORACLE_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.OracleExceptionSorter"; + + public final static String DEFAULT_MYSQL_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.MySQLExceptionSorter"; + + + public final static String MYSQL_INTEGRATION_SORTER_CLASS = "com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter"; + + public final static String DEFAULT_MYSQL_VALID_CONNECTION_CHECKERCLASS = "com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker"; + + /** + * 全局é…ç½®dataIdæ¨¡æ¿ + */ + private static MessageFormat GLOBAL_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.global.{0}"); + + /** + * 应用é…ç½®dataIdæ¨¡æ¿ + */ + private static MessageFormat APP_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.app.{0}.{1}"); + + private static MessageFormat PASSWD_FORMAT = new MessageFormat( + "com.taobao.tddl.atom.passwd.{0}.{1}.{2}"); + + /** + * dbNameæ¨¡æ¿ + */ + private static MessageFormat DB_NAME_FORMAT = new MessageFormat( + "atom.dbkey.{0}^{1}"); + + /** + * æ ¹æ®dbKey获å–全局é…ç½®dataId + * + * @param dbKey + * æ•°æ®åº“åKEY + * @return + */ + public static String getGlobalDataId(String dbKey) { + return GLOBAL_FORMAT.format(new Object[] { dbKey }); + } + + /** + * æ ¹æ®åº”用åå’ŒdbKeyèŽ·å–æŒ‡å®šçš„应用é…ç½®dataId + * + * @param appName + * @param dbKey + * @return + */ + public static String getAppDataId(String appName, String dbKey) { + return APP_FORMAT.format(new Object[] { appName, dbKey }); + } + + /** + * æ ¹æ®dbKeyå’ŒuserName获得对应的passwdçš„dataId + * + * @param dbKey + * @param userName + * @return + */ + public static String getPasswdDataId(String dbName, String dbType, + String userName) { + return PASSWD_FORMAT.format(new Object[] { dbName, dbType, userName }); + } + + /** + * @param appName + * @param dbkey + * @return + */ + public static String getDbNameStr(String appName, String dbkey) { + return DB_NAME_FORMAT.format(new Object[] { appName, dbkey }); + } +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java index cf30b504..1f8ac930 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java @@ -1,33 +1,82 @@ package org.adbcj.mysql.netty; import org.adbcj.Connection; +import org.adbcj.ConnectionManager; +import org.adbcj.DbException; import org.adbcj.DbFuture; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; - -public class WrappedMysqlConnection implements PoolableObjectFactory { - private MysqlConnectionManager connectionManager = null; - public Connection makeObject() throws Exception { - DbFuture conn = connectionManager.connect(); - return conn.get(); - } - - public void destroyObject(Connection conn) throws Exception { - conn.close(true); - } - - public boolean validateObject(Connection obj) { - Connection conn = (Connection)obj; - return !conn.isClosed(); - } - - public void activateObject(Connection obj) throws Exception { - - } - - public void passivateObject(Connection obj) throws Exception { - - } - - - +import org.adbcj.DbSessionFuture; +import org.adbcj.PreparedStatement; +import org.adbcj.Result; +import org.adbcj.ResultEventHandler; +import org.adbcj.ResultSet; +import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; +import org.adbcj.support.DefaultDbSessionFuture; + +public class WrappedMysqlConnection implements Connection { + + protected final ObjectPool pool; + protected final Connection conn; + + public WrappedMysqlConnection(Connection conn, ObjectPool pool){ + this.pool = pool; + this.conn = conn; + } + + public synchronized DbSessionFuture close(boolean immediate) throws DbException { + try { + pool.returnObject(conn); + } catch (Exception e) { + throw new DbException(e); + } + return new DefaultDbSessionFuture(null); + } + + public void beginTransaction() { + conn.beginTransaction(); + } + + public DbSessionFuture commit() { + return conn.commit(); + } + + public ConnectionManager getConnectionManager() { + return conn.getConnectionManager(); + } + + public DbFuture ping() { + return conn.ping(); + } + + public DbSessionFuture rollback() { + return conn.rollback(); + } + + public boolean isInTransaction() { + return conn.isInTransaction(); + } + + public DbSessionFuture executeQuery(String sql) { + return conn.executeQuery(sql); + } + + public DbSessionFuture executeQuery(String sql, ResultEventHandler eventHandler, T accumulator) { + return conn.executeQuery(sql, eventHandler, accumulator); + } + + public DbSessionFuture executeUpdate(String sql) { + return conn.executeUpdate(sql); + } + + public DbSessionFuture prepareStatement(String sql) { + return conn.prepareStatement(sql); + } + + public DbSessionFuture prepareStatement(Object key, String sql) { + return conn.prepareStatement(key, sql); + } + + public boolean isClosed() throws DbException { + return conn.isClosed(); + } + } diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java new file mode 100644 index 00000000..d3e76c97 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java @@ -0,0 +1,96 @@ +package org.adbcj.mysql.netty; + +import java.util.Properties; + +import org.adbcj.Connection; +import org.adbcj.mysql.codec.AbstractMySqlConnectionManager; +import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; +import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPool; +import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.adbcj.support.DefaultDbFuture; + +public class WrappedMysqlConnectionManager extends AbstractMySqlConnectionManager { + + private MysqlConnectionManager plainMySQLConnectionManager = null; + private GenericObjectPoolConfig config = new GenericObjectPoolConfig(); + + ObjectPool pool = null; + + public WrappedMysqlConnectionManager(String host, int port, String username, String password, String schema, + Properties properties){ + super(username, password, schema, properties); + this.plainMySQLConnectionManager = new MysqlConnectionManager(host, + port, + username, + password, + schema, + properties); + PoolableObjectFactory factory = new WrappedMysqlConnectionPoolableObject(plainMySQLConnectionManager); + config.setLifo(false); + config.setMaxTotal(10); + config.setMaxIdle(5); + config.setMinIdle(1); + config.setMaxWaitMillis(5 * 1000); + pool = new GenericObjectPool(factory, config); + } + + public WrappedMysqlConnectionManager(String host, int port, String username, String password, String schema, + Properties properties, GenericObjectPoolConfig config){ + super(username, password, schema, properties); + this.plainMySQLConnectionManager = new MysqlConnectionManager(host, + port, + username, + password, + schema, + properties); + PoolableObjectFactory factory = new WrappedMysqlConnectionPoolableObject(plainMySQLConnectionManager); + pool = new GenericObjectPool(factory, config); + } + + @Override + protected void dispose() { + try { + plainMySQLConnectionManager.dispose(); + + } finally { + pool.close(); + } + } + + @Override + protected DefaultDbFuture createConnectionFuture() { + DefaultDbFuture dbFuture = new DefaultDbFuture(); + try { + dbFuture.setResult(new WrappedMysqlConnection(pool.borrowObject(), pool)); + } catch (Exception e) { + dbFuture.setException(e); + } + return dbFuture; + } + + public MysqlConnectionManager getPlainMySQLConnectionManager() { + return plainMySQLConnectionManager; + } + + public void setPlainMySQLConnectionManager(MysqlConnectionManager plainMySQLConnectionManager) { + this.plainMySQLConnectionManager = plainMySQLConnectionManager; + } + + public GenericObjectPoolConfig getConfig() { + return config; + } + + public void setConfig(GenericObjectPoolConfig config) { + this.config = config; + } + + public ObjectPool getPool() { + return pool; + } + + public void setPool(ObjectPool pool) { + this.pool = pool; + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java new file mode 100644 index 00000000..b15bd7e4 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java @@ -0,0 +1,54 @@ +package org.adbcj.mysql.netty; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Properties; + +import org.adbcj.ConnectionManager; +import org.adbcj.ConnectionManagerFactory; +import org.adbcj.DbException; + +public class WrappedMysqlConnectionManagerFactory implements ConnectionManagerFactory { + + private WrappedMysqlConnectionManager connectionManager = null; + + public static final String PROTOCOL = "pooledMysqlnetty"; + public static final int DEFAULT_PORT = 3306; + + public ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) + throws DbException { + String host = null; + int port = 0; + String schema = null; + + try { + /* + * Parse URL + */ + URI uri = new URI(url); + // Throw away the 'adbcj' protocol part of the URL + uri = new URI(uri.getSchemeSpecificPart()); + + host = uri.getHost(); + port = uri.getPort(); + if (port < 0) { + port = DEFAULT_PORT; + } + String path = uri.getPath().trim(); + if (path.length() == 0 || "/".equals(path)) { + throw new DbException("You must specific a database in the URL path"); + } + schema = path.substring(1); + + } catch (URISyntaxException e) { + throw new DbException(e); + } + connectionManager = new WrappedMysqlConnectionManager(host, port, username, password, schema, properties); + return connectionManager; + } + + public boolean canHandle(String protocol) { + return PROTOCOL.equalsIgnoreCase(protocol); + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java new file mode 100644 index 00000000..d58ee4a6 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java @@ -0,0 +1,39 @@ +package org.adbcj.mysql.netty; + +import org.adbcj.Connection; +import org.adbcj.DbFuture; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; + +public class WrappedMysqlConnectionPoolableFactory implements PoolableObjectFactory { + private MysqlConnectionManager connectionManager = null; + + public WrappedMysqlConnectionPoolableFactory(MysqlConnectionManager connectionManager) { + super(); + this.connectionManager = connectionManager; + } + + public Connection makeObject() throws Exception { + DbFuture conn = connectionManager.connect(); + return conn.get(); + } + + public void destroyObject(Connection conn) throws Exception { + conn.close(true); + } + + public boolean validateObject(Connection obj) { + Connection conn = (Connection)obj; + return !conn.isClosed(); + } + + public void activateObject(Connection obj) throws Exception { + + } + + public void passivateObject(Connection obj) throws Exception { + + } + + + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java new file mode 100644 index 00000000..3b791a4c --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java @@ -0,0 +1,38 @@ +package org.adbcj.mysql.netty; + +import org.adbcj.Connection; +import org.adbcj.DbFuture; +import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; + +public class WrappedMysqlConnectionPoolableObject implements PoolableObjectFactory { + + private MysqlConnectionManager connectionManager = null; + + public WrappedMysqlConnectionPoolableObject(MysqlConnectionManager connectionManager){ + super(); + this.connectionManager = connectionManager; + } + + public Connection makeObject() throws Exception { + DbFuture conn = connectionManager.connect(); + return conn.get(); + } + + public void destroyObject(Connection conn) throws Exception { + conn.close(true); + } + + public boolean validateObject(Connection obj) { + Connection conn = (Connection) obj; + return !conn.isClosed(); + } + + public void activateObject(Connection obj) throws Exception { + + } + + public void passivateObject(Connection obj) throws Exception { + + } + +} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java index 1f8a309d..13169da3 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java @@ -22,147 +22,151 @@ * defined by the public constants. *

* This class is not thread-safe. - * + * * @version $Revision: $ - * * @since 2.0 */ public abstract class BaseObjectPoolConfig implements Cloneable { /** * The default value for the {@code lifo} configuration attribute. + * * @see GenericObjectPool#getLifo() * @see GenericKeyedObjectPool#getLifo() */ - public static final boolean DEFAULT_LIFO = true; + public static final boolean DEFAULT_LIFO = true; /** * The default value for the {@code maxWait} configuration attribute. + * * @see GenericObjectPool#getMaxWaitMillis() * @see GenericKeyedObjectPool#getMaxWaitMillis() */ - public static final long DEFAULT_MAX_WAIT_MILLIS = -1L; + public static final long DEFAULT_MAX_WAIT_MILLIS = -1L; /** * The default value for the {@code minEvictableIdleTimeMillis} * configuration attribute. + * * @see GenericObjectPool#getMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() */ - public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = - 1000L * 60L * 30L; + public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L; /** * The default value for the {@code softMinEvictableIdleTimeMillis} * configuration attribute. + * * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() */ - public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1; + public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1; /** * The default value for the {@code numTestsPerEvictionRun} configuration * attribute. + * * @see GenericObjectPool#getNumTestsPerEvictionRun() * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() */ - public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; + public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; /** * The default value for the {@code testOnBorrow} configuration attribute. + * * @see GenericObjectPool#getTestOnBorrow() * @see GenericKeyedObjectPool#getTestOnBorrow() */ - public static final boolean DEFAULT_TEST_ON_BORROW = false; + public static final boolean DEFAULT_TEST_ON_BORROW = false; /** * The default value for the {@code testOnReturn} configuration attribute. + * * @see GenericObjectPool#getTestOnReturn() * @see GenericKeyedObjectPool#getTestOnReturn() */ - public static final boolean DEFAULT_TEST_ON_RETURN = false; + public static final boolean DEFAULT_TEST_ON_RETURN = false; /** * The default value for the {@code testWhileIdle} configuration attribute. + * * @see GenericObjectPool#getTestWhileIdle() * @see GenericKeyedObjectPool#getTestWhileIdle() */ - public static final boolean DEFAULT_TEST_WHILE_IDLE = false; + public static final boolean DEFAULT_TEST_WHILE_IDLE = false; /** * The default value for the {@code timeBetweenEvictionRunsMillis} * configuration attribute. + * * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() */ - public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; + public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; /** * The default value for the {@code blockWhenExhausted} configuration * attribute. + * * @see GenericObjectPool#getBlockWhenExhausted() * @see GenericKeyedObjectPool#getBlockWhenExhausted() */ - public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true; + public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true; /** * The default value for enabling JMX for pools created with a configuration * instance. */ - public static final boolean DEFAULT_JMX_ENABLE = true; + public static final boolean DEFAULT_JMX_ENABLE = true; /** * The default value for the prefix used to name JMX enabled pools created * with a configuration instance. + * * @see GenericObjectPool#getJmxName() * @see GenericKeyedObjectPool#getJmxName() */ - public static final String DEFAULT_JMX_NAME_PREFIX = "pool"; + public static final String DEFAULT_JMX_NAME_PREFIX = "pool"; /** * The default value for the {@code evictionPolicyClassName} configuration * attribute. + * * @see GenericObjectPool#getEvictionPolicyClassName() * @see GenericKeyedObjectPool#getEvictionPolicyClassName() */ - public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = - "org.apache.commons.pool2.impl.DefaultEvictionPolicy"; - - - private boolean lifo = DEFAULT_LIFO; + public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = "org.adbcj.mysql.netty.org.apache.commons.pool2.impl.DefaultEvictionPolicy"; - private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS; + private boolean lifo = DEFAULT_LIFO; - private long minEvictableIdleTimeMillis = - DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS; - private long softMinEvictableIdleTimeMillis = - DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; + private long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - private int numTestsPerEvictionRun = - DEFAULT_NUM_TESTS_PER_EVICTION_RUN; + private long softMinEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME; + private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; - private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; + private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME; - private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; + private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; - private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE; + private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; - private long timeBetweenEvictionRunsMillis = - DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; + private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE; - private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED; + private long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; - private boolean jmxEnabled = DEFAULT_JMX_ENABLE; + private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED; - private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX; + private boolean jmxEnabled = DEFAULT_JMX_ENABLE; + private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX; /** * Get the value for the {@code lifo} configuration attribute for pools * created with this configuration instance. + * * @see GenericObjectPool#getLifo() * @see GenericKeyedObjectPool#getLifo() */ @@ -173,6 +177,7 @@ public boolean getLifo() { /** * Set the value for the {@code lifo} configuration attribute for pools * created with this configuration instance. + * * @see GenericObjectPool#getLifo() * @see GenericKeyedObjectPool#getLifo() */ @@ -183,6 +188,7 @@ public void setLifo(boolean lifo) { /** * Get the value for the {@code maxWait} configuration attribute for pools * created with this configuration instance. + * * @see GenericObjectPool#getMaxWaitMillis() * @see GenericKeyedObjectPool#getMaxWaitMillis() */ @@ -193,6 +199,7 @@ public long getMaxWaitMillis() { /** * Set the value for the {@code maxWait} configuration attribute for pools * created with this configuration instance. + * * @see GenericObjectPool#getMaxWaitMillis() * @see GenericKeyedObjectPool#getMaxWaitMillis() */ @@ -203,6 +210,7 @@ public void setMaxWaitMillis(long maxWaitMillis) { /** * Get the value for the {@code minEvictableIdleTimeMillis} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() */ @@ -213,6 +221,7 @@ public long getMinEvictableIdleTimeMillis() { /** * Set the value for the {@code minEvictableIdleTimeMillis} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() */ @@ -224,6 +233,7 @@ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { * Get the value for the {@code softMinEvictableIdleTimeMillis} * configuration attribute for pools created with this configuration * instance. + * * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() */ @@ -235,17 +245,18 @@ public long getSoftMinEvictableIdleTimeMillis() { * Set the value for the {@code softMinEvictableIdleTimeMillis} * configuration attribute for pools created with this configuration * instance. + * * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() */ - public void setSoftMinEvictableIdleTimeMillis( - long softMinEvictableIdleTimeMillis) { + public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) { this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; } /** * Get the value for the {@code numTestsPerEvictionRun} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getNumTestsPerEvictionRun() * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() */ @@ -256,6 +267,7 @@ public int getNumTestsPerEvictionRun() { /** * Set the value for the {@code numTestsPerEvictionRun} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getNumTestsPerEvictionRun() * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() */ @@ -266,6 +278,7 @@ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { /** * Get the value for the {@code testOnBorrow} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestOnBorrow() * @see GenericKeyedObjectPool#getTestOnBorrow() */ @@ -276,6 +289,7 @@ public boolean getTestOnBorrow() { /** * Set the value for the {@code testOnBorrow} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestOnBorrow() * @see GenericKeyedObjectPool#getTestOnBorrow() */ @@ -286,6 +300,7 @@ public void setTestOnBorrow(boolean testOnBorrow) { /** * Get the value for the {@code testOnReturn} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestOnReturn() * @see GenericKeyedObjectPool#getTestOnReturn() */ @@ -296,6 +311,7 @@ public boolean getTestOnReturn() { /** * Set the value for the {@code testOnReturn} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestOnReturn() * @see GenericKeyedObjectPool#getTestOnReturn() */ @@ -306,6 +322,7 @@ public void setTestOnReturn(boolean testOnReturn) { /** * Get the value for the {@code testWhileIdle} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestWhileIdle() * @see GenericKeyedObjectPool#getTestWhileIdle() */ @@ -316,6 +333,7 @@ public boolean getTestWhileIdle() { /** * Set the value for the {@code testWhileIdle} configuration attribute for * pools created with this configuration instance. + * * @see GenericObjectPool#getTestWhileIdle() * @see GenericKeyedObjectPool#getTestWhileIdle() */ @@ -326,6 +344,7 @@ public void setTestWhileIdle(boolean testWhileIdle) { /** * Get the value for the {@code timeBetweenEvictionRunsMillis} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() */ @@ -336,17 +355,18 @@ public long getTimeBetweenEvictionRunsMillis() { /** * Set the value for the {@code timeBetweenEvictionRunsMillis} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() */ - public void setTimeBetweenEvictionRunsMillis( - long timeBetweenEvictionRunsMillis) { + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } /** * Get the value for the {@code evictionPolicyClassName} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getEvictionPolicyClassName() * @see GenericKeyedObjectPool#getEvictionPolicyClassName() */ @@ -357,6 +377,7 @@ public String getEvictionPolicyClassName() { /** * Set the value for the {@code evictionPolicyClassName} configuration * attribute for pools created with this configuration instance. + * * @see GenericObjectPool#getEvictionPolicyClassName() * @see GenericKeyedObjectPool#getEvictionPolicyClassName() */ @@ -367,6 +388,7 @@ public void setEvictionPolicyClassName(String evictionPolicyClassName) { /** * Get the value for the {@code blockWhenExhausted} configuration attribute * for pools created with this configuration instance. + * * @see GenericObjectPool#getBlockWhenExhausted() * @see GenericKeyedObjectPool#getBlockWhenExhausted() */ @@ -377,6 +399,7 @@ public boolean getBlockWhenExhausted() { /** * Set the value for the {@code blockWhenExhausted} configuration attribute * for pools created with this configuration instance. + * * @see GenericObjectPool#getBlockWhenExhausted() * @see GenericKeyedObjectPool#getBlockWhenExhausted() */ diff --git a/mysql/netty/src/test/java/Test.java b/mysql/netty/src/test/java/Test.java index 9b686be4..c4dd3c55 100644 --- a/mysql/netty/src/test/java/Test.java +++ b/mysql/netty/src/test/java/Test.java @@ -7,7 +7,7 @@ public class Test { public static void main(String[] args) throws DbException, Exception { - ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:mysqlnetty://localhost/test", "foo", "dawg"); + ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:pooledMysqlnetty://localhost/test", "foo", "dawg"); Connection connection = cm.connect().get(); connection.close(true); } From bd290bcda6f08b21b834644b0e4cb822cb3cd85b Mon Sep 17 00:00:00 2001 From: shenxun Date: Thu, 27 Jun 2013 10:34:03 +0800 Subject: [PATCH 03/17] =?UTF-8?q?=20=E6=8F=90=E4=BA=A4common=20pool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql/netty/pom.xml | 37 +++++- .../apache/commons/pool2/impl/package.html | 42 ++++++ .../org/apache/commons/pool2/overview.html | 121 ++++++++++++++++++ .../org/apache/commons/pool2/package.html | 63 +++++++++ .../org.adbcj.ConnectionManagerFactory | 1 + 5 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html create mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html diff --git a/mysql/netty/pom.xml b/mysql/netty/pom.xml index 1029acc5..49117eea 100644 --- a/mysql/netty/pom.xml +++ b/mysql/netty/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 - org.adbcj + org.adbcj mysql-build 1.0-tb-SNAPSHOT @@ -21,10 +19,39 @@ netty ${netty.version} + + commons-lang + commons-lang + 2.6 + + + + org.slf4j + slf4j-api + + + log4j + log4j + 1.2.16 + + + org.slf4j + slf4j-log4j12 + + + + com.taobao.diamond + diamond-client + 2.0.5.3 + ${project.groupId} mysql-codec + + org.slf4j + slf4j-log4j12 + diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html new file mode 100644 index 00000000..11dbec2f --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html @@ -0,0 +1,42 @@ + + + + + Package Documentation for org.apache.commons.pool2.impl + + +

+ Object pooling API implementations. +

+

+ {@link org.apache.commons.pool2.impl.GenericObjectPool GenericObjectPool} + ({@link org.apache.commons.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool}) + provides a more robust (but also more complicated) + implementation of {@link org.apache.commons.pool2.ObjectPool ObjectPool} + ({@link org.apache.commons.pool2.KeyedObjectPool KeyedObjectPool}). +

+

+ {@link org.apache.commons.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool} + provides a {@link java.lang.ref.SoftReference SoftReference} based + {@link org.apache.commons.pool2.ObjectPool ObjectPool}. +

+

+ See also the {@link org.apache.commons.pool2} package. +

+ + diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html new file mode 100644 index 00000000..5a25931c --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html @@ -0,0 +1,121 @@ + + + + + Overview of the org.apache.commons.pool2 component + + +

+ Generic Object pooling API with several implementations. +

+

+ The org.apache.commons.pool2 package defines a simple + interface for a pool of object instances, and a handful of base + classes that may be useful when creating pool implementations. + The API supports pooling of unique objects which can be requested + via a key as well as pools where all objects are equivalent. +

+

+ The org.apache.commons.pool2.impl package contains + several pool implementations. + {@link org.apache.commons.pool2.impl.GenericObjectPool + GenericObjectPool} has many configuration options and can support + a limited set of objects such as would be useful in a database + connection pool. + {@link org.apache.commons.pool2.impl.SoftReferenceObjectPool + SoftReferenceObjectPool} has no limit on the number of objects in the + pool, but the garbage collector can remove idle objects from the pool + as needed. There is also a keyed version of + {@link org.apache.commons.pool2.impl.GenericObjectPool + GenericObjectPool}, + {@link org.apache.commons.pool2.impl.GenericKeyedObjectPool + GenericKeyedObjectPool} +

+

+ Here is a simple example of pooling HashMap instances. + First create an {@link org.apache.commons.pool2.PoolableObjectFactory + PoolableObjectFactory} +

+
+    public class HashMapFactory
+        extends {@link org.apache.commons.pool2.BasePoolableObjectFactory BasePoolableObjectFactory}<Map<Object,Object>>
+    {
+        /**
+         * Creates an instance that can be returned by the pool.
+         * @return an instance that can be returned by the pool.
+         */
+        public Map<Object,Object> makeObject()
+            throws Exception
+        {
+            return new HashMap<Object,Object>();
+        }
+
+        /**
+         * Uninitialize an instance to be returned to the pool.
+         * @param obj the instance to be passivated
+         */
+        public void passivateObject(Map<Object,Object> obj)
+            throws Exception
+        {
+            obj.clear();
+        }
+    }
+
+

+ A class that makes frequent use of a Map could then use a pool + as shown below: +

+
+    public class Foo
+    {
+        private {@link org.apache.commons.pool2.ObjectPool ObjectPool<Map<Object,Object>>} pool;
+        public Foo()
+        {
+            {@link org.apache.commons.pool2.PoolableObjectFactory PoolableObjectFactory<Map<Object,Object>>} factory = new HashMapFactory();
+            pool = new {@link org.apache.commons.pool2.impl.GenericObjectPool GenericObjectPool}<Map<Object,Object>>(factory);
+        }
+
+        public doSomething()
+        {
+            ...
+            Map<Object,Object> map = null;
+            try
+            {
+                map = pool.borrowObject();
+                // use map
+                ...
+            }
+            finally
+            {
+                if (map != null)
+                {
+                    pool.returnObject(map);
+                }
+            }
+            ...
+        }
+    }
+
+ +

+The above example shows how one would use an +{@link org.apache.commons.pool2.ObjectPool ObjectPool}. The other supplied +implementations or another special purpose pool would be used similarly. +

+ + \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html new file mode 100644 index 00000000..3eba5fe0 --- /dev/null +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html @@ -0,0 +1,63 @@ + + + + + Package Documentation for org.apache.commons.pool2 + + +

+ Object pooling API. +

+

+ The org.apache.commons.pool2 package defines a simple + interface for a pool of object instances, and a handful of base + classes that may be useful when creating pool implementations. +

+

+ The pool package itself doesn't define a specific object + pooling implementation, but rather a contract that implementations may + support in order to be fully interchangeable. +

+

+ The pool package separates the way in which instances are + pooled from the way in which they are created, resulting in a pair of + interfaces: +

+
+
{@link org.apache.commons.pool2.ObjectPool ObjectPool}
+
+ defines a simple object pooling interface, with methods for + borrowing instances from and returning them to the pool. +
+
{@link org.apache.commons.pool2.PoolableObjectFactory PoolableObjectFactory}
+
+ defines lifecycle methods for object instances contained within a pool. + By associating a factory with a pool, the pool can create new object + instances as needed. +
+
+

+ The pool package also provides a keyed pool interface, + which pools instances of multiple types, accessed according to an + arbitrary key. See + {@link org.apache.commons.pool2.KeyedObjectPool KeyedObjectPool} and + {@link org.apache.commons.pool2.KeyedPoolableObjectFactory + KeyedPoolableObjectFactory}. +

+ + diff --git a/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory b/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory index 27952be7..a97af6d7 100644 --- a/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory +++ b/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory @@ -1 +1,2 @@ org.adbcj.mysql.netty.MySqlConnectionManagerFactory +org.adbcj.mysql.netty.WrappedMysqlConnectionManagerFactory \ No newline at end of file From 101da4bc0a9f8d3f73a48fc7466e97ced81ccb5e Mon Sep 17 00:00:00 2001 From: shenxun Date: Tue, 2 Jul 2013 14:22:41 +0800 Subject: [PATCH 04/17] reverse to origin pom. --- api/pom.xml | 2 +- jdbc/pom.xml | 2 +- mysql/codec/pom.xml | 2 +- .../adbcj/mysql/codec/ProtocolHandler.java | 328 +-- mysql/mina/pom.xml | 2 +- mysql/netty/pom.xml | 18 +- .../tdhs/config/AtomAlreadyInitException.java | 22 - .../taobao/tdhs/config/AtomDbStatusEnum.java | 64 - .../taobao/tdhs/config/AtomDbTypeEnum.java | 53 - .../tdhs/config/AtomIllegalException.java | 26 - .../tdhs/config/AtomInitialException.java | 26 - .../taobao/tdhs/config/ConfigDataHandler.java | 55 - .../tdhs/config/ConfigDataHandlerFactory.java | 109 - .../tdhs/config/ConfigDataListener.java | 19 - .../com/taobao/tdhs/config/DbConfManager.java | 40 - .../taobao/tdhs/config/DbPasswdManager.java | 21 - .../DefaultConfigDataHandlerFactory.java | 251 --- .../com/taobao/tdhs/config/DiamondConfig.java | 80 - .../tdhs/config/DiamondConfigDataHandler.java | 122 -- .../tdhs/config/DiamondDbConfManager.java | 94 - .../tdhs/config/DiamondDbPasswdManager.java | 62 - .../config/SecureIdentityLoginModule.java | 113 -- .../taobao/tdhs/config/TAtomConfParser.java | 189 -- .../taobao/tdhs/config/TAtomConstants.java | 125 -- .../com/taobao/tdhs/config/TAtomDsConfDO.java | 294 --- .../taobao/tdhs/config/TAtomDsConfHandle.java | 318 --- .../com/taobao/tdhs/config/TDDLConstant.java | 13 - .../tdhs/config/group/ConfigManager.java | 152 -- .../tdhs/config/group/GroupExtraConfig.java | 131 -- .../com/taobao/tdhs/config/group/Weight.java | 155 -- .../tdhs/config/group/WeightSelector.java | 120 -- .../netty/AtomMysqlConnectionManager.java | 88 - .../netty/GroupMysqlConnectionManager.java | 108 - .../org/adbcj/mysql/netty/TAtomConstants.java | 125 -- .../mysql/netty/WrappedMysqlConnection.java | 82 - .../netty/WrappedMysqlConnectionManager.java | 96 - .../WrappedMysqlConnectionManagerFactory.java | 54 - ...WrappedMysqlConnectionPoolableFactory.java | 39 - .../WrappedMysqlConnectionPoolableObject.java | 38 - .../pool2/BaseKeyedPoolableObjectFactory.java | 100 - .../apache/commons/pool2/BaseObjectPool.java | 141 -- .../pool2/BasePoolableObjectFactory.java | 82 - .../apache/commons/pool2/KeyedObjectPool.java | 220 -- .../pool2/KeyedPoolableObjectFactory.java | 140 -- .../org/apache/commons/pool2/ObjectPool.java | 169 -- .../org/apache/commons/pool2/PoolUtils.java | 1807 ----------------- .../commons/pool2/PoolableObjectFactory.java | 135 -- .../commons/pool2/impl/AbandonedConfig.java | 194 -- .../pool2/impl/BaseGenericObjectPool.java | 1077 ---------- .../pool2/impl/BaseObjectPoolConfig.java | 443 ---- .../pool2/impl/DefaultEvictionPolicy.java | 53 - .../commons/pool2/impl/EvictionConfig.java | 63 - .../commons/pool2/impl/EvictionPolicy.java | 45 - .../commons/pool2/impl/EvictionTimer.java | 130 -- .../pool2/impl/GenericKeyedObjectPool.java | 1380 ------------- .../impl/GenericKeyedObjectPoolConfig.java | 104 - .../impl/GenericKeyedObjectPoolMBean.java | 160 -- .../commons/pool2/impl/GenericObjectPool.java | 960 --------- .../pool2/impl/GenericObjectPoolConfig.java | 91 - .../pool2/impl/GenericObjectPoolMBean.java | 163 -- .../impl/InterruptibleReentrantLock.java | 45 - .../pool2/impl/LinkedBlockingDeque.java | 1213 ----------- .../commons/pool2/impl/PooledObject.java | 305 --- .../commons/pool2/impl/PooledObjectState.java | 90 - .../pool2/impl/SoftReferenceObjectPool.java | 339 ---- .../apache/commons/pool2/impl/TrackedUse.java | 34 - mysql/pom.xml | 2 +- pom.xml | 7 +- postgresql/codec/pom.xml | 2 +- postgresql/mina/pom.xml | 2 +- postgresql/netty/pom.xml | 2 +- postgresql/pom.xml | 2 +- tck/pom.xml | 2 +- 73 files changed, 188 insertions(+), 13152 deletions(-) delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java delete mode 100644 mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java diff --git a/api/pom.xml b/api/pom.xml index ac559461..90870e79 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT adbcj-api diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 53a2f04e..882c7de6 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT adbcj-jdbc diff --git a/mysql/codec/pom.xml b/mysql/codec/pom.xml index c1ff35eb..482a2339 100644 --- a/mysql/codec/pom.xml +++ b/mysql/codec/pom.xml @@ -8,7 +8,7 @@ org.adbcj mysql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT mysql-codec diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/ProtocolHandler.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/ProtocolHandler.java index 0e78c494..d014427e 100644 --- a/mysql/codec/src/main/java/org/adbcj/mysql/codec/ProtocolHandler.java +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/ProtocolHandler.java @@ -8,170 +8,186 @@ import org.adbcj.Result; import org.adbcj.ResultSet; import org.adbcj.Value; +import org.adbcj.support.AbstractDbSession.Request; import org.adbcj.support.DefaultDbFuture; import org.adbcj.support.DefaultResult; -import org.adbcj.support.AbstractDbSession.Request; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Asynchronous protocol handler suitable for use with frameworks like MINA or Netty. - * + * Asynchronous protocol handler suitable for use with frameworks like MINA or + * Netty. + * * @author Mike Heath */ public class ProtocolHandler { - private final Logger logger = LoggerFactory.getLogger(ProtocolHandler.class); - - public void connectionClosed(AbstractMySqlConnection connection) throws Exception { - logger.trace("IoSession closed"); - connection.doClose(); - } - - /** - * Handles an exception - * - * @param connection - * @param cause - * @return any exception that couldn't be handled, null if the exception was succesfully handled - * @throws Exception - */ - public Throwable handleException(AbstractMySqlConnection connection, Throwable cause) throws Exception { - logger.debug("Caught exception: ", cause); - - DbException dbException = DbException.wrap(connection, cause); - if (connection != null) { - DefaultDbFuture connectFuture = connection.getConnectFuture(); - if (!connectFuture.isDone()) { - connectFuture.setException(dbException); - return null; - } - Request activeRequest = connection.getActiveRequest(); - if (activeRequest != null) { - if (!activeRequest.isDone()) { - try { - activeRequest.error(dbException); - - return null; - } catch (Throwable e) { - return e; - } - } - } - } - return dbException; - } - - public void messageReceived(AbstractMySqlConnection connection, Object message) throws Exception { - logger.trace("Received message: {}", message); - if (message instanceof ServerGreeting) { - handleServerGreeting(connection, (ServerGreeting)message); - } else if (message instanceof OkResponse) { - handleOkResponse(connection, (OkResponse)message); - } else if (message instanceof ErrorResponse) { - handleErrorResponse(connection, (ErrorResponse)message); - } else if (message instanceof ResultSetResponse) { - handleResultSetResponse(connection, (ResultSetResponse)message); - } else if (message instanceof ResultSetFieldResponse) { - handleResultSetFieldResponse(connection, (ResultSetFieldResponse)message); - } else if (message instanceof ResultSetRowResponse) { - handleResultSetRowResponse(connection, (ResultSetRowResponse)message); - } else if (message instanceof EofResponse) { - handleEofResponse(connection, (EofResponse)message); - } else { - throw new IllegalStateException("Unable to handle message of type: " + message.getClass().getName()); - } - } - - private void handleServerGreeting(AbstractMySqlConnection connection, ServerGreeting serverGreeting) { - // TODO save the parts of the greeting that we might need (like the protocol version, etc.) - // Send Login request - LoginRequest request = new LoginRequest(connection.getCredentials(), connection.getClientCapabilities(), connection.getExtendedClientCapabilities(), connection.getCharacterSet(), serverGreeting.getSalt()); - connection.write(request); - } - - private void handleOkResponse(AbstractMySqlConnection connection, OkResponse response) { - logger.trace("Response '{}' on connection {}", response, connection); - - List warnings = null; - if (response.getWarningCount() > 0) { - warnings = new LinkedList(); - for (int i = 0; i < response.getWarningCount(); i++) { - warnings.add(response.getMessage()); - } - } - - logger.warn("Warnings: {}", warnings); - - Request activeRequest = connection.getActiveRequest(); - if (activeRequest == null) { - // TODO Do we need to pass the warnings on to the connection? - DefaultDbFuture connectFuture = connection.getConnectFuture(); - if (!connectFuture.isDone() ) { - connectFuture.setResult(connection); - - return; - } else { - throw new IllegalStateException("Received an OkResponse with no activeRequest " + response); - } - } - Result result = new DefaultResult(response.getAffectedRows(), warnings); - activeRequest.complete(result); - } - - private void handleErrorResponse(AbstractMySqlConnection connection, ErrorResponse message) { - throw new MysqlException(connection, message.getMessage()); - } - - private void handleResultSetResponse(AbstractMySqlConnection connection, ResultSetResponse message) { - Request activeRequest = connection.getActiveRequest(); - - if (activeRequest == null) { - throw new IllegalStateException("No active request for response: " + message); - } - - logger.debug("Start field definitions"); - activeRequest.getEventHandler().startFields(activeRequest.getAccumulator()); - } - - private void handleResultSetFieldResponse(AbstractMySqlConnection connection, ResultSetFieldResponse message) { - Request activeRequest = connection.getActiveRequest(); - - ResultSetFieldResponse fieldResponse = (ResultSetFieldResponse)message; - activeRequest.getEventHandler().field(fieldResponse.getField(), activeRequest.getAccumulator()); - } - - private void handleResultSetRowResponse(AbstractMySqlConnection connection, ResultSetRowResponse message) { - Request activeRequest = connection.getActiveRequest(); - - ResultSetRowResponse rowResponse = (ResultSetRowResponse)message; - - activeRequest.getEventHandler().startRow(activeRequest.getAccumulator()); - for (Value value : rowResponse.getValues()) { - activeRequest.getEventHandler().value(value, activeRequest.getAccumulator()); - } - activeRequest.getEventHandler().endRow(activeRequest.getAccumulator()); - } - - private void handleEofResponse(AbstractMySqlConnection connection, EofResponse message) { - logger.trace("Fetching active request in handleEofResponse()"); - Request activeRequest = connection.getActiveRequest(); - - if (activeRequest == null) { - throw new IllegalStateException("No active request for response: " + message); - } - - EofResponse eof = (EofResponse)message; - switch (eof.getType()) { - case FIELD: - activeRequest.getEventHandler().endFields(activeRequest.getAccumulator()); - break; - case ROW: - activeRequest.getEventHandler().endResults(activeRequest.getAccumulator()); - activeRequest.complete(activeRequest.getAccumulator()); - break; - default: - throw new MysqlException(connection, "Unkown eof response type"); - } - } + + private final Logger logger = LoggerFactory.getLogger(ProtocolHandler.class); + + public void connectionClosed(AbstractMySqlConnection connection) throws Exception { + logger.trace("IoSession closed"); + connection.doClose(); + } + + /** + * Handles an exception + * + * @param connection + * @param cause + * @return any exception that couldn't be handled, null if the exception was + * succesfully handled + * @throws Exception + */ + public Throwable handleException(AbstractMySqlConnection connection, Throwable cause) throws Exception { + logger.debug("Caught exception: ", cause); + + DbException dbException = DbException.wrap(connection, cause); + if (connection != null) { + DefaultDbFuture connectFuture = connection.getConnectFuture(); + if (!connectFuture.isDone()) { + connectFuture.setException(dbException); + return null; + } + Request activeRequest = connection.getActiveRequest(); + if (activeRequest != null) { + if (!activeRequest.isDone()) { + try { + activeRequest.error(dbException); + + return null; + } catch (Throwable e) { + return e; + } + } + } + } + return dbException; + } + + public void messageReceived(AbstractMySqlConnection connection, Object message) throws Exception { + logger.trace("Received message: {}", message); + if (message instanceof ServerGreeting) { + handleServerGreeting(connection, (ServerGreeting) message); + } else if (message instanceof OkResponse) { + handleOkResponse(connection, (OkResponse) message); + } else if (message instanceof ErrorResponse) { + handleErrorResponse(connection, (ErrorResponse) message); + } else if (message instanceof ResultSetResponse) { + handleResultSetResponse(connection, (ResultSetResponse) message); + } else if (message instanceof ResultSetFieldResponse) { + handleResultSetFieldResponse(connection, (ResultSetFieldResponse) message); + } else if (message instanceof ResultSetRowResponse) { + handleResultSetRowResponse(connection, (ResultSetRowResponse) message); + } else if (message instanceof EofResponse) { + handleEofResponse(connection, (EofResponse) message); + } else { + throw new IllegalStateException("Unable to handle message of type: " + message.getClass().getName()); + } + } + + private void handleServerGreeting(AbstractMySqlConnection connection, ServerGreeting serverGreeting) { + // TODO save the parts of the greeting that we might need (like the + // protocol version, etc.) + // Send Login request + LoginRequest request = new LoginRequest(connection.getCredentials(), + connection.getClientCapabilities(), + connection.getExtendedClientCapabilities(), + connection.getCharacterSet(), + serverGreeting.getSalt()); + connection.write(request); + } + + private void handleOkResponse(AbstractMySqlConnection connection, OkResponse response) { + logger.trace("Response '{}' on connection {}", response, connection); + + List warnings = null; + if (response.getWarningCount() > 0) { + warnings = new LinkedList(); + for (int i = 0; i < response.getWarningCount(); i++) { + warnings.add(response.getMessage()); + } + } + + logger.warn("Warnings: {}", warnings); + + Request activeRequest = connection.getActiveRequest(); + if (activeRequest == null) { + // TODO Do we need to pass the warnings on to the connection? + DefaultDbFuture connectFuture = connection.getConnectFuture(); + if (!connectFuture.isDone()) { + connectFuture.setResult(connection); + + return; + } else { + throw new IllegalStateException("Received an OkResponse with no activeRequest " + response); + } + } + Result result = new DefaultResult(response.getAffectedRows(), warnings); + activeRequest.complete(result); + } + + private void handleErrorResponse(AbstractMySqlConnection connection, ErrorResponse message) { + StringBuilder sb = new StringBuilder(); + if (!message.getMessage().isEmpty()) { + sb.append(message.getMessage()).append("\n"); + } + if (!message.getSqlState().isEmpty()) { + sb.append(message.getSqlState()).append("\n"); + } + + throw new MysqlException(connection, sb.toString()); + } + + private void handleResultSetResponse(AbstractMySqlConnection connection, ResultSetResponse message) { + Request activeRequest = connection.getActiveRequest(); + + if (activeRequest == null) { + throw new IllegalStateException("No active request for response: " + message); + } + + logger.debug("Start field definitions"); + activeRequest.getEventHandler().startFields(activeRequest.getAccumulator()); + } + + private void handleResultSetFieldResponse(AbstractMySqlConnection connection, ResultSetFieldResponse message) { + Request activeRequest = connection.getActiveRequest(); + + ResultSetFieldResponse fieldResponse = (ResultSetFieldResponse) message; + activeRequest.getEventHandler().field(fieldResponse.getField(), activeRequest.getAccumulator()); + } + + private void handleResultSetRowResponse(AbstractMySqlConnection connection, ResultSetRowResponse message) { + Request activeRequest = connection.getActiveRequest(); + + ResultSetRowResponse rowResponse = (ResultSetRowResponse) message; + + activeRequest.getEventHandler().startRow(activeRequest.getAccumulator()); + for (Value value : rowResponse.getValues()) { + activeRequest.getEventHandler().value(value, activeRequest.getAccumulator()); + } + activeRequest.getEventHandler().endRow(activeRequest.getAccumulator()); + } + + private void handleEofResponse(AbstractMySqlConnection connection, EofResponse message) { + logger.trace("Fetching active request in handleEofResponse()"); + Request activeRequest = connection.getActiveRequest(); + + if (activeRequest == null) { + throw new IllegalStateException("No active request for response: " + message); + } + + EofResponse eof = (EofResponse) message; + switch (eof.getType()) { + case FIELD: + activeRequest.getEventHandler().endFields(activeRequest.getAccumulator()); + break; + case ROW: + activeRequest.getEventHandler().endResults(activeRequest.getAccumulator()); + activeRequest.complete(activeRequest.getAccumulator()); + break; + default: + throw new MysqlException(connection, "Unkown eof response type"); + } + } } diff --git a/mysql/mina/pom.xml b/mysql/mina/pom.xml index 4aaf0144..0987a6f2 100644 --- a/mysql/mina/pom.xml +++ b/mysql/mina/pom.xml @@ -8,7 +8,7 @@ org.adbcj mysql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT mysql-mina diff --git a/mysql/netty/pom.xml b/mysql/netty/pom.xml index 49117eea..12c1d509 100644 --- a/mysql/netty/pom.xml +++ b/mysql/netty/pom.xml @@ -6,7 +6,7 @@ org.adbcj mysql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT mysql-netty @@ -19,31 +19,17 @@ netty ${netty.version} - - commons-lang - commons-lang - 2.6 - org.slf4j slf4j-api - - log4j - log4j - 1.2.16 - + org.slf4j slf4j-log4j12 - - com.taobao.diamond - diamond-client - 2.0.5.3 - ${project.groupId} mysql-codec diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java deleted file mode 100644 index 5d81f287..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomAlreadyInitException.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.taobao.tdhs.config; - -public class AtomAlreadyInitException extends Exception { - - private static final long serialVersionUID = -3907211238952987907L; - - public AtomAlreadyInitException() { - super(); - } - - public AtomAlreadyInitException(String msg) { - super(msg); - } - - public AtomAlreadyInitException(Throwable cause) { - super(cause); - } - - public AtomAlreadyInitException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java deleted file mode 100644 index 8f4a7dd4..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbStatusEnum.java +++ /dev/null @@ -1,64 +0,0 @@ - -package com.taobao.tdhs.config; - -import com.alibaba.common.lang.StringUtil; - -/** - * æ•°æ®åº“çŠ¶æ€æžšä¸¾ç±»åž‹ - * @author qihao - * - */ -public enum AtomDbStatusEnum { - - R_STAUTS(TAtomConstants.DB_STATUS_R), W_STATUS(TAtomConstants.DB_STATUS_W), RW_STATUS(TAtomConstants.DB_STATUS_RW), NA_STATUS( - TAtomConstants.DB_STATUS_NA); - - private String status; - - AtomDbStatusEnum(String status) { - this.status = status; - } - - public String getStatus() { - return status; - } - - public static AtomDbStatusEnum getAtomDbStatusEnumByType(String type) { - AtomDbStatusEnum statusEnum = null; - if (StringUtil.isNotBlank(type)) { - String typeStr = type.toUpperCase().trim(); - if (typeStr.length() > 1) { - if (AtomDbStatusEnum.NA_STATUS.getStatus().equals(typeStr)) { - statusEnum = AtomDbStatusEnum.NA_STATUS; - } else if (!StringUtil.contains(typeStr, AtomDbStatusEnum.NA_STATUS.getStatus()) - &&StringUtil.contains(typeStr, AtomDbStatusEnum.R_STAUTS.getStatus()) - && StringUtil.contains(typeStr, AtomDbStatusEnum.W_STATUS.getStatus())) { - statusEnum = AtomDbStatusEnum.RW_STATUS; - } - } else { - if (AtomDbStatusEnum.R_STAUTS.getStatus().equals(typeStr)) { - statusEnum = AtomDbStatusEnum.R_STAUTS; - } else if (AtomDbStatusEnum.W_STATUS.getStatus().equals(typeStr)) { - statusEnum = AtomDbStatusEnum.W_STATUS; - } - } - } - return statusEnum; - } - - public boolean isNaStatus() { - return this == AtomDbStatusEnum.NA_STATUS; - } - - public boolean isRstatus() { - return this == AtomDbStatusEnum.R_STAUTS || this == AtomDbStatusEnum.RW_STATUS; - } - - public boolean isWstatus() { - return this == AtomDbStatusEnum.W_STATUS || this == AtomDbStatusEnum.RW_STATUS; - } - - public boolean isRWstatus() { - return this == AtomDbStatusEnum.RW_STATUS; - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java deleted file mode 100644 index 62c6ab08..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomDbTypeEnum.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.taobao.tdhs.config; - - -/** - * æ•°æ®åº“类型枚举类型 - * - * @author qihao - * - */ -public enum AtomDbTypeEnum { - - ORACLE(TAtomConstants.DEFAULT_ORACLE_DRIVER_CLASS, TAtomConstants.DEFAULT_ORACLE_SORTER_CLASS), - - MYSQL(TAtomConstants.DEFAULT_MYSQL_DRIVER_CLASS, TAtomConstants.DEFAULT_MYSQL_SORTER_CLASS); - - private String driverClass; - private String sorterClass; - - AtomDbTypeEnum(String driverClass, String sorterClass) { - this.driverClass = driverClass; - this.sorterClass = sorterClass; - } - - public static AtomDbTypeEnum getAtomDbTypeEnumByType(String type) { - /* - if (StringUtil.isNotBlank(type)) { - for (AtomDbTypeEnum typeEnum : AtomDbTypeEnum.values()) { - if (typeEnum.getType().equals(type.toUpperCase().trim())) { - return typeEnum; - } - } - } - return null; - */ - try { - return AtomDbTypeEnum.valueOf(type.trim().toUpperCase()); - } catch (Exception e) { - return null; - } - } - - public String getDriverClass() { - return driverClass; - } - - public String getSorterClass() { - return sorterClass; - } - - /*public String getType() { - return type; - }*/ -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java deleted file mode 100644 index 2444807a..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomIllegalException.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.taobao.tdhs.config; - -/** - * @author qihao - * - */ -public class AtomIllegalException extends Exception { - - private static final long serialVersionUID = -5341803227125385166L; - - public AtomIllegalException() { - super(); - } - - public AtomIllegalException(String msg) { - super(msg); - } - - public AtomIllegalException(Throwable cause) { - super(cause); - } - - public AtomIllegalException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java deleted file mode 100644 index f0c6e2ee..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/AtomInitialException.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.taobao.tdhs.config; - -/** - * @author qihao - * - */ -public class AtomInitialException extends Exception { - - private static final long serialVersionUID = -2933446568649742125L; - - public AtomInitialException() { - super(); - } - - public AtomInitialException(String msg) { - super(msg); - } - - public AtomInitialException(Throwable cause) { - super(cause); - } - - public AtomInitialException(String msg, Throwable cause) { - super(msg, cause); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java deleted file mode 100644 index f85d70e8..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -//Copyrigh(c) Taobao.com -package com.taobao.tdhs.config; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -/** - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-11上åˆ11:22:29 - * @desc 获å–é…置的处ç†å™¨ - */ -public interface ConfigDataHandler { - public static final String FIRST_SERVER_STRATEGY = "firstServer"; - public static final String FIRST_CACHE_THEN_SERVER_STRATEGY="firstCache"; - - /** - * DefaultConfigDataHandler会在 实例化具体的Handler之åŽè°ƒç”¨æ­¤æ–¹æ³• 给予Handlerç›¸å…³ä¿¡æ¯ - * @param dataId æ•°æ®åœ¨é…置平å°ä¸Šæ³¨å†Œçš„id - * @param listenerList æ•°æ®ç›‘å¬å™¨åˆ—表 - * @param prop 全局é…置和è¿è¡Œæ—¶ - */ - void init(String dataId, List listenerList, - Map prop); - - /** - * 从é…ç½®ä¸­å¿ƒæ‹‰å–æ•°æ® - * @param timeout 获å–é…置信æ¯è¶…æ—¶æ—¶é—´ - * @param strategy 获å–é…置策略 - * @return - */ - String getData(long timeout, String strategy); - - /** - * 为推é€è¿‡æ¥çš„æ•°æ®æ³¨å†Œå¤„ç†çš„监å¬å™¨ - * @param configDataListener 监å¬å™¨ - * @param executor 执行的executor - */ - void addListener(ConfigDataListener configDataListener, Executor executor); - - /** - * 为推é€è¿‡æ¥çš„æ•°æ®æ³¨å†Œå¤šä¸ªå¤„ç†ç›‘å¬å™¨ - * @param configDataListenerList 监å¬å™¨åˆ—表 - * @param executor 执行的executor - */ - void addListeners(List configDataListenerList, - Executor executor); - - /** - * åœæ­¢åº•层é…置管ç†å™¨ - */ - void closeUnderManager(); -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java deleted file mode 100644 index d6f1eb66..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataHandlerFactory.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -/** - * @author whisper - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-11上åˆ11:22:29 - * @desc 得到具体的é…置处ç†å™¨å®žä¾‹ - */ -public interface ConfigDataHandlerFactory { - /** - * 对æŸä¸€ä¸ªdataIdè¿›è¡Œç›‘å¬ - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandler(String dataId); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ - * @param dataId æ•°æ®åœ¨p诶值中心注册的id - * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandler(String dataId, - ConfigDataListener configDataListener); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,处ç†å™¨æ”¶åˆ°é…ç½®ä¿¡æ¯æ—¶ - * ,é€ä¸ªè°ƒç”¨ç›‘å¬å™¨çš„回调方法 - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerWithListenerList(String dataId, - List configDataListenerList); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œå¹¶ä¸”æä¾›å†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ - * @param config TDDL内部对handleræä¾›çš„一些é…ç½® - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerC(String dataId, - ConfigDataListener configDataListener, - Map config); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬,使用者æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,并且æä¾›å†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 - * @param config TDDL内部对handleræä¾›çš„一些é…ç½® - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerWithListenerListC(String dataId, - List configDataListenerList, - Map config); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œå¹¶ä¸”æä¾›æ‰§è¡Œçº¿ç¨‹æ±  - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ - * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerE(String dataId, - ConfigDataListener configDataListener, Executor executor); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表,并且æä¾›æ‰§è¡Œçº¿ç¨‹æ±  - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 - * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerWithListenerListE(String dataId, - List configDataListenerList, Executor executor); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨ï¼Œ - * 并且æä¾›æ‰§è¡Œçº¿ç¨‹æ± å’Œå†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListener æ•°æ®å›žè°ƒç›‘å¬å™¨ - * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  - * @param config TDDL内部对handleræä¾›çš„一些é…ç½® - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerCE(String dataId, - ConfigDataListener configDataListener, Executor executor, - Map config); - - /** - * 对æŸä¸€ä¸ªdataId进行监å¬ï¼Œä½¿ç”¨è€…æä¾›å›žè°ƒç›‘å¬å™¨åˆ—表, - * 并且æä¾›æ‰§è¡Œçº¿ç¨‹æ± å’Œå†…部一些é…ç½®(å¯èƒ½è¢«handler忽视) - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param configDataListenerList æ•°æ®å›žè°ƒç›‘å¬å™¨åˆ—表 - * @param executor æ•°æ®æŽ¥æ”¶å¤„ç†çº¿ç¨‹æ±  - * @param config TDDL内部对handleræä¾›çš„一些é…ç½® - * @return 返回é…置数æ®å¤„ç†å™¨å®žä¾‹ - */ - ConfigDataHandler getConfigDataHandlerWithListenerListCE(String dataId, - List configDataListenerList, Executor executor, - Map config); -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java deleted file mode 100644 index 2c3986d9..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/ConfigDataListener.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.taobao.tdhs.config; - -/** - * @author shenxun - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-11上åˆ11:22:29 - * @desc 接收信æ¯çš„å›žè°ƒæŽ¥å£ - */ -public interface ConfigDataListener { - /** - * é…ç½®ä¸­å¿ƒå®¢æˆ·ç«¯æ”¶åˆ°æ•°æ®æ—¶è°ƒç”¨æ³¨å†Œçš„监å¬å™¨æ–¹æ³•, - * 并把收到的数æ®ä¼ é€’到此方法中 - * @param dataId æ•°æ®åœ¨é…置中心注册的id - * @param data å­—ç¬¦ä¸²æ•°æ® - */ - void onDataRecieved(String dataId,String data); -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java deleted file mode 100644 index 8a5f5db3..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbConfManager.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.taobao.tdhs.config; - - -/** - * TAtomæ•°æ®æºå…¨å±€å’Œåº”用的é…ç½®ç®¡ç†æŽ¥å£å®šä¹‰ - * - * @author qihao - * - */ -public interface DbConfManager { - /**获å–全局é…ç½® - * - * @return - */ - public String getGlobalDbConf(); - - /**获å–应用é…ç½® - * - * @return - */ - public String getAppDbDbConf(); - - /** - * 注册全局é…ç½®ç›‘å¬ - * - * @param Listener - */ - public void registerGlobaDbConfListener(ConfigDataListener Listener); - - /**注册应用é…ç½®ç›‘å¬ - * - * @param Listener - */ - public void registerAppDbConfListener(ConfigDataListener Listener); - - /** - * åœæ­¢DbConfManager - */ - public void stopDbConfManager(); -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java deleted file mode 100644 index b3a23659..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DbPasswdManager.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.taobao.tdhs.config; - - -public interface DbPasswdManager { - - /**��ȡ��ݿ����� - * @return - */ - public String getPasswd(); - - /**ע��Ӧ�����ü��� - * - * @param Listener - */ - public void registerPasswdConfListener(ConfigDataListener Listener); - - /** - * Í£Ö¹DbPasswdManager - */ - public void stopDbPasswdManager(); -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java deleted file mode 100644 index f798551c..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DefaultConfigDataHandlerFactory.java +++ /dev/null @@ -1,251 +0,0 @@ -//Copyright(c) Taobao.com -package com.taobao.tdhs.config; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Executor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * @description - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-11下åˆ01:17:21 - */ -@SuppressWarnings("rawtypes") -public class DefaultConfigDataHandlerFactory implements - ConfigDataHandlerFactory { - private static final Log log = LogFactory - .getLog(DefaultConfigDataHandlerFactory.class); - private static final String HANDLER_CLASS = "config.handler.constructor.name"; - private static final String DEFAULT_HANDLER_CLASS = "com.taobao.tdhs.config.DiamondConfigDataHandler"; - - private static String propertyFile = "remote-config.properties"; - private static String handlerClassName; - private static Class handlerClassObj; - private static Constructor handlerConstructor; - private static Properties prop; - - static { - findSpecifiedConfigHandlerClass(); - createConstuctFromClassName(); - } - - private static void findSpecifiedConfigHandlerClass() { - ClassLoader currentCL = getBaseClassLoader(); - InputStream resource; - for (;;) { - if (currentCL != null) { - resource = currentCL.getResourceAsStream(propertyFile); - } else { - resource = ClassLoader.getSystemResourceAsStream(propertyFile); - break; - } - - if (null != resource) { - break; - } else { - currentCL = currentCL.getParent(); - } - } - - if (null != resource) { - prop = new Properties(); - try { - prop.load(resource); - handlerClassName = prop.getProperty(HANDLER_CLASS); - if (null == handlerClassName || "".equals(handlerClassName)) { - handlerClassName = DEFAULT_HANDLER_CLASS; - } - } catch (IOException e) { - log.error("properties can not load " + propertyFile); - } - } else { - handlerClassName = DEFAULT_HANDLER_CLASS; - } - } - - @SuppressWarnings("unchecked") - private static void createConstuctFromClassName() { - ClassLoader currentCL = getBaseClassLoader(); - handlerClassObj = loadClass(handlerClassName, currentCL); - if (null == handlerClassObj) { - throw new IllegalArgumentException("can not get handler class:" - + handlerClassName); - } - - try { - handlerConstructor = handlerClassObj.getConstructor(); - } catch (SecurityException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - - private static Class loadClass(String className, ClassLoader currentCL) { - log.info("Trying to load '" + className); - try { - Class clazz = currentCL.loadClass(handlerClassName); - if (clazz != null) { - return clazz; - } - } catch (ClassNotFoundException e) { - log.error("can not load the class "); - } - - return null; - - } - - private static boolean useTCCL = true; - - private static ClassLoader getBaseClassLoader() { - ClassLoader thisClassLoader = DefaultConfigDataHandlerFactory.class - .getClassLoader(); - if (useTCCL == false) { - return thisClassLoader; - } - ClassLoader contextClassLoader = Thread.currentThread() - .getContextClassLoader(); - ClassLoader baseClassLoader = getLowestClassLoader(contextClassLoader, - thisClassLoader); - return baseClassLoader; - } - - private static ClassLoader getLowestClassLoader(ClassLoader c1, - ClassLoader c2) { - if (c1 == null) - return c2; - - if (c2 == null) - return c1; - - ClassLoader current; - - current = c1; - while (current != null) { - if (current == c2) - return c1; - current = current.getParent(); - } - - current = c2; - while (current != null) { - if (current == c1) - return c2; - current = current.getParent(); - } - - return null; - } - - public static String objectId(Object o) { - if (o == null) { - return "null"; - } else { - // 这里这个System.identityHashCodeåªä¼šåœ¨åˆå§‹åŒ–时调用一次,所以 - // å…¶å¯èƒ½å­˜åœ¨çš„问题影å“å¹¶ä¸å¤§ã€‚ - return o.getClass().getName() + "@" + System.identityHashCode(o); - } - } - - - public ConfigDataHandler getConfigDataHandler(String dataId) { - return this.getConfigDataHandler(dataId, null); - } - - - public ConfigDataHandler getConfigDataHandler(String dataId, - ConfigDataListener configDataListener) { - return this.getConfigDataHandlerC(dataId, configDataListener, - new HashMap()); - } - - - public ConfigDataHandler getConfigDataHandlerWithListenerList( - String dataId, List configDataListenerList) { - return this.getConfigDataHandlerWithListenerListC(dataId, - configDataListenerList, new HashMap()); - } - - - public ConfigDataHandler getConfigDataHandlerC(String dataId, - ConfigDataListener configDataListener, Map config) { - return this.getConfigDataHandlerCE(dataId, configDataListener, null, - config); - } - - - public ConfigDataHandler getConfigDataHandlerWithListenerListC( - String dataId, List configDataListenerList, - Map config) { - return this.getConfigDataHandlerWithListenerListCE(dataId, - configDataListenerList, null, config); - } - - - public ConfigDataHandler getConfigDataHandlerE(String dataId, - ConfigDataListener configDataListener, Executor executor) { - return this.getConfigDataHandlerCE(dataId, configDataListener, - executor, new HashMap()); - } - - - public ConfigDataHandler getConfigDataHandlerWithListenerListE( - String dataId, List configDataListenerList, - Executor executor) { - return this - .getConfigDataHandlerWithListenerListCE(dataId, - configDataListenerList, executor, - new HashMap()); - } - - - public ConfigDataHandler getConfigDataHandlerCE(String dataId, - ConfigDataListener configDataListener, Executor executor, - Map config) { - List configDataListenerList = new ArrayList(); - configDataListenerList.add(configDataListener); - return this.getConfigDataHandlerWithListenerListCE(dataId, - configDataListenerList, executor, config); - } - - public ConfigDataHandler getConfigDataHandlerWithListenerListCE( - String dataId, List configDataListenerList, - Executor executor, Map config) { - try { - ConfigDataHandler instance = (ConfigDataHandler) handlerConstructor - .newInstance(); - Map configMap = new HashMap(); - if (config != null) { - configMap.putAll(config); - } - - if (prop != null) { - configMap.putAll((Map) prop); - } - instance.init(dataId, configDataListenerList, configMap); - return instance; - } catch (IllegalArgumentException e) { - log.error("illegal arguments!", e); - } catch (InstantiationException e) { - log.error("handler init error!", e); - } catch (IllegalAccessException e) { - log.error("securty limit,handler can not be init!", e); - } catch (InvocationTargetException e) { - log.error("constructor invode error!", e); - } - return null; - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java deleted file mode 100644 index de587f48..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -//Copyright(c) Taobao.com -package com.taobao.tdhs.config; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import com.taobao.diamond.client.DiamondConfigure; -import com.taobao.diamond.client.impl.DiamondClientFactory; - -/** - * @description - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-17����07:21:41 - */ -public class DiamondConfig { - private volatile static DiamondConfigure configure = DiamondClientFactory - .getSingletonDiamondSubscriber().getDiamondConfigure(); - - protected static void handleConfig(Map prop) { - if(null==prop){ - return; - } - - Object interval = prop.get("pollingIntervalTime"); - if (interval != null) { - configure.setPollingIntervalTime((Integer) interval); - } - - Object connectTimeOut = prop.get("connectTimeOut"); - if (connectTimeOut != null) { - configure.setConnectionTimeout((Integer) connectTimeOut); - } - - Object onceTimeout = prop.get("onceTimeout"); - if (onceTimeout != null) { - configure.setOnceTimeout((Integer) onceTimeout); - } - - Object receiveWaitTime = prop.get("receiveWaitTime"); - if (receiveWaitTime != null) { - configure.setReceiveWaitTime((Integer) receiveWaitTime); - } - - Object domainNames = prop.get("domainNames"); - if (domainNames != null) { - String[] domains = String.valueOf(domainNames).split(","); - List domainNameList = Arrays.asList(domains); - configure.setDomainNameList(domainNameList); - } - - Object maxHostConns = prop.get("maxHostConns"); - if (maxHostConns != null) { - configure.setMaxHostConnections((Integer) maxHostConns); - } - - Object connStateCheckEnable = prop.get("connStateCheckEnable"); - if (connStateCheckEnable != null) { - configure.setConnectionStaleCheckingEnabled(Boolean.valueOf(String - .valueOf(connStateCheckEnable))); - } - - Object maxTotalConns=prop.get("maxTotalConns"); - if (maxTotalConns != null) { - configure.setMaxTotalConnections((Integer)maxTotalConns); - } - - Object filePath=prop.get("filePath"); - if (filePath != null) { - configure.setFilePath((String)filePath); - } - - Object port=prop.get("port"); - if (port != null) { - configure.setFilePath((String)port); - } - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java deleted file mode 100644 index 3f6d8d2d..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondConfigDataHandler.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.taobao.diamond.manager.DiamondManager; -import com.taobao.diamond.manager.ManagerListener; -import com.taobao.diamond.manager.impl.DefaultDiamondManager; - -/** - * @author shenxun - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-1-11����11:22:29 - * @desc �־���������diamondʵ�� - */ -public class DiamondConfigDataHandler implements ConfigDataHandler { - private static final Log logger = LogFactory - .getLog(DiamondConfigDataHandler.class); - private DiamondManager diamondManager; - private String dataId; - private String mbeanId; - - public void init(final String dataId, - final List configDataListenerList, - final Map config) { - mbeanId = dataId + System.currentTimeMillis(); - DiamondConfig.handleConfig(config); - DefaultDiamondManager.Builder builder = new DefaultDiamondManager.Builder( - dataId, new ManagerListener() { - public void receiveConfigInfo(String data) { - if (configDataListenerList != null) { - for (ConfigDataListener configDataListener : configDataListenerList) { - configDataListener.onDataRecieved(dataId, data); - } - } - } - - public Executor getExecutor() { - return (Executor) config.get("executor"); - } - }); - String group = (String) config.get("group"); - if (null != group) { - builder.setGroup(group); - } - this.diamondManager = builder.build(); - this.dataId = dataId; - - } - - public String getData(long timeout, String strategy) { - String data = null; - if (strategy != null - && strategy - .equals(ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY)) { - data = diamondManager.getAvailableConfigureInfomation(timeout); - } else if (strategy != null - && strategy.equals(ConfigDataHandler.FIRST_SERVER_STRATEGY)) { - data = diamondManager.getConfigureInfomation(timeout); - } - - - return data; - } - - public void addListener(final ConfigDataListener configDataListener, - final Executor executor) { - if (configDataListener != null) { - diamondManager.setManagerListener(new ManagerListener() { - public void receiveConfigInfo(String data) { - configDataListener.onDataRecieved(dataId, data); - } - - public Executor getExecutor() { - return executor; - } - }); - } - } - - public void addListeners( - final List configDataListenerList, - final Executor executor) { - if (configDataListenerList != null) { - diamondManager.setManagerListener(new ManagerListener() { - public void receiveConfigInfo(String data) { - for (ConfigDataListener configDataListener : configDataListenerList) { - try { - configDataListener.onDataRecieved(dataId, data); - } catch (Exception e) { - logger.error("one of listener failed", e); - continue; - } - } - - } - - public Executor getExecutor() { - return executor; - } - }); - } - } - - public void closeUnderManager() { - diamondManager.close(); - } - - public String getDataId() { - return dataId; - } - - public void setDataId(String dataId) { - this.dataId = dataId; - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java deleted file mode 100644 index 9363605b..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbConfManager.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * ȫ�ֺ�Ӧ�õ����ù���Diamondʵ�� - * - * @author qihao - * - */ -public class DiamondDbConfManager implements DbConfManager { - private static Log logger = LogFactory.getLog(DiamondDbConfManager.class); - private String globalConfigDataId; - private String appConfigDataId; - private ConfigDataHandlerFactory configFactory; - private ConfigDataHandler globalHandler; - private ConfigDataHandler appDBHandler; - private volatile List globalDbConfListener = new ArrayList(); - private volatile List appDbConfListener = new ArrayList(); - - public void init() { - configFactory = new DefaultConfigDataHandlerFactory(); - Map config = new HashMap(); - config.put("group", TAtomConstants.DEFAULT_DIAMOND_GROUP); - globalHandler = configFactory.getConfigDataHandlerWithListenerListCE( - globalConfigDataId, globalDbConfListener, - Executors.newSingleThreadScheduledExecutor(), config); - appDBHandler = configFactory.getConfigDataHandlerWithListenerListCE( - appConfigDataId, appDbConfListener, - Executors.newSingleThreadScheduledExecutor(), config); - } - - public String getAppDbConfDataId() { - return appConfigDataId; - } - - public String getAppDbDbConf() { - if (null != appDBHandler) { - return appDBHandler.getData(TDDLConstant.DIAMOND_GET_DATA_TIMEOUT,ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); - } - logger.error("[getDataError] appDBConfig not init !"); - return null; - } - - public String getGlobalDbConf() { - if (null != globalHandler) { - return globalHandler.getData(TDDLConstant.DIAMOND_GET_DATA_TIMEOUT,ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); - } - logger.error("[getDataError] globalConfig not init !"); - return null; - } - - public void setGlobalConfigDataId(String globalConfigDataId) { - this.globalConfigDataId = globalConfigDataId; - } - - public String getAppConfigDataId() { - return appConfigDataId; - } - - public void setAppConfigDataId(String appConfigDataId) { - this.appConfigDataId = appConfigDataId; - } - - /** - * @param Listener - */ - public void registerGlobaDbConfListener(ConfigDataListener listener) { - globalDbConfListener.add(listener); - } - - /** - * @param Listener - */ - public void registerAppDbConfListener(ConfigDataListener listener) { - appDbConfListener.add(listener); - } - - public void stopDbConfManager() { - if (null != this.globalHandler) { - this.globalHandler.closeUnderManager(); - } - if (null != this.appDBHandler) { - this.appDBHandler.closeUnderManager(); - } - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java deleted file mode 100644 index c3edb7d6..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/DiamondDbPasswdManager.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Executors; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * ���������Diamondʵ�� - * - * @author qihao - * - */ -public class DiamondDbPasswdManager implements DbPasswdManager { - private static Log logger = LogFactory.getLog(DiamondDbPasswdManager.class); - private String passwdConfDataId; - private ConfigDataHandlerFactory configFactory; - private ConfigDataHandler passwdHandler; - private volatile List passwdConfListener = new ArrayList(); - - public void init() { - configFactory = new DefaultConfigDataHandlerFactory(); - Map config = new HashMap(); - config.put("group", TAtomConstants.DEFAULT_DIAMOND_GROUP); - passwdHandler = configFactory.getConfigDataHandlerWithListenerListCE( - passwdConfDataId, passwdConfListener, - Executors.newSingleThreadScheduledExecutor(), config); - } - - public String getPasswd() { - if (null != passwdHandler) { - String passwdStr = passwdHandler.getData( - TDDLConstant.DIAMOND_GET_DATA_TIMEOUT, - ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); - if (passwdStr == null) { - logger.error("[getDataError] remote password string is empty !"); - return null; - } - return TAtomConfParser.parserPasswd(passwdStr); - } - logger.error("[getDataError] passwdConfig not init !"); - return null; - } - - public void registerPasswdConfListener(ConfigDataListener Listener) { - passwdConfListener.add(Listener); - } - - public void setPasswdConfDataId(String passwdConfDataId) { - this.passwdConfDataId = passwdConfDataId; - } - - public void stopDbPasswdManager() { - if (null != this.passwdHandler) { - this.passwdHandler.closeUnderManager(); - } - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java deleted file mode 100644 index 31dcf12c..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/SecureIdentityLoginModule.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.taobao.tdhs.config; - -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.commons.lang.StringUtils; - -public class SecureIdentityLoginModule { - - private static byte[] ENC_KEY_BYTES = "jaas is the way".getBytes(); - - private String userName; - - private String password; - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getDecodedPassword() throws Exception { - return new String(decode(password)); - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((password == null) ? 0 : password.hashCode()); - result = prime * result + ((userName == null) ? 0 : userName.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - SecureIdentityLoginModule other = (SecureIdentityLoginModule) obj; - if (password == null) { - if (other.password != null) return false; - } else if (!password.equals(other.password)) return false; - if (userName == null) { - if (other.userName != null) return false; - } else if (!userName.equals(other.userName)) return false; - return true; - } - - public static String encode(String encKey, String secret) throws NoSuchAlgorithmException, NoSuchPaddingException, - InvalidKeyException, IllegalBlockSizeException, - BadPaddingException { - byte[] kbytes = SecureIdentityLoginModule.ENC_KEY_BYTES; - if (StringUtils.isNotBlank(encKey)) { - kbytes = encKey.getBytes(); - } - SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish"); - Cipher cipher = Cipher.getInstance("Blowfish"); - cipher.init(Cipher.ENCRYPT_MODE, key); - byte[] encoding = cipher.doFinal(secret.getBytes()); - BigInteger n = new BigInteger(encoding); - return n.toString(16); - } - - public static String encode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, - InvalidKeyException, BadPaddingException, IllegalBlockSizeException { - return SecureIdentityLoginModule.encode(null, secret); - } - - public static String decode(String encKey, String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, - InvalidKeyException, BadPaddingException, - IllegalBlockSizeException { - byte[] kbytes = SecureIdentityLoginModule.ENC_KEY_BYTES; - if (StringUtils.isNotBlank(encKey)) { - kbytes = encKey.getBytes(); - } - SecretKeySpec key = new SecretKeySpec(kbytes, "Blowfish"); - BigInteger n = new BigInteger(secret, 16); - byte[] encoding = n.toByteArray(); - Cipher cipher = Cipher.getInstance("Blowfish"); - cipher.init(Cipher.DECRYPT_MODE, key); - byte[] decode = cipher.doFinal(encoding); - return new String(decode); - } - - public static char[] decode(String secret) throws NoSuchPaddingException, NoSuchAlgorithmException, - InvalidKeyException, BadPaddingException, IllegalBlockSizeException { - return SecureIdentityLoginModule.decode(null, secret).toCharArray(); - } - - public static void main(String[] args) throws Exception { - System.out.println("Encoded password: " + new String(SecureIdentityLoginModule.encode("Config_RsA+"))); - System.out.println("decoded password: " - + new String(SecureIdentityLoginModule.decode("-5ba6f4c59342aa2ce70e0b8bdc250194e9eba007b67f1e12"))); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java deleted file mode 100644 index 2b95164d..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConfParser.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.taobao.tdhs.config; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.alibaba.common.lang.StringUtil; -import com.alibaba.common.lang.io.ByteArrayInputStream; - -/** - * TAtomæ•°æ®æºçš„æŽ¨é€é…置解æžç±» - * - * @author qihao - */ -public class TAtomConfParser { - - private static Log logger = LogFactory.getLog(TAtomConfParser.class); - - public static final String GLOBA_IP_KEY = "ip"; - public static final String GLOBA_PORT_KEY = "port"; - public static final String GLOBA_DB_NAME_KEY = "dbName"; - public static final String GLOBA_DB_TYPE_KEY = "dbType"; - public static final String GLOBA_DB_STATUS_KEY = "dbStatus"; - public static final String APP_USER_NAME_KEY = "userName"; - public static final String APP_MIN_POOL_SIZE_KEY = "minPoolSize"; - public static final String APP_MAX_POOL_SIZE_KEY = "maxPoolSize"; - public static final String APP_IDLE_TIMEOUT_KEY = "idleTimeout"; - public static final String APP_BLOCKING_TIMEOUT_KEY = "blockingTimeout"; - public static final String APP_PREPARED_STATEMENT_CACHE_SIZE_KEY = "preparedStatementCacheSize"; - public static final String APP_ORACLE_CON_TYPE_KEY = "oracleConType"; - public static final String APP_CON_PROP_KEY = "connectionProperties"; - public static final String PASSWD_ENC_PASSWD_KEY = "encPasswd"; - public static final String PASSWD_ENC_KEY_KEY = "encKey"; - /** - * 写,次数é™åˆ¶ - */ - public static final String APP_WRITE_RESTRICT_TIMES = "writeRestrictTimes"; - /** - * 读,次数é™åˆ¶ - */ - public static final String APP_READ_RESTRICT_TIMES = "readRestrictTimes"; - /** - * thread count 次数é™åˆ¶ - */ - public static final String APP_THREAD_COUNT_RESTRICT = "threadCountRestrict"; - - public static final String APP_TIME_SLICE_IN_MILLS = "timeSliceInMillis"; - - public static TAtomDsConfDO parserTAtomDsConfDO(String globaConfStr, String appConfStr) { - TAtomDsConfDO pasObj = new TAtomDsConfDO(); - if (StringUtil.isNotBlank(globaConfStr)) { - Properties globaProp = TAtomConfParser.parserConfStr2Properties(globaConfStr); - if (!globaProp.isEmpty()) { - String ip = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_IP_KEY)); - if (StringUtil.isNotBlank(ip)) { - pasObj.setIp(ip); - } - String port = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_PORT_KEY)); - if (StringUtil.isNotBlank(port)) { - pasObj.setPort(port); - } - String dbName = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_NAME_KEY)); - if (StringUtil.isNotBlank(dbName)) { - pasObj.setDbName(dbName); - } - String dbType = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_TYPE_KEY)); - if (StringUtil.isNotBlank(dbType)) { - pasObj.setDbType(dbType); - } - String dbStatus = StringUtil.trim(globaProp.getProperty(TAtomConfParser.GLOBA_DB_STATUS_KEY)); - if (StringUtil.isNotBlank(dbStatus)) { - pasObj.setDbStatus(dbStatus); - } - } - } - if (StringUtil.isNotBlank(appConfStr)) { - Properties appProp = TAtomConfParser.parserConfStr2Properties(appConfStr); - if (!appProp.isEmpty()) { - String userName = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_USER_NAME_KEY)); - if (StringUtil.isNotBlank(userName)) { - pasObj.setUserName(userName); - } - String oracleConType = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_ORACLE_CON_TYPE_KEY)); - if (StringUtil.isNotBlank(oracleConType)) { - pasObj.setOracleConType(oracleConType); - } - String minPoolSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_MIN_POOL_SIZE_KEY)); - if (StringUtil.isNotBlank(minPoolSize) && StringUtil.isNumeric(minPoolSize)) { - pasObj.setMinPoolSize(Integer.valueOf(minPoolSize)); - } - String maxPoolSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_MAX_POOL_SIZE_KEY)); - if (StringUtil.isNotBlank(maxPoolSize) && StringUtil.isNumeric(maxPoolSize)) { - pasObj.setMaxPoolSize(Integer.valueOf(maxPoolSize)); - } - String idleTimeout = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_IDLE_TIMEOUT_KEY)); - if (StringUtil.isNotBlank(idleTimeout) && StringUtil.isNumeric(idleTimeout)) { - pasObj.setIdleTimeout(Long.valueOf(idleTimeout)); - } - String blockingTimeout = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_BLOCKING_TIMEOUT_KEY)); - if (StringUtil.isNotBlank(blockingTimeout) && StringUtil.isNumeric(blockingTimeout)) { - pasObj.setBlockingTimeout(Integer.valueOf(blockingTimeout)); - } - String preparedStatementCacheSize = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_PREPARED_STATEMENT_CACHE_SIZE_KEY)); - if (StringUtil.isNotBlank(preparedStatementCacheSize) - && StringUtil.isNumeric(preparedStatementCacheSize)) { - pasObj.setPreparedStatementCacheSize(Integer.valueOf(preparedStatementCacheSize)); - } - - String writeRestrictTimes = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_WRITE_RESTRICT_TIMES)); - if (StringUtil.isNotBlank(writeRestrictTimes) && StringUtil.isNumeric(writeRestrictTimes)) { - pasObj.setWriteRestrictTimes(Integer.valueOf(writeRestrictTimes)); - } - - String readRestrictTimes = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_READ_RESTRICT_TIMES)); - if (StringUtil.isNotBlank(readRestrictTimes) && StringUtil.isNumeric(readRestrictTimes)) { - pasObj.setReadRestrictTimes(Integer.valueOf(readRestrictTimes)); - } - String threadCountRestrict = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_THREAD_COUNT_RESTRICT)); - if (StringUtil.isNotBlank(threadCountRestrict) && StringUtil.isNumeric(threadCountRestrict)) { - pasObj.setThreadCountRestrict(Integer.valueOf(threadCountRestrict)); - } - String timeSliceInMillis = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_TIME_SLICE_IN_MILLS)); - if (StringUtil.isNotBlank(timeSliceInMillis) && StringUtil.isNumeric(timeSliceInMillis)) { - pasObj.setTimeSliceInMillis(Integer.valueOf(timeSliceInMillis)); - } - - String conPropStr = StringUtil.trim(appProp.getProperty(TAtomConfParser.APP_CON_PROP_KEY)); - Map connectionProperties = parserConPropStr2Map(conPropStr); - if (null != connectionProperties && !connectionProperties.isEmpty()) { - pasObj.setConnectionProperties(connectionProperties); - } - } - } - return pasObj; - } - - public static Map parserConPropStr2Map(String conPropStr) { - Map connectionProperties = null; - if (StringUtil.isNotBlank(conPropStr)) { - String[] keyValues = StringUtil.split(conPropStr, ";"); - if (null != keyValues && keyValues.length > 0) { - connectionProperties = new HashMap(keyValues.length); - for (String keyValue : keyValues) { - String key = StringUtil.substringBefore(keyValue, "="); - String value = StringUtil.substringAfter(keyValue, "="); - if (StringUtil.isNotBlank(key) && StringUtil.isNotBlank(value)) { - connectionProperties.put(key, value); - } - } - } - } - return connectionProperties; - } - - public static String parserPasswd(String passwdStr) { - String passwd = null; - Properties passwdProp = TAtomConfParser.parserConfStr2Properties(passwdStr); - String encPasswd = passwdProp.getProperty(TAtomConfParser.PASSWD_ENC_PASSWD_KEY); - if (StringUtil.isNotBlank(encPasswd)) { - String encKey = passwdProp.getProperty(TAtomConfParser.PASSWD_ENC_KEY_KEY); - try { - passwd = SecureIdentityLoginModule.decode(encKey, encPasswd); - } catch (Exception e) { - logger.error("[parserPasswd Error] decode dbPasswdError!may jdk version error!", e); - } - } - return passwd; - } - - private static Properties parserConfStr2Properties(String data) { - Properties prop = new Properties(); - if (StringUtil.isNotBlank(data)) { - ByteArrayInputStream byteArrayInputStream = null; - try { - byteArrayInputStream = new ByteArrayInputStream((data).getBytes()); - prop.load(byteArrayInputStream); - } catch (IOException e) { - logger.error("parserConfStr2Properties Error", e); - } finally { - byteArrayInputStream.close(); - } - } - return prop; - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java deleted file mode 100644 index 3d6e5af1..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomConstants.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.taobao.tdhs.config; - -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Map; - -/** - * TAtomæ•°æ®æºçš„常é‡è®¾ç½®ç±» - * - * @author qihao - * - */ -public class TAtomConstants { - - public final static String DEFAULT_DIAMOND_GROUP = null; - - public final static String DEFAULT_MYSQL_CHAR_SET = "gbk"; - - //public final static String ORACLE_DBTYPE_STR = "ORACLE"; - - //public final static String MYSQL_DBTYPE_STR = "MYSQL"; - - public final static String DEFAULT_ORACLE_CON_TYPE = "oci"; - - public final static String DB_STATUS_R = "R"; - - public final static String DB_STATUS_W = "W"; - - public final static String DB_STATUS_RW = "RW"; - - public final static String DB_STATUS_NA = "NA"; - - public static Map DEFAULT_ORACLE_CONNECTION_PROPERTIES = new HashMap( - 2); - static { - TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( - "SetBigStringTryClob", "true"); - TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( - "defaultRowPrefetch", "50"); - } - - public static Map DEFAULT_MYSQL_CONNECTION_PROPERTIES = new HashMap( - 1); - static { - TAtomConstants.DEFAULT_MYSQL_CONNECTION_PROPERTIES.put( - "characterEncoding", "gbk"); - } - - public final static String DEFAULT_ORACLE_DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver"; - - public final static String DEFAULT_MYSQL_DRIVER_CLASS = "com.mysql.jdbc.Driver"; - - public final static String DEFAULT_ORACLE_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.OracleExceptionSorter"; - - public final static String DEFAULT_MYSQL_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.MySQLExceptionSorter"; - - - public final static String MYSQL_INTEGRATION_SORTER_CLASS = "com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter"; - - public final static String DEFAULT_MYSQL_VALID_CONNECTION_CHECKERCLASS = "com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker"; - - /** - * 全局é…ç½®dataIdæ¨¡æ¿ - */ - private static MessageFormat GLOBAL_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.global.{0}"); - - /** - * 应用é…ç½®dataIdæ¨¡æ¿ - */ - private static MessageFormat APP_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.app.{0}.{1}"); - - private static MessageFormat PASSWD_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.passwd.{0}.{1}.{2}"); - - /** - * dbNameæ¨¡æ¿ - */ - private static MessageFormat DB_NAME_FORMAT = new MessageFormat( - "atom.dbkey.{0}^{1}"); - - /** - * æ ¹æ®dbKey获å–全局é…ç½®dataId - * - * @param dbKey - * æ•°æ®åº“åKEY - * @return - */ - public static String getGlobalDataId(String dbKey) { - return GLOBAL_FORMAT.format(new Object[] { dbKey }); - } - - /** - * æ ¹æ®åº”用åå’ŒdbKeyèŽ·å–æŒ‡å®šçš„应用é…ç½®dataId - * - * @param appName - * @param dbKey - * @return - */ - public static String getAppDataId(String appName, String dbKey) { - return APP_FORMAT.format(new Object[] { appName, dbKey }); - } - - /** - * æ ¹æ®dbKeyå’ŒuserName获得对应的passwdçš„dataId - * - * @param dbKey - * @param userName - * @return - */ - public static String getPasswdDataId(String dbName, String dbType, - String userName) { - return PASSWD_FORMAT.format(new Object[] { dbName, dbType, userName }); - } - - /** - * @param appName - * @param dbkey - * @return - */ - public static String getDbNameStr(String appName, String dbkey) { - return DB_NAME_FORMAT.format(new Object[] { appName, dbkey }); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java deleted file mode 100644 index 12764693..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfDO.java +++ /dev/null @@ -1,294 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.HashMap; -import java.util.Map; - -import com.alibaba.common.lang.StringUtil; - -/** - * TAtomæ•°æ®æºå…¨å±€å’Œåº”用é…置的DO - * - * @author qihao - * @author shenxun - * - */ -public class TAtomDsConfDO implements Cloneable { - - private String ip; - - private String port; - - private String dbName; - - private String userName; - - private String passwd; - - private String driverClass; - - private String sorterClass; - - private int preparedStatementCacheSize; - - private int minPoolSize; - - private int maxPoolSize; - - private int blockingTimeout; - - private long idleTimeout; - - //private String dbType; - - private String oracleConType = TAtomConstants.DEFAULT_ORACLE_CON_TYPE; - - private AtomDbTypeEnum dbTypeEnum; - - private AtomDbStatusEnum dbStautsEnum; - - private String dbStatus; - - private Map connectionProperties = new HashMap(); - - /** - * 写 次数é™åˆ¶ - */ - private int writeRestrictTimes; - - /** - * 读 次数é™åˆ¶ - */ - private int readRestrictTimes; - - /** - * 统计时间片 - */ - private int timeSliceInMillis; - - /** - * 线程技术counté™åˆ¶ - */ - private int threadCountRestrict; - - /** - * å…许并å‘读的最大个数,0为ä¸é™åˆ¶ - */ - private int maxConcurrentReadRestrict; - - /** - * å…许并å‘写的最大个数,0为ä¸é™åˆ¶ - */ - private int maxConcurrentWriteRestrict; - - private volatile boolean isSingleInGroup; - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public String getPort() { - return port; - } - - public void setPort(String port) { - this.port = port; - } - - public String getDbName() { - return dbName; - } - - public void setDbName(String dbName) { - this.dbName = dbName; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getPasswd() { - return passwd; - } - - public void setPasswd(String passwd) { - this.passwd = passwd; - } - - public String getDriverClass() { - if (StringUtil.isBlank(driverClass) && null != this.dbTypeEnum) { - return this.dbTypeEnum.getDriverClass(); - } - return driverClass; - } - - public void setDriverClass(String driverClass) { - this.driverClass = driverClass; - } - - public String getSorterClass() { - if (StringUtil.isBlank(sorterClass) && null != this.dbTypeEnum) { - return this.dbTypeEnum.getSorterClass(); - } - return sorterClass; - } - - public void setSorterClass(String sorterClass) { - this.sorterClass = sorterClass; - } - - public int getPreparedStatementCacheSize() { - return preparedStatementCacheSize; - } - - public void setPreparedStatementCacheSize(int preparedStatementCacheSize) { - this.preparedStatementCacheSize = preparedStatementCacheSize; - } - - public int getMinPoolSize() { - return minPoolSize; - } - - public void setMinPoolSize(int minPoolSize) { - this.minPoolSize = minPoolSize; - } - - public int getMaxPoolSize() { - return maxPoolSize; - } - - public void setMaxPoolSize(int maxPoolSize) { - this.maxPoolSize = maxPoolSize; - } - - public int getBlockingTimeout() { - return blockingTimeout; - } - - public void setBlockingTimeout(int blockingTimeout) { - this.blockingTimeout = blockingTimeout; - } - - public long getIdleTimeout() { - return idleTimeout; - } - - public void setIdleTimeout(long idleTimeout) { - this.idleTimeout = idleTimeout; - } - - public Map getConnectionProperties() { - return connectionProperties; - } - - public String getDbType() { - return dbTypeEnum.name().toLowerCase(); - } - - public void setDbType(String dbType) { - this.dbTypeEnum = AtomDbTypeEnum.getAtomDbTypeEnumByType(dbType); - } - - public String getDbStatus() { - return dbStatus; - } - - public void setDbStatus(String dbStatus) { - this.dbStatus = dbStatus; - if (StringUtil.isNotBlank(dbStatus)) { - this.dbStautsEnum = AtomDbStatusEnum.getAtomDbStatusEnumByType(dbStatus); - } - } - - public AtomDbStatusEnum getDbStautsEnum() { - return dbStautsEnum; - } - - public AtomDbTypeEnum getDbTypeEnum() { - return dbTypeEnum; - } - - public void setConnectionProperties(Map connectionProperties) { - this.connectionProperties = connectionProperties; - } - - public String getOracleConType() { - return oracleConType; - } - - public void setOracleConType(String oracleConType) { - this.oracleConType = oracleConType; - } - - public int getWriteRestrictTimes() { - return writeRestrictTimes; - } - - public void setWriteRestrictTimes(int writeRestrictTimes) { - this.writeRestrictTimes = writeRestrictTimes; - } - - public int getReadRestrictTimes() { - return readRestrictTimes; - } - - public void setReadRestrictTimes(int readRestrictTimes) { - this.readRestrictTimes = readRestrictTimes; - } - - public int getThreadCountRestrict() { - return threadCountRestrict; - } - - public void setThreadCountRestrict(int threadCountRestrict) { - this.threadCountRestrict = threadCountRestrict; - } - - public int getTimeSliceInMillis() { - return timeSliceInMillis; - } - - public void setTimeSliceInMillis(int timeSliceInMillis) { - this.timeSliceInMillis = timeSliceInMillis; - } - - public int getMaxConcurrentReadRestrict() { - return maxConcurrentReadRestrict; - } - - public void setMaxConcurrentReadRestrict(int maxConcurrentReadRestrict) { - this.maxConcurrentReadRestrict = maxConcurrentReadRestrict; - } - - public int getMaxConcurrentWriteRestrict() { - return maxConcurrentWriteRestrict; - } - - public void setMaxConcurrentWriteRestrict(int maxConcurrentWriteRestrict) { - this.maxConcurrentWriteRestrict = maxConcurrentWriteRestrict; - } - - public TAtomDsConfDO clone() { - TAtomDsConfDO tAtomDsConfDO = null; - try { - tAtomDsConfDO = (TAtomDsConfDO) super.clone(); - } catch (CloneNotSupportedException e) { - } - return tAtomDsConfDO; - } - - public boolean isSingleInGroup() { - return isSingleInGroup; - } - - public void setSingleInGroup(boolean isSingleInGroup) { - this.isSingleInGroup = isSingleInGroup; - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java deleted file mode 100644 index 50cce6bc..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/TAtomDsConfHandle.java +++ /dev/null @@ -1,318 +0,0 @@ -package com.taobao.tdhs.config; - -import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; - -import org.adbcj.ConnectionManager; -import org.adbcj.mysql.netty.WrappedMysqlConnectionManager; -import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.alibaba.common.lang.StringUtil; - -/** - * æ•°æ®åº“动æ€åˆ‡æ¢çš„Handle类,所有数æ®åº“的动æ€åˆ‡æ¢ éƒ½æ˜¯ç”±è¿™ä¸ªç±»å®Œæˆ - * - * @author qihao - */ -public class TAtomDsConfHandle { - - private static Log logger = LogFactory.getLog(TAtomDsConfHandle.class); - private String appName; - - private String dbKey; - - private ConnectionManager connectionManager; - /** - * è¿è¡Œæ—¶é…ç½® - */ - private volatile TAtomDsConfDO runTimeConf = new TAtomDsConfDO(); - - /** - * 本地é…置,优先于推é€çš„动æ€é…ç½® - */ - private TAtomDsConfDO localConf = new TAtomDsConfDO(); - - /** - * 全局é…置,应用é…ç½®è®¢é˜…ç®¡ç† - */ - private DbConfManager dbConfManager; - - /** - * 密ç é…ç½®è®¢é˜…ç®¡ç† - */ - private DbPasswdManager dbPasswdManager; - - /** - * åˆå§‹åŒ–标记为一但åˆå§‹åŒ–过,所有本地的é…ç½®ç¦æ­¢æ”¹åЍ - */ - private volatile boolean initFalg; - - /** - * æ•°æ®æºæ“作é”,当需è¦å¯¹æ•°æ®æºè¿›è¡Œé‡å»ºæˆ–者刷新时需è¦å…ˆèŽ·å¾—è¯¥é” - */ - private final ReentrantLock lock = new ReentrantLock(); - - /** - * åˆå§‹åŒ–æ–¹æ³•ï¼Œåˆ›å»ºå¯¹åº”çš„æ•°æ®æºï¼Œåªèƒ½è¢«è°ƒç”¨ä¸€æ¬¡ - * - * @throws Exception - */ - public void init() throws Exception { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] double call Init !"); - } - // 1.åˆå§‹åŒ–傿•°æ£€æŸ¥ - if (StringUtil.isBlank(this.appName) || StringUtil.isBlank(this.dbKey)) { - String errorMsg = "[attributeError] TAtomDatasource of appName Or dbKey is Empty !"; - logger.error(errorMsg); - throw new AtomIllegalException(errorMsg); - } - // 2.é…ç½®dbConfManager - DiamondDbConfManager defaultDbConfManager = new DiamondDbConfManager(); - defaultDbConfManager.setGlobalConfigDataId(TAtomConstants.getGlobalDataId(this.dbKey)); - defaultDbConfManager.setAppConfigDataId(TAtomConstants.getAppDataId(this.appName, this.dbKey)); - // åˆå§‹åŒ–dbConfManager - defaultDbConfManager.init(); - dbConfManager = defaultDbConfManager; - // 3.获å–全局é…ç½® - String globaConfStr = dbConfManager.getGlobalDbConf(); - // 注册全局é…ç½®ç›‘å¬ - registerGlobaDbConfListener(defaultDbConfManager); - if (StringUtil.isBlank(globaConfStr)) { - String errorMsg = "[ConfError] read globalConfig is Empty !"; - logger.error(errorMsg); - throw new AtomInitialException(errorMsg); - } - // 4.获å–应用é…ç½® - String appConfStr = dbConfManager.getAppDbDbConf(); - // 注册应用é…ç½®ç›‘å¬ - registerAppDbConfListener(defaultDbConfManager); - if (StringUtil.isBlank(appConfStr)) { - String errorMsg = "[ConfError] read appConfig is Empty !"; - logger.error(errorMsg); - throw new AtomInitialException(errorMsg); - } - lock.lock(); - try { - // 5.è§£æžé…ç½®stringæˆTAtomDsConfDO - runTimeConf = TAtomConfParser.parserTAtomDsConfDO(globaConfStr, appConfStr); - // 6.å¤„ç†æœ¬åœ°ä¼˜å…ˆé…ç½® - overConfByLocal(localConf, runTimeConf); - // 7.如果没有设置本地密ç ï¼Œåˆ™ç”¨è®¢çš„密ç ï¼Œåˆå§‹åŒ–passwdManager - if (StringUtil.isBlank(this.runTimeConf.getPasswd())) { - // 检查dbKey和对应的userName是å¦ä¸ºç©º - if (StringUtil.isBlank(runTimeConf.getUserName())) { - String errorMsg = "[attributeError] TAtomDatasource of UserName is Empty !"; - logger.error(errorMsg); - throw new AtomIllegalException(errorMsg); - } - DiamondDbPasswdManager diamondDbPasswdManager = new DiamondDbPasswdManager(); - diamondDbPasswdManager.setPasswdConfDataId(TAtomConstants.getPasswdDataId(runTimeConf.getDbName(), - runTimeConf.getDbType(), - runTimeConf.getUserName())); - diamondDbPasswdManager.init(); - dbPasswdManager = diamondDbPasswdManager; - // 获å–å¯†ç  - String passwd = dbPasswdManager.getPasswd(); - if (StringUtil.isBlank(passwd)) { - String errorMsg = "[PasswdError] read passwd is Empty !"; - logger.error(errorMsg); - throw new AtomInitialException(errorMsg); - } - runTimeConf.setPasswd(passwd); - } - String ip = runTimeConf.getIp(); - - String port = runTimeConf.getPort(); - // 因为是epoll模型,所以连接数å‡å°‘一些 - - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - int blockingTimeout = runTimeConf.getBlockingTimeout(); - if (blockingTimeout > -1) { - config.setBlockWhenExhausted(true); - config.setMaxWaitMillis(blockingTimeout); - } else { - config.setBlockWhenExhausted(false); - } - - int maxPoolSize = runTimeConf.getMaxPoolSize(); - if (maxPoolSize > 0) { - config.setMaxTotal(maxPoolSize); - } - int minPoolSize = runTimeConf.getMinPoolSize(); - if (minPoolSize > 0) { - config.setMinIdle(minPoolSize); - } - config.setLifo(false); - connectionManager = new WrappedMysqlConnectionManager(ip, - Integer.valueOf(port), - runTimeConf.getUserName(), - runTimeConf.getPasswd(), - runTimeConf.getDbName(), - null, - config); - initFalg = true; - } finally { - lock.unlock(); - } - } - - /** - * 全局é…置监å¬,全局é…ç½®å‘生å˜åŒ–, 需è¦é‡æ–°FLUSHæ•°æ®æº - * - * @param defaultDbConfManager - */ - private void registerGlobaDbConfListener(DbConfManager dbConfManager) { - dbConfManager.registerGlobaDbConfListener(new ConfigDataListener() { - - public void onDataRecieved(String dataId, String data) { - logger.error("[GlobaConf HandleData] dataId : " + dataId + " data: " + data); - if (null == data || StringUtil.isBlank(data)) { - return; - } - lock.lock(); - try { - } finally { - lock.unlock(); - } - } - - }); - } - - /** - * 应用é…置监å¬ï¼Œå½“应用é…ç½®å‘生å˜åŒ–时,区分å‘生 å˜åŒ–çš„é…置,æ¥å†³å®šå…·ä½“是flush还是reCreate - * - * @param defaultDbConfManager - */ - private void registerAppDbConfListener(DbConfManager dbConfManager) { - dbConfManager.registerAppDbConfListener(new ConfigDataListener() { - - public void onDataRecieved(String dataId, String data) { - logger.error("[AppConf HandleData] dataId : " + dataId + " data: " + data); - if (null == data || StringUtil.isBlank(data)) { - return; - } - lock.lock(); - try { - String appConfStr = data; - TAtomDsConfDO tmpConf = TAtomConfParser.parserTAtomDsConfDO(null, appConfStr); - TAtomDsConfDO newConf = TAtomDsConfHandle.this.runTimeConf.clone(); - // 有些既有é…ç½®ä¸èƒ½å˜æ›´ï¼Œæ‰€ä»¥å…‹éš†è€çš„é…置,然åŽå°†æ–°çš„set进去 - newConf.setUserName(tmpConf.getUserName()); - newConf.setMinPoolSize(tmpConf.getMinPoolSize()); - newConf.setMaxPoolSize(tmpConf.getMaxPoolSize()); - newConf.setIdleTimeout(tmpConf.getIdleTimeout()); - newConf.setBlockingTimeout(tmpConf.getBlockingTimeout()); - newConf.setPreparedStatementCacheSize(tmpConf.getPreparedStatementCacheSize()); - newConf.setConnectionProperties(tmpConf.getConnectionProperties()); - newConf.setOracleConType(tmpConf.getOracleConType()); - // 增加3个具体的实现 - newConf.setWriteRestrictTimes(tmpConf.getWriteRestrictTimes()); - newConf.setReadRestrictTimes(tmpConf.getReadRestrictTimes()); - newConf.setThreadCountRestrict(tmpConf.getThreadCountRestrict()); - newConf.setTimeSliceInMillis(tmpConf.getTimeSliceInMillis()); - // å¤„ç†æœ¬åœ°ä¼˜å…ˆé…ç½® - overConfByLocal(TAtomDsConfHandle.this.localConf, newConf); - // 转æ¢tAtomDsConfDO - // 检查转æ¢åŽç»“æžœæ˜¯å¦æ­£ç¡® - } finally { - lock.unlock(); - } - } - - }); - } - - /** - * 是用本地é…置覆盖传入的TAtomDsConfDO的属性 - * - * @param tAtomDsConfDO - */ - private void overConfByLocal(TAtomDsConfDO localDsConfDO, TAtomDsConfDO newDsConfDO) { - if (null == newDsConfDO || null == localDsConfDO) { - return; - } - if (StringUtil.isNotBlank(localDsConfDO.getDriverClass())) { - newDsConfDO.setDriverClass(localDsConfDO.getDriverClass()); - } - if (StringUtil.isNotBlank(localDsConfDO.getSorterClass())) { - newDsConfDO.setSorterClass(localDsConfDO.getSorterClass()); - } - if (StringUtil.isNotBlank(localDsConfDO.getPasswd())) { - newDsConfDO.setPasswd(localDsConfDO.getPasswd()); - } - if (null != localDsConfDO.getConnectionProperties() && !localDsConfDO.getConnectionProperties().isEmpty()) { - newDsConfDO.setConnectionProperties(localDsConfDO.getConnectionProperties()); - } - } - - void setSingleInGroup(boolean isSingleInGroup) { - this.runTimeConf.setSingleInGroup(isSingleInGroup); - } - - public void setAppName(String appName) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset appName !"); - } - this.appName = appName; - } - - public void setDbKey(String dbKey) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset dbKey !"); - } - this.dbKey = dbKey; - } - - public void setLocalPasswd(String passwd) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset passwd !"); - } - this.localConf.setPasswd(passwd); - } - - public void setLocalConnectionProperties(Map map) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset connectionProperties !"); - } - this.localConf.setConnectionProperties(map); - } - - public void setLocalDriverClass(String driverClass) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset driverClass !"); - } - this.localConf.setDriverClass(driverClass); - } - - public void setLocalSorterClass(String sorterClass) throws AtomAlreadyInitException { - if (initFalg) { - throw new AtomAlreadyInitException("[AlreadyInit] couldn't Reset sorterClass !"); - } - this.localConf.setSorterClass(sorterClass); - } - - public String getAppName() { - return appName; - } - - public String getDbKey() { - return dbKey; - } - - public AtomDbStatusEnum getStatus() { - return this.runTimeConf.getDbStautsEnum(); - } - - public AtomDbTypeEnum getDbType() { - return this.runTimeConf.getDbTypeEnum(); - } - - public ConnectionManager getConnectionManager() { - return connectionManager; - } - -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java deleted file mode 100644 index d3a7f14a..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/TDDLConstant.java +++ /dev/null @@ -1,13 +0,0 @@ -//Copyright(c) Taobao.com -package com.taobao.tdhs.config; -/** - * @description TDDL整个工程的常é‡ç±» - * @author junyu - * @version 1.0 - * @since 1.6 - * @date 2011-5-23上åˆ09:54:49 - */ -public class TDDLConstant { - //åˆæ¬¡èŽ·å–diamondé…置超时时间 - public static final long DIAMOND_GET_DATA_TIMEOUT=10*1000; -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java deleted file mode 100644 index f646e539..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/ConfigManager.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.taobao.tdhs.config.group; - -import java.util.ArrayList; -import java.util.List; - -import org.adbcj.ConnectionManager; -import org.adbcj.mysql.netty.AtomMysqlConnectionManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.taobao.tdhs.config.ConfigDataHandler; -import com.taobao.tdhs.config.ConfigDataHandlerFactory; -import com.taobao.tdhs.config.ConfigDataListener; -import com.taobao.tdhs.config.DefaultConfigDataHandlerFactory; - -/** - * 一个ConfigManager对应一个TGroupDataSource, - * 主è¦ç”¨äºŽå°†æ ¹æ®Groupçš„dataIDå–得的对应é…置字符串信(比如db0:rwp1q1i0, db1:rwp0q0i1), - * 转化为真正的Group层的é…置体系结构:一个Group层挂ç€ä¸¤ä¸ªAtom db0 与 db1 , 则我们使用一个 Map æ¥è¡¨ç¤º 其中的String 为æ¯ä¸ªAtom DS çš„dbKey ,DataSourceWrapper - * 为ç»è¿‡å°è£…çš„TAtomDataSource - * ---这里需è¦è§£é‡Šä¸€ä¸‹ï¼Œä¸ºä»€ä¹ˆä¸ç›´æŽ¥ä½¿ç”¨AtomDataSource?因为æ¯ä¸ªAtomDataSource还有相应的æƒé‡å’Œä¼˜å…ˆçº§ä¿¡æ¯ 因此,需è¦***方法 - * 其中,é…置的æ¯ä¸€ä¸ªAtom DataSourceä¹Ÿåªæ˜¯ç”¨Atom - * çš„dbKeyè¡¨ç¤ºï¼Œå› æ­¤ï¼Œæˆ‘ä»¬è¿˜éœ€è¦æ ¹æ®æ­¤dbKeyå–å¾—Atomçš„é…置信æ¯ï¼Œå¹¶ä¸”将它å°è£…æˆä¸€ä¸ªAtomDataSource对象。 因此需è¦***方法 - * 有了这个map能根æ®dbKey迅速的找到对应的Datasource也是ä¸å¤Ÿçš„,我们的Groupå±‚åº”è¯¥æ˜¯å¯¹åº”ç”¨é€æ˜Žçš„, - * å› æ­¤ï¼Œå½“æˆ‘ä»¬çš„è¯»å†™è¯·æ±‚è¿›æ¥æ—¶ï¼ŒGroup层应该能够根æ®é…置的æƒé‡å’Œä¼˜å…ˆçº§ï¼Œè‡ªåŠ¨çš„é€‰æ‹©ä¸€ä¸ªåˆé€‚çš„DB上进行读写, - * 所以,我们还需è¦å°†é…置信æ¯ç”Ÿæˆä¸€ä¸ªDBSelectoræ¥è‡ªåŠ¨çš„å®Œæˆæ ¹æ®æƒé‡ã€ä¼˜å…ˆçº§é€‰æ‹©åˆé€‚的目标库 因此,需è¦***方法 - * - * @author yangzhu - * @author linxuan refactor - */ -public class ConfigManager { - - private static final Log logger = LogFactory.getLog(ConfigManager.class); - - private final ConfigDataListener configReceiver; // //åŠ¨æ€æŽ¥æ”¶Diamond推é€è¿‡æ¥çš„ä¿¡æ¯ - private ConfigDataHandlerFactory configFactory; - private ConfigDataHandler globalHandler; - - // add by junyu - - private String fullGroupKey; - private String appName = null; - - private int configReceiveTimeout = 20000; - private List atomTdhsClient = new ArrayList(); - private WeightSelector writeSelector = new WeightSelector(); - private WeightSelector readSelector = new WeightSelector(); - - public ConfigManager(){ - configReceiver = new ConfigReceiver(); - } - - /** - * 从Diamondé…置中心æå–ä¿¡æ¯ï¼Œæž„造TAtomDataSourceã€æž„造有优先级信æ¯çš„读写DBSelector ---add by - * mazhidan.pt - */ - public void init() { - // 警告: ä¸è¦åœ¨æž„造DefaultDiamondManager时就注册ManagerListener(比如:configReceiver) - // 也就是说,ä¸è¦è¿™æ ·ç”¨: new DefaultDiamondManager(dbGroupKey, configReceiver), - // 而是è¦è®¾æˆnull,等第一次å–å¾—ä¿¡æ¯å¹¶è§£æžå®ŒæˆåŽå†æ³¨å†Œï¼Œè¿™æ ·å¯ä»¥ä¸ç”¨åŒæ­¥ï¼Œé¿å…任何与并å‘相关的问题, - // 因为有å¯èƒ½åœ¨ç¬¬ä¸€æ¬¡åˆšå–回信æ¯åŽï¼ŒDiamondé…置中心那边马上修改了记录,导致ManagerListener这个线程立刻收到信æ¯ï¼Œ - // 造æˆåˆå§‹åŒ–线程和ManagerListenerçº¿ç¨‹åŒæ—¶è§£æžä¿¡æ¯ã€‚ - configFactory = new DefaultConfigDataHandlerFactory(); - globalHandler = configFactory.getConfigDataHandler(fullGroupKey, null); - - String dsWeightCommaStr = globalHandler.getData(configReceiveTimeout, - ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY); - String[] dbArray = dsWeightCommaStr.split(","); // 逗å·åˆ†éš”:db0:rwp1q1i0, - for (String db : dbArray) { - String[] dbNameAndWeight = db.split(":"); - if (dbNameAndWeight.length != 2) { - throw new IllegalArgumentException("weight can't find " + db); - } - String dbKey = dbNameAndWeight[0]; - String weightStr = dbNameAndWeight[1]; - Weight weight = new Weight(weightStr); - int w = weight.w; - AtomMysqlConnectionManager one = new AtomMysqlConnectionManager(); - try { - one.setAppName(appName); - one.setDbKey(dbKey); - one.init(); - } catch (Exception e) { - throw new RuntimeException(e); - } - int index = atomTdhsClient.size(); - atomTdhsClient.add(one); - for (int i = 0; i < w; i++) { - writeSelector.add(index); - } - - int r = weight.r; - for (int i = 0; i < r; i++) { - readSelector.add(index); - } - } - - } - - public String getFullGroupKey() { - return fullGroupKey; - } - - public void setFullGroupKey(String fullGroupKey) { - this.fullGroupKey = fullGroupKey; - } - - public String getAppName() { - return appName; - } - - public void setAppName(String appName) { - this.appName = appName; - } - - public List getAtomTdhsClient() { - return atomTdhsClient; - } - - public void setAtomTdhsClient(List atomTdhsClient) { - this.atomTdhsClient = atomTdhsClient; - } - - public WeightSelector getWriteSelector() { - return writeSelector; - } - - public void setWriteSelector(WeightSelector writeSelector) { - this.writeSelector = writeSelector; - } - - public WeightSelector getReadSelector() { - return readSelector; - } - - public void setReadSelector(WeightSelector readSelector) { - this.readSelector = readSelector; - } - - private class ConfigReceiver implements ConfigDataListener { - - public void onDataRecieved(String dataId, String data) { - try { - logger.warn("group ds data received !dataId:" + dataId + " data:" + data); - logger.warn("not allow"); - } catch (Throwable t) { - logger.error("动æ€è§£æžé…ç½®ä¿¡æ¯æ—¶å‡ºçŽ°é”™è¯¯:" + data, t); - } - } - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java deleted file mode 100644 index e9c77e4c..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/GroupExtraConfig.java +++ /dev/null @@ -1,131 +0,0 @@ -package com.taobao.tdhs.config.group; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * @author jiechen.qzm - */ -public class GroupExtraConfig { - /** - * when set this parameter is true,table not in tableDsIndexMap or sql not - * in sqlDsIndexMap, this sql will be forced go to main db, priority is - * low(compare to local seted dataSourceIndex, - * tableDsIndexMap,sqlDsIndexMap),higher than weight select. - * - * add by junyu,2011-11-01 - */ - private boolean defaultMain = false; - - /** - * this map define the actual_table and dataSourceIndex relation - * - * add by junyu,2011-11-01 - */ - private Map tableDsIndexMap = new HashMap(); - - /** - * this map define the sql and dataSourceIndex relation - * - * add by junyu,2011-11-01 - */ - private Map sqlDsIndexMap = new HashMap(); - - /** - * this list contain the sqls whitch are forbidden - * add by jiechen,2011-12-29 - */ - private Set sqlForbidSet = new HashSet(); - - public boolean isDefaultMain() { - return defaultMain; - } - - public void setDefaultMain(boolean defaultMain) { - this.defaultMain = defaultMain; - } - - public Map getTableDsIndexMap() { - return tableDsIndexMap; - } - - public void setTableDsIndexMap(Map tableDsIndexMap) { - this.tableDsIndexMap = tableDsIndexMap; - } - - public Map getSqlDsIndexMap() { - return sqlDsIndexMap; - } - - public void setSqlDsIndexMap(Map sqlDsIndexMap) { - this.sqlDsIndexMap = sqlDsIndexMap; - } - - public Set getSqlForbidSet() { - return sqlForbidSet; - } - - public void setSqlForbidSet(Set sqlForbidSet) { - this.sqlForbidSet = sqlForbidSet; - } - - /*public Boolean getDefaultMain() { - return defaultMain; - } - - public void setDefaultMain(Boolean defaultMain) { - this.defaultMain = defaultMain; - } - - public void clearDefaultMain() { - this.defaultMain = false; - } - - public Map getTableDsIndexMap() { - return tableDsIndexMap; - } - - public void setTableDsIndexMap(Map tableDsIndexMap) { - this.clearTableDsIndexMap(); - this.tableDsIndexMap.putAll(tableDsIndexMap); - } - - public void clearTableDsIndexMap() { - this.tableDsIndexMap.clear(); - } - - public Map getSqlDsIndexMap() { - return sqlDsIndexMap; - } - - public void setSqlDsIndexMap(Map sqlDsIndexMap) { - this.clearSqlDsIndexMap(); - this.sqlDsIndexMap.putAll(sqlDsIndexMap); - } - - public void clearSqlDsIndexMap() { - this.sqlDsIndexMap.clear(); - } - - public Set getSqlForbidSet() { - return sqlForbidSet; - } - - public void setSqlForbidSet(Set sqlForbidSet) { - this.clearSqlForbinSet(); - this.sqlForbidSet.addAll(sqlForbidSet); - } - - public void clearSqlForbinSet() { - this.sqlForbidSet.clear(); - } - - public void clearAll() { - this.clearDefaultMain(); - this.clearTableDsIndexMap(); - this.clearSqlDsIndexMap(); - this.clearSqlForbinSet(); - }*/ -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java deleted file mode 100644 index e2ae4827..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/Weight.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.taobao.tdhs.config.group; - -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * - *

æ•°æ®åº“æƒé‡é…置,æƒé‡è¶Šå¤§ï¼Œè¢«é€‰ä¸­çš„æœºçŽ‡è¶Šå¤§. - * - *

æƒé‡é…置模å¼: - *

[r|R](\\d*) [w|W](\\d*) [p|P](\\d*) [q|Q](\\d*) [i|I](\\d*) - * - *

å­—æ¯r或R表示å¯ä»¥å¯¹æ•°æ®åº“进行读æ“作, åŽé¢è·Ÿä¸€ä¸ªæ•°å­—表示读æ“作的æƒé‡ï¼Œå¦‚果字æ¯r或RåŽé¢æ²¡æœ‰æ•°å­—,则默认是10; - * - *

å­—æ¯w或W表示å¯ä»¥å¯¹æ•°æ®åº“进行写æ“作, åŽé¢è·Ÿä¸€ä¸ªæ•°å­—表示写æ“作的æƒé‡ï¼Œå¦‚果字æ¯w或WåŽé¢æ²¡æœ‰æ•°å­—,则默认是10;< - * - *

å­—æ¯p或P表示读æ“作的优先级, 数字越大优先级越高,读æ“作优先从优先级最高的数æ®åº“中读数æ®ï¼Œ - * 如果字æ¯p或PåŽé¢æ²¡æœ‰æ•°å­—,则默认优先级是0; - * - *

å­—æ¯q或Q表示写æ“作的优先级, 数字越大优先级越高,写æ“作优先从优先级最高的数æ®åº“中写数æ®ï¼Œ - * 如果字æ¯q或QåŽé¢æ²¡æœ‰æ•°å­—,则默认优先级是0. - * - *

å­—æ¯i或I表示动æ€DBIndex, 和用户通过threadLocal指定的dbIndex结åˆï¼Œå®žçްrwä¹‹ä¸Šæ›´çµæ´»çš„路由 - * 一个dbå¯ä»¥åŒæ—¶é…置多个iï¼›ä¸åŒçš„dbå¯ä»¥é…置相åŒçš„i,例如 db0:i0i2,db1:i1,db2:i1,db3:i2则 - * 用户指定dbIndex=0,路由到db0ï¼›ï¼ˆåªæœ‰db0有i0) - * 用户指定dbIndex=1ï¼Œéšæœºè·¯ç”±åˆ°db1å’Œdb2;(db1å’Œdb2都有i1) - * 用户指定dbIndex=2ï¼Œéšæœºè·¯ç”±åˆ°db0å’Œdb3;(db0å’Œdb3都有i2) - * - *

如:db1: r10w10p2, db2: r20p2, db3: rp3,则对应如下三个Weight: - * db1: Weight(r10w10p2) - * db2: Weight(r20p2) - * db3: Weight(rp3) - * - *

在这个例å­ä¸­ï¼Œå¯¹db1, db2,db3这三个数æ®åº“的读æ“作分æˆäº†ä¸¤ä¸ªä¼˜å…ˆçº§: - * p3->[db3] - * p2->[db1, db2] - * - * 当进行读æ“作时,因为db3的优先级最高,所以优先从db3读, - * 如果db3无法进行读æ“作,å†ä»Ždb1, db2ä¸­éšæœºé€‰ä¸€ä¸ªï¼Œå› ä¸ºdb2的读æƒé‡æ˜¯20,而db1是10,所以db2被选中的机率比db1更大。 - * - *

如果在数æ®åº“ååŽé¢æ²¡æœ‰è®¾ç½®æƒé‡å­—符串,就认为æƒé‡å­—符串是null, - * 如: db1: r10w10, db2, db3,则对应如下三个Weight: - * db1: Weight(r10w10) - * db2: Weight(null) - * db3: Weight(null) - * - *

为了兼容2.4之å‰çš„è€ç‰ˆæœ¬ï¼Œå½“æƒé‡å­—符串是null时,相当于"r10w10p0q0", - * 对于上é¢çš„例å­ï¼Œå®žé™…的数æ®åº“æƒé‡é…置是:db1: r10w10p0q0, db2: r10w10p0q0, db3: r10w10p0q0。 - * - * @author yangzhu - * @author linxuan add indexes i/I at 2011/01/21 - * - */ -public class Weight { - private static final Pattern weightPattern_r = Pattern.compile("[R](\\d*)"); - private static final Pattern weightPattern_w = Pattern.compile("[W](\\d*)"); - private static final Pattern weightPattern_p = Pattern.compile("[P](\\d*)"); - private static final Pattern weightPattern_q = Pattern.compile("[Q](\\d*)"); - private static final Pattern weightPattern_i = Pattern.compile("[I](\\d*)"); - - /** - * 读æƒé‡ï¼Œé»˜è®¤æ˜¯10 - */ - public final int r; - - /** - * 写æƒé‡ï¼Œé»˜è®¤æ˜¯10 - */ - public final int w; - - /** - * 读优先级,默认是0 - */ - public final int p; - - /** - * 写优先级,默认是0 - */ - public final int q; - - public final Set indexes; - - public Weight(String weightStr) { - //兼容2.4之å‰çš„è€ç‰ˆæœ¬ï¼Œå½“æƒé‡å­—符串是null时,相当于"r10w10p0q0", - if (weightStr == null) { - r = 10; - w = 10; - p = 0; - q = 0; - indexes = null; - } else { - weightStr = weightStr.trim().toUpperCase(); - - //如果字æ¯'R'在weightStr中找ä¸åˆ°ï¼Œåˆ™è¯»æƒé‡æ˜¯0, - //如果字æ¯'R'在weightStr中已找到了,但是在字æ¯'R'åŽé¢æ²¡æœ‰æ•°å­—,是读æƒé‡æ˜¯10 - r = getUnitWeight(weightStr, 'R', weightPattern_r, 0, 10); - - w = getUnitWeight(weightStr, 'W', weightPattern_w, 0, 10); - - p = getUnitWeight(weightStr, 'P', weightPattern_p, 0, 0); - - q = getUnitWeight(weightStr, 'Q', weightPattern_q, 0, 0); - - indexes = getUnitWeights(weightStr, 'I', weightPattern_i); - - } - } - - public String toString() { - return "Weight[r=" + r + ", w=" + w + ", p=" + p + ", q=" + q + ", indexes=" + indexes + "]"; - } - - //如果字符c在weightStr中找ä¸åˆ°ï¼Œåˆ™è¿”回defaultValue1, - //如果字符c在weightSträ¸­å·²ç»æ‰¾åˆ°äº†ï¼Œä½†æ˜¯åœ¨å­—æ¯cåŽé¢æ²¡æœ‰æ•°å­—,则返回defaultValue2, - //å¦åˆ™è¿”回字æ¯cåŽé¢ 的数字. - private static int getUnitWeight(String weightStr, char c, Pattern p, int defaultValue1, int defaultValue2) { - if (weightStr.indexOf(c) == -1) { - return defaultValue1; - } else { - Matcher m = p.matcher(weightStr); - m.find(); - - if (m.group(1).length() == 0) { - return defaultValue2; - } else { - return Integer.parseInt(m.group(1)); - } - } - } - - private static Set getUnitWeights(String weightStr, char c, Pattern p) { - if (weightStr.indexOf(c) == -1) { - return null; - } - Set is = new HashSet(); - int start = 0; - Matcher m = p.matcher(weightStr); - while (m.find(start)) { - if (m.group(1).length() != 0) { - is.add(Integer.valueOf(m.group(1))); - } - start = m.end(); - } - return is; - } - - public static void main(String[] args) { - System.out.println(new Weight("wr0i1")); - System.out.println(new Weight("wr0i0I1")); - System.out.println(new Weight("i0w10I1r20")); - System.out.println(new Weight("i0w10I1r20i3")); - } -} diff --git a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java b/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java deleted file mode 100644 index 54002ea1..00000000 --- a/mysql/netty/src/main/java/com/taobao/tdhs/config/group/WeightSelector.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.taobao.tdhs.config.group; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Random; - - -public class WeightSelector { - Random ran = new Random(); - - List index = new ArrayList(); - - public Integer getIndex() - { - return index.get(ran.nextInt(index.size())); - } - public void add(int arg0, Integer arg1) { - index.add(arg0, arg1); - } - - public boolean add(Integer arg0) { - return index.add(arg0); - } - - public boolean addAll(Collection arg0) { - return index.addAll(arg0); - } - - public boolean addAll(int arg0, Collection arg1) { - return index.addAll(arg0, arg1); - } - - public void clear() { - index.clear(); - } - - public boolean contains(Object arg0) { - return index.contains(arg0); - } - - public boolean containsAll(Collection arg0) { - return index.containsAll(arg0); - } - - public boolean equals(Object arg0) { - return index.equals(arg0); - } - - public Integer get(int arg0) { - return index.get(arg0); - } - - public int hashCode() { - return index.hashCode(); - } - - public int indexOf(Object arg0) { - return index.indexOf(arg0); - } - - public boolean isEmpty() { - return index.isEmpty(); - } - - public Iterator iterator() { - return index.iterator(); - } - - public int lastIndexOf(Object arg0) { - return index.lastIndexOf(arg0); - } - - public ListIterator listIterator() { - return index.listIterator(); - } - - public ListIterator listIterator(int arg0) { - return index.listIterator(arg0); - } - - public Integer remove(int arg0) { - return index.remove(arg0); - } - - public boolean remove(Object arg0) { - return index.remove(arg0); - } - - public boolean removeAll(Collection arg0) { - return index.removeAll(arg0); - } - - public boolean retainAll(Collection arg0) { - return index.retainAll(arg0); - } - - public Integer set(int arg0, Integer arg1) { - return index.set(arg0, arg1); - } - - public int size() { - return index.size(); - } - - public List subList(int arg0, int arg1) { - return index.subList(arg0, arg1); - } - - public Object[] toArray() { - return index.toArray(); - } - - public T[] toArray(T[] arg0) { - return index.toArray(arg0); - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java deleted file mode 100644 index 01f9cec9..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/AtomMysqlConnectionManager.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.adbcj.mysql.netty; - -import java.util.HashMap; -import java.util.Map; - -import org.adbcj.Connection; -import org.adbcj.ConnectionManager; -import org.adbcj.DbException; -import org.adbcj.DbFuture; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import com.taobao.tdhs.config.AtomAlreadyInitException; -import com.taobao.tdhs.config.TAtomDsConfHandle; - -public class AtomMysqlConnectionManager implements ConnectionManager { - - private static Map cacheConfHandleMap = new HashMap(); - - private final static Log logger = LogFactory.getLog(AtomMysqlConnectionManager.class); - TAtomDsConfHandle atomTdhs = new TAtomDsConfHandle(); - protected volatile boolean inited = false; - - public void setAppName(String appName) throws AtomAlreadyInitException { - atomTdhs.setAppName(appName); - } - - public void setDbKey(String dbKey) throws AtomAlreadyInitException { - atomTdhs.setDbKey(dbKey); - } - - public String getAppName() { - return atomTdhs.getAppName(); - } - - public String getDbKey() { - return atomTdhs.getDbKey(); - } - - public void init() { - if (inited) { - return; - } - inited = true; - try { - String dbName = TAtomConstants.getDbNameStr(this.getAppName(), this.getDbKey()); - synchronized (cacheConfHandleMap) { - TAtomDsConfHandle cacheConfHandle = cacheConfHandleMap.get(dbName); - if (null == cacheConfHandle) { - // åˆå§‹åŒ–config的管ç†å™¨ - this.atomTdhs.init(); - cacheConfHandleMap.put(dbName, atomTdhs); - logger.info("create new TAtomDsConfHandle dbName : " + dbName); - } else { - atomTdhs = cacheConfHandle; - logger.info("use the cache TAtomDsConfHandle dbName : " + dbName); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public DbFuture connect() { - init(); - return atomTdhs.getConnectionManager().connect(); - } - - public DbFuture close(boolean immediate) throws DbException { - init(); - return atomTdhs.getConnectionManager().close(immediate); - } - - public boolean isClosed() { - init(); - return atomTdhs.getConnectionManager().isClosed(); - } - - public boolean isPipeliningEnabled() { - init(); - return atomTdhs.getConnectionManager().isPipeliningEnabled(); - } - - public void setPipeliningEnabled(boolean pipeliningEnabled) { - init(); - atomTdhs.getConnectionManager().setPipeliningEnabled(pipeliningEnabled); - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java deleted file mode 100644 index 83ee6fbd..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/GroupMysqlConnectionManager.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.adbcj.mysql.netty; - -import org.adbcj.Connection; -import org.adbcj.ConnectionManager; -import org.adbcj.DbException; -import org.adbcj.DbFuture; - -import com.taobao.tdhs.config.group.ConfigManager; -import com.taobao.tdhs.config.group.WeightSelector; - -/** - * TODO !! ç›®å‰åªå…许写主机。。 简略一点为了先能跑通 - * http://gitlab.alibaba-inc.com/shenxun/adbjc-tb/issues/2785 - * - * @author Whisper 2013-6-21 下åˆ3:12:42 - * @since 3.0.1 - */ -public class GroupMysqlConnectionManager implements ConnectionManager { - - private static String VERSION = "2.4.1"; - private static String PREFIX = "com.taobao.tddl.jdbc.group_V" + VERSION + "_"; - private String dbGroupKey; - private String fullDbGroupKey = null; - private String appName; - private ConfigManager configManager = new ConfigManager(); - protected volatile boolean inited = false; - - public void init() { - if (inited) { - return; - } - inited = true; - configManager.setAppName(appName); - configManager.setFullGroupKey(getFullDbGroupKey()); - configManager.init(); - // db1:rwp0q0i1 - } - - public GroupMysqlConnectionManager(String dbGroupKey, String appName){ - super(); - this.dbGroupKey = dbGroupKey; - this.appName = appName; - } - - public ConnectionManager getClient(boolean isWrite) { - int index = 0; - if (isWrite) { - WeightSelector ws = configManager.getWriteSelector(); - index = ws.getIndex(); - - } else { - WeightSelector ws = configManager.getReadSelector(); - index = ws.getIndex(); - } - return configManager.getAtomTdhsClient().get(index); - } - - public static String getFullDbGroupKey(String dbGroupKey) { - return PREFIX + dbGroupKey; - } - - public String getFullDbGroupKey() { - if (fullDbGroupKey == null) fullDbGroupKey = PREFIX + getDbGroupKey(); - return fullDbGroupKey; - } - - public String getDbGroupKey() { - return dbGroupKey; - } - - public void setDbGroupKey(String dbGroupKey) { - this.dbGroupKey = dbGroupKey; - } - - public String getAppName() { - return appName; - } - - public void setAppName(String appName) { - this.appName = appName; - } - - public DbFuture connect() { - init(); - return getClient(true).connect(); - } - - public DbFuture close(boolean immediate) throws DbException { - init(); - return getClient(true).close(immediate); - } - - public boolean isClosed() { - init(); - return getClient(true).isClosed(); - } - - public boolean isPipeliningEnabled() { - init(); - return getClient(true).isPipeliningEnabled(); - } - - public void setPipeliningEnabled(boolean pipeliningEnabled) { - init(); - getClient(true).setPipeliningEnabled(pipeliningEnabled); - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java deleted file mode 100644 index ec9400b2..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/TAtomConstants.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.adbcj.mysql.netty; - -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Map; - -/** - * TAtomæ•°æ®æºçš„常é‡è®¾ç½®ç±» - * - * @author qihao - * - */ -public class TAtomConstants { - - public final static String DEFAULT_DIAMOND_GROUP = null; - - public final static String DEFAULT_MYSQL_CHAR_SET = "gbk"; - - //public final static String ORACLE_DBTYPE_STR = "ORACLE"; - - //public final static String MYSQL_DBTYPE_STR = "MYSQL"; - - public final static String DEFAULT_ORACLE_CON_TYPE = "oci"; - - public final static String DB_STATUS_R = "R"; - - public final static String DB_STATUS_W = "W"; - - public final static String DB_STATUS_RW = "RW"; - - public final static String DB_STATUS_NA = "NA"; - - public static Map DEFAULT_ORACLE_CONNECTION_PROPERTIES = new HashMap( - 2); - static { - TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( - "SetBigStringTryClob", "true"); - TAtomConstants.DEFAULT_ORACLE_CONNECTION_PROPERTIES.put( - "defaultRowPrefetch", "50"); - } - - public static Map DEFAULT_MYSQL_CONNECTION_PROPERTIES = new HashMap( - 1); - static { - TAtomConstants.DEFAULT_MYSQL_CONNECTION_PROPERTIES.put( - "characterEncoding", "gbk"); - } - - public final static String DEFAULT_ORACLE_DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver"; - - public final static String DEFAULT_MYSQL_DRIVER_CLASS = "com.mysql.jdbc.Driver"; - - public final static String DEFAULT_ORACLE_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.OracleExceptionSorter"; - - public final static String DEFAULT_MYSQL_SORTER_CLASS = "com.taobao.datasource.resource.adapter.jdbc.vendor.MySQLExceptionSorter"; - - - public final static String MYSQL_INTEGRATION_SORTER_CLASS = "com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter"; - - public final static String DEFAULT_MYSQL_VALID_CONNECTION_CHECKERCLASS = "com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker"; - - /** - * 全局é…ç½®dataIdæ¨¡æ¿ - */ - private static MessageFormat GLOBAL_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.global.{0}"); - - /** - * 应用é…ç½®dataIdæ¨¡æ¿ - */ - private static MessageFormat APP_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.app.{0}.{1}"); - - private static MessageFormat PASSWD_FORMAT = new MessageFormat( - "com.taobao.tddl.atom.passwd.{0}.{1}.{2}"); - - /** - * dbNameæ¨¡æ¿ - */ - private static MessageFormat DB_NAME_FORMAT = new MessageFormat( - "atom.dbkey.{0}^{1}"); - - /** - * æ ¹æ®dbKey获å–全局é…ç½®dataId - * - * @param dbKey - * æ•°æ®åº“åKEY - * @return - */ - public static String getGlobalDataId(String dbKey) { - return GLOBAL_FORMAT.format(new Object[] { dbKey }); - } - - /** - * æ ¹æ®åº”用åå’ŒdbKeyèŽ·å–æŒ‡å®šçš„应用é…ç½®dataId - * - * @param appName - * @param dbKey - * @return - */ - public static String getAppDataId(String appName, String dbKey) { - return APP_FORMAT.format(new Object[] { appName, dbKey }); - } - - /** - * æ ¹æ®dbKeyå’ŒuserName获得对应的passwdçš„dataId - * - * @param dbKey - * @param userName - * @return - */ - public static String getPasswdDataId(String dbName, String dbType, - String userName) { - return PASSWD_FORMAT.format(new Object[] { dbName, dbType, userName }); - } - - /** - * @param appName - * @param dbkey - * @return - */ - public static String getDbNameStr(String appName, String dbkey) { - return DB_NAME_FORMAT.format(new Object[] { appName, dbkey }); - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java deleted file mode 100644 index 1f8ac930..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnection.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.adbcj.mysql.netty; - -import org.adbcj.Connection; -import org.adbcj.ConnectionManager; -import org.adbcj.DbException; -import org.adbcj.DbFuture; -import org.adbcj.DbSessionFuture; -import org.adbcj.PreparedStatement; -import org.adbcj.Result; -import org.adbcj.ResultEventHandler; -import org.adbcj.ResultSet; -import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; -import org.adbcj.support.DefaultDbSessionFuture; - -public class WrappedMysqlConnection implements Connection { - - protected final ObjectPool pool; - protected final Connection conn; - - public WrappedMysqlConnection(Connection conn, ObjectPool pool){ - this.pool = pool; - this.conn = conn; - } - - public synchronized DbSessionFuture close(boolean immediate) throws DbException { - try { - pool.returnObject(conn); - } catch (Exception e) { - throw new DbException(e); - } - return new DefaultDbSessionFuture(null); - } - - public void beginTransaction() { - conn.beginTransaction(); - } - - public DbSessionFuture commit() { - return conn.commit(); - } - - public ConnectionManager getConnectionManager() { - return conn.getConnectionManager(); - } - - public DbFuture ping() { - return conn.ping(); - } - - public DbSessionFuture rollback() { - return conn.rollback(); - } - - public boolean isInTransaction() { - return conn.isInTransaction(); - } - - public DbSessionFuture executeQuery(String sql) { - return conn.executeQuery(sql); - } - - public DbSessionFuture executeQuery(String sql, ResultEventHandler eventHandler, T accumulator) { - return conn.executeQuery(sql, eventHandler, accumulator); - } - - public DbSessionFuture executeUpdate(String sql) { - return conn.executeUpdate(sql); - } - - public DbSessionFuture prepareStatement(String sql) { - return conn.prepareStatement(sql); - } - - public DbSessionFuture prepareStatement(Object key, String sql) { - return conn.prepareStatement(key, sql); - } - - public boolean isClosed() throws DbException { - return conn.isClosed(); - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java deleted file mode 100644 index d3e76c97..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManager.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.adbcj.mysql.netty; - -import java.util.Properties; - -import org.adbcj.Connection; -import org.adbcj.mysql.codec.AbstractMySqlConnectionManager; -import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; -import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.adbcj.support.DefaultDbFuture; - -public class WrappedMysqlConnectionManager extends AbstractMySqlConnectionManager { - - private MysqlConnectionManager plainMySQLConnectionManager = null; - private GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - - ObjectPool pool = null; - - public WrappedMysqlConnectionManager(String host, int port, String username, String password, String schema, - Properties properties){ - super(username, password, schema, properties); - this.plainMySQLConnectionManager = new MysqlConnectionManager(host, - port, - username, - password, - schema, - properties); - PoolableObjectFactory factory = new WrappedMysqlConnectionPoolableObject(plainMySQLConnectionManager); - config.setLifo(false); - config.setMaxTotal(10); - config.setMaxIdle(5); - config.setMinIdle(1); - config.setMaxWaitMillis(5 * 1000); - pool = new GenericObjectPool(factory, config); - } - - public WrappedMysqlConnectionManager(String host, int port, String username, String password, String schema, - Properties properties, GenericObjectPoolConfig config){ - super(username, password, schema, properties); - this.plainMySQLConnectionManager = new MysqlConnectionManager(host, - port, - username, - password, - schema, - properties); - PoolableObjectFactory factory = new WrappedMysqlConnectionPoolableObject(plainMySQLConnectionManager); - pool = new GenericObjectPool(factory, config); - } - - @Override - protected void dispose() { - try { - plainMySQLConnectionManager.dispose(); - - } finally { - pool.close(); - } - } - - @Override - protected DefaultDbFuture createConnectionFuture() { - DefaultDbFuture dbFuture = new DefaultDbFuture(); - try { - dbFuture.setResult(new WrappedMysqlConnection(pool.borrowObject(), pool)); - } catch (Exception e) { - dbFuture.setException(e); - } - return dbFuture; - } - - public MysqlConnectionManager getPlainMySQLConnectionManager() { - return plainMySQLConnectionManager; - } - - public void setPlainMySQLConnectionManager(MysqlConnectionManager plainMySQLConnectionManager) { - this.plainMySQLConnectionManager = plainMySQLConnectionManager; - } - - public GenericObjectPoolConfig getConfig() { - return config; - } - - public void setConfig(GenericObjectPoolConfig config) { - this.config = config; - } - - public ObjectPool getPool() { - return pool; - } - - public void setPool(ObjectPool pool) { - this.pool = pool; - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java deleted file mode 100644 index b15bd7e4..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionManagerFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.adbcj.mysql.netty; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Properties; - -import org.adbcj.ConnectionManager; -import org.adbcj.ConnectionManagerFactory; -import org.adbcj.DbException; - -public class WrappedMysqlConnectionManagerFactory implements ConnectionManagerFactory { - - private WrappedMysqlConnectionManager connectionManager = null; - - public static final String PROTOCOL = "pooledMysqlnetty"; - public static final int DEFAULT_PORT = 3306; - - public ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) - throws DbException { - String host = null; - int port = 0; - String schema = null; - - try { - /* - * Parse URL - */ - URI uri = new URI(url); - // Throw away the 'adbcj' protocol part of the URL - uri = new URI(uri.getSchemeSpecificPart()); - - host = uri.getHost(); - port = uri.getPort(); - if (port < 0) { - port = DEFAULT_PORT; - } - String path = uri.getPath().trim(); - if (path.length() == 0 || "/".equals(path)) { - throw new DbException("You must specific a database in the URL path"); - } - schema = path.substring(1); - - } catch (URISyntaxException e) { - throw new DbException(e); - } - connectionManager = new WrappedMysqlConnectionManager(host, port, username, password, schema, properties); - return connectionManager; - } - - public boolean canHandle(String protocol) { - return PROTOCOL.equalsIgnoreCase(protocol); - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java deleted file mode 100644 index d58ee4a6..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.adbcj.mysql.netty; - -import org.adbcj.Connection; -import org.adbcj.DbFuture; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; - -public class WrappedMysqlConnectionPoolableFactory implements PoolableObjectFactory { - private MysqlConnectionManager connectionManager = null; - - public WrappedMysqlConnectionPoolableFactory(MysqlConnectionManager connectionManager) { - super(); - this.connectionManager = connectionManager; - } - - public Connection makeObject() throws Exception { - DbFuture conn = connectionManager.connect(); - return conn.get(); - } - - public void destroyObject(Connection conn) throws Exception { - conn.close(true); - } - - public boolean validateObject(Connection obj) { - Connection conn = (Connection)obj; - return !conn.isClosed(); - } - - public void activateObject(Connection obj) throws Exception { - - } - - public void passivateObject(Connection obj) throws Exception { - - } - - - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java deleted file mode 100644 index 3b791a4c..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/WrappedMysqlConnectionPoolableObject.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.adbcj.mysql.netty; - -import org.adbcj.Connection; -import org.adbcj.DbFuture; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; - -public class WrappedMysqlConnectionPoolableObject implements PoolableObjectFactory { - - private MysqlConnectionManager connectionManager = null; - - public WrappedMysqlConnectionPoolableObject(MysqlConnectionManager connectionManager){ - super(); - this.connectionManager = connectionManager; - } - - public Connection makeObject() throws Exception { - DbFuture conn = connectionManager.connect(); - return conn.get(); - } - - public void destroyObject(Connection conn) throws Exception { - conn.close(true); - } - - public boolean validateObject(Connection obj) { - Connection conn = (Connection) obj; - return !conn.isClosed(); - } - - public void activateObject(Connection obj) throws Exception { - - } - - public void passivateObject(Connection obj) throws Exception { - - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java deleted file mode 100644 index a1954dc2..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseKeyedPoolableObjectFactory.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -/** - * A base implementation of KeyedPoolableObjectFactory. - *

- * All operations defined here are essentially no-op's. - *

- * This class is immutable, and therefore thread-safe. - * - * @see KeyedPoolableObjectFactory - * - * @param The type of keys managed by this factory. - * @param Type of element managed by this factory. - * - * @version $Revision: 1333925 $ - * - * @since 2.0 - */ -public abstract class BaseKeyedPoolableObjectFactory - implements KeyedPoolableObjectFactory { - - /** - * Create an instance that can be served by the pool. - * - * @param key the key used when constructing the object - * @return an instance that can be served by the pool - */ - - public abstract V makeObject(K key) - throws Exception; - - /** - * Destroy an instance no longer needed by the pool. - *

- * The default implementation is a no-op. - * - * @param key the key used when selecting the instance - * @param obj the instance to be destroyed - */ - - public void destroyObject(K key, V obj) - throws Exception { - } - - /** - * Ensures that the instance is safe to be returned by the pool. - *

- * The default implementation always returns true. - * - * @param key the key used when selecting the object - * @param obj the instance to be validated - * @return always true in the default implementation - */ - - public boolean validateObject(K key, V obj) { - return true; - } - - /** - * Reinitialize an instance to be returned by the pool. - *

- * The default implementation is a no-op. - * - * @param key the key used when selecting the object - * @param obj the instance to be activated - */ - - public void activateObject(K key, V obj) - throws Exception { - } - - /** - * Uninitialize an instance to be returned to the idle object pool. - *

- * The default implementation is a no-op. - * - * @param key the key used when selecting the object - * @param obj the instance to be passivated - */ - - public void passivateObject(K key, V obj) - throws Exception { - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java deleted file mode 100644 index 5646b047..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BaseObjectPool.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -/** - * A simple base implementation of {@link ObjectPool}. - * Optional operations are implemented to either do nothing, return a value - * indicating it is unsupported or throw {@link UnsupportedOperationException}. - *

- * This class is intended to be thread-safe. - * - * @param Type of element pooled in this pool. - * - * @version $Revision: 1333925 $ - * - * @since 2.0 - */ -public abstract class BaseObjectPool implements ObjectPool { - /** - * Obtains an instance from the pool. - * - * @return an instance from the pool - * - * @throws Exception if an instance cannot be obtained from the pool - */ - - public abstract T borrowObject() throws Exception; - - /** - * Returns an instance to the pool. - * - * @param obj instance to return to the pool - */ - - public abstract void returnObject(T obj) throws Exception; - - /** - * Invalidates an object from the pool. - *

- * By contract, obj must have been obtained - * using {@link #borrowObject borrowObject}. - *

- * This method should be used when an object that has been borrowed is - * determined (due to an exception or other problem) to be invalid. - * - * @param obj a {@link #borrowObject borrowed} instance to be disposed. - * @throws Exception - */ - - public abstract void invalidateObject(T obj) throws Exception; - - /** - * Not supported in this base implementation. - * - * @return a negative value. - */ - - public int getNumIdle() { - return -1; - } - - /** - * Not supported in this base implementation. - * - * @return a negative value. - */ - - public int getNumActive() { - return -1; - } - - /** - * Not supported in this base implementation. - * - * @throws UnsupportedOperationException - */ - - public void clear() throws Exception, UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this base implementation.Always throws an - * {@link UnsupportedOperationException}, subclasses should override this - * behavior. - * - * @throws UnsupportedOperationException - */ - - public void addObject() throws Exception, UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Close this pool. This affects the behavior of isClosed and - * assertOpen. - */ - - public void close() { - closed = true; - } - - /** - * Has this pool instance been closed. - * - * @return true when this pool has been closed. - */ - public final boolean isClosed() { - return closed; - } - - /** - * Throws an IllegalStateException when this pool has been - * closed. - * - * @throws IllegalStateException when this pool has been closed. - * - * @see #isClosed() - */ - protected final void assertOpen() throws IllegalStateException { - if (isClosed()) { - throw new IllegalStateException("Pool not open"); - } - } - - private volatile boolean closed = false; -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java deleted file mode 100644 index b5aa0bd5..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/BasePoolableObjectFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -/** - * A base implementation of PoolableObjectFactory. - *

- * All operations defined here are essentially no-op's. - *

- * This class is immutable, and therefore thread-safe - * - * @param Type of element managed in this factory. - * - * @see PoolableObjectFactory - * @see BaseKeyedPoolableObjectFactory - * - * @version $Revision: 1333925 $ - * - * @since 2.0 - */ -public abstract class BasePoolableObjectFactory implements PoolableObjectFactory { - /** - * {@inheritDoc} - */ - - public abstract T makeObject() throws Exception; - - /** - * No-op. - * - * @param obj ignored - */ - - public void destroyObject(T obj) - throws Exception { - } - - /** - * This implementation always returns true. - * - * @param obj ignored - * - * @return true - */ - - public boolean validateObject(T obj) { - return true; - } - - /** - * No-op. - * - * @param obj ignored - */ - - public void activateObject(T obj) throws Exception { - } - - /** - * No-op. - * - * @param obj ignored - */ - - public void passivateObject(T obj) - throws Exception { - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java deleted file mode 100644 index 4a3aa318..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedObjectPool.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -import java.util.NoSuchElementException; - -/** - * A "keyed" pooling interface. - *

- * A keyed pool pools instances of multiple types. Each type may be accessed - * using an arbitrary key. - *

- * Example of use: - *

 Object obj = null;
- * Object key = "Key";
- *
- * try {
- *     obj = pool.borrowObject(key);
- *     //...use the object...
- * } catch(Exception e) {
- *     // invalidate the object
- *     pool.invalidateObject(key, obj);
- *     // do not return the object to the pool twice
- *     obj = null;
- * } finally {
- *     // make sure the object is returned to the pool
- *     if(null != obj) {
- *         pool.returnObject(key, obj);
- *     }
- * }
- *

- * {@link KeyedObjectPool} implementations may choose to store at most - * one instance per key value, or may choose to maintain a pool of instances - * for each key (essentially creating a {@link java.util.Map Map} of - * {@link ObjectPool pools}). - *

- * See {@link org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericKeyedObjectPool - * GenericKeyedObjectPool} for an implementation. - * - * @param The type of keys maintained by this pool. - * @param Type of element pooled in this pool. - * - * @see KeyedPoolableObjectFactory - * @see ObjectPool - * @see org.adbcj.mysql.netty.org.apache.commons.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool - * - * @version $Revision: 1334193 $ - * - * @since 2.0 - */ -public interface KeyedObjectPool { - /** - * Obtains an instance from this pool for the specified key. - *

- * Instances returned from this method will have been either newly created - * with {@link KeyedPoolableObjectFactory#makeObject makeObject} or will be - * a previously idle object and have been activated with - * {@link KeyedPoolableObjectFactory#activateObject activateObject} and then - * validated with - * {@link KeyedPoolableObjectFactory#validateObject validateObject}. - *

- * By contract, clients must return the borrowed object - * using {@link #returnObject returnObject}, - * {@link #invalidateObject invalidateObject}, or a related method as - * defined in an implementation or sub-interface, using a key - * that is {@link Object#equals equivalent} to the one used to borrow the - * instance in the first place. - *

- * The behaviour of this method when the pool has been exhausted is not - * strictly specified (although it may be specified by implementations). - * - * @param key the key used to obtain the object - * - * @return an instance from this pool. - * - * @throws IllegalStateException - * after {@link #close close} has been called on this pool - * @throws Exception - * when {@link KeyedPoolableObjectFactory#makeObject - * makeObject} throws an exception - * @throws NoSuchElementException - * when the pool is exhausted and cannot or will not return - * another instance - */ - V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException; - - /** - * Return an instance to the pool. By contract, obj - * must have been obtained using - * {@link #borrowObject borrowObject} or a related method as defined in an - * implementation or sub-interface using a key that is - * equivalent to the one used to borrow the instance in the first place. - * - * @param key the key used to obtain the object - * @param obj a {@link #borrowObject borrowed} instance to be returned. - * - * @throws Exception - */ - void returnObject(K key, V obj) throws Exception; - - /** - * Invalidates an object from the pool. - *

- * By contract, obj must have been obtained - * using {@link #borrowObject borrowObject} or a related method as defined - * in an implementation or sub-interface using a key that is - * equivalent to the one used to borrow the Object in the first - * place. - *

- * This method should be used when an object that has been borrowed is - * determined (due to an exception or other problem) to be invalid. - * - * @param key the key used to obtain the object - * @param obj a {@link #borrowObject borrowed} instance to be returned. - * - * @throws Exception - */ - void invalidateObject(K key, V obj) throws Exception; - - /** - * Create an object using the {@link KeyedPoolableObjectFactory factory} or - * other implementation dependent mechanism, passivate it, and then place it - * in the idle object pool. addObject is useful for - * "pre-loading" a pool with idle objects (Optional operation). - * - * @param key the key a new instance should be added to - * - * @throws Exception - * when {@link KeyedPoolableObjectFactory#makeObject} fails. - * @throws IllegalStateException - * after {@link #close} has been called on this pool. - * @throws UnsupportedOperationException - * when this pool cannot add new idle objects. - */ - void addObject(K key) throws Exception, IllegalStateException, - UnsupportedOperationException; - - /** - * Returns the number of instances corresponding to the given - * key currently idle in this pool. Returns a negative value if - * this information is not available. - * - * @param key the key to query - * @return the number of instances corresponding to the given - * key currently idle in this pool. - */ - int getNumIdle(K key); - - /** - * Returns the number of instances currently borrowed from but not yet - * returned to the pool corresponding to the given key. - * Returns a negative value if this information is not available. - * - * @param key the key to query - * @return the number of instances currently borrowed from but not yet - * returned to the pool corresponding to the given key. -= */ - int getNumActive(K key); - - /** - * Returns the total number of instances currently idle in this pool. - * Returns a negative value if this information is not available. - * @return the total number of instances currently idle in this pool. - = */ - int getNumIdle(); - - /** - * Returns the total number of instances current borrowed from this pool but - * not yet returned. Returns a negative value if this information is not - * available. - * @return the total number of instances current borrowed from this pool but - * not yet returned. - */ - int getNumActive(); - - /** - * Clears the pool, removing all pooled instances (optional operation). - * - * @throws UnsupportedOperationException when this implementation doesn't - * support the operation - */ - void clear() throws Exception, UnsupportedOperationException; - - /** - * Clears the specified pool, removing all pooled instances corresponding to - * the given key (optional operation). - * - * @param key the key to clear - * - * @throws UnsupportedOperationException when this implementation doesn't - * support the operation - */ - void clear(K key) throws Exception, UnsupportedOperationException; - - /** - * Close this pool, and free any resources associated with it. - *

- * Calling {@link #addObject addObject} or - * {@link #borrowObject borrowObject} after invoking this method on a pool - * will cause them to throw an {@link IllegalStateException}. - *

- * Implementations should silently fail if not all resources can be freed. - */ - void close(); -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java deleted file mode 100644 index 2c2b3447..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/KeyedPoolableObjectFactory.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -/** - * An interface defining life-cycle methods for - * instances to be served by a {@link KeyedObjectPool}. - *

- * By contract, when an {@link KeyedObjectPool} - * delegates to a {@link KeyedPoolableObjectFactory}, - *

    - *
  1. - * {@link #makeObject} is called whenever a new instance is needed. - *
  2. - *
  3. - * {@link #activateObject} is invoked on every instance that has been - * {@link #passivateObject passivated} before it is - * {@link KeyedObjectPool#borrowObject borrowed} from the pool. - *
  4. - *
  5. - * {@link #validateObject} is invoked on {@link #activateObject activated} - * instances to make sure they can be - * {@link KeyedObjectPool#borrowObject borrowed} from the pool. - * validateObject may also be used to test an - * instance being {@link KeyedObjectPool#returnObject returned} to the pool - * before it is {@link #passivateObject passivated}. It will only be invoked - * on an activated instance. - *
  6. - *
  7. - * {@link #passivateObject passivateObject} - * is invoked on every instance when it is returned to the pool. - *
  8. - *
  9. - * {@link #destroyObject destroyObject} - * is invoked on every instance when it is being "dropped" from the - * pool (whether due to the response from validateObject, - * or for reasons specific to the pool implementation.) There is no - * guarantee that the instance being destroyed will - * be considered active, passive or in a generally consistent state. - *
  10. - *
- * {@link KeyedPoolableObjectFactory} must be thread-safe. The only promise - * an {@link KeyedObjectPool} makes is that the same instance of an object will - * not be passed to more than one method of a - * KeyedPoolableObjectFactory at a time. - * - * @see KeyedObjectPool - * - * @param The type of keys managed by this factory. - * @param Type of element managed by this factory. - * - * @version $Revision: 1333925 $ - * - * @since 2.0 - */ -public interface KeyedPoolableObjectFactory { - /** - * Create an instance that can be served by the pool. - * - * @param key the key used when constructing the object - * - * @return an instance that can be served by the pool. - * - * @throws Exception if there is a problem creating a new instance, - * this will be propagated to the code requesting an object. - */ - V makeObject(K key) throws Exception; - - /** - * Destroy an instance no longer needed by the pool. - *

- * It is important for implementations of this method to be aware that there - * is no guarantee about what state obj will be in and the - * implementation should be prepared to handle unexpected errors. - *

- * Also, an implementation must take in to consideration that instances lost - * to the garbage collector may never be destroyed. - * - * @param key the key used when selecting the instance - * @param obj the instance to be destroyed - * - * @throws Exception should be avoided as it may be swallowed by - * the pool implementation. - * - * @see #validateObject - * @see KeyedObjectPool#invalidateObject - */ - void destroyObject(K key, V obj) throws Exception; - - /** - * Ensures that the instance is safe to be returned by the pool. - * - * @param key the key used when selecting the object - * @param obj the instance to be validated - * - * @return false if obj is not valid and should - * be dropped from the pool, true otherwise. - */ - boolean validateObject(K key, V obj); - - /** - * Reinitialize an instance to be returned by the pool. - * - * @param key the key used when selecting the object - * @param obj the instance to be activated - * - * @throws Exception if there is a problem activating obj, - * this exception may be swallowed by the pool. - * - * @see #destroyObject - */ - void activateObject(K key, V obj) throws Exception; - - /** - * Uninitialize an instance to be returned to the idle object pool. - * - * @param key the key used when selecting the object - * @param obj the instance to be passivated - * - * @throws Exception if there is a problem passivating obj, - * this exception may be swallowed by the pool. - * - * @see #destroyObject - */ - void passivateObject(K key, V obj) throws Exception; -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java deleted file mode 100644 index b65fe716..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/ObjectPool.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -import java.util.NoSuchElementException; - -/** - * A pooling simple interface. - *

- * Example of use: - *

 Object obj = null;
- *
- * try {
- *     obj = pool.borrowObject();
- *     try {
- *         //...use the object...
- *     } catch(Exception e) {
- *         // invalidate the object
- *         pool.invalidateObject(obj);
- *         // do not return the object to the pool twice
- *         obj = null;
- *     } finally {
- *         // make sure the object is returned to the pool
- *         if(null != obj) {
- *             pool.returnObject(obj);
- *        }
- *     }
- * } catch(Exception e) {
- *       // failed to borrow an object
- * }
- *

- * See {@link BaseObjectPool} for a simple base implementation. - * - * @param Type of element pooled in this pool. - * - * @see PoolableObjectFactory - * @see KeyedObjectPool - * @see BaseObjectPool - * - * @version $Revision: 1334194 $ - * - * @since 2.0 - */ -public interface ObjectPool { - /** - * Obtains an instance from this pool. - *

- * Instances returned from this method will have been either newly created - * with {@link PoolableObjectFactory#makeObject} or will be a previously - * idle object and have been activated with - * {@link PoolableObjectFactory#activateObject} and then validated with - * {@link PoolableObjectFactory#validateObject}. - *

- * By contract, clients must return the borrowed instance - * using {@link #returnObject}, {@link #invalidateObject}, or a related - * method as defined in an implementation or sub-interface. - *

- * The behaviour of this method when the pool has been exhausted - * is not strictly specified (although it may be specified by - * implementations). - * - * @return an instance from this pool. - * - * @throws IllegalStateException - * after {@link #close close} has been called on this pool. - * @throws Exception - * when {@link PoolableObjectFactory#makeObject} throws an - * exception. - * @throws NoSuchElementException - * when the pool is exhausted and cannot or will not return - * another instance. - */ - T borrowObject() throws Exception, NoSuchElementException, - IllegalStateException; - - /** - * Return an instance to the pool. By contract, obj - * must have been obtained using {@link #borrowObject()} or - * a related method as defined in an implementation or sub-interface. - * - * @param obj a {@link #borrowObject borrowed} instance to be returned. - * - * @throws Exception - */ - void returnObject(T obj) throws Exception; - - /** - * Invalidates an object from the pool. - *

- * By contract, obj must have been obtained - * using {@link #borrowObject} or a related method as defined in an - * implementation or sub-interface. - *

- * This method should be used when an object that has been borrowed is - * determined (due to an exception or other problem) to be invalid. - * - * @param obj a {@link #borrowObject borrowed} instance to be disposed. - * - * @throws Exception - */ - void invalidateObject(T obj) throws Exception; - - /** - * Create an object using the {@link PoolableObjectFactory factory} or other - * implementation dependent mechanism, passivate it, and then place it in - * the idle object pool. addObject is useful for "pre-loading" - * a pool with idle objects. (Optional operation). - * - * @throws Exception - * when {@link PoolableObjectFactory#makeObject} fails. - * @throws IllegalStateException - * after {@link #close} has been called on this pool. - * @throws UnsupportedOperationException - * when this pool cannot add new idle objects. - */ - void addObject() throws Exception, IllegalStateException, - UnsupportedOperationException; - - /** - * Return the number of instances currently idle in this pool. This may be - * considered an approximation of the number of objects that can be - * {@link #borrowObject borrowed} without creating any new instances. - * Returns a negative value if this information is not available. - * @return the number of instances currently idle in this pool. - */ - int getNumIdle(); - - /** - * Return the number of instances currently borrowed from this pool. Returns - * a negative value if this information is not available. - * @return the number of instances currently borrowed from this pool. -= */ - int getNumActive(); - - /** - * Clears any objects sitting idle in the pool, releasing any associated - * resources (optional operation). Idle objects cleared must be - * {@link PoolableObjectFactory#destroyObject(Object)}. - * - * @throws UnsupportedOperationException - * if this implementation does not support the operation - */ - void clear() throws Exception, UnsupportedOperationException; - - /** - * Close this pool, and free any resources associated with it. - *

- * Calling {@link #addObject} or {@link #borrowObject} after invoking this - * method on a pool will cause them to throw an {@link IllegalStateException}. - *

- * Implementations should silently fail if not all resources can be freed. - */ - void close(); -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java deleted file mode 100644 index 5213c010..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolUtils.java +++ /dev/null @@ -1,1807 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Timer; -import java.util.TimerTask; -import java.util.Collections; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; - -/** - * This class consists exclusively of static methods that operate on or return - * ObjectPool or KeyedObjectPool related interfaces. - * - * @version $Revision: 1351161 $ - * - * @since 2.0 - */ -public final class PoolUtils { - - /** - * Timer used to periodically check pools idle object count. Because a - * {@link Timer} creates a {@link Thread}, an IODH is used. - */ - static class TimerHolder { - static final Timer MIN_IDLE_TIMER = new Timer(true); - } - - /** - * PoolUtils instances should NOT be constructed in standard programming. - * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);. - * This constructor is public to permit tools that require a JavaBean - * instance to operate. - */ - public PoolUtils() { - } - - /** - * Should the supplied Throwable be re-thrown (eg if it is an instance of - * one of the Throwables that should never be swallowed). Used by the pool - * error handling for operations that throw exceptions that normally need to - * be ignored. - * - * @param t - * The Throwable to check - * @throws ThreadDeath - * if that is passed in - * @throws VirtualMachineError - * if that is passed in - */ - public static void checkRethrow(Throwable t) { - if (t instanceof ThreadDeath) { - throw (ThreadDeath) t; - } - if (t instanceof VirtualMachineError) { - throw (VirtualMachineError) t; - } - // All other instances of Throwable will be silently swallowed - } - - /** - * Periodically check the idle object count for the pool. At most one idle - * object will be added per period. If there is an exception when calling - * {@link ObjectPool#addObject()} then no more checks will be performed. - * - * @param pool - * the pool to check periodically. - * @param minIdle - * if the {@link ObjectPool#getNumIdle()} is less than this then - * add an idle object. - * @param period - * the frequency to check the number of idle objects in a pool, - * see {@link Timer#schedule(TimerTask, long, long)}. - * @param the type of objects in the pool - * @return the {@link TimerTask} that will periodically check the pools idle - * object count. - * @throws IllegalArgumentException - * when pool is null or when - * minIdle is negative or when period - * isn't valid for {@link Timer#schedule(TimerTask, long, long)} - */ - public static TimerTask checkMinIdle(final ObjectPool pool, - final int minIdle, final long period) - throws IllegalArgumentException { - if (pool == null) { - throw new IllegalArgumentException("keyedPool must not be null."); - } - if (minIdle < 0) { - throw new IllegalArgumentException("minIdle must be non-negative."); - } - final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle); - getMinIdleTimer().schedule(task, 0L, period); - return task; - } - - /** - * Periodically check the idle object count for the key in the keyedPool. At - * most one idle object will be added per period. If there is an exception - * when calling {@link KeyedObjectPool#addObject(Object)} then no more - * checks for that key will be performed. - * - * @param keyedPool - * the keyedPool to check periodically. - * @param key - * the key to check the idle count of. - * @param minIdle - * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than - * this then add an idle object. - * @param period - * the frequency to check the number of idle objects in a - * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. - * @param the type of the pool key - * @param the type of pool entries - * @return the {@link TimerTask} that will periodically check the pools idle - * object count. - * @throws IllegalArgumentException - * when keyedPool, key is - * null or when minIdle is negative or - * when period isn't valid for - * {@link Timer#schedule(TimerTask, long, long)}. - */ - public static TimerTask checkMinIdle( - final KeyedObjectPool keyedPool, final K key, - final int minIdle, final long period) - throws IllegalArgumentException { - if (keyedPool == null) { - throw new IllegalArgumentException("keyedPool must not be null."); - } - if (key == null) { - throw new IllegalArgumentException("key must not be null."); - } - if (minIdle < 0) { - throw new IllegalArgumentException("minIdle must be non-negative."); - } - final TimerTask task = new KeyedObjectPoolMinIdleTimerTask( - keyedPool, key, minIdle); - getMinIdleTimer().schedule(task, 0L, period); - return task; - } - - /** - * Periodically check the idle object count for each key in the - * Collection keys in the keyedPool. At most one - * idle object will be added per period. - * - * @param keyedPool - * the keyedPool to check periodically. - * @param keys - * a collection of keys to check the idle object count. - * @param minIdle - * if the {@link KeyedObjectPool#getNumIdle(Object)} is less than - * this then add an idle object. - * @param period - * the frequency to check the number of idle objects in a - * keyedPool, see {@link Timer#schedule(TimerTask, long, long)}. - * @param the type of the pool key - * @param the type of pool entries - * @return a {@link Map} of key and {@link TimerTask} pairs that will - * periodically check the pools idle object count. - * @throws IllegalArgumentException - * when keyedPool, keys, or any of the - * values in the collection is null or when - * minIdle is negative or when period - * isn't valid for {@link Timer#schedule(TimerTask, long, long)} - * . - * @see #checkMinIdle(KeyedObjectPool, Object, int, long) - */ - public static Map checkMinIdle( - final KeyedObjectPool keyedPool, final Collection keys, - final int minIdle, final long period) - throws IllegalArgumentException { - if (keys == null) { - throw new IllegalArgumentException("keys must not be null."); - } - final Map tasks = new HashMap(keys.size()); - final Iterator iter = keys.iterator(); - while (iter.hasNext()) { - final K key = iter.next(); - final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period); - tasks.put(key, task); - } - return tasks; - } - - /** - * Call addObject() on pool count - * number of times. - * - * @param pool - * the pool to prefill. - * @param count - * the number of idle objects to add. - * @param the type of objects in the pool - * @throws Exception - * when {@link ObjectPool#addObject()} fails. - * @throws IllegalArgumentException - * when pool is null. - */ - public static void prefill(final ObjectPool pool, final int count) - throws Exception, IllegalArgumentException { - if (pool == null) { - throw new IllegalArgumentException("pool must not be null."); - } - for (int i = 0; i < count; i++) { - pool.addObject(); - } - } - - /** - * Call addObject(Object) on keyedPool with - * key count number of times. - * - * @param keyedPool - * the keyedPool to prefill. - * @param key - * the key to add objects for. - * @param count - * the number of idle objects to add for key. - * @param the type of the pool key - * @param the type of pool entries - * @throws Exception - * when {@link KeyedObjectPool#addObject(Object)} fails. - * @throws IllegalArgumentException - * when keyedPool or key is - * null. - */ - public static void prefill(final KeyedObjectPool keyedPool, - final K key, final int count) throws Exception, - IllegalArgumentException { - if (keyedPool == null) { - throw new IllegalArgumentException("keyedPool must not be null."); - } - if (key == null) { - throw new IllegalArgumentException("key must not be null."); - } - for (int i = 0; i < count; i++) { - keyedPool.addObject(key); - } - } - - /** - * Call addObject(Object) on keyedPool with each - * key in keys for count number of times. This has - * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)} - * for each key in the keys collection. - * - * @param keyedPool - * the keyedPool to prefill. - * @param keys - * {@link Collection} of keys to add objects for. - * @param count - * the number of idle objects to add for each key. - * @param the type of the pool key - * @param the type of pool entries - * @throws Exception - * when {@link KeyedObjectPool#addObject(Object)} fails. - * @throws IllegalArgumentException - * when keyedPool, keys, or any value - * in keys is null. - * @see #prefill(KeyedObjectPool, Object, int) - */ - public static void prefill(final KeyedObjectPool keyedPool, - final Collection keys, final int count) throws Exception, - IllegalArgumentException { - if (keys == null) { - throw new IllegalArgumentException("keys must not be null."); - } - final Iterator iter = keys.iterator(); - while (iter.hasNext()) { - prefill(keyedPool, iter.next(), count); - } - } - - /** - * Returns a synchronized (thread-safe) ObjectPool backed by the specified - * ObjectPool. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. Wrapping a pool that {@link #wait() waits} for poolable - * objects to be returned before allowing another one to be borrowed with - * another layer of synchronization will cause liveliness issues or a - * deadlock. - *

- * - * @param pool - * the ObjectPool to be "wrapped" in a synchronized ObjectPool. - * @param the type of objects in the pool - * @return a synchronized view of the specified ObjectPool. - */ - public static ObjectPool synchronizedPool(final ObjectPool pool) { - if (pool == null) { - throw new IllegalArgumentException("pool must not be null."); - } - /* - * assert !(pool instanceof GenericObjectPool) : - * "GenericObjectPool is already thread-safe"; assert !(pool instanceof - * SoftReferenceObjectPool) : - * "SoftReferenceObjectPool is already thread-safe"; assert !(pool - * instanceof StackObjectPool) : - * "StackObjectPool is already thread-safe"; assert - * !"org.apache.commons.pool.composite.CompositeObjectPool" - * .equals(pool.getClass().getName()) : - * "CompositeObjectPools are already thread-safe"; - */ - return new SynchronizedObjectPool(pool); - } - - /** - * Returns a synchronized (thread-safe) KeyedObjectPool backed by the - * specified KeyedObjectPool. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. Wrapping a pool that {@link #wait() waits} for poolable - * objects to be returned before allowing another one to be borrowed with - * another layer of synchronization will cause liveliness issues or a - * deadlock. - *

- * - * @param keyedPool - * the KeyedObjectPool to be "wrapped" in a synchronized - * KeyedObjectPool. - * @param the type of the pool key - * @param the type of pool entries - * @return a synchronized view of the specified KeyedObjectPool. - */ - public static KeyedObjectPool synchronizedPool( - final KeyedObjectPool keyedPool) { - if (keyedPool == null) { - throw new IllegalArgumentException("keyedPool must not be null."); - } - /* - * assert !(keyedPool instanceof GenericKeyedObjectPool) : - * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool - * instanceof StackKeyedObjectPool) : - * "StackKeyedObjectPool is already thread-safe"; assert - * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool" - * .equals(keyedPool.getClass().getName()) : - * "CompositeKeyedObjectPools are already thread-safe"; - */ - return new SynchronizedKeyedObjectPool(keyedPool); - } - - /** - * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the - * specified PoolableObjectFactory. - * - * @param factory - * the PoolableObjectFactory to be "wrapped" in a synchronized - * PoolableObjectFactory. - * @param the type of objects in the pool - * @return a synchronized view of the specified PoolableObjectFactory. - */ - public static PoolableObjectFactory synchronizedPoolableFactory( - final PoolableObjectFactory factory) { - return new SynchronizedPoolableObjectFactory(factory); - } - - /** - * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by - * the specified KeyedPoolableObjectFactory. - * - * @param keyedFactory - * the KeyedPoolableObjectFactory to be "wrapped" in a - * synchronized KeyedPoolableObjectFactory. - * @param the type of the pool key - * @param the type of pool entries - * @return a synchronized view of the specified KeyedPoolableObjectFactory. - */ - public static KeyedPoolableObjectFactory synchronizedPoolableFactory( - final KeyedPoolableObjectFactory keyedFactory) { - return new SynchronizedKeyedPoolableObjectFactory(keyedFactory); - } - - /** - * Returns a pool that adaptively decreases it's size when idle objects are - * no longer needed. This is intended as an always thread-safe alternative - * to using an idle object evictor provided by many pool implementations. - * This is also an effective way to shrink FIFO ordered pools that - * experience load spikes. - * - * @param pool - * the ObjectPool to be decorated so it shrinks it's idle count - * when possible. - * @param the type of objects in the pool - * @return a pool that adaptively decreases it's size when idle objects are - * no longer needed. - * @see #erodingPool(ObjectPool, float) - */ - public static ObjectPool erodingPool(final ObjectPool pool) { - return erodingPool(pool, 1f); - } - - /** - * Returns a pool that adaptively decreases it's size when idle objects are - * no longer needed. This is intended as an always thread-safe alternative - * to using an idle object evictor provided by many pool implementations. - * This is also an effective way to shrink FIFO ordered pools that - * experience load spikes. - *

- * The factor parameter provides a mechanism to tweak the rate at which the - * pool tries to shrink it's size. Values between 0 and 1 cause the pool to - * try to shrink it's size more often. Values greater than 1 cause the pool - * to less frequently try to shrink it's size. - *

- * - * @param pool - * the ObjectPool to be decorated so it shrinks it's idle count - * when possible. - * @param factor - * a positive value to scale the rate at which the pool tries to - * reduce it's size. If 0 < factor < 1 then the pool - * shrinks more aggressively. If 1 < factor then the pool - * shrinks less aggressively. - * @param the type of objects in the pool - * @return a pool that adaptively decreases it's size when idle objects are - * no longer needed. - * @see #erodingPool(ObjectPool) - */ - public static ObjectPool erodingPool(final ObjectPool pool, - final float factor) { - if (pool == null) { - throw new IllegalArgumentException("pool must not be null."); - } - if (factor <= 0f) { - throw new IllegalArgumentException("factor must be positive."); - } - return new ErodingObjectPool(pool, factor); - } - - /** - * Returns a pool that adaptively decreases it's size when idle objects are - * no longer needed. This is intended as an always thread-safe alternative - * to using an idle object evictor provided by many pool implementations. - * This is also an effective way to shrink FIFO ordered pools that - * experience load spikes. - * - * @param keyedPool - * the KeyedObjectPool to be decorated so it shrinks it's idle - * count when possible. - * @param the type of the pool key - * @param the type of pool entries - * @return a pool that adaptively decreases it's size when idle objects are - * no longer needed. - * @see #erodingPool(KeyedObjectPool, float) - * @see #erodingPool(KeyedObjectPool, float, boolean) - */ - public static KeyedObjectPool erodingPool( - final KeyedObjectPool keyedPool) { - return erodingPool(keyedPool, 1f); - } - - /** - * Returns a pool that adaptively decreases it's size when idle objects are - * no longer needed. This is intended as an always thread-safe alternative - * to using an idle object evictor provided by many pool implementations. - * This is also an effective way to shrink FIFO ordered pools that - * experience load spikes. - *

- * The factor parameter provides a mechanism to tweak the rate at which the - * pool tries to shrink it's size. Values between 0 and 1 cause the pool to - * try to shrink it's size more often. Values greater than 1 cause the pool - * to less frequently try to shrink it's size. - *

- * - * @param keyedPool - * the KeyedObjectPool to be decorated so it shrinks it's idle - * count when possible. - * @param factor - * a positive value to scale the rate at which the pool tries to - * reduce it's size. If 0 < factor < 1 then the pool - * shrinks more aggressively. If 1 < factor then the pool - * shrinks less aggressively. - * @param the type of the pool key - * @param the type of pool entries - * @return a pool that adaptively decreases it's size when idle objects are - * no longer needed. - * @see #erodingPool(KeyedObjectPool, float, boolean) - */ - public static KeyedObjectPool erodingPool( - final KeyedObjectPool keyedPool, final float factor) { - return erodingPool(keyedPool, factor, false); - } - - /** - * Returns a pool that adaptively decreases it's size when idle objects are - * no longer needed. This is intended as an always thread-safe alternative - * to using an idle object evictor provided by many pool implementations. - * This is also an effective way to shrink FIFO ordered pools that - * experience load spikes. - *

- * The factor parameter provides a mechanism to tweak the rate at which the - * pool tries to shrink it's size. Values between 0 and 1 cause the pool to - * try to shrink it's size more often. Values greater than 1 cause the pool - * to less frequently try to shrink it's size. - *

- *

- * The perKey parameter determines if the pool shrinks on a whole pool basis - * or a per key basis. When perKey is false, the keys do not have an effect - * on the rate at which the pool tries to shrink it's size. When perKey is - * true, each key is shrunk independently. - *

- * - * @param keyedPool - * the KeyedObjectPool to be decorated so it shrinks it's idle - * count when possible. - * @param factor - * a positive value to scale the rate at which the pool tries to - * reduce it's size. If 0 < factor < 1 then the pool - * shrinks more aggressively. If 1 < factor then the pool - * shrinks less aggressively. - * @param perKey - * when true, each key is treated independently. - * @param the type of the pool key - * @param the type of pool entries - * @return a pool that adaptively decreases it's size when idle objects are - * no longer needed. - * @see #erodingPool(KeyedObjectPool) - * @see #erodingPool(KeyedObjectPool, float) - */ - public static KeyedObjectPool erodingPool( - final KeyedObjectPool keyedPool, final float factor, - final boolean perKey) { - if (keyedPool == null) { - throw new IllegalArgumentException("keyedPool must not be null."); - } - if (factor <= 0f) { - throw new IllegalArgumentException("factor must be positive."); - } - if (perKey) { - return new ErodingPerKeyKeyedObjectPool(keyedPool, factor); - } - return new ErodingKeyedObjectPool(keyedPool, factor); - } - - /** - * Get the Timer for checking keyedPool's idle count. - * - * @return the {@link Timer} for checking keyedPool's idle count. - */ - private static Timer getMinIdleTimer() { - return TimerHolder.MIN_IDLE_TIMER; - } - - /** - * Timer task that adds objects to the pool until the number of idle - * instances reaches the configured minIdle. Note that this is not the same - * as the pool's minIdle setting. - */ - private static class ObjectPoolMinIdleTimerTask extends TimerTask { - - /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ - private final int minIdle; - - /** Object pool */ - private final ObjectPool pool; - - /** - * Create a new ObjectPoolMinIdleTimerTask for the given pool with the - * given minIdle setting. - * - * @param pool - * object pool - * @param minIdle - * number of idle instances to maintain - * @throws IllegalArgumentException - * if the pool is null - */ - ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) - throws IllegalArgumentException { - if (pool == null) { - throw new IllegalArgumentException("pool must not be null."); - } - this.pool = pool; - this.minIdle = minIdle; - } - - /** - * {@inheritDoc} - */ - - public void run() { - boolean success = false; - try { - if (pool.getNumIdle() < minIdle) { - pool.addObject(); - } - success = true; - - } catch (Exception e) { - cancel(); - - } finally { - // detect other types of Throwable and cancel this Timer - if (!success) { - cancel(); - } - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("ObjectPoolMinIdleTimerTask"); - sb.append("{minIdle=").append(minIdle); - sb.append(", pool=").append(pool); - sb.append('}'); - return sb.toString(); - } - } - - /** - * Timer task that adds objects to the pool until the number of idle - * instances for the given key reaches the configured minIdle. Note that - * this is not the same as the pool's minIdle setting. - */ - private static class KeyedObjectPoolMinIdleTimerTask extends - TimerTask { - /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ - private final int minIdle; - - /** Key to ensure minIdle for */ - private final K key; - - /** Keyed object pool */ - private final KeyedObjectPool keyedPool; - - /** - * Create a new KeyedObjecPoolMinIdleTimerTask. - * - * @param keyedPool - * keyed object pool - * @param key - * key to ensure minimum number of idle instances - * @param minIdle - * minimum number of idle instances - * @throws IllegalArgumentException - * if the key is null - */ - KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, - final K key, final int minIdle) throws IllegalArgumentException { - if (keyedPool == null) { - throw new IllegalArgumentException( - "keyedPool must not be null."); - } - this.keyedPool = keyedPool; - this.key = key; - this.minIdle = minIdle; - } - - /** - * {@inheritDoc} - */ - - public void run() { - boolean success = false; - try { - if (keyedPool.getNumIdle(key) < minIdle) { - keyedPool.addObject(key); - } - success = true; - - } catch (Exception e) { - cancel(); - - } finally { - // detect other types of Throwable and cancel this Timer - if (!success) { - cancel(); - } - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("KeyedObjectPoolMinIdleTimerTask"); - sb.append("{minIdle=").append(minIdle); - sb.append(", key=").append(key); - sb.append(", keyedPool=").append(keyedPool); - sb.append('}'); - return sb.toString(); - } - } - - /** - * A synchronized (thread-safe) ObjectPool backed by the specified - * ObjectPool. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. Wrapping a pool that {@link #wait() waits} for poolable - * objects to be returned before allowing another one to be borrowed with - * another layer of synchronization will cause liveliness issues or a - * deadlock. - *

- */ - private static class SynchronizedObjectPool implements ObjectPool { - - /** - * Object whose monitor is used to synchronize methods on the wrapped - * pool. - */ - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - - /** the underlying object pool */ - private final ObjectPool pool; - - /** - * Create a new SynchronizedObjectPool wrapping the given pool. - * - * @param pool - * the ObjectPool to be "wrapped" in a synchronized - * ObjectPool. - * @throws IllegalArgumentException - * if the pool is null - */ - SynchronizedObjectPool(final ObjectPool pool) - throws IllegalArgumentException { - if (pool == null) { - throw new IllegalArgumentException("pool must not be null."); - } - this.pool = pool; - } - - /** - * {@inheritDoc} - */ - - public T borrowObject() throws Exception, NoSuchElementException, - IllegalStateException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - return pool.borrowObject(); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void returnObject(final T obj) { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - pool.returnObject(obj); - } catch (Exception e) { - // swallowed as of Pool 2 - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void invalidateObject(final T obj) { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - pool.invalidateObject(obj); - } catch (Exception e) { - // swallowed as of Pool 2 - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void addObject() throws Exception, IllegalStateException, - UnsupportedOperationException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - pool.addObject(); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle() { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return pool.getNumIdle(); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumActive() { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return pool.getNumActive(); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void clear() throws Exception, UnsupportedOperationException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - pool.clear(); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void close() { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - pool.close(); - } catch (Exception e) { - // swallowed as of Pool 2 - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SynchronizedObjectPool"); - sb.append("{pool=").append(pool); - sb.append('}'); - return sb.toString(); - } - } - - /** - * A synchronized (thread-safe) KeyedObjectPool backed by the specified - * KeyedObjectPool. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. Wrapping a pool that {@link #wait() waits} for poolable - * objects to be returned before allowing another one to be borrowed with - * another layer of synchronization will cause liveliness issues or a - * deadlock. - *

- */ - private static class SynchronizedKeyedObjectPool implements - KeyedObjectPool { - - /** - * Object whose monitor is used to synchronize methods on the wrapped - * pool. - */ - private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); - - /** Underlying object pool */ - private final KeyedObjectPool keyedPool; - - /** - * Create a new SynchronizedKeyedObjectPool wrapping the given pool - * - * @param keyedPool - * KeyedObjectPool to wrap - * @throws IllegalArgumentException - * if keyedPool is null - */ - SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) - throws IllegalArgumentException { - if (keyedPool == null) { - throw new IllegalArgumentException( - "keyedPool must not be null."); - } - this.keyedPool = keyedPool; - } - - /** - * {@inheritDoc} - */ - - public V borrowObject(final K key) throws Exception, - NoSuchElementException, IllegalStateException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - return keyedPool.borrowObject(key); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void returnObject(final K key, final V obj) { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.returnObject(key, obj); - } catch (Exception e) { - // swallowed - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void invalidateObject(final K key, final V obj) { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.invalidateObject(key, obj); - } catch (Exception e) { - // swallowed as of Pool 2 - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void addObject(final K key) throws Exception, - IllegalStateException, UnsupportedOperationException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.addObject(key); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle(final K key) { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return keyedPool.getNumIdle(key); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumActive(final K key) { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return keyedPool.getNumActive(key); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle() { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return keyedPool.getNumIdle(); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public int getNumActive() { - ReadLock readLock = readWriteLock.readLock(); - readLock.lock(); - try { - return keyedPool.getNumActive(); - } finally { - readLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void clear() throws Exception, UnsupportedOperationException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.clear(); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void clear(final K key) throws Exception, - UnsupportedOperationException { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.clear(key); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void close() { - WriteLock writeLock = readWriteLock.writeLock(); - writeLock.lock(); - try { - keyedPool.close(); - } catch (Exception e) { - // swallowed as of Pool 2 - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SynchronizedKeyedObjectPool"); - sb.append("{keyedPool=").append(keyedPool); - sb.append('}'); - return sb.toString(); - } - } - - /** - * A fully synchronized PoolableObjectFactory that wraps a - * PoolableObjectFactory and synchronizes access to the wrapped factory - * methods. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. - *

- */ - private static class SynchronizedPoolableObjectFactory implements - PoolableObjectFactory { - /** Synchronization lock */ - private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); - - /** Wrapped factory */ - private final PoolableObjectFactory factory; - - /** - * Create a SynchronizedPoolableObjectFactory wrapping the given - * factory. - * - * @param factory - * underlying factory to wrap - * @throws IllegalArgumentException - * if the factory is null - */ - SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) - throws IllegalArgumentException { - if (factory == null) { - throw new IllegalArgumentException("factory must not be null."); - } - this.factory = factory; - } - - /** - * {@inheritDoc} - */ - - public T makeObject() throws Exception { - writeLock.lock(); - try { - return factory.makeObject(); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void destroyObject(final T obj) throws Exception { - writeLock.lock(); - try { - factory.destroyObject(obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public boolean validateObject(final T obj) { - writeLock.lock(); - try { - return factory.validateObject(obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void activateObject(final T obj) throws Exception { - writeLock.lock(); - try { - factory.activateObject(obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void passivateObject(final T obj) throws Exception { - writeLock.lock(); - try { - factory.passivateObject(obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SynchronizedPoolableObjectFactory"); - sb.append("{factory=").append(factory); - sb.append('}'); - return sb.toString(); - } - } - - /** - * A fully synchronized KeyedPoolableObjectFactory that wraps a - * KeyedPoolableObjectFactory and synchronizes access to the wrapped factory - * methods. - *

- * Note: This should not be used on pool implementations that already - * provide proper synchronization such as the pools provided in the Commons - * Pool library. - *

- */ - private static class SynchronizedKeyedPoolableObjectFactory - implements KeyedPoolableObjectFactory { - /** Synchronization lock */ - private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock(); - - /** Wrapped factory */ - private final KeyedPoolableObjectFactory keyedFactory; - - /** - * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given - * factory. - * - * @param keyedFactory - * underlying factory to wrap - * @throws IllegalArgumentException - * if the factory is null - */ - SynchronizedKeyedPoolableObjectFactory( - final KeyedPoolableObjectFactory keyedFactory) - throws IllegalArgumentException { - if (keyedFactory == null) { - throw new IllegalArgumentException( - "keyedFactory must not be null."); - } - this.keyedFactory = keyedFactory; - } - - /** - * {@inheritDoc} - */ - - public V makeObject(final K key) throws Exception { - writeLock.lock(); - try { - return keyedFactory.makeObject(key); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void destroyObject(final K key, final V obj) throws Exception { - writeLock.lock(); - try { - keyedFactory.destroyObject(key, obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public boolean validateObject(final K key, final V obj) { - writeLock.lock(); - try { - return keyedFactory.validateObject(key, obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void activateObject(final K key, final V obj) throws Exception { - writeLock.lock(); - try { - keyedFactory.activateObject(key, obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public void passivateObject(final K key, final V obj) throws Exception { - writeLock.lock(); - try { - keyedFactory.passivateObject(key, obj); - } finally { - writeLock.unlock(); - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SynchronizedKeyedPoolableObjectFactory"); - sb.append("{keyedFactory=").append(keyedFactory); - sb.append('}'); - return sb.toString(); - } - } - - /** - * Encapsulate the logic for when the next poolable object should be - * discarded. Each time update is called, the next time to shrink is - * recomputed, based on the float factor, number of idle instances in the - * pool and high water mark. Float factor is assumed to be between 0 and 1. - * Values closer to 1 cause less frequent erosion events. Erosion event - * timing also depends on numIdle. When this value is relatively high (close - * to previously established high water mark), erosion occurs more - * frequently. - */ - private static class ErodingFactor { - /** Determines frequency of "erosion" events */ - private final float factor; - - /** Time of next shrink event */ - private transient volatile long nextShrink; - - /** High water mark - largest numIdle encountered */ - private transient volatile int idleHighWaterMark; - - /** - * Create a new ErodingFactor with the given erosion factor. - * - * @param factor - * erosion factor - */ - public ErodingFactor(final float factor) { - this.factor = factor; - nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now - // + - // 15 - // min - // * - // factor - idleHighWaterMark = 1; - } - - /** - * Updates internal state using the supplied time and numIdle. - * - * @param now - * current time - * @param numIdle - * number of idle elements in the pool - */ - public void update(final long now, final int numIdle) { - final int idle = Math.max(0, numIdle); - idleHighWaterMark = Math.max(idle, idleHighWaterMark); - final float maxInterval = 15f; - final float minutes = maxInterval + - ((1f - maxInterval) / idleHighWaterMark) * idle; - nextShrink = now + (long) (minutes * 60000f * factor); - } - - /** - * Returns the time of the next erosion event. - * - * @return next shrink time - */ - public long getNextShrink() { - return nextShrink; - } - - /** - * {@inheritDoc} - */ - - public String toString() { - return "ErodingFactor{" + "factor=" + factor + - ", idleHighWaterMark=" + idleHighWaterMark + '}'; - } - } - - /** - * Decorates an object pool, adding "eroding" behavior. Based on the - * configured {@link #factor erosion factor}, objects returning to the pool - * may be invalidated instead of being added to idle capacity. - */ - private static class ErodingObjectPool implements ObjectPool { - /** Underlying object pool */ - private final ObjectPool pool; - - /** Erosion factor */ - private final ErodingFactor factor; - - /** - * Create an ErodingObjectPool wrapping the given pool using the - * specified erosion factor. - * - * @param pool - * underlying pool - * @param factor - * erosion factor - determines the frequency of erosion - * events - * @see #factor - */ - public ErodingObjectPool(final ObjectPool pool, final float factor) { - this.pool = pool; - this.factor = new ErodingFactor(factor); - } - - /** - * {@inheritDoc} - */ - - public T borrowObject() throws Exception, NoSuchElementException, - IllegalStateException { - return pool.borrowObject(); - } - - /** - * Returns obj to the pool, unless erosion is triggered, in which case - * obj is invalidated. Erosion is triggered when there are idle - * instances in the pool and more than the {@link #factor erosion - * factor}-determined time has elapsed since the last returnObject - * activation. - * - * @param obj - * object to return or invalidate - * @see #factor - */ - - public void returnObject(final T obj) { - boolean discard = false; - final long now = System.currentTimeMillis(); - synchronized (pool) { - if (factor.getNextShrink() < now) { // XXX: Pool 3: move test - // out of sync block - final int numIdle = pool.getNumIdle(); - if (numIdle > 0) { - discard = true; - } - - factor.update(now, numIdle); - } - } - try { - if (discard) { - pool.invalidateObject(obj); - } else { - pool.returnObject(obj); - } - } catch (Exception e) { - // swallowed - } - } - - /** - * {@inheritDoc} - */ - - public void invalidateObject(final T obj) { - try { - pool.invalidateObject(obj); - } catch (Exception e) { - // swallowed - } - } - - /** - * {@inheritDoc} - */ - - public void addObject() throws Exception, IllegalStateException, - UnsupportedOperationException { - pool.addObject(); - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle() { - return pool.getNumIdle(); - } - - /** - * {@inheritDoc} - */ - - public int getNumActive() { - return pool.getNumActive(); - } - - /** - * {@inheritDoc} - */ - - public void clear() throws Exception, UnsupportedOperationException { - pool.clear(); - } - - /** - * {@inheritDoc} - */ - - public void close() { - try { - pool.close(); - } catch (Exception e) { - // swallowed - } - } - - /** - * {@inheritDoc} - */ - - public String toString() { - return "ErodingObjectPool{" + "factor=" + factor + ", pool=" + - pool + '}'; - } - } - - /** - * Decorates a keyed object pool, adding "eroding" behavior. Based on the - * configured {@link #factor erosion factor}, objects returning to the pool - * may be invalidated instead of being added to idle capacity. - */ - private static class ErodingKeyedObjectPool implements - KeyedObjectPool { - /** Underlying pool */ - private final KeyedObjectPool keyedPool; - - /** Erosion factor */ - private final ErodingFactor erodingFactor; - - /** - * Create an ErodingObjectPool wrapping the given pool using the - * specified erosion factor. - * - * @param keyedPool - * underlying pool - * @param factor - * erosion factor - determines the frequency of erosion - * events - * @see #erodingFactor - */ - public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, - final float factor) { - this(keyedPool, new ErodingFactor(factor)); - } - - /** - * Create an ErodingObjectPool wrapping the given pool using the - * specified erosion factor. - * - * @param keyedPool - * underlying pool - must not be null - * @param erodingFactor - * erosion factor - determines the frequency of erosion - * events - * @see #factor - */ - protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, - final ErodingFactor erodingFactor) { - if (keyedPool == null) { - throw new IllegalArgumentException( - "keyedPool must not be null."); - } - this.keyedPool = keyedPool; - this.erodingFactor = erodingFactor; - } - - /** - * {@inheritDoc} - */ - - public V borrowObject(final K key) throws Exception, - NoSuchElementException, IllegalStateException { - return keyedPool.borrowObject(key); - } - - /** - * Returns obj to the pool, unless erosion is triggered, in which case - * obj is invalidated. Erosion is triggered when there are idle - * instances in the pool associated with the given key and more than the - * configured {@link #erodingFactor erosion factor} time has elapsed - * since the last returnObject activation. - * - * @param obj - * object to return or invalidate - * @param key - * key - * @see #erodingFactor - */ - - public void returnObject(final K key, final V obj) throws Exception { - boolean discard = false; - final long now = System.currentTimeMillis(); - final ErodingFactor factor = getErodingFactor(key); - synchronized (keyedPool) { - if (factor.getNextShrink() < now) { - final int numIdle = getNumIdle(key); - if (numIdle > 0) { - discard = true; - } - - factor.update(now, numIdle); - } - } - try { - if (discard) { - keyedPool.invalidateObject(key, obj); - } else { - keyedPool.returnObject(key, obj); - } - } catch (Exception e) { - // swallowed - } - } - - /** - * Returns the eroding factor for the given key - * - * @param key - * key - * @return eroding factor for the given keyed pool - */ - protected ErodingFactor getErodingFactor(final K key) { - return erodingFactor; - } - - /** - * {@inheritDoc} - */ - - public void invalidateObject(final K key, final V obj) { - try { - keyedPool.invalidateObject(key, obj); - } catch (Exception e) { - // swallowed - } - } - - /** - * {@inheritDoc} - */ - - public void addObject(final K key) throws Exception, - IllegalStateException, UnsupportedOperationException { - keyedPool.addObject(key); - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle() { - return keyedPool.getNumIdle(); - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle(final K key) { - return keyedPool.getNumIdle(key); - } - - /** - * {@inheritDoc} - */ - - public int getNumActive() { - return keyedPool.getNumActive(); - } - - /** - * {@inheritDoc} - */ - - public int getNumActive(final K key) { - return keyedPool.getNumActive(key); - } - - /** - * {@inheritDoc} - */ - - public void clear() throws Exception, UnsupportedOperationException { - keyedPool.clear(); - } - - /** - * {@inheritDoc} - */ - - public void clear(final K key) throws Exception, - UnsupportedOperationException { - keyedPool.clear(key); - } - - /** - * {@inheritDoc} - */ - - public void close() { - try { - keyedPool.close(); - } catch (Exception e) { - // swallowed - } - } - - /** - * Returns the underlying pool - * - * @return the keyed pool that this ErodingKeyedObjectPool wraps - */ - protected KeyedObjectPool getKeyedPool() { - return keyedPool; - } - - /** - * {@inheritDoc} - */ - - public String toString() { - return "ErodingKeyedObjectPool{" + "erodingFactor=" + - erodingFactor + ", keyedPool=" + keyedPool + '}'; - } - } - - /** - * Extends ErodingKeyedObjectPool to allow erosion to take place on a - * per-key basis. Timing of erosion events is tracked separately for - * separate keyed pools. - */ - private static class ErodingPerKeyKeyedObjectPool extends - ErodingKeyedObjectPool { - /** Erosion factor - same for all pools */ - private final float factor; - - /** Map of ErodingFactor instances keyed on pool keys */ - private final Map factors = Collections.synchronizedMap(new HashMap()); - - /** - * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed - * pool with the specified erosion factor. - * - * @param keyedPool - * underlying keyed pool - * @param factor - * erosion factor - */ - public ErodingPerKeyKeyedObjectPool( - final KeyedObjectPool keyedPool, final float factor) { - super(keyedPool, null); - this.factor = factor; - } - - /** - * {@inheritDoc} - */ - - protected ErodingFactor getErodingFactor(final K key) { - ErodingFactor factor = factors.get(key); - // this may result in two ErodingFactors being created for a key - // since they are small and cheap this is okay. - if (factor == null) { - factor = new ErodingFactor(this.factor); - factors.put(key, factor); - } - return factor; - } - - /** - * {@inheritDoc} - */ - - public String toString() { - return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor + - ", keyedPool=" + getKeyedPool() + '}'; - } - } -} \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java deleted file mode 100644 index 1a32787a..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/PoolableObjectFactory.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2; - -/** - * An interface defining life-cycle methods for instances to be served by an - * {@link ObjectPool}. - *

- * By contract, when an {@link ObjectPool} delegates to a - * {@link PoolableObjectFactory}, - *

    - *
  1. - * {@link #makeObject} is called whenever a new instance is needed. - *
  2. - *
  3. - * {@link #activateObject} is invoked on every instance that has been - * {@link #passivateObject passivated} before it is - * {@link ObjectPool#borrowObject borrowed} from the pool. - *
  4. - *
  5. - * {@link #validateObject} is invoked on {@link #activateObject activated} - * instances to make sure they can be {@link ObjectPool#borrowObject borrowed} - * from the pool. {@link #validateObject} may also be used to - * test an instance being {@link ObjectPool#returnObject returned} to the pool - * before it is {@link #passivateObject passivated}. It will only be invoked - * on an activated instance. - *
  6. - *
  7. - * {@link #passivateObject} is invoked on every instance when it is returned - * to the pool. - *
  8. - *
  9. - * {@link #destroyObject} is invoked on every instance when it is being - * "dropped" from the pool (whether due to the response from - * {@link #validateObject}, or for reasons specific to the pool - * implementation.) There is no guarantee that the instance being destroyed - * will be considered active, passive or in a generally consistent state. - *
  10. - *
- * {@link PoolableObjectFactory} must be thread-safe. The only promise - * an {@link ObjectPool} makes is that the same instance of an object will not - * be passed to more than one method of a PoolableObjectFactory - * at a time. - * - * @param Type of element managed in this factory. - * - * @see ObjectPool - * - * @version $Revision: 1333925 $ - * - * @since 2.0 - */ -public interface PoolableObjectFactory { - /** - * Creates an instance that can be served by the pool. Instances returned from - * this method should be in the same state as if they had been - * {@link #activateObject activated}. They will not be activated before being - * served by the pool. - * - * @return an instance that can be served by the pool. - * - * @throws Exception if there is a problem creating a new instance, - * this will be propagated to the code requesting an object. - */ - T makeObject() throws Exception; - - /** - * Destroys an instance no longer needed by the pool. - *

- * It is important for implementations of this method to be aware that there - * is no guarantee about what state obj will be in and the - * implementation should be prepared to handle unexpected errors. - *

- * Also, an implementation must take in to consideration that instances lost - * to the garbage collector may never be destroyed. - *

- * - * @param obj the instance to be destroyed - * - * @throws Exception should be avoided as it may be swallowed by - * the pool implementation. - * - * @see #validateObject - * @see ObjectPool#invalidateObject - */ - void destroyObject(T obj) throws Exception; - - /** - * Ensures that the instance is safe to be returned by the pool. - * - * @param obj the instance to be validated - * - * @return false if obj is not valid and should - * be dropped from the pool, true otherwise. - */ - boolean validateObject(T obj); - - /** - * Reinitialize an instance to be returned by the pool. - * - * @param obj the instance to be activated - * - * @throws Exception if there is a problem activating obj, - * this exception may be swallowed by the pool. - * - * @see #destroyObject - */ - void activateObject(T obj) throws Exception; - - /** - * Uninitialize an instance to be returned to the idle object pool. - * - * @param obj the instance to be passivated - * - * @throws Exception if there is a problem passivating obj, - * this exception may be swallowed by the pool. - * - * @see #destroyObject - */ - void passivateObject(T obj) throws Exception; -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java deleted file mode 100644 index 3bfb41ae..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/AbandonedConfig.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.io.PrintWriter; - -/** - * Configuration settings for abandoned object removal. - * - * @version $Revision:$ - */ -public class AbandonedConfig { - - /** - * Whether or not borrowObject performs abandoned object removal. - */ - private boolean removeAbandonedOnBorrow = false; - - /** - * Whether or not pool maintenance (evictor) performs abandoned object - * removal. - */ - private boolean removeAbandonedOnMaintenance = false; - - /** - *

Flag to remove abandoned objects if they exceed the - * removeAbandonedTimeout when borrowObject is invoked.

- * - *

The default value is false.

- * - *

If set to true, abandoned objects are removed by borrowObject if - * there are fewer than 2 idle objects available in the pool and - * getNumActive() > getMaxTotal() - 3

- * - * @return true if abandoned objects are to be removed by borrowObject - */ - public boolean getRemoveAbandonedOnBorrow() { - return (this.removeAbandonedOnBorrow); - } - - /** - *

Flag to remove abandoned objects if they exceed the - * removeAbandonedTimeout when borrowObject is invoked.

- * - * @param removeAbandonedOnBorrow true means abandoned objects will be - * removed by borrowObject - * @see #getRemoveAbandonedOnBorrow() - */ - public void setRemoveAbandonedOnBorrow(boolean removeAbandonedOnBorrow) { - this.removeAbandonedOnBorrow = removeAbandonedOnBorrow; - } - - /** - *

Flag to remove abandoned objects if they exceed the - * removeAbandonedTimeout when pool maintenance (the "evictor") - * runs.

- * - *

The default value is false.

- * - *

If set to true, abandoned objects are removed by the pool - * maintenance thread when it runs. This setting has no effect - * unless maintenance is enabled by setting - *{@link GenericObjectPool#getTimeBetweenEvictionRunsMillis() timeBetweenEvictionRunsMillis} - * to a positive number.

- * - * @return true if abandoned objects are to be removed by the evictor - */ - public boolean getRemoveAbandonedOnMaintenance() { - return (this.removeAbandonedOnMaintenance); - } - - /** - *

Flag to remove abandoned objects if they exceed the - * removeAbandonedTimeout when pool maintenance runs.

- * - * @param removeAbandonedOnMaintenance true means abandoned objects will be - * removed by pool maintenance - * @see #getRemoveAbandonedOnMaintenance - */ - public void setRemoveAbandonedOnMaintenance(boolean removeAbandonedOnMaintenance) { - this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance; - } - - /** - * Timeout in seconds before an abandoned object can be removed. - */ - private int removeAbandonedTimeout = 300; - - /** - *

Timeout in seconds before an abandoned object can be removed.

- * - *

The time of most recent use of an object is the maximum (latest) of - * {@link TrackedUse#getLastUsed()} (if this class of the object implements - * TrackedUse) and the time when the object was borrowed from the pool.

- * - *

The default value is 300 seconds.

- * - * @return the abandoned object timeout in seconds - */ - public int getRemoveAbandonedTimeout() { - return (this.removeAbandonedTimeout); - } - - /** - *

Sets the timeout in seconds before an abandoned object can be - * removed

- * - *

Setting this property has no effect if - * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and - * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance} - * are both false.

- * - * @param removeAbandonedTimeout new abandoned timeout in seconds - * @see #getRemoveAbandonedTimeout() - */ - public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) { - this.removeAbandonedTimeout = removeAbandonedTimeout; - } - - /** - * Determines whether or not to log stack traces for application code - * which abandoned an object. - */ - private boolean logAbandoned = false; - - /** - * Flag to log stack traces for application code which abandoned - * an object. - * - * Defaults to false. - * Logging of abandoned objects adds overhead for every object created - * because a stack trace has to be generated. - * - * @return boolean true if stack trace logging is turned on for abandoned - * objects - * - */ - public boolean getLogAbandoned() { - return (this.logAbandoned); - } - - /** - * Sets the flag to log stack traces for application code which abandoned - * an object. - * - * @param logAbandoned true turns on abandoned stack trace logging - * @see #getLogAbandoned() - * - */ - public void setLogAbandoned(boolean logAbandoned) { - this.logAbandoned = logAbandoned; - } - - /** - * PrintWriter to use to log information on abandoned objects. - */ - private PrintWriter logWriter = new PrintWriter(System.out); - - /** - * Returns the log writer being used by this configuration to log - * information on abandoned objects. If not set, a PrintWriter based on - * System.out is used. - * - * @return log writer in use - */ - public PrintWriter getLogWriter() { - return logWriter; - } - - /** - * Sets the log writer to be used by this configuration to log - * information on abandoned objects. - * - * @param logWriter The new log writer - */ - public void setLogWriter(PrintWriter logWriter) { - this.logWriter = logWriter; - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java deleted file mode 100644 index 44abfb86..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseGenericObjectPool.java +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.TimerTask; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.management.InstanceAlreadyExistsException; -import javax.management.InstanceNotFoundException; -import javax.management.ListenerNotFoundException; -import javax.management.MBeanNotificationInfo; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.NotCompliantMBeanException; -import javax.management.Notification; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationEmitter; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; -import javax.management.ObjectName; - -/** - * Base class that provides common functionality for {@link GenericObjectPool} - * and {@link GenericKeyedObjectPool}. The primary reason this class exists is - * reduce code duplication between the two pool implementations. - * - * @param Type of element pooled in this pool. - * - * This class is intended to be thread-safe. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public abstract class BaseGenericObjectPool implements NotificationEmitter { - - // Constants - /** - * Name of the JMX notification broadcast when the pool implementation - * swallows an {@link Exception}. - */ - public static final String NOTIFICATION_SWALLOWED_EXCEPTION = - "SWALLOWED_EXCEPTION"; - /** - * The size of the caches used to store historical data for some attributes - * so that rolling means may be calculated. - */ - public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100; - private static final int SWALLOWED_EXCEPTION_QUEUE_SIZE = 10; - - // Configuration attributes - private volatile int maxTotal = - GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL; - private volatile boolean blockWhenExhausted = - GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED; - private volatile long maxWaitMillis = - GenericKeyedObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS; - private volatile boolean lifo = GenericObjectPoolConfig.DEFAULT_LIFO; - private volatile boolean testOnBorrow = - GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW; - private volatile boolean testOnReturn = - GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN; - private volatile boolean testWhileIdle = - GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE; - private volatile long timeBetweenEvictionRunsMillis = - GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; - private volatile int numTestsPerEvictionRun = - GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; - private volatile long minEvictableIdleTimeMillis = - GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - private volatile long softMinEvictableIdleTimeMillis = - GenericObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - private volatile EvictionPolicy evictionPolicy; - - - // Internal (primarily state) attributes - final Object closeLock = new Object(); - volatile boolean closed = false; - final Object evictionLock = new Object(); - private Evictor evictor = null; // @GuardedBy("evictionLock") - Iterator> evictionIterator = null; // @GuardedBy("evictionLock") - /* - * Class loader for evictor thread to use since in a J2EE or similar - * environment the context class loader for the evictor thread may have - * visibility of the correct factory. See POOL-161. - */ - private final ClassLoader factoryClassLoader; - - - // Monitoring (primarily JMX) attributes - private final ObjectName oname; - private final NotificationBroadcasterSupport jmxNotificationSupport; - private final String creationStackTrace; - private final Deque swallowedExceptions = new LinkedList(); - private final AtomicInteger swallowedExcpetionCount = new AtomicInteger(0); - private final AtomicLong borrowedCount = new AtomicLong(0); - private final AtomicLong returnedCount = new AtomicLong(0); - final AtomicLong createdCount = new AtomicLong(0); - final AtomicLong destroyedCount = new AtomicLong(0); - final AtomicLong destroyedByEvictorCount = new AtomicLong(0); - final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0); - private final LinkedList activeTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() - private final LinkedList idleTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() - private final LinkedList waitTimes = new LinkedList(); // @GuardedBy("activeTimes") - except in initStats() - private final Object maxBorrowWaitTimeMillisLock = new Object(); - private volatile long maxBorrowWaitTimeMillis = 0; // @GuardedBy("maxBorrowWaitTimeMillisLock") - - - /** - * Handles JMX registration (if required) and the initialization required for - * monitoring. - * - * @param config Pool configuration - * @param jmxNameBase Base JMX name for the new pool - * @param jmxNamePrefix Prefix tobe used for JMX name for the new pool - */ - public BaseGenericObjectPool(BaseObjectPoolConfig config, - String jmxNameBase, String jmxNamePrefix) { - if (config.getJmxEnabled()) { - this.jmxNotificationSupport = new NotificationBroadcasterSupport(); - this.oname = jmxRegister(jmxNameBase, jmxNamePrefix); - } else { - this.jmxNotificationSupport = null; - this.oname = null; - } - - // Populate the swallowed exceptions queue - for (int i = 0; i < SWALLOWED_EXCEPTION_QUEUE_SIZE; i++) { - swallowedExceptions.add(null); - } - - // Populate the creation stack trace - this.creationStackTrace = getStackTrace(new Exception()); - - // save the current CCL to be used later by the evictor Thread - factoryClassLoader = Thread.currentThread().getContextClassLoader(); - - // Initialise the attributes used to record rolling averages - initStats(); - } - - - /** - * Returns the maximum number of objects that can be allocated by the pool - * (checked out to clients, or idle awaiting checkout) at a given time. When - * non-positive, there is no limit to the number of objects that can be - * managed by the pool at one time. - * - * @return the cap on the total number of object instances managed by the - * pool. - * - * @see #setMaxTotal - */ - public final int getMaxTotal() { - return maxTotal; - } - - /** - * Sets the cap on the number of objects that can be allocated by the pool - * (checked out to clients, or idle awaiting checkout) at a given time. Use - * a negative value for no limit. - * - * @param maxTotal The cap on the total number of object instances managed - * by the pool. Negative values mean that there is no limit - * to the number of objects allocated by the pool. - * - * @see #getMaxTotal - */ - public final void setMaxTotal(int maxTotal) { - this.maxTotal = maxTotal; - } - - /** - * Returns whether to block when the borrowObject() method is - * invoked when the pool is exhausted (the maximum number of "active" - * objects has been reached). - * - * @return true if borrowObject() should block - * when the pool is exhausted - * - * @see #setBlockWhenExhausted - */ - public final boolean getBlockWhenExhausted() { - return blockWhenExhausted; - } - - /** - * Sets whether to block when the borrowObject() method is - * invoked when the pool is exhausted (the maximum number of "active" - * objects has been reached). - * - * @param blockWhenExhausted true if - * borrowObject() should block - * when the pool is exhausted - * - * @see #getBlockWhenExhausted - */ - public final void setBlockWhenExhausted(boolean blockWhenExhausted) { - this.blockWhenExhausted = blockWhenExhausted; - } - - /** - * Returns the maximum amount of time (in milliseconds) the - * borrowObject() method should block before throwing an - * exception when the pool is exhausted and - * {@link #getBlockWhenExhausted} is true. When less than 0, the - * borrowObject() method may block indefinitely. - * - * @return the maximum number of milliseconds borrowObject() - * will block. - * - * @see #setMaxWaitMillis - * @see #setBlockWhenExhausted - */ - public final long getMaxWaitMillis() { - return maxWaitMillis; - } - - /** - * Sets the maximum amount of time (in milliseconds) the - * borrowObject() method should block before throwing an - * exception when the pool is exhausted and - * {@link #getBlockWhenExhausted} is true. When less than 0, the - * borrowObject() method may block indefinitely. - * - * @param maxWaitMillis the maximum number of milliseconds - * borrowObject() will block or negative - * for indefinitely. - * - * @see #getMaxWaitMillis - * @see #setBlockWhenExhausted - */ - public final void setMaxWaitMillis(long maxWaitMillis) { - this.maxWaitMillis = maxWaitMillis; - } - - /** - * Returns whether the pool has LIFO (last in, first out) behaviour with - * respect to idle objects - always returning the most recently used object - * from the pool, or as a FIFO (first in, first out) queue, where the pool - * always returns the oldest object in the idle object pool. - * - * @return true if the pool is configured with LIFO behaviour - * or false if the pool is configured with FIFO - * behaviour - * - * @see #setLifo - */ - public final boolean getLifo() { - return lifo; - } - - /** - * Sets whether the pool has LIFO (last in, first out) behaviour with - * respect to idle objects - always returning the most recently used object - * from the pool, or as a FIFO (first in, first out) queue, where the pool - * always returns the oldest object in the idle object pool. - * - * @param lifo true if the pool is to be configured with LIFO - * behaviour or false if the pool is to be - * configured with FIFO behaviour - * - * @see #getLifo() - */ - public final void setLifo(boolean lifo) { - this.lifo = lifo; - } - - /** - * Returns whether objects borrowed from the pool will be validated before - * being returned from the borrowObject() method. Validation is - * performed by the validateObject() method of the factory - * associated with the pool. If the object fails to validate, it will be - * removed from the pool and destroyed, and a new attempt will be made to - * borrow an object from the pool. - * - * @return true if objects are validated before being returned - * from the borrowObject() method - * - * @see #setTestOnBorrow - */ - public final boolean getTestOnBorrow() { - return testOnBorrow; - } - - /** - * Sets whether objects borrowed from the pool will be validated before - * being returned from the borrowObject() method. Validation is - * performed by the validateObject() method of the factory - * associated with the pool. If the object fails to validate, it will be - * removed from the pool and destroyed, and a new attempt will be made to - * borrow an object from the pool. - * - * @param testOnBorrow true if objects should be validated - * before being returned from the - * borrowObject() method - * - * @see #getTestOnBorrow - */ - public final void setTestOnBorrow(boolean testOnBorrow) { - this.testOnBorrow = testOnBorrow; - } - - /** - * Returns whether objects borrowed from the pool will be validated when - * they are returned to the pool via the returnObject() method. - * Validation is performed by the validateObject() method of - * the factory associated with the pool. If the object fails to it will be - * destroyed rather then returned the pool. - * - * @return true if objects are validated on being returned to - * the pool via the returnObject() method - * - * @see #setTestOnReturn - */ - public final boolean getTestOnReturn() { - return testOnReturn; - } - - /** - * Sets whether objects borrowed from the pool will be validated when - * they are returned to the pool via the returnObject() method. - * Validation is performed by the validateObject() method of - * the factory associated with the pool. If the object fails to it will be - * destroyed rather then returned the pool. - * - * @param testOnReturn true if objects are validated on being - * returned to the pool via the - * returnObject() method - * - * @see #getTestOnReturn - */ - public final void setTestOnReturn(boolean testOnReturn) { - this.testOnReturn = testOnReturn; - } - - /** - * Returns whether objects sitting idle in the pool will be validated by the - * idle object evictor (if any - see - * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed - * by the validateObject() method of the factory associated - * with the pool. If the object fails to validate, it will be removed from - * the pool and destroyed. - * - * @return true if objects will be validated by the evictor - * - * @see #setTestWhileIdle - * @see #setTimeBetweenEvictionRunsMillis - */ - public final boolean getTestWhileIdle() { - return testWhileIdle; - } - - /** - * Returns whether objects sitting idle in the pool will be validated by the - * idle object evictor (if any - see - * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed - * by the validateObject() method of the factory associated - * with the pool. If the object fails to validate, it will be removed from - * the pool and destroyed. - * - * @param testWhileIdle - * true so objects will be validated by the evictor - * - * @see #getTestWhileIdle - * @see #setTimeBetweenEvictionRunsMillis - */ - public final void setTestWhileIdle(boolean testWhileIdle) { - this.testWhileIdle = testWhileIdle; - } - - /** - * Returns the number of milliseconds to sleep between runs of the idle - * object evictor thread. When non-positive, no idle object evictor thread - * will be run. - * - * @return number of milliseconds to sleep between evictor runs - * - * @see #setTimeBetweenEvictionRunsMillis - */ - public final long getTimeBetweenEvictionRunsMillis() { - return timeBetweenEvictionRunsMillis; - } - - /** - * Sets the number of milliseconds to sleep between runs of the idle - * object evictor thread. When non-positive, no idle object evictor thread - * will be run. - * - * @param timeBetweenEvictionRunsMillis - * number of milliseconds to sleep between evictor runs - * - * @see #getTimeBetweenEvictionRunsMillis - */ - public final void setTimeBetweenEvictionRunsMillis( - long timeBetweenEvictionRunsMillis) { - this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; - startEvictor(timeBetweenEvictionRunsMillis); - } - - /** - * Returns the maximum number of objects to examine during each run (if any) - * of the idle object evictor thread. When positive, the number of tests - * performed for a run will be the minimum of the configured value and the - * number of idle instances in the pool. When negative, the number of tests - * performed will be ceil({@link #getNumIdle}/ - * abs({@link #getNumTestsPerEvictionRun})) whch means that when the value - * is -n roughly one nth of the idle objects will be tested per - * run. - * - * @return max number of objects to examine during each evictor run - * - * @see #setNumTestsPerEvictionRun - * @see #setTimeBetweenEvictionRunsMillis - */ - public final int getNumTestsPerEvictionRun() { - return numTestsPerEvictionRun; - } - - /** - * Sets the maximum number of objects to examine during each run (if any) - * of the idle object evictor thread. When positive, the number of tests - * performed for a run will be the minimum of the configured value and the - * number of idle instances in the pool. When negative, the number of tests - * performed will be ceil({@link #getNumIdle}/ - * abs({@link #getNumTestsPerEvictionRun})) whch means that when the value - * is -n roughly one nth of the idle objects will be tested per - * run. - * - * @param numTestsPerEvictionRun - * max number of objects to examine during each evictor run - * - * @see #getNumTestsPerEvictionRun - * @see #setTimeBetweenEvictionRunsMillis - */ - public final void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { - this.numTestsPerEvictionRun = numTestsPerEvictionRun; - } - - /** - * Returns the minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction by the idle object evictor (if any - - * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, - * no objects will be evicted from the pool due to idle time alone. - * - * @return minimum amount of time an object may sit idle in the pool before - * it is eligible for eviction - * - * @see #setMinEvictableIdleTimeMillis - * @see #setTimeBetweenEvictionRunsMillis - */ - public final long getMinEvictableIdleTimeMillis() { - return minEvictableIdleTimeMillis; - } - - /** - * Sets the minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction by the idle object evictor (if any - - * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive, - * no objects will be evicted from the pool due to idle time alone. - * - * @param minEvictableIdleTimeMillis - * minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction - * - * @see #getMinEvictableIdleTimeMillis - * @see #setTimeBetweenEvictionRunsMillis - */ - public final void setMinEvictableIdleTimeMillis( - long minEvictableIdleTimeMillis) { - this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; - } - - /** - * Returns the minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction by the idle object evictor (if any - - * see {@link #setTimeBetweenEvictionRunsMillis(long)}), - * with the extra condition that at least minIdle object - * instances remain in the pool. This setting is overridden by - * {@link #getMinEvictableIdleTimeMillis} (that is, if - * {@link #getMinEvictableIdleTimeMillis} is positive, then - * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). - * - * @return minimum amount of time an object may sit idle in the pool before - * it is eligible for eviction if minIdle instances are available - * - * @see #setSoftMinEvictableIdleTimeMillis - */ - public final long getSoftMinEvictableIdleTimeMillis() { - return softMinEvictableIdleTimeMillis; - } - - /** - * Sets the minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction by the idle object evictor (if any - - * see {@link #setTimeBetweenEvictionRunsMillis(long)}), - * with the extra condition that at least minIdle object - * instances remain in the pool. This setting is overridden by - * {@link #getMinEvictableIdleTimeMillis} (that is, if - * {@link #getMinEvictableIdleTimeMillis} is positive, then - * {@link #getSoftMinEvictableIdleTimeMillis} is ignored). - * - * @param softMinEvictableIdleTimeMillis - * minimum amount of time an object may sit idle in the pool - * before it is eligible for eviction if minIdle instances are - * available - * - * @see #getSoftMinEvictableIdleTimeMillis - */ - public final void setSoftMinEvictableIdleTimeMillis( - long softMinEvictableIdleTimeMillis) { - this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; - } - - /** - * Returns the name of the {@link EvictionPolicy} implementation that is - * used by this pool. - * - * @return The fully qualified class name of the {@link EvictionPolicy} - * - * @see #setEvictionPolicyClassName(String) - */ - public final String getEvictionPolicyClassName() { - return evictionPolicy.getClass().getName(); - } - - /** - * Sets the name of the {@link EvictionPolicy} implementation that is - * used by this pool. - * - * @param evictionPolicyClassName the fully qualified class name of the - * new eviction policy - * - * @see #getEvictionPolicyClassName() - */ - @SuppressWarnings("unchecked") - public final void setEvictionPolicyClassName( - String evictionPolicyClassName) { - try { - Class clazz = Class.forName(evictionPolicyClassName); - Object policy = clazz.newInstance(); - if (policy instanceof EvictionPolicy) { - this.evictionPolicy = (EvictionPolicy) policy; - } - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException( - "Unable to create EvictionPolicy instance of type " + - evictionPolicyClassName, e); - } catch (InstantiationException e) { - throw new IllegalArgumentException( - "Unable to create EvictionPolicy instance of type " + - evictionPolicyClassName, e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException( - "Unable to create EvictionPolicy instance of type " + - evictionPolicyClassName, e); - } - } - - - /** - * Closes the pool, destroys the remaining idle objects and, if registered - * in JMX, deregisters it. - */ - public abstract void close(); - - /** - * Has this pool instance been closed. - * @return true when this pool has been closed. - */ - public final boolean isClosed() { - return closed; - } - - /** - *

Perform numTests idle object eviction tests, evicting - * examined objects that meet the criteria for eviction. If - * testWhileIdle is true, examined objects are validated - * when visited (and removed if invalid); otherwise only objects that - * have been idle for more than minEvicableIdleTimeMillis - * are removed.

- * - * @throws Exception when there is a problem evicting idle objects. - */ - public abstract void evict() throws Exception; - - /** - * Returns the {@link EvictionPolicy} defined for this pool. - * @return the eviction policy - */ - final EvictionPolicy getEvictionPolicy() { - return evictionPolicy; - } - - /** - * Verifies that the pool is open. - * @throws IllegalStateException if the pool is closed. - */ - final void assertOpen() throws IllegalStateException { - if (isClosed()) { - throw new IllegalStateException("Pool not open"); - } - } - - /** - *

Starts the evictor with the given delay. If there is an evictor - * running when this method is called, it is stopped and replaced with a - * new evictor with the specified delay.

- * - *

This method needs to be final, since it is called from a constructor. - * See POOL-195.

- * - * @param delay time in milliseconds before start and between eviction runs - */ - final void startEvictor(long delay) { - synchronized (evictionLock) { - if (null != evictor) { - EvictionTimer.cancel(evictor); - evictor = null; - evictionIterator = null; - } - if (delay > 0) { - evictor = new Evictor(); - EvictionTimer.schedule(evictor, delay, delay); - } - } - } - - /** - * Tries to ensure that the configured minimum number of idle instances are - * available in the pool. - * @throws Exception if an error occurs creating idle instances - */ - abstract void ensureMinIdle() throws Exception; - - - // Monitoring (primarily JMX) related methods - - /** - * Provides the name under which the pool has been registered with the - * platform MBean server or null if the pool has not been - * registered. - * @return the JMX name - */ - public final ObjectName getJmxName() { - return oname; - } - - /** - * Provides the stack trace for the call that created this pool. JMX - * registration may trigger a memory leak so it is important that pools are - * deregistered when no longer used by calling the {@link #close()} method. - * This method is provided to assist with identifying code that creates but - * does not close it thereby creating a memory leak. - * @return pool creation stack trace - */ - public final String getCreationStackTrace() { - return creationStackTrace; - } - - /** - * Lists the most recent exceptions that have been swallowed by the pool - * implementation. Exceptions are typically swallowed when a problem occurs - * while destroying an object. - * @return array containing stack traces of recently swallowed exceptions - */ - public final String[] getSwallowedExceptions() { - List temp = - new ArrayList(SWALLOWED_EXCEPTION_QUEUE_SIZE); - synchronized (swallowedExceptions) { - temp.addAll(swallowedExceptions); - } - return temp.toArray(new String[SWALLOWED_EXCEPTION_QUEUE_SIZE]); - } - - /** - * The total number of objects successfully borrowed from this pool over the - * lifetime of the pool. - * @return the borrowed object count - */ - public final long getBorrowedCount() { - return borrowedCount.get(); - } - - /** - * The total number of objects returned to this pool over the lifetime of - * the pool. This excludes attempts to return the same object multiple - * times. - * @return the returned object count - */ - public final long getReturnedCount() { - return returnedCount.get(); - } - - /** - * The total number of objects created for this pool over the lifetime of - * the pool. - * @return the created object count - */ - public final long getCreatedCount() { - return createdCount.get(); - } - - /** - * The total number of objects destroyed by this pool over the lifetime of - * the pool. - * @return the destroyed object count - */ - public final long getDestroyedCount() { - return destroyedCount.get(); - } - - /** - * The total number of objects destroyed by the evictor associated with this - * pool over the lifetime of the pool. - * @return the evictor destroyed object count - */ - public final long getDestroyedByEvictorCount() { - return destroyedByEvictorCount.get(); - } - - /** - * The total number of objects destroyed by this pool as a result of failing - * validation during borrowObject() over the lifetime of the - * pool. - * @return validation destroyed object count - */ - public final long getDestroyedByBorrowValidationCount() { - return destroyedByBorrowValidationCount.get(); - } - - /** - * The mean time objects are active for based on the last {@link - * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool. - * @return mean time an object has been checked out from the pool among - * recently returned objects - */ - public final long getMeanActiveTimeMillis() { - return getMeanFromStatsCache(activeTimes); - } - - /** - * The mean time objects are idle for based on the last {@link - * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. - * @return mean time an object has been idle in the pool among recently - * borrowed objects - */ - public final long getMeanIdleTimeMillis() { - return getMeanFromStatsCache(idleTimes); - } - - /** - * The mean time threads wait to borrow an object based on the last {@link - * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool. - * @return mean time in milliseconds that a recently served thread has had - * to wait to borrow an object from the pool - */ - public final long getMeanBorrowWaitTimeMillis() { - return getMeanFromStatsCache(waitTimes); - } - - /** - * The maximum time a thread has waited to borrow objects from the pool. - * @return maximum wait time in milliseconds since the pool was created - */ - public final long getMaxBorrowWaitTimeMillis() { - return maxBorrowWaitTimeMillis; - } - - /** - * The number of instances currently idle in this pool. - * @return count of instances available for checkout from the pool - */ - public abstract int getNumIdle(); - - /** - * Returns the {@link NotificationBroadcasterSupport} for the pool - * @return JMX notification broadcaster - */ - final NotificationBroadcasterSupport getJmxNotificationSupport() { - return jmxNotificationSupport; - } - - /** - * Swallows an exception, sends a JMX notification, and adds the swallowed exception - * to the swallowed exceptions queue. - * @param e exception to be swallowed - */ - final void swallowException(Exception e) { - String msg = getStackTrace(e); - - ObjectName oname = getJmxName(); - if (oname != null && !isClosed()) { - Notification n = new Notification(NOTIFICATION_SWALLOWED_EXCEPTION, - oname, swallowedExcpetionCount.incrementAndGet(), msg); - getJmxNotificationSupport().sendNotification(n); - } - - // Add the exception the queue, removing the oldest - synchronized (swallowedExceptions) { - swallowedExceptions.addLast(msg); - swallowedExceptions.pollFirst(); - } - } - - /** - * Updates statistics after an object is borrowed from the pool. - * @param p object borrowed from the pool - * @param waitTime time (in milliseconds) that the borrowing thread had to wait - */ - final void updateStatsBorrow(PooledObject p, long waitTime) { - borrowedCount.incrementAndGet(); - synchronized (idleTimes) { - idleTimes.add(Long.valueOf(p.getIdleTimeMillis())); - idleTimes.poll(); - } - synchronized (waitTimes) { - waitTimes.add(Long.valueOf(waitTime)); - waitTimes.poll(); - } - synchronized (maxBorrowWaitTimeMillisLock) { - if (waitTime > maxBorrowWaitTimeMillis) { - maxBorrowWaitTimeMillis = waitTime; - } - } - } - - /** - * Updates statistics after an object is returned to the pool. - * @param activeTime the amount of time (in milliseconds) that the returning - * object was checked out - */ - final void updateStatsReturn(long activeTime) { - returnedCount.incrementAndGet(); - synchronized (activeTimes) { - activeTimes.add(Long.valueOf(activeTime)); - activeTimes.poll(); - } - } - - /** - * Unregisters this pool's MBean. - */ - final void jmxUnregister() { - if (oname != null) { - try { - ManagementFactory.getPlatformMBeanServer().unregisterMBean( - oname); - } catch (MBeanRegistrationException e) { - swallowException(e); - } catch (InstanceNotFoundException e) { - swallowException(e); - } - } - } - - /** - * Registers the pool with the platform MBean server. - * The registered name will be - * jmxNameBase + jmxNamePrefix + i where i is the least - * integer greater than or equal to 1 such that the name is not already - * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException - * returning null. - * - * @param jmxNameBase base JMX name for this pool - * @param jmxNamePrefix name prefix - * @return registered ObjectName, null if registration fails - */ - private ObjectName jmxRegister(String jmxNameBase, String jmxNamePrefix) { - ObjectName objectName = null; - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - int i = 1; - boolean registered = false; - while (!registered) { - try { - ObjectName oname = - new ObjectName(jmxNameBase + jmxNamePrefix + i); - mbs.registerMBean(this, oname); - objectName = oname; - registered = true; - } catch (MalformedObjectNameException e) { - if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals( - jmxNamePrefix)) { - // Shouldn't happen. Skip registration if it does. - registered = true; - } else { - // Must be an invalid name prefix. Use the default - // instead. - jmxNamePrefix = - BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX; - } - } catch (InstanceAlreadyExistsException e) { - // Increment the index and try again - i++; - } catch (MBeanRegistrationException e) { - // Shouldn't happen. Skip registration if it does. - registered = true; - } catch (NotCompliantMBeanException e) { - // Shouldn't happen. Skip registration if it does. - registered = true; - } - } - return objectName; - } - - /** - * Gets the stack trace of an exception as a string. - * @param e exception to trace - * @return exception stack trace as a string - */ - private String getStackTrace(Exception e) { - // Need the exception in string form to prevent the retention of - // references to classes in the stack trace that could trigger a memory - // leak in a container environment. - Writer w = new StringWriter(); - PrintWriter pw = new PrintWriter(w); - e.printStackTrace(pw); - return w.toString(); - } - - /** - * Returns the greatest integer less than ore equal to the arithmetic mean - * of the entries in cache, acquiring and holding the argument's - * monitor while making a local copy. - * @param cache list containing entries to analyze - * @return truncated arithmetic mean - */ - private long getMeanFromStatsCache(LinkedList cache) { - List times = new ArrayList(MEAN_TIMING_STATS_CACHE_SIZE); - synchronized (cache) { - times.addAll(cache); - } - double result = 0; - int counter = 0; - Iterator iter = times.iterator(); - while (iter.hasNext()) { - Long time = iter.next(); - if (time != null) { - counter++; - result = result * ((counter - 1) / (double) counter) + - time.longValue()/(double) counter; - } - } - return (long) result; - } - - /** - * Initializes pool statistics. - */ - private void initStats() { - for (int i = 0; i < MEAN_TIMING_STATS_CACHE_SIZE; i++) { - activeTimes.add(null); - idleTimes.add(null); - waitTimes.add(null); - } - } - - - // Implement NotificationEmitter interface - - - public final void addNotificationListener(NotificationListener listener, - NotificationFilter filter, Object handback) - throws IllegalArgumentException { - - if (jmxNotificationSupport == null) { - throw new UnsupportedOperationException("JMX is not enabled"); - } - jmxNotificationSupport.addNotificationListener( - listener, filter, handback); - } - - - public final void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException { - - if (jmxNotificationSupport == null) { - throw new UnsupportedOperationException("JMX is not enabled"); - } - jmxNotificationSupport.removeNotificationListener(listener); - } - - - public final MBeanNotificationInfo[] getNotificationInfo() { - - if (jmxNotificationSupport == null) { - throw new UnsupportedOperationException("JMX is not enabled"); - } - return jmxNotificationSupport.getNotificationInfo(); - } - - - public final void removeNotificationListener(NotificationListener listener, - NotificationFilter filter, Object handback) - throws ListenerNotFoundException { - - if (jmxNotificationSupport == null) { - throw new UnsupportedOperationException("JMX is not enabled"); - } - jmxNotificationSupport.removeNotificationListener( - listener, filter, handback); - } - - - // Inner classes - - /** - * The idle object evictor {@link TimerTask}. - * - * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis - */ - class Evictor extends TimerTask { - /** - * Run pool maintenance. Evict objects qualifying for eviction and then - * ensure that the minimum number of idle instances are available. - * Since the Timer that invokes Evictors is shared for all Pools but - * pools may exist in different class loaders, the Evictor ensures that - * any actions taken are under the class loader of the factory - * associated with the pool. - */ - - public void run() { - ClassLoader savedClassLoader = - Thread.currentThread().getContextClassLoader(); - try { - // Set the class loader for the factory - Thread.currentThread().setContextClassLoader( - factoryClassLoader); - - // Evict from the pool - try { - evict(); - } catch(Exception e) { - swallowException(e); - } catch(OutOfMemoryError oome) { - // Log problem but give evictor thread a chance to continue - // in case error is recoverable - oome.printStackTrace(System.err); - } - // Re-create idle instances. - try { - ensureMinIdle(); - } catch (Exception e) { - swallowException(e); - } - } finally { - // Restore the previous CCL - Thread.currentThread().setContextClassLoader(savedClassLoader); - } - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java deleted file mode 100644 index 13169da3..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/BaseObjectPoolConfig.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * Provides the implementation for the common attributes shared by the - * sub-classes. New instances of this class will be created using the defaults - * defined by the public constants. - *

- * This class is not thread-safe. - * - * @version $Revision: $ - * @since 2.0 - */ -public abstract class BaseObjectPoolConfig implements Cloneable { - - /** - * The default value for the {@code lifo} configuration attribute. - * - * @see GenericObjectPool#getLifo() - * @see GenericKeyedObjectPool#getLifo() - */ - public static final boolean DEFAULT_LIFO = true; - - /** - * The default value for the {@code maxWait} configuration attribute. - * - * @see GenericObjectPool#getMaxWaitMillis() - * @see GenericKeyedObjectPool#getMaxWaitMillis() - */ - public static final long DEFAULT_MAX_WAIT_MILLIS = -1L; - - /** - * The default value for the {@code minEvictableIdleTimeMillis} - * configuration attribute. - * - * @see GenericObjectPool#getMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() - */ - public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L; - - /** - * The default value for the {@code softMinEvictableIdleTimeMillis} - * configuration attribute. - * - * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() - */ - public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1; - - /** - * The default value for the {@code numTestsPerEvictionRun} configuration - * attribute. - * - * @see GenericObjectPool#getNumTestsPerEvictionRun() - * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() - */ - public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; - - /** - * The default value for the {@code testOnBorrow} configuration attribute. - * - * @see GenericObjectPool#getTestOnBorrow() - * @see GenericKeyedObjectPool#getTestOnBorrow() - */ - public static final boolean DEFAULT_TEST_ON_BORROW = false; - - /** - * The default value for the {@code testOnReturn} configuration attribute. - * - * @see GenericObjectPool#getTestOnReturn() - * @see GenericKeyedObjectPool#getTestOnReturn() - */ - public static final boolean DEFAULT_TEST_ON_RETURN = false; - - /** - * The default value for the {@code testWhileIdle} configuration attribute. - * - * @see GenericObjectPool#getTestWhileIdle() - * @see GenericKeyedObjectPool#getTestWhileIdle() - */ - public static final boolean DEFAULT_TEST_WHILE_IDLE = false; - - /** - * The default value for the {@code timeBetweenEvictionRunsMillis} - * configuration attribute. - * - * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() - * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() - */ - public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; - - /** - * The default value for the {@code blockWhenExhausted} configuration - * attribute. - * - * @see GenericObjectPool#getBlockWhenExhausted() - * @see GenericKeyedObjectPool#getBlockWhenExhausted() - */ - public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true; - - /** - * The default value for enabling JMX for pools created with a configuration - * instance. - */ - public static final boolean DEFAULT_JMX_ENABLE = true; - - /** - * The default value for the prefix used to name JMX enabled pools created - * with a configuration instance. - * - * @see GenericObjectPool#getJmxName() - * @see GenericKeyedObjectPool#getJmxName() - */ - public static final String DEFAULT_JMX_NAME_PREFIX = "pool"; - - /** - * The default value for the {@code evictionPolicyClassName} configuration - * attribute. - * - * @see GenericObjectPool#getEvictionPolicyClassName() - * @see GenericKeyedObjectPool#getEvictionPolicyClassName() - */ - public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = "org.adbcj.mysql.netty.org.apache.commons.pool2.impl.DefaultEvictionPolicy"; - - private boolean lifo = DEFAULT_LIFO; - - private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS; - - private long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - - private long softMinEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; - - private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; - - private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME; - - private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; - - private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; - - private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE; - - private long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; - - private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED; - - private boolean jmxEnabled = DEFAULT_JMX_ENABLE; - - private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX; - - /** - * Get the value for the {@code lifo} configuration attribute for pools - * created with this configuration instance. - * - * @see GenericObjectPool#getLifo() - * @see GenericKeyedObjectPool#getLifo() - */ - public boolean getLifo() { - return lifo; - } - - /** - * Set the value for the {@code lifo} configuration attribute for pools - * created with this configuration instance. - * - * @see GenericObjectPool#getLifo() - * @see GenericKeyedObjectPool#getLifo() - */ - public void setLifo(boolean lifo) { - this.lifo = lifo; - } - - /** - * Get the value for the {@code maxWait} configuration attribute for pools - * created with this configuration instance. - * - * @see GenericObjectPool#getMaxWaitMillis() - * @see GenericKeyedObjectPool#getMaxWaitMillis() - */ - public long getMaxWaitMillis() { - return maxWaitMillis; - } - - /** - * Set the value for the {@code maxWait} configuration attribute for pools - * created with this configuration instance. - * - * @see GenericObjectPool#getMaxWaitMillis() - * @see GenericKeyedObjectPool#getMaxWaitMillis() - */ - public void setMaxWaitMillis(long maxWaitMillis) { - this.maxWaitMillis = maxWaitMillis; - } - - /** - * Get the value for the {@code minEvictableIdleTimeMillis} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() - */ - public long getMinEvictableIdleTimeMillis() { - return minEvictableIdleTimeMillis; - } - - /** - * Set the value for the {@code minEvictableIdleTimeMillis} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getMinEvictableIdleTimeMillis() - */ - public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { - this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; - } - - /** - * Get the value for the {@code softMinEvictableIdleTimeMillis} - * configuration attribute for pools created with this configuration - * instance. - * - * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() - */ - public long getSoftMinEvictableIdleTimeMillis() { - return softMinEvictableIdleTimeMillis; - } - - /** - * Set the value for the {@code softMinEvictableIdleTimeMillis} - * configuration attribute for pools created with this configuration - * instance. - * - * @see GenericObjectPool#getSoftMinEvictableIdleTimeMillis() - * @see GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis() - */ - public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) { - this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; - } - - /** - * Get the value for the {@code numTestsPerEvictionRun} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getNumTestsPerEvictionRun() - * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() - */ - public int getNumTestsPerEvictionRun() { - return numTestsPerEvictionRun; - } - - /** - * Set the value for the {@code numTestsPerEvictionRun} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getNumTestsPerEvictionRun() - * @see GenericKeyedObjectPool#getNumTestsPerEvictionRun() - */ - public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { - this.numTestsPerEvictionRun = numTestsPerEvictionRun; - } - - /** - * Get the value for the {@code testOnBorrow} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestOnBorrow() - * @see GenericKeyedObjectPool#getTestOnBorrow() - */ - public boolean getTestOnBorrow() { - return testOnBorrow; - } - - /** - * Set the value for the {@code testOnBorrow} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestOnBorrow() - * @see GenericKeyedObjectPool#getTestOnBorrow() - */ - public void setTestOnBorrow(boolean testOnBorrow) { - this.testOnBorrow = testOnBorrow; - } - - /** - * Get the value for the {@code testOnReturn} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestOnReturn() - * @see GenericKeyedObjectPool#getTestOnReturn() - */ - public boolean getTestOnReturn() { - return testOnReturn; - } - - /** - * Set the value for the {@code testOnReturn} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestOnReturn() - * @see GenericKeyedObjectPool#getTestOnReturn() - */ - public void setTestOnReturn(boolean testOnReturn) { - this.testOnReturn = testOnReturn; - } - - /** - * Get the value for the {@code testWhileIdle} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestWhileIdle() - * @see GenericKeyedObjectPool#getTestWhileIdle() - */ - public boolean getTestWhileIdle() { - return testWhileIdle; - } - - /** - * Set the value for the {@code testWhileIdle} configuration attribute for - * pools created with this configuration instance. - * - * @see GenericObjectPool#getTestWhileIdle() - * @see GenericKeyedObjectPool#getTestWhileIdle() - */ - public void setTestWhileIdle(boolean testWhileIdle) { - this.testWhileIdle = testWhileIdle; - } - - /** - * Get the value for the {@code timeBetweenEvictionRunsMillis} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() - * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() - */ - public long getTimeBetweenEvictionRunsMillis() { - return timeBetweenEvictionRunsMillis; - } - - /** - * Set the value for the {@code timeBetweenEvictionRunsMillis} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getTimeBetweenEvictionRunsMillis() - * @see GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis() - */ - public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { - this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; - } - - /** - * Get the value for the {@code evictionPolicyClassName} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getEvictionPolicyClassName() - * @see GenericKeyedObjectPool#getEvictionPolicyClassName() - */ - public String getEvictionPolicyClassName() { - return evictionPolicyClassName; - } - - /** - * Set the value for the {@code evictionPolicyClassName} configuration - * attribute for pools created with this configuration instance. - * - * @see GenericObjectPool#getEvictionPolicyClassName() - * @see GenericKeyedObjectPool#getEvictionPolicyClassName() - */ - public void setEvictionPolicyClassName(String evictionPolicyClassName) { - this.evictionPolicyClassName = evictionPolicyClassName; - } - - /** - * Get the value for the {@code blockWhenExhausted} configuration attribute - * for pools created with this configuration instance. - * - * @see GenericObjectPool#getBlockWhenExhausted() - * @see GenericKeyedObjectPool#getBlockWhenExhausted() - */ - public boolean getBlockWhenExhausted() { - return blockWhenExhausted; - } - - /** - * Set the value for the {@code blockWhenExhausted} configuration attribute - * for pools created with this configuration instance. - * - * @see GenericObjectPool#getBlockWhenExhausted() - * @see GenericKeyedObjectPool#getBlockWhenExhausted() - */ - public void setBlockWhenExhausted(boolean blockWhenExhausted) { - this.blockWhenExhausted = blockWhenExhausted; - } - - /** - * Gets the value of the flag that determines if JMX will be enabled for - * pools created with this configuration instance. - */ - public boolean getJmxEnabled() { - return jmxEnabled; - } - - /** - * Sets the value of the flag that determines if JMX will be enabled for - * pools created with this configuration instance. - */ - public void setJmxEnabled(boolean jmxEnabled) { - this.jmxEnabled = jmxEnabled; - } - - /** - * Gets the value of the JMX name prefix that will be used as part of the - * name assigned to JMX enabled pools created with this configuration - * instance. - */ - public String getJmxNamePrefix() { - return jmxNamePrefix; - } - - /** - * Sets the value of the JMX name prefix that will be used as part of the - * name assigned to JMX enabled pools created with this configuration - * instance. - */ - public void setJmxNamePrefix(String jmxNamePrefix) { - this.jmxNamePrefix = jmxNamePrefix; - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java deleted file mode 100644 index 1b3be595..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/DefaultEvictionPolicy.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * Provides the default implementation of {@link EvictionPolicy} used by the - * pools. Objects will be evicted if the following conditions are met: - *

    - *
  • the object has been idle longer than - * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} / - * {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()}
  • - *
  • there are more than {@link GenericObjectPool#getMinIdle()} / - * {@link GenericKeyedObjectPoolConfig#getMinIdlePerKey()} idle objects in - * the pool and the object has been idle for longer than - * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} / - * {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()} - *
- * This class is immutable and thread-safe. - * - * @param the type of objects in the pool - * - * @version $Revision: $ - * - * @since 2.0 - */ -public class DefaultEvictionPolicy implements EvictionPolicy { - - - public boolean evict(EvictionConfig config, PooledObject underTest, - int idleCount) { - - if ((config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && - config.getMinIdle() < idleCount) || - config.getIdleEvictTime() < underTest.getIdleTimeMillis()) { - return true; - } - return false; - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java deleted file mode 100644 index d238848a..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionConfig.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * This class is used by pool implementations to pass configuration information - * to {@link EvictionPolicy} instances. The {@link EvictionPolicy} may also have - * its own specific configuration attributes. - *

- * This class is immutable and thread-safe. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public class EvictionConfig { - - private final long idleEvictTime; - private final long idleSoftEvictTime; - private final int minIdle; - - - public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, - int minIdle) { - if (poolIdleEvictTime > 0) { - idleEvictTime = poolIdleEvictTime; - } else { - idleEvictTime = Long.MAX_VALUE; - } - if (poolIdleSoftEvictTime > 0) { - idleSoftEvictTime = poolIdleSoftEvictTime; - } else { - idleSoftEvictTime = Long.MAX_VALUE; - } - this.minIdle = minIdle; - } - - public long getIdleEvictTime() { - return idleEvictTime; - } - - public long getIdleSoftEvictTime() { - return idleSoftEvictTime; - } - - public int getMinIdle() { - return minIdle; - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java deleted file mode 100644 index f932a786..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionPolicy.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * To provide a custom eviction policy (i.e. something other than {@link - * DefaultEvictionPolicy} for a pool, users must provide an implementation of - * this interface that provides the required eviction policy. - * - * @param the type of objects in the pool - * - * @version $Revision: $ - * - * @since 2.0 - */ -public interface EvictionPolicy { - - /** - * This method is called to test if an idle object in the pool should be - * evicted or not. - * - * @param config The pool configuration settings related to eviction - * @param underTest The pooled object being tested for eviction - * @param idleCount The current number of idle objects in the pool including - * the object under test - * @return true if the object should be evicted, otherwise - * false - */ - boolean evict(EvictionConfig config, PooledObject underTest, - int idleCount); -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java deleted file mode 100644 index 802a2980..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/EvictionTimer.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Timer; -import java.util.TimerTask; - -/** - * Provides a shared idle object eviction timer for all pools. This class wraps - * the standard {@link Timer} and keeps track of how many pools are using it. - * If no pools are using the timer, it is cancelled. This prevents a thread - * being left running which, in application server environments, can lead to - * memory leads and/or prevent applications from shutting down or reloading - * cleanly. - *

- * This class has package scope to prevent its inclusion in the pool public API. - * The class declaration below should *not* be changed to public. - *

- * This class is intended to be thread-safe. - */ -class EvictionTimer { - - /** Timer instance */ - private static Timer _timer; //@GuardedBy("this") - - /** Static usage count tracker */ - private static int _usageCount; //@GuardedBy("this") - - /** Prevent instantiation */ - private EvictionTimer() { - // Hide the default constuctor - } - - /** - * Add the specified eviction task to the timer. Tasks that are added with a - * call to this method *must* call {@link #cancel(TimerTask)} to cancel the - * task to prevent memory and/or thread leaks in application server - * environments. - * @param task Task to be scheduled - * @param delay Delay in milliseconds before task is executed - * @param period Time in milliseconds between executions - */ - static synchronized void schedule(TimerTask task, long delay, long period) { - if (null == _timer) { - // Force the new Timer thread to be created with a context class - // loader set to the class loader that loaded this library - ClassLoader ccl = AccessController.doPrivileged( - new PrivilegedGetTccl()); - try { - AccessController.doPrivileged(new PrivilegedSetTccl( - EvictionTimer.class.getClassLoader())); - _timer = new Timer("commons-pool-EvictionTimer", true); - } finally { - AccessController.doPrivileged(new PrivilegedSetTccl(ccl)); - } - } - _usageCount++; - _timer.schedule(task, delay, period); - } - - /** - * Remove the specified eviction task from the timer. - * @param task Task to be scheduled - */ - static synchronized void cancel(TimerTask task) { - task.cancel(); - _usageCount--; - if (_usageCount == 0) { - _timer.cancel(); - _timer = null; - } - } - - /** - * {@link PrivilegedAction} used to get the ContextClassLoader - */ - private static class PrivilegedGetTccl implements PrivilegedAction { - - /** - * {@inheritDoc} - */ - - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - } - - /** - * {@link PrivilegedAction} used to set the ContextClassLoader - */ - private static class PrivilegedSetTccl implements PrivilegedAction { - - /** ClassLoader */ - private final ClassLoader cl; - - /** - * Create a new PrivilegedSetTccl using the given classloader - * @param cl ClassLoader to use - */ - PrivilegedSetTccl(ClassLoader cl) { - this.cl = cl; - } - - /** - * {@inheritDoc} - */ - - public Void run() { - Thread.currentThread().setContextClassLoader(cl); - return null; - } - } - -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java deleted file mode 100644 index 3d3fc309..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java +++ /dev/null @@ -1,1380 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.adbcj.mysql.netty.org.apache.commons.pool2.KeyedObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.KeyedPoolableObjectFactory; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; - -/** - * A configurable KeyedObjectPool implementation. - *

- * When coupled with the appropriate {@link KeyedPoolableObjectFactory}, - * GenericKeyedObjectPool provides robust pooling functionality for - * keyed objects. A GenericKeyedObjectPool can be viewed as a map - * of sub-pools, keyed on the (unique) key values provided to the - * {@link #preparePool preparePool}, {@link #addObject addObject} or - * {@link #borrowObject borrowObject} methods. Each time a new key value is - * provided to one of these methods, a sub-new pool is created under the given - * key to be managed by the containing GenericKeyedObjectPool. - *

- * Optionally, one may configure the pool to examine and possibly evict objects - * as they sit idle in the pool and to ensure that a minimum number of idle - * objects is maintained for each key. This is performed by an "idle object - * eviction" thread, which runs asynchronously. Caution should be used when - * configuring this optional feature. Eviction runs contend with client threads - * for access to objects in the pool, so if they run too frequently performance - * issues may result. - *

- * Implementation note: To prevent possible deadlocks, care has been taken to - * ensure that no call to a factory method will occur within a synchronization - * block. See POOL-125 and DBCP-44 for more information. - *

- * This class is intended to be thread-safe. - * - * @see GenericObjectPool - * - * @param The type of keys maintained by this pool. - * @param Type of element pooled in this pool. - * - * @version $Revision: 1431456 $ - * - * @since 2.0 - */ -public class GenericKeyedObjectPool extends BaseGenericObjectPool - implements KeyedObjectPool, GenericKeyedObjectPoolMBean { - - /** - * Create a new GenericKeyedObjectPool using defaults from - * {@link GenericKeyedObjectPoolConfig}. - * @param factory the factory to be used to create entries - */ - public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) { - this(factory, new GenericKeyedObjectPoolConfig()); - } - - /** - * Create a new GenericKeyedObjectPool using a specific - * configuration. - * - * @param factory the factory to be used to create entries - * @param config The configuration to use for this pool instance. The - * configuration is used by value. Subsequent changes to - * the configuration object will not be reflected in the - * pool. - */ - public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, - GenericKeyedObjectPoolConfig config) { - - super(config, ONAME_BASE, config.getJmxNamePrefix()); - - if (factory == null) { - jmxUnregister(); // tidy up - throw new IllegalArgumentException("factory may not be null"); - } - this.factory = factory; - - setConfig(config); - - startEvictor(getMinEvictableIdleTimeMillis()); - } - - /** - * Returns the limit on the number of object instances allocated by the pool - * (checked out or idle), per key. When the limit is reached, the sub-pool - * is said to be exhausted. A negative value indicates no limit. - * - * @return the limit on the number of active instances per key - * - * @see #setMaxTotalPerKey - */ - - public int getMaxTotalPerKey() { - return maxTotalPerKey; - } - - /** - * Sets the limit on the number of object instances allocated by the pool - * (checked out or idle), per key. When the limit is reached, the sub-pool - * is said to be exhausted. A negative value indicates no limit. - * - * @param maxTotalPerKey the limit on the number of active instances per key - * - * @see #getMaxTotalPerKey - */ - public void setMaxTotalPerKey(int maxTotalPerKey) { - this.maxTotalPerKey = maxTotalPerKey; - } - - - /** - * Returns the cap on the number of "idle" instances per key in the pool. - * If maxIdlePerKey is set too low on heavily loaded systems it is possible - * you will see objects being destroyed and almost immediately new objects - * being created. This is a result of the active threads momentarily - * returning objects faster than they are requesting them them, causing the - * number of idle objects to rise above maxIdlePerKey. The best value for - * maxIdlePerKey for heavily loaded system will vary but the default is a - * good starting point. - * - * @return the maximum number of "idle" instances that can be held in a - * given keyed sub-pool or a negative value if there is no limit - * - * @see #setMaxIdlePerKey - */ - - public int getMaxIdlePerKey() { - return maxIdlePerKey; - } - - /** - * Sets the cap on the number of "idle" instances per key in the pool. - * If maxIdlePerKey is set too low on heavily loaded systems it is possible - * you will see objects being destroyed and almost immediately new objects - * being created. This is a result of the active threads momentarily - * returning objects faster than they are requesting them them, causing the - * number of idle objects to rise above maxIdlePerKey. The best value for - * maxIdlePerKey for heavily loaded system will vary but the default is a - * good starting point. - * - * @param maxIdlePerKey the maximum number of "idle" instances that can be - * held in a given keyed sub-pool. Use a negative value - * for no limit - * - * @see #getMaxIdlePerKey - */ - public void setMaxIdlePerKey(int maxIdlePerKey) { - this.maxIdlePerKey = maxIdlePerKey; - } - - /** - * Sets the target for the minimum number of idle objects to maintain in - * each of the keyed sub-pools. This setting only has an effect if it is - * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than - * zero. If this is the case, an attempt is made to ensure that each - * sub-pool has the required minimum number of instances during idle object - * eviction runs. - *

- * If the configured value of minIdlePerKey is greater than the configured - * value for maxIdlePerKey then the value of maxIdlePerKey will be used - * instead. - * - * @param minIdlePerKey The minimum size of the each keyed pool - * - * @see #getMinIdlePerKey - * @see #getMaxIdlePerKey() - * @see #setTimeBetweenEvictionRunsMillis - */ - public void setMinIdlePerKey(int minIdlePerKey) { - this.minIdlePerKey = minIdlePerKey; - } - - /** - * Returns the target for the minimum number of idle objects to maintain in - * each of the keyed sub-pools. This setting only has an effect if it is - * positive and {@link #getTimeBetweenEvictionRunsMillis()} is greater than - * zero. If this is the case, an attempt is made to ensure that each - * sub-pool has the required minimum number of instances during idle object - * eviction runs. - *

- * If the configured value of minIdlePerKey is greater than the configured - * value for maxIdlePerKey then the value of maxIdlePerKey will be used - * instead. - * - * @return minimum size of the each keyed pool - * - * @see #setTimeBetweenEvictionRunsMillis - */ - - public int getMinIdlePerKey() { - int maxIdlePerKey = getMaxIdlePerKey(); - if (this.minIdlePerKey > maxIdlePerKey) { - return maxIdlePerKey; - } else { - return minIdlePerKey; - } - } - - /** - * Sets the configuration. - * - * @param conf the new configuration to use. This is used by value. - * - * @see GenericKeyedObjectPoolConfig - */ - public void setConfig(GenericKeyedObjectPoolConfig conf) { - setLifo(conf.getLifo()); - setMaxIdlePerKey(conf.getMaxIdlePerKey()); - setMaxTotalPerKey(conf.getMaxTotalPerKey()); - setMaxTotal(conf.getMaxTotal()); - setMinIdlePerKey(conf.getMinIdlePerKey()); - setMaxWaitMillis(conf.getMaxWaitMillis()); - setBlockWhenExhausted(conf.getBlockWhenExhausted()); - setTestOnBorrow(conf.getTestOnBorrow()); - setTestOnReturn(conf.getTestOnReturn()); - setTestWhileIdle(conf.getTestWhileIdle()); - setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun()); - setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis()); - setSoftMinEvictableIdleTimeMillis( - conf.getSoftMinEvictableIdleTimeMillis()); - setTimeBetweenEvictionRunsMillis( - conf.getTimeBetweenEvictionRunsMillis()); - setEvictionPolicyClassName(conf.getEvictionPolicyClassName()); - } - - /** - * Obtain a reference to the factory used to create, destroy and validate - * the objects used by this pool. - * - * @return the factory - */ - public KeyedPoolableObjectFactory getFactory() { - return factory; - } - - /** - * Equivalent to {@link #borrowObject(Object, long) borrowObject}(key, - * {@link #getMaxWaitMillis()}). - *

- * {@inheritDoc} - */ - - public T borrowObject(K key) throws Exception { - return borrowObject(key, getMaxWaitMillis()); - } - - /** - * Borrows an object from the sub-pool associated with the given key using - * the specified waiting time which only applies if - * {@link #getBlockWhenExhausted()} is true. - *

- * If there is one or more idle instances available in the sub-pool - * associated with the given key, then an idle instance will be selected - * based on the value of {@link #getLifo()}, activated and returned. If - * activation fails, or {@link #getTestOnBorrow() testOnBorrow} is set to - * true and validation fails, the instance is destroyed and the - * next available instance is examined. This continues until either a valid - * instance is returned or there are no more idle instances available. - *

- * If there are no idle instances available in the sub-pool associated with - * the given key, behavior depends on the {@link #getMaxTotalPerKey() - * maxTotalPerKey}, {@link #getMaxTotal() maxTotal}, and (if applicable) - * {@link #getBlockWhenExhausted()} and the value passed in to the - * borrowMaxWait parameter. If the number of instances checked - * out from the sub-pool under the given key is less than - * maxTotalPerKey and the total number of instances in - * circulation (under all keys) is less than maxTotal, a new - * instance is created, activated and (if applicable) validated and returned - * to the caller. - *

- * If the associated sub-pool is exhausted (no available idle instances and - * no capacity to create new ones), this method will either block - * ({@link #getBlockWhenExhausted()} is true) or throw a - * NoSuchElementException - * ({@link #getBlockWhenExhausted()} is false). - * The length of time that this method will block when - * {@link #getBlockWhenExhausted()} is true is determined by the value - * passed in to the borrowMaxWait parameter. - *

- * When maxTotal is set to a positive value and this method is - * invoked when at the limit with no idle instances available, an attempt is - * made to create room by clearing the oldest 15% of the elements from the - * keyed sub-pools. - *

- * When the pool is exhausted, multiple calling threads may be - * simultaneously blocked waiting for instances to become available. A - * "fairness" algorithm has been implemented to ensure that threads receive - * available instances in request arrival order. - * - * @param key pool key - * @param borrowMaxWaitMillis The time to wait in milliseconds for an object - * to become available - * - * @return object instance from the keyed pool - * - * @throws NoSuchElementException if a keyed object instance cannot be - * returned. - */ - public T borrowObject(K key, long borrowMaxWaitMillis) throws Exception { - assertOpen(); - - PooledObject p = null; - - // Get local copy of current config so it is consistent for entire - // method execution - boolean blockWhenExhausted = getBlockWhenExhausted(); - - boolean create; - long waitTime = 0; - ObjectDeque objectDeque = register(key); - - try { - while (p == null) { - create = false; - if (blockWhenExhausted) { - p = objectDeque.getIdleObjects().pollFirst(); - if (p == null) { - create = true; - p = create(key); - } - if (p == null) { - if (borrowMaxWaitMillis < 0) { - p = objectDeque.getIdleObjects().takeFirst(); - } else { - waitTime = System.currentTimeMillis(); - p = objectDeque.getIdleObjects().pollFirst( - borrowMaxWaitMillis, TimeUnit.MILLISECONDS); - waitTime = System.currentTimeMillis() - waitTime; - } - } - if (p == null) { - throw new NoSuchElementException( - "Timeout waiting for idle object"); - } - if (!p.allocate()) { - p = null; - } - } else { - p = objectDeque.getIdleObjects().pollFirst(); - if (p == null) { - create = true; - p = create(key); - } - if (p == null) { - throw new NoSuchElementException("Pool exhausted"); - } - if (!p.allocate()) { - p = null; - } - } - - if (p != null) { - try { - factory.activateObject(key, p.getObject()); - } catch (Exception e) { - try { - destroy(key, p, true); - } catch (Exception e1) { - // Ignore - activation failure is more important - } - p = null; - if (create) { - NoSuchElementException nsee = new NoSuchElementException( - "Unable to activate object"); - nsee.initCause(e); - throw nsee; - } - } - if (p != null && getTestOnBorrow()) { - boolean validate = false; - Throwable validationThrowable = null; - try { - validate = factory.validateObject(key, p.getObject()); - } catch (Throwable t) { - PoolUtils.checkRethrow(t); - validationThrowable = t; - } - if (!validate) { - try { - destroy(key, p, true); - destroyedByBorrowValidationCount.incrementAndGet(); - } catch (Exception e) { - // Ignore - validation failure is more important - } - p = null; - if (create) { - NoSuchElementException nsee = new NoSuchElementException( - "Unable to validate object"); - nsee.initCause(validationThrowable); - throw nsee; - } - } - } - } - } - } finally { - deregister(key); - } - - updateStatsBorrow(p, waitTime); - - return p.getObject(); - } - - - /** - * Returns an object to a keyed sub-pool. - *

- * If {@link #getMaxIdlePerKey() maxIdle} is set to a positive value and the - * number of idle instances under the given key has reached this value, the - * returning instance is destroyed. - *

- * If {@link #getTestOnReturn() testOnReturn} == true, the returning - * instance is validated before being returned to the idle instance sub-pool - * under the given key. In this case, if validation fails, the instance is - * destroyed. - *

- * Exceptions encountered destroying objects for any reason are swallowed - * but remain accessible via {@link #getSwallowedExceptions()}. - * - * @param key pool key - * @param obj instance to return to the keyed pool - * - * @throws IllegalStateException if an object is returned to the pool that - * was not borrowed from it or if an object is - * returned to the pool multiple times - */ - - public void returnObject(K key, T obj) { - - ObjectDeque objectDeque = poolMap.get(key); - - PooledObject p = objectDeque.getAllObjects().get(obj); - - if (p == null) { - throw new IllegalStateException( - "Returned object not currently part of this pool"); - } - - long activeTime = p.getActiveTimeMillis(); - - if (getTestOnReturn()) { - if (!factory.validateObject(key, obj)) { - try { - destroy(key, p, true); - } catch (Exception e) { - swallowException(e); - } - updateStatsReturn(activeTime); - return; - } - } - - try { - factory.passivateObject(key, obj); - } catch (Exception e1) { - swallowException(e1); - try { - destroy(key, p, true); - } catch (Exception e) { - swallowException(e); - } - updateStatsReturn(activeTime); - return; - } - - if (!p.deallocate()) { - throw new IllegalStateException( - "Object has already been retured to this pool"); - } - - int maxIdle = getMaxIdlePerKey(); - LinkedBlockingDeque> idleObjects = - objectDeque.getIdleObjects(); - - if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { - try { - destroy(key, p, true); - } catch (Exception e) { - swallowException(e); - } - } else { - if (getLifo()) { - idleObjects.addFirst(p); - } else { - idleObjects.addLast(p); - } - } - - if (hasBorrowWaiters()) { - reuseCapacity(); - } - - updateStatsReturn(activeTime); - } - - - /** - * {@inheritDoc} - *

- * Activation of this method decrements the active count associated with - * the given keyed pool and attempts to destroy obj. - * - * @param key pool key - * @param obj instance to invalidate - * - * @throws Exception if an exception occurs destroying the - * object - * @throws IllegalStateException if obj does not belong to the pool - * under the given key - */ - - public void invalidateObject(K key, T obj) throws Exception { - - ObjectDeque objectDeque = poolMap.get(key); - - PooledObject p = objectDeque.getAllObjects().get(obj); - if (p == null) { - throw new IllegalStateException( - "Object not currently part of this pool"); - } - synchronized (p) { - if (p.getState() != PooledObjectState.INVALID) { - destroy(key, p, true); - } - } - } - - - /** - * Clears any objects sitting idle in the pool by removing them from the - * idle instance sub-pools and then invoking the configured - * PoolableObjectFactory's - * {@link KeyedPoolableObjectFactory#destroyObject(Object, Object)} method - * on each idle instance. - *

- * Implementation notes: - *

    - *
  • This method does not destroy or effect in any way instances that are - * checked out when it is invoked.
  • - *
  • Invoking this method does not prevent objects being returned to the - * idle instance pool, even during its execution. Additional instances may - * be returned while removed items are being destroyed.
  • - *
  • Exceptions encountered destroying idle instances are swallowed but - * remain accessible via {@link #getSwallowedExceptions()}.
  • - *
- */ - - public void clear() { - Iterator iter = poolMap.keySet().iterator(); - - while (iter.hasNext()) { - clear(iter.next()); - } - } - - - /** - * Clears the specified sub-pool, removing all pooled instances - * corresponding to the given key. Exceptions encountered - * destroying idle instances are swallowed but remain accessible via - * {@link #getSwallowedExceptions()}. - * - * @param key the key to clear - */ - - public void clear(K key) { - - ObjectDeque objectDeque = register(key); - - try { - LinkedBlockingDeque> idleObjects = - objectDeque.getIdleObjects(); - - PooledObject p = idleObjects.poll(); - - while (p != null) { - try { - destroy(key, p, true); - } catch (Exception e) { - swallowException(e); - } - p = idleObjects.poll(); - } - } finally { - deregister(key); - } - } - - - /** - * {@inheritDoc} - */ - - public int getNumActive() { - return numTotal.get() - getNumIdle(); - } - - /** - * {@inheritDoc} - */ - - public int getNumIdle() { - Iterator> iter = poolMap.values().iterator(); - int result = 0; - - while (iter.hasNext()) { - result += iter.next().getIdleObjects().size(); - } - - return result; - } - - /** - * Returns the number of instances currently borrowed from but not yet - * returned to the sub-pool corresponding to the given key. - * - * @param key the key to query - */ - - public int getNumActive(K key) { - final ObjectDeque objectDeque = poolMap.get(key); - if (objectDeque != null) { - return objectDeque.getAllObjects().size() - - objectDeque.getIdleObjects().size(); - } else { - return 0; - } - } - - /** - * Returns the number of idle instances in the sub-pool corresponding to the - * given key. - * - * @param key the key to query - */ - - public int getNumIdle(K key) { - final ObjectDeque objectDeque = poolMap.get(key); - return objectDeque != null ? objectDeque.getIdleObjects().size() : 0; - } - - - /** - * Closes the keyed object pool. Once the pool is closed, - * {@link #borrowObject(Object)} will fail with IllegalStateException, but - * {@link #returnObject(Object, Object)} and - * {@link #invalidateObject(Object, Object)} will continue to work, with - * returned objects destroyed on return. - *

- * Destroys idle instances in the pool by invoking {@link #clear()}. - */ - - public void close() { - if (isClosed()) { - return; - } - - synchronized (closeLock) { - if (isClosed()) { - return; - } - - // Stop the evictor before the pool is closed since evict() calls - // assertOpen() - startEvictor(-1L); - - closed = true; - // This clear removes any idle objects - clear(); - - jmxUnregister(); - - // Release any threads that were waiting for an object - Iterator> iter = poolMap.values().iterator(); - while (iter.hasNext()) { - iter.next().getIdleObjects().interuptTakeWaiters(); - } - // This clear cleans up the keys now any waiting threads have been - // interrupted - clear(); - } - } - - - /** - * Clears oldest 15% of objects in pool. The method sorts the objects into - * a TreeMap and then iterates the first 15% for removal. - */ - public void clearOldest() { - - // build sorted map of idle objects - final Map, K> map = new TreeMap, K>(); - - for (K k : poolMap.keySet()) { - ObjectDeque queue = poolMap.get(k); - // Protect against possible NPE if key has been removed in another - // thread. Not worth locking the keys while this loop completes. - if (queue != null) { - final LinkedBlockingDeque> idleObjects = - queue.getIdleObjects(); - for (PooledObject p : idleObjects) { - // each item into the map using the PooledObject object as the - // key. It then gets sorted based on the idle time - map.put(p, k); - } - } - } - - // Now iterate created map and kill the first 15% plus one to account - // for zero - int itemsToRemove = ((int) (map.size() * 0.15)) + 1; - Iterator, K>> iter = - map.entrySet().iterator(); - - while (iter.hasNext() && itemsToRemove > 0) { - Map.Entry, K> entry = iter.next(); - // kind of backwards on naming. In the map, each key is the - // PooledObject because it has the ordering with the timestamp - // value. Each value that the key references is the key of the - // list it belongs to. - K key = entry.getValue(); - PooledObject p = entry.getKey(); - // Assume the destruction succeeds - boolean destroyed = true; - try { - destroyed = destroy(key, p, false); - } catch (Exception e) { - swallowException(e); - } - if (destroyed) { - itemsToRemove--; - } - } - } - - /** - * Attempt to create one new instance to serve from the most heavily - * loaded pool that can add a new instance. - * - * This method exists to ensure liveness in the pool when threads are - * parked waiting and capacity to create instances under the requested keys - * subsequently becomes available. - * - * This method is not guaranteed to create an instance and its selection - * of the most loaded pool that can create an instance may not always be - * correct, since it does not lock the pool and instances may be created, - * borrowed, returned or destroyed by other threads while it is executing. - */ - private void reuseCapacity() { - final int maxTotalPerKey = getMaxTotalPerKey(); - - // Find the most loaded pool that could take a new instance - int maxQueueLength = 0; - LinkedBlockingDeque> mostLoaded = null; - K loadedKey = null; - for (K k : poolMap.keySet()) { - final ObjectDeque deque = poolMap.get(k); - if (deque != null) { - final LinkedBlockingDeque> pool = deque.getIdleObjects(); - final int queueLength = pool.getTakeQueueLength(); - if (getNumActive(k) < maxTotalPerKey && queueLength > maxQueueLength) { - maxQueueLength = queueLength; - mostLoaded = pool; - loadedKey = k; - } - } - } - - // Attempt to add an instance to the most loaded pool - if (mostLoaded != null) { - register(loadedKey); - try { - PooledObject p = create(loadedKey); - if (p != null) { - addIdleObject(loadedKey, p); - } - } catch (Exception e) { - swallowException(e); - } finally { - deregister(loadedKey); - } - } - } - - private boolean hasBorrowWaiters() { - for (K k : poolMap.keySet()) { - final ObjectDeque deque = poolMap.get(k); - if (deque != null) { - final LinkedBlockingDeque> pool = - deque.getIdleObjects(); - if(pool.hasTakeWaiters()) { - return true; - } - } - } - return false; - } - - - /** - * {@inheritDoc} - *

- * Successive activations of this method examine objects in keyed sub-pools - * in sequence, cycling through the keys and examining objects in - * oldest-to-youngest order within the keyed sub-pools. - */ - - public void evict() throws Exception { - assertOpen(); - - if (getNumIdle() == 0) { - return; - } - - PooledObject underTest = null; - EvictionPolicy evictionPolicy = getEvictionPolicy(); - - synchronized (evictionLock) { - EvictionConfig evictionConfig = new EvictionConfig( - getMinEvictableIdleTimeMillis(), - getSoftMinEvictableIdleTimeMillis(), - getMinIdlePerKey()); - - boolean testWhileIdle = getTestWhileIdle(); - - LinkedBlockingDeque> idleObjects = null; - - for (int i = 0, m = getNumTests(); i < m; i++) { - if(evictionIterator == null || !evictionIterator.hasNext()) { - if (evictionKeyIterator == null || - !evictionKeyIterator.hasNext()) { - List keyCopy = new ArrayList(); - Lock readLock = keyLock.readLock(); - readLock.lock(); - try { - keyCopy.addAll(poolKeyList); - } finally { - readLock.unlock(); - } - evictionKeyIterator = keyCopy.iterator(); - } - while (evictionKeyIterator.hasNext()) { - evictionKey = evictionKeyIterator.next(); - ObjectDeque objectDeque = poolMap.get(evictionKey); - if (objectDeque == null) { - continue; - } - idleObjects = objectDeque.getIdleObjects(); - - if (getLifo()) { - evictionIterator = idleObjects.descendingIterator(); - } else { - evictionIterator = idleObjects.iterator(); - } - if (evictionIterator.hasNext()) { - break; - } - evictionIterator = null; - } - } - if (evictionIterator == null) { - // Pools exhausted - return; - } - try { - underTest = evictionIterator.next(); - } catch (NoSuchElementException nsee) { - // Object was borrowed in another thread - // Don't count this as an eviction test so reduce i; - i--; - evictionIterator = null; - continue; - } - - if (!underTest.startEvictionTest()) { - // Object was borrowed in another thread - // Don't count this as an eviction test so reduce i; - i--; - continue; - } - - if (evictionPolicy.evict(evictionConfig, underTest, - poolMap.get(evictionKey).getIdleObjects().size())) { - destroy(evictionKey, underTest, true); - destroyedByEvictorCount.incrementAndGet(); - } else { - if (testWhileIdle) { - boolean active = false; - try { - factory.activateObject(evictionKey, - underTest.getObject()); - active = true; - } catch (Exception e) { - destroy(evictionKey, underTest, true); - destroyedByEvictorCount.incrementAndGet(); - } - if (active) { - if (!factory.validateObject(evictionKey, - underTest.getObject())) { - destroy(evictionKey, underTest, true); - destroyedByEvictorCount.incrementAndGet(); - } else { - try { - factory.passivateObject(evictionKey, - underTest.getObject()); - } catch (Exception e) { - destroy(evictionKey, underTest, true); - destroyedByEvictorCount.incrementAndGet(); - } - } - } - } - if (!underTest.endEvictionTest(idleObjects)) { - // TODO - May need to add code here once additional - // states are used - } - } - } - } - } - - private PooledObject create(K key) throws Exception { - int maxTotalPerKey = getMaxTotalPerKey(); // Per key - int maxTotal = getMaxTotal(); // All keys - - // Check against the overall limit - boolean loop = true; - - while (loop) { - int newNumTotal = numTotal.incrementAndGet(); - if (maxTotal > -1 && newNumTotal > maxTotal) { - numTotal.decrementAndGet(); - if (getNumIdle() == 0) { - return null; - } else { - clearOldest(); - } - } else { - loop = false; - } - } - - ObjectDeque objectDeque = poolMap.get(key); - long newCreateCount = objectDeque.getCreateCount().incrementAndGet(); - - // Check against the per key limit - if (maxTotalPerKey > -1 && newCreateCount > maxTotalPerKey || - newCreateCount > Integer.MAX_VALUE) { - numTotal.decrementAndGet(); - objectDeque.getCreateCount().decrementAndGet(); - return null; - } - - - T t = null; - try { - t = factory.makeObject(key); - } catch (Exception e) { - numTotal.decrementAndGet(); - throw e; - } - - PooledObject p = new PooledObject(t); - createdCount.incrementAndGet(); - objectDeque.getAllObjects().put(t, p); - return p; - } - - private boolean destroy(K key, PooledObject toDestroy, boolean always) - throws Exception { - - ObjectDeque objectDeque = register(key); - - try { - boolean isIdle = objectDeque.getIdleObjects().remove(toDestroy); - - if (isIdle || always) { - objectDeque.getAllObjects().remove(toDestroy.getObject()); - toDestroy.invalidate(); - - try { - factory.destroyObject(key, toDestroy.getObject()); - } finally { - objectDeque.getCreateCount().decrementAndGet(); - destroyedCount.incrementAndGet(); - numTotal.decrementAndGet(); - } - return true; - } else { - return false; - } - } finally { - deregister(key); - } - } - - - /* - * register() and deregister() must always be used as a pair. - * - * If this method returns without throwing an exception then it will never - * return null. - */ - private ObjectDeque register(K k) { - Lock lock = keyLock.readLock(); - ObjectDeque objectDeque = null; - try { - lock.lock(); - objectDeque = poolMap.get(k); - if (objectDeque == null) { - // Upgrade to write lock - lock.unlock(); - lock = keyLock.writeLock(); - lock.lock(); - objectDeque = poolMap.get(k); - if (objectDeque == null) { - objectDeque = new ObjectDeque(); - objectDeque.getNumInterested().incrementAndGet(); - // NOTE: Keys must always be added to both poolMap and - // poolKeyList at the same time while protected by - // keyLock.writeLock() - poolMap.put(k, objectDeque); - poolKeyList.add(k); - } else { - objectDeque.getNumInterested().incrementAndGet(); - } - } else { - objectDeque.getNumInterested().incrementAndGet(); - } - } finally { - lock.unlock(); - } - return objectDeque; - } - - /* - * register() and deregister() must always be used as a pair. - */ - private void deregister(K k) { - ObjectDeque objectDeque; - - objectDeque = poolMap.get(k); - long numInterested = objectDeque.getNumInterested().decrementAndGet(); - if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) { - // Potential to remove key - Lock writeLock = keyLock.writeLock(); - writeLock.lock(); - try { - if (objectDeque.getCreateCount().get() == 0 && - objectDeque.getNumInterested().get() == 0) { - // NOTE: Keys must always be removed from both poolMap and - // poolKeyList at the same time while protected by - // keyLock.writeLock() - poolMap.remove(k); - poolKeyList.remove(k); - } - } finally { - writeLock.unlock(); - } - } - } - - - void ensureMinIdle() throws Exception { - int minIdlePerKey = getMinIdlePerKey(); - if (minIdlePerKey < 1) { - return; - } - - for (K k : poolMap.keySet()) { - ensureMinIdle(k); - } - } - - private void ensureMinIdle(K key) throws Exception { - // Calculate current pool objects - ObjectDeque objectDeque = poolMap.get(key); - - // objectDeque == null is OK here. It is handled correctly by both - // methods called below. - - // this method isn't synchronized so the - // calculateDeficit is done at the beginning - // as a loop limit and a second time inside the loop - // to stop when another thread already returned the - // needed objects - int deficit = calculateDeficit(objectDeque); - - for (int i = 0; i < deficit && calculateDeficit(objectDeque) > 0; i++) { - addObject(key); - } - } - - /** - * Create an object using the {@link KeyedPoolableObjectFactory#makeObject - * factory}, passivate it, and then place it in the idle object pool. - * addObject is useful for "pre-loading" a pool with idle - * objects. - * - * @param key the key a new instance should be added to - * - * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} - * fails. - */ - - public void addObject(K key) throws Exception { - assertOpen(); - register(key); - try { - PooledObject p = create(key); - addIdleObject(key, p); - } finally { - deregister(key); - } - } - - private void addIdleObject(K key, PooledObject p) throws Exception { - - if (p != null) { - factory.passivateObject(key, p.getObject()); - LinkedBlockingDeque> idleObjects = - poolMap.get(key).getIdleObjects(); - if (getLifo()) { - idleObjects.addFirst(p); - } else { - idleObjects.addLast(p); - } - } - } - - /** - * Registers a key for pool control and ensures that - * {@link #getMinIdlePerKey()} idle instances are created. - * - * @param key - The key to register for pool control. - */ - public void preparePool(K key) throws Exception { - int minIdlePerKey = getMinIdlePerKey(); - if (minIdlePerKey < 1) { - return; - } - ensureMinIdle(key); - } - - private int getNumTests() { - int totalIdle = getNumIdle(); - int numTests = getNumTestsPerEvictionRun(); - if (numTests >= 0) { - return Math.min(numTests, totalIdle); - } - return(int)(Math.ceil(totalIdle/Math.abs((double)numTests))); - } - - private int calculateDeficit(ObjectDeque objectDeque) { - - if (objectDeque == null) { - return getMinIdlePerKey(); - } - - // Used more than once so keep a local copy so the value is consistent - int maxTotal = getMaxTotal(); - int maxTotalPerKey = getMaxTotalPerKey(); - - int objectDefecit = 0; - - // Calculate no of objects needed to be created, in order to have - // the number of pooled objects < maxTotalPerKey(); - objectDefecit = getMinIdlePerKey() - objectDeque.getIdleObjects().size(); - if (maxTotalPerKey > 0) { - int growLimit = Math.max(0, - maxTotalPerKey - objectDeque.getIdleObjects().size()); - objectDefecit = Math.min(objectDefecit, growLimit); - } - - // Take the maxTotal limit into account - if (maxTotal > 0) { - int growLimit = Math.max(0, maxTotal - getNumActive() - getNumIdle()); - objectDefecit = Math.min(objectDefecit, growLimit); - } - - return objectDefecit; - } - - - //--- JMX support ---------------------------------------------------------- - - - public Map getNumActivePerKey() { - HashMap result = new HashMap(); - - Iterator>> iter = poolMap.entrySet().iterator(); - while (iter.hasNext()) { - Entry> entry = iter.next(); - if (entry != null) { - K key = entry.getKey(); - ObjectDeque objectDequeue = entry.getValue(); - if (key != null && objectDequeue != null) { - result.put(key.toString(), Integer.valueOf( - objectDequeue.getAllObjects().size() - - objectDequeue.getIdleObjects().size())); - } - } - } - return result; - } - - /** - * Return an estimate of the number of threads currently blocked waiting for - * an object from the pool. This is intended for monitoring only, not for - * synchronization control. - */ - - public int getNumWaiters() { - int result = 0; - - if (getBlockWhenExhausted()) { - Iterator> iter = poolMap.values().iterator(); - - while (iter.hasNext()) { - // Assume no overflow - result += iter.next().getIdleObjects().getTakeQueueLength(); - } - } - - return result; - } - - /** - * Return an estimate of the number of threads currently blocked waiting for - * an object from the pool for the given key. This is intended for - * monitoring only, not for synchronization control. - */ - - public int getNumWaiters(K key) { - if (getBlockWhenExhausted()) { - final ObjectDeque objectDeque = poolMap.get(key); - if (objectDeque == null) { - return 0; - } else { - return objectDeque.getIdleObjects().getTakeQueueLength(); - } - } else { - return 0; - } - } - - - public List getKeys() { - List keyCopy = new ArrayList(); - Lock readLock = keyLock.readLock(); - readLock.lock(); - try { - keyCopy.addAll(poolKeyList); - } finally { - readLock.unlock(); - } - return keyCopy; - } - - - //--- inner classes ---------------------------------------------- - - /* - * Maintains information on the per key queue for a given key. - */ - private class ObjectDeque { - - private final LinkedBlockingDeque> idleObjects = - new LinkedBlockingDeque>(); - - /* - * Number of instances created - number destroyed. - * Invariant: createCount <= maxTotalPerKey - */ - private final AtomicInteger createCount = new AtomicInteger(0); - - /* - * The map is keyed on pooled instances. Note: pooled instances - * must be distinguishable by equals for this structure to - * work properly. - */ - private final Map> allObjects = - new ConcurrentHashMap>(); - - /* - * Number of threads with registered interest in this key. - * register(K) increments this counter and deRegister(K) decrements it. - * Invariant: empty keyed pool will not be dropped unless numInterested - * is 0. - */ - private final AtomicLong numInterested = new AtomicLong(0); - - public LinkedBlockingDeque> getIdleObjects() { - return idleObjects; - } - - public AtomicInteger getCreateCount() { - return createCount; - } - - public AtomicLong getNumInterested() { - return numInterested; - } - - public Map> getAllObjects() { - return allObjects; - } - } - - //--- configuration attributes --------------------------------------------- - private volatile int maxIdlePerKey = - GenericKeyedObjectPoolConfig.DEFAULT_MAX_IDLE_PER_KEY; - private volatile int minIdlePerKey = - GenericKeyedObjectPoolConfig.DEFAULT_MIN_IDLE_PER_KEY; - private volatile int maxTotalPerKey = - GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL_PER_KEY; - private final KeyedPoolableObjectFactory factory; - - - //--- internal attributes -------------------------------------------------- - - /* - * My hash of sub-pools (ObjectQueue). The list of keys must be kept - * in step with {@link #poolKeyList} using {@link #keyLock} to ensure any - * changes to the list of current keys is made in a thread-safe manner. - */ - private final Map> poolMap = - new ConcurrentHashMap>(); // @GuardedBy("keyLock") for write access (and some read access) - /* - * List of pool keys - used to control eviction order. The list of keys - * must be kept in step with {@link #poolMap} using {@link #keyLock} - * to ensure any changes to the list of current keys is made in a - * thread-safe manner. - */ - private final List poolKeyList = new ArrayList(); // @GuardedBy("keyLock") - private final ReadWriteLock keyLock = new ReentrantReadWriteLock(true); - /* - * The combined count of the currently active objects for all keys and those - * in the process of being created. Under load, it may exceed - * {@link #maxTotal} but there will never be more than {@link #maxTotal} - * created at any one time. - */ - private final AtomicInteger numTotal = new AtomicInteger(0); - private Iterator evictionKeyIterator = null; // @GuardedBy("evictionLock") - private K evictionKey = null; // @GuardedBy("evictionLock") - - // JMX specific attributes - private static final String ONAME_BASE = - "org.apache.commoms.pool2:type=GenericKeyedObjectPool,name="; -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java deleted file mode 100644 index dbba0f0c..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolConfig.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * A simple "struct" encapsulating the configuration for a - * {@link GenericKeyedObjectPool}. - * - *

- * This class is not thread-safe; it is only intended to be used to provide - * attributes used when creating a pool. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public class GenericKeyedObjectPoolConfig extends BaseObjectPoolConfig { - - public static final int DEFAULT_MAX_TOTAL_PER_KEY = 8; - - /** - * The default maximum number of instances under management - * (idle or checked out) across all keyed pools. - */ - public static final int DEFAULT_MAX_TOTAL = -1; - - /** - * The default minimum number of idle instances that the maintenance - * thread (if enabled) will try to maintain per key. - */ - public static final int DEFAULT_MIN_IDLE_PER_KEY = 0; - - /** - * The default maximum number of idle instances per key. - */ - public static final int DEFAULT_MAX_IDLE_PER_KEY = 8; - - - private int minIdlePerKey = DEFAULT_MIN_IDLE_PER_KEY; - - private int maxIdlePerKey = DEFAULT_MAX_IDLE_PER_KEY; - - private int maxTotalPerKey = DEFAULT_MAX_TOTAL_PER_KEY; - - private int maxTotal = DEFAULT_MAX_TOTAL; - - public GenericKeyedObjectPoolConfig() { - } - - public int getMaxTotal() { - return maxTotal; - } - - public void setMaxTotal(int maxTotal) { - this.maxTotal = maxTotal; - } - - public int getMaxTotalPerKey() { - return maxTotalPerKey; - } - - public void setMaxTotalPerKey(int maxTotalPerKey) { - this.maxTotalPerKey = maxTotalPerKey; - } - - public int getMinIdlePerKey() { - return minIdlePerKey; - } - - public void setMinIdlePerKey(int minIdlePerKey) { - this.minIdlePerKey = minIdlePerKey; - } - - public int getMaxIdlePerKey() { - return maxIdlePerKey; - } - - public void setMaxIdlePerKey(int maxIdlePerKey) { - this.maxIdlePerKey = maxIdlePerKey; - } - - - public GenericKeyedObjectPoolConfig clone() { - try { - return (GenericKeyedObjectPoolConfig) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); // Can't happen - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java deleted file mode 100644 index d27b73d7..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericKeyedObjectPoolMBean.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.util.List; -import java.util.Map; - -/** - * Defines the methods that will be made available via JMX. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public interface GenericKeyedObjectPoolMBean { - // Expose getters for configuration settings - /** - * See {@link GenericKeyedObjectPool#getBlockWhenExhausted()} - */ - boolean getBlockWhenExhausted(); - /** - * See {@link GenericKeyedObjectPool#getLifo()} - */ - boolean getLifo(); - /** - * See {@link GenericKeyedObjectPool#getMaxIdlePerKey()} - */ - int getMaxIdlePerKey(); - /** - * See {@link GenericKeyedObjectPool#getMaxTotal()} - */ - int getMaxTotal(); - /** - * See {@link GenericKeyedObjectPool#getMaxTotalPerKey()} - */ - int getMaxTotalPerKey(); - /** - * See {@link GenericKeyedObjectPool#getMaxWaitMillis()} - */ - long getMaxWaitMillis(); - /** - * See {@link GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()} - */ - long getMinEvictableIdleTimeMillis(); - /** - * See {@link GenericKeyedObjectPool#getMinIdlePerKey()} - */ - int getMinIdlePerKey(); - /** - * See {@link GenericKeyedObjectPool#getNumActive()} - */ - int getNumActive(); - /** - * See {@link GenericKeyedObjectPool#getNumIdle()} - */ - int getNumIdle(); - /** - * See {@link GenericKeyedObjectPool#getNumTestsPerEvictionRun()} - */ - int getNumTestsPerEvictionRun(); - /** - * See {@link GenericKeyedObjectPool#getTestOnBorrow()} - */ - boolean getTestOnBorrow(); - /** - * See {@link GenericKeyedObjectPool#getTestOnReturn()} - */ - boolean getTestOnReturn(); - /** - * See {@link GenericKeyedObjectPool#getTestWhileIdle()} - */ - boolean getTestWhileIdle(); - /** - * See {@link GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()} - */ - long getTimeBetweenEvictionRunsMillis(); - /** - * See {@link GenericKeyedObjectPool#isClosed()} - */ - boolean isClosed(); - // Expose getters for monitoring attributes - /** - * See {@link GenericKeyedObjectPool#getNumActivePerKey()} - */ - Map getNumActivePerKey(); - /** - * See {@link GenericKeyedObjectPool#getBorrowedCount()} - */ - long getBorrowedCount(); - /** - * See {@link GenericKeyedObjectPool#getReturnedCount()} - */ - long getReturnedCount(); - /** - * See {@link GenericKeyedObjectPool#getCreatedCount()} - */ - long getCreatedCount(); - /** - * See {@link GenericKeyedObjectPool#getDestroyedCount()} - */ - long getDestroyedCount(); - /** - * See {@link GenericKeyedObjectPool#getDestroyedByEvictorCount()} - */ - long getDestroyedByEvictorCount(); - /** - * See {@link GenericKeyedObjectPool#getDestroyedByBorrowValidationCount()} - */ - long getDestroyedByBorrowValidationCount(); - /** - * See {@link GenericKeyedObjectPool#getMeanActiveTimeMillis()} - */ - long getMeanActiveTimeMillis(); - /** - * See {@link GenericKeyedObjectPool#getMeanIdleTimeMillis()} - */ - long getMeanIdleTimeMillis(); - /** - * See {@link GenericKeyedObjectPool#getMaxBorrowWaitTimeMillis()} - */ - long getMeanBorrowWaitTimeMillis(); - /** - * See {@link GenericKeyedObjectPool#getMaxBorrowWaitTimeMillis()} - */ - long getMaxBorrowWaitTimeMillis(); - /** - * See {@link GenericKeyedObjectPool#getSwallowedExceptions()} - */ - String[] getSwallowedExceptions(); - /** - * See {@link GenericKeyedObjectPool#getCreationStackTrace()} - */ - String getCreationStackTrace(); - /** - * See {@link GenericKeyedObjectPool#getNumWaiters()} - */ - int getNumWaiters(); - /** - * See {@link GenericKeyedObjectPool#getNumWaiters(Object)} - */ - int getNumWaiters(K key); - /** - * See {@link GenericKeyedObjectPool#getKeys()} - */ - List getKeys(); -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java deleted file mode 100644 index 25c86496..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPool.java +++ /dev/null @@ -1,960 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; - -/** - * A configurable {@link ObjectPool} implementation. - *

- * When coupled with the appropriate {@link PoolableObjectFactory}, - * GenericObjectPool provides robust pooling functionality for - * arbitrary objects.

- *

- * Optionally, one may configure the pool to examine and possibly evict objects - * as they sit idle in the pool and to ensure that a minimum number of idle - * objects are available. This is performed by an "idle object eviction" thread, - * which runs asynchronously. Caution should be used when configuring this - * optional feature. Eviction runs contend with client threads for access to - * objects in the pool, so if they run too frequently performance issues may - * result.

- *

- * The pool can also be configured to detect and remove "abandoned" objects, - * i.e. objects that have been checked out of the pool but neither used nor - * returned before the configured - * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}. - * Abandoned object removal can be configured to happen when - * borrowObject is invoked and the pool is close to starvation, or - * it can be executed by the idle object evictor, or both. If pooled objects - * implement the {@link TrackedUse} interface, their last use will be queried - * using the getLastUsed method on that interface; otherwise - * abandonment is determined by how long an object has been checked out from - * the pool.

- *

- * Implementation note: To prevent possible deadlocks, care has been taken to - * ensure that no call to a factory method will occur within a synchronization - * block. See POOL-125 and DBCP-44 for more information.

- *

- * This class is intended to be thread-safe.

- * - * @see GenericKeyedObjectPool - * - * @param Type of element pooled in this pool. - * - * @version $Revision: 1431458 $ - * - * @since 2.0 - */ -public class GenericObjectPool extends BaseGenericObjectPool - implements ObjectPool, GenericObjectPoolMBean { - - /** - * Create a new GenericObjectPool using defaults from - * {@link GenericObjectPoolConfig}. - */ - public GenericObjectPool(PoolableObjectFactory factory) { - this(factory, new GenericObjectPoolConfig()); - } - - /** - * Create a new GenericObjectPool using a specific - * configuration. - * - * @param config The configuration to use for this pool instance. The - * configuration is used by value. Subsequent changes to - * the configuration object will not be reflected in the - * pool. - */ - public GenericObjectPool(PoolableObjectFactory factory, - GenericObjectPoolConfig config) { - - super(config, ONAME_BASE, config.getJmxNamePrefix()); - - if (factory == null) { - jmxUnregister(); // tidy up - throw new IllegalArgumentException("factory may not be null"); - } - this.factory = factory; - - setConfig(config); - - startEvictor(getTimeBetweenEvictionRunsMillis()); - } - - /** - * Create a new GenericObjectPool that tracks and destroys - * objects that are checked out, but never returned to the pool. - * - * @param config The base pool configuration to use for this pool instance. - * The configuration is used by value. Subsequent changes to - * the configuration object will not be reflected in the - * pool. - * @param abandonedConfig Configuration for abandoned object identification - * and removal. The configuration is used by value. - */ - public GenericObjectPool(PoolableObjectFactory factory, - GenericObjectPoolConfig config, AbandonedConfig abandonedConfig) { - this(factory, config); - setAbandonedConfig(abandonedConfig); - } - - /** - * Returns the cap on the number of "idle" instances in the pool. If maxIdle - * is set too low on heavily loaded systems it is possible you will see - * objects being destroyed and almost immediately new objects being created. - * This is a result of the active threads momentarily returning objects - * faster than they are requesting them them, causing the number of idle - * objects to rise above maxIdle. The best value for maxIdle for heavily - * loaded system will vary but the default is a good starting point. - * - * @return the maximum number of "idle" instances that can be held in the - * pool or a negative value if there is no limit - * - * @see #setMaxIdle - */ - - public int getMaxIdle() { - return maxIdle; - } - - /** - * Returns the cap on the number of "idle" instances in the pool. If maxIdle - * is set too low on heavily loaded systems it is possible you will see - * objects being destroyed and almost immediately new objects being created. - * This is a result of the active threads momentarily returning objects - * faster than they are requesting them them, causing the number of idle - * objects to rise above maxIdle. The best value for maxIdle for heavily - * loaded system will vary but the default is a good starting point. - * - * @param maxIdle - * The cap on the number of "idle" instances in the pool. Use a - * negative value to indicate an unlimited number of idle - * instances - * - * @see #getMaxIdle - */ - public void setMaxIdle(int maxIdle) { - this.maxIdle = maxIdle; - } - - /** - * Sets the target for the minimum number of idle objects to maintain in - * the pool. This setting only has an effect if it is positive and - * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this - * is the case, an attempt is made to ensure that the pool has the required - * minimum number of instances during idle object eviction runs. - *

- * If the configured value of minIdle is greater than the configured value - * for maxIdle then the value of maxIdle will be used instead. - * - * @param minIdle - * The minimum number of objects. - * - * @see #getMinIdle() - * @see #getMaxIdle() - * @see #getTimeBetweenEvictionRunsMillis() - */ - public void setMinIdle(int minIdle) { - this.minIdle = minIdle; - } - - /** - * Returns the target for the minimum number of idle objects to maintain in - * the pool. This setting only has an effect if it is positive and - * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this - * is the case, an attempt is made to ensure that the pool has the required - * minimum number of instances during idle object eviction runs. - *

- * If the configured value of minIdle is greater than the configured value - * for maxIdle then the value of maxIdle will be used instead. - * - * @return The minimum number of objects. - * - * @see #setMinIdle(int) - * @see #setMaxIdle(int) - * @see #setTimeBetweenEvictionRunsMillis(long) - */ - - public int getMinIdle() { - int maxIdle = getMaxIdle(); - if (this.minIdle > maxIdle) { - return maxIdle; - } else { - return minIdle; - } - } - - /** - * Whether or not abandoned object removal is configured for this pool. - * - * @return true if this pool is configured to detect and remove - * abandoned objects - */ - - public boolean isAbandonedConfig() { - return abandonedConfig != null; - } - - /** - * Returns true if abandoned object removal is configured for this pool - * and removal events are to be logged. - * - * See {@link AbandonedConfig#getLogAbandoned()} - */ - - public boolean getLogAbandoned() { - return isAbandonedConfig() && abandonedConfig.getLogAbandoned(); - } - - /** - * Returns true if abandoned object removal is configured to be - * activated by borrowObject. - * - * See {@link AbandonedConfig#getRemoveAbandonedOnBorrow()} - */ - - public boolean getRemoveAbandonedOnBorrow() { - return isAbandonedConfig() && - abandonedConfig.getRemoveAbandonedOnBorrow(); - } - - /** - * Returns true if abandoned object removal is configured to be - * activated when the evictor runs. - * - * See {@link AbandonedConfig#getRemoveAbandonedOnMaintenance()} - */ - - public boolean getRemoveAbandonedOnMaintenance() { - return isAbandonedConfig() && - abandonedConfig.getRemoveAbandonedOnMaintenance(); - } - - /** - * Returns the abandoned object timeout if abandoned object removal - * is configured for this pool; Integer.MAX_VALUE otherwise. - * - * See {@link AbandonedConfig#getRemoveAbandonedTimeout()} - */ - - public int getRemoveAbandonedTimeout() { - return isAbandonedConfig() ? - abandonedConfig.getRemoveAbandonedTimeout() : - Integer.MAX_VALUE; - } - - - /** - * Sets the base pool configuration. - * - * @param conf the new configuration to use. This is used by value. - * - * @see GenericObjectPoolConfig - */ - public void setConfig(GenericObjectPoolConfig conf) { - setLifo(conf.getLifo()); - setMaxIdle(conf.getMaxIdle()); - setMinIdle(conf.getMinIdle()); - setMaxTotal(conf.getMaxTotal()); - setMaxWaitMillis(conf.getMaxWaitMillis()); - setBlockWhenExhausted(conf.getBlockWhenExhausted()); - setTestOnBorrow(conf.getTestOnBorrow()); - setTestOnReturn(conf.getTestOnReturn()); - setTestWhileIdle(conf.getTestWhileIdle()); - setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun()); - setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis()); - setTimeBetweenEvictionRunsMillis( - conf.getTimeBetweenEvictionRunsMillis()); - setSoftMinEvictableIdleTimeMillis( - conf.getSoftMinEvictableIdleTimeMillis()); - setEvictionPolicyClassName(conf.getEvictionPolicyClassName()); - } - - /** - * Sets the abandoned object removal configuration. - * - * @param abandonedConfig the new configuration to use. This is used by value. - * - * @see AbandonedConfig - */ - public void setAbandonedConfig(AbandonedConfig abandonedConfig) throws IllegalArgumentException { - this.abandonedConfig = new AbandonedConfig(); - this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned()); - this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter()); - this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow()); - this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance()); - this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout()); - } - - /** - * Obtain a reference to the factory used to create, destroy and validate - * the objects used by this pool. - * - * @return the factory - */ - public PoolableObjectFactory getFactory() { - return factory; - } - - /** - * Equivalent to {@link #borrowObject(long) - * borrowObject}({@link #getMaxWaitMillis()}). - */ - - public T borrowObject() throws Exception { - return borrowObject(getMaxWaitMillis()); - } - - /** - * Borrow an object from the pool using the specific waiting time which only - * applies if {@link #getBlockWhenExhausted()} is true. - *

- * If there is one or more idle instance available in the pool, then an - * idle instance will be selected based on the value of {@link #getLifo()}, - * activated and returned. If activation fails, or {@link #getTestOnBorrow() - * testOnBorrow} is set to true and validation fails, the - * instance is destroyed and the next available instance is examined. This - * continues until either a valid instance is returned or there are no more - * idle instances available. - *

- * If there are no idle instances available in the pool, behavior depends on - * the {@link #getMaxTotal() maxTotal}, (if applicable) - * {@link #getBlockWhenExhausted()} and the value passed in to the - * borrowMaxWaitMillis parameter. If the number of instances - * checked out from the pool is less than maxActive, a new - * instance is created, activated and (if applicable) validated and returned - * to the caller. - *

- * If the pool is exhausted (no available idle instances and no capacity to - * create new ones), this method will either block (if - * {@link #getBlockWhenExhausted()} is true) or throw a - * NoSuchElementException (if - * {@link #getBlockWhenExhausted()} is false). The length of time that this - * method will block when {@link #getBlockWhenExhausted()} is true is - * determined by the value passed in to the borrowMaxWait - * parameter. - *

- * When the pool is exhausted, multiple calling threads may be - * simultaneously blocked waiting for instances to become available. A - * "fairness" algorithm has been implemented to ensure that threads receive - * available instances in request arrival order. - * - * @param borrowMaxWaitMillis The time to wait in milliseconds for an object - * to become available - * - * @return object instance from the pool - * - * @throws NoSuchElementException if an instance cannot be returned - */ - public T borrowObject(long borrowMaxWaitMillis) throws Exception { - assertOpen(); - - if (isAbandonedConfig() && - abandonedConfig.getRemoveAbandonedOnBorrow() && - (getNumIdle() < 2) && - (getNumActive() > getMaxTotal() - 3) ) { - removeAbandoned(); - } - - PooledObject p = null; - - // Get local copy of current config so it is consistent for entire - // method execution - boolean blockWhenExhausted = getBlockWhenExhausted(); - - boolean create; - long waitTime = 0; - - while (p == null) { - create = false; - if (blockWhenExhausted) { - p = idleObjects.pollFirst(); - if (p == null) { - create = true; - p = create(); - } - if (p == null) { - if (borrowMaxWaitMillis < 0) { - p = idleObjects.takeFirst(); - } else { - waitTime = System.currentTimeMillis(); - p = idleObjects.pollFirst(borrowMaxWaitMillis, - TimeUnit.MILLISECONDS); - waitTime = System.currentTimeMillis() - waitTime; - } - } - if (p == null) { - throw new NoSuchElementException( - "Timeout waiting for idle object"); - } - if (!p.allocate()) { - p = null; - } - } else { - p = idleObjects.pollFirst(); - if (p == null) { - create = true; - p = create(); - } - if (p == null) { - throw new NoSuchElementException("Pool exhausted"); - } - if (!p.allocate()) { - p = null; - } - } - - if (p != null) { - try { - factory.activateObject(p.getObject()); - } catch (Exception e) { - try { - destroy(p); - } catch (Exception e1) { - // Ignore - activation failure is more important - } - p = null; - if (create) { - NoSuchElementException nsee = new NoSuchElementException( - "Unable to activate object"); - nsee.initCause(e); - throw nsee; - } - } - if (p != null && getTestOnBorrow()) { - boolean validate = false; - Throwable validationThrowable = null; - try { - validate = factory.validateObject(p.getObject()); - } catch (Throwable t) { - PoolUtils.checkRethrow(t); - validationThrowable = t; - } - if (!validate) { - try { - destroy(p); - destroyedByBorrowValidationCount.incrementAndGet(); - } catch (Exception e) { - // Ignore - validation failure is more important - } - p = null; - if (create) { - NoSuchElementException nsee = new NoSuchElementException( - "Unable to validate object"); - nsee.initCause(validationThrowable); - throw nsee; - } - } - } - } - } - - updateStatsBorrow(p, waitTime); - - return p.getObject(); - } - - /** - * Returns an object instance to the pool. - *

- * If {@link #getMaxIdle() maxIdle} is set to a positive value and the - * number of idle instances has reached this value, the returning instance - * is destroyed. - *

- * If {@link #getTestOnReturn() testOnReturn} == true, the returning - * instance is validated before being returned to the idle instance pool. In - * this case, if validation fails, the instance is destroyed. - *

- * Exceptions encountered destroying objects for any reason are swallowed - * but remain accessible via {@link #getSwallowedExceptions()}. - * - * @param obj instance to return to the pool - */ - - public void returnObject(T obj) { - PooledObject p = allObjects.get(obj); - - if (!isAbandonedConfig()) { - if (p == null) { - throw new IllegalStateException( - "Returned object not currently part of this pool"); - } - } else { - if (p == null) { - return; // Object was abandoned and removed - } else { - // Make sure object is not being reclaimed - synchronized(p) { - final PooledObjectState state = p.getState(); - if (state == PooledObjectState.ABANDONED || - state == PooledObjectState.INVALID) { - return; - } else { - p.markReturning(); // Keep from being marked abandoned - } - } - } - } - - long activeTime = p.getActiveTimeMillis(); - - if (getTestOnReturn()) { - if (!factory.validateObject(obj)) { - try { - destroy(p); - } catch (Exception e) { - swallowException(e); - } - updateStatsReturn(activeTime); - return; - } - } - - try { - factory.passivateObject(obj); - } catch (Exception e1) { - swallowException(e1); - try { - destroy(p); - } catch (Exception e) { - swallowException(e); - } - updateStatsReturn(activeTime); - return; - } - - if (!p.deallocate()) { - throw new IllegalStateException( - "Object has already been retured to this pool or is invalid"); - } - - int maxIdle = getMaxIdle(); - if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) { - try { - destroy(p); - } catch (Exception e) { - swallowException(e); - } - } else { - if (getLifo()) { - idleObjects.addFirst(p); - } else { - idleObjects.addLast(p); - } - } - updateStatsReturn(activeTime); - } - - /** - * {@inheritDoc} - *

- * Activation of this method decrements the active count and attempts to - * destroy the instance. - * - * @throws Exception if an exception occurs destroying the - * object - * @throws IllegalStateException if obj does not belong to this pool - */ - - public void invalidateObject(T obj) throws Exception { - PooledObject p = allObjects.get(obj); - if (p == null) { - if (isAbandonedConfig()) { - return; - } else { - throw new IllegalStateException( - "Invalidated object not currently part of this pool"); - } - } - synchronized (p) { - if (p.getState() != PooledObjectState.INVALID) { - destroy(p); - } - } - } - - /** - * Clears any objects sitting idle in the pool by removing them from the - * idle instance pool and then invoking the configured - * {@link PoolableObjectFactory#destroyObject(Object)} method on each idle - * instance. - *

- * Implementation notes: - *

    - *
  • This method does not destroy or effect in any way instances that are - * checked out of the pool when it is invoked.
  • - *
  • Invoking this method does not prevent objects being returned to the - * idle instance pool, even during its execution. Additional instances may - * be returned while removed items are being destroyed.
  • - *
  • Exceptions encountered destroying idle instances are swallowed but - * remain accessible via {@link #getSwallowedExceptions()}.
  • - *
- */ - - public void clear() { - PooledObject p = idleObjects.poll(); - - while (p != null) { - try { - destroy(p); - } catch (Exception e) { - swallowException(e); - } - p = idleObjects.poll(); - } - } - - /** - * Returns the total number of instances currently borrowed from this pool - * but not yet returned. - */ - - public int getNumActive() { - return allObjects.size() - idleObjects.size(); - } - - - public int getNumIdle() { - return idleObjects.size(); - } - - /** - * Closes the pool. Once the pool is closed, {@link #borrowObject()} will - * fail with IllegalStateException, but {@link #returnObject(Object)} and - * {@link #invalidateObject(Object)} will continue to work, with returned - * objects destroyed on return. - *

- * Destroys idle instances in the pool by invoking {@link #clear()}. - */ - - public void close() { - if (isClosed()) { - return; - } - - synchronized (closeLock) { - if (isClosed()) { - return; - } - - // Stop the evictor before the pool is closed since evict() calls - // assertOpen() - startEvictor(-1L); - - closed = true; - // This clear removes any idle objects - clear(); - - jmxUnregister(); - - // Release any threads that were waiting for an object - idleObjects.interuptTakeWaiters(); - } - } - - /** - * {@inheritDoc} - *

- * Successive activations of this method examine objects in sequence, - * cycling through objects in oldest-to-youngest order. - */ - - public void evict() throws Exception { - assertOpen(); - - if (idleObjects.size() > 0) { - - PooledObject underTest = null; - EvictionPolicy evictionPolicy = getEvictionPolicy(); - - synchronized (evictionLock) { - EvictionConfig evictionConfig = new EvictionConfig( - getMinEvictableIdleTimeMillis(), - getSoftMinEvictableIdleTimeMillis(), - getMinIdle()); - - boolean testWhileIdle = getTestWhileIdle(); - - for (int i = 0, m = getNumTests(); i < m; i++) { - if (evictionIterator == null || !evictionIterator.hasNext()) { - if (getLifo()) { - evictionIterator = idleObjects.descendingIterator(); - } else { - evictionIterator = idleObjects.iterator(); - } - } - if (!evictionIterator.hasNext()) { - // Pool exhausted, nothing to do here - return; - } - - try { - underTest = evictionIterator.next(); - } catch (NoSuchElementException nsee) { - // Object was borrowed in another thread - // Don't count this as an eviction test so reduce i; - i--; - evictionIterator = null; - continue; - } - - if (!underTest.startEvictionTest()) { - // Object was borrowed in another thread - // Don't count this as an eviction test so reduce i; - i--; - continue; - } - - if (evictionPolicy.evict(evictionConfig, underTest, - idleObjects.size())) { - destroy(underTest); - destroyedByEvictorCount.incrementAndGet(); - } else { - if (testWhileIdle) { - boolean active = false; - try { - factory.activateObject(underTest.getObject()); - active = true; - } catch (Exception e) { - destroy(underTest); - destroyedByEvictorCount.incrementAndGet(); - } - if (active) { - if (!factory.validateObject(underTest.getObject())) { - destroy(underTest); - destroyedByEvictorCount.incrementAndGet(); - } else { - try { - factory.passivateObject(underTest.getObject()); - } catch (Exception e) { - destroy(underTest); - destroyedByEvictorCount.incrementAndGet(); - } - } - } - } - if (!underTest.endEvictionTest(idleObjects)) { - // TODO - May need to add code here once additional - // states are used - } - } - } - } - } - if (isAbandonedConfig() && abandonedConfig.getRemoveAbandonedOnMaintenance()) { - removeAbandoned(); - } - } - - private PooledObject create() throws Exception { - int localMaxTotal = getMaxTotal(); - long newCreateCount = createCount.incrementAndGet(); - if (localMaxTotal > -1 && newCreateCount > localMaxTotal || - newCreateCount > Integer.MAX_VALUE) { - createCount.decrementAndGet(); - return null; - } - - T t = null; - try { - t = factory.makeObject(); - } catch (Exception e) { - createCount.decrementAndGet(); - throw e; - } - - final PooledObject p; - if (isAbandonedConfig() && abandonedConfig.getLogAbandoned()) { - p = new PooledObject(t, abandonedConfig.getLogWriter()); - } else { - p = new PooledObject(t); - } - createdCount.incrementAndGet(); - allObjects.put(t, p); - return p; - } - - private void destroy(PooledObject toDestory) throws Exception { - toDestory.invalidate(); - idleObjects.remove(toDestory); - allObjects.remove(toDestory.getObject()); - try { - factory.destroyObject(toDestory.getObject()); - } finally { - destroyedCount.incrementAndGet(); - createCount.decrementAndGet(); - } - } - - - void ensureMinIdle() throws Exception { - int minIdle = getMinIdle(); - if (minIdle < 1) { - return; - } - - while (idleObjects.size() < minIdle) { - PooledObject p = create(); - if (p == null) { - // Can't create objects, no reason to think another call to - // create will work. Give up. - break; - } - if (getLifo()) { - idleObjects.addFirst(p); - } else { - idleObjects.addLast(p); - } - } - } - - /** - * Create an object, and place it into the pool. addObject() is useful for - * "pre-loading" a pool with idle objects. - */ - - public void addObject() throws Exception { - assertOpen(); - if (factory == null) { - throw new IllegalStateException( - "Cannot add objects without a factory."); - } - PooledObject p = create(); - addIdleObject(p); - } - - private void addIdleObject(PooledObject p) throws Exception { - if (p != null) { - factory.passivateObject(p.getObject()); - if (getLifo()) { - idleObjects.addFirst(p); - } else { - idleObjects.addLast(p); - } - } - } - - private int getNumTests() { - int numTestsPerEvictionRun = getNumTestsPerEvictionRun(); - if (numTestsPerEvictionRun >= 0) { - return Math.min(numTestsPerEvictionRun, idleObjects.size()); - } else { - return (int) (Math.ceil(idleObjects.size() / - Math.abs((double) numTestsPerEvictionRun))); - } - } - - /** - * Recover abandoned objects which have been checked out but - * not used since longer than the removeAbandonedTimeout. - */ - private void removeAbandoned() { - // Generate a list of abandoned objects to remove - final long now = System.currentTimeMillis(); - final long timeout = - now - (abandonedConfig.getRemoveAbandonedTimeout() * 1000L); - ArrayList> remove = new ArrayList>(); - Iterator> it = allObjects.values().iterator(); - while (it.hasNext()) { - PooledObject pooledObject = it.next(); - synchronized (pooledObject) { - if (pooledObject.getState() == PooledObjectState.ALLOCATED && - pooledObject.getLastUsed() <= timeout) { - pooledObject.markAbandoned(); - remove.add(pooledObject); - } - } - } - - // Now remove the abandoned objects - Iterator> itr = remove.iterator(); - while (itr.hasNext()) { - PooledObject pooledObject = itr.next(); - if (abandonedConfig.getLogAbandoned()) { - pooledObject.printStackTrace(); - } - try { - invalidateObject(pooledObject.getObject()); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - //--- JMX support ---------------------------------------------------------- - - /** - * Return an estimate of the number of threads currently blocked waiting for - * an object from the pool. This is intended for monitoring only, not for - * synchronization control. - */ - - public int getNumWaiters() { - if (getBlockWhenExhausted()) { - return idleObjects.getTakeQueueLength(); - } else { - return 0; - } - } - - - // --- configuration attributes -------------------------------------------- - - private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE; - private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE; - private final PoolableObjectFactory factory; - - - // --- internal attributes ------------------------------------------------- - - /* - * All of the objects currently associated with this pool in any state. It - * excludes objects that have been destroyed. The size of - * {@link #allObjects} will always be less than or equal to {@link - * #_maxActive}. Map keys are pooled objects, values are the PooledObject - * wrappers used internally by the pool. - */ - private final Map> allObjects = - new ConcurrentHashMap>(); - /* - * The combined count of the currently created objects and those in the - * process of being created. Under load, it may exceed {@link #_maxActive} - * if multiple threads try and create a new object at the same time but - * {@link #create(boolean)} will ensure that there are never more than - * {@link #_maxActive} objects created at any one time. - */ - private final AtomicLong createCount = new AtomicLong(0); - private final LinkedBlockingDeque> idleObjects = - new LinkedBlockingDeque>(); - - // JMX specific attributes - private static final String ONAME_BASE = - "org.apache.commoms.pool2:type=GenericObjectPool,name="; - - // Additional configuration properties for abandoned object tracking - private volatile AbandonedConfig abandonedConfig = null; -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java deleted file mode 100644 index 58aad26d..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolConfig.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * A simple "struct" encapsulating the configuration for a - * {@link GenericObjectPool}. - * - *

- * This class is not thread-safe; it is only intended to be used to provide - * attributes used when creating a pool. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public class GenericObjectPoolConfig extends BaseObjectPoolConfig { - - /** - * The default maximum number of instances under management - * (idle or checked out). - */ - public static final int DEFAULT_MAX_TOTAL = 8; - - /** - * The default cap on the number of "sleeping" instances in the pool. - */ - public static final int DEFAULT_MAX_IDLE = 8; - - /** - * The default minimum number of "sleeping" instances in the pool before - * before the evictor thread (if active) spawns new objects. - */ - public static final int DEFAULT_MIN_IDLE = 0; - - - private int maxTotal = DEFAULT_MAX_TOTAL; - - private int maxIdle = DEFAULT_MAX_IDLE; - - private int minIdle = DEFAULT_MIN_IDLE; - - public int getMaxTotal() { - return maxTotal; - } - - public void setMaxTotal(int maxTotal) { - this.maxTotal = maxTotal; - } - - - public int getMaxIdle() { - return maxIdle; - } - - public void setMaxIdle(int maxIdle) { - this.maxIdle = maxIdle; - } - - - public int getMinIdle() { - return minIdle; - } - - public void setMinIdle(int minIdle) { - this.minIdle = minIdle; - } - - - public GenericObjectPoolConfig clone() { - try { - return (GenericObjectPoolConfig) super.clone(); - } catch (CloneNotSupportedException e) { - throw new AssertionError(); // Can't happen - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java deleted file mode 100644 index 8607b491..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/GenericObjectPoolMBean.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * Defines the methods that will be made available via JMX. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public interface GenericObjectPoolMBean { - // Getters for basic configuration settings - /** - * See {@link GenericObjectPool#getBlockWhenExhausted()} - */ - boolean getBlockWhenExhausted(); - /** - * See {@link GenericObjectPool#getLifo()} - */ - boolean getLifo(); - /** - * See {@link GenericObjectPool#getMaxIdle()} - */ - int getMaxIdle(); - /** - * See {@link GenericObjectPool#getMaxTotal()} - */ - int getMaxTotal(); - /** - * See {@link GenericObjectPool#getMaxWaitMillis()} - */ - long getMaxWaitMillis(); - /** - * See {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} - */ - long getMinEvictableIdleTimeMillis(); - /** - * See {@link GenericObjectPool#getMinIdle()} - */ - int getMinIdle(); - /** - * See {@link GenericObjectPool#getNumActive()} - */ - int getNumActive(); - /** - * See {@link GenericObjectPool#getNumIdle()} - */ - int getNumIdle(); - /** - * See {@link GenericObjectPool#getNumTestsPerEvictionRun()} - */ - int getNumTestsPerEvictionRun(); - /** - * See {@link GenericObjectPool#getTestOnBorrow()} - */ - boolean getTestOnBorrow(); - /** - * See {@link GenericObjectPool#getTestOnReturn()} - */ - boolean getTestOnReturn(); - /** - * See {@link GenericObjectPool#getTestWhileIdle()} - */ - boolean getTestWhileIdle(); - /** - * See {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} - */ - long getTimeBetweenEvictionRunsMillis(); - /** - * See {@link GenericObjectPool#isClosed()} - */ - boolean isClosed(); - // Getters for monitoring attributes - /** - * See {@link GenericObjectPool#getBorrowedCount()} - */ - long getBorrowedCount(); - /** - * See {@link GenericObjectPool#getReturnedCount()} - */ - long getReturnedCount(); - /** - * See {@link GenericObjectPool#getCreatedCount()} - */ - long getCreatedCount(); - /** - * See {@link GenericObjectPool#getDestroyedCount()} - */ - long getDestroyedCount(); - /** - * See {@link GenericObjectPool#getDestroyedByEvictorCount()} - */ - long getDestroyedByEvictorCount(); - /** - * See {@link GenericObjectPool#getDestroyedByBorrowValidationCount()} - */ - long getDestroyedByBorrowValidationCount(); - /** - * See {@link GenericObjectPool#getMeanActiveTimeMillis()} - */ - long getMeanActiveTimeMillis(); - /** - * See {@link GenericObjectPool#getMeanIdleTimeMillis()} - */ - long getMeanIdleTimeMillis(); - /** - * See {@link GenericObjectPool#getMeanBorrowWaitTimeMillis()} - */ - long getMeanBorrowWaitTimeMillis(); - /** - * See {@link GenericObjectPool#getMaxBorrowWaitTimeMillis()} - */ - long getMaxBorrowWaitTimeMillis(); - /** - * See {@link GenericObjectPool#getSwallowedExceptions()} - */ - String[] getSwallowedExceptions(); - /** - * See {@link GenericObjectPool#getCreationStackTrace()} - */ - String getCreationStackTrace(); - /** - * See {@link GenericObjectPool#getNumWaiters()} - */ - int getNumWaiters(); - - // Getters for abandoned object removal configuration - /** - * See {@link GenericObjectPool#isAbandonedConfig()} - */ - boolean isAbandonedConfig(); - /** - * See {@link GenericObjectPool#getLogAbandoned()} - */ - boolean getLogAbandoned(); - /** - * See {@link GenericObjectPool#getRemoveAbandonedOnBorrow()} - */ - boolean getRemoveAbandonedOnBorrow(); - /** - * See {@link GenericObjectPool#getRemoveAbandonedOnMaintenance()} - */ - boolean getRemoveAbandonedOnMaintenance(); - /** - * See {@link GenericObjectPool#getRemoveAbandonedTimeout()} - */ - int getRemoveAbandonedTimeout(); -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java deleted file mode 100644 index 0b752f1d..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/InterruptibleReentrantLock.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.util.Collection; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * This sub-class was created to expose the waiting threads so that they can be - * interrupted when the pool using the queue that uses this lock is closed. The - * class is intended for internal use only. - *

- * This class is intended to be thread-safe. - */ -class InterruptibleReentrantLock extends ReentrantLock { - - private static final long serialVersionUID = 1L; - - /** - * Interrupt the threads that are waiting on a specific condition - * - * @param condition the condition on which the threads are waiting. - */ - public void interruptWaiters(Condition condition) { - Collection threads = getWaitingThreads(condition); - for (Thread thread : threads) { - thread.interrupt(); - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java deleted file mode 100644 index eb2827df..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/LinkedBlockingDeque.java +++ /dev/null @@ -1,1213 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.util.AbstractQueue; -import java.util.Collection; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * An optionally-bounded {@linkplain java.util.concurrent.BlockingDeque blocking deque} based on - * linked nodes. - * - *

The optional capacity bound constructor argument serves as a - * way to prevent excessive expansion. The capacity, if unspecified, - * is equal to {@link Integer#MAX_VALUE}. Linked nodes are - * dynamically created upon each insertion unless this would bring the - * deque above capacity. - * - *

Most operations run in constant time (ignoring time spent - * blocking). Exceptions include {@link #remove(Object) remove}, - * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link - * #removeLastOccurrence removeLastOccurrence}, {@link #contains - * contains}, {@link #iterator iterator.remove()}, and the bulk - * operations, all of which run in linear time. - * - *

This class and its iterator implement all of the - * optional methods of the {@link Collection} and {@link - * Iterator} interfaces. - * - *

This class is a member of the - * - * Java Collections Framework. - * - * @param the type of elements held in this collection - * - * Note: This was copied from Apache Harmony and modified to suit the needs of - * Commons Pool. - */ -class LinkedBlockingDeque extends AbstractQueue - implements java.io.Serializable { - - /* - * Implemented as a simple doubly-linked list protected by a - * single lock and using conditions to manage blocking. - * - * To implement weakly consistent iterators, it appears we need to - * keep all Nodes GC-reachable from a predecessor dequeued Node. - * That would cause two problems: - * - allow a rogue Iterator to cause unbounded memory retention - * - cause cross-generational linking of old Nodes to new Nodes if - * a Node was tenured while live, which generational GCs have a - * hard time dealing with, causing repeated major collections. - * However, only non-deleted Nodes need to be reachable from - * dequeued Nodes, and reachability does not necessarily have to - * be of the kind understood by the GC. We use the trick of - * linking a Node that has just been dequeued to itself. Such a - * self-link implicitly means to jump to "first" (for next links) - * or "last" (for prev links). - */ - - /* - * We have "diamond" multiple interface/abstract class inheritance - * here, and that introduces ambiguities. Often we want the - * BlockingDeque javadoc combined with the AbstractQueue - * implementation, so a lot of method specs are duplicated here. - */ - - private static final long serialVersionUID = -387911632671998426L; - - /** Doubly-linked list node class */ - private static final class Node { - /** - * The item, or null if this node has been removed. - */ - E item; - - /** - * One of: - * - the real predecessor Node - * - this Node, meaning the predecessor is tail - * - null, meaning there is no predecessor - */ - Node prev; - - /** - * One of: - * - the real successor Node - * - this Node, meaning the successor is head - * - null, meaning there is no successor - */ - Node next; - - Node(E x, Node p, Node n) { - item = x; - prev = p; - next = n; - } - } - - /** - * Pointer to first node. - * Invariant: (first == null && last == null) || - * (first.prev == null && first.item != null) - */ - private transient Node first; - - /** - * Pointer to last node. - * Invariant: (first == null && last == null) || - * (last.next == null && last.item != null) - */ - private transient Node last; - - /** Number of items in the deque */ - private transient int count; - - /** Maximum number of items in the deque */ - private final int capacity; - - /** Main lock guarding all access */ - private final InterruptibleReentrantLock lock = - new InterruptibleReentrantLock(); - - /** Condition for waiting takes */ - private final Condition notEmpty = lock.newCondition(); - - /** Condition for waiting puts */ - private final Condition notFull = lock.newCondition(); - - /** - * Creates a {@code LinkedBlockingDeque} with a capacity of - * {@link Integer#MAX_VALUE}. - */ - public LinkedBlockingDeque() { - this(Integer.MAX_VALUE); - } - - /** - * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity. - * - * @param capacity the capacity of this deque - * @throws IllegalArgumentException if {@code capacity} is less than 1 - */ - public LinkedBlockingDeque(int capacity) { - if (capacity <= 0) throw new IllegalArgumentException(); - this.capacity = capacity; - } - - /** - * Creates a {@code LinkedBlockingDeque} with a capacity of - * {@link Integer#MAX_VALUE}, initially containing the elements of - * the given collection, added in traversal order of the - * collection's iterator. - * - * @param c the collection of elements to initially contain - * @throws NullPointerException if the specified collection or any - * of its elements are null - */ - public LinkedBlockingDeque(Collection c) { - this(Integer.MAX_VALUE); - final ReentrantLock lock = this.lock; - lock.lock(); // Never contended, but necessary for visibility - try { - for (E e : c) { - if (e == null) - throw new NullPointerException(); - if (!linkLast(e)) - throw new IllegalStateException("Deque full"); - } - } finally { - lock.unlock(); - } - } - - - // Basic linking and unlinking operations, called only while holding lock - - /** - * Links e as first element, or returns false if full. - */ - private boolean linkFirst(E e) { - // assert lock.isHeldByCurrentThread(); - if (count >= capacity) - return false; - Node f = first; - Node x = new Node(e, null, f); - first = x; - if (last == null) - last = x; - else - f.prev = x; - ++count; - notEmpty.signal(); - return true; - } - - /** - * Links e as last element, or returns false if full. - */ - private boolean linkLast(E e) { - // assert lock.isHeldByCurrentThread(); - if (count >= capacity) - return false; - Node l = last; - Node x = new Node(e, l, null); - last = x; - if (first == null) - first = x; - else - l.next = x; - ++count; - notEmpty.signal(); - return true; - } - - /** - * Removes and returns first element, or null if empty. - */ - private E unlinkFirst() { - // assert lock.isHeldByCurrentThread(); - Node f = first; - if (f == null) - return null; - Node n = f.next; - E item = f.item; - f.item = null; - f.next = f; // help GC - first = n; - if (n == null) - last = null; - else - n.prev = null; - --count; - notFull.signal(); - return item; - } - - /** - * Removes and returns last element, or null if empty. - */ - private E unlinkLast() { - // assert lock.isHeldByCurrentThread(); - Node l = last; - if (l == null) - return null; - Node p = l.prev; - E item = l.item; - l.item = null; - l.prev = l; // help GC - last = p; - if (p == null) - first = null; - else - p.next = null; - --count; - notFull.signal(); - return item; - } - - /** - * Unlinks x. - */ - private void unlink(Node x) { - // assert lock.isHeldByCurrentThread(); - Node p = x.prev; - Node n = x.next; - if (p == null) { - unlinkFirst(); - } else if (n == null) { - unlinkLast(); - } else { - p.next = n; - n.prev = p; - x.item = null; - // Don't mess with x's links. They may still be in use by - // an iterator. - --count; - notFull.signal(); - } - } - - // BlockingDeque methods - - /** - * @throws IllegalStateException - * @throws NullPointerException - */ - public void addFirst(E e) { - if (!offerFirst(e)) - throw new IllegalStateException("Deque full"); - } - - /** - * @throws IllegalStateException - * @throws NullPointerException - */ - public void addLast(E e) { - if (!offerLast(e)) - throw new IllegalStateException("Deque full"); - } - - /** - * @throws NullPointerException - */ - public boolean offerFirst(E e) { - if (e == null) throw new NullPointerException(); - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return linkFirst(e); - } finally { - lock.unlock(); - } - } - - /** - * @throws NullPointerException - */ - public boolean offerLast(E e) { - if (e == null) throw new NullPointerException(); - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return linkLast(e); - } finally { - lock.unlock(); - } - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public void putFirst(E e) throws InterruptedException { - if (e == null) throw new NullPointerException(); - final ReentrantLock lock = this.lock; - lock.lock(); - try { - while (!linkFirst(e)) - notFull.await(); - } finally { - lock.unlock(); - } - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public void putLast(E e) throws InterruptedException { - if (e == null) throw new NullPointerException(); - final ReentrantLock lock = this.lock; - lock.lock(); - try { - while (!linkLast(e)) - notFull.await(); - } finally { - lock.unlock(); - } - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public boolean offerFirst(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - while (!linkFirst(e)) { - if (nanos <= 0) - return false; - nanos = notFull.awaitNanos(nanos); - } - return true; - } finally { - lock.unlock(); - } - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public boolean offerLast(E e, long timeout, TimeUnit unit) - throws InterruptedException { - if (e == null) throw new NullPointerException(); - long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - while (!linkLast(e)) { - if (nanos <= 0) - return false; - nanos = notFull.awaitNanos(nanos); - } - return true; - } finally { - lock.unlock(); - } - } - - /** - * @throws NoSuchElementException - */ - public E removeFirst() { - E x = pollFirst(); - if (x == null) throw new NoSuchElementException(); - return x; - } - - /** - * @throws NoSuchElementException - */ - public E removeLast() { - E x = pollLast(); - if (x == null) throw new NoSuchElementException(); - return x; - } - - public E pollFirst() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return unlinkFirst(); - } finally { - lock.unlock(); - } - } - - public E pollLast() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return unlinkLast(); - } finally { - lock.unlock(); - } - } - - public E takeFirst() throws InterruptedException { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - E x; - while ( (x = unlinkFirst()) == null) - notEmpty.await(); - return x; - } finally { - lock.unlock(); - } - } - - public E takeLast() throws InterruptedException { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - E x; - while ( (x = unlinkLast()) == null) - notEmpty.await(); - return x; - } finally { - lock.unlock(); - } - } - - public E pollFirst(long timeout, TimeUnit unit) - throws InterruptedException { - long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - E x; - while ( (x = unlinkFirst()) == null) { - if (nanos <= 0) - return null; - nanos = notEmpty.awaitNanos(nanos); - } - return x; - } finally { - lock.unlock(); - } - } - - public E pollLast(long timeout, TimeUnit unit) - throws InterruptedException { - long nanos = unit.toNanos(timeout); - final ReentrantLock lock = this.lock; - lock.lockInterruptibly(); - try { - E x; - while ( (x = unlinkLast()) == null) { - if (nanos <= 0) - return null; - nanos = notEmpty.awaitNanos(nanos); - } - return x; - } finally { - lock.unlock(); - } - } - - /** - * @throws NoSuchElementException - */ - public E getFirst() { - E x = peekFirst(); - if (x == null) throw new NoSuchElementException(); - return x; - } - - /** - * @throws NoSuchElementException - */ - public E getLast() { - E x = peekLast(); - if (x == null) throw new NoSuchElementException(); - return x; - } - - public E peekFirst() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return (first == null) ? null : first.item; - } finally { - lock.unlock(); - } - } - - public E peekLast() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return (last == null) ? null : last.item; - } finally { - lock.unlock(); - } - } - - public boolean removeFirstOccurrence(Object o) { - if (o == null) return false; - final ReentrantLock lock = this.lock; - lock.lock(); - try { - for (Node p = first; p != null; p = p.next) { - if (o.equals(p.item)) { - unlink(p); - return true; - } - } - return false; - } finally { - lock.unlock(); - } - } - - public boolean removeLastOccurrence(Object o) { - if (o == null) return false; - final ReentrantLock lock = this.lock; - lock.lock(); - try { - for (Node p = last; p != null; p = p.prev) { - if (o.equals(p.item)) { - unlink(p); - return true; - } - } - return false; - } finally { - lock.unlock(); - } - } - - // BlockingQueue methods - - /** - * Inserts the specified element at the end of this deque unless it would - * violate capacity restrictions. When using a capacity-restricted deque, - * it is generally preferable to use method {@link #offer(Object) offer}. - * - *

This method is equivalent to {@link #addLast}. - * - * @throws IllegalStateException if the element cannot be added at this - * time due to capacity restrictions - * @throws NullPointerException if the specified element is null - */ - - public boolean add(E e) { - addLast(e); - return true; - } - - /** - * @throws NullPointerException if the specified element is null - */ - - public boolean offer(E e) { - return offerLast(e); - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public void put(E e) throws InterruptedException { - putLast(e); - } - - /** - * @throws NullPointerException - * @throws InterruptedException - */ - public boolean offer(E e, long timeout, TimeUnit unit) - throws InterruptedException { - return offerLast(e, timeout, unit); - } - - /** - * Retrieves and removes the head of the queue represented by this deque. - * This method differs from {@link #poll poll} only in that it throws an - * exception if this deque is empty. - * - *

This method is equivalent to {@link #removeFirst() removeFirst}. - * - * @return the head of the queue represented by this deque - * @throws NoSuchElementException if this deque is empty - */ - - public E remove() { - return removeFirst(); - } - - - public E poll() { - return pollFirst(); - } - - public E take() throws InterruptedException { - return takeFirst(); - } - - public E poll(long timeout, TimeUnit unit) throws InterruptedException { - return pollFirst(timeout, unit); - } - - /** - * Retrieves, but does not remove, the head of the queue represented by - * this deque. This method differs from {@link #peek peek} only in that - * it throws an exception if this deque is empty. - * - *

This method is equivalent to {@link #getFirst() getFirst}. - * - * @return the head of the queue represented by this deque - * @throws NoSuchElementException if this deque is empty - */ - - public E element() { - return getFirst(); - } - - - public E peek() { - return peekFirst(); - } - - /** - * Returns the number of additional elements that this deque can ideally - * (in the absence of memory or resource constraints) accept without - * blocking. This is always equal to the initial capacity of this deque - * less the current {@code size} of this deque. - * - *

Note that you cannot always tell if an attempt to insert - * an element will succeed by inspecting {@code remainingCapacity} - * because it may be the case that another thread is about to - * insert or remove an element. - */ - public int remainingCapacity() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return capacity - count; - } finally { - lock.unlock(); - } - } - - /** - * @throws UnsupportedOperationException - * @throws ClassCastException - * @throws NullPointerException - * @throws IllegalArgumentException - */ - public int drainTo(Collection c) { - return drainTo(c, Integer.MAX_VALUE); - } - - /** - * @throws UnsupportedOperationException - * @throws ClassCastException - * @throws NullPointerException - * @throws IllegalArgumentException - */ - public int drainTo(Collection c, int maxElements) { - if (c == null) - throw new NullPointerException(); - if (c == this) - throw new IllegalArgumentException(); - final ReentrantLock lock = this.lock; - lock.lock(); - try { - int n = Math.min(maxElements, count); - for (int i = 0; i < n; i++) { - c.add(first.item); // In this order, in case add() throws. - unlinkFirst(); - } - return n; - } finally { - lock.unlock(); - } - } - - // Stack methods - - /** - * @throws IllegalStateException - * @throws NullPointerException - */ - public void push(E e) { - addFirst(e); - } - - /** - * @throws NoSuchElementException - */ - public E pop() { - return removeFirst(); - } - - // Collection methods - - /** - * Removes the first occurrence of the specified element from this deque. - * If the deque does not contain the element, it is unchanged. - * More formally, removes the first element {@code e} such that - * {@code o.equals(e)} (if such an element exists). - * Returns {@code true} if this deque contained the specified element - * (or equivalently, if this deque changed as a result of the call). - * - *

This method is equivalent to - * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}. - * - * @param o element to be removed from this deque, if present - * @return {@code true} if this deque changed as a result of the call - */ - - public boolean remove(Object o) { - return removeFirstOccurrence(o); - } - - /** - * Returns the number of elements in this deque. - * - * @return the number of elements in this deque - */ - - public int size() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return count; - } finally { - lock.unlock(); - } - } - - /** - * Returns {@code true} if this deque contains the specified element. - * More formally, returns {@code true} if and only if this deque contains - * at least one element {@code e} such that {@code o.equals(e)}. - * - * @param o object to be checked for containment in this deque - * @return {@code true} if this deque contains the specified element - */ - - public boolean contains(Object o) { - if (o == null) return false; - final ReentrantLock lock = this.lock; - lock.lock(); - try { - for (Node p = first; p != null; p = p.next) - if (o.equals(p.item)) - return true; - return false; - } finally { - lock.unlock(); - } - } - - /* - * TODO: Add support for more efficient bulk operations. - * - * We don't want to acquire the lock for every iteration, but we - * also want other threads a chance to interact with the - * collection, especially when count is close to capacity. - */ - -// /** -// * Adds all of the elements in the specified collection to this -// * queue. Attempts to addAll of a queue to itself result in -// * {@code IllegalArgumentException}. Further, the behavior of -// * this operation is undefined if the specified collection is -// * modified while the operation is in progress. -// * -// * @param c collection containing elements to be added to this queue -// * @return {@code true} if this queue changed as a result of the call -// * @throws ClassCastException -// * @throws NullPointerException -// * @throws IllegalArgumentException -// * @throws IllegalStateException -// * @see #add(Object) -// */ -// public boolean addAll(Collection c) { -// if (c == null) -// throw new NullPointerException(); -// if (c == this) -// throw new IllegalArgumentException(); -// final ReentrantLock lock = this.lock; -// lock.lock(); -// try { -// boolean modified = false; -// for (E e : c) -// if (linkLast(e)) -// modified = true; -// return modified; -// } finally { -// lock.unlock(); -// } -// } - - /** - * Returns an array containing all of the elements in this deque, in - * proper sequence (from first to last element). - * - *

The returned array will be "safe" in that no references to it are - * maintained by this deque. (In other words, this method must allocate - * a new array). The caller is thus free to modify the returned array. - * - *

This method acts as bridge between array-based and collection-based - * APIs. - * - * @return an array containing all of the elements in this deque - */ - - public Object[] toArray() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - Object[] a = new Object[count]; - int k = 0; - for (Node p = first; p != null; p = p.next) - a[k++] = p.item; - return a; - } finally { - lock.unlock(); - } - } - - /** - * Returns an array containing all of the elements in this deque, in - * proper sequence; the runtime type of the returned array is that of - * the specified array. If the deque fits in the specified array, it - * is returned therein. Otherwise, a new array is allocated with the - * runtime type of the specified array and the size of this deque. - * - *

If this deque fits in the specified array with room to spare - * (i.e., the array has more elements than this deque), the element in - * the array immediately following the end of the deque is set to - * {@code null}. - * - *

Like the {@link #toArray()} method, this method acts as bridge between - * array-based and collection-based APIs. Further, this method allows - * precise control over the runtime type of the output array, and may, - * under certain circumstances, be used to save allocation costs. - * - *

Suppose {@code x} is a deque known to contain only strings. - * The following code can be used to dump the deque into a newly - * allocated array of {@code String}: - * - *

-     *     String[] y = x.toArray(new String[0]);
- * - * Note that {@code toArray(new Object[0])} is identical in function to - * {@code toArray()}. - * - * @param a the array into which the elements of the deque are to - * be stored, if it is big enough; otherwise, a new array of the - * same runtime type is allocated for this purpose - * @return an array containing all of the elements in this deque - * @throws ArrayStoreException if the runtime type of the specified array - * is not a supertype of the runtime type of every element in - * this deque - * @throws NullPointerException if the specified array is null - */ - - @SuppressWarnings("unchecked") - public T[] toArray(T[] a) { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - if (a.length < count) - a = (T[])java.lang.reflect.Array.newInstance - (a.getClass().getComponentType(), count); - - int k = 0; - for (Node p = first; p != null; p = p.next) - a[k++] = (T)p.item; - if (a.length > k) - a[k] = null; - return a; - } finally { - lock.unlock(); - } - } - - - public String toString() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - return super.toString(); - } finally { - lock.unlock(); - } - } - - /** - * Atomically removes all of the elements from this deque. - * The deque will be empty after this call returns. - */ - - public void clear() { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - for (Node f = first; f != null; ) { - f.item = null; - Node n = f.next; - f.prev = null; - f.next = null; - f = n; - } - first = last = null; - count = 0; - notFull.signalAll(); - } finally { - lock.unlock(); - } - } - - /** - * Returns an iterator over the elements in this deque in proper sequence. - * The elements will be returned in order from first (head) to last (tail). - * The returned {@code Iterator} is a "weakly consistent" iterator that - * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. - * - * @return an iterator over the elements in this deque in proper sequence - */ - - public Iterator iterator() { - return new Itr(); - } - - /** - * Returns an iterator over the elements in this deque in reverse - * sequential order. The elements will be returned in order from - * last (tail) to first (head). - * The returned {@code Iterator} is a "weakly consistent" iterator that - * will never throw {@link java.util.ConcurrentModificationException - * ConcurrentModificationException}, - * and guarantees to traverse elements as they existed upon - * construction of the iterator, and may (but is not guaranteed to) - * reflect any modifications subsequent to construction. - */ - public Iterator descendingIterator() { - return new DescendingItr(); - } - - /** - * Base class for Iterators for LinkedBlockingDeque - */ - private abstract class AbstractItr implements Iterator { - /** - * The next node to return in next() - */ - Node next; - - /** - * nextItem holds on to item fields because once we claim that - * an element exists in hasNext(), we must return item read - * under lock (in advance()) even if it was in the process of - * being removed when hasNext() was called. - */ - E nextItem; - - /** - * Node returned by most recent call to next. Needed by remove. - * Reset to null if this element is deleted by a call to remove. - */ - private Node lastRet; - - abstract Node firstNode(); - abstract Node nextNode(Node n); - - AbstractItr() { - // set to initial position - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - lock.lock(); - try { - next = firstNode(); - nextItem = (next == null) ? null : next.item; - } finally { - lock.unlock(); - } - } - - /** - * Advances next. - */ - void advance() { - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - lock.lock(); - try { - // assert next != null; - Node s = nextNode(next); - if (s == next) { - next = firstNode(); - } else { - // Skip over removed nodes. - // May be necessary if multiple interior Nodes are removed. - while (s != null && s.item == null) - s = nextNode(s); - next = s; - } - nextItem = (next == null) ? null : next.item; - } finally { - lock.unlock(); - } - } - - - public boolean hasNext() { - return next != null; - } - - - public E next() { - if (next == null) - throw new NoSuchElementException(); - lastRet = next; - E x = nextItem; - advance(); - return x; - } - - - public void remove() { - Node n = lastRet; - if (n == null) - throw new IllegalStateException(); - lastRet = null; - final ReentrantLock lock = LinkedBlockingDeque.this.lock; - lock.lock(); - try { - if (n.item != null) - unlink(n); - } finally { - lock.unlock(); - } - } - } - - /** Forward iterator */ - private class Itr extends AbstractItr { - - Node firstNode() { return first; } - - Node nextNode(Node n) { return n.next; } - } - - /** Descending iterator */ - private class DescendingItr extends AbstractItr { - - Node firstNode() { return last; } - - Node nextNode(Node n) { return n.prev; } - } - - /** - * Save the state of this deque to a stream (that is, serialize it). - * - * @serialData The capacity (int), followed by elements (each an - * {@code Object}) in the proper order, followed by a null - * @param s the stream - */ - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { - final ReentrantLock lock = this.lock; - lock.lock(); - try { - // Write out capacity and any hidden stuff - s.defaultWriteObject(); - // Write out all elements in the proper order. - for (Node p = first; p != null; p = p.next) - s.writeObject(p.item); - // Use trailing null as sentinel - s.writeObject(null); - } finally { - lock.unlock(); - } - } - - /** - * Reconstitute this deque from a stream (that is, - * deserialize it). - * @param s the stream - */ - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); - count = 0; - first = null; - last = null; - // Read in all elements and place in queue - for (;;) { - E item = (E)s.readObject(); - if (item == null) - break; - add(item); - } - } - - // Monitoring methods - - /** - * Returns true if there are threads waiting to take instances from this deque. - * See disclaimer on accuracy in {@link ReentrantLock#hasWaiters(Condition)}. - * - * @return true if there is at least one thread waiting on this deque's notEmpty condition. - */ - public boolean hasTakeWaiters() { - lock.lock(); - try { - return lock.hasWaiters(notEmpty); - } finally { - lock.unlock(); - } - } - - /** - * Returns the length of the queue of threads waiting to take instances from this deque. - * See disclaimer on accuracy in {@link ReentrantLock#getWaitQueueLength(Condition)}. - * - * @return number of threads waiting on this deque's notEmpty condition. - */ - public int getTakeQueueLength() { - lock.lock(); - try { - return lock.getWaitQueueLength(notEmpty); - } finally { - lock.unlock(); - } - } - - /** - * Interrupts the threads currently waiting to take an object from the pool. - * See disclaimer on accuracy in - * {@link ReentrantLock#getWaitingThreads(Condition)}. - */ - public void interuptTakeWaiters() { - lock.lock(); - try { - lock.interruptWaiters(notEmpty); - } finally { - lock.unlock(); - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java deleted file mode 100644 index 51bce9fb..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObject.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * This wrapper is used to track the additional information, such as state, for - * the pooled objects. - *

- * This class is intended to be thread-safe. - * - * @param the type of object in the pool - * - * @version $Revision: $ - * - * @since 2.0 - */ -public class PooledObject implements Comparable> { - - private final T object; - private PooledObjectState state = PooledObjectState.IDLE; // @GuardedBy("this") to ensure transitions are valid - private final long createTime = System.currentTimeMillis(); - private volatile long lastBorrowTime = createTime; - private volatile long lastReturnTime = createTime; - private final Exception createdBy; - private final PrintWriter logWriter; - - public PooledObject(T object) { - this.object = object; - createdBy = null; - logWriter = null; - } - - public PooledObject(T object, PrintWriter logWriter) { - this.object = object; - this.logWriter = logWriter; - createdBy = new AbandonedObjectException(); - } - - /** - * Obtain the underlying object that is wrapped by this instance of - * {@link PooledObject}. - */ - public T getObject() { - return object; - } - - /** - * Obtain the time (using the same basis as - * {@link System#currentTimeMillis()}) that this object was created. - */ - public long getCreateTime() { - return createTime; - } - - /** - * Obtain the time in milliseconds that this object last spent in the the - * active state (it may still be active in which case subsequent calls will - * return an increased value). - */ - public long getActiveTimeMillis() { - // Take copies to avoid threading issues - long rTime = lastReturnTime; - long bTime = lastBorrowTime; - - if (rTime > bTime) { - return rTime - bTime; - } else { - return System.currentTimeMillis() - bTime; - } - } - - /** - * Obtain the time in milliseconds that this object last spend in the the - * idle state (it may still be idle in which case subsequent calls will - * return an increased value). - */ - public long getIdleTimeMillis() { - return System.currentTimeMillis() - lastReturnTime; - } - - public long getLastBorrowTime() { - return lastBorrowTime; - } - - public long getLastReturnTime() { - return lastReturnTime; - } - - /** - * Return an estimate of the last time this object was used. If the class - * of the pooled object implements {@link TrackedUse}, what is returned is - * the maximum of {@link TrackedUse#getLastUsed()} and - * {@link #getLastBorrowTime()}; otherwise this method gives the same - * value as {@link #getLastBorrowTime()}. - * - * @return the last time this object was used - */ - public long getLastUsed() { - if (object instanceof TrackedUse) { - return Math.max(((TrackedUse) object).getLastUsed(), lastBorrowTime); - } else { - return lastBorrowTime; - } - } - - /** - * Orders instances based on idle time - i.e. the length of time since the - * instance was returned to the pool. Used by the GKOP idle object evictor. - *

- * Note: This class has a natural ordering that is inconsistent with - * equals if distinct objects have the same identity hash code. - */ - - public int compareTo(PooledObject other) { - final long lastActiveDiff = - this.getLastReturnTime() - other.getLastReturnTime(); - if (lastActiveDiff == 0) { - // Make sure the natural ordering is broadly consistent with equals - // although this will break down if distinct objects have the same - // identity hash code. - // see java.lang.Comparable Javadocs - return System.identityHashCode(this) - System.identityHashCode(other); - } - // handle int overflow - return (int)Math.min(Math.max(lastActiveDiff, Integer.MIN_VALUE), Integer.MAX_VALUE); - } - - - - public boolean equals(Object obj) { - // Overridden purely to stop FindBugs complaining because compareTo() - // has been defined. - return super.equals(obj); - } - - - public int hashCode() { - // Overridden because equals() had to be overridden (see above) - return super.hashCode(); - } - - /** - * Provides a String form of the wrapper for debug purposes. The format is - * not fixed and may change at any time. - */ - - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("Object: "); - result.append(object.toString()); - result.append(", State: "); - synchronized (this) { - result.append(state.toString()); - } - return result.toString(); - // TODO add other attributes - } - - public synchronized boolean startEvictionTest() { - if (state == PooledObjectState.IDLE) { - state = PooledObjectState.MAINTAIN_EVICTION; - return true; - } - - return false; - } - - public synchronized boolean endEvictionTest( - LinkedBlockingDeque> idleQueue) { - if (state == PooledObjectState.MAINTAIN_EVICTION) { - state = PooledObjectState.IDLE; - return true; - } else if (state == PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD) { - state = PooledObjectState.IDLE; - if (!idleQueue.offerFirst(this)) { - // TODO - Should never happen - } - } - - return false; - } - - /** - * Allocates the object. - * - * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} - */ - public synchronized boolean allocate() { - if (state == PooledObjectState.IDLE) { - state = PooledObjectState.ALLOCATED; - lastBorrowTime = System.currentTimeMillis(); - return true; - } else if (state == PooledObjectState.MAINTAIN_EVICTION) { - // TODO Allocate anyway and ignore eviction test - state = PooledObjectState.MAINTAIN_EVICTION_RETURN_TO_HEAD; - return false; - } - // TODO if validating and testOnBorrow == true then pre-allocate for - // performance - return false; - } - - /** - * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE} - * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}. - * - * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED} - */ - public synchronized boolean deallocate() { - if (state == PooledObjectState.ALLOCATED || - state == PooledObjectState.RETURNING) { - state = PooledObjectState.IDLE; - lastReturnTime = System.currentTimeMillis(); - return true; - } - - return false; - } - - /** - * Sets the state to {@link PooledObjectState#INVALID INVALID} - */ - public synchronized void invalidate() { - state = PooledObjectState.INVALID; - } - - /** - * Prints the stack trace of the code that created this pooled object to - * the configured log writer. Does nothing of no PrintWriter was supplied - * to the constructor. - */ - public void printStackTrace() { - if (createdBy != null && logWriter != null) { - createdBy.printStackTrace(logWriter); - } - } - - /** - * Returns the state of this object. - * @return state - */ - public synchronized PooledObjectState getState() { - return state; - } - - /** - * Marks the pooled object as abandoned. - */ - public synchronized void markAbandoned() { - state = PooledObjectState.ABANDONED; - } - - /** - * Marks the object as returning to the pool. - */ - public synchronized void markReturning() { - state = PooledObjectState.RETURNING; - } - - static class AbandonedObjectException extends Exception { - - private static final long serialVersionUID = 7398692158058772916L; - - /** Date format */ - //@GuardedBy("this") - private static final SimpleDateFormat format = new SimpleDateFormat - ("'Pooled object created' yyyy-MM-dd HH:mm:ss " + - "'by the following code was never returned to the pool:'"); - - private final long _createdTime; - - public AbandonedObjectException() { - _createdTime = System.currentTimeMillis(); - } - - // Override getMessage to avoid creating objects and formatting - // dates unless the log message will actually be used. - - public String getMessage() { - String msg; - synchronized(format) { - msg = format.format(new Date(_createdTime)); - } - return msg; - } - } -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java deleted file mode 100644 index 656303b3..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/PooledObjectState.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * Provides the possible states that a {@link PooledObject} may be in. - * - * TODO: Find shorter names for these states without loss of meaning. - * - * @version $Revision: $ - * - * @since 2.0 - */ -public enum PooledObjectState { - /** - * In the queue, not in use. - */ - IDLE, - - /** - * In use. - */ - ALLOCATED, - - /** - * In the queue, currently being tested for possible eviction. - */ - MAINTAIN_EVICTION, - - /** - * Not in the queue, currently being tested for possible eviction. An - * attempt to borrow the object was made while being tested which removed it - * from the queue. It should be returned to the head of the queue once - * eviction testing completes. - * TODO: Consider allocating object and ignoring the result of the eviction - * test. - */ - MAINTAIN_EVICTION_RETURN_TO_HEAD, - - /** - * In the queue, currently being validated. - */ - MAINTAIN_VALIDATION, - - /** - * Not in queue, currently being validated. The object was borrowed while - * being validated and since testOnBorrow was configured, it was removed - * from the queue and pre-allocated. It should be allocated once validation - * completes. - */ - MAINTAIN_VALIDATION_PREALLOCATED, - - /** - * Not in queue, currently being validated. An attempt to borrow the object - * was made while previously being tested for eviction which removed it from - * the queue. It should be returned to the head of the queue once validation - * completes. - */ - MAINTAIN_VALIDATION_RETURN_TO_HEAD, - - /** - * Failed maintenance (e.g. eviction test or validation) and will be / has - * been destroyed - */ - INVALID, - - /** - * Deemed abandoned, to be invalidated. - */ - ABANDONED, - - /** - * Returning to the pool. - */ - RETURNING -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java deleted file mode 100644 index 92811d78..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -import org.adbcj.mysql.netty.org.apache.commons.pool2.BaseObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.ObjectPool; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolUtils; -import org.adbcj.mysql.netty.org.apache.commons.pool2.PoolableObjectFactory; - -/** - * A {@link java.lang.ref.SoftReference SoftReference} based {@link ObjectPool}. - *

- * This class is intended to be thread-safe. - * - * @param - * Type of element pooled in this pool. - * - * @version $Revision: 1361742 $ - * - * @since 2.0 - */ -public class SoftReferenceObjectPool extends BaseObjectPool { - /** - * Create a SoftReferenceObjectPool with the specified factory. - * - * @param factory - * object factory to use. - */ - public SoftReferenceObjectPool(PoolableObjectFactory factory) { - _pool = new ArrayList>(); - _factory = factory; - } - - /** - * Borrow an object from the pool. If there are no idle instances available - * in the pool, the configured factory's - * {@link PoolableObjectFactory#makeObject()} method is invoked to create a - * new instance. - *

- * All instances are {@link PoolableObjectFactory#activateObject(Object) - * activated} and {@link PoolableObjectFactory#validateObject(Object) - * validated} before being returned by this method. If validation fails or - * an exception occurs activating or validating an idle instance, the - * failing instance is {@link PoolableObjectFactory#destroyObject(Object) - * destroyed} and another instance is retrieved from the pool, validated and - * activated. This process continues until either the pool is empty or an - * instance passes validation. If the pool is empty on activation or it does - * not contain any valid instances, the factory's makeObject - * method is used to create a new instance. If the created instance either - * raises an exception on activation or fails validation, - * NoSuchElementException is thrown. Exceptions thrown by - * MakeObject are propagated to the caller; but other than - * ThreadDeath or VirtualMachineError, exceptions - * generated by activation, validation or destroy methods are swallowed - * silently. - * - * @throws NoSuchElementException - * if a valid object cannot be provided - * @throws IllegalStateException - * if invoked on a {@link #close() closed} pool - * @throws Exception - * if an exception occurs creating a new instance - * @return a valid, activated object instance - */ - - public synchronized T borrowObject() throws Exception { - assertOpen(); - T obj = null; - boolean newlyCreated = false; - while (null == obj) { - if (_pool.isEmpty()) { - if (null == _factory) { - throw new NoSuchElementException(); - } else { - newlyCreated = true; - obj = _factory.makeObject(); - } - } else { - SoftReference ref = _pool.remove(_pool.size() - 1); - obj = ref.get(); - ref.clear(); // prevent this ref from being enqueued with - // refQueue. - } - if (null != _factory && null != obj) { - try { - _factory.activateObject(obj); - if (!_factory.validateObject(obj)) { - throw new Exception("ValidateObject failed"); - } - } catch (Throwable t) { - PoolUtils.checkRethrow(t); - try { - _factory.destroyObject(obj); - } catch (Throwable t2) { - PoolUtils.checkRethrow(t2); - // Swallowed - } finally { - obj = null; - } - if (newlyCreated) { - throw new NoSuchElementException( - "Could not create a validated object, cause: " + - t.getMessage()); - } - } - } - } - _numActive++; - return obj; - } - - /** - * Returns an instance to the pool after successful validation and - * passivation. The returning instance is destroyed if any of the following - * are true: - *

    - *
  • the pool is closed
  • - *
  • {@link PoolableObjectFactory#validateObject(Object) validation} fails - *
  • - *
  • {@link PoolableObjectFactory#passivateObject(Object) passivation} - * throws an exception
  • - *
- * Exceptions passivating or destroying instances are silently swallowed. - * Exceptions validating instances are propagated to the client. - * - * @param obj - * instance to return to the pool - */ - - public synchronized void returnObject(T obj) throws Exception { - boolean success = !isClosed(); - if (_factory != null) { - if (!_factory.validateObject(obj)) { - success = false; - } else { - try { - _factory.passivateObject(obj); - } catch (Exception e) { - success = false; - } - } - } - - boolean shouldDestroy = !success; - _numActive--; - if (success) { - _pool.add(new SoftReference(obj, refQueue)); - } - notifyAll(); // _numActive has changed - - if (shouldDestroy && _factory != null) { - try { - _factory.destroyObject(obj); - } catch (Exception e) { - // ignored - } - } - } - - /** - * {@inheritDoc} - */ - - public synchronized void invalidateObject(T obj) throws Exception { - _numActive--; - if (_factory != null) { - _factory.destroyObject(obj); - } - notifyAll(); // _numActive has changed - } - - /** - * Create an object, and place it into the pool. addObject() is useful for - * "pre-loading" a pool with idle objects. - *

- * Before being added to the pool, the newly created instance is - * {@link PoolableObjectFactory#validateObject(Object) validated} and - * {@link PoolableObjectFactory#passivateObject(Object) passivated}. If - * validation fails, the new instance is - * {@link PoolableObjectFactory#destroyObject(Object) destroyed}. Exceptions - * generated by the factory makeObject or - * passivate are propagated to the caller. Exceptions - * destroying instances are silently swallowed. - * - * @throws IllegalStateException - * if invoked on a {@link #close() closed} pool - * @throws Exception - * when the {@link #getFactory() factory} has a problem creating - * or passivating an object. - */ - - public synchronized void addObject() throws Exception { - assertOpen(); - if (_factory == null) { - throw new IllegalStateException( - "Cannot add objects without a factory."); - } - T obj = _factory.makeObject(); - - boolean success = true; - if (!_factory.validateObject(obj)) { - success = false; - } else { - _factory.passivateObject(obj); - } - - boolean shouldDestroy = !success; - if (success) { - _pool.add(new SoftReference(obj, refQueue)); - notifyAll(); // _numActive has changed - } - - if (shouldDestroy) { - try { - _factory.destroyObject(obj); - } catch (Exception e) { - // ignored - } - } - } - - /** - * Returns an approximation not less than the of the number of idle - * instances in the pool. - * - * @return estimated number of idle instances in the pool - */ - - public synchronized int getNumIdle() { - pruneClearedReferences(); - return _pool.size(); - } - - /** - * Return the number of instances currently borrowed from this pool. - * - * @return the number of instances currently borrowed from this pool - */ - - public synchronized int getNumActive() { - return _numActive; - } - - /** - * Clears any objects sitting idle in the pool. - */ - - public synchronized void clear() { - if (null != _factory) { - Iterator> iter = _pool.iterator(); - while (iter.hasNext()) { - try { - T obj = iter.next().get(); - if (null != obj) { - _factory.destroyObject(obj); - } - } catch (Exception e) { - // ignore error, keep destroying the rest - } - } - } - _pool.clear(); - pruneClearedReferences(); - } - - /** - * Close this pool, and free any resources associated with it. Invokes - * {@link #clear()} to destroy and remove instances in the pool. - *

- * Calling {@link #addObject} or {@link #borrowObject} after invoking this - * method on a pool will cause them to throw an - * {@link IllegalStateException}. - */ - - public void close() { - super.close(); - clear(); - } - - /** - * If any idle objects were garbage collected, remove their - * {@link Reference} wrappers from the idle object pool. - */ - private void pruneClearedReferences() { - Reference ref; - while ((ref = refQueue.poll()) != null) { - try { - _pool.remove(ref); - } catch (UnsupportedOperationException uoe) { - // ignored - } - } - } - - /** - * Returns the {@link PoolableObjectFactory} used by this pool to create and - * manage object instances. - * - * @return the factory - */ - public synchronized PoolableObjectFactory getFactory() { - return _factory; - } - - private final List> _pool; - - private final PoolableObjectFactory _factory; - - /** - * Queue of broken references that might be able to be removed from - * _pool. This is used to help {@link #getNumIdle()} be more - * accurate with minimal performance overhead. - */ - private final ReferenceQueue refQueue = new ReferenceQueue(); - - private int _numActive = 0; // @GuardedBy("this") -} diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java deleted file mode 100644 index 5713a47b..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/TrackedUse.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.adbcj.mysql.netty.org.apache.commons.pool2.impl; - -/** - * Methods to support usage tracking for instances managed by pools configured - * to remove abandoned objects. - * - * @version $Revision:$ - */ -public interface TrackedUse { - - /** - * Get the last time this object was used in ms. - * - * @return long time in ms - */ - long getLastUsed(); -} diff --git a/mysql/pom.xml b/mysql/pom.xml index 67c14fc1..11a1db5b 100644 --- a/mysql/pom.xml +++ b/mysql/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT mysql-build diff --git a/pom.xml b/pom.xml index f18f8b1a..26b254b8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT pom ADBCJ @@ -72,14 +72,15 @@ - + 2.0.1 + org.apache.maven.plugins maven-surefire-plugin diff --git a/postgresql/codec/pom.xml b/postgresql/codec/pom.xml index 12254373..37686222 100644 --- a/postgresql/codec/pom.xml +++ b/postgresql/codec/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT postgresql-codec diff --git a/postgresql/mina/pom.xml b/postgresql/mina/pom.xml index 0bc72c5f..a0374811 100644 --- a/postgresql/mina/pom.xml +++ b/postgresql/mina/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT postgresql-mina diff --git a/postgresql/netty/pom.xml b/postgresql/netty/pom.xml index 21144c90..22b77dc9 100644 --- a/postgresql/netty/pom.xml +++ b/postgresql/netty/pom.xml @@ -8,7 +8,7 @@ org.adbcj postgresql-build - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT postgresql-netty diff --git a/postgresql/pom.xml b/postgresql/pom.xml index db9afb35..df058fd4 100644 --- a/postgresql/pom.xml +++ b/postgresql/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT postgresql-build diff --git a/tck/pom.xml b/tck/pom.xml index 1bac79ff..f06f548f 100644 --- a/tck/pom.xml +++ b/tck/pom.xml @@ -8,7 +8,7 @@ org.adbcj adbcj - 1.0-tb-SNAPSHOT + 0.2-SNAPSHOT adbcj-tck From 36d627c6a762b0ef96af3030df4f818a57234a50 Mon Sep 17 00:00:00 2001 From: shenxun Date: Tue, 2 Jul 2013 14:27:25 +0800 Subject: [PATCH 05/17] add ignore for eclipse --- .gitignore | 3 + .../apache/commons/pool2/impl/package.html | 42 ------ .../org/apache/commons/pool2/overview.html | 121 ------------------ .../org/apache/commons/pool2/package.html | 63 --------- 4 files changed, 3 insertions(+), 226 deletions(-) delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html delete mode 100644 mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html diff --git a/.gitignore b/.gitignore index 4bfa5506..924d2ffc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ .idea/ *.iml target/ +*.project +.settings/ +*.classpath \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html deleted file mode 100644 index 11dbec2f..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/impl/package.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - Package Documentation for org.apache.commons.pool2.impl - - -

- Object pooling API implementations. -

-

- {@link org.apache.commons.pool2.impl.GenericObjectPool GenericObjectPool} - ({@link org.apache.commons.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool}) - provides a more robust (but also more complicated) - implementation of {@link org.apache.commons.pool2.ObjectPool ObjectPool} - ({@link org.apache.commons.pool2.KeyedObjectPool KeyedObjectPool}). -

-

- {@link org.apache.commons.pool2.impl.SoftReferenceObjectPool SoftReferenceObjectPool} - provides a {@link java.lang.ref.SoftReference SoftReference} based - {@link org.apache.commons.pool2.ObjectPool ObjectPool}. -

-

- See also the {@link org.apache.commons.pool2} package. -

- - diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html deleted file mode 100644 index 5a25931c..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/overview.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - Overview of the org.apache.commons.pool2 component - - -

- Generic Object pooling API with several implementations. -

-

- The org.apache.commons.pool2 package defines a simple - interface for a pool of object instances, and a handful of base - classes that may be useful when creating pool implementations. - The API supports pooling of unique objects which can be requested - via a key as well as pools where all objects are equivalent. -

-

- The org.apache.commons.pool2.impl package contains - several pool implementations. - {@link org.apache.commons.pool2.impl.GenericObjectPool - GenericObjectPool} has many configuration options and can support - a limited set of objects such as would be useful in a database - connection pool. - {@link org.apache.commons.pool2.impl.SoftReferenceObjectPool - SoftReferenceObjectPool} has no limit on the number of objects in the - pool, but the garbage collector can remove idle objects from the pool - as needed. There is also a keyed version of - {@link org.apache.commons.pool2.impl.GenericObjectPool - GenericObjectPool}, - {@link org.apache.commons.pool2.impl.GenericKeyedObjectPool - GenericKeyedObjectPool} -

-

- Here is a simple example of pooling HashMap instances. - First create an {@link org.apache.commons.pool2.PoolableObjectFactory - PoolableObjectFactory} -

-
-    public class HashMapFactory
-        extends {@link org.apache.commons.pool2.BasePoolableObjectFactory BasePoolableObjectFactory}<Map<Object,Object>>
-    {
-        /**
-         * Creates an instance that can be returned by the pool.
-         * @return an instance that can be returned by the pool.
-         */
-        public Map<Object,Object> makeObject()
-            throws Exception
-        {
-            return new HashMap<Object,Object>();
-        }
-
-        /**
-         * Uninitialize an instance to be returned to the pool.
-         * @param obj the instance to be passivated
-         */
-        public void passivateObject(Map<Object,Object> obj)
-            throws Exception
-        {
-            obj.clear();
-        }
-    }
-
-

- A class that makes frequent use of a Map could then use a pool - as shown below: -

-
-    public class Foo
-    {
-        private {@link org.apache.commons.pool2.ObjectPool ObjectPool<Map<Object,Object>>} pool;
-        public Foo()
-        {
-            {@link org.apache.commons.pool2.PoolableObjectFactory PoolableObjectFactory<Map<Object,Object>>} factory = new HashMapFactory();
-            pool = new {@link org.apache.commons.pool2.impl.GenericObjectPool GenericObjectPool}<Map<Object,Object>>(factory);
-        }
-
-        public doSomething()
-        {
-            ...
-            Map<Object,Object> map = null;
-            try
-            {
-                map = pool.borrowObject();
-                // use map
-                ...
-            }
-            finally
-            {
-                if (map != null)
-                {
-                    pool.returnObject(map);
-                }
-            }
-            ...
-        }
-    }
-
- -

-The above example shows how one would use an -{@link org.apache.commons.pool2.ObjectPool ObjectPool}. The other supplied -implementations or another special purpose pool would be used similarly. -

- - \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html b/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html deleted file mode 100644 index 3eba5fe0..00000000 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/org/apache/commons/pool2/package.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - Package Documentation for org.apache.commons.pool2 - - -

- Object pooling API. -

-

- The org.apache.commons.pool2 package defines a simple - interface for a pool of object instances, and a handful of base - classes that may be useful when creating pool implementations. -

-

- The pool package itself doesn't define a specific object - pooling implementation, but rather a contract that implementations may - support in order to be fully interchangeable. -

-

- The pool package separates the way in which instances are - pooled from the way in which they are created, resulting in a pair of - interfaces: -

-
-
{@link org.apache.commons.pool2.ObjectPool ObjectPool}
-
- defines a simple object pooling interface, with methods for - borrowing instances from and returning them to the pool. -
-
{@link org.apache.commons.pool2.PoolableObjectFactory PoolableObjectFactory}
-
- defines lifecycle methods for object instances contained within a pool. - By associating a factory with a pool, the pool can create new object - instances as needed. -
-
-

- The pool package also provides a keyed pool interface, - which pools instances of multiple types, accessed according to an - arbitrary key. See - {@link org.apache.commons.pool2.KeyedObjectPool KeyedObjectPool} and - {@link org.apache.commons.pool2.KeyedPoolableObjectFactory - KeyedPoolableObjectFactory}. -

- - From 5e6f9f7577ca1b0866b35be7d35723cb20879765 Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 01:17:33 +0800 Subject: [PATCH 06/17] add type convert to jdbc test and fix those bugs --- .../org/adbcj/ConnectionManagerProvider.java | 71 +-- api/src/main/java/org/adbcj/Type.java | 1 + .../adbcj/mysql/codec/MySqlClientDecoder.java | 46 +- .../java/org/adbcj/mysql/codec/MysqlDefs.java | 562 ++++++++++++++++++ .../java/org/adbcj/mysql/codec/MysqlType.java | 73 ++- .../org/adbcj/mysql/codec/SimpleBlob.java | 162 +++++ .../java/org/adbcj/mysql/netty/TestType.java | 97 +++ 7 files changed, 945 insertions(+), 67 deletions(-) create mode 100644 mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlDefs.java create mode 100644 mysql/codec/src/main/java/org/adbcj/mysql/codec/SimpleBlob.java create mode 100644 mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java diff --git a/api/src/main/java/org/adbcj/ConnectionManagerProvider.java b/api/src/main/java/org/adbcj/ConnectionManagerProvider.java index 5138fba6..0dcc9f26 100644 --- a/api/src/main/java/org/adbcj/ConnectionManagerProvider.java +++ b/api/src/main/java/org/adbcj/ConnectionManagerProvider.java @@ -23,38 +23,41 @@ public class ConnectionManagerProvider { - public static final String ADBCJ_PROTOCOL = "adbcj"; - - private ConnectionManagerProvider () {} - - public static ConnectionManager createConnectionManager(String url, String username, String password) throws DbException { - return createConnectionManager(url, username, password, null); - } - - public static ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) throws DbException { - if (url == null) { - throw new IllegalArgumentException("Connection url can not be null"); - } - - try { - URI uri = new URI(url); - String adbcjProtocol = uri.getScheme(); - if (!ADBCJ_PROTOCOL.equals(adbcjProtocol)) { - throw new DbException("Invalid connection URL: " + url); - } - URI driverUri = new URI(uri.getSchemeSpecificPart()); - String protocol = driverUri.getScheme(); - - ServiceLoader serviceLoader = ServiceLoader.load(ConnectionManagerFactory.class); - for (ConnectionManagerFactory factory : serviceLoader) { - if (factory.canHandle(protocol)) { - return factory.createConnectionManager(url, username, password, properties); - } - } - throw new DbException("Could not find ConnectionManagerFactory for protocol '" + protocol + "'"); - } catch (URISyntaxException e) { - throw new DbException("Invalid connection URL: " + url); - } - } - + public static final String ADBCJ_PROTOCOL = "adbcj"; + + private ConnectionManagerProvider(){ + } + + public static ConnectionManager createConnectionManager(String url, String username, String password) + throws DbException { + return createConnectionManager(url, username, password, null); + } + + public static ConnectionManager createConnectionManager(String url, String username, String password, + Properties properties) throws DbException { + if (url == null) { + throw new IllegalArgumentException("Connection url can not be null"); + } + + try { + URI uri = new URI(url); + String adbcjProtocol = uri.getScheme(); + if (!ADBCJ_PROTOCOL.equals(adbcjProtocol)) { + throw new DbException("Invalid connection URL: " + url); + } + URI driverUri = new URI(uri.getSchemeSpecificPart()); + String protocol = driverUri.getScheme(); + + ServiceLoader serviceLoader = ServiceLoader.load(ConnectionManagerFactory.class); + for (ConnectionManagerFactory factory : serviceLoader) { + if (factory.canHandle(protocol)) { + return factory.createConnectionManager(url, username, password, properties); + } + } + throw new DbException("Could not find ConnectionManagerFactory for protocol '" + protocol + "'"); + } catch (URISyntaxException e) { + throw new DbException("Invalid connection URL: " + url); + } + } + } diff --git a/api/src/main/java/org/adbcj/Type.java b/api/src/main/java/org/adbcj/Type.java index c1a73b96..01b94bb7 100644 --- a/api/src/main/java/org/adbcj/Type.java +++ b/api/src/main/java/org/adbcj/Type.java @@ -26,6 +26,7 @@ public enum Type { ARRAY(Types.ARRAY), BIGINT(Types.BIGINT), + LONG(Types.BIGINT), BINARY(Types.BINARY), BIT(Types.BIT), BLOB(Types.BLOB), diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java index fb41579e..21204b7b 100644 --- a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MySqlClientDecoder.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.io.InputStream; +import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; @@ -218,12 +220,16 @@ protected ServerPacket doDecode(InputStream input, boolean block) throws IOExcep // TODO add decoding for all column types switch (field.getColumnType()) { case TINYINT: - value = Byte.valueOf(strVal); + //in java Boolean is the same with Integer + value = Integer.valueOf(strVal); break; case INTEGER: value = Integer.valueOf(strVal); break; case BIGINT: + value = BigInteger.valueOf(Long.valueOf(strVal)); + break; + case LONG: value = Long.valueOf(strVal); break; case VARCHAR: @@ -260,7 +266,28 @@ protected ServerPacket doDecode(InputStream input, boolean block) throws IOExcep // UTF-8?GBK? value = strVal.getBytes(); break; - + case BLOB: + value = new SimpleBlob(strVal.getBytes()); + break; + case BIT: + value = strVal.getBytes(); + break; + case DECIMAL: + if(strVal == null) + { + break; + } + if(strVal.contains(".")) + { + //double + value = BigDecimal.valueOf(Double.valueOf(strVal)); + } + else + { + value = BigDecimal.valueOf(Long.valueOf(strVal)); + } + + break; default: throw new IllegalStateException("Don't know how to handle column type of " + field.getColumnType()); @@ -305,7 +332,12 @@ protected ServerGreeting decodeServerGreeting(InputStream in, int length, int pa in.read(salt, SALT_SIZE, SALT2_SIZE); in.read(); // Throw away 0 byte - + String str = IoUtils.readString(in, "ASCII"); + if (!"mysql_native_password".equals(str)) { + // in 5.5, the authentication plugin name is specifical tolded by + // default + throw new IllegalStateException("not supported yet : " + str); + } return new ServerGreeting(length, packetNumber, protocol, @@ -356,8 +388,14 @@ protected ResultSetFieldResponse decodeFieldResponse(InputStream in, int packetL MysqlCharacterSet charSet = MysqlCharacterSet.findById(characterSetNumber); long length = IoUtils.readUnsignedInt(in); int fieldTypeId = in.read(); - MysqlType fieldType = MysqlType.findById(fieldTypeId); Set flags = IoUtils.readEnumSet(in, FieldFlag.class); + boolean unsigned = false; + if(flags.contains(FieldFlag.UNSIGNED)) + { + unsigned = true; + } + MysqlType fieldType = MysqlType.findById(fieldTypeId,unsigned); + int decimals = in.read(); in.skip(2); // Skip filler long fieldDefault = IoUtils.readBinaryLengthEncoding(in); diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlDefs.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlDefs.java new file mode 100644 index 00000000..7053b923 --- /dev/null +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlDefs.java @@ -0,0 +1,562 @@ +/* + Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + + + The MySQL Connector/J is licensed under the terms of the GPLv2 + , like most MySQL Connectors. + There are special exceptions to the terms and conditions of the GPLv2 as it is applied to + this software, see the FLOSS License Exception + . + + This program is free software; you can redistribute it and/or modify it under the terms + of the GNU General Public License as published by the Free Software Foundation; version 2 + of the License. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this + program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth + Floor, Boston, MA 02110-1301 USA + + + + */ +package org.adbcj.mysql.codec; + +import java.sql.Types; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * MysqlDefs contains many values that are needed for communication with the + * MySQL server. + * + * @author Mark Matthews + * @version $Id$ + */ +public final class MysqlDefs { + + // ~ Static fields/initializers + // --------------------------------------------- + + static final int COM_BINLOG_DUMP = 18; + + static final int COM_CHANGE_USER = 17; + + static final int COM_CLOSE_STATEMENT = 25; + + static final int COM_CONNECT_OUT = 20; + + static final int COM_END = 29; + + static final int COM_EXECUTE = 23; + + static final int COM_FETCH = 28; + + static final int COM_LONG_DATA = 24; + + static final int COM_PREPARE = 22; + + static final int COM_REGISTER_SLAVE = 21; + + static final int COM_RESET_STMT = 26; + + static final int COM_SET_OPTION = 27; + + static final int COM_TABLE_DUMP = 19; + + static final int CONNECT = 11; + + static final int CREATE_DB = 5; + + static final int DEBUG = 13; + + static final int DELAYED_INSERT = 16; + + static final int DROP_DB = 6; + + static final int FIELD_LIST = 4; + + static final int FIELD_TYPE_BIT = 16; + + public static final int FIELD_TYPE_BLOB = 252; + + static final int FIELD_TYPE_DATE = 10; + + static final int FIELD_TYPE_DATETIME = 12; + + // Data Types + static final int FIELD_TYPE_DECIMAL = 0; + + static final int FIELD_TYPE_DOUBLE = 5; + + static final int FIELD_TYPE_ENUM = 247; + + static final int FIELD_TYPE_FLOAT = 4; + + static final int FIELD_TYPE_GEOMETRY = 255; + + static final int FIELD_TYPE_INT24 = 9; + + static final int FIELD_TYPE_LONG = 3; + + static final int FIELD_TYPE_LONG_BLOB = 251; + + static final int FIELD_TYPE_LONGLONG = 8; + + static final int FIELD_TYPE_MEDIUM_BLOB = 250; + + static final int FIELD_TYPE_NEW_DECIMAL = 246; + + static final int FIELD_TYPE_NEWDATE = 14; + + static final int FIELD_TYPE_NULL = 6; + + static final int FIELD_TYPE_SET = 248; + + static final int FIELD_TYPE_SHORT = 2; + + static final int FIELD_TYPE_STRING = 254; + + static final int FIELD_TYPE_TIME = 11; + + static final int FIELD_TYPE_TIMESTAMP = 7; + + static final int FIELD_TYPE_TINY = 1; + + // Older data types + static final int FIELD_TYPE_TINY_BLOB = 249; + + static final int FIELD_TYPE_VAR_STRING = 253; + + static final int FIELD_TYPE_VARCHAR = 15; + + // Newer data types + static final int FIELD_TYPE_YEAR = 13; + + static final int INIT_DB = 2; + + static final long LENGTH_BLOB = 65535; + + static final long LENGTH_LONGBLOB = 4294967295L; + + static final long LENGTH_MEDIUMBLOB = 16777215; + + static final long LENGTH_TINYBLOB = 255; + + // Limitations + static final int MAX_ROWS = 50000000; // From the + // MySQL FAQ + + /** + * Used to indicate that the server sent no field-level character set + * information, so the driver should use the connection-level character + * encoding instead. + */ + public static final int NO_CHARSET_INFO = -1; + + static final byte OPEN_CURSOR_FLAG = 1; + + static final int PING = 14; + + static final int PROCESS_INFO = 10; + + static final int PROCESS_KILL = 12; + + static final int QUERY = 3; + + static final int QUIT = 1; + + // ~ Methods + // ---------------------------------------------------------------- + + static final int RELOAD = 7; + + static final int SHUTDOWN = 8; + + // + // Constants defined from mysql + // + // DB Operations + static final int SLEEP = 0; + + static final int STATISTICS = 9; + + static final int TIME = 15; + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + static int mysqlToJavaType(int mysqlType) { + int jdbcType; + + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_NEW_DECIMAL: + case MysqlDefs.FIELD_TYPE_DECIMAL: + jdbcType = Types.DECIMAL; + + break; + + case MysqlDefs.FIELD_TYPE_TINY: + jdbcType = Types.TINYINT; + + break; + + case MysqlDefs.FIELD_TYPE_SHORT: + jdbcType = Types.SMALLINT; + + break; + + case MysqlDefs.FIELD_TYPE_LONG: + jdbcType = Types.INTEGER; + + break; + + case MysqlDefs.FIELD_TYPE_FLOAT: + jdbcType = Types.REAL; + + break; + + case MysqlDefs.FIELD_TYPE_DOUBLE: + jdbcType = Types.DOUBLE; + + break; + + case MysqlDefs.FIELD_TYPE_NULL: + jdbcType = Types.NULL; + + break; + + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + jdbcType = Types.TIMESTAMP; + + break; + + case MysqlDefs.FIELD_TYPE_LONGLONG: + jdbcType = Types.BIGINT; + + break; + + case MysqlDefs.FIELD_TYPE_INT24: + jdbcType = Types.INTEGER; + + break; + + case MysqlDefs.FIELD_TYPE_DATE: + jdbcType = Types.DATE; + + break; + + case MysqlDefs.FIELD_TYPE_TIME: + jdbcType = Types.TIME; + + break; + + case MysqlDefs.FIELD_TYPE_DATETIME: + jdbcType = Types.TIMESTAMP; + + break; + + case MysqlDefs.FIELD_TYPE_YEAR: + jdbcType = Types.DATE; + + break; + + case MysqlDefs.FIELD_TYPE_NEWDATE: + jdbcType = Types.DATE; + + break; + + case MysqlDefs.FIELD_TYPE_ENUM: + jdbcType = Types.CHAR; + + break; + + case MysqlDefs.FIELD_TYPE_SET: + jdbcType = Types.CHAR; + + break; + + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + jdbcType = Types.VARBINARY; + + break; + + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + jdbcType = Types.LONGVARBINARY; + + break; + + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + jdbcType = Types.LONGVARBINARY; + + break; + + case MysqlDefs.FIELD_TYPE_BLOB: + jdbcType = Types.LONGVARBINARY; + + break; + + case MysqlDefs.FIELD_TYPE_VAR_STRING: + case MysqlDefs.FIELD_TYPE_VARCHAR: + jdbcType = Types.VARCHAR; + + break; + + case MysqlDefs.FIELD_TYPE_STRING: + jdbcType = Types.CHAR; + + break; + case MysqlDefs.FIELD_TYPE_GEOMETRY: + jdbcType = Types.BINARY; + + break; + case MysqlDefs.FIELD_TYPE_BIT: + jdbcType = Types.BIT; + + break; + default: + jdbcType = Types.VARCHAR; + } + + return jdbcType; + } + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + static int mysqlToJavaType(String mysqlType) { + if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } else if (mysqlType.equalsIgnoreCase("TINYINT")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_TINY); + } else if (mysqlType.equalsIgnoreCase("SMALLINT")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_SHORT); + } else if (mysqlType.equalsIgnoreCase("MEDIUMINT")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("INT") || mysqlType.equalsIgnoreCase("INTEGER")) { //$NON-NLS-1$ //$NON-NLS-2$ + return mysqlToJavaType(FIELD_TYPE_LONG); + } else if (mysqlType.equalsIgnoreCase("BIGINT")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_LONGLONG); + } else if (mysqlType.equalsIgnoreCase("INT24")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("REAL")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("FLOAT")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_FLOAT); + } else if (mysqlType.equalsIgnoreCase("DECIMAL")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("NUMERIC")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("DOUBLE")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("CHAR")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_STRING); + } else if (mysqlType.equalsIgnoreCase("VARCHAR")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_VAR_STRING); + } else if (mysqlType.equalsIgnoreCase("DATE")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DATE); + } else if (mysqlType.equalsIgnoreCase("TIME")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_TIME); + } else if (mysqlType.equalsIgnoreCase("YEAR")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_YEAR); + } else if (mysqlType.equalsIgnoreCase("TIMESTAMP")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_TIMESTAMP); + } else if (mysqlType.equalsIgnoreCase("DATETIME")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_DATETIME); + } else if (mysqlType.equalsIgnoreCase("TINYBLOB")) { //$NON-NLS-1$ + return java.sql.Types.BINARY; + } else if (mysqlType.equalsIgnoreCase("BLOB")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("MEDIUMBLOB")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("LONGBLOB")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("TINYTEXT")) { //$NON-NLS-1$ + return java.sql.Types.VARCHAR; + } else if (mysqlType.equalsIgnoreCase("TEXT")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("MEDIUMTEXT")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("LONGTEXT")) { //$NON-NLS-1$ + return java.sql.Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("ENUM")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_ENUM); + } else if (mysqlType.equalsIgnoreCase("SET")) { //$NON-NLS-1$ + return mysqlToJavaType(FIELD_TYPE_SET); + } else if (mysqlType.equalsIgnoreCase("GEOMETRY")) { + return mysqlToJavaType(FIELD_TYPE_GEOMETRY); + } else if (mysqlType.equalsIgnoreCase("BINARY")) { + return Types.BINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("VARBINARY")) { + return Types.VARBINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } + + // Punt + return java.sql.Types.OTHER; + } + + /** + * @param mysqlType + * @return + */ + public static String typeToName(int mysqlType) { + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_DECIMAL: + return "FIELD_TYPE_DECIMAL"; + + case MysqlDefs.FIELD_TYPE_TINY: + return "FIELD_TYPE_TINY"; + + case MysqlDefs.FIELD_TYPE_SHORT: + return "FIELD_TYPE_SHORT"; + + case MysqlDefs.FIELD_TYPE_LONG: + return "FIELD_TYPE_LONG"; + + case MysqlDefs.FIELD_TYPE_FLOAT: + return "FIELD_TYPE_FLOAT"; + + case MysqlDefs.FIELD_TYPE_DOUBLE: + return "FIELD_TYPE_DOUBLE"; + + case MysqlDefs.FIELD_TYPE_NULL: + return "FIELD_TYPE_NULL"; + + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + return "FIELD_TYPE_TIMESTAMP"; + + case MysqlDefs.FIELD_TYPE_LONGLONG: + return "FIELD_TYPE_LONGLONG"; + + case MysqlDefs.FIELD_TYPE_INT24: + return "FIELD_TYPE_INT24"; + + case MysqlDefs.FIELD_TYPE_DATE: + return "FIELD_TYPE_DATE"; + + case MysqlDefs.FIELD_TYPE_TIME: + return "FIELD_TYPE_TIME"; + + case MysqlDefs.FIELD_TYPE_DATETIME: + return "FIELD_TYPE_DATETIME"; + + case MysqlDefs.FIELD_TYPE_YEAR: + return "FIELD_TYPE_YEAR"; + + case MysqlDefs.FIELD_TYPE_NEWDATE: + return "FIELD_TYPE_NEWDATE"; + + case MysqlDefs.FIELD_TYPE_ENUM: + return "FIELD_TYPE_ENUM"; + + case MysqlDefs.FIELD_TYPE_SET: + return "FIELD_TYPE_SET"; + + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + return "FIELD_TYPE_TINY_BLOB"; + + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + return "FIELD_TYPE_MEDIUM_BLOB"; + + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + return "FIELD_TYPE_LONG_BLOB"; + + case MysqlDefs.FIELD_TYPE_BLOB: + return "FIELD_TYPE_BLOB"; + + case MysqlDefs.FIELD_TYPE_VAR_STRING: + return "FIELD_TYPE_VAR_STRING"; + + case MysqlDefs.FIELD_TYPE_STRING: + return "FIELD_TYPE_STRING"; + + case MysqlDefs.FIELD_TYPE_VARCHAR: + return "FIELD_TYPE_VARCHAR"; + + case MysqlDefs.FIELD_TYPE_GEOMETRY: + return "FIELD_TYPE_GEOMETRY"; + + default: + return " Unknown MySQL Type # " + mysqlType; + } + } + + private static Map mysqlToJdbcTypesMap = new HashMap(); + + static { + mysqlToJdbcTypesMap.put("BIT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_BIT))); + + mysqlToJdbcTypesMap.put("TINYINT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_TINY))); + mysqlToJdbcTypesMap.put("SMALLINT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_SHORT))); + mysqlToJdbcTypesMap.put("MEDIUMINT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_INT24))); + mysqlToJdbcTypesMap.put("INT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_LONG))); + mysqlToJdbcTypesMap.put("INTEGER", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_LONG))); + mysqlToJdbcTypesMap.put("BIGINT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_LONGLONG))); + mysqlToJdbcTypesMap.put("INT24", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_INT24))); + mysqlToJdbcTypesMap.put("REAL", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DOUBLE))); + mysqlToJdbcTypesMap.put("FLOAT", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_FLOAT))); + mysqlToJdbcTypesMap.put("DECIMAL", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DECIMAL))); + mysqlToJdbcTypesMap.put("NUMERIC", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DECIMAL))); + mysqlToJdbcTypesMap.put("DOUBLE", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DOUBLE))); + mysqlToJdbcTypesMap.put("CHAR", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_STRING))); + mysqlToJdbcTypesMap.put("VARCHAR", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_VAR_STRING))); + mysqlToJdbcTypesMap.put("DATE", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DATE))); + mysqlToJdbcTypesMap.put("TIME", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_TIME))); + mysqlToJdbcTypesMap.put("YEAR", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_YEAR))); + mysqlToJdbcTypesMap.put("TIMESTAMP", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_TIMESTAMP))); + mysqlToJdbcTypesMap.put("DATETIME", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_DATETIME))); + mysqlToJdbcTypesMap.put("TINYBLOB", Integer.valueOf(java.sql.Types.BINARY)); + mysqlToJdbcTypesMap.put("BLOB", Integer.valueOf(java.sql.Types.LONGVARBINARY)); + mysqlToJdbcTypesMap.put("MEDIUMBLOB", Integer.valueOf(java.sql.Types.LONGVARBINARY)); + mysqlToJdbcTypesMap.put("LONGBLOB", Integer.valueOf(java.sql.Types.LONGVARBINARY)); + mysqlToJdbcTypesMap.put("TINYTEXT", Integer.valueOf(java.sql.Types.VARCHAR)); + mysqlToJdbcTypesMap.put("TEXT", Integer.valueOf(java.sql.Types.LONGVARCHAR)); + mysqlToJdbcTypesMap.put("MEDIUMTEXT", Integer.valueOf(java.sql.Types.LONGVARCHAR)); + mysqlToJdbcTypesMap.put("LONGTEXT", Integer.valueOf(java.sql.Types.LONGVARCHAR)); + mysqlToJdbcTypesMap.put("ENUM", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_ENUM))); + mysqlToJdbcTypesMap.put("SET", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_SET))); + mysqlToJdbcTypesMap.put("GEOMETRY", Integer.valueOf(mysqlToJavaType(FIELD_TYPE_GEOMETRY))); + } + + static final void appendJdbcTypeMappingQuery(StringBuffer buf, String mysqlTypeColumnName) { + + buf.append("CASE "); + Map typesMap = new HashMap(); + typesMap.putAll(mysqlToJdbcTypesMap); + typesMap.put("BINARY", Integer.valueOf(Types.BINARY)); + typesMap.put("VARBINARY", Integer.valueOf(Types.VARBINARY)); + + Iterator mysqlTypes = typesMap.keySet().iterator(); + + while (mysqlTypes.hasNext()) { + String mysqlTypeName = mysqlTypes.next(); + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append("' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + + if (mysqlTypeName.equalsIgnoreCase("DOUBLE") || mysqlTypeName.equalsIgnoreCase("FLOAT") + || mysqlTypeName.equalsIgnoreCase("DECIMAL") || mysqlTypeName.equalsIgnoreCase("NUMERIC")) { + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append(" unsigned' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + } + } + + buf.append(" ELSE "); + buf.append(Types.OTHER); + buf.append(" END "); + + } +} diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlType.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlType.java index 1a62058b..0000114c 100644 --- a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlType.java +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlType.java @@ -22,33 +22,37 @@ // TODO Make sure all the types are mapped up properly - Most of these are guesses public enum MysqlType { - DECIMAL(0x00, Type.DECIMAL), - TINY(0x01, Type.TINYINT), - SHORT(0x02, Type.SMALLINT), - LONG(0x03, Type.BIGINT), - FLOAT(0x04, Type.FLOAT), - DOUBLE(0x05, Type.DOUBLE), - NULL(0x06, Type.NULL), - TIMESTAMP(0x07, Type.TIMESTAMP), - LONGLONG(0x08, Type.BIGINT), - INT24(0x09, Type.INTEGER), - DATE(0x0a, Type.DATE), - TIME(0x0b, Type.TIME), - DATETIME(0x0c, Type.TIMESTAMP), - YEAR(0x0d, Type.INTEGER), - NEWDATE(0x0e, Type.DATE), - VARCHAR(0x0f, Type.VARCHAR), - BIT(0x10, Type.BIT), - NEWDECIMAL(0xf6, Type.DECIMAL), - ENUM(0xf7, Type.INTEGER), - SET(0xf8, Type.ARRAY), - TINY_BLOB(0xf9, Type.BLOB), - MEDIUM_BLOB(0xfa, Type.BLOB), - LONG_BLOB(0xfb, Type.BLOB), - BLOB(0xfc, Type.BLOB), - VAR_STRING(0xfd, Type.VARCHAR), - STRING(0xfe, Type.VARCHAR), - GEOMETRY(0xff, Type.STRUCT); + + SIGNED_DECIMAL(MysqlDefs.FIELD_TYPE_DECIMAL, Type.DECIMAL), + SIGNED_NEW_DECIMAL(MysqlDefs.FIELD_TYPE_NEW_DECIMAL,Type.DECIMAL), + SIGNED_TINY(MysqlDefs.FIELD_TYPE_TINY, Type.TINYINT), + SIGNED_SHORT(MysqlDefs.FIELD_TYPE_SHORT, Type.SMALLINT), + SIGNED_LONG(MysqlDefs.FIELD_TYPE_LONG, Type.INTEGER), + SIGNED_FLOAT(MysqlDefs.FIELD_TYPE_FLOAT, Type.FLOAT), + SIGNED_DOUBLE(MysqlDefs.FIELD_TYPE_DOUBLE, Type.DOUBLE), + SIGNED_NULL(MysqlDefs.FIELD_TYPE_NULL, Type.NULL), + SIGNED_TIMESTAMP(MysqlDefs.FIELD_TYPE_TIMESTAMP, Type.TIMESTAMP), + SIGNED_LONGLONG(MysqlDefs.FIELD_TYPE_LONGLONG, Type.LONG), + SIGNED_INT24(MysqlDefs.FIELD_TYPE_INT24, Type.INTEGER), + SIGNED_DATE(MysqlDefs.FIELD_TYPE_DATE, Type.DATE), + SIGNED_TIME(MysqlDefs.FIELD_TYPE_TIME, Type.TIME), + SIGNED_DATETIME(MysqlDefs.FIELD_TYPE_DATETIME, Type.TIMESTAMP), + SIGNED_YEAR(MysqlDefs.FIELD_TYPE_YEAR, Type.INTEGER), + SIGNED_NEWDATE(MysqlDefs.FIELD_TYPE_NEWDATE, Type.DATE), + SIGNED_VARCHAR(MysqlDefs.FIELD_TYPE_VARCHAR, Type.VARCHAR), + SIGNED_BIT(MysqlDefs.FIELD_TYPE_BIT, Type.BIT), + SIGNED_NEWDECIMAL(MysqlDefs.FIELD_TYPE_NEW_DECIMAL, Type.DECIMAL), + SIGNED_ENUM(MysqlDefs.FIELD_TYPE_ENUM, Type.INTEGER), + SIGNED_SET(MysqlDefs.FIELD_TYPE_SET, Type.ARRAY), + SIGNED_TINY_BLOB(MysqlDefs.FIELD_TYPE_TINY_BLOB, Type.BLOB), + SIGNED_MEDIUM_BLOB(MysqlDefs.FIELD_TYPE_MEDIUM_BLOB, Type.BLOB), + SIGNED_LONG_BLOB(MysqlDefs.FIELD_TYPE_LONG_BLOB, Type.BLOB), + SIGNED_BLOB(MysqlDefs.FIELD_TYPE_BLOB, Type.BLOB), + SIGNED_VAR_STRING(MysqlDefs.FIELD_TYPE_VAR_STRING, Type.VARCHAR), + SIGNED_STRING(MysqlDefs.FIELD_TYPE_STRING, Type.VARCHAR), + SIGNED_GEOMETRY(MysqlDefs.FIELD_TYPE_GEOMETRY, Type.STRUCT), + UNSIGNED_LONGLONG(MysqlDefs.FIELD_TYPE_LONGLONG,Type.BIGINT), + UNSIGNED_LONG(MysqlDefs.FIELD_TYPE_LONG,Type.LONG); private final int id; private final Type type; @@ -66,10 +70,21 @@ public Type getType() { return type; } - public static MysqlType findById(int id) { + public static MysqlType findById(int id,boolean unsign) { for (MysqlType type : values()) { if (id == type.id) { - return type; + if(unsign) + { + if(type == SIGNED_LONG) + { + return UNSIGNED_LONG; + } + else if(type == SIGNED_LONGLONG) + { + return UNSIGNED_LONGLONG; + } + } + return type; } } return null; diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/SimpleBlob.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/SimpleBlob.java new file mode 100644 index 00000000..78be24be --- /dev/null +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/SimpleBlob.java @@ -0,0 +1,162 @@ +package org.adbcj.mysql.codec; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Blob; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; + +/** + * @author + */ +public class SimpleBlob implements Blob { + + private final byte[] data; + + /** + * Constructor TDHSBlob creates a new TDHSBlob instance. + * + * @param data of type byte[] + */ + public SimpleBlob(byte[] data){ + this.data = data; + } + + /** + * Method length ... + * + * @return long + * @throws SQLException when + */ + public long length() throws SQLException { + return data != null ? data.length : 0; + } + + /** + * Method getBytes ... + * + * @param pos of type long + * @param length of type int + * @return byte[] + * @throws SQLException when + */ + public byte[] getBytes(long pos, int length) throws SQLException { + pos--; + if (data == null || data.length < pos + length) { + throw new SQLException("getBytes out of range! " + "the byte length[" + length() + "]," + + "request is pos [" + pos + "] length [" + length + "]"); + } + byte[] r = new byte[length]; + System.arraycopy(data, (int) pos, r, 0, length); + return r; + } + + /** + * Method getBinaryStream returns the binaryStream of this TDHSBlob object. + * + * @return the binaryStream (type InputStream) of this TDHSBlob object. + * @throws SQLException when + */ + public InputStream getBinaryStream() throws SQLException { + return data == null ? null : new ByteArrayInputStream(data); + } + + /** + * Method position ... + * + * @param pattern of type byte[] + * @param start of type long + * @return long + * @throws SQLException when + */ + public long position(byte[] pattern, long start) throws SQLException { + if (start < 1 || start > length()) { + throw new SQLException("start [" + start + "] is out of range!"); + } + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method position ... + * + * @param pattern of type Blob + * @param start of type long + * @return long + * @throws SQLException when + */ + public long position(Blob pattern, long start) throws SQLException { + if (start < 1 || start > length()) { + throw new SQLException("start [" + start + "] is out of range!"); + } + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method setBytes ... + * + * @param pos of type long + * @param bytes of type byte[] + * @return int + * @throws SQLException when + */ + public int setBytes(long pos, byte[] bytes) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method setBytes ... + * + * @param pos of type long + * @param bytes of type byte[] + * @param offset of type int + * @param len of type int + * @return int + * @throws SQLException when + */ + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method setBinaryStream ... + * + * @param pos of type long + * @return OutputStream + * @throws SQLException when + */ + public OutputStream setBinaryStream(long pos) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method truncate ... + * + * @param len of type long + * @throws SQLException when + */ + public void truncate(long len) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } + + /** + * Method free ... + * + * @throws SQLException when + */ + public void free() throws SQLException { + } + + /** + * Method getBinaryStream ... + * + * @param pos of type long + * @param length of type long + * @return InputStream + * @throws SQLException when + */ + public InputStream getBinaryStream(long pos, long length) throws SQLException { + byte[] bytes = getBytes(pos, (int) length); + return bytes == null ? null : new ByteArrayInputStream(bytes); + } +} diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java new file mode 100644 index 00000000..8154ac8a --- /dev/null +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java @@ -0,0 +1,97 @@ +package org.adbcj.mysql.netty; + +import java.io.InputStream; +import java.math.BigDecimal; +import java.sql.Blob; + +import junit.framework.Assert; + +import org.adbcj.Connection; +import org.adbcj.ConnectionManager; +import org.adbcj.ConnectionManagerProvider; +import org.adbcj.DbSessionFuture; +import org.adbcj.Result; +import org.adbcj.ResultSet; +import org.adbcj.Row; +import org.adbcj.Value; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class TestType { + + // public static ConnectionManager cm = + // ConnectionManagerProvider.createConnectionManager("adbcj:mysqlnetty://10.232.31.25:3309/unitTest", + // "test", + // "test"); + + public static ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:mysqlnetty://localhost/unit_test", + "root", + ""); + public static final String DATE = "'1986-03-22 05:33:12'"; + + @BeforeMethod + public void prepare() throws Exception { + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeUpdate("delete from type_test"); + Assert.assertTrue(result.get().getAffectedRows() > -1); + String sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,tinyintr," + + "smallintr,mediumintr,bitr,bigintr,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,'varch','char','lob',100,4," + + "1,100,b'0',1000000,1.1,2.2,1000.1," + DATE + "," + DATE + "," + DATE + "," + DATE + "," + DATE + + ")"; + result = connection.executeUpdate(sql); + Assert.assertTrue(result.get().getAffectedRows() > -1); + connection.close(true); + } + + public void tear() throws Exception { + + } + + @Test + public void testType() throws Exception { + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,tinyintr," + + "smallintr,mediumintr,bitr,bigintr,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr from type_test"); + ResultSet r = result.get(); + Row row = r.iterator().next(); + Value[] values = row.getValues(); + // pk + Assert.assertEquals(0, values[0].getValue()); + // varcharr varch + Assert.assertEquals("varch", values[1].getValue()); + // charr 'char' + Assert.assertEquals("char", values[2].getValue()); + // blobr 'lob' + InputStream instream = ((Blob) values[3].getValue()).getBinaryStream(); + byte[] b = new byte[instream.available()]; + instream.read(b); + String str = new String(b); + Assert.assertEquals("lob", str); + // ,integerr 100 + Assert.assertEquals(100, values[4].getValue()); + + // ,tinyintr, 4 + Assert.assertEquals(Integer.valueOf("4"), values[5].getValue()); + // "smallintr + Assert.assertEquals(1, values[6].getValue()); + // ,mediumintr 100 + Assert.assertEquals(100, values[7].getValue()); + // ,bitr, 0 + Assert.assertEquals(Byte.valueOf("0").byteValue(), (byte)((byte[])values[8].getValue())[0]); + // bigintr 1000000 + Assert.assertEquals(1000000l, values[9].getValue()); + // ,floatr + Assert.assertEquals(1.1f, values[10].getValue()); + // ,doubler," 2.2 + Assert.assertEquals(2.2d, values[11].getValue()); + // + "decimalr, + Assert.assertEquals(BigDecimal.valueOf(1000l), values[12].getValue()); + // dater + Assert.assertEquals("1986-03-22", values[13].getValue()); + // ,timer,datetimer,timestampr,yearr + // "0,'varch','char','lob',100,4," + // + "1,100,0,1000000,1.1,2.2,1000.1,now(),now(),now(),now(),now() + } +} From 787ba497eb5143fe08d30850a4764a90ce65819c Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 01:18:04 +0800 Subject: [PATCH 07/17] add sql --- .../org/adbcj/mysql/netty/createTable.sql | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql b/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql new file mode 100644 index 00000000..edfb127c --- /dev/null +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql @@ -0,0 +1,23 @@ +create schema unit_test; +use unit_test; +CREATE TABLE `type_test` ( + `varcharr` varchar(255) DEFAULT NULL, + `charr` char(255) DEFAULT NULL, + `blobr` blob, + `integerr` int(11) DEFAULT NULL, + `tinyintr` tinyint(4) DEFAULT NULL, + `smallintr` smallint(6) DEFAULT NULL, + `mediumintr` mediumint(9) DEFAULT NULL, + `bitr` bit(1) DEFAULT NULL, + `bigintr` bigint(20) DEFAULT NULL, + `floatr` float DEFAULT NULL, + `doubler` double DEFAULT NULL, + `decimalr` decimal(10,0) DEFAULT NULL, + `dater` date DEFAULT NULL, + `timer` time DEFAULT NULL, + `datetimer` datetime DEFAULT NULL, + `timestampr` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + `yearr` year(4) DEFAULT NULL, + `pk` int(11) NOT NULL, + PRIMARY KEY (`pk`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file From 2565e7a700418cadadd4dfe12c5021d9dbcc2fba Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 21:53:55 +0800 Subject: [PATCH 08/17] type test without unsign complate --- .../services/org.adbcj.ConnectionManagerFactory | 1 - .../java/org/adbcj/mysql/netty/TestType.java | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory b/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory index a97af6d7..27952be7 100644 --- a/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory +++ b/mysql/netty/src/main/resources/META-INF/services/org.adbcj.ConnectionManagerFactory @@ -1,2 +1 @@ org.adbcj.mysql.netty.MySqlConnectionManagerFactory -org.adbcj.mysql.netty.WrappedMysqlConnectionManagerFactory \ No newline at end of file diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java index 8154ac8a..c7bda572 100644 --- a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java @@ -3,6 +3,9 @@ import java.io.InputStream; import java.math.BigDecimal; import java.sql.Blob; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; import junit.framework.Assert; @@ -89,9 +92,14 @@ public void testType() throws Exception { // + "decimalr, Assert.assertEquals(BigDecimal.valueOf(1000l), values[12].getValue()); // dater - Assert.assertEquals("1986-03-22", values[13].getValue()); - // ,timer,datetimer,timestampr,yearr - // "0,'varch','char','lob',100,4," - // + "1,100,0,1000000,1.1,2.2,1000.1,now(),now(),now(),now(),now() + Assert.assertEquals(Date.valueOf("1986-03-22"), values[13].getValue()); + //timer + Assert.assertEquals(Time.valueOf("05:33:12"), values[14].getValue()); + //datetimer + Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[15].getValue()); + //,timestampr + Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[16].getValue()); + //yearr + Assert.assertEquals(1986, values[17].getValue()); } } From 4c466573a7e9787ae8618ea16864865e72bbfdd6 Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 22:36:04 +0800 Subject: [PATCH 09/17] add unsigned test --- .../java/org/adbcj/mysql/netty/TestType.java | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java index c7bda572..56a7cfe9 100644 --- a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java @@ -2,6 +2,7 @@ import java.io.InputStream; import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.Blob; import java.sql.Date; import java.sql.Time; @@ -37,10 +38,10 @@ public void prepare() throws Exception { Connection connection = cm.connect().get(); DbSessionFuture result = connection.executeUpdate("delete from type_test"); Assert.assertTrue(result.get().getAffectedRows() > -1); - String sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,tinyintr," - + "smallintr,mediumintr,bitr,bigintr,floatr,doubler," - + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,'varch','char','lob',100,4," - + "1,100,b'0',1000000,1.1,2.2,1000.1," + DATE + "," + DATE + "," + DATE + "," + DATE + "," + DATE + String sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,'varch','char','lob',100,100,4,4," + + "1,1,100,100,b'0',1000000,1000000,1.1,2.2,1000.1," + DATE + "," + DATE + "," + DATE + "," + DATE + "," + DATE + ")"; result = connection.executeUpdate(sql); Assert.assertTrue(result.get().getAffectedRows() > -1); @@ -54,8 +55,8 @@ public void tear() throws Exception { @Test public void testType() throws Exception { Connection connection = cm.connect().get(); - DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,tinyintr," - + "smallintr,mediumintr,bitr,bigintr,floatr,doubler," + DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + "decimalr,dater,timer,datetimer,timestampr,yearr from type_test"); ResultSet r = result.get(); Row row = r.iterator().next(); @@ -74,32 +75,43 @@ public void testType() throws Exception { Assert.assertEquals("lob", str); // ,integerr 100 Assert.assertEquals(100, values[4].getValue()); + // ,integerr_unsign 100 + Assert.assertEquals(100l, values[5].getValue()); // ,tinyintr, 4 - Assert.assertEquals(Integer.valueOf("4"), values[5].getValue()); + Assert.assertEquals(Integer.valueOf("4"), values[6].getValue()); + // ,tinyintr_unsign, 4 + Assert.assertEquals(Integer.valueOf("4"), values[7].getValue()); + // "smallintr - Assert.assertEquals(1, values[6].getValue()); + Assert.assertEquals(1, values[8].getValue()); + // "smallintr_unsign + Assert.assertEquals(1, values[9].getValue()); // ,mediumintr 100 - Assert.assertEquals(100, values[7].getValue()); + Assert.assertEquals(100, values[10].getValue()); + // ,mediumintr_unsign 100 + Assert.assertEquals(100, values[11].getValue()); // ,bitr, 0 - Assert.assertEquals(Byte.valueOf("0").byteValue(), (byte)((byte[])values[8].getValue())[0]); + Assert.assertEquals(Byte.valueOf("0").byteValue(), (byte)((byte[])values[12].getValue())[0]); // bigintr 1000000 - Assert.assertEquals(1000000l, values[9].getValue()); + Assert.assertEquals(1000000l, values[13].getValue()); + // bigintr 1000000 + Assert.assertEquals(BigInteger.valueOf(1000000l), values[14].getValue()); // ,floatr - Assert.assertEquals(1.1f, values[10].getValue()); + Assert.assertEquals(1.1f, values[15].getValue()); // ,doubler," 2.2 - Assert.assertEquals(2.2d, values[11].getValue()); + Assert.assertEquals(2.2d, values[16].getValue()); // + "decimalr, - Assert.assertEquals(BigDecimal.valueOf(1000l), values[12].getValue()); + Assert.assertEquals(BigDecimal.valueOf(1000l), values[17].getValue()); // dater - Assert.assertEquals(Date.valueOf("1986-03-22"), values[13].getValue()); + Assert.assertEquals(Date.valueOf("1986-03-22"), values[18].getValue()); //timer - Assert.assertEquals(Time.valueOf("05:33:12"), values[14].getValue()); + Assert.assertEquals(Time.valueOf("05:33:12"), values[19].getValue()); //datetimer - Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[15].getValue()); + Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[20].getValue()); //,timestampr - Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[16].getValue()); + Assert.assertEquals(Timestamp.valueOf("1986-03-22 05:33:12"), values[21].getValue()); //yearr - Assert.assertEquals(1986, values[17].getValue()); + Assert.assertEquals(1986, values[22].getValue()); } } From 42bc40fa66a8e79796b34e0a5202309459c0ee11 Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 23:00:32 +0800 Subject: [PATCH 10/17] add null test for mysql --- .gitignore | 3 +- .../java/org/adbcj/mysql/netty/TestType.java | 89 +++++++++++++++++-- .../org/adbcj/mysql/netty/createTable.sql | 5 ++ 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 924d2ffc..1abfe0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ target/ *.project .settings/ -*.classpath \ No newline at end of file +*.classpath +test-output/ \ No newline at end of file diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java index 56a7cfe9..efdbbd6f 100644 --- a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java @@ -18,7 +18,7 @@ import org.adbcj.ResultSet; import org.adbcj.Row; import org.adbcj.Value; -import org.testng.annotations.BeforeMethod; +import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; public class TestType { @@ -33,8 +33,7 @@ public class TestType { ""); public static final String DATE = "'1986-03-22 05:33:12'"; - @BeforeMethod - public void prepare() throws Exception { + public void prepare_notNull() throws Exception { Connection connection = cm.connect().get(); DbSessionFuture result = connection.executeUpdate("delete from type_test"); Assert.assertTrue(result.get().getAffectedRows() > -1); @@ -47,13 +46,93 @@ public void prepare() throws Exception { Assert.assertTrue(result.get().getAffectedRows() > -1); connection.close(true); } - + + public void prepare_Null() throws Exception { + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeUpdate("delete from type_test"); + Assert.assertTrue(result.get().getAffectedRows() > -1); + String sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,NULL,NULL,NULL,NULL,NULL,NULL,NULL," + + "NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL" + + ")"; + result = connection.executeUpdate(sql); + Assert.assertTrue(result.get().getAffectedRows() > -1); + connection.close(true); + } + + @AfterMethod public void tear() throws Exception { - + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeUpdate("delete from type_test"); + Assert.assertTrue(result.get().getAffectedRows() > -1); + connection.close(true); } + + @Test + public void testNull() throws Exception { + prepare_Null(); + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr from type_test"); + ResultSet r = result.get(); + Row row = r.iterator().next(); + Value[] values = row.getValues(); + // pk + Assert.assertEquals(0, values[0].getValue()); + // varcharr varch + Assert.assertEquals(null, values[1].getValue()); + Assert.assertTrue(values[1].isNull()); + // charr 'char' + Assert.assertEquals(null, values[2].getValue()); + // blobr 'lob' + Assert.assertEquals(null, values[3].getValue()); + // ,integerr 100 + Assert.assertEquals(null, values[4].getValue()); + // ,integerr_unsign 100 + Assert.assertEquals(null, values[5].getValue()); + + // ,tinyintr, 4 + Assert.assertEquals(null, values[6].getValue()); + // ,tinyintr_unsign, 4 + Assert.assertEquals(null, values[7].getValue()); + + // "smallintr + Assert.assertEquals(null, values[8].getValue()); + // "smallintr_unsign + Assert.assertEquals(null, values[9].getValue()); + // ,mediumintr 100 + Assert.assertEquals(null, values[10].getValue()); + // ,mediumintr_unsign 100 + Assert.assertEquals(null, values[11].getValue()); + // ,bitr, 0 + Assert.assertEquals(null, ((byte[])values[12].getValue())); + // bigintr 1000000 + Assert.assertEquals(null, values[13].getValue()); + // bigintr 1000000 + Assert.assertEquals(null, values[14].getValue()); + // ,floatr + Assert.assertEquals(null, values[15].getValue()); + // ,doubler," 2.2 + Assert.assertEquals(null, values[16].getValue()); + // + "decimalr, + Assert.assertEquals(null, values[17].getValue()); + // dater + Assert.assertEquals(null, values[18].getValue()); + //timer + Assert.assertEquals(null, values[19].getValue()); + //datetimer + Assert.assertEquals(null, values[20].getValue()); + //,timestampr + Assert.assertEquals(null, values[21].getValue()); + //yearr + Assert.assertEquals(null, values[22].getValue()); + } @Test public void testType() throws Exception { + prepare_notNull(); Connection connection = cm.connect().get(); DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql b/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql index edfb127c..a796a5eb 100644 --- a/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/createTable.sql @@ -5,11 +5,16 @@ CREATE TABLE `type_test` ( `charr` char(255) DEFAULT NULL, `blobr` blob, `integerr` int(11) DEFAULT NULL, + `integerr_unsigned` int(11) UNSIGNED DEFAULT NULL, `tinyintr` tinyint(4) DEFAULT NULL, + `tinyintr_unsigned` tinyint(4) UNSIGNED DEFAULT NULL, `smallintr` smallint(6) DEFAULT NULL, + `smallintr_unsigned` smallint(6) UNSIGNED DEFAULT NULL, `mediumintr` mediumint(9) DEFAULT NULL, + `mediumintr_unsigned` mediumint(9) UNSIGNED DEFAULT NULL, `bitr` bit(1) DEFAULT NULL, `bigintr` bigint(20) DEFAULT NULL, + `bigintr_unsigned` bigint(20) UNSIGNED DEFAULT NULL, `floatr` float DEFAULT NULL, `doubler` double DEFAULT NULL, `decimalr` decimal(10,0) DEFAULT NULL, From 91c630dfa545e71dcf5a64a270f53c6f4f73dc2c Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 23:42:08 +0800 Subject: [PATCH 11/17] revert to original code style and add some override annotations --- .../org/adbcj/ConnectionManagerProvider.java | 11 +- .../main/java/org/adbcj/ConnectionPool.java | 186 +++++++++--------- .../org/adbcj/jdbc/JdbcConnectionManager.java | 2 + .../jdbc/JdbcConnectionManagerFactory.java | 3 +- .../adbcj/mysql/mina/MysqlMessageEncoder.java | 2 + .../netty/MySqlConnectionManagerFactory.java | 4 +- mysql/netty/src/test/java/Test.java | 2 +- pom.xml | 2 +- .../mina/MinaConnectionManager.java | 50 +++-- .../netty/NettyConnectionManager.java | 79 ++++---- 10 files changed, 170 insertions(+), 171 deletions(-) diff --git a/api/src/main/java/org/adbcj/ConnectionManagerProvider.java b/api/src/main/java/org/adbcj/ConnectionManagerProvider.java index 0dcc9f26..8b0c9937 100644 --- a/api/src/main/java/org/adbcj/ConnectionManagerProvider.java +++ b/api/src/main/java/org/adbcj/ConnectionManagerProvider.java @@ -25,16 +25,13 @@ public class ConnectionManagerProvider { public static final String ADBCJ_PROTOCOL = "adbcj"; - private ConnectionManagerProvider(){ - } + private ConnectionManagerProvider () {} - public static ConnectionManager createConnectionManager(String url, String username, String password) - throws DbException { + public static ConnectionManager createConnectionManager(String url, String username, String password) throws DbException { return createConnectionManager(url, username, password, null); } - public static ConnectionManager createConnectionManager(String url, String username, String password, - Properties properties) throws DbException { + public static ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) throws DbException { if (url == null) { throw new IllegalArgumentException("Connection url can not be null"); } @@ -60,4 +57,4 @@ public static ConnectionManager createConnectionManager(String url, String usern } } -} +} \ No newline at end of file diff --git a/api/src/main/java/org/adbcj/ConnectionPool.java b/api/src/main/java/org/adbcj/ConnectionPool.java index 86e9a3b0..4ad4e157 100644 --- a/api/src/main/java/org/adbcj/ConnectionPool.java +++ b/api/src/main/java/org/adbcj/ConnectionPool.java @@ -4,106 +4,106 @@ //********************************************************************* package org.adbcj; -import org.adbcj.support.DefaultDbFuture; -import org.adbcj.support.DefaultDbSessionFuture; - import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; +import org.adbcj.support.DefaultDbFuture; +import org.adbcj.support.DefaultDbSessionFuture; + /** * @author Mike Heath */ public class ConnectionPool implements DbSessionProvider { - private final Queue sessions = new ConcurrentLinkedQueue(); - private final ConnectionManager connectionManager; - private final AtomicInteger count = new AtomicInteger(0); - - public ConnectionPool(ConnectionManager connectionManager) { - this.connectionManager = connectionManager; - } - - public void addConnection() { - sessions.add(connectionManager.connect().getUninterruptably()); - count.incrementAndGet(); - System.out.println("Pool size at: " + count.get()); - } - - public void setPoolSize(int size) { - if (size < count.get()) { - throw new IllegalArgumentException("Can't decrease pool size."); - } - while (count.get() < size) { - addConnection(); - } - } - - - public DbFuture connect() { - final DbSession session = sessions.poll(); - if (session == null) { - throw new IllegalStateException("No connections available in pool"); - } - DefaultDbFuture future = new DefaultDbFuture(); - future.setResult(new DbSession() { - - - public void beginTransaction() { - session.beginTransaction(); - } - - - public DbSessionFuture commit() { - return session.commit(); - } - - - public DbSessionFuture rollback() { - return session.rollback(); - } - - - public boolean isInTransaction() { - return session.isInTransaction(); - } - - - public DbSessionFuture executeQuery(String sql) { - return session.executeQuery(sql); - } - - - public DbSessionFuture executeQuery(String sql, ResultEventHandler eventHandler, T accumulator) { - return session.executeQuery(sql, eventHandler, accumulator); - } - - - public DbSessionFuture executeUpdate(String sql) { - return session.executeUpdate(sql); - } - - - public DbSessionFuture prepareStatement(String sql) { - return session.prepareStatement(sql); - } - - - public DbSessionFuture prepareStatement(Object key, String sql) { - return session.prepareStatement(key, sql); - } - - - public DbSessionFuture close(boolean immediate) throws DbException { - sessions.add(session); - return DefaultDbSessionFuture.createCompletedFuture(this, null); - } - - - public boolean isClosed() throws DbException { - return false; - } - }); - return future; - } + private final Queue sessions = new ConcurrentLinkedQueue(); + private final ConnectionManager connectionManager; + private final AtomicInteger count = new AtomicInteger(0); + + public ConnectionPool(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + + public void addConnection() { + sessions.add(connectionManager.connect().getUninterruptably()); + count.incrementAndGet(); + System.out.println("Pool size at: " + count.get()); + } + + public void setPoolSize(int size) { + if (size < count.get()) { + throw new IllegalArgumentException("Can't decrease pool size."); + } + while (count.get() < size) { + addConnection(); + } + } + + @Override + public DbFuture connect() { + final DbSession session = sessions.poll(); + if (session == null) { + throw new IllegalStateException("No connections available in pool"); + } + DefaultDbFuture future = new DefaultDbFuture(); + future.setResult(new DbSession() { + + @Override + public void beginTransaction() { + session.beginTransaction(); + } + + @Override + public DbSessionFuture commit() { + return session.commit(); + } + + @Override + public DbSessionFuture rollback() { + return session.rollback(); + } + + @Override + public boolean isInTransaction() { + return session.isInTransaction(); + } + + @Override + public DbSessionFuture executeQuery(String sql) { + return session.executeQuery(sql); + } + + @Override + public DbSessionFuture executeQuery(String sql, ResultEventHandler eventHandler, T accumulator) { + return session.executeQuery(sql, eventHandler, accumulator); + } + + @Override + public DbSessionFuture executeUpdate(String sql) { + return session.executeUpdate(sql); + } + + @Override + public DbSessionFuture prepareStatement(String sql) { + return session.prepareStatement(sql); + } + + @Override + public DbSessionFuture prepareStatement(Object key, String sql) { + return session.prepareStatement(key, sql); + } + + @Override + public DbSessionFuture close(boolean immediate) throws DbException { + sessions.add(session); + return DefaultDbSessionFuture.createCompletedFuture(this, null); + } + + @Override + public boolean isClosed() throws DbException { + return false; + } + }); + return future; + } } \ No newline at end of file diff --git a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java index 2a98a57b..fdf62c6d 100644 --- a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java +++ b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java @@ -105,6 +105,7 @@ public DbFuture close(boolean immediate) throws DbException { if (closeFuture == null) { closeFuture = new DefaultDbFuture(); closeFuture.addListener(new DbListener() { + @Override public void onCompletion(DbFuture future) throws Exception { executorService.shutdown(); } @@ -117,6 +118,7 @@ public void onCompletion(DbFuture future) throws Exception { final AtomicBoolean allClosed = new AtomicBoolean(false); DbListener listener = new DbListener() { + @Override public void onCompletion(DbFuture future) { try { int count = countDown.decrementAndGet(); diff --git a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java index 08332f72..0ec97854 100644 --- a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java +++ b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManagerFactory.java @@ -43,7 +43,8 @@ public ConnectionManager createConnectionManager(String url, String username, St throw new DbException(e); } } - + + @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java index 040fab80..cea5b8ad 100644 --- a/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java +++ b/mysql/mina/src/main/java/org/adbcj/mysql/mina/MysqlMessageEncoder.java @@ -31,10 +31,12 @@ public class MysqlMessageEncoder implements ProtocolEncoder { private final MySqlClientEncoder encoder = new MySqlClientEncoder(); + @Override public void dispose(IoSession session) throws Exception { // Nothing to dispose } + @Override public void encode(IoSession session, Object message, ProtocolEncoderOutput encoderOut) throws Exception { IoBuffer buffer = IoBuffer.allocate(1024); OutputStream out = buffer.asOutputStream(); diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java index 9d49f30e..dfbbc68b 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MySqlConnectionManagerFactory.java @@ -13,7 +13,7 @@ public class MySqlConnectionManagerFactory implements ConnectionManagerFactory { public static final String PROTOCOL = "mysqlnetty"; public static final int DEFAULT_PORT = 3306; - + @Override public ConnectionManager createConnectionManager(String url, String username, String password, Properties properties) throws DbException { String host = null; int port = 0; @@ -45,7 +45,7 @@ public ConnectionManager createConnectionManager(String url, String username, St } - + @Override public boolean canHandle(String protocol) { return PROTOCOL.equals(protocol); } diff --git a/mysql/netty/src/test/java/Test.java b/mysql/netty/src/test/java/Test.java index c4dd3c55..9b686be4 100644 --- a/mysql/netty/src/test/java/Test.java +++ b/mysql/netty/src/test/java/Test.java @@ -7,7 +7,7 @@ public class Test { public static void main(String[] args) throws DbException, Exception { - ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:pooledMysqlnetty://localhost/test", "foo", "dawg"); + ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:mysqlnetty://localhost/test", "foo", "dawg"); Connection connection = cm.connect().get(); connection.close(true); } diff --git a/pom.xml b/pom.xml index 26b254b8..df7c5ef0 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ maven-compiler-plugin - 1.7 + 1.6 1.6 true diff --git a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java index fbd20581..0b705414 100644 --- a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java +++ b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java @@ -1,37 +1,35 @@ package org.adbcj.postgresql.mina; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.util.Properties; + +import org.adbcj.Connection; +import org.adbcj.DbException; +import org.adbcj.DbFuture; import org.adbcj.postgresql.codec.AbstractConnectionManager; -import org.adbcj.postgresql.codec.backend.BackendMessageDecoder; import org.adbcj.postgresql.codec.backend.AbstractBackendMessage; -import org.adbcj.postgresql.codec.frontend.FrontendMessageEncoder; +import org.adbcj.postgresql.codec.backend.BackendMessageDecoder; import org.adbcj.postgresql.codec.frontend.AbstractFrontendMessage; -import org.adbcj.postgresql.mina.IoHandler; -import org.adbcj.postgresql.mina.IoSessionUtil; -import org.adbcj.support.DefaultDbFuture; +import org.adbcj.postgresql.codec.frontend.FrontendMessageEncoder; import org.adbcj.support.DecoderInputStream; -import org.adbcj.Connection; -import org.adbcj.DbFuture; -import org.adbcj.DbException; -import org.apache.mina.core.session.IoSession; -import org.apache.mina.core.session.IoSessionInitializer; +import org.adbcj.support.DefaultDbFuture; +import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; import org.apache.mina.core.future.ConnectFuture; -import org.apache.mina.core.buffer.IoBuffer; -import org.apache.mina.filter.codec.ProtocolDecoder; +import org.apache.mina.core.session.IoSession; +import org.apache.mina.core.session.IoSessionInitializer; +import org.apache.mina.filter.codec.CumulativeProtocolDecoder; import org.apache.mina.filter.codec.ProtocolCodecFactory; -import org.apache.mina.filter.codec.ProtocolEncoder; import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.codec.ProtocolEncoderOutput; +import org.apache.mina.filter.codec.ProtocolDecoder; import org.apache.mina.filter.codec.ProtocolDecoderOutput; -import org.apache.mina.filter.codec.CumulativeProtocolDecoder; +import org.apache.mina.filter.codec.ProtocolEncoder; +import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Properties; -import java.net.InetSocketAddress; -import java.io.OutputStream; - /** * @author Mike Heath */ @@ -54,7 +52,7 @@ public ProtocolDecoder getDecoder(IoSession session) throws Exception { private final BackendMessageDecoder decoder = new BackendMessageDecoder(connection.getConnectionState()); - + @Override protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { DecoderInputStream inputStream = new DecoderInputStream(in.asInputStream()); while (true) { @@ -75,12 +73,12 @@ public ProtocolEncoder getEncoder(IoSession session) throws Exception { private final FrontendMessageEncoder encoder = new FrontendMessageEncoder(connection.getConnectionState()); - + @Override public void dispose(IoSession ioSession) throws Exception { // Do nothing. } - + @Override public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception { IoBuffer buffer = IoBuffer.allocate(4096); OutputStream out = buffer.asOutputStream(); @@ -136,7 +134,7 @@ class PgConnectFuture extends DefaultDbFuture implements IoSessionIn private boolean cancelled = false; private boolean started = false; - + @Override public synchronized void initializeSession(IoSession session, ConnectFuture future) { if (cancelled) { session.close(true); @@ -148,7 +146,7 @@ public synchronized void initializeSession(IoSession session, ConnectFuture futu IoSessionUtil.setConnection(session, connection); } - + @Override protected synchronized boolean doCancel(boolean mayInterruptIfRunning) { if (started) { logger.debug("Can't cancel, connection already started"); @@ -195,10 +193,10 @@ public void setPipeliningEnabled(boolean pipeliningEnabled) { // // ================================================================================================================ - + @Override public String toString() { return String.format("Postgresql (MINA) Connection Manager (Db: '%s', User: '%s')", getDatabase(), getUsername()); } -} +} \ No newline at end of file diff --git a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java index f83d3ff4..f32c98ba 100644 --- a/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java +++ b/postgresql/netty/src/main/java/org/adbcj/postgresql/netty/NettyConnectionManager.java @@ -1,47 +1,47 @@ package org.adbcj.postgresql.netty; -import org.adbcj.DbFuture; +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.Properties; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import org.adbcj.DbException; -import org.adbcj.support.DecoderInputStream; -import org.adbcj.support.DefaultDbFuture; +import org.adbcj.DbFuture; +import org.adbcj.postgresql.codec.AbstractConnection; import org.adbcj.postgresql.codec.AbstractConnectionManager; import org.adbcj.postgresql.codec.ConnectionState; -import org.adbcj.postgresql.codec.AbstractConnection; import org.adbcj.postgresql.codec.ProtocolHandler; -import org.adbcj.postgresql.codec.backend.BackendMessageDecoder; import org.adbcj.postgresql.codec.backend.AbstractBackendMessage; -import org.adbcj.postgresql.codec.frontend.FrontendMessageEncoder; +import org.adbcj.postgresql.codec.backend.BackendMessageDecoder; import org.adbcj.postgresql.codec.frontend.AbstractFrontendMessage; -import org.jboss.netty.channel.ChannelFactory; -import org.jboss.netty.channel.Channels; -import org.jboss.netty.channel.ChannelPipelineCoverage; -import org.jboss.netty.channel.ChannelHandlerContext; +import org.adbcj.postgresql.codec.frontend.FrontendMessageEncoder; +import org.adbcj.support.DecoderInputStream; +import org.adbcj.support.DefaultDbFuture; +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBufferInputStream; +import org.jboss.netty.buffer.ChannelBufferOutputStream; +import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelDownstreamHandler; import org.jboss.netty.channel.ChannelEvent; -import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.SimpleChannelHandler; -import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; -import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.handler.codec.frame.FrameDecoder; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBufferInputStream; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.net.InetSocketAddress; -import java.io.InputStream; - /** * @author Mike Heath */ @@ -86,7 +86,7 @@ private ClientBootstrap initBootstrap(ChannelFactory channelFactory, String host } - + @Override public DbFuture connect() { if (isClosed()) { throw new DbException("Connection manager is closed"); @@ -95,7 +95,7 @@ public DbFuture connect() { return new PostgresqlConnectFuture(channelFuture); } - + @Override public DbFuture close(boolean immediate) throws DbException { if (isClosed()) { return closeFuture; @@ -117,19 +117,19 @@ public DbFuture close(boolean immediate) throws DbException { } } - + @Override public boolean isClosed() { synchronized (this) { return closeFuture != null; } } - + @Override public boolean isPipeliningEnabled() { return pipeliningEnabled; } - + @Override public void setPipeliningEnabled(boolean pipeliningEnabled) { this.pipeliningEnabled = pipeliningEnabled; } @@ -141,7 +141,7 @@ private class PostgresqlConnectFuture extends DefaultDbFuture getConnectFuture() { return connectFuture; } - + @Override protected boolean isConnectionClosing() { return !channel.isOpen(); } - + @Override protected void write(AbstractFrontendMessage message) { channel.write(message); } - + @Override protected void write(AbstractFrontendMessage[] messages) { channel.write(messages); } @@ -209,17 +209,17 @@ class Handler extends SimpleChannelHandler { this.protocolHandler = protocolHandler; } - + @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { protocolHandler.handleMessage(connection, (AbstractBackendMessage) e.getMessage()); } - + @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { protocolHandler.handleException(connection, e.getCause()); } - + @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { protocolHandler.closeConnection(connection); } @@ -236,7 +236,7 @@ class Decoder extends FrameDecoder { this.decoder = new BackendMessageDecoder(state); } - + @Override protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { InputStream in = new ChannelBufferInputStream(buffer); DecoderInputStream dis = new DecoderInputStream(in); @@ -283,4 +283,3 @@ public void handleDownstream(ChannelHandlerContext context, ChannelEvent event) Channels.write(context, e.getFuture(), buffer); } } - From 5dd002a450f8ba7710996d218fa4f478cc656d1d Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 23:49:14 +0800 Subject: [PATCH 12/17] add override --- .../org/adbcj/jdbc/JdbcConnectionManager.java | 16 +- .../mysql/netty/MessageQueuingHandler.java | 2 +- .../mina/MinaConnectionManager.java | 326 +++++++++--------- 3 files changed, 172 insertions(+), 172 deletions(-) diff --git a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java index fdf62c6d..66269414 100644 --- a/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java +++ b/jdbc/src/main/java/org/adbcj/jdbc/JdbcConnectionManager.java @@ -40,14 +40,14 @@ public class JdbcConnectionManager implements ConnectionManager { private static final Object USER = "user"; private static final Object PASSWORD = "password"; - + private final String jdbcUrl; private final Properties properties; private final ExecutorService executorService; private final Object lock = this; private final Set connections = new HashSet(); // Access must be synchronized on lock - + private volatile DefaultDbFuture closeFuture; private volatile boolean pipeliningEnabled = false; @@ -105,7 +105,7 @@ public DbFuture close(boolean immediate) throws DbException { if (closeFuture == null) { closeFuture = new DefaultDbFuture(); closeFuture.addListener(new DbListener() { - @Override + @Override public void onCompletion(DbFuture future) throws Exception { executorService.shutdown(); } @@ -116,9 +116,9 @@ public void onCompletion(DbFuture future) throws Exception { } final AtomicInteger countDown = new AtomicInteger(); final AtomicBoolean allClosed = new AtomicBoolean(false); - + DbListener listener = new DbListener() { - @Override + @Override public void onCompletion(DbFuture future) { try { int count = countDown.decrementAndGet(); @@ -154,7 +154,7 @@ public boolean isClosed() { * Non API Method * */ - + public ExecutorService getExecutorService() { return executorService; } @@ -177,5 +177,5 @@ public void setPipeliningEnabled(boolean pipeliningEnabled) { public String toString() { return String.format("%s: %s (user: %s)", getClass().getName(), jdbcUrl, properties.get(USER)); } - -} + +} \ No newline at end of file diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java index 108d3d65..6d6c339d 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MessageQueuingHandler.java @@ -19,7 +19,7 @@ class MessageQueuingHandler implements ChannelUpstreamHandler { // Access must be synchronized on this private boolean flushed = false; - + @Override public synchronized void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (!flushed) { diff --git a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java index 0b705414..0088c558 100644 --- a/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java +++ b/postgresql/mina/src/main/java/org/adbcj/postgresql/mina/MinaConnectionManager.java @@ -34,169 +34,169 @@ * @author Mike Heath */ public class MinaConnectionManager extends AbstractConnectionManager { - public static final String CODEC_NAME = AbstractConnectionManager.class.getName() + ".codec"; - - private final Logger logger = LoggerFactory.getLogger(AbstractConnectionManager.class); - - private final NioSocketConnector socketConnector; - - // Access must be synchronized on 'this' - private DefaultDbFuture closeFuture = null; - - private volatile boolean pipeliningEnabled = true; - - private static final ProtocolCodecFactory CODEC_FACTORY = new ProtocolCodecFactory() { - public ProtocolDecoder getDecoder(IoSession session) throws Exception { - final MinaConnection connection = IoSessionUtil.getConnection(session); - return new CumulativeProtocolDecoder() { - - private final BackendMessageDecoder decoder = new BackendMessageDecoder(connection.getConnectionState()); - - @Override - protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { - DecoderInputStream inputStream = new DecoderInputStream(in.asInputStream()); - while (true) { - inputStream.setLimit(Integer.MAX_VALUE); - AbstractBackendMessage message = decoder.decode(inputStream, false); - if (message == null) { - return false; - } - out.write(message); - } - } - - }; - } - public ProtocolEncoder getEncoder(IoSession session) throws Exception { - final MinaConnection connection = IoSessionUtil.getConnection(session); - return new ProtocolEncoder() { - - private final FrontendMessageEncoder encoder = new FrontendMessageEncoder(connection.getConnectionState()); - - @Override - public void dispose(IoSession ioSession) throws Exception { - // Do nothing. - } - - @Override - public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception { - IoBuffer buffer = IoBuffer.allocate(4096); - OutputStream out = buffer.asOutputStream(); - if (o instanceof AbstractFrontendMessage) { - encoder.encode(out, (AbstractFrontendMessage)o); - } else if (o instanceof AbstractFrontendMessage[]) { - encoder.encode(out, (AbstractFrontendMessage[])o); - } else { - throw new IllegalStateException("Unkown message type for: " + o); - } - out.close(); - buffer.flip(); - protocolEncoderOutput.write(buffer); - protocolEncoderOutput.flush(); - } - }; - } - }; - - public MinaConnectionManager(String host, int port, String username, String password, String database, - Properties properties) { - super(username, password, database); - logger.debug("Creating new Postgresql ConnectionManager"); - - socketConnector = new NioSocketConnector(); - - socketConnector.getSessionConfig().setTcpNoDelay(true); - DefaultIoFilterChainBuilder filterChain = socketConnector.getFilterChain(); - - filterChain.addLast(CODEC_NAME, new ProtocolCodecFilter(CODEC_FACTORY)); - - socketConnector.setHandler(new IoHandler(this)); - - InetSocketAddress address = new InetSocketAddress(host, port); - socketConnector.setDefaultRemoteAddress(address); - } - - public DbFuture connect() { - if (isClosed()) { - throw new DbException("Connection manager closed"); - } - logger.debug("Starting connection"); - PgConnectFuture future = new PgConnectFuture(); - socketConnector.connect(future); - - logger.debug("Started connection"); - - return future; - } - - class PgConnectFuture extends DefaultDbFuture implements IoSessionInitializer { - - private boolean cancelled = false; - private boolean started = false; - - @Override - public synchronized void initializeSession(IoSession session, ConnectFuture future) { - if (cancelled) { - session.close(true); - return; - } - logger.debug("Creating AbstractConnection"); - - MinaConnection connection = new MinaConnection(MinaConnectionManager.this, this, session); - IoSessionUtil.setConnection(session, connection); - } - - @Override - protected synchronized boolean doCancel(boolean mayInterruptIfRunning) { - if (started) { - logger.debug("Can't cancel, connection already started"); - return false; - } - logger.debug("Cancelled connect"); - cancelled = true; - return true; - } - - } - - public synchronized DbFuture close(boolean immediate) throws DbException { - // TODO Put test in TCK to make sure all ConnectionManager connections get closed - if (isClosed()) { - return closeFuture; - } - closeFuture = new DefaultDbFuture(); - if (immediate) { - socketConnector.dispose(); - closeFuture.setResult(null); - } else { - // TODO Implement MinaConnectionManager.close(boolean) - throw new IllegalStateException("Non immediate finalizeClose not yet implemented"); - } - return closeFuture; - } - - public synchronized boolean isClosed() { - return closeFuture != null; - } - - public boolean isPipeliningEnabled() { - return pipeliningEnabled; - } - - public void setPipeliningEnabled(boolean pipeliningEnabled) { - this.pipeliningEnabled = pipeliningEnabled; - } - - // ================================================================================================================ - // - // Non-API methods - // - // ================================================================================================================ - - @Override - public String toString() { - return String.format("Postgresql (MINA) Connection Manager (Db: '%s', User: '%s')", getDatabase(), getUsername()); - } + public static final String CODEC_NAME = AbstractConnectionManager.class.getName() + ".codec"; + + private final Logger logger = LoggerFactory.getLogger(AbstractConnectionManager.class); + + private final NioSocketConnector socketConnector; + + // Access must be synchronized on 'this' + private DefaultDbFuture closeFuture = null; + + private volatile boolean pipeliningEnabled = true; + + private static final ProtocolCodecFactory CODEC_FACTORY = new ProtocolCodecFactory() { + public ProtocolDecoder getDecoder(IoSession session) throws Exception { + final MinaConnection connection = IoSessionUtil.getConnection(session); + return new CumulativeProtocolDecoder() { + + private final BackendMessageDecoder decoder = new BackendMessageDecoder(connection.getConnectionState()); + + @Override + protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { + DecoderInputStream inputStream = new DecoderInputStream(in.asInputStream()); + while (true) { + inputStream.setLimit(Integer.MAX_VALUE); + AbstractBackendMessage message = decoder.decode(inputStream, false); + if (message == null) { + return false; + } + out.write(message); + } + } + + }; + } + public ProtocolEncoder getEncoder(IoSession session) throws Exception { + final MinaConnection connection = IoSessionUtil.getConnection(session); + return new ProtocolEncoder() { + + private final FrontendMessageEncoder encoder = new FrontendMessageEncoder(connection.getConnectionState()); + + @Override + public void dispose(IoSession ioSession) throws Exception { + // Do nothing. + } + + @Override + public void encode(IoSession ioSession, Object o, ProtocolEncoderOutput protocolEncoderOutput) throws Exception { + IoBuffer buffer = IoBuffer.allocate(4096); + OutputStream out = buffer.asOutputStream(); + if (o instanceof AbstractFrontendMessage) { + encoder.encode(out, (AbstractFrontendMessage)o); + } else if (o instanceof AbstractFrontendMessage[]) { + encoder.encode(out, (AbstractFrontendMessage[])o); + } else { + throw new IllegalStateException("Unkown message type for: " + o); + } + out.close(); + buffer.flip(); + protocolEncoderOutput.write(buffer); + protocolEncoderOutput.flush(); + } + }; + } + }; + + public MinaConnectionManager(String host, int port, String username, String password, String database, + Properties properties) { + super(username, password, database); + logger.debug("Creating new Postgresql ConnectionManager"); + + socketConnector = new NioSocketConnector(); + + socketConnector.getSessionConfig().setTcpNoDelay(true); + DefaultIoFilterChainBuilder filterChain = socketConnector.getFilterChain(); + + filterChain.addLast(CODEC_NAME, new ProtocolCodecFilter(CODEC_FACTORY)); + + socketConnector.setHandler(new IoHandler(this)); + + InetSocketAddress address = new InetSocketAddress(host, port); + socketConnector.setDefaultRemoteAddress(address); + } + + public DbFuture connect() { + if (isClosed()) { + throw new DbException("Connection manager closed"); + } + logger.debug("Starting connection"); + PgConnectFuture future = new PgConnectFuture(); + socketConnector.connect(future); + + logger.debug("Started connection"); + + return future; + } + + class PgConnectFuture extends DefaultDbFuture implements IoSessionInitializer { + + private boolean cancelled = false; + private boolean started = false; + + @Override + public synchronized void initializeSession(IoSession session, ConnectFuture future) { + if (cancelled) { + session.close(true); + return; + } + logger.debug("Creating AbstractConnection"); + + MinaConnection connection = new MinaConnection(MinaConnectionManager.this, this, session); + IoSessionUtil.setConnection(session, connection); + } + + @Override + protected synchronized boolean doCancel(boolean mayInterruptIfRunning) { + if (started) { + logger.debug("Can't cancel, connection already started"); + return false; + } + logger.debug("Cancelled connect"); + cancelled = true; + return true; + } + + } + + public synchronized DbFuture close(boolean immediate) throws DbException { + // TODO Put test in TCK to make sure all ConnectionManager connections get closed + if (isClosed()) { + return closeFuture; + } + closeFuture = new DefaultDbFuture(); + if (immediate) { + socketConnector.dispose(); + closeFuture.setResult(null); + } else { + // TODO Implement MinaConnectionManager.close(boolean) + throw new IllegalStateException("Non immediate finalizeClose not yet implemented"); + } + return closeFuture; + } + + public synchronized boolean isClosed() { + return closeFuture != null; + } + + public boolean isPipeliningEnabled() { + return pipeliningEnabled; + } + + public void setPipeliningEnabled(boolean pipeliningEnabled) { + this.pipeliningEnabled = pipeliningEnabled; + } + + // ================================================================================================================ + // + // Non-API methods + // + // ================================================================================================================ + + @Override + public String toString() { + return String.format("Postgresql (MINA) Connection Manager (Db: '%s', User: '%s')", getDatabase(), getUsername()); + } } \ No newline at end of file From 3ac0f1234e0521c03f69ac334909dc08aba9c12b Mon Sep 17 00:00:00 2001 From: shenxun Date: Wed, 3 Jul 2013 23:57:22 +0800 Subject: [PATCH 13/17] add exception test --- .../org/adbcj/mysql/netty/ExceptionTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 mysql/netty/src/test/java/org/adbcj/mysql/netty/ExceptionTest.java diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/ExceptionTest.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/ExceptionTest.java new file mode 100644 index 00000000..6ec3e800 --- /dev/null +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/ExceptionTest.java @@ -0,0 +1,54 @@ +package org.adbcj.mysql.netty; + +import junit.framework.Assert; + +import org.adbcj.Connection; +import org.adbcj.ConnectionManager; +import org.adbcj.ConnectionManagerProvider; +import org.adbcj.DbSessionFuture; +import org.adbcj.Result; +import org.adbcj.ResultSet; +import org.testng.annotations.Test; + + +public class ExceptionTest { + + public static ConnectionManager cm = ConnectionManagerProvider.createConnectionManager("adbcj:mysqlnetty://localhost/unit_test", + "root", + ""); + public static final String DATE = "'1986-03-22 05:33:12'"; + + @Test + public void test_duplicate_exception() throws Exception { + Connection connection = cm.connect().get(); + DbSessionFuture result = connection.executeUpdate("delete from type_test"); + Assert.assertTrue(result.get().getAffectedRows() > -1); + String sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,'varch','char','lob',100,100,4,4," + + "1,1,100,100,b'0',1000000,1000000,1.1,2.2,1000.1," + DATE + "," + DATE + "," + DATE + "," + DATE + "," + DATE + + ")"; + result = connection.executeUpdate(sql); + Assert.assertTrue(result.get().getAffectedRows() > -1); + + sql = "insert into type_test (" + "pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr) values (" + "0,'varch','char','lob',100,100,4,4," + + "1,1,100,100,b'0',1000000,1000000,1.1,2.2,1000.1," + DATE + "," + DATE + "," + DATE + "," + DATE + "," + DATE + + ")"; + result = connection.executeUpdate(sql); + try { + Assert.assertTrue(result.get().getAffectedRows() > -1); + Assert.fail(); + } catch (Exception e) { + Assert.assertEquals("org.adbcj.mysql.codec.MysqlException: 23000Duplicate entry '0' for key 'PRIMARY'\n", e.getMessage()); + + } + + //make sure the connection can execute other request + sql = "select * from type_test"; + DbSessionFuture queryResult = connection.executeQuery(sql); + Assert.assertTrue(queryResult.get().size()>0); + connection.close(true); + } +} From ee553630538e95f2c8e4a4ef3c3979fd420ef948 Mon Sep 17 00:00:00 2001 From: shenxun Date: Sat, 6 Jul 2013 18:21:40 +0800 Subject: [PATCH 14/17] add prepared statment for adbcj --- .../mysql/codec/AbstractMySqlConnection.java | 11 +- .../org/adbcj/mysql/codec/FastDateFormat.java | 1522 +++++++++++++++++ .../org/adbcj/mysql/codec/FormatCache.java | 202 +++ .../mysql/codec/MysqlPreparedStatement.java | 133 ++ .../codec/MysqlPreparedStatementUnitTest.java | 61 + .../java/org/adbcj/mysql/netty/TestType.java | 10 +- 6 files changed, 1933 insertions(+), 6 deletions(-) create mode 100644 mysql/codec/src/main/java/org/adbcj/mysql/codec/FastDateFormat.java create mode 100644 mysql/codec/src/main/java/org/adbcj/mysql/codec/FormatCache.java create mode 100644 mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlPreparedStatement.java create mode 100644 mysql/codec/src/test/java/org/adbcj/mysql/codec/MysqlPreparedStatementUnitTest.java diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/AbstractMySqlConnection.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/AbstractMySqlConnection.java index d7211d66..ecd3446c 100644 --- a/mysql/codec/src/main/java/org/adbcj/mysql/codec/AbstractMySqlConnection.java +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/AbstractMySqlConnection.java @@ -14,6 +14,7 @@ import org.adbcj.ResultEventHandler; import org.adbcj.support.AbstractDbSession; import org.adbcj.support.DefaultDbFuture; +import org.adbcj.support.DefaultDbSessionFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,6 +31,8 @@ public abstract class AbstractMySqlConnection extends AbstractDbSession implemen private Request closeRequest; // Access must by synchronized on 'this' private MysqlCharacterSet charset = MysqlCharacterSet.LATIN1_SWEDISH_CI; + + private final FastDateFormat fastDateFormat; protected AbstractMySqlConnection(AbstractMySqlConnectionManager connectionManager, LoginCredentials credentials) { super(connectionManager.isPipeliningEnabled()); @@ -37,6 +40,8 @@ protected AbstractMySqlConnection(AbstractMySqlConnectionManager connectionManag this.credentials = credentials; this.id = connectionManager.nextId(); connectionManager.addConnection(this); + String format = "yyyy-MM-dd HH:mm:ss"; + fastDateFormat = FastDateFormat.getInstance(format); } public abstract void write(ClientRequest request); @@ -156,13 +161,13 @@ public String toString() { public DbSessionFuture prepareStatement(String sql) { checkClosed(); - // TODO Implement MySQL prepareStatement(String sql) - throw new IllegalStateException("Not yet implemented"); + PreparedStatement myPs = new MysqlPreparedStatement(sql, this, fastDateFormat); + DbSessionFuture dbFuture = DefaultDbSessionFuture.createCompletedFuture(this, myPs); + return dbFuture; } public DbSessionFuture prepareStatement(Object key, String sql) { checkClosed(); - // TODO Implement MySQL prepareStatement(Object key, String sql) throw new IllegalStateException("Not yet implemented"); } diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/FastDateFormat.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/FastDateFormat.java new file mode 100644 index 00000000..b6653810 --- /dev/null +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/FastDateFormat.java @@ -0,0 +1,1522 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.codec; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + *

FastDateFormat is a fast and thread-safe version of + * {@link java.text.SimpleDateFormat}.

+ * + *

This class can be used as a direct replacement to + * {@code SimpleDateFormat} in most formatting situations. + * This class is especially useful in multi-threaded server environments. + * {@code SimpleDateFormat} is not thread-safe in any JDK version, + * nor will it be as Sun have closed the bug/RFE. + *

+ * + *

Only formatting is supported, but all patterns are compatible with + * SimpleDateFormat (except time zones and some year patterns - see below).

+ * + *

Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent + * time zones in RFC822 format (eg. {@code +0800} or {@code -1100}). + * This pattern letter can be used here (on all JDK versions).

+ * + *

In addition, the pattern {@code 'ZZ'} has been made to represent + * ISO8601 full format time zones (eg. {@code +08:00} or {@code -11:00}). + * This introduces a minor incompatibility with Java 1.4, but at a gain of + * useful functionality.

+ * + *

Javadoc cites for the year pattern: For formatting, if the number of + * pattern letters is 2, the year is truncated to 2 digits; otherwise it is + * interpreted as a number. Starting with Java 1.7 a pattern of 'Y' or + * 'YYY' will be formatted as '2003', while it was '03' in former Java + * versions. FastDateFormat implements the behavior of Java 7.

+ * + * @since 2.0 + * @version $Id: FastDateFormat.java 1146138 2011-07-13 17:01:37Z joehni $ + */ +public class FastDateFormat extends Format { + // A lot of the speed in this class comes from caching, but some comes + // from the special int to StringBuffer conversion. + // + // The following produces a padded 2 digit number: + // buffer.append((char)(value / 10 + '0')); + // buffer.append((char)(value % 10 + '0')); + // + // Note that the fastest append to StringBuffer is a single char (used here). + // Note that Integer.toString() is not called, the conversion is simply + // taking the value and adding (mathematically) the ASCII value for '0'. + // So, don't change this code! It works and is very fast. + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + * FULL locale dependent date or time style. + */ + public static final int FULL = DateFormat.FULL; + /** + * LONG locale dependent date or time style. + */ + public static final int LONG = DateFormat.LONG; + /** + * MEDIUM locale dependent date or time style. + */ + public static final int MEDIUM = DateFormat.MEDIUM; + /** + * SHORT locale dependent date or time style. + */ + public static final int SHORT = DateFormat.SHORT; + + private static final FormatCache cache= new FormatCache() { + @Override + protected FastDateFormat createInstance(String pattern, TimeZone timeZone, Locale locale) { + return new FastDateFormat(pattern, timeZone, locale); + } + }; + + private static ConcurrentMap cTimeZoneDisplayCache = + new ConcurrentHashMap(7); + + /** + * The pattern. + */ + private final String mPattern; + /** + * The time zone. + */ + private final TimeZone mTimeZone; + /** + * The locale. + */ + private final Locale mLocale; + /** + * The parsed rules. + */ + private transient Rule[] mRules; + /** + * The estimated maximum length. + */ + private transient int mMaxLengthEstimate; + + //----------------------------------------------------------------------- + /** + *

Gets a formatter instance using the default pattern in the + * default locale.

+ * + * @return a date/time formatter + */ + public static FastDateFormat getInstance() { + return cache.getDateTimeInstance(SHORT, SHORT, null, null); + } + + /** + *

Gets a formatter instance using the specified pattern in the + * default locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(String pattern) { + return cache.getInstance(pattern, null, null); + } + + /** + *

Gets a formatter instance using the specified pattern and + * time zone.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(String pattern, TimeZone timeZone) { + return cache.getInstance(pattern, timeZone, null); + } + + /** + *

Gets a formatter instance using the specified pattern and + * locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param locale optional locale, overrides system locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(String pattern, Locale locale) { + return cache.getInstance(pattern, null, locale); + } + + /** + *

Gets a formatter instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or {@code null} + */ + public static FastDateFormat getInstance(String pattern, TimeZone timeZone, Locale locale) { + return cache.getInstance(pattern, timeZone, locale); + } + + //----------------------------------------------------------------------- + /** + *

Gets a date formatter instance using the specified style in the + * default time zone and locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(int style) { + return cache.getDateTimeInstance(style, null, null, null); + } + + /** + *

Gets a date formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(int style, Locale locale) { + return cache.getDateTimeInstance(style, null, null, locale); + } + + /** + *

Gets a date formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(int style, TimeZone timeZone) { + return cache.getDateTimeInstance(style, null, timeZone, null); + } + + /** + *

Gets a date formatter instance using the specified style, time + * zone and locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + */ + public static FastDateFormat getDateInstance(int style, TimeZone timeZone, Locale locale) { + return cache.getDateTimeInstance(style, null, timeZone, locale); + } + + //----------------------------------------------------------------------- + /** + *

Gets a time formatter instance using the specified style in the + * default time zone and locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(int style) { + return cache.getDateTimeInstance(null, style, null, null); + } + + /** + *

Gets a time formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(int style, Locale locale) { + return cache.getDateTimeInstance(null, style, null, locale); + } + + /** + *

Gets a time formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted time + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(int style, TimeZone timeZone) { + return cache.getDateTimeInstance(null, style, timeZone, null); + } + + /** + *

Gets a time formatter instance using the specified style, time + * zone and locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted time + * @param locale optional locale, overrides system locale + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + */ + public static FastDateFormat getTimeInstance(int style, TimeZone timeZone, Locale locale) { + return cache.getDateTimeInstance(null, style, timeZone, locale); + } + + //----------------------------------------------------------------------- + /** + *

Gets a date/time formatter instance using the specified style + * in the default time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle) { + return cache.getDateTimeInstance(dateStyle, timeStyle, null, null); + } + + /** + *

Gets a date/time formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { + return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale); + } + + /** + *

Gets a date/time formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(int dateStyle, int timeStyle, TimeZone timeZone) { + return getDateTimeInstance(dateStyle, timeStyle, timeZone, null); + } + /** + *

Gets a date/time formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + public static FastDateFormat getDateTimeInstance( + int dateStyle, int timeStyle, TimeZone timeZone, Locale locale) { + return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale); + } + + //----------------------------------------------------------------------- + /** + *

Gets the time zone display name, using a cache for performance.

+ * + * @param tz the zone to query + * @param daylight true if daylight savings + * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT} + * @param locale the locale to use + * @return the textual name of the time zone + */ + static String getTimeZoneDisplay(TimeZone tz, boolean daylight, int style, Locale locale) { + TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale); + String value = cTimeZoneDisplayCache.get(key); + if (value == null) { + // This is a very slow call, so cache the results. + value = tz.getDisplayName(daylight, style, locale); + String prior = cTimeZoneDisplayCache.putIfAbsent(key, value); + if (prior != null) { + value= prior; + } + } + return value; + } + + // Constructor + //----------------------------------------------------------------------- + /** + *

Constructs a new FastDateFormat.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale to use + * @throws NullPointerException if pattern, timeZone, or locale is null. + */ + protected FastDateFormat(String pattern, TimeZone timeZone, Locale locale) { + mPattern = pattern; + mTimeZone = timeZone; + mLocale = locale; + + init(); + } + + /** + *

Initializes the instance for first use.

+ */ + private void init() { + List rulesList = parsePattern(); + mRules = rulesList.toArray(new Rule[rulesList.size()]); + + int len = 0; + for (int i=mRules.length; --i >= 0; ) { + len += mRules[i].estimateLength(); + } + + mMaxLengthEstimate = len; + } + + // Parse the pattern + //----------------------------------------------------------------------- + /** + *

Returns a list of Rules given a pattern.

+ * + * @return a {@code List} of Rule objects + * @throws IllegalArgumentException if pattern is invalid + */ + protected List parsePattern() { + DateFormatSymbols symbols = new DateFormatSymbols(mLocale); + List rules = new ArrayList(); + + String[] ERAs = symbols.getEras(); + String[] months = symbols.getMonths(); + String[] shortMonths = symbols.getShortMonths(); + String[] weekdays = symbols.getWeekdays(); + String[] shortWeekdays = symbols.getShortWeekdays(); + String[] AmPmStrings = symbols.getAmPmStrings(); + + int length = mPattern.length(); + int[] indexRef = new int[1]; + + for (int i = 0; i < length; i++) { + indexRef[0] = i; + String token = parseToken(mPattern, indexRef); + i = indexRef[0]; + + int tokenLen = token.length(); + if (tokenLen == 0) { + break; + } + + Rule rule; + char c = token.charAt(0); + + switch (c) { + case 'G': // era designator (text) + rule = new TextField(Calendar.ERA, ERAs); + break; + case 'y': // year (number) + if (tokenLen == 2) { + rule = TwoDigitYearField.INSTANCE; + } else { + rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen); + } + break; + case 'M': // month in year (text and number) + if (tokenLen >= 4) { + rule = new TextField(Calendar.MONTH, months); + } else if (tokenLen == 3) { + rule = new TextField(Calendar.MONTH, shortMonths); + } else if (tokenLen == 2) { + rule = TwoDigitMonthField.INSTANCE; + } else { + rule = UnpaddedMonthField.INSTANCE; + } + break; + case 'd': // day in month (number) + rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); + break; + case 'h': // hour in am/pm (number, 1..12) + rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); + break; + case 'H': // hour in day (number, 0..23) + rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); + break; + case 'm': // minute in hour (number) + rule = selectNumberRule(Calendar.MINUTE, tokenLen); + break; + case 's': // second in minute (number) + rule = selectNumberRule(Calendar.SECOND, tokenLen); + break; + case 'S': // millisecond (number) + rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); + break; + case 'E': // day in week (text) + rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); + break; + case 'D': // day in year (number) + rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); + break; + case 'F': // day of week in month (number) + rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); + break; + case 'w': // week in year (number) + rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); + break; + case 'W': // week in month (number) + rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); + break; + case 'a': // am/pm marker (text) + rule = new TextField(Calendar.AM_PM, AmPmStrings); + break; + case 'k': // hour in day (1..24) + rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); + break; + case 'K': // hour in am/pm (0..11) + rule = selectNumberRule(Calendar.HOUR, tokenLen); + break; + case 'z': // time zone (text) + if (tokenLen >= 4) { + rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG); + } else { + rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT); + } + break; + case 'Z': // time zone (value) + if (tokenLen == 1) { + rule = TimeZoneNumberRule.INSTANCE_NO_COLON; + } else { + rule = TimeZoneNumberRule.INSTANCE_COLON; + } + break; + case '\'': // literal text + String sub = token.substring(1); + if (sub.length() == 1) { + rule = new CharacterLiteral(sub.charAt(0)); + } else { + rule = new StringLiteral(sub); + } + break; + default: + throw new IllegalArgumentException("Illegal pattern component: " + token); + } + + rules.add(rule); + } + + return rules; + } + + /** + *

Performs the parsing of tokens.

+ * + * @param pattern the pattern + * @param indexRef index references + * @return parsed token + */ + protected String parseToken(String pattern, int[] indexRef) { + StringBuilder buf = new StringBuilder(); + + int i = indexRef[0]; + int length = pattern.length(); + + char c = pattern.charAt(i); + if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { + // Scan a run of the same character, which indicates a time + // pattern. + buf.append(c); + + while (i + 1 < length) { + char peek = pattern.charAt(i + 1); + if (peek == c) { + buf.append(c); + i++; + } else { + break; + } + } + } else { + // This will identify token as text. + buf.append('\''); + + boolean inLiteral = false; + + for (; i < length; i++) { + c = pattern.charAt(i); + + if (c == '\'') { + if (i + 1 < length && pattern.charAt(i + 1) == '\'') { + // '' is treated as escaped ' + i++; + buf.append(c); + } else { + inLiteral = !inLiteral; + } + } else if (!inLiteral && + (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { + i--; + break; + } else { + buf.append(c); + } + } + } + + indexRef[0] = i; + return buf.toString(); + } + + /** + *

Gets an appropriate rule for the padding required.

+ * + * @param field the field to get a rule for + * @param padding the padding required + * @return a new rule with the correct padding + */ + protected NumberRule selectNumberRule(int field, int padding) { + switch (padding) { + case 1: + return new UnpaddedNumberField(field); + case 2: + return new TwoDigitNumberField(field); + default: + return new PaddedNumberField(field, padding); + } + } + + // Format methods + //----------------------------------------------------------------------- + /** + *

Formats a {@code Date}, {@code Calendar} or + * {@code Long} (milliseconds) object.

+ * + * @param obj the object to format + * @param toAppendTo the buffer to append to + * @param pos the position - ignored + * @return the buffer passed in + */ + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + if (obj instanceof Date) { + return format((Date) obj, toAppendTo); + } else if (obj instanceof Calendar) { + return format((Calendar) obj, toAppendTo); + } else if (obj instanceof Long) { + return format(((Long) obj).longValue(), toAppendTo); + } else { + throw new IllegalArgumentException("Unknown class: " + + (obj == null ? "" : obj.getClass().getName())); + } + } + + /** + *

Formats a millisecond {@code long} value.

+ * + * @param millis the millisecond value to format + * @return the formatted string + * @since 2.1 + */ + public String format(long millis) { + return format(new Date(millis)); + } + + /** + *

Formats a {@code Date} object using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @return the formatted string + */ + public String format(Date date) { + Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar + c.setTime(date); + return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString(); + } + + /** + *

Formats a {@code Calendar} object.

+ * + * @param calendar the calendar to format + * @return the formatted string + */ + public String format(Calendar calendar) { + return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString(); + } + + /** + *

Formats a milliseond {@code long} value into the + * supplied {@code StringBuffer}.

+ * + * @param millis the millisecond value to format + * @param buf the buffer to format into + * @return the specified string buffer + * @since 2.1 + */ + public StringBuffer format(long millis, StringBuffer buf) { + return format(new Date(millis), buf); + } + + /** + *

Formats a {@code Date} object into the + * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + public StringBuffer format(Date date, StringBuffer buf) { + Calendar c = new GregorianCalendar(mTimeZone, mLocale); // hard code GregorianCalendar + c.setTime(date); + return applyRules(c, buf); + } + + /** + *

Formats a {@code Calendar} object into the + * supplied {@code StringBuffer}.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + public StringBuffer format(Calendar calendar, StringBuffer buf) { + return applyRules(calendar, buf); + } + + /** + *

Performs the formatting by applying the rules to the + * specified calendar.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + protected StringBuffer applyRules(Calendar calendar, StringBuffer buf) { + for (Rule rule : mRules) { + rule.appendTo(buf, calendar); + } + return buf; + } + + // Parsing + //----------------------------------------------------------------------- + /** + *

Parsing is not supported.

+ * + * @param source the string to parse + * @param pos the parsing position + * @return {@code null} as not supported + */ + @Override + public Object parseObject(String source, ParsePosition pos) { + pos.setIndex(0); + pos.setErrorIndex(0); + return null; + } + + // Accessors + //----------------------------------------------------------------------- + /** + *

Gets the pattern used by this formatter.

+ * + * @return the pattern, {@link java.text.SimpleDateFormat} compatible + */ + public String getPattern() { + return mPattern; + } + + /** + *

Gets the time zone used by this formatter.

+ * + *

This zone is always used for {@code Date} formatting.

+ * + * @return the time zone + */ + public TimeZone getTimeZone() { + return mTimeZone; + } + + /** + *

Gets the locale used by this formatter.

+ * + * @return the locale + */ + public Locale getLocale() { + return mLocale; + } + + /** + *

Gets an estimate for the maximum string length that the + * formatter will produce.

+ * + *

The actual formatted length will almost always be less than or + * equal to this amount.

+ * + * @return the maximum formatted length + */ + public int getMaxLengthEstimate() { + return mMaxLengthEstimate; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

Compares two objects for equality.

+ * + * @param obj the object to compare to + * @return {@code true} if equal + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof FastDateFormat == false) { + return false; + } + FastDateFormat other = (FastDateFormat) obj; + return mPattern.equals(other.mPattern) + && mTimeZone.equals(other.mTimeZone) + && mLocale.equals(other.mLocale); + } + + /** + *

Returns a hashcode compatible with equals.

+ * + * @return a hashcode compatible with equals + */ + @Override + public int hashCode() { + return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode()); + } + + /** + *

Gets a debugging string version of this formatter.

+ * + * @return a debugging string + */ + @Override + public String toString() { + return "FastDateFormat[" + mPattern + "]"; + } + + // Serializing + //----------------------------------------------------------------------- + /** + * Create the object after serialization. This implementation reinitializes the + * transient properties. + * + * @param in ObjectInputStream from which the object is being deserialized. + * @throws IOException if there is an IO issue. + * @throws ClassNotFoundException if a class cannot be found. + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + init(); + } + + // Rules + //----------------------------------------------------------------------- + /** + *

Inner class defining a rule.

+ */ + private interface Rule { + /** + * Returns the estimated lentgh of the result. + * + * @return the estimated length + */ + int estimateLength(); + + /** + * Appends the value of the specified calendar to the output buffer based on the rule implementation. + * + * @param buffer the output buffer + * @param calendar calendar to be appended + */ + void appendTo(StringBuffer buffer, Calendar calendar); + } + + /** + *

Inner class defining a numeric rule.

+ */ + private interface NumberRule extends Rule { + /** + * Appends the specified value to the output buffer based on the rule implementation. + * + * @param buffer the output buffer + * @param value the value to be appended + */ + void appendTo(StringBuffer buffer, int value); + } + + /** + *

Inner class to output a constant single character.

+ */ + private static class CharacterLiteral implements Rule { + private final char mValue; + + /** + * Constructs a new instance of {@code CharacterLiteral} + * to hold the specified value. + * + * @param value the character literal + */ + CharacterLiteral(char value) { + mValue = value; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 1; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + buffer.append(mValue); + } + } + + /** + *

Inner class to output a constant string.

+ */ + private static class StringLiteral implements Rule { + private final String mValue; + + /** + * Constructs a new instance of {@code StringLiteral} + * to hold the specified value. + * + * @param value the string literal + */ + StringLiteral(String value) { + mValue = value; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return mValue.length(); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + buffer.append(mValue); + } + } + + /** + *

Inner class to output one of a set of values.

+ */ + private static class TextField implements Rule { + private final int mField; + private final String[] mValues; + + /** + * Constructs an instance of {@code TextField} + * with the specified field and values. + * + * @param field the field + * @param values the field values + */ + TextField(int field, String[] values) { + mField = field; + mValues = values; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + int max = 0; + for (int i=mValues.length; --i >= 0; ) { + int len = mValues[i].length(); + if (len > max) { + max = len; + } + } + return max; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + buffer.append(mValues[calendar.get(mField)]); + } + } + + /** + *

Inner class to output an unpadded number.

+ */ + private static class UnpaddedNumberField implements NumberRule { + private final int mField; + + /** + * Constructs an instance of {@code UnpadedNumberField} with the specified field. + * + * @param field the field + */ + UnpaddedNumberField(int field) { + mField = field; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 4; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + if (value < 10) { + buffer.append((char)(value + '0')); + } else if (value < 100) { + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } else { + buffer.append(Integer.toString(value)); + } + } + } + + /** + *

Inner class to output an unpadded month.

+ */ + private static class UnpaddedMonthField implements NumberRule { + static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); + + /** + * Constructs an instance of {@code UnpaddedMonthField}. + * + */ + UnpaddedMonthField() { + super(); + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.MONTH) + 1); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + if (value < 10) { + buffer.append((char)(value + '0')); + } else { + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } + } + } + + /** + *

Inner class to output a padded number.

+ */ + private static class PaddedNumberField implements NumberRule { + private final int mField; + private final int mSize; + + /** + * Constructs an instance of {@code PaddedNumberField}. + * + * @param field the field + * @param size size of the output field + */ + PaddedNumberField(int field, int size) { + if (size < 3) { + // Should use UnpaddedNumberField or TwoDigitNumberField. + throw new IllegalArgumentException(); + } + mField = field; + mSize = size; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 4; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + if (value < 100) { + for (int i = mSize; --i >= 2; ) { + buffer.append('0'); + } + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } else { + int digits; + if (value < 1000) { + digits = 3; + } else { + isTrue(value > -1, "Negative values should not be possible", value); + digits = Integer.toString(value).length(); + } + for (int i = mSize; --i >= digits; ) { + buffer.append('0'); + } + buffer.append(Integer.toString(value)); + } + } + } + + public static void isTrue(boolean expression, String message, Object... values) { + if (expression == false) { + throw new IllegalArgumentException(String.format(message, values)); + } + } + /** + *

Inner class to output a two digit number.

+ */ + private static class TwoDigitNumberField implements NumberRule { + private final int mField; + + /** + * Constructs an instance of {@code TwoDigitNumberField} with the specified field. + * + * @param field the field + */ + TwoDigitNumberField(int field) { + mField = field; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + if (value < 100) { + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } else { + buffer.append(Integer.toString(value)); + } + } + } + + /** + *

Inner class to output a two digit year.

+ */ + private static class TwoDigitYearField implements NumberRule { + static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); + + /** + * Constructs an instance of {@code TwoDigitYearField}. + */ + TwoDigitYearField() { + super(); + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.YEAR) % 100); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } + } + + /** + *

Inner class to output a two digit month.

+ */ + private static class TwoDigitMonthField implements NumberRule { + static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); + + /** + * Constructs an instance of {@code TwoDigitMonthField}. + */ + TwoDigitMonthField() { + super(); + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.MONTH) + 1); + } + + /** + * {@inheritDoc} + */ + public final void appendTo(StringBuffer buffer, int value) { + buffer.append((char)(value / 10 + '0')); + buffer.append((char)(value % 10 + '0')); + } + } + + /** + *

Inner class to output the twelve hour field.

+ */ + private static class TwelveHourField implements NumberRule { + private final NumberRule mRule; + + /** + * Constructs an instance of {@code TwelveHourField} with the specified + * {@code NumberRule}. + * + * @param rule the rule + */ + TwelveHourField(NumberRule rule) { + mRule = rule; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return mRule.estimateLength(); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + int value = calendar.get(Calendar.HOUR); + if (value == 0) { + value = calendar.getLeastMaximum(Calendar.HOUR) + 1; + } + mRule.appendTo(buffer, value); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, int value) { + mRule.appendTo(buffer, value); + } + } + + /** + *

Inner class to output the twenty four hour field.

+ */ + private static class TwentyFourHourField implements NumberRule { + private final NumberRule mRule; + + /** + * Constructs an instance of {@code TwentyFourHourField} with the specified + * {@code NumberRule}. + * + * @param rule the rule + */ + TwentyFourHourField(NumberRule rule) { + mRule = rule; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return mRule.estimateLength(); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + int value = calendar.get(Calendar.HOUR_OF_DAY); + if (value == 0) { + value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; + } + mRule.appendTo(buffer, value); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, int value) { + mRule.appendTo(buffer, value); + } + } + + /** + *

Inner class to output a time zone name.

+ */ + private static class TimeZoneNameRule implements Rule { + private final TimeZone mTimeZone; + private final String mStandard; + private final String mDaylight; + + /** + * Constructs an instance of {@code TimeZoneNameRule} with the specified properties. + * + * @param timeZone the time zone + * @param locale the locale + * @param style the style + */ + TimeZoneNameRule(TimeZone timeZone, Locale locale, int style) { + mTimeZone = timeZone; + + mStandard = getTimeZoneDisplay(timeZone, false, style, locale); + mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return Math.max(mStandard.length(), mDaylight.length()); + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + if (mTimeZone.useDaylightTime() && calendar.get(Calendar.DST_OFFSET) != 0) { + buffer.append(mDaylight); + } else { + buffer.append(mStandard); + } + } + } + + /** + *

Inner class to output a time zone as a number {@code +/-HHMM} + * or {@code +/-HH:MM}.

+ */ + private static class TimeZoneNumberRule implements Rule { + static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); + static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); + + final boolean mColon; + + /** + * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties. + * + * @param colon add colon between HH and MM in the output if {@code true} + */ + TimeZoneNumberRule(boolean colon) { + mColon = colon; + } + + /** + * {@inheritDoc} + */ + public int estimateLength() { + return 5; + } + + /** + * {@inheritDoc} + */ + public void appendTo(StringBuffer buffer, Calendar calendar) { + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + + if (offset < 0) { + buffer.append('-'); + offset = -offset; + } else { + buffer.append('+'); + } + + int hours = offset / (60 * 60 * 1000); + buffer.append((char)(hours / 10 + '0')); + buffer.append((char)(hours % 10 + '0')); + + if (mColon) { + buffer.append(':'); + } + + int minutes = offset / (60 * 1000) - 60 * hours; + buffer.append((char)(minutes / 10 + '0')); + buffer.append((char)(minutes % 10 + '0')); + } + } + + // ---------------------------------------------------------------------- + /** + *

Inner class that acts as a compound key for time zone names.

+ */ + private static class TimeZoneDisplayKey { + private final TimeZone mTimeZone; + private final int mStyle; + private final Locale mLocale; + + /** + * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties. + * + * @param timeZone the time zone + * @param daylight adjust the style for daylight saving time if {@code true} + * @param style the timezone style + * @param locale the timezone locale + */ + TimeZoneDisplayKey(TimeZone timeZone, + boolean daylight, int style, Locale locale) { + mTimeZone = timeZone; + if (daylight) { + style |= 0x80000000; + } + mStyle = style; + mLocale = locale; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return (mStyle * 31 + mLocale.hashCode() ) * 31 + mTimeZone.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TimeZoneDisplayKey) { + TimeZoneDisplayKey other = (TimeZoneDisplayKey)obj; + return + mTimeZone.equals(other.mTimeZone) && + mStyle == other.mStyle && + mLocale.equals(other.mLocale); + } + return false; + } + } +} diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/FormatCache.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/FormatCache.java new file mode 100644 index 00000000..6d202838 --- /dev/null +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/FormatCache.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.adbcj.mysql.codec; + +import java.text.DateFormat; +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + *

FormatCache is a cache and factory for {@link Format}s.

+ * + * @since 3.0 + * @version $Id: FormatCache 892161 2009-12-18 07:21:10Z $ + */ +// TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach. +abstract class FormatCache { + /** + * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG + */ + static final int NONE= -1; + + private final ConcurrentMap cInstanceCache + = new ConcurrentHashMap(7); + + private final ConcurrentMap cDateTimeInstanceCache + = new ConcurrentHashMap(7); + + /** + *

Gets a formatter instance using the default pattern in the + * default timezone and locale.

+ * + * @return a date/time formatter + */ + public F getInstance() { + return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault()); + } + + /** + *

Gets a formatter instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone the non-null time zone + * @param locale the non-null locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or null + */ + public F getInstance(String pattern, TimeZone timeZone, Locale locale) { + if (pattern == null) { + throw new NullPointerException("pattern must not be null"); + } + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } + if (locale == null) { + locale = Locale.getDefault(); + } + MultipartKey key = new MultipartKey(pattern, timeZone, locale); + F format = cInstanceCache.get(key); + if (format == null) { + format = createInstance(pattern, timeZone, locale); + F previousValue= cInstanceCache.putIfAbsent(key, format); + if (previousValue != null) { + // another thread snuck in and did the same work + // we should return the instance that is in ConcurrentMap + format= previousValue; + } + } + return format; + } + + /** + *

Create a format instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null. + * @param timeZone time zone, this will not be null. + * @param locale locale, this will not be null. + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or null + */ + abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale); + + /** + *

Gets a date/time formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + public F getDateTimeInstance(Integer dateStyle, Integer timeStyle, TimeZone timeZone, Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale); + + String pattern = cDateTimeInstanceCache.get(key); + if (pattern == null) { + try { + DateFormat formatter; + if (dateStyle == null) { + formatter = DateFormat.getTimeInstance(timeStyle, locale); + } + else if (timeStyle == null) { + formatter = DateFormat.getDateInstance(dateStyle, locale); + } + else { + formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale); + } + pattern = ((SimpleDateFormat)formatter).toPattern(); + String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern); + if (previous != null) { + // even though it doesn't matter if another thread put the pattern + // it's still good practice to return the String instance that is + // actually in the ConcurrentMap + pattern= previous; + } + } catch (ClassCastException ex) { + throw new IllegalArgumentException("No date time pattern for locale: " + locale); + } + } + + return getInstance(pattern, timeZone, locale); + } + + // ---------------------------------------------------------------------- + /** + *

Helper class to hold multi-part Map keys

+ */ + private static class MultipartKey { + private final Object[] keys; + private int hashCode; + + /** + * Constructs an instance of MultipartKey to hold the specified objects. + * @param keys the set of objects that make up the key. Each key may be null. + */ + public MultipartKey(Object... keys) { + this.keys = keys; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ( obj instanceof MultipartKey == false ) { + return false; + } + return Arrays.equals(keys, ((MultipartKey)obj).keys); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if(hashCode==0) { + int rc= 0; + for(Object key : keys) { + if(key!=null) { + rc= rc*7 + key.hashCode(); + } + } + hashCode= rc; + } + return hashCode; + } + } + +} diff --git a/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlPreparedStatement.java b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlPreparedStatement.java new file mode 100644 index 00000000..9ed853d2 --- /dev/null +++ b/mysql/codec/src/main/java/org/adbcj/mysql/codec/MysqlPreparedStatement.java @@ -0,0 +1,133 @@ +package org.adbcj.mysql.codec; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.adbcj.DbFuture; +import org.adbcj.DbSession; +import org.adbcj.PreparedStatement; +import org.adbcj.Result; +import org.adbcj.ResultSet; + + +/** + * mysql doesn't have the 'real' prepared statement . + * so here I just replace all question mark by params + * @author Whisper 2013Äê7ÔÂ4ÈÕ ÏÂÎç1:39:54 + * @since 3.0.1 + */ +public class MysqlPreparedStatement implements PreparedStatement{ + protected final String originalSql ; + protected final DbSession session; + protected final FastDateFormat fdf; + public MysqlPreparedStatement(String originalSql,DbSession session,FastDateFormat fdf){ + super(); + this.originalSql = originalSql; + this.session = session; + this.fdf = fdf; + } + + @Override + public List getParameterKeys() { + return null; + } + + @Override + public String getNativeSQL() { + return originalSql; + } + + @Override + public DbFuture executeQuery(Object... params) { + String newSql = replacePattern(originalSql,fdf, params); + return session.executeQuery(newSql); + } + public static final String replacePattern(String sql,FastDateFormat fdf,Object...params) { + StringBuilder sb = new StringBuilder(); + int quotationCount = 0; + int questionMarkCount = 0; + for(int i = 0; i DbFuture executeQuery(Map params) { + throw new UnsupportedOperationException("not supported yet !"); + } + + @Override + public DbFuture executeUpdate(Object... params) { + String newSql = replacePattern(originalSql,fdf, params); + return session.executeUpdate(newSql); + } + + @Override + public DbFuture executeUpdate(Map params) { + throw new UnsupportedOperationException("not supported yet !"); + } + +} diff --git a/mysql/codec/src/test/java/org/adbcj/mysql/codec/MysqlPreparedStatementUnitTest.java b/mysql/codec/src/test/java/org/adbcj/mysql/codec/MysqlPreparedStatementUnitTest.java new file mode 100644 index 00000000..fd8d58ce --- /dev/null +++ b/mysql/codec/src/test/java/org/adbcj/mysql/codec/MysqlPreparedStatementUnitTest.java @@ -0,0 +1,61 @@ +package org.adbcj.mysql.codec; + +import java.math.BigInteger; +import java.util.Date; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.testng.annotations.Test; + + +public class MysqlPreparedStatementUnitTest extends TestCase { + @Test + public void test_normal() throws Exception + { + String format = "yyyy-MM-dd HH:mm:ss"; + FastDateFormat fdf = FastDateFormat.getInstance(format); + + String sql = "select * from table where id = ?"; + String after = null; + after = MysqlPreparedStatement.replacePattern(sql,fdf, 1); + Assert.assertEquals("select * from table where id = 1", after); + + after = MysqlPreparedStatement.replacePattern(sql,fdf, BigInteger.valueOf(1l)); + Assert.assertEquals("select * from table where id = 1", after); + + after = MysqlPreparedStatement.replacePattern(sql,fdf, 1.1f); + Assert.assertEquals("select * from table where id = 1.1", after); + + after = MysqlPreparedStatement.replacePattern(sql,fdf, 2.2d); + Assert.assertEquals("select * from table where id = 2.2", after); + + sql = "select * from table where id = ? and b = ?"; + after = MysqlPreparedStatement.replacePattern(sql,fdf, 1,"'asdf?'"); + Assert.assertEquals("select * from table where id = 1 and b = 'asdf?'", after); + + after = MysqlPreparedStatement.replacePattern(sql,fdf, 1,new Date(10000000l)); + Assert.assertEquals("select * from table where id = 1 and b = '1970-01-01 10:46:40'", after); + + after = MysqlPreparedStatement.replacePattern(sql,fdf, 1,"asdf?"); + Assert.assertEquals("select * from table where id = 1 and b = 'asdf?'", after); + + } + + @Test + public void test_exception() throws Exception + { + String format = "yyyy-MM-dd HH:mm:ss"; + FastDateFormat fdf = FastDateFormat.getInstance(format); + + String sql = "select * from table where id = ? and b = ?"; +// String after = null; + + try { + String after = MysqlPreparedStatement.replacePattern(sql, fdf, 1); + Assert.fail(); + } catch (Exception e) { + Assert.assertEquals("params' size is less than question mark in sql", e.getMessage()); + } + } +} diff --git a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java index efdbbd6f..88794342 100644 --- a/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java +++ b/mysql/netty/src/test/java/org/adbcj/mysql/netty/TestType.java @@ -13,7 +13,9 @@ import org.adbcj.Connection; import org.adbcj.ConnectionManager; import org.adbcj.ConnectionManagerProvider; +import org.adbcj.DbFuture; import org.adbcj.DbSessionFuture; +import org.adbcj.PreparedStatement; import org.adbcj.Result; import org.adbcj.ResultSet; import org.adbcj.Row; @@ -69,6 +71,7 @@ public void tear() throws Exception { connection.close(true); } + @Test public void testNull() throws Exception { @@ -134,9 +137,10 @@ public void testNull() throws Exception { public void testType() throws Exception { prepare_notNull(); Connection connection = cm.connect().get(); - DbSessionFuture result = connection.executeQuery("select pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," - + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," - + "decimalr,dater,timer,datetimer,timestampr,yearr from type_test"); + DbSessionFuture ps = connection.prepareStatement("select pk,varcharr,charr,blobr,integerr,integerr_unsigned,tinyintr,tinyintr_unsigned," + + "smallintr,smallintr_unsigned,mediumintr,mediumintr_unsigned,bitr,bigintr,bigintr_unsigned,floatr,doubler," + + "decimalr,dater,timer,datetimer,timestampr,yearr from type_test where pk = ?"); + DbFuture result = ps.get().executeQuery(0); ResultSet r = result.get(); Row row = r.iterator().next(); Value[] values = row.getValues(); From 197c059e83ca1cf7c1c5a3212b90276f9ebc86ef Mon Sep 17 00:00:00 2001 From: shenxun Date: Sat, 6 Jul 2013 22:56:20 +0800 Subject: [PATCH 15/17] exception handling enhancement --- .../java/org/adbcj/mysql/netty/MysqlConnectionManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java index 1b3676d0..f63ae559 100644 --- a/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java +++ b/mysql/netty/src/main/java/org/adbcj/mysql/netty/MysqlConnectionManager.java @@ -195,8 +195,9 @@ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Ex public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Throwable t = handler.handleException(connection, e.getCause()); if (t != null) { - // TODO: Pass exception on to connectionManager - t.printStackTrace(); +// t.printStackTrace(); + e.getChannel().close(); + super.exceptionCaught(ctx, e); } } From cf6afa7c8adde59e58c30f5c959d9ebf53c216e7 Mon Sep 17 00:00:00 2001 From: Whisper Date: Mon, 8 Jul 2013 10:40:36 +0800 Subject: [PATCH 16/17] Create README.md --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..b84733b6 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +adbcj +===== + +Asynchronous Database Connectivity in Java ,like jdbc + +enhancement: + +done: +1. prepared statment has been supported +2. add mysql5.5 protocol support +3. make mysql data type adjuestment to the mysql manaul : http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-type-conversions.html +4. exception handling + +TODO: From b688d008937d19d99c6e9e76c2c8eb2ac336715c Mon Sep 17 00:00:00 2001 From: Whisper Date: Mon, 8 Jul 2013 11:44:58 +0800 Subject: [PATCH 17/17] Update README.md --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b84733b6..5223b523 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,12 @@ Asynchronous Database Connectivity in Java ,like jdbc enhancement: -done: -1. prepared statment has been supported -2. add mysql5.5 protocol support -3. make mysql data type adjuestment to the mysql manaul : http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-type-conversions.html -4. exception handling +done: +1. prepared statment has been supported +2. add mysql5.5 protocol support +3. make mysql data type adjuestment to the mysql manaul : http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-type-conversions.html +4. exception handling + + +TODO: -TODO: