背景
近期,由于工作需要研究了下truelicense,给xxx添加一个证书,限制产品的使用期限。前期将truelicense整合到spring-boot项目中很容易,过程中没有出现问题,但是同样的代码在整合到osgi容器中的时候,出现了异常,异常如下:
de.schlichtherle.xml.PersistenceServiceException: java.lang.reflect.UndeclaredThrowableException
at de.schlichtherle.xml.PersistenceService.load(PersistenceService.java:397)[311:truelicense-xml:1.33.0]
at de.schlichtherle.license.PrivacyGuard.key2cert(PrivacyGuard.java:174)[312:truelicense-core:1.33.0]
at com.monk.core.license.CustomLicenseManager.install(CustomLicenseManager.java:48)[306:com.monk.core:1.0.0]
at de.schlichtherle.license.LicenseManager.install(LicenseManager.java:406)[312:truelicense-core:1.33.0]
at de.schlichtherle.license.LicenseManager.install(LicenseManager.java:382)[312:truelicense-core:1.33.0]
at com.monk.core.license.LicenseVerify.installLicense(LicenseVerify.java:80)[306:com.monk.core:1.0.0]
at com.monk.core.CoreBundleActivator.start(CoreBundleActivator.java:95)[306:com.monk.core:1.0.0]
at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:645)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.Felix.activateBundle(Felix.java:2146)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2064)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:955)[org.apache.felix.framework-4.2.1.jar:]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundle(DirectoryWatcher.java:1245)[7:org.apache.felix.fileinstall:3.5.0]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startBundles(DirectoryWatcher.java:1217)[7:org.apache.felix.fileinstall:3.5.0]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.startAllBundles(DirectoryWatcher.java:1207)[7:org.apache.felix.fileinstall:3.5.0]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.doProcess(DirectoryWatcher.java:504)[7:org.apache.felix.fileinstall:3.5.0]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.process(DirectoryWatcher.java:358)[7:org.apache.felix.fileinstall:3.5.0]
at org.apache.felix.fileinstall.internal.DirectoryWatcher.run(DirectoryWatcher.java:310)[7:org.apache.felix.fileinstall:3.5.0]
Caused by: java.lang.reflect.UndeclaredThrowableException
at de.schlichtherle.xml.PersistenceService$1.exceptionThrown(PersistenceService.java:79)
at com.sun.beans.decoder.DocumentHandler.handleException(DocumentHandler.java:359)[:1.8.0_212]
at com.sun.beans.decoder.DocumentHandler$1.run(DocumentHandler.java:388)[:1.8.0_212]
at com.sun.beans.decoder.DocumentHandler$1.run(DocumentHandler.java:372)[:1.8.0_212]
at java.security.AccessController.doPrivileged(Native Method)[:1.8.0_212]
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)[:1.8.0_212]
at com.sun.beans.decoder.DocumentHandler.parse(DocumentHandler.java:372)[:1.8.0_212]
at java.beans.XMLDecoder$1.run(XMLDecoder.java:201)[:1.8.0_212]
at java.beans.XMLDecoder$1.run(XMLDecoder.java:199)[:1.8.0_212]
at java.security.AccessController.doPrivileged(Native Method)[:1.8.0_212]
at java.beans.XMLDecoder.parsingComplete(XMLDecoder.java:199)[:1.8.0_212]
at java.beans.XMLDecoder.close(XMLDecoder.java:174)[:1.8.0_212]
at de.schlichtherle.xml.PersistenceService.load(PersistenceService.java:395)[311:truelicense-xml:1.33.0]
... 16 more
Caused by: java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)[:1.8.0_212]
at java.io.BufferedInputStream.fill(BufferedInputStream.java:214)[:1.8.0_212]
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)[:1.8.0_212]
at org.apache.xerces.impl.XMLEntityManager$RewindableInputStream.readAndBuffer(Unknown Source)[:]
at org.apache.xerces.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)[:]
at org.apache.xerces.impl.XMLVersionDetector.determineDocVersion(Unknown Source)[:]
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)[:]
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)[:]
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)[:]
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)[:]
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)[:]
at org.apache.xerces.jaxp.SAXParserImpl.parse(Unknown Source)[:]
at com.sun.beans.decoder.DocumentHandler$1.run(DocumentHandler.java:375)[:1.8.0_212]
... 26 more
异常分析:
首先从错误堆栈信息来看,能看出来问题是出在解析XML的时候,java.beans.XMLDecoder.close()方法在关闭文件流的时候发现文件流已经被关闭了。于是就可以带着下面的几个问题去跟一下代码
- 为什么会解析XML? 在哪里解析的XML —> 我生成的证书是个加密文件也不是XML呀,莫非这个加密文件在经过truelicense解密后就是个xml文件,毕竟用xml来存储配置信息也很常见。
- 如果是解析XML,解析XML的方式有多种,有没有可能出现了jar包冲突
既然有这两个问题,那么truelicense又是开源的,先把源码down下来,刨一下truelicense的源码,肯定可以验证第一个疑问的猜想,以及第一个疑问答案在哪里解析的XML
源码分析
在安装证书的时候,需要传给LicenseManager这个类其中一个参数就是证书的位置,LicenseManager将证书读成byte[]数组,经过一系列的解析(加解密就略过了,不是重点)最终得到一个InputStream,将这个流打印出来发现就是一个XML,解析XML的方式是通过SAXParser去解析的。(解开了第一个疑问)
// 入参key就是证书文件的byte[] 该方法在de.schlichtherle.license.LicenseManager中
protected synchronized LicenseContent install(final byte[] key, final LicenseNotary notary) throws Exception {
// 这一行就是将证书文件解析成GenericCertificate对象
final GenericCertificate certificate = getPrivacyGuard().key2cert(key);
notary.verify(certificate);
final LicenseContent content = (LicenseContent) certificate.getContent();
validate(content);
setLicenseKey(key);
setCertificate(certificate);
return content;
}
// 这个方法的作用就是将证书的字节流解析转换成GenericCertificate对象(凭证信息) 该方法在de.schlichtherle.license.PrivacyGuard中
public GenericCertificate key2cert(final byte[] key) throws Exception {
// 这一行姑且理解为将证书文件解密之后读成一个InputSteam(XML形式)
final InputStream in = new GZIPInputStream(new ByteArrayInputStream(getCipher4Decryption().doFinal(key)));
final GenericCertificate certificate;
try {
// 再经过这个方法将XML解析成GenericCertificate对象
// PersistenceService.load(in)方法返回的是一个Object对象,再强转成GenericCertificate对象
certificate = (GenericCertificate) PersistenceService.load(in);
}
finally {
try {
in.close(); }
catch (IOException weDontCare) {
}
}
return certificate;
}
// 解析XML的具体方法 在de.schlichtherle.xml.PersistenceService类中
public static Object load(InputStream xmlIn) throws PersistenceServiceException {
if (null == xmlIn) throw new NullPointerException();
XMLDecoder decoder = null;
try {
// Note that the constructor already loads the complete object
// graph into memory. If anything goes wrong, an unchecked
// exception is thrown already HERE!
decoder = new XMLDecoder(
new BufferedInputStream(xmlIn, BUFSIZE),
null,
createExceptionListener());
// decoder.readObject()方法就是解析XML的具体方法,前面日志中打印出来的close()方法就是在这个方法中调用的
return decoder.readObject();
} catch (final UndeclaredThrowableException ex) {
throw new PersistenceServiceException(ex.getCause()); // unwrap cause
} catch (final Throwable ex) {
throw new PersistenceServiceException(ex);
} finally {
if (null != decoder) {
try {
decoder.close(); // Could throw e.g. OutOfMemoryError (again)!
} catch (final Throwable paranoid) {
throw new PersistenceServiceException(paranoid);
}
}
}
}
从XMLDecoder.readObject()这个方法一路跟jdk的源码,源码的调用链如下:
java.beans.XMLDecoder#readObject --> com.sun.beans.decoder.DocumentHandler#parse --> com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl#newSAXParserImpl
// 解析XML的真实实现类 在com.sun.beans.decoder.DocumentHandler中
public void parse(final InputSource var1) {
if (this.acc == null && null != System.getSecurityManager()) {
throw new SecurityException("AccessControlContext is not set");
} else {
AccessControlContext var2 = AccessController.getContext();
SharedSecrets.getJavaSecurityAccess().doIntersectionPrivilege(new PrivilegedAction<Void>() {
public Void run() {
try {
SAXParserFactory.newInstance().newSAXParser().parse(var1, DocumentHandler.this);
} catch (ParserConfigurationException var3) {
DocumentHandler.this.handleException(var3)

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



