77package com.diffplug.atplug
88
99import java.io.ByteArrayOutputStream
10+ import java.io.EOFException
1011import java.lang.reflect.Constructor
1112import java.net.URL
1213import java.nio.charset.StandardCharsets
13- import java.util.*
1414import java.util.jar.Manifest
1515import java.util.zip.ZipException
1616
@@ -33,22 +33,12 @@ interface PlugRegistry {
3333 private const val PATH_MANIFEST = " META-INF/MANIFEST.MF"
3434 private const val DS_WITHIN_MANIFEST = " AtPlug-Component"
3535
36- internal fun parseComponent (manifestUrl : String , servicePath : String ): PlugDescriptor {
37- val serviceUrl =
38- URL (manifestUrl.substring(0 , manifestUrl.length - PATH_MANIFEST .length) + servicePath)
39-
40- val out = ByteArrayOutputStream ()
41- serviceUrl.openStream().use { it.copyTo(out ) }
42- val serviceFileContent = String (out .toByteArray(), StandardCharsets .UTF_8 )
43- return PlugDescriptor .fromJson(serviceFileContent)
44- }
45-
4636 fun setHarness (data : PlugInstanceMap ? ) {
4737 val registry = instance.value
4838 if (registry is Eager ) {
4939 registry.setHarness(data)
5040 } else {
51- throw AssertionError (" Registry must not be set, was ${ registry} " )
41+ throw AssertionError (" Registry must not be set, was $registry " )
5242 }
5343 }
5444 }
@@ -62,49 +52,81 @@ interface PlugRegistry {
6252 val values = Eager ::class .java.classLoader.getResources(PATH_MANIFEST )
6353 while (values.hasMoreElements()) {
6454 val manifestUrl = values.nextElement()
65- manifestUrl.openStream().use { stream ->
66- // parse the manifest
67- val manifest = Manifest (stream)
68- val services = manifest.mainAttributes.getValue(DS_WITHIN_MANIFEST )
69- if (services != null ) {
70- // it's got declarative services!
71- for (service in
72- services.split(" ," .toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
73- val servicePath = service.trim { it <= ' ' }
74- try {
75- if (servicePath.isNotEmpty()) {
76- val asString = manifestUrl.toExternalForm()
77- val component = parseComponent(asString, servicePath)
78- synchronized(this ) {
79- data.putDescriptor(component.provides, component)
80- owners.get(component.provides)?.doRegister(component)
81- }
82- }
83- } catch (e: ZipException ) {
84- // When a JVM loads a jar, it mmaps the jar. If that jar changes
85- // (as it does when generating plugin metadata in a Gradle daemon)
86- // then you get ZipException after the change. The accuracy of the
87- // registry is irrelevant during metadata generation - the registry
88- // exists during metadata generation only because the `SocketOwner`s
89- // register themselves in their constructors. Therefore, it is safe to
90- // ignore these errors during metadata generation.
91- val prop = System .getProperty(" atplug.generate" )
92- if (prop != " true" ) {
93- throw e
94- }
55+ try {
56+ parseManifest(manifestUrl, true )
57+ } catch (e: EOFException ) {
58+ // do the parsing again but this time disable caching
59+ // https://stackoverflow.com/questions/36517604/closing-a-jarurlconnection
60+ parseManifest(manifestUrl, false )
61+ }
62+ }
63+ }
64+ }
65+
66+ private fun parseManifest (manifestUrl : URL , allowCaching : Boolean ) {
67+ val connection = manifestUrl.openConnection()
68+ if (! allowCaching) {
69+ connection.useCaches = false
70+ }
71+ connection.getInputStream().use { stream ->
72+ // parse the manifest
73+ val manifest = Manifest (stream)
74+ val services = manifest.mainAttributes.getValue(DS_WITHIN_MANIFEST )
75+ if (services != null ) {
76+ // it's got declarative services!
77+ for (service in
78+ services.split(" ," .toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
79+ val servicePath = service.trim { it <= ' ' }
80+ try {
81+ if (servicePath.isNotEmpty()) {
82+ val asString = manifestUrl.toExternalForm()
83+ val component = parseComponent(asString, servicePath, allowCaching)
84+ synchronized(this ) {
85+ data.putDescriptor(component.provides, component)
86+ owners[component.provides]?.doRegister(component)
9587 }
9688 }
89+ } catch (e: ZipException ) {
90+ // When a JVM loads a jar, it mmaps the jar. If that jar changes
91+ // (as it does when generating plugin metadata in a Gradle daemon)
92+ // then you get ZipException after the change. The accuracy of the
93+ // registry is irrelevant during metadata generation - the registry
94+ // exists during metadata generation only because the `SocketOwner`s
95+ // register themselves in their constructors. Therefore, it is safe to
96+ // ignore these errors during metadata generation.
97+ val prop = System .getProperty(" atplug.generate" )
98+ if (prop != " true" ) {
99+ throw e
100+ }
97101 }
98102 }
99103 }
100104 }
101105 }
102106
107+ private fun parseComponent (
108+ manifestUrl : String ,
109+ servicePath : String ,
110+ allowCaching : Boolean
111+ ): PlugDescriptor {
112+ val serviceUrl =
113+ URL (manifestUrl.substring(0 , manifestUrl.length - PATH_MANIFEST .length) + servicePath)
114+
115+ val connection = serviceUrl.openConnection()
116+ if (! allowCaching) {
117+ connection.useCaches = false
118+ }
119+ val out = ByteArrayOutputStream ()
120+ connection.getInputStream().use { it.copyTo(out ) }
121+ val serviceFileContent = String (out .toByteArray(), StandardCharsets .UTF_8 )
122+ return PlugDescriptor .fromJson(serviceFileContent)
123+ }
124+
103125 override fun <T > registerSocket (socketClass : Class <T >, socketOwner : SocketOwner <T >) {
104126 synchronized(this ) {
105127 val prevOwner = owners.put(socketClass.name, socketOwner)
106- assert (prevOwner == null ) { " Multiple owners registered for ${ socketClass} " }
107- data.descriptorMap.get( socketClass.name) ?.forEach(socketOwner::doRegister)
128+ assert (prevOwner == null ) { " Multiple owners registered for $socketClass " }
129+ data.descriptorMap[ socketClass.name] ?.forEach(socketOwner::doRegister)
108130 }
109131 }
110132
@@ -128,7 +150,7 @@ interface PlugRegistry {
128150 " Class must have a no-arg constructor, but it didn't. " +
129151 clazz +
130152 " " +
131- Arrays .asList (* clazz.constructors)
153+ listOf (* clazz.constructors)
132154 }
133155 return constructor .newInstance() as T
134156 }
@@ -138,12 +160,12 @@ interface PlugRegistry {
138160 fun setHarness (newHarness : PlugInstanceMap ? ) {
139161 val toRemove = lastHarness ? : data
140162 toRemove.descriptorMap.forEach { (clazz, plugDescriptors) ->
141- owners.get( clazz) ?.let { owner -> plugDescriptors.forEach(owner::doRemove) }
163+ owners[ clazz] ?.let { owner -> plugDescriptors.forEach(owner::doRemove) }
142164 }
143165
144166 val toAdd = newHarness ? : data
145167 toAdd.descriptorMap.forEach { (clazz, plugDescriptors) ->
146- owners.get( clazz) ?.let { owner -> plugDescriptors.forEach(owner::doRegister) }
168+ owners[ clazz] ?.let { owner -> plugDescriptors.forEach(owner::doRegister) }
147169 }
148170 lastHarness = newHarness
149171 }
0 commit comments