Lines 47-56
Link Here
|
47 |
import java.io.ByteArrayInputStream; |
47 |
import java.io.ByteArrayInputStream; |
48 |
import java.io.IOException; |
48 |
import java.io.IOException; |
49 |
import java.io.InputStream; |
49 |
import java.io.InputStream; |
|
|
50 |
import java.io.OutputStream; |
51 |
import java.net.URL; |
52 |
import java.util.List; |
50 |
import java.util.Stack; |
53 |
import java.util.Stack; |
51 |
import java.util.concurrent.atomic.AtomicBoolean; |
54 |
import java.util.concurrent.atomic.AtomicBoolean; |
52 |
import javax.xml.parsers.ParserConfigurationException; |
55 |
import javax.xml.parsers.ParserConfigurationException; |
|
|
56 |
import org.netbeans.api.annotations.common.NonNull; |
57 |
import org.netbeans.spi.project.libraries.LibraryImplementation; |
58 |
import org.netbeans.spi.project.libraries.LibraryTypeProvider; |
59 |
import org.netbeans.spi.project.libraries.NamedLibraryImplementation; |
60 |
import org.openide.filesystems.FileObject; |
53 |
import org.openide.xml.XMLUtil; |
61 |
import org.openide.xml.XMLUtil; |
|
|
62 |
import org.w3c.dom.Document; |
63 |
import org.w3c.dom.Element; |
54 |
import org.xml.sax.Attributes; |
64 |
import org.xml.sax.Attributes; |
55 |
import org.xml.sax.ContentHandler; |
65 |
import org.xml.sax.ContentHandler; |
56 |
import org.xml.sax.EntityResolver; |
66 |
import org.xml.sax.EntityResolver; |
Lines 75-84
Link Here
|
75 |
*/ |
85 |
*/ |
76 |
public class LibraryDeclarationParser implements ContentHandler, EntityResolver { |
86 |
public class LibraryDeclarationParser implements ContentHandler, EntityResolver { |
77 |
|
87 |
|
|
|
88 |
private static final String LIBRARY_DEF_1 = "-//NetBeans//DTD Library Declaration 1.0//EN"; //NOI18N |
89 |
private static final String LIBRARY_DTD_1 = "http://www.netbeans.org/dtds/library-declaration-1_0.dtd"; //NOI18N |
90 |
static final String LIBRARY_NS = "http://www.netbeans.org/ns/library-declaration/2"; //NOI18N |
91 |
static final String VER_1 = "1.0"; //NOI18N |
92 |
static final String VER_2 = "2.0"; //NOI18N |
93 |
private static final String LIBRARY = "library"; //NOI18N |
94 |
private static final String VERSION = "version"; //NOI18N |
95 |
private static final String VOLUME = "volume"; //NOI18N |
96 |
private static final String DESCRIPTION = "description"; //NOI18N |
97 |
private static final String TYPE = "type"; //NOI18N |
98 |
private static final String RESOURCE = "resource"; //NOI18N |
99 |
private static final String NAME = "name"; //NOI18N |
100 |
private static final String BUNDLE = "localizing-bundle"; //NOI18N |
101 |
private static final String DISPLAY_NAME = "display-name"; //NOI18N |
102 |
|
78 |
private StringBuffer buffer; |
103 |
private StringBuffer buffer; |
79 |
private final LibraryDeclarationConvertor parslet; |
104 |
private final LibraryDeclarationConvertor parslet; |
80 |
private final LibraryDeclarationHandler handler; |
105 |
private final LibraryDeclarationHandler handler; |
81 |
private Stack<Object[]> context; |
106 |
private Stack<Object[]> context; |
|
|
107 |
private String expectedNS; |
82 |
private final AtomicBoolean used = new AtomicBoolean(); |
108 |
private final AtomicBoolean used = new AtomicBoolean(); |
83 |
|
109 |
|
84 |
/** |
110 |
/** |
Lines 98-103
Link Here
|
98 |
* This SAX interface method is implemented by the parser. |
124 |
* This SAX interface method is implemented by the parser. |
99 |
* |
125 |
* |
100 |
*/ |
126 |
*/ |
|
|
127 |
@Override |
101 |
public final void setDocumentLocator(Locator locator) { |
128 |
public final void setDocumentLocator(Locator locator) { |
102 |
} |
129 |
} |
103 |
|
130 |
|
Lines 105-110
Link Here
|
105 |
* This SAX interface method is implemented by the parser. |
132 |
* This SAX interface method is implemented by the parser. |
106 |
* |
133 |
* |
107 |
*/ |
134 |
*/ |
|
|
135 |
@Override |
108 |
public final void startDocument() throws SAXException { |
136 |
public final void startDocument() throws SAXException { |
109 |
handler.startDocument(); |
137 |
handler.startDocument(); |
110 |
} |
138 |
} |
Lines 113-118
Link Here
|
113 |
* This SAX interface method is implemented by the parser. |
141 |
* This SAX interface method is implemented by the parser. |
114 |
* |
142 |
* |
115 |
*/ |
143 |
*/ |
|
|
144 |
@Override |
116 |
public final void endDocument() throws SAXException { |
145 |
public final void endDocument() throws SAXException { |
117 |
handler.endDocument(); |
146 |
handler.endDocument(); |
118 |
} |
147 |
} |
Lines 121-133
Link Here
|
121 |
* This SAX interface method is implemented by the parser. |
150 |
* This SAX interface method is implemented by the parser. |
122 |
* |
151 |
* |
123 |
*/ |
152 |
*/ |
|
|
153 |
@Override |
124 |
public final void startElement(String ns, String name, String qname, Attributes attrs) throws SAXException { |
154 |
public final void startElement(String ns, String name, String qname, Attributes attrs) throws SAXException { |
125 |
dispatch(true); |
155 |
dispatch(true); |
126 |
context.push(new Object[] {qname, new AttributesImpl(attrs)}); |
156 |
context.push(new Object[] {qname, ns, new AttributesImpl(attrs)}); |
127 |
if ("volume".equals(qname)) { |
157 |
if (VOLUME.equals(qname)) { |
128 |
handler.start_volume(attrs); |
158 |
handler.start_volume(attrs); |
129 |
} else if ("library".equals(qname)) { |
159 |
} else if (LIBRARY.equals(qname)) { |
130 |
handler.start_library(attrs); |
160 |
expectedNS = handler.start_library(ns, attrs); |
131 |
} |
161 |
} |
132 |
} |
162 |
} |
133 |
|
163 |
|
Lines 135-146
Link Here
|
135 |
* This SAX interface method is implemented by the parser. |
165 |
* This SAX interface method is implemented by the parser. |
136 |
* |
166 |
* |
137 |
*/ |
167 |
*/ |
|
|
168 |
@Override |
138 |
public final void endElement(String ns, String name, String qname) throws SAXException { |
169 |
public final void endElement(String ns, String name, String qname) throws SAXException { |
139 |
dispatch(false); |
170 |
dispatch(false); |
140 |
context.pop(); |
171 |
context.pop(); |
141 |
if ("volume".equals(qname)) { |
172 |
if (VOLUME.equals(qname)) { |
142 |
handler.end_volume(); |
173 |
handler.end_volume(); |
143 |
} else if ("library".equals(qname)) { |
174 |
} else if (LIBRARY.equals(qname)) { |
144 |
handler.end_library(); |
175 |
handler.end_library(); |
145 |
} |
176 |
} |
146 |
} |
177 |
} |
Lines 149-154
Link Here
|
149 |
* This SAX interface method is implemented by the parser. |
180 |
* This SAX interface method is implemented by the parser. |
150 |
* |
181 |
* |
151 |
*/ |
182 |
*/ |
|
|
183 |
@Override |
152 |
public final void characters(char[] chars, int start, int len) throws SAXException { |
184 |
public final void characters(char[] chars, int start, int len) throws SAXException { |
153 |
buffer.append(chars, start, len); |
185 |
buffer.append(chars, start, len); |
154 |
} |
186 |
} |
Lines 157-162
Link Here
|
157 |
* This SAX interface method is implemented by the parser. |
189 |
* This SAX interface method is implemented by the parser. |
158 |
* |
190 |
* |
159 |
*/ |
191 |
*/ |
|
|
192 |
@Override |
160 |
public final void ignorableWhitespace(char[] chars, int start, int len) throws SAXException { |
193 |
public final void ignorableWhitespace(char[] chars, int start, int len) throws SAXException { |
161 |
} |
194 |
} |
162 |
|
195 |
|
Lines 164-169
Link Here
|
164 |
* This SAX interface method is implemented by the parser. |
197 |
* This SAX interface method is implemented by the parser. |
165 |
* |
198 |
* |
166 |
*/ |
199 |
*/ |
|
|
200 |
@Override |
167 |
public final void processingInstruction(String target, String data) throws SAXException { |
201 |
public final void processingInstruction(String target, String data) throws SAXException { |
168 |
} |
202 |
} |
169 |
|
203 |
|
Lines 171-176
Link Here
|
171 |
* This SAX interface method is implemented by the parser. |
205 |
* This SAX interface method is implemented by the parser. |
172 |
* |
206 |
* |
173 |
*/ |
207 |
*/ |
|
|
208 |
@Override |
174 |
public final void startPrefixMapping(final String prefix, final String uri) throws SAXException { |
209 |
public final void startPrefixMapping(final String prefix, final String uri) throws SAXException { |
175 |
} |
210 |
} |
176 |
|
211 |
|
Lines 178-183
Link Here
|
178 |
* This SAX interface method is implemented by the parser. |
213 |
* This SAX interface method is implemented by the parser. |
179 |
* |
214 |
* |
180 |
*/ |
215 |
*/ |
|
|
216 |
@Override |
181 |
public final void endPrefixMapping(final String prefix) throws SAXException { |
217 |
public final void endPrefixMapping(final String prefix) throws SAXException { |
182 |
} |
218 |
} |
183 |
|
219 |
|
Lines 185-214
Link Here
|
185 |
* This SAX interface method is implemented by the parser. |
221 |
* This SAX interface method is implemented by the parser. |
186 |
* |
222 |
* |
187 |
*/ |
223 |
*/ |
|
|
224 |
@Override |
188 |
public final void skippedEntity(String name) throws SAXException { |
225 |
public final void skippedEntity(String name) throws SAXException { |
189 |
} |
226 |
} |
190 |
|
227 |
|
191 |
private void dispatch(final boolean fireOnlyIfMixed) throws SAXException { |
228 |
private void dispatch(final boolean fireOnlyIfMixed) throws SAXException { |
192 |
if (fireOnlyIfMixed && buffer.length() == 0) return; //skip it |
229 |
if (fireOnlyIfMixed && buffer.length() == 0) return; //skip it |
193 |
|
230 |
|
194 |
Object[] ctx = context.peek(); |
231 |
final Object[] ctx = context.peek(); |
195 |
String here = (String) ctx[0]; |
232 |
final String here = (String) ctx[0]; |
196 |
Attributes attrs = (Attributes) ctx[1]; |
233 |
final String ns = (String) ctx[1]; |
197 |
if ("description".equals(here)) { |
234 |
Attributes attrs = (Attributes) ctx[2]; |
|
|
235 |
if (!expectedNS.equals(ns)) { |
236 |
throw new SAXException("Invalid librray descriptor namespace"); // NOI18N |
237 |
} |
238 |
if (DESCRIPTION.equals(here)) { |
198 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
239 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
199 |
handler.handle_description (buffer.length() == 0 ? null : buffer.toString(), attrs); |
240 |
handler.handle_description (buffer.length() == 0 ? null : buffer.toString(), attrs); |
200 |
} else if ("type".equals(here)) { |
241 |
} else if (TYPE.equals(here)) { |
201 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
242 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
202 |
handler.handle_type(buffer.length() == 0 ? null : buffer.toString(), attrs); |
243 |
handler.handle_type(buffer.length() == 0 ? null : buffer.toString(), attrs); |
203 |
} else if ("resource".equals(here)) { |
244 |
} else if (RESOURCE.equals(here)) { |
204 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
245 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
205 |
handler.handle_resource(parslet.parseResource(buffer.length() == 0 ? null : buffer.toString()), attrs); |
246 |
handler.handle_resource(parslet.parseResource(buffer.length() == 0 ? null : buffer.toString()), attrs); |
206 |
} else if ("name".equals(here)) { |
247 |
} else if (NAME.equals(here)) { |
207 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
248 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
208 |
handler.handle_name(buffer.length() == 0 ? null : buffer.toString(), attrs); |
249 |
handler.handle_name(buffer.length() == 0 ? null : buffer.toString(), attrs); |
209 |
} else if ("localizing-bundle".equals(here)) { |
250 |
} else if (BUNDLE.equals(here)) { |
210 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
251 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
211 |
handler.handle_localizingBundle(buffer.length() == 0 ? null : buffer.toString(), attrs); |
252 |
handler.handle_localizingBundle(buffer.length() == 0 ? null : buffer.toString(), attrs); |
|
|
253 |
} else if (DISPLAY_NAME.equals(here) && LIBRARY_NS.equals(ns)) { |
254 |
if (fireOnlyIfMixed) throw new IllegalStateException("Unexpected characters() event! (Missing DTD?)"); |
255 |
handler.handle_displayName(buffer.length() == 0 ? null : buffer.toString(), attrs); |
212 |
} else { |
256 |
} else { |
213 |
//do not care |
257 |
//do not care |
214 |
} |
258 |
} |
Lines 225-251
Link Here
|
225 |
* |
269 |
* |
226 |
*/ |
270 |
*/ |
227 |
public void parse(final InputSource input) throws SAXException, ParserConfigurationException, IOException { |
271 |
public void parse(final InputSource input) throws SAXException, ParserConfigurationException, IOException { |
228 |
parse(input, this); |
|
|
229 |
} |
230 |
|
231 |
private void parse(final InputSource input, final LibraryDeclarationParser recognizer) throws SAXException, ParserConfigurationException, IOException { |
232 |
if (used.getAndSet(true)) { |
272 |
if (used.getAndSet(true)) { |
233 |
throw new IllegalStateException("The LibraryDeclarationParser was already used, create a new instance"); //NOI18N |
273 |
throw new IllegalStateException("The LibraryDeclarationParser was already used, create a new instance"); //NOI18N |
234 |
} |
274 |
} |
235 |
try { |
275 |
try { |
236 |
XMLReader parser = XMLUtil.createXMLReader(false, false); |
276 |
final XMLReader parser = XMLUtil.createXMLReader(false, true); |
237 |
parser.setContentHandler(recognizer); |
277 |
parser.setContentHandler(this); |
238 |
parser.setErrorHandler(recognizer.getDefaultErrorHandler()); |
278 |
parser.setErrorHandler(getDefaultErrorHandler()); |
239 |
parser.setEntityResolver(recognizer); |
279 |
parser.setEntityResolver(this); |
240 |
parser.parse(input); |
280 |
parser.parse(input); |
241 |
} finally { |
281 |
} finally { |
242 |
//Recover recognizer internal state from exceptions to be reusable |
282 |
//Recover recognizer internal state from exceptions to be reusable |
243 |
if (!recognizer.context.empty()) { |
283 |
if (!context.empty()) { |
244 |
recognizer.context.clear(); |
284 |
context.clear(); |
245 |
} |
285 |
} |
246 |
if (recognizer.buffer.length() > 0) { |
286 |
if (buffer.length() > 0) { |
247 |
recognizer.buffer.delete(0, recognizer.buffer.length()); |
287 |
buffer.delete(0, buffer.length()); |
248 |
} |
288 |
} |
|
|
289 |
expectedNS = null; |
249 |
} |
290 |
} |
250 |
} |
291 |
} |
251 |
|
292 |
|
Lines 256-269
Link Here
|
256 |
*/ |
297 |
*/ |
257 |
protected ErrorHandler getDefaultErrorHandler() { |
298 |
protected ErrorHandler getDefaultErrorHandler() { |
258 |
return new ErrorHandler() { |
299 |
return new ErrorHandler() { |
|
|
300 |
@Override |
259 |
public void error(SAXParseException ex) throws SAXException { |
301 |
public void error(SAXParseException ex) throws SAXException { |
260 |
throw ex; |
302 |
throw ex; |
261 |
} |
303 |
} |
262 |
|
304 |
|
|
|
305 |
@Override |
263 |
public void fatalError(SAXParseException ex) throws SAXException { |
306 |
public void fatalError(SAXParseException ex) throws SAXException { |
264 |
throw ex; |
307 |
throw ex; |
265 |
} |
308 |
} |
266 |
|
309 |
|
|
|
310 |
@Override |
267 |
public void warning(SAXParseException ex) throws SAXException { |
311 |
public void warning(SAXParseException ex) throws SAXException { |
268 |
// ignore |
312 |
// ignore |
269 |
} |
313 |
} |
Lines 273-285
Link Here
|
273 |
|
317 |
|
274 |
/** Implementation of entity resolver. Points to the local DTD |
318 |
/** Implementation of entity resolver. Points to the local DTD |
275 |
* for our public ID */ |
319 |
* for our public ID */ |
|
|
320 |
@Override |
276 |
public InputSource resolveEntity (String publicId, String systemId) |
321 |
public InputSource resolveEntity (String publicId, String systemId) |
277 |
throws SAXException { |
322 |
throws SAXException { |
278 |
if ("-//NetBeans//DTD Library Declaration 1.0//EN".equals(publicId)) { |
323 |
if (LIBRARY_DEF_1.equals(publicId)) { |
279 |
InputStream is = new ByteArrayInputStream(new byte[0]); |
324 |
InputStream is = new ByteArrayInputStream(new byte[0]); |
280 |
return new InputSource(is); |
325 |
return new InputSource(is); |
281 |
} |
326 |
} |
282 |
return null; // i.e. follow advice of systemID |
327 |
return null; // i.e. follow advice of systemID |
283 |
} |
328 |
} |
|
|
329 |
|
330 |
static void writeLibraryDefinition ( |
331 |
final @NonNull FileObject definitionFile, |
332 |
final @NonNull LibraryImplementation library, |
333 |
final @NonNull LibraryTypeProvider libraryTypeProvider) throws IOException { |
334 |
final Document doc = Util.supportsDisplayName(library) ? |
335 |
createLibraryDefinition2(library, libraryTypeProvider) : |
336 |
createLibraryDefinition1(library, libraryTypeProvider); |
337 |
final OutputStream os = definitionFile.getOutputStream(); |
338 |
try { |
339 |
XMLUtil.write(doc, os, "UTF-8"); // NOI18N |
340 |
} finally { |
341 |
os.close(); |
342 |
} |
343 |
} |
344 |
|
345 |
private static Document createLibraryDefinition1( |
346 |
final @NonNull LibraryImplementation library, |
347 |
final @NonNull LibraryTypeProvider libraryTypeProvider) { |
348 |
final Document doc = XMLUtil.createDocument(LIBRARY, null, |
349 |
LIBRARY_DEF_1, |
350 |
LIBRARY_DTD_1); |
351 |
final Element libraryE = doc.getDocumentElement(); |
352 |
libraryE.setAttribute(VERSION, VER_1); // NOI18N |
353 |
libraryE.appendChild(doc.createElement(NAME)).appendChild(doc.createTextNode(library.getName())); // NOI18N |
354 |
libraryE.appendChild(doc.createElement(TYPE)).appendChild(doc.createTextNode(library.getType())); // NOI18N |
355 |
String description = library.getDescription(); |
356 |
if (description != null && description.length() > 0) { |
357 |
libraryE.appendChild(doc.createElement(DESCRIPTION)).appendChild(doc.createTextNode(description)); // NOI18N |
358 |
} |
359 |
String localizingBundle = library.getLocalizingBundle(); |
360 |
if (localizingBundle != null && localizingBundle.length() > 0) { |
361 |
libraryE.appendChild(doc.createElement(BUNDLE)).appendChild(doc.createTextNode(localizingBundle)); // NOI18N |
362 |
} |
363 |
String displayname = Util.getDisplayName(library); |
364 |
if (displayname != null) { |
365 |
libraryE.appendChild(doc.createElement(DISPLAY_NAME)).appendChild(doc.createTextNode(displayname)); // NOI18N |
366 |
} |
367 |
for (String vtype : libraryTypeProvider.getSupportedVolumeTypes()) { |
368 |
Element volumeE = (Element) libraryE.appendChild(doc.createElement(VOLUME)); // NOI18N |
369 |
volumeE.appendChild(doc.createElement(TYPE)).appendChild(doc.createTextNode(vtype)); // NOI18N |
370 |
List<URL> volume = library.getContent(vtype); |
371 |
if (volume != null) { |
372 |
//If null -> broken library, repair it. |
373 |
for (URL url : volume) { |
374 |
volumeE.appendChild(doc.createElement(RESOURCE)).appendChild(doc.createTextNode(url.toString())); // NOI18N |
375 |
} |
376 |
} |
377 |
} |
378 |
return doc; |
379 |
} |
380 |
|
381 |
private static Document createLibraryDefinition2( |
382 |
final @NonNull LibraryImplementation library, |
383 |
final @NonNull LibraryTypeProvider libraryTypeProvider) { |
384 |
final Document doc = XMLUtil.createDocument(LIBRARY, LIBRARY_NS, null, null); |
385 |
final Element libraryE = doc.getDocumentElement(); |
386 |
libraryE.setAttribute(VERSION, VER_2); // NOI18N |
387 |
libraryE.appendChild(doc.createElementNS(LIBRARY_NS, NAME)).appendChild(doc.createTextNode(library.getName())); // NOI18N |
388 |
libraryE.appendChild(doc.createElementNS(LIBRARY_NS, TYPE)).appendChild(doc.createTextNode(library.getType())); // NOI18N |
389 |
String description = library.getDescription(); |
390 |
if (description != null && description.length() > 0) { |
391 |
libraryE.appendChild(doc.createElementNS(LIBRARY_NS, DESCRIPTION)).appendChild(doc.createTextNode(description)); // NOI18N |
392 |
} |
393 |
String localizingBundle = library.getLocalizingBundle(); |
394 |
if (localizingBundle != null && localizingBundle.length() > 0) { |
395 |
libraryE.appendChild(doc.createElementNS(LIBRARY_NS, BUNDLE)).appendChild(doc.createTextNode(localizingBundle)); // NOI18N |
396 |
} |
397 |
String displayname = Util.getDisplayName(library); |
398 |
if (displayname != null) { |
399 |
libraryE.appendChild(doc.createElementNS(LIBRARY_NS, DISPLAY_NAME)).appendChild(doc.createTextNode(displayname)); // NOI18N |
400 |
} |
401 |
for (String vtype : libraryTypeProvider.getSupportedVolumeTypes()) { |
402 |
Element volumeE = (Element) libraryE.appendChild(doc.createElementNS(LIBRARY_NS,VOLUME)); // NOI18N |
403 |
volumeE.appendChild(doc.createElementNS(LIBRARY_NS, TYPE)).appendChild(doc.createTextNode(vtype)); // NOI18N |
404 |
List<URL> volume = library.getContent(vtype); |
405 |
if (volume != null) { |
406 |
for (URL url : volume) { |
407 |
volumeE.appendChild(doc.createElementNS(LIBRARY_NS, RESOURCE)).appendChild(doc.createTextNode(url.toString())); // NOI18N |
408 |
} |
409 |
} |
410 |
} |
411 |
return doc; |
412 |
} |
284 |
} |
413 |
} |
285 |
|
414 |
|