7
7
package com.diffplug.atplug
8
8
9
9
import java.io.ByteArrayOutputStream
10
+ import java.io.EOFException
10
11
import java.lang.reflect.Constructor
11
12
import java.net.URL
12
13
import java.nio.charset.StandardCharsets
13
- import java.util.*
14
14
import java.util.jar.Manifest
15
15
import java.util.zip.ZipException
16
16
@@ -33,22 +33,12 @@ interface PlugRegistry {
33
33
private const val PATH_MANIFEST = " META-INF/MANIFEST.MF"
34
34
private const val DS_WITHIN_MANIFEST = " AtPlug-Component"
35
35
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
-
46
36
fun setHarness (data : PlugInstanceMap ? ) {
47
37
val registry = instance.value
48
38
if (registry is Eager ) {
49
39
registry.setHarness(data)
50
40
} else {
51
- throw AssertionError (" Registry must not be set, was ${ registry} " )
41
+ throw AssertionError (" Registry must not be set, was $registry " )
52
42
}
53
43
}
54
44
}
@@ -62,49 +52,81 @@ interface PlugRegistry {
62
52
val values = Eager ::class .java.classLoader.getResources(PATH_MANIFEST )
63
53
while (values.hasMoreElements()) {
64
54
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)
95
87
}
96
88
}
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
+ }
97
101
}
98
102
}
99
103
}
100
104
}
101
105
}
102
106
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
+
103
125
override fun <T > registerSocket (socketClass : Class <T >, socketOwner : SocketOwner <T >) {
104
126
synchronized(this ) {
105
127
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)
108
130
}
109
131
}
110
132
@@ -128,7 +150,7 @@ interface PlugRegistry {
128
150
" Class must have a no-arg constructor, but it didn't. " +
129
151
clazz +
130
152
" " +
131
- Arrays .asList (* clazz.constructors)
153
+ listOf (* clazz.constructors)
132
154
}
133
155
return constructor .newInstance() as T
134
156
}
@@ -138,12 +160,12 @@ interface PlugRegistry {
138
160
fun setHarness (newHarness : PlugInstanceMap ? ) {
139
161
val toRemove = lastHarness ? : data
140
162
toRemove.descriptorMap.forEach { (clazz, plugDescriptors) ->
141
- owners.get( clazz) ?.let { owner -> plugDescriptors.forEach(owner::doRemove) }
163
+ owners[ clazz] ?.let { owner -> plugDescriptors.forEach(owner::doRemove) }
142
164
}
143
165
144
166
val toAdd = newHarness ? : data
145
167
toAdd.descriptorMap.forEach { (clazz, plugDescriptors) ->
146
- owners.get( clazz) ?.let { owner -> plugDescriptors.forEach(owner::doRegister) }
168
+ owners[ clazz] ?.let { owner -> plugDescriptors.forEach(owner::doRegister) }
147
169
}
148
170
lastHarness = newHarness
149
171
}
0 commit comments