import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.aspectj.lang.Signature;
public aspect LoanAndReturnAspect {
private ThreadLocal
<Integer
> depth
= new ThreadLocal() { @Override
return 0;
}
};
@Override
protected Map
<Connection, Integer
> initialValue
() { }
};
private Map
<Connection, AtomicInteger
> refCounts
=
pointcut loanConnection() :
set
(!static Connection+ *.
*) && target
(theObj
) && args
(conn
) && !within
(LoanAndReturnAspect
); pointcut retainConnectionStatic
(Connection conn
) : set
(static Connection+ *.
*) && args
(conn
) && !within
(LoanAndReturnAspect
); pointcut checkPoint() :
execution(* *.*(..)) && !within(LoanAndReturnAspect); // 註2
call
(void Connection+.
close()) && target
(conn
) && !within
(LoanAndReturnAspect
);
after
() returning
(Connection conn
) : loanConnection
() { // 註3 System.
out.
printf("Loan a connection: %s%n", conn
); possessedConnection.get().put(conn, depth.get());
departments.
put(conn,
Thread.
currentThread()); refCounts.put(conn, new AtomicInteger(0));
}
Object around
() : checkPoint
() { Signature sig
= thisJoinPoint.
getSignature(); logMethod(sig, true);
try {
depth.set(depth.get() + 1);
return proceed();
}
finally {
depth.set(depth.get() - 1);
tryToReturnConnection();
logMethod(sig, false);
}
}
after
(Connection conn
) : releaseConnection
(conn
) && !cflowbelow
(execution
(void Connection+.
close())) { System.
out.
printf("[Manually close] %s%n", conn
); refCounts.remove(conn);
Thread department
= departments.
get(conn
); if (department
== Thread.
currentThread()) possessedConnection.get().remove(conn);
departments.remove(conn);
}
if (isTracking(oldConn))
release(oldConn);
if (isTracking(newConn))
retain(newConn);
}
before
(Connection newConn
) : retainConnectionStatic
(newConn
) { Signature sig
= thisJoinPoint.
getSignature(); if (isTracking(oldConn))
release(oldConn);
if (isTracking(newConn))
retain(newConn);
}
return refCounts.containsKey(conn);
}
int refCount = refCounts.get(conn).incrementAndGet();
System.
out.
printf("[Retain] %s[%d]%n", conn, refCount
); }
int refCount = refCounts.get(conn).decrementAndGet();
System.
out.
printf("[Release] %s[%d]%n", conn, refCount
); if (refCount < 1 && !departments.get(conn).isAlive()) {
returnConnection(conn, false);
}
}
private void tryToReturnConnection() {
int stackDepth = depth.get();
Map
<Connection, Integer
> connTable
= possessedConnection.
get(); List<Connection> willReturn = new LinkedList<Connection>();
if (!isTracking(conn)) continue;
int bornDepth = connTable.get(conn);
if (bornDepth > stackDepth && refCounts.get(conn).intValue() < 1)
willReturn.add(conn);
}
returnConnection(conn, true);
}
}
private void returnConnection
(Connection conn,
boolean inOriginalDepartment
) { System.
out.
printf("[Auto close] %s%n", conn
); try {
conn.close();
}
}
refCounts.remove(conn);
departments.remove(conn);
if (inOriginalDepartment) {
possessedConnection.get().remove(conn);
}
}
private void logMethod
(Signature sig,
boolean isEntering
) { int stackDepth = depth.get();
System.
out.
printf("%s<%s%s:%s>%n",
computeIndentation(stackDepth),
isEntering? "" : "/",
Thread.
currentThread().
getName(), sig
); }
private String computeIndentation
(int level
) { StringBuilder buf = new StringBuilder();
for (int i = 0; i < level; ++i)
buf.append(" ");
return buf.toString();
}
try {
field = obj.getClass().getDeclaredField(name);
if (Modifier.
isStatic(field.
getModifiers())) field = null;
}
}
if (field == null) {
try {
field = obj.getClass().getField(name);
if (Modifier.
isStatic(field.
getModifiers())) field = null;
}
}
}
if (field == null)
throw new RuntimeException(String.
format("can't find instance field named: %s in class: %s", name, obj.
getClass())); field.setAccessible(true);
try {
return field.get(obj);
}
}
}
private Object getStaticFieldValue
(Class
<?> klass,
String name
) { try {
field = klass.getDeclaredField(name);
if (!Modifier.
isStatic(field.
getModifiers())) field = null;
}
}
if (field == null) {
try {
field = klass.getField(name);
if (!Modifier.
isStatic(field.
getModifiers())) field = null;
}
}
}
if (field == null)
field.setAccessible(true);
try {
return field.get(klass);
}
}
}
}
aW1wb3J0IGphdmEuc3FsLkNvbm5lY3Rpb247CmltcG9ydCBqYXZhLnNxbC5Ecml2ZXJNYW5hZ2VyOwppbXBvcnQgamF2YS51dGlsLkNvbGxlY3Rpb25zOwppbXBvcnQgamF2YS51dGlsLk1hcDsKaW1wb3J0IGphdmEudXRpbC5IYXNoTWFwOwppbXBvcnQgamF2YS51dGlsLkxpc3Q7CmltcG9ydCBqYXZhLnV0aWwuTGlua2VkTGlzdDsKaW1wb3J0IGphdmEudXRpbC5jb25jdXJyZW50LmF0b21pYy5BdG9taWNJbnRlZ2VyOwoKaW1wb3J0IGphdmEubGFuZy5yZWZsZWN0LkZpZWxkOwppbXBvcnQgamF2YS5sYW5nLnJlZmxlY3QuTW9kaWZpZXI7CgppbXBvcnQgb3JnLmFzcGVjdGoubGFuZy5TaWduYXR1cmU7CgpwdWJsaWMgYXNwZWN0IExvYW5BbmRSZXR1cm5Bc3BlY3QgewogICAgcHJpdmF0ZSBUaHJlYWRMb2NhbDxJbnRlZ2VyPiBkZXB0aCA9IG5ldyBUaHJlYWRMb2NhbCgpIHsKICAgICAgICBAT3ZlcnJpZGUKICAgICAgICBwcm90ZWN0ZWQgSW50ZWdlciBpbml0aWFsVmFsdWUoKSB7CiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH0KICAgIH07CiAgICBwcml2YXRlIFRocmVhZExvY2FsPE1hcDxDb25uZWN0aW9uLCBJbnRlZ2VyPj4gcG9zc2Vzc2VkQ29ubmVjdGlvbiA9IG5ldyBUaHJlYWRMb2NhbCgpIHsKICAgICAgICBAT3ZlcnJpZGUKICAgICAgICBwcm90ZWN0ZWQgTWFwPENvbm5lY3Rpb24sIEludGVnZXI+IGluaXRpYWxWYWx1ZSgpIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBIYXNoTWFwPENvbm5lY3Rpb24sIEludGVnZXI+KCk7CiAgICAgICAgfQogICAgfTsKICAgIHByaXZhdGUgTWFwPENvbm5lY3Rpb24sIEF0b21pY0ludGVnZXI+IHJlZkNvdW50cyA9CiAgICAgICAgQ29sbGVjdGlvbnMuc3luY2hyb25pemVkTWFwKG5ldyBIYXNoTWFwPENvbm5lY3Rpb24sIEF0b21pY0ludGVnZXI+KCkpOwogICAgcHJpdmF0ZSBNYXA8Q29ubmVjdGlvbiwgVGhyZWFkPiBkZXBhcnRtZW50cyA9CiAgICAgICAgQ29sbGVjdGlvbnMuc3luY2hyb25pemVkTWFwKG5ldyBIYXNoTWFwPENvbm5lY3Rpb24sIFRocmVhZD4oKSk7CiAgICAKICAgIHBvaW50Y3V0IGxvYW5Db25uZWN0aW9uKCkgOgogICAgICAgIGNhbGwoQ29ubmVjdGlvbiBEcml2ZXJNYW5hZ2VyLmdldENvbm5lY3Rpb24oLi4pKSAmJiAhd2l0aGluKExvYW5BbmRSZXR1cm5Bc3BlY3QpOyAvLyDoqLsxCiAgICBwb2ludGN1dCByZXRhaW5Db25uZWN0aW9uKENvbm5lY3Rpb24gY29ubiwgT2JqZWN0IHRoZU9iaikgOgogICAgICAgIHNldCghc3RhdGljIENvbm5lY3Rpb24rICouKikgJiYgdGFyZ2V0KHRoZU9iaikgJiYgYXJncyhjb25uKSAmJiAhd2l0aGluKExvYW5BbmRSZXR1cm5Bc3BlY3QpOwogICAgcG9pbnRjdXQgcmV0YWluQ29ubmVjdGlvblN0YXRpYyhDb25uZWN0aW9uIGNvbm4pIDoKICAgICAgICBzZXQoc3RhdGljIENvbm5lY3Rpb24rICouKikgJiYgYXJncyhjb25uKSAmJiAhd2l0aGluKExvYW5BbmRSZXR1cm5Bc3BlY3QpOwogICAgcG9pbnRjdXQgY2hlY2tQb2ludCgpIDoKICAgICAgICBleGVjdXRpb24oKiAqLiooLi4pKSAmJiAhd2l0aGluKExvYW5BbmRSZXR1cm5Bc3BlY3QpOyAgLy8g6Ki7MgogICAgcG9pbnRjdXQgcmVsZWFzZUNvbm5lY3Rpb24oQ29ubmVjdGlvbiBjb25uKSA6CiAgICAgICAgY2FsbCh2b2lkIENvbm5lY3Rpb24rLmNsb3NlKCkpICYmIHRhcmdldChjb25uKSAmJiAhd2l0aGluKExvYW5BbmRSZXR1cm5Bc3BlY3QpOwogICAgCiAgICBhZnRlcigpIHJldHVybmluZyhDb25uZWN0aW9uIGNvbm4pIDogbG9hbkNvbm5lY3Rpb24oKSB7ICAvLyDoqLszCiAgICAgICAgU3lzdGVtLm91dC5wcmludGYoIkxvYW4gYSBjb25uZWN0aW9uOiAlcyVuIiwgY29ubik7CiAgICAgICAgcG9zc2Vzc2VkQ29ubmVjdGlvbi5nZXQoKS5wdXQoY29ubiwgZGVwdGguZ2V0KCkpOwogICAgICAgIGRlcGFydG1lbnRzLnB1dChjb25uLCBUaHJlYWQuY3VycmVudFRocmVhZCgpKTsKICAgICAgICByZWZDb3VudHMucHV0KGNvbm4sIG5ldyBBdG9taWNJbnRlZ2VyKDApKTsKICAgIH0KICAgIAogICAgT2JqZWN0IGFyb3VuZCgpIDogY2hlY2tQb2ludCgpIHsKICAgICAgICBTaWduYXR1cmUgc2lnID0gdGhpc0pvaW5Qb2ludC5nZXRTaWduYXR1cmUoKTsKICAgICAgICBsb2dNZXRob2Qoc2lnLCB0cnVlKTsKICAgICAgICB0cnkgewogICAgICAgICAgICBkZXB0aC5zZXQoZGVwdGguZ2V0KCkgKyAxKTsKICAgICAgICAgICAgcmV0dXJuIHByb2NlZWQoKTsKICAgICAgICB9CiAgICAgICAgZmluYWxseSB7CiAgICAgICAgICAgIGRlcHRoLnNldChkZXB0aC5nZXQoKSAtIDEpOwogICAgICAgICAgICB0cnlUb1JldHVybkNvbm5lY3Rpb24oKTsKICAgICAgICAgICAgbG9nTWV0aG9kKHNpZywgZmFsc2UpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgYWZ0ZXIoQ29ubmVjdGlvbiBjb25uKSA6IHJlbGVhc2VDb25uZWN0aW9uKGNvbm4pICYmICFjZmxvd2JlbG93KGV4ZWN1dGlvbih2b2lkIENvbm5lY3Rpb24rLmNsb3NlKCkpKSB7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGYoIltNYW51YWxseSBjbG9zZV0gJXMlbiIsIGNvbm4pOwogICAgICAgIHJlZkNvdW50cy5yZW1vdmUoY29ubik7CiAgICAgICAgVGhyZWFkIGRlcGFydG1lbnQgPSBkZXBhcnRtZW50cy5nZXQoY29ubik7CiAgICAgICAgaWYgKGRlcGFydG1lbnQgPT0gVGhyZWFkLmN1cnJlbnRUaHJlYWQoKSkKICAgICAgICAgICAgcG9zc2Vzc2VkQ29ubmVjdGlvbi5nZXQoKS5yZW1vdmUoY29ubik7CiAgICAgICAgZGVwYXJ0bWVudHMucmVtb3ZlKGNvbm4pOwogICAgfQogICAgCiAgICBiZWZvcmUoQ29ubmVjdGlvbiBuZXdDb25uLCBPYmplY3QgdGhlT2JqKSA6IHJldGFpbkNvbm5lY3Rpb24obmV3Q29ubiwgdGhlT2JqKSB7CiAgICAgICAgQ29ubmVjdGlvbiBvbGRDb25uID0gKENvbm5lY3Rpb24pIGdldEZpZWxkVmFsdWUodGhlT2JqLCB0aGlzSm9pblBvaW50LmdldFNpZ25hdHVyZSgpLmdldE5hbWUoKSk7CiAgICAgICAgaWYgKGlzVHJhY2tpbmcob2xkQ29ubikpCiAgICAgICAgICAgIHJlbGVhc2Uob2xkQ29ubik7CiAgICAgICAgaWYgKGlzVHJhY2tpbmcobmV3Q29ubikpCiAgICAgICAgICAgIHJldGFpbihuZXdDb25uKTsKICAgIH0KICAgIAogICAgYmVmb3JlKENvbm5lY3Rpb24gbmV3Q29ubikgOiByZXRhaW5Db25uZWN0aW9uU3RhdGljKG5ld0Nvbm4pIHsKICAgICAgICBTaWduYXR1cmUgc2lnID0gdGhpc0pvaW5Qb2ludC5nZXRTaWduYXR1cmUoKTsKICAgICAgICBDb25uZWN0aW9uIG9sZENvbm4gPSAoQ29ubmVjdGlvbikgZ2V0U3RhdGljRmllbGRWYWx1ZShzaWcuZ2V0RGVjbGFyaW5nVHlwZSgpLCBzaWcuZ2V0TmFtZSgpKTsKICAgICAgICBpZiAoaXNUcmFja2luZyhvbGRDb25uKSkKICAgICAgICAgICAgcmVsZWFzZShvbGRDb25uKTsKICAgICAgICBpZiAoaXNUcmFja2luZyhuZXdDb25uKSkKICAgICAgICAgICAgcmV0YWluKG5ld0Nvbm4pOwogICAgfQogICAgCiAgICBwcml2YXRlIGJvb2xlYW4gaXNUcmFja2luZyhDb25uZWN0aW9uIGNvbm4pIHsKICAgICAgICByZXR1cm4gcmVmQ291bnRzLmNvbnRhaW5zS2V5KGNvbm4pOwogICAgfQogICAgCiAgICBwcml2YXRlIHZvaWQgcmV0YWluKENvbm5lY3Rpb24gY29ubikgewogICAgICAgIGludCByZWZDb3VudCA9IHJlZkNvdW50cy5nZXQoY29ubikuaW5jcmVtZW50QW5kR2V0KCk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGYoIltSZXRhaW5dICVzWyVkXSVuIiwgY29ubiwgcmVmQ291bnQpOwogICAgfQogICAgCiAgICBwcml2YXRlIHZvaWQgcmVsZWFzZShDb25uZWN0aW9uIGNvbm4pIHsKICAgICAgICBpbnQgcmVmQ291bnQgPSByZWZDb3VudHMuZ2V0KGNvbm4pLmRlY3JlbWVudEFuZEdldCgpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRmKCJbUmVsZWFzZV0gJXNbJWRdJW4iLCBjb25uLCByZWZDb3VudCk7CiAgICAgICAgaWYgKHJlZkNvdW50IDwgMSAmJiAhZGVwYXJ0bWVudHMuZ2V0KGNvbm4pLmlzQWxpdmUoKSkgewogICAgICAgICAgICByZXR1cm5Db25uZWN0aW9uKGNvbm4sIGZhbHNlKTsKICAgICAgICB9CiAgICB9CiAgICAKICAgIHByaXZhdGUgdm9pZCB0cnlUb1JldHVybkNvbm5lY3Rpb24oKSB7CiAgICAgICAgaW50IHN0YWNrRGVwdGggPSBkZXB0aC5nZXQoKTsKICAgICAgICBNYXA8Q29ubmVjdGlvbiwgSW50ZWdlcj4gY29ublRhYmxlID0gcG9zc2Vzc2VkQ29ubmVjdGlvbi5nZXQoKTsKICAgICAgICBMaXN0PENvbm5lY3Rpb24+IHdpbGxSZXR1cm4gPSBuZXcgTGlua2VkTGlzdDxDb25uZWN0aW9uPigpOwogICAgICAgIGZvciAoQ29ubmVjdGlvbiBjb25uIDogY29ublRhYmxlLmtleVNldCgpKSB7CiAgICAgICAgICAgIGlmICghaXNUcmFja2luZyhjb25uKSkgY29udGludWU7CiAgICAgICAgICAgIGludCBib3JuRGVwdGggPSBjb25uVGFibGUuZ2V0KGNvbm4pOwogICAgICAgICAgICBpZiAoYm9ybkRlcHRoID4gc3RhY2tEZXB0aCAmJiByZWZDb3VudHMuZ2V0KGNvbm4pLmludFZhbHVlKCkgPCAxKQogICAgICAgICAgICAgICAgd2lsbFJldHVybi5hZGQoY29ubik7CiAgICAgICAgfQogICAgICAgIAogICAgICAgIGZvciAoQ29ubmVjdGlvbiBjb25uIDogd2lsbFJldHVybikgewogICAgICAgICAgICByZXR1cm5Db25uZWN0aW9uKGNvbm4sIHRydWUpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgcHJpdmF0ZSB2b2lkIHJldHVybkNvbm5lY3Rpb24oQ29ubmVjdGlvbiBjb25uLCBib29sZWFuIGluT3JpZ2luYWxEZXBhcnRtZW50KSB7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGYoIltBdXRvIGNsb3NlXSAlcyVuIiwgY29ubik7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgY29ubi5jbG9zZSgpOwogICAgICAgIH0KICAgICAgICBjYXRjaCAoamF2YS5zcWwuU1FMRXhjZXB0aW9uIGUpIHsKICAgICAgICB9CiAgICAgICAgcmVmQ291bnRzLnJlbW92ZShjb25uKTsKICAgICAgICBkZXBhcnRtZW50cy5yZW1vdmUoY29ubik7CiAgICAgICAgaWYgKGluT3JpZ2luYWxEZXBhcnRtZW50KSB7CiAgICAgICAgICAgIHBvc3Nlc3NlZENvbm5lY3Rpb24uZ2V0KCkucmVtb3ZlKGNvbm4pOwogICAgICAgIH0KICAgIH0KICAgIAogICAgcHJpdmF0ZSB2b2lkIGxvZ01ldGhvZChTaWduYXR1cmUgc2lnLCBib29sZWFuIGlzRW50ZXJpbmcpIHsKICAgICAgICBpbnQgc3RhY2tEZXB0aCA9IGRlcHRoLmdldCgpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRmKCIlczwlcyVzOiVzPiVuIiwKICAgICAgICAgICAgY29tcHV0ZUluZGVudGF0aW9uKHN0YWNrRGVwdGgpLAogICAgICAgICAgICBpc0VudGVyaW5nPyAiIiA6ICIvIiwKICAgICAgICAgICAgVGhyZWFkLmN1cnJlbnRUaHJlYWQoKS5nZXROYW1lKCksIHNpZyk7CiAgICB9CiAgICAKICAgIHByaXZhdGUgU3RyaW5nIGNvbXB1dGVJbmRlbnRhdGlvbihpbnQgbGV2ZWwpIHsKICAgICAgICBTdHJpbmdCdWlsZGVyIGJ1ZiA9IG5ldyBTdHJpbmdCdWlsZGVyKCk7CiAgICAgICAgZm9yIChpbnQgaSA9IDA7IGkgPCBsZXZlbDsgKytpKQogICAgICAgICAgICBidWYuYXBwZW5kKCIgICIpOwogICAgICAgIHJldHVybiBidWYudG9TdHJpbmcoKTsKICAgIH0KICAgIAogICAgcHJpdmF0ZSBPYmplY3QgZ2V0RmllbGRWYWx1ZShPYmplY3Qgb2JqLCBTdHJpbmcgbmFtZSkgewogICAgICAgIEZpZWxkIGZpZWxkID0gbnVsbDsKICAgICAgICB0cnkgewogICAgICAgICAgICBmaWVsZCA9IG9iai5nZXRDbGFzcygpLmdldERlY2xhcmVkRmllbGQobmFtZSk7CiAgICAgICAgICAgIGlmIChNb2RpZmllci5pc1N0YXRpYyhmaWVsZC5nZXRNb2RpZmllcnMoKSkpCiAgICAgICAgICAgICAgICBmaWVsZCA9IG51bGw7CiAgICAgICAgfQogICAgICAgIGNhdGNoIChFeGNlcHRpb24gZSkgewogICAgICAgIH0KICAgICAgICBpZiAoZmllbGQgPT0gbnVsbCkgewogICAgICAgICAgICB0cnkgewogICAgICAgICAgICAgICAgZmllbGQgPSBvYmouZ2V0Q2xhc3MoKS5nZXRGaWVsZChuYW1lKTsKICAgICAgICAgICAgICAgIGlmIChNb2RpZmllci5pc1N0YXRpYyhmaWVsZC5nZXRNb2RpZmllcnMoKSkpCiAgICAgICAgICAgICAgICAgICAgZmllbGQgPSBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNhdGNoIChFeGNlcHRpb24gZTEpIHsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZmllbGQgPT0gbnVsbCkKICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFeGNlcHRpb24oU3RyaW5nLmZvcm1hdCgiY2FuJ3QgZmluZCBpbnN0YW5jZSBmaWVsZCBuYW1lZDogJXMgaW4gY2xhc3M6ICVzIiwgbmFtZSwgb2JqLmdldENsYXNzKCkpKTsKICAgICAgICBmaWVsZC5zZXRBY2Nlc3NpYmxlKHRydWUpOwogICAgICAgIHRyeSB7CiAgICAgICAgICAgIHJldHVybiBmaWVsZC5nZXQob2JqKTsKICAgICAgICB9CiAgICAgICAgY2F0Y2ggKEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBSdW50aW1lRXhjZXB0aW9uKGUpOwogICAgICAgIH0KICAgIH0KICAgIAogICAgcHJpdmF0ZSBPYmplY3QgZ2V0U3RhdGljRmllbGRWYWx1ZShDbGFzczw/PiBrbGFzcywgU3RyaW5nIG5hbWUpIHsKICAgICAgICBGaWVsZCBmaWVsZCA9IG51bGw7CiAgICAgICAgdHJ5IHsKICAgICAgICAgICAgZmllbGQgPSBrbGFzcy5nZXREZWNsYXJlZEZpZWxkKG5hbWUpOwogICAgICAgICAgICBpZiAoIU1vZGlmaWVyLmlzU3RhdGljKGZpZWxkLmdldE1vZGlmaWVycygpKSkKICAgICAgICAgICAgICAgIGZpZWxkID0gbnVsbDsKICAgICAgICB9CiAgICAgICAgY2F0Y2ggKEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgfQogICAgICAgIGlmIChmaWVsZCA9PSBudWxsKSB7CiAgICAgICAgICAgIHRyeSB7CiAgICAgICAgICAgICAgICBmaWVsZCA9IGtsYXNzLmdldEZpZWxkKG5hbWUpOwogICAgICAgICAgICAgICAgaWYgKCFNb2RpZmllci5pc1N0YXRpYyhmaWVsZC5nZXRNb2RpZmllcnMoKSkpCiAgICAgICAgICAgICAgICAgICAgZmllbGQgPSBudWxsOwogICAgICAgICAgICB9CiAgICAgICAgICAgIGNhdGNoIChFeGNlcHRpb24gZTEpIHsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoZmllbGQgPT0gbnVsbCkKICAgICAgICAgICAgdGhyb3cgbmV3IFJ1bnRpbWVFeGNlcHRpb24oU3RyaW5nLmZvcm1hdCgiY2FuJ3QgZmluZCBzdGF0aWMgZmllbGQgbmFtZWQ6ICVzIGluIGNsYXNzOiAlcyIsIG5hbWUsIGtsYXNzKSk7CiAgICAgICAgZmllbGQuc2V0QWNjZXNzaWJsZSh0cnVlKTsKICAgICAgICB0cnkgewogICAgICAgICAgICByZXR1cm4gZmllbGQuZ2V0KGtsYXNzKTsKICAgICAgICB9CiAgICAgICAgY2F0Y2ggKEV4Y2VwdGlvbiBlKSB7CiAgICAgICAgICAgIHRocm93IG5ldyBSdW50aW1lRXhjZXB0aW9uKGUpOwogICAgICAgIH0KICAgIH0KfQo=